[neutron] Network segment ranges feature
Hello Neutrinos: First of all, a reference: https://bugs.launchpad.net/neutron/+bug/1863423 I detected some problems with this feature. The service plugin, when enabled and according to the spec [1], should segregate the segmentation range in several ranges. Each one (or many) of those ranges could be assigned to a project. When a network is created in a specific project, should receive a segmentation ID from the project network segment ranges. In case of not having any range assigned, a segmentation ID from a default range will be provided. How the current implementation actually works: When a driver is loaded (VLAN, VXLAN, GRE or Geneve), it creates a default network segment range, based on the static configuration provided in the plugin ("network_vlan_ranges", "vni_ranges", etc). Then the admin can create project specific network segment ranges (remember: always per driver type). Those project specific ranges cannot overlap but the project specific ranges CAN overlap the default one. A valid state could be: VLAN: - Default: 100:1000 - Project1: 100:200 - Project2: 200:300 When assigning segmentation IDs to new networks, the driver will query [2]: - The existing ranges per project. - The default range (always present). The result is that, if the project network segment range runs out of segment IDs, it will retrieve those ones from the default range. That will lead, eventually, to a clash between ranges. Project 1 will be able to allocate a network with a segmentation ID from Project 2 range. E.g.: [3] The problem is how the queries are done: [4] --> select one of each commented line to reproduce "query_project_id" and "query_shared" in [2]. Now we know the feature is not properly working, my question is what the proper behaviour should be. Some alternatives: 1) If a project has one or more network segment ranges, the segmentation ID should be retrieved ONLY from those ranges. If a project does not have any range, then it will retrieve from the shared pool BUT NEVER selecting a segment ID belonging to other project ID (ufff this query is going to be complex). --> IMO, the best solution. 2) If a project has one or more network segment ranges, the segmentation ID should be retrieved first from those ranges and then from the shared one, BUT NEVER selecting a segment ID belonging to other project ID. Same for range-less projects. --> IMO, if the administrator has assigned a range for a project, the project should ONLY use this pool. This is not a good solution. Can I have your feedback? Regards. [1] https://specs.openstack.org/openstack/neutron-specs/specs/stein/network-segm... [2]https://github.com/openstack/neutron/blob/master/neutron/plugins/ml2/drivers... [3]http://paste.openstack.org/show/789872/ [4]http://paste.openstack.org/show/789873/
On Fri, Feb 21, 2020 at 05:23:54PM +0000, Rodolfo Alonso wrote:
Hello Neutrinos:
First of all, a reference: https://bugs.launchpad.net/neutron/+bug/1863423
I detected some problems with this feature. The service plugin, when enabled and according to the spec [1], should segregate the segmentation range in several ranges. Each one (or many) of those ranges could be assigned to a project. When a network is created in a specific project, should receive a segmentation ID from the project network segment ranges. In case of not having any range assigned, a segmentation ID from a default range will be provided.
How the current implementation actually works: When a driver is loaded (VLAN, VXLAN, GRE or Geneve), it creates a default network segment range, based on the static configuration provided in the plugin ("network_vlan_ranges", "vni_ranges", etc). Then the admin can create project specific network segment ranges (remember: always per driver type). Those project specific ranges cannot overlap but the project specific ranges CAN overlap the default one. A valid state could be:
VLAN: - Default: 100:1000 - Project1: 100:200 - Project2: 200:300
When assigning segmentation IDs to new networks, the driver will query [2]: - The existing ranges per project. - The default range (always present).
The result is that, if the project network segment range runs out of segment IDs, it will retrieve those ones from the default range. That will lead, eventually, to a clash between ranges. Project 1 will be able to allocate a network with a segmentation ID from Project 2 range. E.g.: [3]
The problem is how the queries are done: [4] --> select one of each commented line to reproduce "query_project_id" and "query_shared" in [2].
Now we know the feature is not properly working, my question is what the proper behaviour should be. Some alternatives:
1) If a project has one or more network segment ranges, the segmentation ID should be retrieved ONLY from those ranges. If a project does not have any range, then it will retrieve from the shared pool BUT NEVER selecting a segment ID belonging to other project ID (ufff this query is going to be complex). --> IMO, the best solution.
I like this. I would say that we should maintain a state of all parts of the range that have already been assigned. We load that into memory at process start and then we compare against it before we allow any other range requests to be implemented. My inclination would be to, at start, load all ranges up into a bit vector array that indicates what sections of the default range are in use. Also comvert the request into a bit vector array. - Assuming 1 is available and 0 is allocated - If there are any zero bits in "defaultrange | rangerequest" then you are allocating a used range - Adding a range as marked off in the bit vector is as simple as "defaultrange & rangerequest" So I think this will not be difficult to implement, and can be done in a way that avoids nasty SQL. Nate
2) If a project has one or more network segment ranges, the segmentation ID should be retrieved first from those ranges and then from the shared one, BUT NEVER selecting a segment ID belonging to other project ID. Same for range-less projects. --> IMO, if the administrator has assigned a range for a project, the project should ONLY use this pool. This is not a good solution.
Can I have your feedback?
Regards.
[1] https://specs.openstack.org/openstack/neutron-specs/specs/stein/network-segm... [2]https://github.com/openstack/neutron/blob/master/neutron/plugins/ml2/drivers... [3]http://paste.openstack.org/show/789872/ [4]http://paste.openstack.org/show/789873/
Hello On Fri, 2020-02-21 at 15:41 -0500, Nate Johnston wrote:
On Fri, Feb 21, 2020 at 05:23:54PM +0000, Rodolfo Alonso wrote:
Hello Neutrinos:
First of all, a reference: https://bugs.launchpad.net/neutron/+bug/1863423
I detected some problems with this feature. The service plugin, when enabled and according to the spec [1], should segregate the segmentation range in several ranges. Each one (or many) of those ranges could be assigned to a project. When a network is created in a specific project, should receive a segmentation ID from the project network segment ranges. In case of not having any range assigned, a segmentation ID from a default range will be provided.
How the current implementation actually works: When a driver is loaded (VLAN, VXLAN, GRE or Geneve), it creates a default network segment range, based on the static configuration provided in the plugin ("network_vlan_ranges", "vni_ranges", etc). Then the admin can create project specific network segment ranges (remember: always per driver type). Those project specific ranges cannot overlap but the project specific ranges CAN overlap the default one. A valid state could be:
VLAN: - Default: 100:1000 - Project1: 100:200 - Project2: 200:300
When assigning segmentation IDs to new networks, the driver will query [2]: - The existing ranges per project. - The default range (always present).
The result is that, if the project network segment range runs out of segment IDs, it will retrieve those ones from the default range. That will lead, eventually, to a clash between ranges. Project 1 will be able to allocate a network with a segmentation ID from Project 2 range. E.g.: [3]
The problem is how the queries are done: [4] --> select one of each commented line to reproduce "query_project_id" and "query_shared" in [2].
Now we know the feature is not properly working, my question is what the proper behaviour should be. Some alternatives:
1) If a project has one or more network segment ranges, the segmentation ID should be retrieved ONLY from those ranges. If a project does not have any range, then it will retrieve from the shared pool BUT NEVER selecting a segment ID belonging to other project ID (ufff this query is going to be complex). --> IMO, the best solution.
I like this. I would say that we should maintain a state of all parts of the range that have already been assigned. We load that into memory at process start and then we compare against it before we allow any other range requests to be implemented.
My inclination would be to, at start, load all ranges up into a bit vector array that indicates what sections of the default range are in use. Also comvert the request into a bit vector array.
- Assuming 1 is available and 0 is allocated - If there are any zero bits in "defaultrange | rangerequest" then you are allocating a used range - Adding a range as marked off in the bit vector is as simple as "defaultrange & rangerequest"
So I think this will not be difficult to implement, and can be done in a way that avoids nasty SQL.
Nate
That's a good idea and originally I designed a solution based on a cached mapping. But then I realized that, every time we use some kind of shortcut to the DB mapping any resource in a controller, then we have plenty of problems with HA. The DB is, IMO, the best resource for sync resources in HA. There is a way to do this in two steps: - Retrieve the ranges assigned to other projects. Those ranges, by definition, do no overlap. Then join if possible those ranges to have the minimum set of gaps. E.g.: 0-100,120-500,720-1000. - The second DB call will be very similar to the current one, but using those ranges in the opposite way, to filter out those segment IDs within them but belonging to the default one. Regardless of the implementation, what I would like is to have is an idea of how the feature should work. IMO, (1) is the desirable way: if a project has segment ranges, use them (and only those segments). If not, use the default range but never a segment ID belonging to another project range.
2) If a project has one or more network segment ranges, the segmentation ID should be retrieved first from those ranges and then from the shared one, BUT NEVER selecting a segment ID belonging to other project ID. Same for range-less projects. --> IMO, if the administrator has assigned a range for a project, the project should ONLY use this pool. This is not a good solution.
Can I have your feedback?
Regards.
[1] https://specs.openstack.org/openstack/neutron-specs/specs/stein/network-segm... [2] https://github.com/openstack/neutron/blob/master/neutron/plugins/ml2/drivers... [3]http://paste.openstack.org/show/789872/ [4]http://paste.openstack.org/show/789873/
Hi,
On 21 Feb 2020, at 18:23, Rodolfo Alonso <ralonsoh@redhat.com> wrote:
Hello Neutrinos:
First of all, a reference: https://bugs.launchpad.net/neutron/+bug/1863423
I detected some problems with this feature. The service plugin, when enabled and according to the spec [1], should segregate the segmentation range in several ranges. Each one (or many) of those ranges could be assigned to a project. When a network is created in a specific project, should receive a segmentation ID from the project network segment ranges. In case of not having any range assigned, a segmentation ID from a default range will be provided.
How the current implementation actually works: When a driver is loaded (VLAN, VXLAN, GRE or Geneve), it creates a default network segment range, based on the static configuration provided in the plugin ("network_vlan_ranges", "vni_ranges", etc). Then the admin can create project specific network segment ranges (remember: always per driver type). Those project specific ranges cannot overlap but the project specific ranges CAN overlap the default one. A valid state could be:
VLAN: - Default: 100:1000 - Project1: 100:200 - Project2: 200:300
When assigning segmentation IDs to new networks, the driver will query [2]: - The existing ranges per project. - The default range (always present).
The result is that, if the project network segment range runs out of segment IDs, it will retrieve those ones from the default range. That will lead, eventually, to a clash between ranges. Project 1 will be able to allocate a network with a segmentation ID from Project 2 range. E.g.: [3]
The problem is how the queries are done: [4] --> select one of each commented line to reproduce "query_project_id" and "query_shared" in [2].
Now we know the feature is not properly working, my question is what the proper behaviour should be. Some alternatives:
1) If a project has one or more network segment ranges, the segmentation ID should be retrieved ONLY from those ranges. If a project does not have any range, then it will retrieve from the shared pool BUT NEVER selecting a segment ID belonging to other project ID (ufff this query is going to be complex). --> IMO, the best solution.
I like this solution and IMO this makes sense but we will not be able to backport it to the stable branches as it changes API behaviour for end user - it may immediately after update notice errors on creation of new networks when before update it was possible using segmentation_id from shared range.
2) If a project has one or more network segment ranges, the segmentation ID should be retrieved first from those ranges and then from the shared one, BUT NEVER selecting a segment ID belonging to other project ID. Same for range-less projects. --> IMO, if the administrator has assigned a range for a project, the project should ONLY use this pool. This is not a good solution.
This IMO would be better solution for stable branches. As a bug is pretty serious and one tenant can “stole” segmentation ids dedicated to the other tenant I think we should think about fix in stable branches too so I would probably go with this solution.
Can I have your feedback?
Regards.
[1] https://specs.openstack.org/openstack/neutron-specs/specs/stein/network-segm... [2]https://github.com/openstack/neutron/blob/master/neutron/plugins/ml2/drivers... [3]http://paste.openstack.org/show/789872/ [4]http://paste.openstack.org/show/789873/
— Slawek Kaplonski Senior software engineer Red Hat
participants (3)
-
Nate Johnston
-
Rodolfo Alonso
-
Slawek Kaplonski