[bgpcfgd]: Split default bgp config into main config and peer template (#3627)

Now it's possible to add and remove peers based on ConfigDB

- What I did
Fixed functionality for dynamically adding/removing static bgp peers.

- How I did it

Split the bgp default template on bgp part and bgp peer part
Changed bgpcfgd to use 1.

- How to verify it

Build an image and run on your DUT
This commit is contained in:
pavel-shirshov 2019-10-24 07:35:14 -07:00 committed by lguohan
parent e883d35ce1
commit 8457248d01
23 changed files with 581 additions and 749 deletions

View File

@ -1,124 +1,250 @@
#!/usr/bin/env python
import sys
import copy
import Queue
import redis
import subprocess
import datetime
import time
import syslog
import signal
import traceback
import os
import shutil
import tempfile
import json
from collections import defaultdict
from pprint import pprint
import jinja2
import netaddr
from swsscommon import swsscommon
def run_command(command):
syslog.syslog(syslog.LOG_DEBUG, "execute command {}.".format(command))
p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
stdout = p.communicate()[0]
p.wait()
g_run = True
g_debug = False
def run_command(command, shell=False):
str_cmd = " ".join(command)
if g_debug:
syslog.syslog(syslog.LOG_DEBUG, "execute command {}.".format(str_cmd))
p = subprocess.Popen(command, shell=shell, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
if p.returncode != 0:
syslog.syslog(syslog.LOG_ERR, 'command execution returned {}. Command: "{}", stdout: "{}"'.format(p.returncode, command, stdout))
syslog.syslog(syslog.LOG_ERR, 'command execution returned {}. Command: "{}", stdout: "{}", stderr: "{}"'.format(p.returncode, str_cmd, stdout, stderr))
return p.returncode, stdout, stderr
class TemplateFabric(object):
def __init__(self):
j2_template_paths = ['/usr/share/sonic/templates']
j2_loader = jinja2.FileSystemLoader(j2_template_paths)
j2_env = jinja2.Environment(loader=j2_loader, trim_blocks=True)
j2_env.filters['ipv4'] = self.is_ipv4
j2_env.filters['ipv6'] = self.is_ipv6
self.env = j2_env
def from_file(self, filename):
return self.env.get_template(filename)
def from_string(self, tmpl):
return self.env.from_string(tmpl)
@staticmethod
def is_ipv4(value):
if not value:
return False
if isinstance(value, netaddr.IPNetwork):
addr = value
else:
try:
addr = netaddr.IPNetwork(str(value))
except:
return False
return addr.version == 4
@staticmethod
def is_ipv6(value):
if not value:
return False
if isinstance(value, netaddr.IPNetwork):
addr = value
else:
try:
addr = netaddr.IPNetwork(str(value))
except:
return False
return addr.version == 6
class BGPConfigManager(object):
def __init__(self, daemon):
self.daemon = daemon
self.bgp_asn = None
self.bgp_message = Queue.Queue(0)
self.meta = None
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
fabric = TemplateFabric()
self.bgp_peer_add_template = fabric.from_file('bgpd.peer.conf.j2')
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_no_shutdown = fabric.from_string('no neighbor {{ neighbor_addr }} shutdown')
daemon.add_manager(swsscommon.CONFIG_DB, swsscommon.CFG_DEVICE_METADATA_TABLE_NAME, self.__metadata_handler)
daemon.add_manager(swsscommon.CONFIG_DB, swsscommon.CFG_BGP_NEIGHBOR_TABLE_NAME, self.__bgp_handler)
def load_peers(self):
peers = set()
command = ["vtysh", "-c", "show bgp neighbors json"]
rc, out, err = run_command(command)
if rc == 0:
js_bgp = json.loads(out)
peers = set(js_bgp.keys())
return peers
def __metadata_handler(self, key, op, data):
if key != "localhost" \
or "bgp_asn" not in data \
or self.bgp_asn == data["bgp_asn"]:
return
# TODO add ASN update commands
# TODO add ASN update commands
self.meta = { 'localhost': data }
self.bgp_asn = data["bgp_asn"]
self.__update_bgp()
def __update_bgp(self):
while not self.bgp_message.empty():
key, op, data = self.bgp_message.get()
syslog.syslog(syslog.LOG_INFO, 'value for {} changed to {}'.format(key, data))
cmds = []
for key, op, data in self.bgp_messages:
if op == swsscommon.SET_COMMAND:
command = "vtysh -c 'configure terminal' -c 'router bgp {}' -c 'neighbor {} remote-as {}'".format(self.bgp_asn, key, data['asn'])
run_command(command)
if "name" in data:
command = "vtysh -c 'configure terminal' -c 'router bgp {}' -c 'neighbor {} description {}'".format(self.bgp_asn, key, data['name'])
run_command(command)
if "admin_status" in data:
command_mod = "no " if data["admin_status"] == "up" else ""
command = "vtysh -c 'configure terminal' -c 'router bgp {}' -c '{}neighbor {} shutdown'".format(self.bgp_asn, command_mod, key)
run_command(command)
if key not in self.peers:
cmds.append(self.bgp_peer_add_template.render(DEVICE_METADATA=self.meta, neighbor_addr=key, bgp_session=data))
syslog.syslog(syslog.LOG_INFO, 'Peer {} added with attributes {}'.format(key, data))
self.peers.add(key)
else:
# when the peer is already configured we support "shutdown/no shutdown"
# commands for the peers only
if "admin_status" in data:
if data['admin_status'] == 'up':
cmds.append(self.bgp_peer_no_shutdown.render(neighbor_addr=key))
syslog.syslog(syslog.LOG_INFO, 'Peer {} admin state is set to "up"'.format(key))
elif data['admin_status'] == 'down':
cmds.append(self.bgp_peer_shutdown.render(neighbor_addr=key))
syslog.syslog(syslog.LOG_INFO, 'Peer {} admin state is set to "down"'.format(key))
else:
syslog.syslog(syslog.LOG_ERR, "Peer {}: Can't update the peer. has wrong attribute value attr['admin_status'] = '{}'".format(key, data['admin_status']))
else:
syslog.syslog(syslog.LOG_INFO, "Peer {}: Can't update the peer. No 'admin_status' attribute in the request".format(key))
elif op == swsscommon.DEL_COMMAND:
# Neighbor is deleted
command = "vtysh -c 'configure terminal' -c 'router bgp {}' -c 'no neighbor {}'".format(self.bgp_asn, key)
run_command(command)
if key in self.peers:
cmds.append(self.bgp_peer_del_template.render(neighbor_addr=key))
syslog.syslog(syslog.LOG_INFO, 'Peer {} has been removed'.format(key))
self.peers.remove(key)
else:
syslog.syslog(syslog.LOG_WARNING, 'Peer {} is not found'.format(key))
self.bgp_messages = []
if len(cmds) == 0:
return
fd, tmp_filename = tempfile.mkstemp(dir='/tmp')
os.close(fd)
with open (tmp_filename, 'w') as fp:
fp.write('router bgp %s\n' % self.bgp_asn)
for cmd in cmds:
fp.write("%s\n" % cmd)
command = ["vtysh", "-f", tmp_filename]
run_command(command) #FIXME
os.remove(tmp_filename)
def __bgp_handler(self, key, op, data):
self.bgp_message.put((key, op, data))
self.bgp_messages.append((key, op, data))
# If ASN is not set, we just cache this message until the ASN is set.
if self.bgp_asn == None:
return
self.__update_bgp()
if self.bgp_asn is not None:
self.__update_bgp()
class Daemon(object):
SELECT_TIMEOUT = 1000
SUPPORT_DATABASE_LIST = (swsscommon.APPL_DB, swsscommon.CONFIG_DB)
DATABASE_LIST = [ swsscommon.CONFIG_DB ]
def __init__(self):
self.appl_db = swsscommon.DBConnector(swsscommon.APPL_DB, swsscommon.DBConnector.DEFAULT_UNIXSOCKET, 0)
self.conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, swsscommon.DBConnector.DEFAULT_UNIXSOCKET, 0)
self.db_connectors = { db : swsscommon.DBConnector(db, swsscommon.DBConnector.DEFAULT_UNIXSOCKET, 0) for db in Daemon.DATABASE_LIST }
self.selector = swsscommon.Select()
self.db_connectors = {}
self.callbacks = {}
self.callbacks = defaultdict(lambda : defaultdict(list)) # db -> table -> []
self.subscribers = set()
def get_db_connector(self, db):
if db not in Daemon.SUPPORT_DATABASE_LIST:
raise ValueError("database {} not Daemon support list {}.".format(db, SUPPORT_DATABASE_LIST))
# if this database connector has been initialized
if db not in self.db_connectors:
self.db_connectors[db] = swsscommon.DBConnector(db, swsscommon.DBConnector.DEFAULT_UNIXSOCKET, 0)
return self.db_connectors[db]
def add_manager(self, db, table_name, callback):
if db not in self.callbacks:
self.callbacks[db] = {}
if db not in Daemon.DATABASE_LIST:
raise ValueError("database {} isn't supported. Supported '{}' only.".format(db, ",".join(Daemon.DATABASE_LIST)))
if table_name not in self.callbacks[db]:
self.callbacks[db][table_name] = []
conn = self.get_db_connector(db)
conn = self.db_connectors[db]
subscriber = swsscommon.SubscriberStateTable(conn, table_name)
self.subscribers.add(subscriber)
self.selector.addSelectable(subscriber)
self.callbacks[db][table_name].append(callback)
def start(self):
while True:
state, selectable = self.selector.select(Daemon.SELECT_TIMEOUT)
if not selectable:
def run(self):
while g_run:
state, _ = self.selector.select(Daemon.SELECT_TIMEOUT)
if state == self.selector.TIMEOUT:
continue
elif state == self.selector.ERROR:
raise Exception("Received error from select")
for subscriber in self.subscribers:
key, op, fvs = subscriber.pop()
# if no new message
if not key:
continue
data = dict(fvs)
syslog.syslog(syslog.LOG_DEBUG, "Receive message : {}".format((key, op, fvs)))
if g_debug:
syslog.syslog(syslog.LOG_DEBUG, "Received message : {}".format((key, op, fvs)))
for callback in self.callbacks[subscriber.getDbConnector().getDbId()][subscriber.getTableName()]:
callback(key, op, data)
callback(key, op, dict(fvs))
def wait_for_bgpd():
# wait for 20 seconds
stop_time = datetime.datetime.now() + datetime.timedelta(seconds=20)
syslog.syslog(syslog.LOG_INFO, "Start waiting for bgpd: %s" % str(datetime.datetime.now()))
while datetime.datetime.now() < stop_time:
rc, out, err = run_command(["vtysh", "-c", "show daemons"])
if rc == 0 and "bgpd" in out:
syslog.syslog(syslog.LOG_INFO, "bgpd connected to vtysh: %s" % str(datetime.datetime.now()))
return
time.sleep(0.1) # sleep 100 ms
raise RuntimeError("bgpd hasn't been started in 20 seconds")
def main():
syslog.openlog("bgpcfgd")
wait_for_bgpd()
daemon = Daemon()
bgp_manager = BGPConfigManager(daemon)
daemon.start()
syslog.closelog()
daemon.run()
if __name__ == "__main__":
main()
def signal_handler(signum, frame):
global g_run
g_run = False
if __name__ == '__main__':
rc = 0
try:
syslog.openlog('bgpcfgd')
signal.signal(signal.SIGTERM, signal_handler)
signal.signal(signal.SIGINT, signal_handler)
main()
except KeyboardInterrupt:
syslog.syslog(syslog.LOG_NOTICE, "Keyboard interrupt")
except RuntimeError as e:
syslog.syslog(syslog.LOG_CRIT, "%s" % str(e))
rc = -2
except Exception as e:
syslog.syslog(syslog.LOG_CRIT, "Got an exception %s: Traceback: %s" % (str(e), traceback.format_exc()))
rc = -1
finally:
syslog.closelog()
try:
sys.exit(rc)
except SystemExit:
os._exit(rc)

View File

@ -1,3 +1,4 @@
!
{% if DEVICE_METADATA['localhost'].has_key('bgp_asn') %}
{% block bgp_init %}
!
@ -12,7 +13,7 @@ route-map TO_BGP_SPEAKER_V4 deny 10
{% if prefix | ipv4 and name == 'Loopback0' %}
ip prefix-list PL_LoopbackV4 permit {{ prefix | ip }}/32
{% elif prefix | ipv6 and name == 'Loopback0' %}
ipv6 prefix-list PL_LoopbackV6 permit {{ prefix | ip }}/64
ipv6 prefix-list PL_LoopbackV6 permit {{ prefix | replace('/128', '/64') | ip_network }}/64
{% endif %}
{% endfor %}
!
@ -28,6 +29,13 @@ route-map FROM_BGPMON_V4 deny 10
route-map TO_BGPMON_V4 permit 10
!
{% endif %}
!
route-map ISOLATE permit 10
set as-path prepend {{ DEVICE_METADATA['localhost']['bgp_asn'] }}
!
route-map set-next-hop-global-v6 permit 10
set ipv6 next-hop prefer-global
!
router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }}
bgp log-neighbor-changes
bgp bestpath as-path multipath-relax
@ -65,63 +73,32 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }}
{% endif %}
{% endfor %}
{% endblock vlan_advertisement %}
{% block bgp_sessions %}
{% for neighbor_addr, bgp_session in BGP_NEIGHBOR.iteritems() %}
{% if bgp_session['asn'] | int != 0 %}
neighbor {{ neighbor_addr }} remote-as {{ bgp_session['asn'] }}
neighbor {{ neighbor_addr }} description {{ bgp_session['name'] }}
{# set the bgp neighbor timers if they have not default values #}
{% if (bgp_session['keepalive'] is defined and bgp_session['keepalive'] | int != 60)
or (bgp_session['holdtime'] is defined and bgp_session['holdtime'] | int != 180) %}
neighbor {{ neighbor_addr }} timers {{ bgp_session['keepalive'] }} {{ bgp_session['holdtime'] }}
{% endif %}
{% if bgp_session.has_key('admin_status') and bgp_session['admin_status'] == 'down' or not bgp_session.has_key('admin_status') and DEVICE_METADATA['localhost'].has_key('default_bgp_status') and DEVICE_METADATA['localhost']['default_bgp_status'] == 'down' %}
neighbor {{ neighbor_addr }} shutdown
{% endif %}
{# Apply default route-map for v4 peers #}
{% if neighbor_addr | ipv4 %}
neighbor {{ neighbor_addr }} route-map TO_BGP_PEER_V4 out
{% endif %}
{% if neighbor_addr | ipv4 %}
{% block maximum_paths %}
address-family ipv4
maximum-paths 64
exit-address-family
address-family ipv6
maximum-paths 64
exit-address-family
{% endblock maximum_paths %}
{% block peers_peer_group %}
neighbor PEER_V4 peer-group
neighbor PEER_V6 peer-group
address-family ipv4
{% if DEVICE_METADATA['localhost']['type'] == 'ToRRouter' %}
neighbor {{ neighbor_addr }} allowas-in 1
neighbor PEER_V4 allowas-in 1
{% endif %}
neighbor {{ neighbor_addr }} activate
neighbor {{ neighbor_addr }} soft-reconfiguration inbound
{% if bgp_session['rrclient'] | int != 0 %}
neighbor {{ neighbor_addr }} route-reflector-client
{% endif %}
{% if bgp_session['nhopself'] | int != 0 %}
neighbor {{ neighbor_addr }} next-hop-self
{% endif %}
maximum-paths 64
neighbor PEER_V4 soft-reconfiguration inbound
neighbor PEER_V4 route-map TO_BGP_PEER_V4 out
exit-address-family
{% endif %}
{% if neighbor_addr | ipv6 %}
address-family ipv6
{% if DEVICE_METADATA['localhost']['type'] == 'ToRRouter' %}
neighbor {{ neighbor_addr }} allowas-in 1
neighbor PEER_V6 allowas-in 1
{% endif %}
neighbor {{ neighbor_addr }} activate
neighbor {{ neighbor_addr }} soft-reconfiguration inbound
{% if bgp_session['rrclient'] | int != 0 %}
neighbor {{ neighbor_addr }} route-reflector-client
{% endif %}
{% if bgp_session['nhopself'] | int != 0 %}
neighbor {{ neighbor_addr }} next-hop-self
{% endif %}
{% if bgp_session['asn'] != DEVICE_METADATA['localhost']['bgp_asn'] %}
neighbor {{ neighbor_addr }} route-map set-next-hop-global-v6 in
{% endif %}
{# Apply default route-map for v6 peers #}
neighbor {{ neighbor_addr }} route-map TO_BGP_PEER_V6 out
maximum-paths 64
neighbor PEER_V6 soft-reconfiguration inbound
neighbor PEER_V6 route-map TO_BGP_PEER_V6 out
exit-address-family
{% endif %}
{% endif %}
{% endfor %}
{% endblock bgp_sessions %}
{% endblock peers_peer_group %}
{% block bgp_peers_with_range %}
{% if BGP_PEER_RANGE %}
{% for bgp_peer in BGP_PEER_RANGE.values() %}
@ -150,11 +127,9 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }}
{% endfor %}
address-family ipv4
neighbor {{ bgp_peer['name'] }} activate
maximum-paths 64
exit-address-family
address-family ipv6
neighbor {{ bgp_peer['name'] }} activate
maximum-paths 64
exit-address-family
{% endfor %}
{% endif %}

View File

@ -6,28 +6,13 @@
!
{% endblock banner %}
!
{% block system_init %}
hostname {{ DEVICE_METADATA['localhost']['hostname'] }}
password zebra
log syslog informational
log facility local4
{% include "daemons.common.conf.j2" %}
!
agentx
! enable password {# {{ en_passwd }} TODO: param needed #}
{% endblock system_init %}
!
{% if DEVICE_METADATA['localhost']['type'] == "SpineChassisFrontendRouter" %}
{% include "bgpd.conf.spine_chassis_frontend_router.j2" %}
{% else%}
{% include "bgpd.conf.default.j2" %}
{% endif %}
!
{% if DEVICE_METADATA['localhost'].has_key('bgp_asn') %}
maximum-paths 64
!
route-map ISOLATE permit 10
set as-path prepend {{ DEVICE_METADATA['localhost']['bgp_asn'] }}
{% endif %}
!
route-map set-next-hop-global-v6 permit 10
set ipv6 next-hop prefer-global
{% include "bgpd.conf.default.j2" %}
!

View File

@ -1,3 +1,4 @@
!
{# VNET BGP Instance #}
! Vnet BGP instance
{% set interfaces_in_vnets = [] %}
@ -59,70 +60,4 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} vrf {{ vnet_name }}
{% endfor %}
{% endfor %}
{% endblock vnet_bgp_instance %}
{# default bgp #}
{% block default_bgp_instance %}
{% block bgp_init %}
!
! bgp multiple-instance
!
route-map FROM_BGP_SPEAKER_V4 permit 10
!
route-map TO_BGP_SPEAKER_V4 deny 10
!
router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }}
bgp log-neighbor-changes
bgp bestpath as-path multipath-relax
no bgp default ipv4-unicast
bgp graceful-restart restart-time 240
bgp graceful-restart
{% for (name, prefix) in LOOPBACK_INTERFACE | pfx_filter %}
{% if prefix | ipv4 and name == 'Loopback0' %}
bgp router-id {{ prefix | ip }}
{% endif %}
{% endfor %}
{# advertise loopback #}
{% for (name, prefix) in LOOPBACK_INTERFACE | pfx_filter %}
{% if prefix | ipv4 and name == 'Loopback0' %}
network {{ prefix | ip }}/32
{% elif prefix | ipv6 and name == 'Loopback0' %}
address-family ipv6
network {{ prefix | ip }}/64
exit-address-family
{% endif %}
{% endfor %}
{% endblock bgp_init %}
{% block bgp_sessions %}
{% for neighbor_addr, bgp_session in BGP_NEIGHBOR.iteritems() %}
{% if not bgp_session.has_key("local_addr") or bgp_session["local_addr"] not in interfaces_in_vnets %}
{% if bgp_session['asn'] | int != 0 %}
neighbor {{ neighbor_addr }} remote-as {{ bgp_session['asn'] }}
neighbor {{ neighbor_addr }} description {{ bgp_session['name'] }}
{# set the bgp neighbor timers if they have not default values #}
{% if (bgp_session['keepalive'] is defined and bgp_session['keepalive'] | int != 60)
or (bgp_session['holdtime'] is defined and bgp_session['holdtime'] | int != 180) %}
neighbor {{ neighbor_addr }} timers {{ bgp_session['keepalive'] }} {{ bgp_session['holdtime'] }}
{% endif %}
{% if bgp_session.has_key('admin_status') and bgp_session['admin_status'] == 'down' or not bgp_session.has_key('admin_status') and DEVICE_METADATA['localhost'].has_key('default_bgp_status') and DEVICE_METADATA['localhost']['default_bgp_status'] == 'down' %}
neighbor {{ neighbor_addr }} shutdown
{% endif %}
{% if bgp_session["asn"] != DEVICE_METADATA['localhost']['bgp_asn'] %}
{% if neighbor_addr | ipv4 %}
address-family ipv4 unicast
neighbor {{ neighbor_addr }} allowas-in 1
neighbor {{ neighbor_addr }} activate
neighbor {{ neighbor_addr }} soft-reconfiguration inbound
maximum-paths 64
exit-address-family
{% endif %}
{% else %}
address-family l2vpn evpn
neighbor {{ neighbor_addr }} activate
advertise-all-vni
exit-address-family
{% endif %}
{% endif %}
{% endif %}
{% endfor %}
{% endblock bgp_sessions %}
{% endblock default_bgp_instance %}

View File

@ -0,0 +1,30 @@
{% block bgp_peer %}
neighbor {{ neighbor_addr }} remote-as {{ bgp_session['asn'] }}
neighbor {{ neighbor_addr }} description {{ bgp_session['name'] }}
{# set the bgp neighbor timers if they have not default values #}
{% if (bgp_session['keepalive'] is defined and bgp_session['keepalive'] | int != 60)
or (bgp_session['holdtime'] is defined and bgp_session['holdtime'] | int != 180) %}
neighbor {{ neighbor_addr }} timers {{ bgp_session['keepalive'] }} {{ bgp_session['holdtime'] }}
{% endif %}
{% if bgp_session.has_key('admin_status') and bgp_session['admin_status'] == 'down' or not bgp_session.has_key('admin_status') and DEVICE_METADATA['localhost'].has_key('default_bgp_status') and DEVICE_METADATA['localhost']['default_bgp_status'] == 'down' %}
neighbor {{ neighbor_addr }} shutdown
{% endif %}
{% if neighbor_addr | ipv4 %}
address-family ipv4
neighbor {{ neighbor_addr }} peer-group PEER_V4
{% elif neighbor_addr | ipv6 %}
address-family ipv6
{% if bgp_session['asn'] != DEVICE_METADATA['localhost']['bgp_asn'] %}
neighbor {{ neighbor_addr }} route-map set-next-hop-global-v6 in
{% endif %}
neighbor {{ neighbor_addr }} peer-group PEER_V6
{% endif %}
{% if bgp_session['rrclient'] | int != 0 %}
neighbor {{ neighbor_addr }} route-reflector-client
{% endif %}
{% if bgp_session['nhopself'] | int != 0 %}
neighbor {{ neighbor_addr }} next-hop-self
{% endif %}
neighbor {{ neighbor_addr }} activate
exit-address-family
{% endblock bgp_peer %}

View File

@ -0,0 +1,12 @@
!
{% block sys_init %}
hostname {{ DEVICE_METADATA['localhost']['hostname'] }}
password zebra
enable password zebra
{% endblock sys_init %}
!
{% block logging %}
log syslog informational
log facility local4
{% endblock logging %}
!

View File

@ -6,205 +6,13 @@
!
{% endblock banner %}
!
{% block system_init %}
hostname {{ DEVICE_METADATA['localhost']['hostname'] }}
password zebra
log syslog informational
log facility local4
{% include "daemons.common.conf.j2" %}
!
agentx
! enable password {# {{ en_passwd }} TODO: param needed #}
{% endblock system_init %}
!
{% block interfaces %}
! Enable link-detect (default disabled)
{% for (name, prefix) in INTERFACE|pfx_filter %}
interface {{ name }}
link-detect
{% include "zebra.interfaces.conf.j2" %}
!
{% endfor %}
{% for pc in PORTCHANNEL %}
interface {{ pc }}
link-detect
{% include "staticd.default_route.conf.j2" %}
!
{% endfor %}
{% endblock interfaces %}
!
{% block default_route %}
! set static default route to mgmt gateway as a backup to learned default
{% for (name, prefix) in MGMT_INTERFACE|pfx_filter %}
{% if prefix | ipv4 %}
ip route 0.0.0.0/0 {{ MGMT_INTERFACE[(name, prefix)]['gwaddr'] }} 200
{% endif %}
{% endfor %}
{% endblock default_route %}
!
{% block source_loopback %}
{% set lo_ipv4_addrs = [] %}
{% set lo_ipv6_addrs = [] %}
{% if LOOPBACK_INTERFACE %}
{% for (name, prefix) in LOOPBACK_INTERFACE|pfx_filter %}
{% 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
route-map RM_SET_SRC permit 10
set src {{ lo_ipv4_addrs[0] | ip }}
!
{% 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 %}
!
{% if DEVICE_METADATA['localhost'].has_key('bgp_asn') %}
{% block bgp_init %}
!
! bgp multiple-instance
!
route-map FROM_BGP_SPEAKER_V4 permit 10
!
route-map TO_BGP_SPEAKER_V4 deny 10
!
router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }}
bgp log-neighbor-changes
bgp bestpath as-path multipath-relax
no bgp default ipv4-unicast
{# Advertise graceful restart capability for ToR #}
{% if DEVICE_METADATA['localhost']['type'] == 'ToRRouter' %}
bgp graceful-restart
{% endif %}
{% for (name, prefix) in LOOPBACK_INTERFACE|pfx_filter %}
{% if prefix | ipv4 and name == 'Loopback0' %}
bgp router-id {{ prefix | ip }}
{% endif %}
{% endfor %}
{# advertise loopback #}
{% for (name, prefix) in LOOPBACK_INTERFACE|pfx_filter %}
{% if prefix | ipv4 and name == 'Loopback0' %}
network {{ prefix | ip }}/32
{% elif prefix | ipv6 and name == 'Loopback0' %}
address-family ipv6
network {{ prefix | ip }}/64
exit-address-family
{% endif %}
{% endfor %}
{% endblock bgp_init %}
{% endif %}
{% block vlan_advertisement %}
{% for (name, prefix) in VLAN_INTERFACE|pfx_filter %}
{% if prefix | ipv4 %}
network {{ prefix }}
{% elif prefix | ipv6 %}
address-family ipv6
network {{ prefix }}
exit-address-family
{% endif %}
{% endfor %}
{% endblock vlan_advertisement %}
{% block bgp_sessions %}
{% for neighbor_addr, bgp_session in BGP_NEIGHBOR.iteritems() %}
{% if bgp_session['asn'] | int != 0 %}
neighbor {{ neighbor_addr }} remote-as {{ bgp_session['asn'] }}
neighbor {{ neighbor_addr }} description {{ bgp_session['name'] }}
{# set the bgp neighbor timers if they have not default values #}
{% if (bgp_session['keepalive'] is defined and bgp_session['keepalive'] | int != 60)
or (bgp_session['holdtime'] is defined and bgp_session['holdtime'] | int != 180) %}
neighbor {{ neighbor_addr }} timers {{ bgp_session['keepalive'] }} {{ bgp_session['holdtime'] }}
{% endif %}
{% if bgp_session.has_key('admin_status') and bgp_session['admin_status'] == 'down' or not bgp_session.has_key('admin_status') and DEVICE_METADATA['localhost'].has_key('default_bgp_status') and DEVICE_METADATA['localhost']['default_bgp_status'] == 'down' %}
neighbor {{ neighbor_addr }} shutdown
{% endif %}
{% if neighbor_addr | ipv4 %}
address-family ipv4
{% if DEVICE_METADATA['localhost']['type'] == 'ToRRouter' %}
neighbor {{ neighbor_addr }} allowas-in 1
{% endif %}
neighbor {{ neighbor_addr }} activate
neighbor {{ neighbor_addr }} soft-reconfiguration inbound
{% if bgp_session['rrclient'] | int != 0 %}
neighbor {{ neighbor_addr }} route-reflector-client
{% endif %}
{% if bgp_session['nhopself'] | int != 0 %}
neighbor {{ neighbor_addr }} next-hop-self
{% endif %}
maximum-paths 64
exit-address-family
{% endif %}
{% if neighbor_addr | ipv6 %}
address-family ipv6
{% if DEVICE_METADATA['localhost']['type'] == 'ToRRouter' %}
neighbor {{ neighbor_addr }} allowas-in 1
{% endif %}
neighbor {{ neighbor_addr }} activate
neighbor {{ neighbor_addr }} soft-reconfiguration inbound
{% if bgp_session['rrclient'] | int != 0 %}
neighbor {{ neighbor_addr }} route-reflector-client
{% endif %}
{% if bgp_session['nhopself'] | int != 0 %}
neighbor {{ neighbor_addr }} next-hop-self
{% endif %}
{% if bgp_session['asn'] != DEVICE_METADATA['localhost']['bgp_asn'] %}
neighbor {{ neighbor_addr }} route-map set-next-hop-global-v6 in
{% endif %}
maximum-paths 64
exit-address-family
{% endif %}
{% endif %}
{% endfor %}
{% endblock bgp_sessions %}
{% block bgp_peers_with_range %}
{% if BGP_PEER_RANGE %}
{% for bgp_peer in BGP_PEER_RANGE.values() %}
neighbor {{ bgp_peer['name'] }} peer-group
neighbor {{ bgp_peer['name'] }} passive
neighbor {{ bgp_peer['name'] }} remote-as {{ deployment_id_asn_map[DEVICE_METADATA['localhost']['deployment_id']] }}
neighbor {{ bgp_peer['name'] }} ebgp-multihop 255
{% for (name, prefix) in LOOPBACK_INTERFACE|pfx_filter %}
{% if name == 'Loopback1' %}
neighbor {{ bgp_peer['name'] }} update-source {{ prefix | ip }}
{% endif %}
{% endfor %}
{% for ip_range in bgp_peer['ip_range'] %}
bgp listen range {{ip_range}} peer-group {{ bgp_peer['name'] }}
{% endfor %}
address-family ipv4
neighbor {{ bgp_peer['name'] }} activate
neighbor {{ bgp_peer['name'] }} soft-reconfiguration inbound
neighbor {{ bgp_peer['name'] }} route-map FROM_BGP_SPEAKER_V4 in
neighbor {{ bgp_peer['name'] }} route-map TO_BGP_SPEAKER_V4 out
maximum-paths 64
exit-address-family
address-family ipv6
neighbor {{ bgp_peer['name'] }} activate
neighbor {{ bgp_peer['name'] }} soft-reconfiguration inbound
maximum-paths 64
exit-address-family
{% endfor %}
{% endif %}
{% endblock bgp_peers_with_range %}
!
{% if DEVICE_METADATA['localhost'].has_key('bgp_asn') %}
maximum-paths 64
!
route-map ISOLATE permit 10
set as-path prepend {{ DEVICE_METADATA['localhost']['bgp_asn'] }}
{% endif %}
!
route-map set-next-hop-global-v6 permit 10
set ipv6 next-hop prefer-global
{% include "bgpd.conf.default.j2" %}
!

View File

@ -33,8 +33,6 @@ rm -f /var/run/rsyslogd.pid
supervisorctl start rsyslogd
supervisorctl start bgpcfgd
# Start Quagga processes
supervisorctl start zebra
supervisorctl start staticd
@ -45,3 +43,5 @@ if [ "$CONFIG_TYPE" == "unified" ]; then
fi
supervisorctl start fpmsyncd
supervisorctl start bgpcfgd

View File

@ -6,24 +6,7 @@
!
{% endblock banner %}
!
{% block sys_init %}
hostname {{ DEVICE_METADATA['localhost']['hostname'] }}
password zebra
enable password zebra
{% endblock sys_init %}
{% include "daemons.common.conf.j2" %}
!
{% block default_route %}
! set static default route to mgmt gateway as a backup to learned default
{% for (name, prefix) in MGMT_INTERFACE|pfx_filter %}
{% if prefix | ipv4 %}
ip route 0.0.0.0/0 {{ MGMT_INTERFACE[(name, prefix)]['gwaddr'] }} 200
{% endif %}
{% endfor %}
{% endblock default_route %}
{% include "staticd.default_route.conf.j2" %}
!
{% block logging %}
log syslog informational
log facility local4
{% endblock logging %}
!

View File

@ -0,0 +1,10 @@
!
{% block default_route %}
! set static default route to mgmt gateway as a backup to learned default
{% for (name, prefix) in MGMT_INTERFACE|pfx_filter %}
{% if prefix | ipv4 %}
ip route 0.0.0.0/0 {{ MGMT_INTERFACE[(name, prefix)]['gwaddr'] }} 200
{% endif %}
{% endfor %}
{% endblock default_route %}
!

View File

@ -6,74 +6,7 @@
!
{% endblock banner %}
!
{% block sys_init %}
hostname {{ DEVICE_METADATA['localhost']['hostname'] }}
password zebra
enable password zebra
{% endblock sys_init %}
{% include "daemons.common.conf.j2" %}
!
{% block vrf %}
{% if VNET is defined %}
{% for vnet_name, vnet_metadata in VNET.iteritems() %}
vrf {{ vnet_name }}
vni {{ vnet_metadata['vni'] }}
{% include "zebra.interfaces.conf.j2" %}
!
{% endfor %}
{% endif %}
{% endblock vrf %}
!
{% block interfaces %}
! Enable link-detect (default disabled)
{% for (name, prefix) in INTERFACE|pfx_filter %}
interface {{ name }}
link-detect
!
{% endfor %}
{% for pc in PORTCHANNEL %}
interface {{ pc }}
link-detect
!
{% endfor %}
{% endblock interfaces %}
!
{% block source_loopback %}
{% set lo_ipv4_addrs = [] %}
{% set lo_ipv6_addrs = [] %}
{% if LOOPBACK_INTERFACE %}
{% for (name, prefix) in LOOPBACK_INTERFACE|pfx_filter %}
{% 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 %}
log syslog informational
log facility local4
{% endblock logging %}
!

View File

@ -0,0 +1,60 @@
!
{% block vrf %}
{% if VNET is defined %}
{% for vnet_name, vnet_metadata in VNET.iteritems() %}
vrf {{ vnet_name }}
vni {{ vnet_metadata['vni'] }}
!
{% endfor %}
{% endif %}
{% endblock vrf %}
!
{% block interfaces %}
! Enable link-detect (default disabled)
{% for (name, prefix) in INTERFACE|pfx_filter %}
interface {{ name }}
link-detect
!
{% endfor %}
{% for pc in PORTCHANNEL %}
interface {{ pc }}
link-detect
!
{% endfor %}
{% endblock interfaces %}
!
{% block source_loopback %}
{% set lo_ipv4_addrs = [] %}
{% set lo_ipv6_addrs = [] %}
{% if LOOPBACK_INTERFACE %}
{% for (name, prefix) in LOOPBACK_INTERFACE|pfx_filter %}
{% 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 %}
!

View File

@ -103,6 +103,14 @@ def pfx_filter(value):
table[key] = val
return table
def ip_network(value):
""" Extract network for network prefix """
try:
r_v = netaddr.IPNetwork(value)
except:
return "Invalid ip address %s" % value
return r_v.network
class FormatConverter:
"""Convert config DB based schema to legacy minigraph based schema for backward capability.
We will move to DB schema and remove this class when the config templates are modified.
@ -265,6 +273,7 @@ def main():
env.filters['ipv6'] = is_ipv6
env.filters['unique_name'] = unique_name
env.filters['pfx_filter'] = pfx_filter
env.filters['ip_network'] = ip_network
for attr in ['ip', 'network', 'prefixlen', 'netmask']:
env.filters[attr] = partial(prefix_attr, attr)
template = env.get_template(template_file)

View File

@ -4,12 +4,18 @@
! file: bgpd.conf
!
!
!
hostname switch-t0
password zebra
enable password zebra
!
log syslog informational
log facility local4
!!
agentx
! enable password !
!
!
!
!
! bgp multiple-instance
!
@ -18,7 +24,7 @@ route-map FROM_BGP_SPEAKER_V4 permit 10
route-map TO_BGP_SPEAKER_V4 deny 10
!
ip prefix-list PL_LoopbackV4 permit 10.1.0.32/32
ipv6 prefix-list PL_LoopbackV6 permit fc00:1::32/64
ipv6 prefix-list PL_LoopbackV6 permit fc00:1::/64
!
!
route-map TO_BGP_PEER_V4 permit 100
@ -29,6 +35,13 @@ route-map FROM_BGPMON_V4 deny 10
!
route-map TO_BGPMON_V4 permit 10
!
!
route-map ISOLATE permit 10
set as-path prepend 65100
!
route-map set-next-hop-global-v6 permit 10
set ipv6 next-hop prefer-global
!
router bgp 65100
bgp log-neighbor-changes
bgp bestpath as-path multipath-relax
@ -42,81 +55,23 @@ router bgp 65100
network fc00:1::32/64
exit-address-family
network 192.168.0.1/27
neighbor 10.0.0.57 remote-as 64600
neighbor 10.0.0.57 description ARISTA01T1
neighbor 10.0.0.57 route-map TO_BGP_PEER_V4 out
address-family ipv4
neighbor 10.0.0.57 allowas-in 1
neighbor 10.0.0.57 activate
neighbor 10.0.0.57 soft-reconfiguration inbound
maximum-paths 64
exit-address-family
neighbor 10.0.0.59 remote-as 64600
neighbor 10.0.0.59 description ARISTA02T1
neighbor 10.0.0.59 route-map TO_BGP_PEER_V4 out
address-family ipv6
maximum-paths 64
exit-address-family
neighbor PEER_V4 peer-group
neighbor PEER_V6 peer-group
address-family ipv4
neighbor 10.0.0.59 allowas-in 1
neighbor 10.0.0.59 activate
neighbor 10.0.0.59 soft-reconfiguration inbound
maximum-paths 64
neighbor PEER_V4 allowas-in 1
neighbor PEER_V4 soft-reconfiguration inbound
neighbor PEER_V4 route-map TO_BGP_PEER_V4 out
exit-address-family
neighbor 10.0.0.61 remote-as 64600
neighbor 10.0.0.61 description ARISTA03T1
neighbor 10.0.0.61 route-map TO_BGP_PEER_V4 out
address-family ipv4
neighbor 10.0.0.61 allowas-in 1
neighbor 10.0.0.61 activate
neighbor 10.0.0.61 soft-reconfiguration inbound
maximum-paths 64
exit-address-family
neighbor 10.0.0.63 remote-as 64600
neighbor 10.0.0.63 description ARISTA04T1
neighbor 10.0.0.63 route-map TO_BGP_PEER_V4 out
address-family ipv4
neighbor 10.0.0.63 allowas-in 1
neighbor 10.0.0.63 activate
neighbor 10.0.0.63 soft-reconfiguration inbound
maximum-paths 64
exit-address-family
neighbor fc00::7a remote-as 64600
neighbor fc00::7a description ARISTA03T1
address-family ipv6
neighbor fc00::7a allowas-in 1
neighbor fc00::7a activate
neighbor fc00::7a soft-reconfiguration inbound
neighbor fc00::7a route-map set-next-hop-global-v6 in
neighbor fc00::7a route-map TO_BGP_PEER_V6 out
maximum-paths 64
exit-address-family
neighbor fc00::7e remote-as 64600
neighbor fc00::7e description ARISTA04T1
address-family ipv6
neighbor fc00::7e allowas-in 1
neighbor fc00::7e activate
neighbor fc00::7e soft-reconfiguration inbound
neighbor fc00::7e route-map set-next-hop-global-v6 in
neighbor fc00::7e route-map TO_BGP_PEER_V6 out
maximum-paths 64
exit-address-family
neighbor fc00::72 remote-as 64600
neighbor fc00::72 description ARISTA01T1
address-family ipv6
neighbor fc00::72 allowas-in 1
neighbor fc00::72 activate
neighbor fc00::72 soft-reconfiguration inbound
neighbor fc00::72 route-map set-next-hop-global-v6 in
neighbor fc00::72 route-map TO_BGP_PEER_V6 out
maximum-paths 64
exit-address-family
neighbor fc00::76 remote-as 64600
neighbor fc00::76 description ARISTA02T1
address-family ipv6
neighbor fc00::76 allowas-in 1
neighbor fc00::76 activate
neighbor fc00::76 soft-reconfiguration inbound
neighbor fc00::76 route-map set-next-hop-global-v6 in
neighbor fc00::76 route-map TO_BGP_PEER_V6 out
maximum-paths 64
neighbor PEER_V6 allowas-in 1
neighbor PEER_V6 soft-reconfiguration inbound
neighbor PEER_V6 route-map TO_BGP_PEER_V6 out
exit-address-family
neighbor BGPMON_V4 peer-group
neighbor BGPMON_V4 update-source 10.1.0.32
@ -129,11 +84,3 @@ router bgp 65100
neighbor 10.20.30.40 description BGPMonitor
neighbor 10.20.30.40 activate
!!
maximum-paths 64
!
route-map ISOLATE permit 10
set as-path prepend 65100
!
route-map set-next-hop-global-v6 permit 10
set ipv6 next-hop prefer-global
!

View File

@ -4,12 +4,18 @@
! file: frr.conf
!
!
!
hostname switch-t0
password zebra
enable password zebra
!
log syslog informational
log facility local4
!!
agentx
! enable password !
!
!
!
! Enable link-detect (default disabled)
interface PortChannel01
link-detect
@ -24,9 +30,6 @@ interface PortChannel04
link-detect
!
!
! 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
!
! Set ip source to loopback for bgp learned routes
route-map RM_SET_SRC permit 10
set src 10.1.0.32
@ -39,6 +42,11 @@ ip protocol bgp route-map RM_SET_SRC
!
ipv6 protocol bgp route-map RM_SET_SRC6
!
!!
!
! 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
!!
!
!
! bgp multiple-instance
@ -47,91 +55,64 @@ route-map FROM_BGP_SPEAKER_V4 permit 10
!
route-map TO_BGP_SPEAKER_V4 deny 10
!
ip prefix-list PL_LoopbackV4 permit 10.1.0.32/32
ipv6 prefix-list PL_LoopbackV6 permit fc00:1::/64
!
!
route-map TO_BGP_PEER_V4 permit 100
!
route-map TO_BGP_PEER_V6 permit 100
!
route-map FROM_BGPMON_V4 deny 10
!
route-map TO_BGPMON_V4 permit 10
!
!
route-map ISOLATE permit 10
set as-path prepend 65100
!
route-map set-next-hop-global-v6 permit 10
set ipv6 next-hop prefer-global
!
router bgp 65100
bgp log-neighbor-changes
bgp bestpath as-path multipath-relax
no bgp default ipv4-unicast
bgp graceful-restart restart-time 240
bgp graceful-restart
bgp graceful-restart preserve-fw-state
bgp router-id 10.1.0.32
network 10.1.0.32/32
address-family ipv6
network fc00:1::32/64
exit-address-family
network 192.168.0.1/27
neighbor 10.0.0.57 remote-as 64600
neighbor 10.0.0.57 description ARISTA01T1
address-family ipv4
neighbor 10.0.0.57 allowas-in 1
neighbor 10.0.0.57 activate
neighbor 10.0.0.57 soft-reconfiguration inbound
maximum-paths 64
exit-address-family
neighbor 10.0.0.59 remote-as 64600
neighbor 10.0.0.59 description ARISTA02T1
address-family ipv6
maximum-paths 64
exit-address-family
neighbor PEER_V4 peer-group
neighbor PEER_V6 peer-group
address-family ipv4
neighbor 10.0.0.59 allowas-in 1
neighbor 10.0.0.59 activate
neighbor 10.0.0.59 soft-reconfiguration inbound
maximum-paths 64
neighbor PEER_V4 allowas-in 1
neighbor PEER_V4 soft-reconfiguration inbound
neighbor PEER_V4 route-map TO_BGP_PEER_V4 out
exit-address-family
neighbor 10.0.0.61 remote-as 64600
neighbor 10.0.0.61 description ARISTA03T1
address-family ipv4
neighbor 10.0.0.61 allowas-in 1
neighbor 10.0.0.61 activate
neighbor 10.0.0.61 soft-reconfiguration inbound
maximum-paths 64
exit-address-family
neighbor 10.0.0.63 remote-as 64600
neighbor 10.0.0.63 description ARISTA04T1
address-family ipv4
neighbor 10.0.0.63 allowas-in 1
neighbor 10.0.0.63 activate
neighbor 10.0.0.63 soft-reconfiguration inbound
maximum-paths 64
exit-address-family
neighbor fc00::7a remote-as 64600
neighbor fc00::7a description ARISTA03T1
address-family ipv6
neighbor fc00::7a allowas-in 1
neighbor fc00::7a activate
neighbor fc00::7a soft-reconfiguration inbound
neighbor fc00::7a route-map set-next-hop-global-v6 in
maximum-paths 64
neighbor PEER_V6 allowas-in 1
neighbor PEER_V6 soft-reconfiguration inbound
neighbor PEER_V6 route-map TO_BGP_PEER_V6 out
exit-address-family
neighbor fc00::7e remote-as 64600
neighbor fc00::7e description ARISTA04T1
address-family ipv6
neighbor fc00::7e allowas-in 1
neighbor fc00::7e activate
neighbor fc00::7e soft-reconfiguration inbound
neighbor fc00::7e route-map set-next-hop-global-v6 in
maximum-paths 64
exit-address-family
neighbor fc00::72 remote-as 64600
neighbor fc00::72 description ARISTA01T1
address-family ipv6
neighbor fc00::72 allowas-in 1
neighbor fc00::72 activate
neighbor fc00::72 soft-reconfiguration inbound
neighbor fc00::72 route-map set-next-hop-global-v6 in
maximum-paths 64
exit-address-family
neighbor fc00::76 remote-as 64600
neighbor fc00::76 description ARISTA02T1
address-family ipv6
neighbor fc00::76 allowas-in 1
neighbor fc00::76 activate
neighbor fc00::76 soft-reconfiguration inbound
neighbor fc00::76 route-map set-next-hop-global-v6 in
maximum-paths 64
exit-address-family
!
maximum-paths 64
!
route-map ISOLATE permit 10
set as-path prepend 65100
!
route-map set-next-hop-global-v6 permit 10
set ipv6 next-hop prefer-global
!
neighbor BGPMON_V4 peer-group
neighbor BGPMON_V4 update-source 10.1.0.32
neighbor BGPMON_V4 route-map FROM_BGPMON_V4 in
neighbor BGPMON_V4 route-map TO_BGPMON_V4 out
neighbor BGPMON_V4 send-community
neighbor BGPMON_V4 maximum-prefix 1
neighbor 10.20.30.40 remote-as 65100
neighbor 10.20.30.40 peer-group BGPMON_V4
neighbor 10.20.30.40 description BGPMonitor
neighbor 10.20.30.40 activate
!!

View File

@ -4,14 +4,15 @@
! file: staticd.conf
!
!
!
hostname switch-t0
password zebra
enable password zebra
!
! 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
!
log syslog informational
log facility local4
!!
!
! 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
!!

View File

@ -4,12 +4,17 @@
! file: bgpd.conf
!
!
!
hostname SpineFront01
password zebra
enable password zebra
!
log syslog informational
log facility local4
!!
agentx
! enable password !
!
!
! Vnet BGP instance
router bgp 4000 vrf VnetFE
no bgp default ipv4-unicast
@ -30,7 +35,8 @@ router bgp 4000 vrf VnetFE
address-family l2vpn evpn
advertise ipv4 unicast
exit-address-family
!!
!
!
! bgp multiple-instance
!
@ -38,6 +44,20 @@ route-map FROM_BGP_SPEAKER_V4 permit 10
!
route-map TO_BGP_SPEAKER_V4 deny 10
!
ip prefix-list PL_LoopbackV4 permit 4.0.0.0/32
!
!
route-map TO_BGP_PEER_V4 permit 100
!
route-map TO_BGP_PEER_V6 permit 100
!
!
route-map ISOLATE permit 10
set as-path prepend 4000
!
route-map set-next-hop-global-v6 permit 10
set ipv6 next-hop prefer-global
!
router bgp 4000
bgp log-neighbor-changes
bgp bestpath as-path multipath-relax
@ -46,37 +66,20 @@ router bgp 4000
bgp graceful-restart
bgp router-id 4.0.0.0
network 4.0.0.0/32
neighbor 4.0.0.1 remote-as 4000
neighbor 4.0.0.1 description SpineFront02
neighbor 4.0.0.1 timers 3 10
address-family l2vpn evpn
neighbor 4.0.0.1 activate
advertise-all-vni
exit-address-family
neighbor 172.16.0.2 remote-as 5000
neighbor 172.16.0.2 description SpineBack01
neighbor 172.16.0.2 timers 3 10
address-family ipv4 unicast
neighbor 172.16.0.2 allowas-in 1
neighbor 172.16.0.2 activate
neighbor 172.16.0.2 soft-reconfiguration inbound
address-family ipv4
maximum-paths 64
exit-address-family
neighbor 172.16.0.10 remote-as 5000
neighbor 172.16.0.10 description SpineBack02
neighbor 172.16.0.10 timers 3 10
address-family ipv4 unicast
neighbor 172.16.0.10 allowas-in 1
neighbor 172.16.0.10 activate
neighbor 172.16.0.10 soft-reconfiguration inbound
address-family ipv6
maximum-paths 64
exit-address-family
!
maximum-paths 64
!
route-map ISOLATE permit 10
set as-path prepend 4000
!
route-map set-next-hop-global-v6 permit 10
set ipv6 next-hop prefer-global
!
neighbor PEER_V4 peer-group
neighbor PEER_V6 peer-group
address-family ipv4
neighbor PEER_V4 soft-reconfiguration inbound
neighbor PEER_V4 route-map TO_BGP_PEER_V4 out
exit-address-family
address-family ipv6
neighbor PEER_V6 soft-reconfiguration inbound
neighbor PEER_V6 route-map TO_BGP_PEER_V6 out
exit-address-family
!!

View File

@ -4,10 +4,15 @@
! file: zebra.conf
!
!
!
hostname SpineFront01
password zebra
enable password zebra
!
log syslog informational
log facility local4
!!
!
vrf VnetFE
vni 9000
!
@ -29,8 +34,4 @@ route-map RM_SET_SRC permit 10
!
ip protocol bgp route-map RM_SET_SRC
!
!
log syslog informational
log facility local4
!
!!

View File

@ -4,10 +4,15 @@
! file: zebra.conf
!
!
!
hostname SpineFront01
password zebra
enable password zebra
!
log syslog informational
log facility local4
!!
!
vrf VnetFE
vni 8000
!
@ -29,8 +34,4 @@ route-map RM_SET_SRC permit 10
!
ip protocol bgp route-map RM_SET_SRC
!
!
log syslog informational
log facility local4
!
!!

View File

@ -4,10 +4,15 @@
! file: zebra.conf
!
!
!
hostname switch-t0
password zebra
enable password zebra
!
log syslog informational
log facility local4
!!
!
!
! Enable link-detect (default disabled)
interface PortChannel01
@ -35,8 +40,4 @@ ip protocol bgp route-map RM_SET_SRC
!
ipv6 protocol bgp route-map RM_SET_SRC6
!
!
log syslog informational
log facility local4
!
!!

View File

@ -0,0 +1,62 @@
from unittest import TestCase
import subprocess
import os
import filecmp
class TestCfgGen(TestCase):
def setUp(self):
self.test_dir = os.path.dirname(os.path.realpath(__file__))
self.script_file = os.path.join(self.test_dir, '..', 'sonic-cfggen')
self.t0_minigraph = os.path.join(self.test_dir, 't0-sample-graph.xml')
self.t0_port_config = os.path.join(self.test_dir, 't0-sample-port-config.ini')
self.output_file = os.path.join(self.test_dir, 'output')
def tearDown(self):
try:
os.remove(self.output_file)
except OSError:
pass
def run_script(self, argument, check_stderr=False):
# print '\n Running sonic-cfggen ' + argument
if check_stderr:
output = subprocess.check_output(self.script_file + ' ' + argument, stderr=subprocess.STDOUT, shell=True)
else:
output = subprocess.check_output(self.script_file + ' ' + argument, shell=True)
linecount = output.strip().count('\n')
if linecount <= 0:
print ' Output: ' + output.strip()
else:
print ' Output: ({0} lines, {1} bytes)'.format(linecount + 1, len(output))
return output
def run_diff(self, file1, file2):
return subprocess.check_output('diff -u {} {} || true'.format(file1, file2), shell=True)
def run_case(self, template, target):
conf_template = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-fpm-frr', template)
cmd = '-m ' + self.t0_minigraph + ' -p ' + self.t0_port_config + ' -t ' + conf_template + ' > ' + self.output_file
self.run_script(cmd)
original_filename = os.path.join(self.test_dir, 'sample_output', target)
r = filecmp.cmp(original_filename, self.output_file)
diff_output = self.run_diff(original_filename, self.output_file) if not r else ""
return r, "Diff:\n" + diff_output
def test_config_frr(self):
self.assertTrue(*self.run_case('frr.conf.j2', 'frr.conf'))
def test_bgpd_frr(self):
self.assertTrue(*self.run_case('bgpd.conf.j2', 'bgpd_frr.conf'))
def test_zebra_frr(self):
self.assertTrue(*self.run_case('zebra.conf.j2', 'zebra_frr.conf'))
def test_staticd_frr(self):
self.assertTrue(*self.run_case('staticd.conf.j2', 'staticd_frr.conf'))

View File

@ -77,34 +77,6 @@ class TestJ2Files(TestCase):
self.run_script(argument)
self.assertTrue(filecmp.cmp(os.path.join(self.test_dir, 'sample_output', 'zebra_quagga.conf'), self.output_file))
def test_config_frr(self):
conf_template = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-fpm-frr', 'frr.conf.j2')
argument = '-m ' + self.t0_minigraph + ' -p ' + self.t0_port_config + ' -t ' + conf_template + ' > ' + self.output_file
self.run_script(argument)
self.assertTrue(filecmp.cmp(os.path.join(self.test_dir, 'sample_output', 'frr.conf'), self.output_file))
def test_bgpd_frr(self):
conf_template = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-fpm-frr', 'bgpd.conf.j2')
argument = '-m ' + self.t0_minigraph + ' -p ' + self.t0_port_config + ' -t ' + conf_template + ' > ' + self.output_file
self.run_script(argument)
original_filename = os.path.join(self.test_dir, 'sample_output', 'bgpd_frr.conf')
r = filecmp.cmp(original_filename, self.output_file)
diff_output = self.run_diff(original_filename, self.output_file) if not r else ""
self.assertTrue(r, "Diff:\n" + diff_output)
def test_zebra_frr(self):
conf_template = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-fpm-frr', 'zebra.conf.j2')
argument = '-m ' + self.t0_minigraph + ' -p ' + self.t0_port_config + ' -t ' + conf_template + ' > ' + self.output_file
self.run_script(argument)
self.assertTrue(filecmp.cmp(os.path.join(self.test_dir, 'sample_output', 'zebra_frr.conf'), self.output_file))
def test_staticd_frr(self):
conf_template = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-fpm-frr', 'staticd.conf.j2')
argument = '-m ' + self.t0_minigraph + ' -p ' + self.t0_port_config + ' -t ' + conf_template + ' > ' + self.output_file
self.run_script(argument)
self.assertTrue(filecmp.cmp(os.path.join(self.test_dir, 'sample_output', 'staticd_frr.conf'), self.output_file))
def test_ipinip(self):
ipinip_file = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-orchagent', 'ipinip.json.j2')
argument = '-m ' + self.t0_minigraph + ' -p ' + self.t0_port_config + ' -t ' + ipinip_file + ' > ' + self.output_file

View File

@ -16,42 +16,39 @@ class TestJ2FilesT2ChassisFe(TestCase):
self.t2_chassis_fe_port_config = os.path.join(self.test_dir, 't2-chassis-fe-port-config.ini')
self.output_file = os.path.join(self.test_dir, 'output')
def run_script(self, argument):
print 'CMD: sonic-cfggen ' + argument
return subprocess.check_output(self.script_file + ' ' + argument, shell=True)
# Test zebra.conf in FRR docker for a T2 chassis frontend (fe)
def test_t2_chassis_fe_zebra_frr(self):
conf_template = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-fpm-frr', 'zebra.conf.j2')
argument = '-m ' + self.t2_chassis_fe_minigraph + ' -p ' + self.t2_chassis_fe_port_config + ' -t ' + conf_template + ' > ' + self.output_file
self.run_script(argument)
self.assertTrue(filecmp.cmp(os.path.join(self.test_dir, 'sample_output', 't2-chassis-fe-zebra.conf'), self.output_file))
# Test zebra.conf in FRR docker for a T2 chassis frontend (fe) switch with port channel interfaces
def test_t2_chassis_fe_pc_zebra_frr(self):
conf_template = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-fpm-frr', 'zebra.conf.j2')
argument = '-m ' + self.t2_chassis_fe_pc_minigraph + ' -p ' + self.t2_chassis_fe_port_config + ' -t ' + conf_template + ' > ' + self.output_file
self.run_script(argument)
self.assertTrue(filecmp.cmp(os.path.join(self.test_dir, 'sample_output', 't2-chassis-fe-pc-zebra.conf'), self.output_file))
# Test zebra.conf in FRR docker for a T2 chassis frontend (fe) switch with specified VNI
def test_t2_chassis_fe_vni_zebra_frr(self):
conf_template = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-fpm-frr', 'zebra.conf.j2')
argument = '-m ' + self.t2_chassis_fe_vni_minigraph + ' -p ' + self.t2_chassis_fe_port_config + ' -t ' + conf_template + ' > ' + self.output_file
self.run_script(argument)
self.assertTrue(filecmp.cmp(os.path.join(self.test_dir, 'sample_output', 't2-chassis-fe-vni-zebra.conf'), self.output_file))
# Test bgpd.conf in FRR docker for a T2 chassis frontend (fe)
def test_t2_chassis_frontend_bgpd_frr(self):
conf_template = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-fpm-frr', 'bgpd.conf.j2')
argument = '-m ' + self.t2_chassis_fe_minigraph + ' -p ' + self.t2_chassis_fe_port_config + ' -t ' + conf_template + ' > ' + self.output_file
self.run_script(argument)
self.assertTrue(filecmp.cmp(os.path.join(self.test_dir, 'sample_output', 't2-chassis-fe-bgpd.conf'), self.output_file))
def tearDown(self):
try:
os.remove(self.output_file)
except OSError:
pass
def run_script(self, argument):
print 'CMD: sonic-cfggen ' + argument
return subprocess.check_output(self.script_file + ' ' + argument, shell=True)
def run_diff(self, file1, file2):
return subprocess.check_output('diff -u {} {} || true'.format(file1, file2), shell=True)
def run_case(self, minigraph, template, target):
conf_template = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-fpm-frr', template)
cmd = '-m ' + minigraph + ' -p ' + self.t2_chassis_fe_port_config + ' -t ' + conf_template + ' > ' + self.output_file
self.run_script(cmd)
original_filename = os.path.join(self.test_dir, 'sample_output', target)
r = filecmp.cmp(original_filename, self.output_file)
diff_output = self.run_diff(original_filename, self.output_file) if not r else ""
return r, "Diff:\n" + diff_output
# Test zebra.conf in FRR docker for a T2 chassis frontend (fe)
def test_t2_chassis_fe_zebra_frr(self):
self.assertTrue(*self.run_case(self.t2_chassis_fe_minigraph, 'zebra.conf.j2', 't2-chassis-fe-zebra.conf'))
# Test zebra.conf in FRR docker for a T2 chassis frontend (fe) switch with specified VNI
def test_t2_chassis_fe_vni_zebra_frr(self):
self.assertTrue(*self.run_case(self.t2_chassis_fe_vni_minigraph, 'zebra.conf.j2', 't2-chassis-fe-vni-zebra.conf'))
# Test bgpd.conf in FRR docker for a T2 chassis frontend (fe)
def test_t2_chassis_frontend_bgpd_frr(self):
self.assertTrue(*self.run_case(self.t2_chassis_fe_minigraph, 'bgpd.conf.j2', 't2-chassis-fe-bgpd.conf'))