Skip to content

feat: Implement vrf router with auto-allocating evpn_vni attribute#2109

Open
stevekeay wants to merge 2 commits into
mainfrom
vrf-router-evpn-vni
Open

feat: Implement vrf router with auto-allocating evpn_vni attribute#2109
stevekeay wants to merge 2 commits into
mainfrom
vrf-router-evpn-vni

Conversation

@stevekeay

Copy link
Copy Markdown
Contributor

This creates a standalone plugin for 2026.1 to provide the vrf router behaviour we need, including auto-assignment of VNIs from a configured range.

Some of this overlaps work in progress upstream. I have intentionally mirrored the --evpn-vni API surface of the evpn plugin. We are not using any of the actual evpn plugin code but (in theory) once it gains feature parity, we should be able to switch over to it without affecting our users.

This got fairly big. I was thinking it might be cleaner to break it out into a separate package (that we would install separately via pip install in the container) but I wanted to solicit opinions from the team.

To use this:

  • we can roll neutron back to stock 2026.1 (removing the stuff we cherry-picked)
  • change the neutron.conf service_plugins removing evpn and adding understack_vni
  • Add a [understack_vni] section like vni_ranges = 10000:19999

Comment thread python/neutron-understack/neutron_understack/config.py Outdated
This was added because a test case was registering multiple conflicting
options.  I am removing because it is no longer required.
"allow_post": True,
"allow_put": False,
"convert_to": converters.convert_to_int_if_not_none,
"default": 0,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should that be 0 or ATTR_NOT_SPECIFIED ? I am concerned if having it as 0 will not prevent non-admin users from creating routers

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am a bit hazy on the logic for collections, but I think we want non-admin users to create routers, we just don't want them to be able to choose a VNI.

A value of zero is explicitly interpreted as "please auto-assign" in the assignment hook, so the value that actually gets persisted should be non-zero.

Technically it may be more correct to use the sentinel value but I thought this was going to the DB layer, I'm not sure what the best answer is.

@skrobul skrobul Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The python/neutron-understack/neutron_understack/conf/policies/evpn.py has:

   policy.DocumentedRuleDefault(
        name="create_router:evpn_vni",
        check_str=base.ADMIN,
        scope_types=["project"],
        description="Specify ``evpn_vni`` attribute when creating a router",
        operations=ACTION_POST,
...

which will translate to "create_router:evpn_vni": "rule:admin_only" inside a default policy (similarly to stock one and if the user provides any value of the attribute in the request, it will match the rule, effectively requiring admin privileges, so we may need to adjust base.ADMIN to sth else.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are the results of my manual testing:

If a non-admin user provides a valid VNI, it fails:

ubuntu@devstack-ovn:~$ OS_CLOUD=devstack-alt-member openstack router create --flavor understack-vrf-demo  --extra-property type=int,name=evpn_vni,value=10099 steve-test-b
ForbiddenException: 403: Client Error for url: http://192.168.99.10/networking/v2.0/routers, ((rule:create_router and rule:create_router:flavor_id) and rule:create_router:evpn_vni) is disallowed by policy

(The above succeeds when performed as an admin user.)

If a non-admin user provides a VNI of zero, it still fails:

ubuntu@devstack-ovn:~$ OS_CLOUD=devstack-alt-member openstack router create --flavor understack-vrf-demo  --extra-property type=int,name=evpn_vni,value=0 steve-test-b
ForbiddenException: 403: Client Error for url: http://192.168.99.10/networking/v2.0/routers, ((rule:create_router and rule:create_router:flavor_id) and rule:create_router:evpn_vni) is disallowed by policy

(The above succeeds when performed as an admin user.)

If any user created a router but does not include a VNI, the call succeeds and a VNI is allocated from the configured range:

ubuntu@devstack-ovn:~$ OS_CLOUD=devstack-alt-member openstack router create --flavor understack-vrf-demo  steve-test-c
+---------------------------+--------------------------------------+
| Field                     | Value                                |
+---------------------------+--------------------------------------+
| admin_state_up            | UP                                   |
| availability_zone_hints   |                                      |
| availability_zones        |                                      |
| created_at                | 2026-07-08T13:22:11Z                 |
| description               |                                      |
| enable_default_route_bfd  | False                                |
| enable_default_route_ecmp | False                                |
| enable_ndp_proxy          | None                                 |
| enable_snat               | True                                 |
| evpn_vni                  | 10007                                |
| external_gateway_info     | null                                 |
| external_gateways         | []                                   |
| flavor_id                 | 00035dcb-968b-4be6-9057-026f4069ee1a |
| id                        | 92df1c90-78c4-4412-8eb4-e1c94288a4ef |
| name                      | steve-test-c                         |
| project_id                | fa2408453dfa4a658fca0aff301b94ba     |
| revision_number           | 1                                    |
| routes                    |                                      |
| status                    | ACTIVE                               |
| tags                      |                                      |
| updated_at                | 2026-07-08T13:22:11Z                 |
+---------------------------+--------------------------------------+

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I had to walk the code and I still was confused. So I had to have Claude walk it with me to understand and run it in a little repl to test. It's the way for the non-default value (which the default value is 0). So the behavior is actually correct as Steve coded it. But holy cow that feels like a foot gun.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool cool - I misunderstood the requirements and thought we want to allow users to select the VNI, but after thinking about it, it would be bad idea. Thanks for testing

Comment thread python/neutron-understack/pyproject.toml
@stevekeay stevekeay requested review from cardoe and skrobul July 8, 2026 13:30

@cardoe cardoe left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be good to get some operator docs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants