Skip to content

Commit ea38d06

Browse files
authored
Fixbug: EVPN issue in FRR template (#4260)
* Fixbug: EVPN issue in FRR template
1 parent 8585005 commit ea38d06

File tree

2 files changed

+156
-2
lines changed

2 files changed

+156
-2
lines changed

dockers/docker-fpm-frr/bgpcfgd

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,8 @@ class BGPPeerMgr(Manager):
272272
[
273273
("meta", "localhost/bgp_asn"),
274274
("neigmeta", ""),
275+
("local_addresses", ""),
276+
("interfaces", ""),
275277
],
276278
"CONFIG_DB",
277279
swsscommon.CFG_BGP_NEIGHBOR_TABLE_NAME
@@ -290,8 +292,42 @@ class BGPPeerMgr(Manager):
290292
vrf, nbr = key.split('|', 1)
291293
if key not in self.peers:
292294
cmd = None
295+
296+
if "local_addr" not in data:
297+
syslog.syslog(syslog.LOG_WARNING, 'Peer {}. Error in missing required attribute "local_addr"'.format(key))
298+
else:
299+
# The bgp session that belongs to a vnet cannot be advertised as the default BGP session.
300+
# So we need to check whether this bgp session belongs to a vnet.
301+
interface = InterfaceMgr.get_local_interface(self.directory, data["local_addr"])
302+
if not interface:
303+
syslog.syslog(syslog.LOG_INFO,
304+
'Peer {} with local address {} wait for the corresponding interface to be set'.format(
305+
key,
306+
data["local_addr"]
307+
)
308+
)
309+
return False
310+
vnet = InterfaceMgr.get_vnet(interface)
311+
if vnet:
312+
# Ignore the bgp session that is in a vnet
313+
syslog.syslog(
314+
syslog.LOG_INFO,
315+
'Ignore the BGP peer {} as the interface {} is in vnet {}'.format(
316+
key,
317+
interface,
318+
vnet
319+
)
320+
)
321+
return True
322+
293323
neigmeta = self.directory.get_slot("neigmeta")
294324
if 'name' in data and data["name"] not in neigmeta:
325+
syslog.syslog(syslog.LOG_INFO,
326+
'Peer {} with neighbor name {} wait for the corresponding neighbor metadata to be set'.format(
327+
key,
328+
data["name"]
329+
)
330+
)
295331
return False
296332
try:
297333
cmd = self.templates["add"].render(
@@ -390,6 +426,121 @@ class BGPPeerMgr(Manager):
390426
return peers
391427

392428

429+
class InterfaceMgr(Manager):
430+
def __init__(self, daemon, directory, interface_table = swsscommon.CFG_INTF_TABLE_NAME):
431+
super(InterfaceMgr, self).__init__(
432+
daemon,
433+
directory,
434+
[],
435+
"CONFIG_DB",
436+
interface_table
437+
)
438+
439+
def set_handler(self, key, data):
440+
# Interface table can have two keys,
441+
# one with ip prefix and one without ip prefix
442+
if '|' in key:
443+
data = {}
444+
data["interface"], network = key.split('|', 1)
445+
try:
446+
network = netaddr.IPNetwork(str(network))
447+
except:
448+
syslog.syslog(
449+
syslog.LOG_WARNING,
450+
'Subnet {} format is wrong for interface {}'.format(
451+
network,
452+
data["interface"]
453+
)
454+
)
455+
return False
456+
data["prefixlen"] = str(network.prefixlen)
457+
ip = str(network.ip)
458+
self.directory.put("local_addresses", ip, data)
459+
else:
460+
self.directory.put("interfaces", key, data)
461+
return True
462+
463+
def del_handler(self, key):
464+
if '|' in key:
465+
interface, network = key.split('|', 1)
466+
try:
467+
network = netaddr.IPNetwork(str(network))
468+
except:
469+
syslog.syslog(
470+
syslog.LOG_WARNING,
471+
'Subnet {} format is wrong for interface {}'.format(
472+
network,
473+
interface
474+
)
475+
)
476+
return False
477+
ip = str(network.ip)
478+
self.directory.remove("local_addresses", ip)
479+
else:
480+
self.directory.remove("interfaces", key)
481+
482+
@staticmethod
483+
def get_local_interface(directory, local_addr):
484+
"""
485+
@summary: Get interface according to the local address from the directory
486+
@param directory: Directory object that stored metadata of interfaces
487+
@param local_addr: Local address of the interface
488+
@return: Return the metadata of the interface with the local address
489+
If the interface has not been set, return None
490+
"""
491+
local_addresses = directory.get_slot("local_addresses")
492+
# Check if the local address of this bgp session has been set
493+
if local_addr not in local_addresses:
494+
return None
495+
local_address = local_addresses[local_addr]
496+
interfaces = directory.get_slot("interfaces")
497+
# Check if the information for the interface of this local address has been set
498+
if local_address.has_key("interface") and local_address["interface"] in interfaces:
499+
return interfaces[local_address["interface"]]
500+
else:
501+
return None
502+
503+
@staticmethod
504+
def get_vnet(interface):
505+
"""
506+
@summary: Get the VNet name of the interface
507+
@param interface: The metadata of the interface
508+
@return: Return the vnet name of the interface if this interface belongs to a vnet,
509+
Otherwise return None
510+
"""
511+
if interface.has_key("vnet_name") and interface["vnet_name"]:
512+
return interface["vnet_name"]
513+
else:
514+
return None
515+
516+
517+
class LoopbackInterfaceMgr(InterfaceMgr):
518+
def __init__(self, daemon, directory):
519+
super(LoopbackInterfaceMgr, self).__init__(
520+
daemon,
521+
directory,
522+
swsscommon.CFG_LOOPBACK_INTERFACE_TABLE_NAME
523+
)
524+
525+
526+
class VlanInterfaceMgr(InterfaceMgr):
527+
def __init__(self, daemon, directory):
528+
super(VlanInterfaceMgr, self).__init__(
529+
daemon,
530+
directory,
531+
swsscommon.CFG_VLAN_INTF_TABLE_NAME
532+
)
533+
534+
535+
class PortChannelInterfaceMgr(InterfaceMgr):
536+
def __init__(self, daemon, directory):
537+
super(PortChannelInterfaceMgr, self).__init__(
538+
daemon,
539+
directory,
540+
swsscommon.CFG_LAG_INTF_TABLE_NAME
541+
)
542+
543+
393544
def wait_for_bgpd():
394545
# wait for 20 seconds
395546
stop_time = datetime.datetime.now() + datetime.timedelta(seconds=20)
@@ -408,6 +559,10 @@ def main():
408559
BGPDeviceMetaMgr,
409560
BGPNeighborMetaMgr,
410561
BGPPeerMgr,
562+
InterfaceMgr,
563+
LoopbackInterfaceMgr,
564+
VlanInterfaceMgr,
565+
PortChannelInterfaceMgr,
411566
]
412567
wait_for_bgpd()
413568
daemon = Daemon()

dockers/docker-fpm-frr/bgpd.peer.conf.j2

100644100755
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@
2626
neighbor {{ neighbor_addr }} next-hop-self
2727
{% endif %}
2828
{% if bgp_session["asn"] == DEVICE_METADATA['localhost']['bgp_asn']
29-
and DEVICE_METADATA['localhost']['type'] == "SpineChassisFrontendRouter"
30-
and (not bgp_session.has_key("local_addr") or bgp_session["local_addr"] not in interfaces_in_vnets) %}
29+
and DEVICE_METADATA['localhost']['type'] == "SpineChassisFrontendRouter" %}
3130
address-family l2vpn evpn
3231
neighbor {{ neighbor_addr }} activate
3332
advertise-all-vni

0 commit comments

Comments
 (0)