Skip to content

Commit

Permalink
[docker-frr]: bring quagga docker features to frr docker (#2870)
Browse files Browse the repository at this point in the history
- use superviord to manage process in frr docker
- intro separated configuration mode for frr
- bring quagga configuration template to frr.

Signed-off-by: Guohan Lu <gulv@microsoft.com>
  • Loading branch information
lguohan committed May 9, 2019
1 parent 8468f63 commit 5fb185c
Show file tree
Hide file tree
Showing 10 changed files with 394 additions and 100 deletions.
12 changes: 4 additions & 8 deletions dockers/docker-fpm-frr/Dockerfile.j2
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,8 @@ RUN apt-get autoclean -y
RUN apt-get autoremove -y
RUN rm -rf /debs ~/.cache

COPY ["bgpcfgd", "start.sh", "/usr/bin/"]
COPY ["*.j2", "/usr/share/sonic/templates/"]
COPY ["start.sh", "config.sh", "/usr/bin/"]
COPY ["daemons", "/etc/frr/"]
COPY ["daemons.conf", "/etc/frr/"]
COPY ["vtysh.conf", "/etc/frr/"]

ENTRYPOINT /usr/bin/config.sh \
&& /usr/bin/start.sh \
&& /bin/bash
COPY ["supervisord.conf", "/etc/supervisor/conf.d/"]

ENTRYPOINT ["/usr/bin/supervisord"]
65 changes: 65 additions & 0 deletions dockers/docker-fpm-frr/bgpcfgd
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#!/usr/bin/env python

import sys
import redis
import subprocess
import syslog
from swsssdk import ConfigDBConnector

class BGPConfigDaemon:

def __init__(self):
self.config_db = ConfigDBConnector()
self.config_db.connect()
self.bgp_asn = self.config_db.get_entry('DEVICE_METADATA', 'localhost')['bgp_asn']
self.bgp_neighbor = self.config_db.get_table('BGP_NEIGHBOR')

def __run_command(self, command):
# print command
p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
stdout = p.communicate()[0]
p.wait()
if p.returncode != 0:
syslog.syslog(syslog.LOG_ERR, '[bgp cfgd] command execution returned {}. Command: "{}", stdout: "{}"'.format(p.returncode, command, stdout))

def metadata_handler(self, key, data):
if key == 'localhost' and data.has_key('bgp_asn'):
if data['bgp_asn'] != self.bgp_asn:
syslog.syslog(syslog.LOG_INFO, '[bgp cfgd] ASN changed to {} from {}, restart BGP...'.format(data['bgp_asn'], self.bgp_asn))
self.__run_command("supervisorctl restart start.sh")
self.__run_command("service quagga restart")
self.bgp_asn = data['bgp_asn']

def bgp_handler(self, key, data):
syslog.syslog(syslog.LOG_INFO, '[bgp cfgd] value for {} changed to {}'.format(key, data))
if not data:
# Neighbor is deleted
command = "vtysh -c 'configure terminal' -c 'router bgp {}' -c 'no neighbor {}'".format(self.bgp_asn, key)
self.__run_command(command)
self.bgp_neighbor.pop(key)
else:
command = "vtysh -c 'configure terminal' -c 'router bgp {}' -c 'neighbor {} remote-as {}'".format(self.bgp_asn, key, data['asn'])
self.__run_command(command)
if data.has_key('name'):
command = "vtysh -c 'configure terminal' -c 'router bgp {}' -c 'neighbor {} description {}'".format(self.bgp_asn, key, data['name'])
self.__run_command(command)
if data.has_key('admin_status'):
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)
self.__run_command(command)
self.bgp_neighbor[key] = data

def start(self):
self.config_db.subscribe('BGP_NEIGHBOR',
lambda table, key, data: self.bgp_handler(key, data))
self.config_db.subscribe('DEVICE_METADATA',
lambda table, key, data: self.metadata_handler(key, data))
self.config_db.listen()


def main():
daemon = BGPConfigDaemon()
daemon.start()

