diff --git a/dockers/docker-fpm-quagga/bgpd.conf.j2 b/dockers/docker-fpm-quagga/bgpd.conf.j2 index 0c848939df9d..e898ce72ae1f 100644 --- a/dockers/docker-fpm-quagga/bgpd.conf.j2 +++ b/dockers/docker-fpm-quagga/bgpd.conf.j2 @@ -19,6 +19,10 @@ log facility local4 ! ! bgp multiple-instance ! +route-map FROM_BGP_SPEAKER_V4 permit 10 +! +route-map TO_BGP_SPEAKER_V4 deny 10 +! router bgp {{ minigraph_bgp_asn }} bgp log-neighbor-changes bgp bestpath as-path multipath-relax @@ -65,6 +69,19 @@ router bgp {{ minigraph_bgp_asn }} {% endif %} {% endfor %} {% endblock bgp_sessions %} +{% block bgp_peers_with_range %} +{% for bgp_peer in minigraph_bgp_peers_with_range %} + neighbor {{ bgp_peer['name'] }} peer-group + neighbor {{ bgp_peer['name'] }} passive + neighbor {{ bgp_peer['name'] }} remote-as {{deployment_id_asn_map[deployment_id] }} + neighbor {{ bgp_peer['name'] }} ebgp-multihop 255 + neighbor {{ bgp_peer['name'] }} soft-reconfiguration inbound + neighbor {{ bgp_peer['name'] }} update-source Loopback0 + neighbor {{ bgp_peer['name'] }} route-map FROM_BGP_SPEAKER_V4 in + neighbor {{ bgp_peer['name'] }} route-map TO_BGP_SPEAKER_V4 out + bgp listen range {{ bgp_peer['ip_range'] }} peer-group {{ bgp_peer['name'] }} +{% endfor %} +{% endblock bgp_peers_with_range %} ! {% if minigraph_bgp_asn is not none %} maximum-paths 64 diff --git a/dockers/docker-fpm-quagga/start.sh b/dockers/docker-fpm-quagga/start.sh index bc3fbf4e907a..c7df6f20999d 100755 --- a/dockers/docker-fpm-quagga/start.sh +++ b/dockers/docker-fpm-quagga/start.sh @@ -2,9 +2,9 @@ mkdir -p /etc/quagga if [ -f /etc/sonic/bgp_admin.yml ]; then - sonic-cfggen -m /etc/sonic/minigraph.xml -y /etc/sonic/bgp_admin.yml -t /usr/share/sonic/templates/bgpd.conf.j2 > /etc/quagga/bgpd.conf + sonic-cfggen -m /etc/sonic/minigraph.xml -y /etc/sonic/bgp_admin.yml -y /etc/sonic/deployment_id_asn_map.yml -t /usr/share/sonic/templates/bgpd.conf.j2 > /etc/quagga/bgpd.conf else - sonic-cfggen -m /etc/sonic/minigraph.xml -t /usr/share/sonic/templates/bgpd.conf.j2 > /etc/quagga/bgpd.conf + sonic-cfggen -m /etc/sonic/minigraph.xml -y /etc/sonic/deployment_id_asn_map.yml -t /usr/share/sonic/templates/bgpd.conf.j2 > /etc/quagga/bgpd.conf fi sonic-cfggen -m /etc/sonic/minigraph.xml -t /usr/share/sonic/templates/zebra.conf.j2 > /etc/quagga/zebra.conf diff --git a/files/build_templates/sonic_debian_extension.j2 b/files/build_templates/sonic_debian_extension.j2 index 00398654b12c..647a73b5ce1c 100644 --- a/files/build_templates/sonic_debian_extension.j2 +++ b/files/build_templates/sonic_debian_extension.j2 @@ -138,6 +138,9 @@ sudo bash -c "echo ' all: off' >> $FILESYSTEM_ROOT/etc/sonic/bgp_admin.yml" # Copy SNMP configuration files sudo cp $IMAGE_CONFIGS/snmp/snmp.yml $FILESYSTEM_ROOT/etc/sonic/ +# Copy ASN configuration files +sudo cp $IMAGE_CONFIGS/asn/deployment_id_asn_map.yml $FILESYSTEM_ROOT/etc/sonic/ + # Copy sudoers configuration file sudo cp $IMAGE_CONFIGS/sudoers/sudoers $FILESYSTEM_ROOT/etc/ diff --git a/files/image_config/asn/deployment_id_asn_map.yml b/files/image_config/asn/deployment_id_asn_map.yml new file mode 100644 index 000000000000..36168f828954 --- /dev/null +++ b/files/image_config/asn/deployment_id_asn_map.yml @@ -0,0 +1,2 @@ +deployment_id_asn_map: + "1" : 65432 diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py index 7dc060900886..d552eb906364 100644 --- a/src/sonic-config-engine/minigraph.py +++ b/src/sonic-config-engine/minigraph.py @@ -244,6 +244,7 @@ def parse_dpg(dpg, hname): def parse_cpg(cpg, hname): bgp_sessions = [] myasn = None + bgp_peers_with_range = [] for child in cpg: tag = child.tag if tag == str(QName(ns, "PeeringSessions")): @@ -270,12 +271,22 @@ def parse_cpg(cpg, hname): hostname = router.find(str(QName(ns1, "Hostname"))).text if hostname == hname: myasn = int(asn) + peers = router.find(str(QName(ns1, "Peers"))) + for bgpPeer in peers.findall(str(QName(ns, "BGPPeer"))): + addr = bgpPeer.find(str(QName(ns, "Address"))).text + if bgpPeer.find(str(QName(ns1, "PeersRange"))) is not None: + name = bgpPeer.find(str(QName(ns1, "Name"))).text + ip_range = bgpPeer.find(str(QName(ns1, "PeersRange"))).text + bgp_peers_with_range.append({ + 'name': name, + 'ip_range': ip_range + }) else: for bgp_session in bgp_sessions: if hostname == bgp_session['name']: bgp_session['asn'] = int(asn) - return bgp_sessions, myasn + return bgp_sessions, myasn, bgp_peers_with_range def parse_meta(meta, hname): @@ -284,6 +295,7 @@ def parse_meta(meta, hname): ntp_servers = [] mgmt_routes = [] erspan_dst = [] + deployment_id = None device_metas = meta.find(str(QName(ns, "Devices"))) for device in device_metas.findall(str(QName(ns1, "DeviceMetadata"))): if device.find(str(QName(ns1, "Name"))).text == hname: @@ -302,7 +314,9 @@ def parse_meta(meta, hname): mgmt_routes = value_group elif name == "ErspanDestinationIpv4": erspan_dst = value_group - return syslog_servers, dhcp_servers, ntp_servers, mgmt_routes, erspan_dst + elif name == "DeploymentId": + deployment_id = value + return syslog_servers, dhcp_servers, ntp_servers, mgmt_routes, erspan_dst, deployment_id def get_console_info(devices, dev, port): @@ -396,6 +410,8 @@ def parse_xml(filename, platform=None, port_config_file=None): ntp_servers = [] mgmt_routes = [] erspan_dst = [] + bgp_peers_with_range = None + deployment_id = None hwsku_qn = QName(ns, "HwSku") hostname_qn = QName(ns, "Hostname") @@ -411,13 +427,13 @@ def parse_xml(filename, platform=None, port_config_file=None): if child.tag == str(QName(ns, "DpgDec")): (intfs, lo_intfs, mgmt_intf, vlans, pcs, acls) = parse_dpg(child, hostname) elif child.tag == str(QName(ns, "CpgDec")): - (bgp_sessions, bgp_asn) = parse_cpg(child, hostname) + (bgp_sessions, bgp_asn, bgp_peers_with_range) = parse_cpg(child, hostname) elif child.tag == str(QName(ns, "PngDec")): (neighbors, devices, console_dev, console_port, mgmt_dev, mgmt_port) = parse_png(child, hostname) elif child.tag == str(QName(ns, "UngDec")): (u_neighbors, u_devices, _, _, _, _) = parse_png(child, hostname) elif child.tag == str(QName(ns, "MetadataDeclaration")): - (syslog_servers, dhcp_servers, ntp_servers, mgmt_routes, erspan_dst) = parse_meta(child, hostname) + (syslog_servers, dhcp_servers, ntp_servers, mgmt_routes, erspan_dst, deployment_id) = parse_meta(child, hostname) Tree = lambda: defaultdict(Tree) @@ -428,6 +444,7 @@ def parse_xml(filename, platform=None, port_config_file=None): # TODO: alternatively (preferred), implement class containers for multiple-attribute entries, enabling sort by attr results['minigraph_bgp'] = sorted(bgp_sessions, key=lambda x: x['addr']) results['minigraph_bgp_asn'] = bgp_asn + results['minigraph_bgp_peers_with_range'] = bgp_peers_with_range # TODO: sort does not work properly on all interfaces of varying lengths. Need to sort by integer group(s). phyport_intfs = [] @@ -466,6 +483,7 @@ def parse_xml(filename, platform=None, port_config_file=None): results['ntp_servers'] = ntp_servers results['forced_mgmt_routes'] = mgmt_routes results['erspan_dst'] = erspan_dst + results['deployment_id'] = deployment_id return results diff --git a/src/sonic-config-engine/tests/t0-sample-bgp-speaker.xml b/src/sonic-config-engine/tests/t0-sample-bgp-speaker.xml new file mode 100644 index 000000000000..b5e373ddd868 --- /dev/null +++ b/src/sonic-config-engine/tests/t0-sample-bgp-speaker.xml @@ -0,0 +1,346 @@ + + + + + + false + switch-t0 + 10.0.0.56 + ARISTA01T1 + 10.0.0.57 + 1 + 180 + 60 + + + switch-t0 + FC00::71 + ARISTA01T1 + FC00::72 + 1 + 180 + 60 + + + false + switch-t0 + 10.0.0.58 + ARISTA02T1 + 10.0.0.59 + 1 + 180 + 60 + + + switch-t0 + FC00::75 + ARISTA02T1 + FC00::76 + 1 + 180 + 60 + + + false + switch-t0 + 10.0.0.60 + ARISTA03T1 + 10.0.0.61 + 1 + 180 + 60 + + + switch-t0 + FC00::79 + ARISTA03T1 + FC00::7A + 1 + 180 + 60 + + + false + switch-t0 + 10.0.0.62 + ARISTA04T1 + 10.0.0.63 + 1 + 180 + 60 + + + switch-t0 + FC00::7D + ARISTA04T1 + FC00::7E + 1 + 180 + 60 + + + + + 65100 + switch-t0 + + +
10.0.0.57
+ + + +
+ +
10.0.0.59
+ + + +
+ +
10.0.0.61
+ + + +
+ +
10.0.0.63
+ + + +
+ +
10.1.0.32
+ BGPSLBPassive + 10.10.10.10/26 +
+
+ +
+ + 64600 + ARISTA01T1 + + + + 64600 + ARISTA02T1 + + + + 64600 + ARISTA03T1 + + + + 64600 + ARISTA04T1 + + +
+
+ + + + + + HostIP + Loopback0 + + 10.1.0.32/32 + + 10.1.0.32/32 + + + HostIP1 + Loopback0 + + FC00:1::32/128 + + FC00:1::32/128 + + + + + HostIP + eth0 + + 10.0.0.100/24 + + 10.0.0.100/24 + + + + + + + switch-t0 + + + PortChannel01 + fortyGigE0/112 + + + + PortChannel02 + fortyGigE0/116 + + + + PortChannel03 + fortyGigE0/120 + + + + PortChannel04 + fortyGigE0/124 + + + + + + Vlan1000 + fortyGigE0/4;fortyGigE0/8;fortyGigE0/12;fortyGigE0/16;fortyGigE0/20;fortyGigE0/24;fortyGigE0/28;fortyGigE0/32;fortyGigE0/36;fortyGigE0/40;fortyGigE0/44;fortyGigE0/48;fortyGigE0/52;fortyGigE0/56;fortyGigE0/60;fortyGigE0/64;fortyGigE0/68;fortyGigE0/72;fortyGigE0/76;fortyGigE0/80;fortyGigE0/84;fortyGigE0/88;fortyGigE0/92;fortyGigE0/96 + False + 0.0.0.0/0 + + 1000 + 1000 + 192.168.0.0/27 + + + + + + PortChannel01 + 10.0.0.56/31 + + + + PortChannel01 + FC00::71/126 + + + + PortChannel02 + 10.0.0.58/31 + + + + PortChannel02 + FC00::75/126 + + + + PortChannel03 + 10.0.0.60/31 + + + + PortChannel03 + FC00::79/126 + + + + PortChannel04 + 10.0.0.62/31 + + + + PortChannel04 + FC00::7D/126 + + + + Vlan1000 + 192.168.0.1/27 + + + + + + + PortChannel01;PortChannel02;PortChannel03;PortChannel04 + + DataAcl + + + + + + + + + + DeviceInterfaceLink + ARISTA01T1 + Ethernet1/1 + switch-t0 + fortyGigE0/112 + + + DeviceInterfaceLink + ARISTA02T1 + Ethernet1/1 + switch-t0 + fortyGigE0/116 + + + DeviceInterfaceLink + ARISTA03T1 + Ethernet1/1 + switch-t0 + fortyGigE0/120 + + + DeviceInterfaceLink + ARISTA04T1 + Ethernet1/1 + switch-t0 + fortyGigE0/124 + + + + + switch-t0 + Force10-S6000 + + + ARISTA01T1 + Arista + + + ARISTA02T1 + Arista + + + ARISTA03T1 + Arista + + + ARISTA04T1 + Arista + + + + + + + switch-t0 + + + ErspanDestinationIpv4 + + 2.2.2.2 + + + DeploymentId + 1 + + + + + + + switch-t0 + Force10-S6000 +
diff --git a/src/sonic-config-engine/tests/test_cfggen.py b/src/sonic-config-engine/tests/test_cfggen.py index a4ad6cb806fc..9a305fd72aac 100644 --- a/src/sonic-config-engine/tests/test_cfggen.py +++ b/src/sonic-config-engine/tests/test_cfggen.py @@ -11,6 +11,7 @@ def setUp(self): self.sample_graph_t0 = os.path.join(self.test_dir, 't0-sample-graph.xml') self.sample_graph_simple = os.path.join(self.test_dir, 'simple-sample-graph.xml') self.sample_graph_pc_test = os.path.join(self.test_dir, 'pc-test-graph.xml') + self.sample_graph_bgp_speaker = os.path.join(self.test_dir, 't0-sample-bgp-speaker.xml') self.port_config = os.path.join(self.test_dir, 't0-sample-port-config.ini') def run_script(self, argument): @@ -97,3 +98,13 @@ def test_minigraph_neighbors(self): argument = '-m "' + self.sample_graph_t0 + '" -p "' + self.port_config + '" -v minigraph_neighbors' output = self.run_script(argument) self.assertEqual(output.strip(), "{'Ethernet116': {'name': 'ARISTA02T1', 'port': 'Ethernet1/1'}, 'Ethernet124': {'name': 'ARISTA04T1', 'port': 'Ethernet1/1'}, 'Ethernet112': {'name': 'ARISTA01T1', 'port': 'Ethernet1/1'}, 'Ethernet120': {'name': 'ARISTA03T1', 'port': 'Ethernet1/1'}}") + + def test_minigraph_peers_with_range(self): + argument = '-m "' + self.sample_graph_bgp_speaker + '" -p "' + self.port_config + '" -v minigraph_bgp_peers_with_range' + output = self.run_script(argument) + self.assertEqual(output.strip(), "[{'name': 'BGPSLBPassive', 'ip_range': '10.10.10.10/26'}]") + + def test_minigraph_deployment_id(self): + argument = '-m "' + self.sample_graph_bgp_speaker + '" -p "' + self.port_config + '" -v deployment_id' + output = self.run_script(argument) + self.assertEqual(output.strip(), "1")