[bgpcfgd]: Generate set src configuration dynamically (#4273)

* [bgpcfgd]: Generate set src configuration dynamically

Sometimes zebra starts faster then swss configures Loopback0
In this case "set src" inside of the route map will not be
inserted to the configuration because zebra doesn't see Loopback
ips in the list of available ip addresses.

I've added extra logic to push the "set src" configuration only
when Loopback has been configured by swss.
This commit is contained in:
pavel-shirshov 2020-03-18 08:48:03 -07:00 committed by GitHub
parent 6c48a3f113
commit a881a23908
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 48 additions and 51 deletions

View File

@ -78,6 +78,8 @@ class BGPConfigManager(object):
def __init__(self, daemon): def __init__(self, daemon):
self.bgp_asn = None self.bgp_asn = None
self.meta = None self.meta = None
self.lo_ipv4 = None
self.lo_ipv6 = None
self.neig_meta = {} self.neig_meta = {}
self.bgp_messages = [] self.bgp_messages = []
self.peers = self.load_peers() # we can have bgp monitors peers here. it could be fixed by adding support for it here self.peers = self.load_peers() # we can have bgp monitors peers here. it could be fixed by adding support for it here
@ -86,9 +88,11 @@ class BGPConfigManager(object):
self.bgp_peer_del_template = fabric.from_string('no neighbor {{ neighbor_addr }}') self.bgp_peer_del_template = fabric.from_string('no neighbor {{ neighbor_addr }}')
self.bgp_peer_shutdown = fabric.from_string('neighbor {{ neighbor_addr }} shutdown') self.bgp_peer_shutdown = fabric.from_string('neighbor {{ neighbor_addr }} shutdown')
self.bgp_peer_no_shutdown = fabric.from_string('no neighbor {{ neighbor_addr }} shutdown') self.bgp_peer_no_shutdown = fabric.from_string('no neighbor {{ neighbor_addr }} shutdown')
self.zebra_set_src_template = fabric.from_file('zebra.set_src.conf.j2')
daemon.add_manager(swsscommon.CONFIG_DB, swsscommon.CFG_DEVICE_METADATA_TABLE_NAME, self.__metadata_handler) daemon.add_manager(swsscommon.CONFIG_DB, swsscommon.CFG_DEVICE_METADATA_TABLE_NAME, self.__metadata_handler)
daemon.add_manager(swsscommon.CONFIG_DB, swsscommon.CFG_DEVICE_NEIGHBOR_METADATA_TABLE_NAME, self.__neighbor_metadata_handler) daemon.add_manager(swsscommon.CONFIG_DB, swsscommon.CFG_DEVICE_NEIGHBOR_METADATA_TABLE_NAME, self.__neighbor_metadata_handler)
daemon.add_manager(swsscommon.CONFIG_DB, swsscommon.CFG_BGP_NEIGHBOR_TABLE_NAME, self.__bgp_handler) daemon.add_manager(swsscommon.CONFIG_DB, swsscommon.CFG_BGP_NEIGHBOR_TABLE_NAME, self.__bgp_handler)
daemon.add_manager(swsscommon.STATE_DB, swsscommon.STATE_INTERFACE_TABLE_NAME, self.__if_handler)
def load_peers(self): def load_peers(self):
peers = set() peers = set()
@ -136,6 +140,35 @@ class BGPConfigManager(object):
syslog.syslog(syslog.LOG_ERR,"Wrong operation '%s' for neighbor metadata handler" % op) syslog.syslog(syslog.LOG_ERR,"Wrong operation '%s' for neighbor metadata handler" % op)
self.__update_bgp() self.__update_bgp()
def __if_handler(self, key, op, data):
cmds = []
if op == swsscommon.SET_COMMAND and key.startswith("Loopback0|") and "state" in data and data["state"] == "ok":
ip_addr_w_mask = key.replace("Loopback0|", "")
slash_pos = ip_addr_w_mask.rfind("/")
if slash_pos == -1:
syslog.syslog(syslog.LOG_ERR, "Wrong Loopback0 ip address'%s'" % ip_addr_w_mask)
return
ip_addr = ip_addr_w_mask[:slash_pos]
try:
if TemplateFabric.is_ipv4(ip_addr) and self.lo_ipv4 is None:
self.lo_ipv4 = ip_addr
txt = self.zebra_set_src_template.render(rm_name="RM_SET_SRC", lo_ip=ip_addr, ip_proto="")
elif TemplateFabric.is_ipv6(ip_addr) and self.lo_ipv6 is None:
self.lo_ipv6 = ip_addr
txt = self.zebra_set_src_template.render(rm_name="RM_SET_SRC6", lo_ip=ip_addr, ip_proto="v6")
else:
syslog.syslog(syslog.LOG_ERR, "Got ambigous ip addres '%s'" % ip_addr)
except:
syslog.syslog(syslog.LOG_ERR, "Error while rendering set src template" % ip_addr)
else:
cmds.append(txt)
syslog.syslog(syslog.LOG_INFO, "Generate set src configuration with Loopback0 ipv4 '%s'" % ip_addr)
elif op == swsscommon.DEL_COMMAND:
syslog.syslog(syslog.LOG_INFO, "Delete command is not supported for set src templates" % ip_addr)
for cmd in cmds:
self.__apply_cmd(cmd, zebra=True)
def __update_bgp(self): def __update_bgp(self):
cmds = [] cmds = []
new_bgp_messages = [] new_bgp_messages = []
@ -180,7 +213,7 @@ class BGPConfigManager(object):
for cmd in cmds: for cmd in cmds:
self.__apply_cmd(cmd) self.__apply_cmd(cmd)
def __apply_cmd(self, cmd): def __apply_cmd(self, cmd, zebra=False):
lines = [line for line in cmd.split("\n") if not line.startswith('!') and line.strip() != ""] lines = [line for line in cmd.split("\n") if not line.startswith('!') and line.strip() != ""]
if len(lines) == 0: if len(lines) == 0:
return return
@ -198,7 +231,11 @@ class BGPConfigManager(object):
chunks.pop() chunks.pop()
chunks.append(line.strip()) chunks.append(line.strip())
command = ["vtysh", "-c", "conf t", "-c", "router bgp %s" % self.bgp_asn] command = ["vtysh", "-c", "conf t"]
if not zebra:
command.append("-c")
command.append("router bgp %s" % self.bgp_asn)
for chunk in chunks: for chunk in chunks:
command.append("-c") command.append("-c")
command.append(chunk) command.append(chunk)
@ -213,7 +250,7 @@ class BGPConfigManager(object):
class Daemon(object): class Daemon(object):
SELECT_TIMEOUT = 1000 SELECT_TIMEOUT = 1000
DATABASE_LIST = [ swsscommon.CONFIG_DB ] DATABASE_LIST = [ swsscommon.CONFIG_DB, swsscommon.STATE_DB ]
def __init__(self): def __init__(self):
self.db_connectors = { db : swsscommon.DBConnector(db, swsscommon.DBConnector.DEFAULT_UNIXSOCKET, 0) for db in Daemon.DATABASE_LIST } self.db_connectors = { db : swsscommon.DBConnector(db, swsscommon.DBConnector.DEFAULT_UNIXSOCKET, 0) for db in Daemon.DATABASE_LIST }

View File

@ -35,41 +35,6 @@ ip route 0.0.0.0/0 {{ MGMT_INTERFACE[(name, prefix)]['gwaddr'] }} 200
{% endfor %} {% endfor %}
{% endblock default_route %} {% endblock default_route %}
! !
{% block source_loopback %}
{% set lo_ipv4_addrs = [] %}
{% set lo_ipv6_addrs = [] %}
{% if LOOPBACK_INTERFACE %}
{% for (name, prefix) in LOOPBACK_INTERFACE %}
{% if name == 'Loopback0' %}
{% if prefix | ipv6 %}
{% if lo_ipv6_addrs.append(prefix) %}
{% endif %}
{% else %}
{% if lo_ipv4_addrs.append(prefix) %}
{% endif %}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
! Set ip source to loopback for bgp learned routes
{% if lo_ipv4_addrs|length > 0 -%}
route-map RM_SET_SRC permit 10
set src {{ lo_ipv4_addrs[0] | ip }}
!
{% endif %}
{% if lo_ipv6_addrs|length > 0 %}
route-map RM_SET_SRC6 permit 10
set src {{ lo_ipv6_addrs[0] | ip }}
!
{% endif %}
ip protocol bgp route-map RM_SET_SRC
!
{% if lo_ipv6_addrs|length > 0 %}
ipv6 protocol bgp route-map RM_SET_SRC6
!
{% endif %}
{% endblock source_loopback %}
!
{% block logging %} {% block logging %}
log syslog informational log syslog informational
log facility local4 log facility local4

View File

@ -0,0 +1,8 @@
!
! Set ip source to loopback for bgp learned routes
!
route-map {{ rm_name }} permit 10
set src {{ lo_ip }}
!
ip{{ ip_proto }} protocol bgp route-map {{ rm_name }}
!

View File

@ -25,19 +25,6 @@ link-detect
! set static default route to mgmt gateway as a backup to learned default ! set static default route to mgmt gateway as a backup to learned default
ip route 0.0.0.0/0 10.0.0.1 200 ip route 0.0.0.0/0 10.0.0.1 200
! !
! Set ip source to loopback for bgp learned routes
route-map RM_SET_SRC permit 10
set src 10.1.0.32
!
route-map RM_SET_SRC6 permit 10
set src fc00:1::32
!
ip protocol bgp route-map RM_SET_SRC
!
ipv6 protocol bgp route-map RM_SET_SRC6
!
!
log syslog informational log syslog informational
log facility local4 log facility local4
! !