if __name__ == "__main__":
main()
140 changes: 140 additions & 0 deletions dockers/docker-fpm-frr/bgpd.conf.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
!
{% block banner %}
! =========== Managed by sonic-cfggen DO NOT edit manually! ====================
! generated by templates/quagga/bgpd.conf.j2 with config DB data
! file: bgpd.conf
!
{% endblock banner %}
!
{% block system_init %}
hostname {{ DEVICE_METADATA['localhost']['hostname'] }}
password zebra
log syslog informational
log facility local4
! enable password {# {{ en_passwd }} TODO: param needed #}
{% endblock system_init %}
!
{% 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
bgp graceful-restart restart-time 240
bgp graceful-restart
{% for (name, prefix) in LOOPBACK_INTERFACE %}
{% if prefix | ipv4 and name == 'Loopback0' %}
bgp router-id {{ prefix | ip }}
{% endif %}
{% endfor %}
{# advertise loopback #}
{% for (name, prefix) in LOOPBACK_INTERFACE %}
{% 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 %}
{% 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
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
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
{% if bgp_peer['peer_asn'] is defined %}
neighbor {{ bgp_peer['name'] }} remote-as {{ bgp_peer['peer_asn'] }}
{% else %}
neighbor {{ bgp_peer['name'] }} remote-as {{ deployment_id_asn_map[DEVICE_METADATA['localhost']['deployment_id']] }}
{% endif %}
neighbor {{ bgp_peer['name'] }} ebgp-multihop 255
neighbor {{ bgp_peer['name'] }} soft-reconfiguration inbound
{% if bgp_peer['src_address'] is defined %}
neighbor {{ bgp_peer['name'] }} update-source {{ bgp_peer['src_address'] | ip }}
{% else %}
{% for (name, prefix) in LOOPBACK_INTERFACE %}
{% if name == 'Loopback1' %}
neighbor {{ bgp_peer['name'] }} update-source {{ prefix | ip }}
{% endif %}
{% endfor %}
{% endif %}
neighbor {{ bgp_peer['name'] }} route-map FROM_BGP_SPEAKER_V4 in
neighbor {{ bgp_peer['name'] }} route-map TO_BGP_SPEAKER_V4 out
{% 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
maximum-paths 64
exit-address-family
address-family ipv6
neighbor {{ bgp_peer['name'] }} activate
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 %}
!
20 changes: 0 additions & 20 deletions dockers/docker-fpm-frr/config.sh

This file was deleted.

65 changes: 0 additions & 65 deletions dockers/docker-fpm-frr/daemons

This file was deleted.

1 change: 0 additions & 1 deletion dockers/docker-fpm-frr/daemons.conf

This file was deleted.

43 changes: 39 additions & 4 deletions dockers/docker-fpm-frr/start.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,41 @@
#!/bin/bash
#!/usr/bin/env bash

mkdir -p /etc/frr

CONFIG_TYPE=`sonic-cfggen -d -v 'DEVICE_METADATA["localhost"]["docker_routing_config_mode"]'`

if [ -z "$CONFIG_TYPE" ] || [ "$CONFIG_TYPE" == "separated" ]; then
sonic-cfggen -d -y /etc/sonic/deployment_id_asn_map.yml -t /usr/share/sonic/templates/bgpd.conf.j2 > /etc/frr/bgpd.conf
sonic-cfggen -d -t /usr/share/sonic/templates/zebra.conf.j2 > /etc/frr/zebra.conf
touch /etc/frr/vtysh.conf
elif [ "$CONFIG_TYPE" == "unified" ]; then
sonic-cfggen -d -y /etc/sonic/deployment_id_asn_map.yml -t /usr/share/sonic/templates/frr.conf.j2 >/etc/frr/frr.conf
echo "service integrated-vtysh-config" > /etc/frr/vtysh.conf
fi

sonic-cfggen -d -t /usr/share/sonic/templates/isolate.j2 > /usr/sbin/bgp-isolate
chown root:root /usr/sbin/bgp-isolate
chmod 0755 /usr/sbin/bgp-isolate

sonic-cfggen -d -t /usr/share/sonic/templates/unisolate.j2 > /usr/sbin/bgp-unisolate
chown root:root /usr/sbin/bgp-unisolate
chmod 0755 /usr/sbin/bgp-unisolate

mkdir -p /var/sonic
echo "# Config files managed by sonic-config-engine" > /var/sonic/config_status

rm -f /var/run/rsyslogd.pid
service rsyslog start
service frr start
fpmsyncd &

supervisorctl start rsyslogd

supervisorctl start bgpcfgd

# Start Quagga processes
supervisorctl start zebra
supervisorctl start bgpd

if [ "$CONFIG_TYPE" == "unified" ]; then
supervisorctl start vtysh_b
fi

supervisorctl start fpmsyncd
Loading

0 comments on commit 5fb185c

Please sign in to comment.