Skip to content

Commit 570efdb

Browse files
Helen Chencubeek
authored andcommitted
Created Single VxLAN Device management for EVPN
A Single VxLAN Device (SVD) is a vlan-aware Linux bridge and a vlan-aware VxLAN paired together to support mapping of VNI to VLAN ID. It is a way to create a VxLAN interface that can receive traffic for multiple VNIs, reducing the number of VxLAN interfaces needed in the system to support the entire VxLAN VNI space. EVPN uses SVD to map a VNI to VLAN interface on the vlan-aware Linux bridge. The VLAN interface represents the EVPN instance's bridge domain. Netlink, primarily through pyroute2, is used to programmatically create the following interfaces and update their settings. Where pyroute2 does not provide the API, a raw netlink message is composed and the configuration is still through netlink. Creating SVD: ip link add $br type bridge vlan_filtering 1 vlan_default_pvid 0 ip link set $br addrgenmode none ip link set $br address $svd_mac ip link set $br mtu 1500 ip link set dev $br up ip link add $vxlan type vxlan \ dev $underlay_device \ dstport $dstport local $local_ip \ nolearning external vnifilter \ ip link set $vxlan addrgenmode none master $br ip link set $vxlan address $svd_mac bridge link set dev $vxlan \ vlan_tunnel on neigh_suppress on learning off ip link set dev $vxlan up Create VLAN interface with VLAN ID mapped to VNI: bridge vlan add dev $br vid $vid self bridge vlan add dev $vxlan vid $vid bridge vni add dev $vxlan vni $vni bridge vlan add dev $vxlan vid $vid tunnel_info id $vni ip link add vl-0-$vid link $br type vlan id $vid ip link set vl-0-$vid master $vrf ip link set vl-0-$vid addr $router_mac addrgenmode none ip link set vl-0-$vid up Related-Bug: #2144617 Assisted-By: Claude Opus 4.6 Change-Id: I78fec86595fb358880b306ec1fe014adad007d87 Signed-off-by: Helen Chen <ichen@redhat.com>
1 parent 02c4820 commit 570efdb

4 files changed

Lines changed: 423 additions & 2 deletions

File tree

