Skip to content

Commit 04c4c9f

Browse files
authored
Merge pull request #2109 from rackerlabs/vrf-router-evpn-vni
feat: Implement vrf router with auto-allocating evpn_vni attribute
2 parents 07d02d8 + cbbc38a commit 04c4c9f

31 files changed

Lines changed: 864 additions & 1 deletion

.typos.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,5 @@ retreive = "retreive"
3636
metadat = "metadat"
3737
# operators/rook/values-cluster.yaml mentions "ceph-blockpool-ecoded"
3838
ecoded = "ecoded"
39+
# lazy option is not a typo
40+
selectin = "selectin"
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
11
__version__ = "0.1"
2+
3+
# Neutron's extension loader looks for ``<service_plugin_root>.extensions`` as
4+
# an attribute on the imported top-level package.
5+
from neutron_understack import extensions # noqa: F401

python/neutron-understack/neutron_understack/api/__init__.py

Whitespace-only changes.

python/neutron-understack/neutron_understack/api/definitions/__init__.py

Whitespace-only changes.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from neutron_lib import constants
2+
from neutron_lib.api import converters
3+
from neutron_lib.api.definitions import l3
4+
5+
ALIAS = "understack_vni"
6+
IS_SHIM_EXTENSION = False
7+
IS_STANDARD_ATTR_EXTENSION = False
8+
NAME = "Understack Router VNI"
9+
API_PREFIX = ""
10+
DESCRIPTION = "Router extension for Understack hardware VRF VNI allocation"
11+
UPDATED_TIMESTAMP = "2026-07-01T00:00:00-00:00"
12+
RESOURCE_NAME = l3.ROUTER
13+
COLLECTION_NAME = l3.ROUTERS
14+
15+
EVPN_VNI = "evpn_vni"
16+
17+
RESOURCE_ATTRIBUTE_MAP = {
18+
COLLECTION_NAME: {
19+
EVPN_VNI: {
20+
"allow_post": True,
21+
"allow_put": False,
22+
"convert_to": converters.convert_to_int_if_not_none,
23+
"default": 0,
24+
"is_visible": True,
25+
"is_filter": True,
26+
"is_sort_key": True,
27+
"enforce_policy": True,
28+
"validate": {"type:range_or_none": [0, constants.MAX_VXLAN_VNI]},
29+
},
30+
},
31+
}
32+
33+
SUB_RESOURCE_ATTRIBUTE_MAP = {}
34+
ACTION_MAP = {}
35+
REQUIRED_EXTENSIONS = [l3.ALIAS]
36+
OPTIONAL_EXTENSIONS = []
37+
ACTION_STATUS = {}

python/neutron-understack/neutron_understack/conf/__init__.py

Whitespace-only changes.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import itertools
2+
3+
from neutron_understack.conf.policies import evpn
4+
5+
6+
def list_rules():
7+
return itertools.chain(
8+
evpn.list_rules(),
9+
)
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
from neutron.conf.policies import base
2+
from oslo_policy import policy
3+
4+
COLLECTION_PATH = "/routers"
5+
RESOURCE_PATH = "/routers/{id}"
6+
7+
ACTION_POST = [
8+
{"method": "POST", "path": COLLECTION_PATH},
9+
]
10+
ACTION_GET = [
11+
{"method": "GET", "path": COLLECTION_PATH},
12+
{"method": "GET", "path": RESOURCE_PATH},
13+
]
14+
15+
rules = [
16+
policy.DocumentedRuleDefault(
17+
name="create_router:evpn_vni",
18+
check_str=base.ADMIN,
19+
scope_types=["project"],
20+
description="Specify ``evpn_vni`` attribute when creating a router",
21+
operations=ACTION_POST,
22+
),
23+
policy.DocumentedRuleDefault(
24+
name="get_router:evpn_vni",
25+
check_str=base.ADMIN_OR_PROJECT_READER,
26+
scope_types=["project"],
27+
description="Get ``evpn_vni`` attribute of a router",
28+
operations=ACTION_GET,
29+
),
30+
]
31+
32+
33+
def list_rules():
34+
return rules

python/neutron-understack/neutron_understack/config.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
_OPT_GRP_ML2_UNDERSTACK = "ml2_understack"
66
_OPT_GRP_IRONIC = "ironic"
77
_OPT_GRP_L3_SVC_CISCO_ASA = "l3_service_cisco_asa"
8+
_OPT_GRP_UNDERSTACK_VNI = "understack_vni"
89

910
_mech_understack_opts = [
1011
cfg.StrOpt(
@@ -99,6 +100,19 @@
99100
),
100101
]
101102

103+
_understack_vni_opts = [
104+
cfg.ListOpt(
105+
"vni_ranges",
106+
default=["1:16777215"],
107+
item_type=cfg.types.String(),
108+
help=(
109+
"Comma-separated list of VNI ranges available for automatic "
110+
"Understack VRF router VNI allocation. Each entry is either a "
111+
"single VNI or an inclusive start:end range."
112+
),
113+
),
114+
]
115+
102116

103117
def list_understack_opts():
104118
return [
@@ -125,6 +139,12 @@ def list_cisco_asa_opts():
125139
]
126140

127141

142+
def list_understack_vni_opts():
143+
return [
144+
(_OPT_GRP_UNDERSTACK_VNI, _understack_vni_opts),
145+
]
146+
147+
128148
def register_ml2_understack_opts(config):
129149
config.register_opts(_mech_understack_opts, _OPT_GRP_ML2_UNDERSTACK)
130150

@@ -139,6 +159,10 @@ def register_l3_svc_cisco_asa_opts(config):
139159
config.register_opts(_l3_svc_cisco_asa_opts, _OPT_GRP_L3_SVC_CISCO_ASA)
140160

141161

162+
def register_understack_vni_opts(config):
163+
config.register_opts(_understack_vni_opts, _OPT_GRP_UNDERSTACK_VNI)
164+
165+
142166
def get_session(group: str) -> ks_session.Session:
143167
auth = ks_loading.load_auth_from_conf_options(cfg.CONF, group)
144168
session = ks_loading.load_session_from_conf_options(cfg.CONF, group, auth=auth)

python/neutron-understack/neutron_understack/db/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)