From 116b86f11be2a446ee92c90c0c4f5b0d0feab788 Mon Sep 17 00:00:00 2001 From: Zhenggen Xu Date: Tue, 25 Sep 2018 22:00:14 -0700 Subject: [PATCH] FRR 4.0 integration with SONiC -- Uses SONiC FRR repo frr/4.0 (which has SONiC support) to build image -- Makefile changes to make frr4.0 builtable. -- Updated/Added FRR configuration files -- bgpd jinja template fixes To build SONiC images with FRR4.0, simply edit rules/config file and change routing stack to following: SONIC_ROUTING_STACK = frr and then build images as usual. --- .gitmodules | 2 +- dockers/docker-fpm-frr/Dockerfile.j2 | 3 +- dockers/docker-fpm-frr/bgpd.conf.j2 | 64 ++++++++++-- dockers/docker-fpm-frr/daemons | 23 +++-- .../{debian.conf => daemons.conf} | 10 +- dockers/docker-fpm-frr/vtysh.conf | 0 dockers/docker-fpm-frr/zebra.conf.j2 | 12 ++- rules/config | 4 +- rules/frr.mk | 4 +- sonic-slave/Dockerfile | 1 + src/sonic-frr/Makefile | 38 +++++-- src/sonic-frr/frr | 2 +- src/sonic-frr/sonic_frr.install | 23 ----- src/sonic-frr/sonic_frr.rules | 99 ------------------- 14 files changed, 127 insertions(+), 158 deletions(-) rename dockers/docker-fpm-frr/{debian.conf => daemons.conf} (60%) create mode 100644 dockers/docker-fpm-frr/vtysh.conf delete mode 100644 src/sonic-frr/sonic_frr.install delete mode 100755 src/sonic-frr/sonic_frr.rules diff --git a/.gitmodules b/.gitmodules index 3977babe5127..79905318f822 100644 --- a/.gitmodules +++ b/.gitmodules @@ -46,7 +46,7 @@ url = https://github.com/Azure/sonic-platform-daemons [submodule "src/sonic-frr/frr"] path = src/sonic-frr/frr - url = https://github.com/FRRouting/frr.git + url = https://github.com/Azure/sonic-frr.git [submodule "platform/p4/p4-hlir/p4-hlir-v1.1"] path = platform/p4/p4-hlir/p4-hlir-v1.1 url = https://github.com/p4lang/p4-hlir.git diff --git a/dockers/docker-fpm-frr/Dockerfile.j2 b/dockers/docker-fpm-frr/Dockerfile.j2 index 194b91f33499..f1cddbd0c416 100644 --- a/dockers/docker-fpm-frr/Dockerfile.j2 +++ b/dockers/docker-fpm-frr/Dockerfile.j2 @@ -33,7 +33,8 @@ RUN rm -rf /debs ~/.cache COPY ["*.j2", "/usr/share/sonic/templates/"] COPY ["start.sh", "config.sh", "/usr/bin/"] COPY ["daemons", "/etc/frr/"] -COPY ["debian.conf", "/etc/frr/"] +COPY ["daemons.conf", "/etc/frr/"] +COPY ["vtysh.conf", "/etc/frr/"] ENTRYPOINT /usr/bin/config.sh \ && /usr/bin/start.sh \ diff --git a/dockers/docker-fpm-frr/bgpd.conf.j2 b/dockers/docker-fpm-frr/bgpd.conf.j2 index 9afd6a5a8bf0..6eb48039a351 100644 --- a/dockers/docker-fpm-frr/bgpd.conf.j2 +++ b/dockers/docker-fpm-frr/bgpd.conf.j2 @@ -14,32 +14,40 @@ 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 -{# TODO: use lo[0] for backward compatibility, will revisit the case with multiple lo interfaces #} +{# Advertise graceful restart capability for ToR #} +{% if DEVICE_METADATA['localhost']['type'] == 'ToRRouter' %} + bgp graceful-restart +{% endif %} {% 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 %} +{% if prefix | ipv4 and name == 'Loopback0' %} network {{ prefix | ip }}/32 -{% elif prefix | ipv6 %} +{% elif prefix | ipv6 and name == 'Loopback0' %} address-family ipv6 network {{ prefix | ip }}/128 exit-address-family {% endif %} {% endfor %} {% endblock bgp_init %} +{% endif %} {% block vlan_advertisement %} {% for (name, prefix) in VLAN_INTERFACE %} {% if prefix | ipv4 %} @@ -56,13 +64,21 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} {% 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'] }} -{% if DEVICE_METADATA['localhost']['type'] == 'ToRRouter' %} - neighbor {{ neighbor_addr }} allowas-in 1 +{% 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 %} @@ -74,7 +90,11 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} {% 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 %} @@ -90,11 +110,43 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} {% 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 %} +{% 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 diff --git a/dockers/docker-fpm-frr/daemons b/dockers/docker-fpm-frr/daemons index cb7c2322c9fb..c008d1248bf3 100644 --- a/dockers/docker-fpm-frr/daemons +++ b/dockers/docker-fpm-frr/daemons @@ -1,25 +1,25 @@ -# This file tells the quagga package which daemons to start. +# This file tells the frr package which daemons to start. # # Entries are in the format: =(yes|no|priority) # 0, "no" = disabled # 1, "yes" = highest priority # 2 .. 10 = lower priorities -# Read /usr/share/doc/quagga/README.Debian for details. +# Read /usr/share/doc/frr/README.Debian for details. # # Sample configurations for these daemons can be found in -# /usr/share/doc/quagga/examples/. +# /usr/share/doc/frr/examples/. # -# ATTENTION: +# ATTENTION: # # When activation a daemon at the first time, a config file, even if it is -# empty, has to be present *and* be owned by the user and group "quagga", else -# the daemon will not be started by /etc/init.d/quagga. The permissions should +# empty, has to be present *and* be owned by the user and group "frr", else +# the daemon will not be started by /etc/init.d/frr. The permissions should # be u=rw,g=r,o=. # When using "vtysh" such a config file is also needed. It should be owned by -# group "quaggavty" and set to ug=rw,o= though. Check /etc/pam.d/quagga, too. +# group "frrvty" and set to ug=rw,o= though. Check /etc/pam.d/frr, too. # -# The watchquagga daemon is always started. Per default in monitoring-only but -# that can be changed via /etc/quagga/debian.conf. +# The watchfrr daemon is always started. Per default in monitoring-only but +# that can be changed via /etc/frr/daemons.conf. # zebra=yes bgpd=yes @@ -28,4 +28,9 @@ ospf6d=no ripd=no ripngd=no isisd=no +pimd=no +ldpd=no +nhrpd=no +eigrpd=no babeld=no +sharpd=no diff --git a/dockers/docker-fpm-frr/debian.conf b/dockers/docker-fpm-frr/daemons.conf similarity index 60% rename from dockers/docker-fpm-frr/debian.conf rename to dockers/docker-fpm-frr/daemons.conf index 4724fc87422f..33f4acd0ae88 100644 --- a/dockers/docker-fpm-frr/debian.conf +++ b/dockers/docker-fpm-frr/daemons.conf @@ -14,7 +14,15 @@ isisd_options=" --daemon -A 127.0.0.1" pimd_options=" --daemon -A 127.0.0.1" ldpd_options=" --daemon -A 127.0.0.1" nhrpd_options=" --daemon -A 127.0.0.1" +eigrpd_options=" --daemon -A 127.0.0.1" +babeld_options=" --daemon -A 127.0.0.1" +sharpd_options=" --daemon -A 127.0.0.1" # The list of daemons to watch is automatically generated by the init script. watchfrr_enable=yes -watchfrr_options=(-adz -r /usr/sbin/servicebBfrrbBrestartbB%s -s /usr/sbin/servicebBfrrbBstartbB%s -k /usr/sbin/servicebBfrrbBstopbB%s -b bB -t 30) +watchfrr_options=(-d -r /usr/sbin/servicebBfrrbBrestartbB%s -s /usr/sbin/servicebBfrrbBstartbB%s -k /usr/sbin/servicebBfrrbBstopbB%s -b bB -t 30) + +# If valgrind_enable is 'yes' the frr daemons will be started via valgrind. +# The use case for doing so is tracking down memory leaks, etc in frr. +valgrind_enable=no +valgrind=/usr/bin/valgrind diff --git a/dockers/docker-fpm-frr/vtysh.conf b/dockers/docker-fpm-frr/vtysh.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/dockers/docker-fpm-frr/zebra.conf.j2 b/dockers/docker-fpm-frr/zebra.conf.j2 index 8b967f98671c..e4586e72dd62 100644 --- a/dockers/docker-fpm-frr/zebra.conf.j2 +++ b/dockers/docker-fpm-frr/zebra.conf.j2 @@ -40,11 +40,13 @@ ip route 0.0.0.0/0 {{ MGMT_INTERFACE[(name, prefix)]['gwaddr'] }} 200 {% set lo_ipv6_addrs = [] %} {% if LOOPBACK_INTERFACE %} {% for (name, prefix) in LOOPBACK_INTERFACE %} -{% if prefix | ipv6 %} -{% if lo_ipv6_addrs.append(prefix) %} -{% endif %} -{% else %} -{% if lo_ipv4_addrs.append(prefix) %} +{% if name == 'Loopback0' %} +{% if prefix | ipv6 %} +{% if lo_ipv6_addrs.append(prefix) %} +{% endif %} +{% else %} +{% if lo_ipv4_addrs.append(prefix) %} +{% endif %} {% endif %} {% endif %} {% endfor %} diff --git a/rules/config b/rules/config index 5e8a3389530d..ae3ca4f83960 100644 --- a/rules/config +++ b/rules/config @@ -45,8 +45,8 @@ DEFAULT_PASSWORD = YourPaSsWoRd # SONIC_INSTALL_DEBUG_TOOLS = y # SONIC_ROUTING_STACK - specify the routing-stack being elected to drive SONiC's control-plane. -# Quagga will be the default routing-stack for all the SONiC platforms. Other supported -# routing-stacks: frr, gobgp. +# Supported routing stacks on SONiC are: +# routing-stacks: quagga, frr. SONIC_ROUTING_STACK = quagga # ENABLE_SYNCD_RPC - build docker-syncd with rpc packages for testing purposes. diff --git a/rules/frr.mk b/rules/frr.mk index 7fb1837585aa..2b7cc1fa14e4 100644 --- a/rules/frr.mk +++ b/rules/frr.mk @@ -1,9 +1,9 @@ # FRRouting (frr) package -FRR_VERSION = 3.0 +FRR_VERSION = 4.0 export FRR_VERSION -FRR = frr_$(FRR_VERSION)_amd64.deb +FRR = frr_$(FRR_VERSION)-1~sonic.debian8+1_amd64.deb $(FRR)_DEPENDS += $(LIBSNMP_DEV) $(FRR)_SRC_PATH = $(SRC_PATH)/sonic-frr SONIC_MAKE_DEBS += $(FRR) diff --git a/sonic-slave/Dockerfile b/sonic-slave/Dockerfile index c284161c7edd..76ec1781d526 100644 --- a/sonic-slave/Dockerfile +++ b/sonic-slave/Dockerfile @@ -63,6 +63,7 @@ RUN apt-get update && apt-get install -y \ libjson0-dev \ libsystemd-dev \ python-ipaddr \ + install-info \ # For libnl3 (local) build cdbs \ # For SAI meta build diff --git a/src/sonic-frr/Makefile b/src/sonic-frr/Makefile index b044781a60f2..e3c82e158ec2 100644 --- a/src/sonic-frr/Makefile +++ b/src/sonic-frr/Makefile @@ -2,18 +2,40 @@ SHELL = /bin/bash .SHELLFLAGS += -e -MAIN_TARGET = frr_$(FRR_VERSION)_amd64.deb +MAIN_TARGET = frr_$(FRR_VERSION)-1~sonic.debian8+1_amd64.deb $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : - # Replacing frr's rules/install files with SONiC's own versions to activate - # specific knobs and adjust install process to address SONiC's needs. - cp sonic_frr.rules frr/debian/rules - cp sonic_frr.install frr/debian/frr.install - # Build the package + # Build the package pushd ./frr - rm -f debian/*.debhelper.log + + # clean up the previous build + rm -rf debian + rm frr*.tar.gz + rm frr*.tar.xz + rm frr*.dsc + + # make a dist tarball + ./bootstrap.sh + ./configure + make dist + + # Create backports debian sources + cp -a debianpkg debian + make -f debian/rules backports + + # new directory to build the package + rm -rf frrpkg + mkdir frrpkg + cd frrpkg + tar xf ../frr_*.orig.tar.gz + cd frr* + tar xf ../../frr_*sonic.debian8*.debian.tar.xz + + # build package dpkg-buildpackage -rfakeroot -b -us -uc + cd .. + mv $* $(DEST)/ + popd - mv $* $(DEST)/ diff --git a/src/sonic-frr/frr b/src/sonic-frr/frr index 5424c62d6e9d..aaf54fda1378 160000 --- a/src/sonic-frr/frr +++ b/src/sonic-frr/frr @@ -1 +1 @@ -Subproject commit 5424c62d6e9d574a00529edfc0a0b3bb3beb8811 +Subproject commit aaf54fda1378167d7ce317f5b4a16c3a61ef59eb diff --git a/src/sonic-frr/sonic_frr.install b/src/sonic-frr/sonic_frr.install deleted file mode 100644 index b0bf8d6909a7..000000000000 --- a/src/sonic-frr/sonic_frr.install +++ /dev/null @@ -1,23 +0,0 @@ -etc/frr/ -etc/init.d/ -usr/bin/vtysh -usr/include/frr/ -usr/lib/ -tools/frr-reload.py usr/lib/frr/ -tools/frr usr/lib/frr -usr/share/doc/frr/ -usr/share/man/man1/vtysh.1 -usr/share/man/man1/frr.1 -usr/share/man/man8 -usr/share/man/man8/bgpd.8 -usr/share/man/man8/ospf6d.8 -usr/share/man/man8/ospfd.8 -usr/share/man/man8/ripd.8 -usr/share/man/man8/ripngd.8 -usr/share/man/man8/zebra.8 -usr/share/man/man8/isisd.8 -usr/share/man/man8/watchfrr.8 -usr/share/snmp/mibs/ -cumulus/etc/* etc/ -tools/*.service lib/systemd/system -debian/frr.conf usr/lib/tmpfiles.d diff --git a/src/sonic-frr/sonic_frr.rules b/src/sonic-frr/sonic_frr.rules deleted file mode 100755 index f4e0706b5c33..000000000000 --- a/src/sonic-frr/sonic_frr.rules +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/make -f - -export DH_VERBOSE=1 -export DEB_BUILD_HARDENING=1 -export DH_OPTIONS=-v - -ifeq ($(WANT_SNMP), 1) - USE_SNMP=--enable-snmp - $(warning "DEBIAN: SNMP enabled, sorry for your inconvenience") -else - $(warning "DEBIAN: SNMP disabled, see README.Debian") -endif - -ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) - DEBIAN_JOBS := $(subst parallel=,,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) -endif - -ifdef DEBIAN_JOBS -MAKEFLAGS += -j$(DEBIAN_JOBS) -endif - -%: - dh $@ --with=systemd,autoreconf --parallel --dbg-package=frr-dbg --list-missing - -override_dh_auto_configure: - # Frr needs /proc to check some BSD vs Linux specific stuff. - # Else it fails with an obscure error message pointing out that - # IPCTL_FORWARDING is an undefined symbol which is not very helpful. - @if ! [ -d /proc/1 ]; then \ - echo "./configure needs a mounted /proc"; \ - exit 1; \ - fi - - if ! [ -e config.status ]; then \ - dh_auto_configure -- \ - --enable-exampledir=/usr/share/doc/frr/examples/ \ - --localstatedir=/var/run/frr \ - --sbindir=/usr/lib/frr \ - --sysconfdir=/etc/frr \ - $(USE_SNMP) \ - --enable-vtysh=yes \ - --enable-isisd=yes \ - --enable-multipath=256 \ - --enable-user=frr \ - --enable-group=frr \ - --enable-vty-group=frrvty \ - --enable-configfile-mask=0640 \ - --enable-logfile-mask=0640 \ - --enable-werror \ - --enable-gcc-rdynamic \ - --with-libpam \ - --enable-systemd=yes \ - --enable-poll=yes \ - --enable-dependency-tracking \ - --enable-bgp-vnc=no \ - --enable-tcp-zebra \ - --enable-fpm; \ - fi - -override_dh_auto_build: - #dh_auto_build - $(MAKE) - dh_auto_build -- -C doc draft-zebra-00.txt - - - # doc/ is a bit crazy -ifeq ($(GENERATE_PDF), 1) - dh_auto_build -- -C doc frr.pdf || true # pdfetex fails with exit code 1 but still produces a good looking .pdf -endif - rm -vf doc/frr.info - dh_auto_build -- -C doc frr.info - rm -vf doc/frr.info.html* - -override_dh_auto_test: - -override_dh_auto_install: - dh_auto_install - - # cleaning up the info dir - rm -f debian/tmp/usr/share/info/dir* - - # install config files - mkdir -p debian/tmp/etc/frr/ - perl -pi -e 's#^!log file #!log file /var/log/frr/#' debian/tmp/usr/share/doc/frr/examples/*sample* - - # installing frr initialization script - mkdir -p debian/tmp/etc/init.d/ - cp debian/tmp/usr/lib/frr/frr debian/tmp/etc/init.d/ - - # installing the Frr specific SNMP MIB -ifeq ($(WANT_SNMP), 1) - install -D -m 644 ./zebra/GNOME-PRODUCT-ZEBRA-MIB debian/tmp/usr/share/snmp/mibs/GNOME-PRODUCT-ZEBRA-MIB -else - mkdir -p debian/tmp/usr/share/snmp/mibs/ -endif - - # cleaning .la files - sed -i "/dependency_libs/ s/'.*'/''/" debian/tmp/usr/lib/*.la -