mirror of
https://github.com/CumulusNetworks/ifupdown2.git
synced 2024-05-06 15:54:50 +00:00
addons: vxlan: use new vni filter api to set mcast groups per vni
Signed-off-by: Roopa Prabhu <roopa@nvidia.com> Signed-off-by: Julien Fortin <jfortin@nvidia.com>
This commit is contained in:
committed by
Julien Fortin
parent
8acbc3c523
commit
af8d5db22b
@@ -974,14 +974,30 @@ class vxlan(Addon, moduleBase):
|
|||||||
|
|
||||||
def single_vxlan_device_vni_filter(self, ifaceobj):
|
def single_vxlan_device_vni_filter(self, ifaceobj):
|
||||||
vnis = []
|
vnis = []
|
||||||
|
vnisd = {}
|
||||||
for vlan_vni_map in ifaceobj.get_attr_value("bridge-vlan-vni-map"):
|
for vlan_vni_map in ifaceobj.get_attr_value("bridge-vlan-vni-map"):
|
||||||
try:
|
try:
|
||||||
(vls, vis) = utils.get_vlan_vnis_in_map(vlan_vni_map)
|
(vls, vis) = utils.get_vlan_vnis_in_map(vlan_vni_map)
|
||||||
vnis.extend(vis)
|
for v in utils.ranges_to_ints(vis):
|
||||||
|
vnisd[v] = None
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error("%s: %s (%s)" %(ifaceobj.name, vlan_vni_map, str(e)))
|
self.logger.error("%s: %s (%s)" %(ifaceobj.name, vlan_vni_map, str(e)))
|
||||||
return
|
return
|
||||||
self.iproute2.bridge_link_update_vni_filter(ifaceobj.name, vnis)
|
for vni_mcastgrp_map in ifaceobj.get_attr_value("vxlan-mcastgrp-map"):
|
||||||
|
try:
|
||||||
|
vd = utils.get_vni_mcastgrp_in_map(vni_mcastgrp_map)
|
||||||
|
for v, g in vd.items():
|
||||||
|
if v not in vnisd.keys():
|
||||||
|
self.logger.error("%s: group %s configured for a vni not specified in vlan vni map (%s)"
|
||||||
|
%(ifaceobj.name, g, vni_mcastgrp_map))
|
||||||
|
return
|
||||||
|
vnisd[v] = g
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error("%s: %s (%s)" %(ifaceobj.name, vlan_vni_map, str(e)))
|
||||||
|
return
|
||||||
|
|
||||||
|
vnis_int = utils.ranges_to_ints(vnis)
|
||||||
|
self.iproute2.bridge_link_update_vni_filter(ifaceobj.name, vnisd)
|
||||||
|
|
||||||
def _up(self, ifaceobj):
|
def _up(self, ifaceobj):
|
||||||
vxlan_id_str = ifaceobj.get_attr_value_first("vxlan-id")
|
vxlan_id_str = ifaceobj.get_attr_value_first("vxlan-id")
|
||||||
@@ -1109,7 +1125,6 @@ class vxlan(Addon, moduleBase):
|
|||||||
if ifaceobj.link_privflags & ifaceLinkPrivFlags.SINGLE_VXLAN:
|
if ifaceobj.link_privflags & ifaceLinkPrivFlags.SINGLE_VXLAN:
|
||||||
if vxlan_vnifilter and utils.get_boolean_from_string(vxlan_vnifilter):
|
if vxlan_vnifilter and utils.get_boolean_from_string(vxlan_vnifilter):
|
||||||
self.single_vxlan_device_vni_filter(ifaceobj)
|
self.single_vxlan_device_vni_filter(ifaceobj)
|
||||||
self.single_vxlan_device_mcast_grp_map_fdb(ifaceobj, ifname, vxlan_mcast_grp_map)
|
|
||||||
|
|
||||||
vxlan_purge_remotes = self.__get_vlxan_purge_remotes(ifaceobj)
|
vxlan_purge_remotes = self.__get_vlxan_purge_remotes(ifaceobj)
|
||||||
|
|
||||||
@@ -1255,6 +1270,49 @@ class vxlan(Addon, moduleBase):
|
|||||||
% (ifname, src_vni, dst_ip, str(e)), raise_error=False
|
% (ifname, src_vni, dst_ip, str(e)), raise_error=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def single_vxlan_device_mcast_grp_map_vnifilter(self, ifaceobj, ifname, vxlan_mcast_grp_map):
|
||||||
|
# in this piece of code we won't be checking the running state of the fdb table
|
||||||
|
# dumping all fdb entries would cause scalability issues in certain cases.
|
||||||
|
|
||||||
|
# pulling old mcastgrp-map configuration
|
||||||
|
old_user_config_fdb = []
|
||||||
|
|
||||||
|
for old_ifaceobj in statemanager.get_ifaceobjs(ifname) or []:
|
||||||
|
old_user_config_fdb += self.get_vxlan_fdb_src_vni(self.__get_vxlan_mcastgrp_map(old_ifaceobj))
|
||||||
|
|
||||||
|
# new user configuration
|
||||||
|
user_config_fdb = self.get_vxlan_fdb_src_vni(vxlan_mcast_grp_map)
|
||||||
|
|
||||||
|
# compare old and new config to know if we should remove any stale fdb entries.
|
||||||
|
fdb_entries_to_remove = set(old_user_config_fdb) - set(user_config_fdb)
|
||||||
|
|
||||||
|
self.logger.info(old_user_config_fdb)
|
||||||
|
self.logger.info(user_config_fdb)
|
||||||
|
self.logger.info(fdb_entries_to_remove)
|
||||||
|
|
||||||
|
if fdb_entries_to_remove:
|
||||||
|
for mac, src_vni, dst_ip in fdb_entries_to_remove:
|
||||||
|
try:
|
||||||
|
self.iproute2.bridge_fdb_del_src_vni(ifname, mac, src_vni)
|
||||||
|
except Exception as e:
|
||||||
|
if "no such file or directory" not in str(e).lower():
|
||||||
|
self.logger.warning("%s: removing stale fdb entries failed: %s" % (ifname, str(e)))
|
||||||
|
|
||||||
|
if not user_config_fdb:
|
||||||
|
# if vxlan-mcastgrp-map wasn't configure return
|
||||||
|
return
|
||||||
|
|
||||||
|
for mac, src_vni, dst_ip in user_config_fdb:
|
||||||
|
try:
|
||||||
|
self.iproute2.bridge_fdb_add_src_vni(ifname, src_vni, dst_ip)
|
||||||
|
except Exception as e:
|
||||||
|
if "file exists" not in str(e).lower():
|
||||||
|
ifaceobj.set_status(ifaceStatus.ERROR)
|
||||||
|
self.log_error(
|
||||||
|
"%s: vxlan-mcastgrp-map: %s=%s: %s"
|
||||||
|
% (ifname, src_vni, dst_ip, str(e)), raise_error=False
|
||||||
|
)
|
||||||
|
|
||||||
def _down(self, ifaceobj):
|
def _down(self, ifaceobj):
|
||||||
try:
|
try:
|
||||||
self.netlink.link_del(ifaceobj.name)
|
self.netlink.link_del(ifaceobj.name)
|
||||||
|
@@ -561,4 +561,18 @@ class utils():
|
|||||||
vnis.extend([vni])
|
vnis.extend([vni])
|
||||||
return (vlans, vnis)
|
return (vlans, vnis)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_vni_mcastgrp_in_map(cls, vni_mcastgrp_map):
|
||||||
|
vnid = {}
|
||||||
|
for ventry in vni_mcastgrp_map.split():
|
||||||
|
try:
|
||||||
|
(vnis, mcastgrp) = ventry.split('=', 1)
|
||||||
|
vnis_int = utils.ranges_to_ints([vnis])
|
||||||
|
for v in vnis_int:
|
||||||
|
vnid[v] = mcastgrp
|
||||||
|
except Exception as e:
|
||||||
|
cls.logger.error("invalid vlan mcast grp map entry - %s (%s)" % (ventry, str(e)))
|
||||||
|
raise
|
||||||
|
return vnid
|
||||||
|
|
||||||
fcntl.fcntl(utils.DEVNULL, fcntl.F_SETFD, fcntl.FD_CLOEXEC)
|
fcntl.fcntl(utils.DEVNULL, fcntl.F_SETFD, fcntl.FD_CLOEXEC)
|
||||||
|
@@ -912,41 +912,107 @@ class IPRoute2(Cache, Requirements):
|
|||||||
self.logger.debug("ip_route_get_dev: failed .. %s" % str(e))
|
self.logger.debug("ip_route_get_dev: failed .. %s" % str(e))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def bridge_vni_add_list(self, vxlandev, vnis):
|
def bridge_vni_update(self, vxlandev, vnisd):
|
||||||
cmd = "%s vni add dev %s vni %s" % (utils.bridge_cmd, vxlandev, ','.join(vnis))
|
for vr, g in vnisd.items():
|
||||||
utils.exec_command(cmd)
|
cmd = "%s vni add dev %s vni %s" % (utils.bridge_cmd, vxlandev, vr)
|
||||||
|
if g:
|
||||||
|
cmd += ' group %s' %(g)
|
||||||
|
utils.exec_command(cmd)
|
||||||
|
|
||||||
def bridge_vni_del_list(self, vxlandev, vnis):
|
def bridge_vni_del_list(self, vxlandev, vnis):
|
||||||
cmd = "%s vni del dev %s vni %s" % (utils.bridge_cmd, vxlandev, ','.join(vnis))
|
cmd = "%s vni del dev %s vni %s" % (utils.bridge_cmd, vxlandev, ','.join(vnis))
|
||||||
utils.exec_command(cmd)
|
utils.exec_command(cmd)
|
||||||
|
|
||||||
def bridge_link_update_vni_filter(self, vxlandev, vnis):
|
def compress_vnifilter_into_ranges(self, vnis_ints, vnisd):
|
||||||
|
vbegin = 0
|
||||||
|
vend = 0
|
||||||
|
vnisd_ranges = {}
|
||||||
|
for v, g in vnisd.items():
|
||||||
|
if v not in vnis_ints:
|
||||||
|
continue
|
||||||
|
if vbegin == 0:
|
||||||
|
vbegin = v
|
||||||
|
vend = v
|
||||||
|
lastg = g
|
||||||
|
continue
|
||||||
|
elif ((v - vend) == 1 and g == lastg):
|
||||||
|
vend = v
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
if vend > vbegin:
|
||||||
|
range = '%d-%d' %(vbegin, vend)
|
||||||
|
vnisd_ranges[range] = lastg
|
||||||
|
else:
|
||||||
|
vnisd_ranges['%s' %vbegin] = lastg
|
||||||
|
vbegin = v
|
||||||
|
vend = v
|
||||||
|
lastg = g
|
||||||
|
|
||||||
|
if vbegin:
|
||||||
|
if vend > vbegin:
|
||||||
|
range = '%d-%d' %(vbegin, vend)
|
||||||
|
vnisd_ranges[range] = lastg
|
||||||
|
else:
|
||||||
|
vnisd_ranges['%s' %vbegin] = lastg
|
||||||
|
return vnisd_ranges
|
||||||
|
|
||||||
|
def print_data(self, lprefix, data):
|
||||||
|
self.logger.info(lprefix)
|
||||||
|
self.logger.info(data)
|
||||||
|
|
||||||
|
def bridge_link_update_vni_filter(self, vxlandev, vnisd):
|
||||||
try:
|
try:
|
||||||
rvnis = []
|
rvnisd = {}
|
||||||
cmd = 'bridge -j -p vni show dev %s' %( vxlandev )
|
cmd = 'bridge -j -p vni show dev %s' %( vxlandev )
|
||||||
output = utils.exec_command(cmd)
|
output = utils.exec_command(cmd)
|
||||||
if output:
|
if output:
|
||||||
vnishow = json.loads(output.strip("\n"))
|
vnishow = json.loads(output.strip("\n"))
|
||||||
|
self.logger.debug(vnishow)
|
||||||
for s in vnishow:
|
for s in vnishow:
|
||||||
vlist = s.get('vnis')
|
vlist = s.get('vnis')
|
||||||
rvnis = []
|
|
||||||
for v in vlist:
|
for v in vlist:
|
||||||
vstart = v.get('vni')
|
vstart = v.get('vni')
|
||||||
vend = v.get('vniEnd')
|
vend = v.get('vniEnd')
|
||||||
|
group = v.get('group')
|
||||||
if vend:
|
if vend:
|
||||||
rvnis.extend(['%s-%s' %(vstart,vend)])
|
for tv in range(int(vstart), int(vend)+1):
|
||||||
|
if group:
|
||||||
|
rvnisd[tv] = group
|
||||||
|
else:
|
||||||
|
rvnisd[tv] = None
|
||||||
else:
|
else:
|
||||||
rvnis.extend([str(vstart)])
|
if group:
|
||||||
vnis_int = utils.ranges_to_ints(vnis)
|
rvnisd[int(vstart)] = group
|
||||||
rvnis_int = utils.ranges_to_ints(rvnis)
|
else:
|
||||||
|
rvnisd[int(vstart)] = None
|
||||||
|
vnis_int = vnisd.keys()
|
||||||
|
rvnis_int = rvnisd.keys()
|
||||||
(vnis_to_del, vnis_to_add) = utils.diff_ids(vnis_int,
|
(vnis_to_del, vnis_to_add) = utils.diff_ids(vnis_int,
|
||||||
rvnis_int)
|
rvnis_int)
|
||||||
if vnis_to_del:
|
if vnis_to_del:
|
||||||
self.bridge_vni_del_list(vxlandev,
|
self.bridge_vni_del(vxlandev,
|
||||||
utils.compress_into_ranges(vnis_to_del))
|
utils.compress_into_ranges(vnis_to_del))
|
||||||
if vnis_to_add:
|
if vnis_to_add:
|
||||||
self.bridge_vni_add_list(vxlandev,
|
self.bridge_vni_update(vxlandev,
|
||||||
utils.compress_into_ranges(vnis_to_add))
|
self.compress_vnifilter_into_ranges(vnis_to_add, vnisd))
|
||||||
|
|
||||||
|
# Do any vnis need group update ?
|
||||||
|
# check remaining vnis
|
||||||
|
vnis_rem = set(vnis_int)
|
||||||
|
if vnis_to_add:
|
||||||
|
vnis_rem = vnis_rem.difference(set(vnis_to_add))
|
||||||
|
if vnis_to_del:
|
||||||
|
vnis_rem = vnis_rem.difference(set(vnis_to_del))
|
||||||
|
vnis_rem = list(vnis_rem)
|
||||||
|
vnis_to_update = []
|
||||||
|
if vnis_rem:
|
||||||
|
for v in vnis_rem:
|
||||||
|
# check if group is not same
|
||||||
|
if vnisd.get(v) != rvnisd.get(v):
|
||||||
|
vnis_to_update.append(v)
|
||||||
|
if vnis_to_update:
|
||||||
|
self.bridge_vni_update(vxlandev,
|
||||||
|
self.compress_vnifilter_into_ranges(vnis_to_update, vnisd))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.info("bridge vni show failed .. %s" % str(e))
|
self.logger.info("bridge vni show failed .. %s" % str(e))
|
||||||
return None
|
return None
|
||||||
|
Reference in New Issue
Block a user