neutron/agent/linux/svd.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# Copyright 2026 Red Hat, LLC
2+
# All Rights Reserved.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
5+
# not use this file except in compliance with the License. You may obtain
6+
# a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
# License for the specific language governing permissions and limitations
14+
# under the License.
15+
16+
import errno
17+
18+
from pyroute2.netlink import exceptions as netlink_exc
19+
20+
from neutron.agent.ovn.extensions.evpn import exceptions as evpn_exc
21+
from neutron.privileged.agent.linux import svd as privileged_svd
22+
23+
24+
class Svd:
25+
"""A Single VXLAN Device: a VLAN-aware bridge + VXLAN device pair.
26+
27+
Up to 4094 VNIs share the same SVD via VLAN/VNI mappings added
28+
with add_vni().
29+
30+
When a VNI is mapped to a VLAN, a VLAN interface with
31+
EVPN_VLAN_IFNAME_PATTERN is created
32+
"""
33+
34+
def __init__(self, br_evpn, vxlan_evpn, index=0):
35+
self._index = index
36+
self.br_evpn = br_evpn
37+
self.vxlan_evpn = vxlan_evpn
38+
39+
def create(self, local_ip, mac, vxlan_parent, dstport):
40+
try:
41+
privileged_svd.create_svd(
42+
self.br_evpn, self.vxlan_evpn,
43+
local_ip, mac, vxlan_parent, dstport)
44+
except IndexError:
45+
raise evpn_exc.SvdNoVxlanParent("Missing VxLAN underlay: %s" %
46+
(vxlan_parent))
47+
except netlink_exc.NetlinkError as e:
48+
if e.code == errno.EEXIST:
49+
raise evpn_exc.SvdDeviceAlreadyExists("SVD %s/%s device(s) "
50+
"already exist(s)" %
51+
(self.br_evpn,
52+
self.vxlan_evpn))
53+
raise evpn_exc.SvdNetlinkError(
54+
"Failed to add SVD %s/%s: %s" %
55+
(self.br_evpn, self.vxlan_evpn, e))
56+
57+
def delete(self):
58+
try:
59+
privileged_svd.delete_svd(self.br_evpn, self.vxlan_evpn)
60+
except IndexError:
61+
raise evpn_exc.SvdNotFound(
62+
"SVD %s/%s not found" %
63+
(self.br_evpn, self.vxlan_evpn))
64+
except netlink_exc.NetlinkError as e:
65+
raise evpn_exc.SvdNetlinkError(
66+
"Failed to delete SVD %s/%s: %s" %
67+
(self.br_evpn, self.vxlan_evpn, e))
68+
69+
def add_vni(self, vni, vid, vrf_name, mac):
70+
try:
71+
privileged_svd.add_vni(
72+
self.br_evpn, self.vxlan_evpn,
73+
vni, vid, vrf_name, mac, self._index)
74+
except IndexError:
75+
raise evpn_exc.SvdDevsNotFound(
76+
"SVD %s/%s or VRF %s not found" %
77+
(self.br_evpn, self.vxlan_evpn, vrf_name))
78+
except netlink_exc.NetlinkError as e:
79+
raise evpn_exc.SvdNetlinkError(
80+
"Failed to add VNI %d to SVD %s/%s: %s" %
81+
(vni, self.br_evpn, self.vxlan_evpn, e))
82+
83+
def del_vni(self, vni, vid):
84+
try:
85+
privileged_svd.del_vni(
86+
self.br_evpn, self.vxlan_evpn,
87+
vni, vid, self._index)
88+
except IndexError:
89+
raise evpn_exc.SvdSviNotFound(
90+
"SVI for VNI %d not found on SVD %s/%s" %
91+
(vni, self.br_evpn, self.vxlan_evpn))
92+
except netlink_exc.NetlinkError as e:
93+
raise evpn_exc.SvdNetlinkError(
94+
"Failed to delete VNI %d from SVD %s/%s: %s" %
95+
(vni, self.br_evpn, self.vxlan_evpn, e))

neutron/agent/ovn/extensions/evpn/constants.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2026 Red Hat, Inc.
1+
# Copyright 2026 Red Hat, LLC
22
# All Rights Reserved.
33
#
44
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -19,9 +19,14 @@
1919
EVPN_LINK_KIND_VRF = 'vrf'
2020
EVPN_RTM_NEWLINK = 'RTM_NEWLINK'
2121
EVPN_RTM_DELLINK = 'RTM_DELLINK'
22+
EVPN_IP_LINK_ADD = 'add'
23+
EVPN_IP_LINK_DEL = 'del'
24+
EVPN_IP_LINK_SET = 'set'
2225

2326
EVPN_LB_NAME_PREFIX = 'brevpn-'
2427

2528
EVPN_VXLAN_IFNAME = 'vxlanevpn-'
2629

2730
EVPN_VLAN_IFNAME_PATTERN = 'vl-%(index)d-%(vid)d'
31+
32+
EVPN_BR_MTU = 1500

neutron/agent/ovn/extensions/evpn/exceptions.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2026 Red Hat, Inc.
1+
# Copyright 2026 Red Hat, LLC
22
# All Rights Reserved.
33
#
44
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -28,3 +28,27 @@ class FSMIllegalTransition(Exception):
2828

2929
class FSMMissingTransitionCallback(Exception):
3030
pass
31+
32+
33+
class SvdNoVxlanParent(Exception):
34+
pass
35+
36+
37+
class SvdDeviceAlreadyExists(Exception):
38+
pass
39+
40+
41+
class SvdDevsNotFound(Exception):
42+
pass
43+
44+
45+
class SvdSviNotFound(Exception):
46+
pass
47+
48+
49+
class SvdNotFound(Exception):
50+
pass
51+
52+
53+
class SvdNetlinkError(Exception):
54+
pass

0 commit comments

Comments
 (0)