From c48cf83c4d89779da355ae2a81f442a26799d311 Mon Sep 17 00:00:00 2001 From: Wei Bai Date: Sat, 29 Jun 2019 16:16:56 +0800 Subject: [PATCH 01/15] Add special parsing for T2 chassis frontend --- src/sonic-config-engine/minigraph.py | 69 ++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py index 8d08b399b434..1bc1de3014d8 100644 --- a/src/sonic-config-engine/minigraph.py +++ b/src/sonic-config-engine/minigraph.py @@ -26,6 +26,10 @@ ns2 = "Microsoft.Search.Autopilot.NetMux" ns3 = "http://www.w3.org/2001/XMLSchema-instance" +# Device types +spine_chassis_frontend_role = 'SpineChassisFrontendRouter' +chassis_backend_role = 'ChassisBackendRouter' + class minigraph_encoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, ( @@ -413,6 +417,67 @@ def parse_deviceinfo(meta, hwsku): port_speeds[port_alias_map.get(alias, alias)] = speed return port_speeds, port_descriptions +# Special parsing for spine chassis frontend +def parse_spine_chassis_fe(results, lo_intfs, phyport_intfs, pc_intfs, devices): + chassis_vnet ='VnetFE' + chassis_vxlan_tunnel = 'TunnelInt' + chassis_vni = 8000 + + # Vxlan tunnel information + lo_addr = '0.0.0.0' + for lo in lo_intfs: + lo_network = ipaddress.IPNetwork(lo[1]) + if lo_network.version == 4: + lo_addr = str(lo_network.ip) + break + + results['VXLAN_TUNNEL'] = {chassis_vxlan_tunnel: { + 'source_ip': lo_addr + }} + + # Vnet information + results['VNET'] = {chassis_vnet: { + 'vxlan_tunnel': chassis_vxlan_tunnel, + 'vni': chassis_vni + }} + + # Find physical L3 interfaces that should be enslaved to Vnet + for intf in phyport_intfs: + if isinstance(intf, tuple) == False: + continue + + # intf = (intf name, IP prefix) + intf_name = intf[0] + neighbor_router = results['DEVICE_NEIGHBOR'][intf_name]['name'] + + # If the neighbor router is an external router + if devices[neighbor_router]['type'] != chassis_backend_role: + + # Enslave the interface to a Vnet + if intf_name in phyport_intfs: + phyport_intfs[intf_name] = {'vnet_name': chassis_vnet} + else: + print >> sys.stderr, 'Warning: cannot find the key %s' % (intf_name) + + # Find port chennel interfaces that should be enslaved to Vnet + for pc_intf in pc_intfs: + if isinstance(pc_intf, tuple) == False: + continue + + # pc intf = (pc intf name, IP prefix) + pc_intf_name = pc_intf[0] + neighbor_router = results['DEVICE_NEIGHBOR'][pc_intf_name]['name'] + + # If the neighbor router is an external router + if devices[neighbor_router]['type'] != chassis_backend_role: + + # Enslave the port channel interface to a Vnet + if pc_intf_name in pc_intfs: + pc_intfs[pc_intf_name] = {'vnet_name': chassis_vnet} + else: + print >> sys.stderr, 'Warning: cannot find the key %s' % (pc_intf_name) + + def parse_xml(filename, platform=None, port_config_file=None): root = ET.parse(filename).getroot() mini_graph_path = filename @@ -643,6 +708,10 @@ def parse_xml(filename, platform=None, port_config_file=None): count += 1 results['MIRROR_SESSION'] = mirror_sessions + # Special parsing for spine chassis frontend routers + if current_device['type'] == spine_chassis_frontend_role: + parse_spine_chassis_fe(results, lo_intfs, phyport_intfs, pc_intfs, devices) + return results From f6d3c60a93869813754c91f5683cc204124a25d2 Mon Sep 17 00:00:00 2001 From: Wei Bai Date: Sun, 30 Jun 2019 00:21:08 +0800 Subject: [PATCH 02/15] Parse VNI in minigraph file VNI is in DPG --- src/sonic-config-engine/minigraph.py | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py index 1bc1de3014d8..4525914ee777 100644 --- a/src/sonic-config-engine/minigraph.py +++ b/src/sonic-config-engine/minigraph.py @@ -30,6 +30,9 @@ spine_chassis_frontend_role = 'SpineChassisFrontendRouter' chassis_backend_role = 'ChassisBackendRouter' +# Default Virtual Network Index (VNI) +vni_default = 8000 + class minigraph_encoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, ( @@ -153,6 +156,14 @@ def parse_dpg(dpg, hname): if hostname.text.lower() != hname.lower(): continue + vni = vni_default + vni_element = child.find(str(QName(ns, "VNI"))) + if vni_element != None: + if vni_element.text.isdigit(): + vni = int(vni_element.text) + else: + print >> sys.stderr, "VNI must be an integer (use default VNI %d instead)" % vni_default + ipintfs = child.find(str(QName(ns, "IPInterfaces"))) intfs = {} for ipintf in ipintfs.findall(str(QName(ns, "IPInterface"))): @@ -294,8 +305,8 @@ def parse_dpg(dpg, hname): except: print >> sys.stderr, "Warning: Ignoring Control Plane ACL %s without type" % aclname - return intfs, lo_intfs, mgmt_intf, vlans, vlan_members, pcs, pc_members, acls - return None, None, None, None, None, None, None + return intfs, lo_intfs, mgmt_intf, vlans, vlan_members, pcs, pc_members, acls, vni + return None, None, None, None, None, None, None, None, None def parse_cpg(cpg, hname): @@ -418,10 +429,10 @@ def parse_deviceinfo(meta, hwsku): return port_speeds, port_descriptions # Special parsing for spine chassis frontend -def parse_spine_chassis_fe(results, lo_intfs, phyport_intfs, pc_intfs, devices): +def parse_spine_chassis_fe(results, vni, lo_intfs, phyport_intfs, pc_intfs, devices): chassis_vnet ='VnetFE' chassis_vxlan_tunnel = 'TunnelInt' - chassis_vni = 8000 + chassis_vni = vni # Vxlan tunnel information lo_addr = '0.0.0.0' @@ -527,7 +538,7 @@ def parse_xml(filename, platform=None, port_config_file=None): port_alias_map.update(alias_map) for child in root: if child.tag == str(QName(ns, "DpgDec")): - (intfs, lo_intfs, mgmt_intf, vlans, vlan_members, pcs, pc_members, acls) = parse_dpg(child, hostname) + (intfs, lo_intfs, mgmt_intf, vlans, vlan_members, pcs, pc_members, acls, vni) = parse_dpg(child, hostname) elif child.tag == str(QName(ns, "CpgDec")): (bgp_sessions, bgp_asn, bgp_peers_with_range) = parse_cpg(child, hostname) elif child.tag == str(QName(ns, "PngDec")): @@ -710,7 +721,7 @@ def parse_xml(filename, platform=None, port_config_file=None): # Special parsing for spine chassis frontend routers if current_device['type'] == spine_chassis_frontend_role: - parse_spine_chassis_fe(results, lo_intfs, phyport_intfs, pc_intfs, devices) + parse_spine_chassis_fe(results, vni, lo_intfs, phyport_intfs, pc_intfs, devices) return results From bf9f6fa225e375266a5162e19afd6dd78036dd5a Mon Sep 17 00:00:00 2001 From: Wei Bai Date: Sun, 30 Jun 2019 00:21:19 +0800 Subject: [PATCH 03/15] Add new minigraph test --- .../tests/t2-chassis-fe-graph-vni.xml | 249 ++++++++++++++++++ .../tests/t2-chassis-fe-graph.xml | 248 +++++++++++++++++ .../tests/t2-chassis-fe-port-config.ini | 33 +++ src/sonic-config-engine/tests/test_cfggen.py | 46 ++++ .../tests/test_minigraph_case.py | 47 ++++ 5 files changed, 623 insertions(+) create mode 100644 src/sonic-config-engine/tests/t2-chassis-fe-graph-vni.xml create mode 100644 src/sonic-config-engine/tests/t2-chassis-fe-graph.xml create mode 100644 src/sonic-config-engine/tests/t2-chassis-fe-port-config.ini diff --git a/src/sonic-config-engine/tests/t2-chassis-fe-graph-vni.xml b/src/sonic-config-engine/tests/t2-chassis-fe-graph-vni.xml new file mode 100644 index 000000000000..f820b180f701 --- /dev/null +++ b/src/sonic-config-engine/tests/t2-chassis-fe-graph-vni.xml @@ -0,0 +1,249 @@ + + + + + + SpineFront01 + 192.168.0.2 + Leaf01 + 192.168.0.1 + 1 + 10 + 3 + + + SpineFront01 + 172.16.0.1 + SpineBack01 + 172.16.0.2 + 1 + 10 + 3 + + + SpineFront01 + 172.16.0.9 + SpineBack02 + 172.16.0.10 + 1 + 10 + 3 + + + SpineFront01 + 4.0.0.0 + SpineFront02 + 4.0.0.1 + 10 + 10 + 3 + + + + + 4000 + SpineFront01 + + +
192.168.0.1
+ + + +
+ +
172.16.0.2
+ + + +
+ +
172.16.0.10
+ + + +
+ +
4.0.0.1
+ + + +
+
+ +
+ + 3000 + Leaf01 + + + + 5000 + SpineBack01 + + + + 5000 + SpineBack02 + + + + 4000 + SpineFront02 + + +
+
+ + + 9000 + + + + HostIP + Loopback0 + + 4.0.0.0/32 + + 4.0.0.0/32 + + + + + + + + SpineFront01 + + + + + + Ethernet0 + 192.168.0.2/30 + + + + Ethernet4 + 172.16.0.1/30 + + + + Ethernet8 + 172.16.0.9/30 + + + + + + + + + + + + DeviceInterfaceLink + Leaf01 + Ethernet4 + SpineFront01 + Ethernet0 + + + DeviceInterfaceLink + SpineBack01 + Ethernet0 + SpineFront01 + Ethernet4 + + + DeviceInterfaceLink + SpineBack02 + Ethernet4 + SpineFront01 + Ethernet8 + + + + + SpineFront01 + Force10-S6000 + + + SpineFront02 + Force10-S6000 + + + Leaf01 + Force10-S6000 + + + SpineBack01 + Force10-S6000 + + + SpineBack02 + Force10-S6000 + + + + + + true + + + DeviceInterface + + true + false + 1 + Ethernet0 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + false + 1 + Ethernet4 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + false + 1 + Ethernet8 + + false + 0 + 0 + 40000 + + + false + 0 + Force10-S6000 + + + + + + + SpineFront01 + + + + + + SpineFront01 + Force10-S6000 +
diff --git a/src/sonic-config-engine/tests/t2-chassis-fe-graph.xml b/src/sonic-config-engine/tests/t2-chassis-fe-graph.xml new file mode 100644 index 000000000000..76320b766be5 --- /dev/null +++ b/src/sonic-config-engine/tests/t2-chassis-fe-graph.xml @@ -0,0 +1,248 @@ + + + + + + SpineFront01 + 192.168.0.2 + Leaf01 + 192.168.0.1 + 1 + 10 + 3 + + + SpineFront01 + 172.16.0.1 + SpineBack01 + 172.16.0.2 + 1 + 10 + 3 + + + SpineFront01 + 172.16.0.9 + SpineBack02 + 172.16.0.10 + 1 + 10 + 3 + + + SpineFront01 + 4.0.0.0 + SpineFront02 + 4.0.0.1 + 10 + 10 + 3 + + + + + 4000 + SpineFront01 + + +
192.168.0.1
+ + + +
+ +
172.16.0.2
+ + + +
+ +
172.16.0.10
+ + + +
+ +
4.0.0.1
+ + + +
+
+ +
+ + 3000 + Leaf01 + + + + 5000 + SpineBack01 + + + + 5000 + SpineBack02 + + + + 4000 + SpineFront02 + + +
+
+ + + + + + HostIP + Loopback0 + + 4.0.0.0/32 + + 4.0.0.0/32 + + + + + + + + SpineFront01 + + + + + + Ethernet0 + 192.168.0.2/30 + + + + Ethernet4 + 172.16.0.1/30 + + + + Ethernet8 + 172.16.0.9/30 + + + + + + + + + + + + DeviceInterfaceLink + Leaf01 + Ethernet4 + SpineFront01 + Ethernet0 + + + DeviceInterfaceLink + SpineBack01 + Ethernet0 + SpineFront01 + Ethernet4 + + + DeviceInterfaceLink + SpineBack02 + Ethernet4 + SpineFront01 + Ethernet8 + + + + + SpineFront01 + Force10-S6000 + + + SpineFront02 + Force10-S6000 + + + Leaf01 + Force10-S6000 + + + SpineBack01 + Force10-S6000 + + + SpineBack02 + Force10-S6000 + + + + + + true + + + DeviceInterface + + true + false + 1 + Ethernet0 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + false + 1 + Ethernet4 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + false + 1 + Ethernet8 + + false + 0 + 0 + 40000 + + + false + 0 + Force10-S6000 + + + + + + + SpineFront01 + + + + + + SpineFront01 + Force10-S6000 +
diff --git a/src/sonic-config-engine/tests/t2-chassis-fe-port-config.ini b/src/sonic-config-engine/tests/t2-chassis-fe-port-config.ini new file mode 100644 index 000000000000..1a9786c590e6 --- /dev/null +++ b/src/sonic-config-engine/tests/t2-chassis-fe-port-config.ini @@ -0,0 +1,33 @@ +# name lanes +Ethernet0 0,1,2,3 +Ethernet4 4,5,6,7 +Ethernet8 8,9,10,11 +Ethernet12 12,13,14,15 +Ethernet16 16,17,18,19 +Ethernet20 20,21,22,23 +Ethernet24 24,25,26,27 +Ethernet28 28,29,30,31 +Ethernet32 32,33,34,35 +Ethernet36 36,37,38,39 +Ethernet40 40,41,42,43 +Ethernet44 44,45,46,47 +Ethernet48 48,49,50,51 +Ethernet52 52,53,54,55 +Ethernet56 56,57,58,59 +Ethernet60 60,61,62,63 +Ethernet64 64,65,66,67 +Ethernet68 68,69,70,71 +Ethernet72 72,73,74,75 +Ethernet76 76,77,78,79 +Ethernet80 80,81,82,83 +Ethernet84 84,85,86,87 +Ethernet88 88,89,90,91 +Ethernet92 92,93,94,95 +Ethernet96 96,97,98,99 +Ethernet100 100,101,102,103 +Ethernet104 104,105,106,107 +Ethernet108 108,109,110,111 +Ethernet112 112,113,114,115 +Ethernet116 116,117,118,119 +Ethernet120 120,121,122,123 +Ethernet124 124,125,126,127 \ No newline at end of file diff --git a/src/sonic-config-engine/tests/test_cfggen.py b/src/sonic-config-engine/tests/test_cfggen.py index f267651ff675..64a6c3e0948c 100644 --- a/src/sonic-config-engine/tests/test_cfggen.py +++ b/src/sonic-config-engine/tests/test_cfggen.py @@ -13,8 +13,11 @@ def setUp(self): self.sample_graph_metadata = os.path.join(self.test_dir, 'simple-sample-graph-metadata.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.sample_graph_t2_chassis_fe = os.path.join(self.test_dir, 't2-chassis-fe-graph.xml') + self.sample_graph_t2_chassis_fe_vni = os.path.join(self.test_dir, 't2-chassis-fe-graph-vni.xml') self.sample_device_desc = os.path.join(self.test_dir, 'device.xml') self.port_config = os.path.join(self.test_dir, 't0-sample-port-config.ini') + self.t2_chassis_fe_port_config = os.path.join(self.test_dir, 't2-chassis-fe-port-config.ini') def run_script(self, argument, check_stderr=False): print '\n Running sonic-cfggen ' + argument @@ -239,3 +242,46 @@ def test_metadata_ntp(self): output = self.run_script(argument) self.assertEqual(output.strip(), "{'10.0.10.1': {}, '10.0.10.2': {}}") + def test_minigraph_t2_chassis_fe_type(self): + argument = '-m "' + self.sample_graph_t2_chassis_fe + '" -p "' + self.t2_chassis_fe_port_config + '" -v "DEVICE_METADATA[\'localhost\'][\'type\']"' + output = self.run_script(argument) + self.assertEqual(output.strip(), 'SpineChassisFrontendRouter') + + def test_minigraph_t2_chassis_fe_interfaces(self): + argument = '-m "' + self.sample_graph_t2_chassis_fe + '" -p "' + self.t2_chassis_fe_port_config + '" -v "INTERFACE"' + output = self.run_script(argument) + self.assertEqual(output.strip(), + "{'Ethernet8': {}, " + "('Ethernet8', '172.16.0.9/30'): {}, " + "'Ethernet0': {'vnet_name': 'VnetFE'}, " + "('Ethernet4', '172.16.0.1/30'): {}, " + "('Ethernet0', '192.168.0.2/30'): {}, " + "'Ethernet4': {}}") + + def test_minigraph_vnet(self): + argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v "VNET"' + output = self.run_script(argument) + self.assertEqual(output.strip(), "") + + # Test a minigraph file where VNI is not specified + # Default VNI is 8000 + def test_minigraph_t2_chassis_fe_vnet(self): + argument = '-m "' + self.sample_graph_t2_chassis_fe + '" -p "' + self.t2_chassis_fe_port_config + '" -v "VNET"' + output = self.run_script(argument) + self.assertEqual(output.strip(), "{'VnetFE': {'vxlan_tunnel': 'TunnelInt', 'vni': 8000}}") + + # Test a minigraph file where VNI is specified + def test_minigraph_t2_chassis_fe_vnet2(self): + argument = '-m "' + self.sample_graph_t2_chassis_fe_vni + '" -p "' + self.t2_chassis_fe_port_config + '" -v "VNET"' + output = self.run_script(argument) + self.assertEqual(output.strip(), "{'VnetFE': {'vxlan_tunnel': 'TunnelInt', 'vni': 9000}}") + + def test_minigraph_vxlan(self): + argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v "VXLAN_TUNNEL"' + output = self.run_script(argument) + self.assertEqual(output.strip(), "") + + def test_minigraph_t2_chassis_fe_vxlan(self): + argument = '-m "' + self.sample_graph_t2_chassis_fe + '" -p "' + self.t2_chassis_fe_port_config + '" -v "VXLAN_TUNNEL"' + output = self.run_script(argument) + self.assertEqual(output.strip(), "{'TunnelInt': {'source_ip': '4.0.0.0'}}") \ No newline at end of file diff --git a/src/sonic-config-engine/tests/test_minigraph_case.py b/src/sonic-config-engine/tests/test_minigraph_case.py index d363acdca074..568b346bc9fd 100644 --- a/src/sonic-config-engine/tests/test_minigraph_case.py +++ b/src/sonic-config-engine/tests/test_minigraph_case.py @@ -8,7 +8,10 @@ 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.sample_graph = os.path.join(self.test_dir, 'simple-sample-graph-case.xml') + self.sample_graph_t2_chassis_fe = os.path.join(self.test_dir, 't2-chassis-fe-graph.xml') + self.sample_graph_t2_chassis_fe_vni = os.path.join(self.test_dir, 't2-chassis-fe-graph-vni.xml') self.port_config = os.path.join(self.test_dir, 't0-sample-port-config.ini') + self.t2_chassis_fe_port_config = os.path.join(self.test_dir, 't2-chassis-fe-port-config.ini') def run_script(self, argument, check_stderr=False): print '\n Running sonic-cfggen ' + argument @@ -123,3 +126,47 @@ def test_metadata_ntp(self): argument = '-m "' + self.sample_graph + '" -p "' + self.port_config + '" -v "NTP_SERVER"' output = self.run_script(argument) self.assertEqual(output.strip(), "{'10.0.10.1': {}, '10.0.10.2': {}}") + + def test_minigraph_t2_chassis_fe_type(self): + argument = '-m "' + self.sample_graph_t2_chassis_fe + '" -p "' + self.t2_chassis_fe_port_config + '" -v "DEVICE_METADATA[\'localhost\'][\'type\']"' + output = self.run_script(argument) + self.assertEqual(output.strip(), 'SpineChassisFrontendRouter') + + def test_minigraph_t2_chassis_fe_interfaces(self): + argument = '-m "' + self.sample_graph_t2_chassis_fe + '" -p "' + self.t2_chassis_fe_port_config + '" -v "INTERFACE"' + output = self.run_script(argument) + self.assertEqual(output.strip(), + "{'Ethernet8': {}, " + "('Ethernet8', '172.16.0.9/30'): {}, " + "'Ethernet0': {'vnet_name': 'VnetFE'}, " + "('Ethernet4', '172.16.0.1/30'): {}, " + "('Ethernet0', '192.168.0.2/30'): {}, " + "'Ethernet4': {}}") + + def test_minigraph_vnet(self): + argument = '-m "' + self.sample_graph + '" -p "' + self.port_config + '" -v "VNET"' + output = self.run_script(argument) + self.assertEqual(output.strip(), "") + + # Test a minigraph file where VNI is not specified + # Default VNI is 8000 + def test_minigraph_t2_chassis_fe_vnet(self): + argument = '-m "' + self.sample_graph_t2_chassis_fe + '" -p "' + self.t2_chassis_fe_port_config + '" -v "VNET"' + output = self.run_script(argument) + self.assertEqual(output.strip(), "{'VnetFE': {'vxlan_tunnel': 'TunnelInt', 'vni': 8000}}") + + # Test a minigraph file where VNI is specified + def test_minigraph_t2_chassis_fe_vnet2(self): + argument = '-m "' + self.sample_graph_t2_chassis_fe_vni + '" -p "' + self.t2_chassis_fe_port_config + '" -v "VNET"' + output = self.run_script(argument) + self.assertEqual(output.strip(), "{'VnetFE': {'vxlan_tunnel': 'TunnelInt', 'vni': 9000}}") + + def test_minigraph_vxlan(self): + argument = '-m "' + self.sample_graph + '" -p "' + self.port_config + '" -v "VXLAN_TUNNEL"' + output = self.run_script(argument) + self.assertEqual(output.strip(), "") + + def test_minigraph_t2_chassis_fe_vxlan(self): + argument = '-m "' + self.sample_graph_t2_chassis_fe + '" -p "' + self.t2_chassis_fe_port_config + '" -v "VXLAN_TUNNEL"' + output = self.run_script(argument) + self.assertEqual(output.strip(), "{'TunnelInt': {'source_ip': '4.0.0.0'}}") \ No newline at end of file From 5f1859f78f2437f22f79e79a2d6dde66329d5702 Mon Sep 17 00:00:00 2001 From: Wei Bai Date: Sun, 30 Jun 2019 00:50:55 +0800 Subject: [PATCH 04/15] Fix Indentation Errors --- src/sonic-config-engine/tests/test_cfggen.py | 2 +- src/sonic-config-engine/tests/test_minigraph_case.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sonic-config-engine/tests/test_cfggen.py b/src/sonic-config-engine/tests/test_cfggen.py index 64a6c3e0948c..af7a7c587ff3 100644 --- a/src/sonic-config-engine/tests/test_cfggen.py +++ b/src/sonic-config-engine/tests/test_cfggen.py @@ -281,7 +281,7 @@ def test_minigraph_vxlan(self): output = self.run_script(argument) self.assertEqual(output.strip(), "") - def test_minigraph_t2_chassis_fe_vxlan(self): + def test_minigraph_t2_chassis_fe_vxlan(self): argument = '-m "' + self.sample_graph_t2_chassis_fe + '" -p "' + self.t2_chassis_fe_port_config + '" -v "VXLAN_TUNNEL"' output = self.run_script(argument) self.assertEqual(output.strip(), "{'TunnelInt': {'source_ip': '4.0.0.0'}}") \ No newline at end of file diff --git a/src/sonic-config-engine/tests/test_minigraph_case.py b/src/sonic-config-engine/tests/test_minigraph_case.py index 568b346bc9fd..cb721efa3843 100644 --- a/src/sonic-config-engine/tests/test_minigraph_case.py +++ b/src/sonic-config-engine/tests/test_minigraph_case.py @@ -166,7 +166,7 @@ def test_minigraph_vxlan(self): output = self.run_script(argument) self.assertEqual(output.strip(), "") - def test_minigraph_t2_chassis_fe_vxlan(self): + def test_minigraph_t2_chassis_fe_vxlan(self): argument = '-m "' + self.sample_graph_t2_chassis_fe + '" -p "' + self.t2_chassis_fe_port_config + '" -v "VXLAN_TUNNEL"' output = self.run_script(argument) self.assertEqual(output.strip(), "{'TunnelInt': {'source_ip': '4.0.0.0'}}") \ No newline at end of file From 271dd71014c8443f024cc665991ad055d0f0d459 Mon Sep 17 00:00:00 2001 From: Wei Bai Date: Sun, 30 Jun 2019 03:00:35 +0800 Subject: [PATCH 05/15] Support enslaving port channel interfaces to vnet --- src/sonic-config-engine/minigraph.py | 20 +- .../tests/t2-chassis-fe-graph-pc.xml | 324 ++++++++++++++++++ 2 files changed, 341 insertions(+), 3 deletions(-) create mode 100644 src/sonic-config-engine/tests/t2-chassis-fe-graph-pc.xml diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py index 4525914ee777..2d8bad7a315a 100644 --- a/src/sonic-config-engine/minigraph.py +++ b/src/sonic-config-engine/minigraph.py @@ -429,7 +429,7 @@ def parse_deviceinfo(meta, hwsku): return port_speeds, port_descriptions # Special parsing for spine chassis frontend -def parse_spine_chassis_fe(results, vni, lo_intfs, phyport_intfs, pc_intfs, devices): +def parse_spine_chassis_fe(results, vni, lo_intfs, phyport_intfs, pc_intfs, pc_members, devices): chassis_vnet ='VnetFE' chassis_vxlan_tunnel = 'TunnelInt' chassis_vni = vni @@ -475,9 +475,23 @@ def parse_spine_chassis_fe(results, vni, lo_intfs, phyport_intfs, pc_intfs, devi if isinstance(pc_intf, tuple) == False: continue + # Get port channel interface name # pc intf = (pc intf name, IP prefix) pc_intf_name = pc_intf[0] - neighbor_router = results['DEVICE_NEIGHBOR'][pc_intf_name]['name'] + + # Get an interface that is enslaved to this port channel + intf_name = None + for pc_member in pc_members: + if isinstance(pc_member, tuple) and pc_member[0] == pc_intf_name: + intf_name = pc_member[1] + break + + if intf_name == None: + print >> sys.stderr, 'Warning: cannot find any interfaces enslaved to %s' % (pc_intf_name) + continue + + # Get the neighbor router of this port channel interface + neighbor_router = results['DEVICE_NEIGHBOR'][intf_name]['name'] # If the neighbor router is an external router if devices[neighbor_router]['type'] != chassis_backend_role: @@ -721,7 +735,7 @@ def parse_xml(filename, platform=None, port_config_file=None): # Special parsing for spine chassis frontend routers if current_device['type'] == spine_chassis_frontend_role: - parse_spine_chassis_fe(results, vni, lo_intfs, phyport_intfs, pc_intfs, devices) + parse_spine_chassis_fe(results, vni, lo_intfs, phyport_intfs, pc_intfs, pc_members, devices) return results diff --git a/src/sonic-config-engine/tests/t2-chassis-fe-graph-pc.xml b/src/sonic-config-engine/tests/t2-chassis-fe-graph-pc.xml new file mode 100644 index 000000000000..3fb744ce91fd --- /dev/null +++ b/src/sonic-config-engine/tests/t2-chassis-fe-graph-pc.xml @@ -0,0 +1,324 @@ + + + + + + SpineFront01 + 192.168.0.2 + Leaf01 + 192.168.0.1 + 1 + 10 + 3 + + + SpineFront01 + 172.16.0.1 + SpineBack01 + 172.16.0.2 + 1 + 10 + 3 + + + SpineFront01 + 172.16.0.9 + SpineBack02 + 172.16.0.10 + 1 + 10 + 3 + + + SpineFront01 + 4.0.0.0 + SpineFront02 + 4.0.0.1 + 10 + 10 + 3 + + + + + 4000 + SpineFront01 + + +
192.168.0.1
+ + + +
+ +
172.16.0.2
+ + + +
+ +
172.16.0.10
+ + + +
+ +
4.0.0.1
+ + + +
+
+ +
+ + 3000 + Leaf01 + + + + 5000 + SpineBack01 + + + + 5000 + SpineBack02 + + + + 4000 + SpineFront02 + + +
+
+ + + + + + HostIP + Loopback0 + + 4.0.0.0/32 + + 4.0.0.0/32 + + + + + + + + SpineFront01 + + + PortChannel0 + Ethernet0;Ethernet4 + + + + PortChannel4 + Ethernet8;Ethernet12 + + + + PortChannel8 + Ethernet16;Ethernet20 + + + + + + + + PortChannel0 + 192.168.0.2/30 + + + + PortChannel4 + 172.16.0.1/30 + + + + PortChannel8 + 172.16.0.9/30 + + + + + + + + + + + + DeviceInterfaceLink + Leaf01 + Ethernet0 + SpineFront01 + Ethernet0 + + + DeviceInterfaceLink + Leaf01 + Ethernet4 + SpineFront01 + Ethernet4 + + + DeviceInterfaceLink + SpineBack01 + Ethernet8 + SpineFront01 + Ethernet8 + + + DeviceInterfaceLink + SpineBack01 + Ethernet12 + SpineFront01 + Ethernet12 + + + DeviceInterfaceLink + SpineBack02 + Ethernet16 + SpineFront01 + Ethernet16 + + + DeviceInterfaceLink + SpineBack02 + Ethernet20 + SpineFront01 + Ethernet20 + + + + + SpineFront01 + Force10-S6000 + + + SpineFront02 + Force10-S6000 + + + Leaf01 + Force10-S6000 + + + SpineBack01 + Force10-S6000 + + + SpineBack02 + Force10-S6000 + + + + + + true + + + DeviceInterface + + true + false + 1 + Ethernet0 + + false + 0 + 0 + 25000 + + + DeviceInterface + + true + false + 1 + Ethernet4 + + false + 0 + 0 + 25000 + + + DeviceInterface + + true + false + 1 + Ethernet8 + + false + 0 + 0 + 25000 + + + DeviceInterface + + true + false + 1 + Ethernet12 + + false + 0 + 0 + 25000 + + + DeviceInterface + + true + false + 1 + Ethernet16 + + false + 0 + 0 + 25000 + + + DeviceInterface + + true + false + 1 + Ethernet20 + + false + 0 + 0 + 25000 + + + false + 0 + Force10-S6000 + + + + + + + SpineFront01 + + + + + + SpineFront01 + Force10-S6000 +
From bdd7f44110b0622be8002beb0bc9689be3f6959a Mon Sep 17 00:00:00 2001 From: Wei Bai Date: Sun, 30 Jun 2019 03:04:25 +0800 Subject: [PATCH 06/15] Update test function names --- src/sonic-config-engine/tests/test_cfggen.py | 4 ++-- src/sonic-config-engine/tests/test_minigraph_case.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sonic-config-engine/tests/test_cfggen.py b/src/sonic-config-engine/tests/test_cfggen.py index af7a7c587ff3..9b754ba61a21 100644 --- a/src/sonic-config-engine/tests/test_cfggen.py +++ b/src/sonic-config-engine/tests/test_cfggen.py @@ -265,13 +265,13 @@ def test_minigraph_vnet(self): # Test a minigraph file where VNI is not specified # Default VNI is 8000 - def test_minigraph_t2_chassis_fe_vnet(self): + def test_minigraph_t2_chassis_fe_vnet_default(self): argument = '-m "' + self.sample_graph_t2_chassis_fe + '" -p "' + self.t2_chassis_fe_port_config + '" -v "VNET"' output = self.run_script(argument) self.assertEqual(output.strip(), "{'VnetFE': {'vxlan_tunnel': 'TunnelInt', 'vni': 8000}}") # Test a minigraph file where VNI is specified - def test_minigraph_t2_chassis_fe_vnet2(self): + def test_minigraph_t2_chassis_fe_vnet(self): argument = '-m "' + self.sample_graph_t2_chassis_fe_vni + '" -p "' + self.t2_chassis_fe_port_config + '" -v "VNET"' output = self.run_script(argument) self.assertEqual(output.strip(), "{'VnetFE': {'vxlan_tunnel': 'TunnelInt', 'vni': 9000}}") diff --git a/src/sonic-config-engine/tests/test_minigraph_case.py b/src/sonic-config-engine/tests/test_minigraph_case.py index cb721efa3843..a2aa00ba8a43 100644 --- a/src/sonic-config-engine/tests/test_minigraph_case.py +++ b/src/sonic-config-engine/tests/test_minigraph_case.py @@ -150,13 +150,13 @@ def test_minigraph_vnet(self): # Test a minigraph file where VNI is not specified # Default VNI is 8000 - def test_minigraph_t2_chassis_fe_vnet(self): + def test_minigraph_t2_chassis_fe_vnet_default(self): argument = '-m "' + self.sample_graph_t2_chassis_fe + '" -p "' + self.t2_chassis_fe_port_config + '" -v "VNET"' output = self.run_script(argument) self.assertEqual(output.strip(), "{'VnetFE': {'vxlan_tunnel': 'TunnelInt', 'vni': 8000}}") # Test a minigraph file where VNI is specified - def test_minigraph_t2_chassis_fe_vnet2(self): + def test_minigraph_t2_chassis_fe_vnet(self): argument = '-m "' + self.sample_graph_t2_chassis_fe_vni + '" -p "' + self.t2_chassis_fe_port_config + '" -v "VNET"' output = self.run_script(argument) self.assertEqual(output.strip(), "{'VnetFE': {'vxlan_tunnel': 'TunnelInt', 'vni': 9000}}") From 1b060ac4985ad8aa9d168c96dc4e826d38a06921 Mon Sep 17 00:00:00 2001 From: Wei Bai Date: Sun, 30 Jun 2019 03:22:06 +0800 Subject: [PATCH 07/15] Add test for port channel interfaces --- src/sonic-config-engine/tests/test_cfggen.py | 12 ++++++++++++ src/sonic-config-engine/tests/test_minigraph_case.py | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/sonic-config-engine/tests/test_cfggen.py b/src/sonic-config-engine/tests/test_cfggen.py index 9b754ba61a21..2fbf475e840d 100644 --- a/src/sonic-config-engine/tests/test_cfggen.py +++ b/src/sonic-config-engine/tests/test_cfggen.py @@ -15,6 +15,7 @@ def setUp(self): self.sample_graph_bgp_speaker = os.path.join(self.test_dir, 't0-sample-bgp-speaker.xml') self.sample_graph_t2_chassis_fe = os.path.join(self.test_dir, 't2-chassis-fe-graph.xml') self.sample_graph_t2_chassis_fe_vni = os.path.join(self.test_dir, 't2-chassis-fe-graph-vni.xml') + self.sample_graph_t2_chassis_fe_pc = os.path.join(self.test_dir, 't2-chassis-fe-graph-pc.xml') self.sample_device_desc = os.path.join(self.test_dir, 'device.xml') self.port_config = os.path.join(self.test_dir, 't0-sample-port-config.ini') self.t2_chassis_fe_port_config = os.path.join(self.test_dir, 't2-chassis-fe-port-config.ini') @@ -258,6 +259,17 @@ def test_minigraph_t2_chassis_fe_interfaces(self): "('Ethernet0', '192.168.0.2/30'): {}, " "'Ethernet4': {}}") + def test_minigraph_t2_chassis_fe_pc_interfaces(self): + argument = '-m "' + self.sample_graph_t2_chassis_fe_pc + '" -p "' + self.t2_chassis_fe_port_config + '" -v "PORTCHANNEL_INTERFACE"' + output = self.run_script(argument) + self.assertEqual(output.strip(), + "{'PortChannel8': {}, " + "('PortChannel0', '192.168.0.2/30'): {}, " + "('PortChannel4', '172.16.0.1/30'): {}, " + "'PortChannel4': {}, " + "('PortChannel8', '172.16.0.9/30'): {}, " + "'PortChannel0': {'vnet_name': 'VnetFE'}}") + def test_minigraph_vnet(self): argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v "VNET"' output = self.run_script(argument) diff --git a/src/sonic-config-engine/tests/test_minigraph_case.py b/src/sonic-config-engine/tests/test_minigraph_case.py index a2aa00ba8a43..5541181fbac0 100644 --- a/src/sonic-config-engine/tests/test_minigraph_case.py +++ b/src/sonic-config-engine/tests/test_minigraph_case.py @@ -10,6 +10,7 @@ def setUp(self): self.sample_graph = os.path.join(self.test_dir, 'simple-sample-graph-case.xml') self.sample_graph_t2_chassis_fe = os.path.join(self.test_dir, 't2-chassis-fe-graph.xml') self.sample_graph_t2_chassis_fe_vni = os.path.join(self.test_dir, 't2-chassis-fe-graph-vni.xml') + self.sample_graph_t2_chassis_fe_pc = os.path.join(self.test_dir, 't2-chassis-fe-graph-pc.xml') self.port_config = os.path.join(self.test_dir, 't0-sample-port-config.ini') self.t2_chassis_fe_port_config = os.path.join(self.test_dir, 't2-chassis-fe-port-config.ini') @@ -143,6 +144,17 @@ def test_minigraph_t2_chassis_fe_interfaces(self): "('Ethernet0', '192.168.0.2/30'): {}, " "'Ethernet4': {}}") + def test_minigraph_t2_chassis_fe_pc_interfaces(self): + argument = '-m "' + self.sample_graph_t2_chassis_fe_pc + '" -p "' + self.t2_chassis_fe_port_config + '" -v "PORTCHANNEL_INTERFACE"' + output = self.run_script(argument) + self.assertEqual(output.strip(), + "{'PortChannel8': {}, " + "('PortChannel0', '192.168.0.2/30'): {}, " + "('PortChannel4', '172.16.0.1/30'): {}, " + "'PortChannel4': {}, " + "('PortChannel8', '172.16.0.9/30'): {}, " + "'PortChannel0': {'vnet_name': 'VnetFE'}}") + def test_minigraph_vnet(self): argument = '-m "' + self.sample_graph + '" -p "' + self.port_config + '" -v "VNET"' output = self.run_script(argument) From bc2fe8ffe6efe3767cba862f9d4a121e33e5bf46 Mon Sep 17 00:00:00 2001 From: zegan Date: Sun, 30 Jun 2019 19:51:08 +0800 Subject: [PATCH 08/15] Add bgpd j2 conf for Chassis Frontend Signed-off-by: zegan --- dockers/docker-fpm-frr/bgpd.conf.default.j2 | 135 +++++++++++++++++ dockers/docker-fpm-frr/bgpd.conf.j2 | 137 +----------------- ...bgpd.conf.spine_chassis_frontend_router.j2 | 131 +++++++++++++++++ 3 files changed, 270 insertions(+), 133 deletions(-) create mode 100644 dockers/docker-fpm-frr/bgpd.conf.default.j2 create mode 100644 dockers/docker-fpm-frr/bgpd.conf.spine_chassis_frontend_router.j2 diff --git a/dockers/docker-fpm-frr/bgpd.conf.default.j2 b/dockers/docker-fpm-frr/bgpd.conf.default.j2 new file mode 100644 index 000000000000..735cb3264a00 --- /dev/null +++ b/dockers/docker-fpm-frr/bgpd.conf.default.j2 @@ -0,0 +1,135 @@ +{% 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 +{% if DEVICE_METADATA['localhost']['type'] == 'ToRRouter' %} + bgp graceful-restart preserve-fw-state +{% 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 +{% 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|pfx_filter %} +{% 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 %} +! diff --git a/dockers/docker-fpm-frr/bgpd.conf.j2 b/dockers/docker-fpm-frr/bgpd.conf.j2 index 9153a2455010..e9554806b64a 100644 --- a/dockers/docker-fpm-frr/bgpd.conf.j2 +++ b/dockers/docker-fpm-frr/bgpd.conf.j2 @@ -15,140 +15,11 @@ agentx ! 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 -{% if DEVICE_METADATA['localhost']['type'] == 'ToRRouter' %} - bgp graceful-restart preserve-fw-state -{% 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 -{% 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|pfx_filter %} -{% 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 %} +{% if DEVICE_METADATA['localhost']['type'] == "SpineChassisFrontendRouter" %} +{% include "bgpd.conf.spine_chassis_frontend_router.j2" %} +{% else%} +{% include "bgpd.conf.default.j2" %} {% endif %} -{% endblock bgp_peers_with_range %} ! {% if DEVICE_METADATA['localhost'].has_key('bgp_asn') %} maximum-paths 64 diff --git a/dockers/docker-fpm-frr/bgpd.conf.spine_chassis_frontend_router.j2 b/dockers/docker-fpm-frr/bgpd.conf.spine_chassis_frontend_router.j2 new file mode 100644 index 000000000000..b11cddd93453 --- /dev/null +++ b/dockers/docker-fpm-frr/bgpd.conf.spine_chassis_frontend_router.j2 @@ -0,0 +1,131 @@ +{# VNET BGP Instance #} +! Vnet BGP instance +{# VNI #} +{% set interfaces_in_vnets = [] %} +{% block vnet_bgp_instance %} +{% for vnet_name, vnet_metadata in VNET.iteritems() %} +vrf {{ vnet_name }} +vni {{ vnet_metadata['vni'] }} +router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} vrf {{ vnet_name }} + no bgp default ipv4-unicast + bgp log-neighbor-changes + bgp bestpath as-path multipath-relax + no bgp default ipv4-unicast + bgp graceful-restart restart-time 240 + bgp graceful-restart +{# Router ID #} +{% for (name, prefix) in LOOPBACK_INTERFACE %} +{% if prefix | ipv4 and name == 'Loopback0' %} + bgp router-id {{ prefix | ip }} +{% endif %} +{% endfor %} +{# Got interfaces that belong this vnet #} +{% set interfaces_in_vnet = [] %} +{% for (key, metadata) in INTERFACE.iteritems() %} +{% if metadata.has_key("vnet_name") and metadata["vnet_name"] == vnet_name %} +{% for (name_prefix_pair, metadata) in INTERFACE.iteritems() %} +{% if key == name_prefix_pair[0] %} +{% if interfaces_in_vnet.append( name_prefix_pair[1] | ip ) %} +{% endif %} +{% if interfaces_in_vnets.append( name_prefix_pair[1] | ip ) %} +{% endif %} +{% endif %} +{% endfor %} +{% endif %} +{% endfor %} +{# Each bgp neighbors #} +{% for neighbor_addr, bgp_session in BGP_NEIGHBOR.iteritems() %} +{% if bgp_session.has_key("local_addr") and bgp_session["local_addr"] in interfaces_in_vnet %} +{% 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 unicast + neighbor {{ neighbor_addr }} activate + neighbor {{ neighbor_addr }} soft-reconfiguration inbound + maximum-paths 64 + exit-address-family +{% endif %} + address-family l2vpn evpn + advertise ipv4 unicast + exit-address-family +{% endif %} +{% endif %} +{% 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 %} +{% 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 %} +{% 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 %} From c283f924c933f76893774f5acbcc571952090bb8 Mon Sep 17 00:00:00 2001 From: Wei Bai Date: Mon, 1 Jul 2019 11:19:50 +0800 Subject: [PATCH 09/15] Add FRR template tests for T2 chassis frontend --- .../sample_output/t2-chassis-fe-bgpd.conf | 78 +++++++++++++++++++ .../sample_output/t2-chassis-fe-zebra.conf | 38 +++++++++ src/sonic-config-engine/tests/test_j2files.py | 16 ++++ 3 files changed, 132 insertions(+) create mode 100644 src/sonic-config-engine/tests/sample_output/t2-chassis-fe-bgpd.conf create mode 100644 src/sonic-config-engine/tests/sample_output/t2-chassis-fe-zebra.conf diff --git a/src/sonic-config-engine/tests/sample_output/t2-chassis-fe-bgpd.conf b/src/sonic-config-engine/tests/sample_output/t2-chassis-fe-bgpd.conf new file mode 100644 index 000000000000..ffb342f43f0c --- /dev/null +++ b/src/sonic-config-engine/tests/sample_output/t2-chassis-fe-bgpd.conf @@ -0,0 +1,78 @@ +! +! =========== Managed by sonic-cfggen DO NOT edit manually! ==================== +! generated by templates/quagga/bgpd.conf.j2 with config DB data +! file: bgpd.conf +! +! +hostname SpineFront01 +password zebra +log syslog informational +log facility local4 +! enable password ! +! Vnet BGP instance +router bgp 4000 vrf VnetFE + no bgp default ipv4-unicast + 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 router-id 4.0.0.0 + neighbor 192.168.0.1 remote-as 3000 + neighbor 192.168.0.1 description Leaf01 + neighbor 192.168.0.1 timers 3 10 + address-family ipv4 unicast + neighbor 192.168.0.1 activate + neighbor 192.168.0.1 soft-reconfiguration inbound + maximum-paths 64 + exit-address-family + address-family l2vpn evpn + advertise ipv4 unicast + exit-address-family + +! +! bgp multiple-instance +! +route-map FROM_BGP_SPEAKER_V4 permit 10 +! +route-map TO_BGP_SPEAKER_V4 deny 10 +! +router bgp 4000 + 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 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 + 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 + maximum-paths 64 + exit-address-family +! +maximum-paths 64 +! +route-map ISOLATE permit 10 +set as-path prepend 4000 +! diff --git a/src/sonic-config-engine/tests/sample_output/t2-chassis-fe-zebra.conf b/src/sonic-config-engine/tests/sample_output/t2-chassis-fe-zebra.conf new file mode 100644 index 000000000000..b89aeb4a382f --- /dev/null +++ b/src/sonic-config-engine/tests/sample_output/t2-chassis-fe-zebra.conf @@ -0,0 +1,38 @@ +! +! =========== Managed by sonic-cfggen DO NOT edit manually! ==================== +! generated by templates/quagga/zebra.conf.j2 using config DB data +! file: zebra.conf +! +! +hostname SpineFront01 +password zebra +enable password zebra +! +vrf VnetFE +vni 8000 +! +! +! Enable link-detect (default disabled) +interface Ethernet0 +link-detect +! +interface Ethernet4 +link-detect +! +interface Ethernet8 +link-detect +! +! +! set static default route to mgmt gateway as a backup to learned default +! +! Set ip source to loopback for bgp learned routes +route-map RM_SET_SRC permit 10 + set src 4.0.0.0 +! +ip protocol bgp route-map RM_SET_SRC +! +! +log syslog informational +log facility local4 +! + diff --git a/src/sonic-config-engine/tests/test_j2files.py b/src/sonic-config-engine/tests/test_j2files.py index ce7f56eccff6..0466dbd2abc9 100644 --- a/src/sonic-config-engine/tests/test_j2files.py +++ b/src/sonic-config-engine/tests/test_j2files.py @@ -17,6 +17,8 @@ def setUp(self): self.t1_mlnx_minigraph = os.path.join(self.test_dir, 't1-sample-graph-mlnx.xml') self.mlnx_port_config = os.path.join(self.test_dir, 'sample-port-config-mlnx.ini') self.dell6100_t0_minigraph = os.path.join(self.test_dir, 'sample-dell-6100-t0-minigraph.xml') + self.t2_chassis_fe_minigraph = os.path.join(self.test_dir, 't2-chassis-fe-graph.xml') + 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): @@ -78,6 +80,20 @@ def test_config_frr(self): self.run_script(argument) self.assertTrue(filecmp.cmp(os.path.join(self.test_dir, 'sample_output', 'frr.conf'), self.output_file)) + # 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 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 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 From 5ef56858c0d6cbd8d55c64fb1661ef42026ffd64 Mon Sep 17 00:00:00 2001 From: Ze Gan Date: Mon, 1 Jul 2019 12:32:42 +0800 Subject: [PATCH 10/15] Modify zebra j2 file for VNET Signed-off-by: Ze Gan --- .../bgpd.conf.spine_chassis_frontend_router.j2 | 3 --- dockers/docker-fpm-frr/zebra.conf.j2 | 10 ++++++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/dockers/docker-fpm-frr/bgpd.conf.spine_chassis_frontend_router.j2 b/dockers/docker-fpm-frr/bgpd.conf.spine_chassis_frontend_router.j2 index b11cddd93453..79fe8789c6bb 100644 --- a/dockers/docker-fpm-frr/bgpd.conf.spine_chassis_frontend_router.j2 +++ b/dockers/docker-fpm-frr/bgpd.conf.spine_chassis_frontend_router.j2 @@ -1,11 +1,8 @@ {# VNET BGP Instance #} ! Vnet BGP instance -{# VNI #} {% set interfaces_in_vnets = [] %} {% block vnet_bgp_instance %} {% for vnet_name, vnet_metadata in VNET.iteritems() %} -vrf {{ vnet_name }} -vni {{ vnet_metadata['vni'] }} router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} vrf {{ vnet_name }} no bgp default ipv4-unicast bgp log-neighbor-changes diff --git a/dockers/docker-fpm-frr/zebra.conf.j2 b/dockers/docker-fpm-frr/zebra.conf.j2 index c0357eaed86a..7200d81fda4a 100644 --- a/dockers/docker-fpm-frr/zebra.conf.j2 +++ b/dockers/docker-fpm-frr/zebra.conf.j2 @@ -12,6 +12,16 @@ password zebra enable password zebra {% endblock sys_init %} ! +{% 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 %} From c82fafaa37a3e98f5cc5a4147be289699421b906 Mon Sep 17 00:00:00 2001 From: Ze Gan Date: Mon, 1 Jul 2019 13:13:53 +0800 Subject: [PATCH 11/15] Add pfx_filter for LOOPBACK_INTERFACE in bgpd Signed-off-by: Ze Gan --- .../bgpd.conf.spine_chassis_frontend_router.j2 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dockers/docker-fpm-frr/bgpd.conf.spine_chassis_frontend_router.j2 b/dockers/docker-fpm-frr/bgpd.conf.spine_chassis_frontend_router.j2 index 79fe8789c6bb..9bd5ef1947c3 100644 --- a/dockers/docker-fpm-frr/bgpd.conf.spine_chassis_frontend_router.j2 +++ b/dockers/docker-fpm-frr/bgpd.conf.spine_chassis_frontend_router.j2 @@ -11,7 +11,7 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} vrf {{ vnet_name }} bgp graceful-restart restart-time 240 bgp graceful-restart {# Router ID #} -{% for (name, prefix) in LOOPBACK_INTERFACE %} +{% for (name, prefix) in LOOPBACK_INTERFACE | pfx_filter %} {% if prefix | ipv4 and name == 'Loopback0' %} bgp router-id {{ prefix | ip }} {% endif %} @@ -76,13 +76,13 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} no bgp default ipv4-unicast bgp graceful-restart restart-time 240 bgp graceful-restart -{% for (name, prefix) in LOOPBACK_INTERFACE %} +{% 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 %} +{% for (name, prefix) in LOOPBACK_INTERFACE | pfx_filter %} {% if prefix | ipv4 and name == 'Loopback0' %} network {{ prefix | ip }}/32 {% elif prefix | ipv6 and name == 'Loopback0' %} From 38ef58279a200437af5487e81799e12c111c9961 Mon Sep 17 00:00:00 2001 From: Wei Bai Date: Mon, 1 Jul 2019 14:37:49 +0800 Subject: [PATCH 12/15] Update test files --- .../tests/sample_output/t2-chassis-fe-bgpd.conf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sonic-config-engine/tests/sample_output/t2-chassis-fe-bgpd.conf b/src/sonic-config-engine/tests/sample_output/t2-chassis-fe-bgpd.conf index ffb342f43f0c..515e0aba8df2 100644 --- a/src/sonic-config-engine/tests/sample_output/t2-chassis-fe-bgpd.conf +++ b/src/sonic-config-engine/tests/sample_output/t2-chassis-fe-bgpd.conf @@ -8,6 +8,7 @@ hostname SpineFront01 password zebra log syslog informational log facility local4 +agentx ! enable password ! ! Vnet BGP instance router bgp 4000 vrf VnetFE @@ -76,3 +77,6 @@ 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 +! From ae830cb9f77b9655b6a8976777e16858941646a0 Mon Sep 17 00:00:00 2001 From: Wei Bai Date: Mon, 1 Jul 2019 16:42:59 +0800 Subject: [PATCH 13/15] Add test for port channel and specified VNI cases --- .../sample_output/t2-chassis-fe-pc-zebra.conf | 38 +++++++++++++++++++ .../t2-chassis-fe-vni-zebra.conf | 38 +++++++++++++++++++ src/sonic-config-engine/tests/test_j2files.py | 16 ++++++++ 3 files changed, 92 insertions(+) create mode 100644 src/sonic-config-engine/tests/sample_output/t2-chassis-fe-pc-zebra.conf create mode 100644 src/sonic-config-engine/tests/sample_output/t2-chassis-fe-vni-zebra.conf diff --git a/src/sonic-config-engine/tests/sample_output/t2-chassis-fe-pc-zebra.conf b/src/sonic-config-engine/tests/sample_output/t2-chassis-fe-pc-zebra.conf new file mode 100644 index 000000000000..8861e6d3012f --- /dev/null +++ b/src/sonic-config-engine/tests/sample_output/t2-chassis-fe-pc-zebra.conf @@ -0,0 +1,38 @@ +! +! =========== Managed by sonic-cfggen DO NOT edit manually! ==================== +! generated by templates/quagga/zebra.conf.j2 using config DB data +! file: zebra.conf +! +! +hostname SpineFront01 +password zebra +enable password zebra +! +vrf VnetFE +vni 8000 +! +! +! Enable link-detect (default disabled) +interface PortChannel0 +link-detect +! +interface PortChannel4 +link-detect +! +interface PortChannel8 +link-detect +! +! +! set static default route to mgmt gateway as a backup to learned default +! +! Set ip source to loopback for bgp learned routes +route-map RM_SET_SRC permit 10 + set src 4.0.0.0 +! +ip protocol bgp route-map RM_SET_SRC +! +! +log syslog informational +log facility local4 +! + diff --git a/src/sonic-config-engine/tests/sample_output/t2-chassis-fe-vni-zebra.conf b/src/sonic-config-engine/tests/sample_output/t2-chassis-fe-vni-zebra.conf new file mode 100644 index 000000000000..1f9dce8812bd --- /dev/null +++ b/src/sonic-config-engine/tests/sample_output/t2-chassis-fe-vni-zebra.conf @@ -0,0 +1,38 @@ +! +! =========== Managed by sonic-cfggen DO NOT edit manually! ==================== +! generated by templates/quagga/zebra.conf.j2 using config DB data +! file: zebra.conf +! +! +hostname SpineFront01 +password zebra +enable password zebra +! +vrf VnetFE +vni 9000 +! +! +! Enable link-detect (default disabled) +interface Ethernet0 +link-detect +! +interface Ethernet4 +link-detect +! +interface Ethernet8 +link-detect +! +! +! set static default route to mgmt gateway as a backup to learned default +! +! Set ip source to loopback for bgp learned routes +route-map RM_SET_SRC permit 10 + set src 4.0.0.0 +! +ip protocol bgp route-map RM_SET_SRC +! +! +log syslog informational +log facility local4 +! + diff --git a/src/sonic-config-engine/tests/test_j2files.py b/src/sonic-config-engine/tests/test_j2files.py index 0466dbd2abc9..018dbd2e89a5 100644 --- a/src/sonic-config-engine/tests/test_j2files.py +++ b/src/sonic-config-engine/tests/test_j2files.py @@ -18,6 +18,8 @@ def setUp(self): self.mlnx_port_config = os.path.join(self.test_dir, 'sample-port-config-mlnx.ini') self.dell6100_t0_minigraph = os.path.join(self.test_dir, 'sample-dell-6100-t0-minigraph.xml') self.t2_chassis_fe_minigraph = os.path.join(self.test_dir, 't2-chassis-fe-graph.xml') + self.t2_chassis_fe_vni_minigraph = os.path.join(self.test_dir, 't2-chassis-fe-graph-vni.xml') + self.t2_chassis_fe_pc_minigraph = os.path.join(self.test_dir, 't2-chassis-fe-graph-pc.xml') 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') @@ -87,6 +89,20 @@ def test_t2_chassis_fe_zebra_frr(self): 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_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_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') From 7c99c262602e582c5f5d2788a5406eb0d7a64b45 Mon Sep 17 00:00:00 2001 From: Wei Bai Date: Fri, 5 Jul 2019 16:57:15 +0800 Subject: [PATCH 14/15] Add function is_ip_prefix_in_key for better code readability --- src/sonic-config-engine/minigraph.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py index 2d8bad7a315a..4c1238a21568 100644 --- a/src/sonic-config-engine/minigraph.py +++ b/src/sonic-config-engine/minigraph.py @@ -428,6 +428,11 @@ def parse_deviceinfo(meta, hwsku): port_speeds[port_alias_map.get(alias, alias)] = speed return port_speeds, port_descriptions +# Function to check if IP address is present in the key. +# If it is present, then the key would be a tuple. +def is_ip_prefix_in_key(key): + return (isinstance(key, tuple)) + # Special parsing for spine chassis frontend def parse_spine_chassis_fe(results, vni, lo_intfs, phyport_intfs, pc_intfs, pc_members, devices): chassis_vnet ='VnetFE' @@ -452,9 +457,10 @@ def parse_spine_chassis_fe(results, vni, lo_intfs, phyport_intfs, pc_intfs, pc_m 'vni': chassis_vni }} - # Find physical L3 interfaces that should be enslaved to Vnet + # Find L3 physical interfaces that should be enslaved to Vnet for intf in phyport_intfs: - if isinstance(intf, tuple) == False: + # We only care about L3 physical interfaces + if is_ip_prefix_in_key(intf) == False: continue # intf = (intf name, IP prefix) @@ -470,24 +476,25 @@ def parse_spine_chassis_fe(results, vni, lo_intfs, phyport_intfs, pc_intfs, pc_m else: print >> sys.stderr, 'Warning: cannot find the key %s' % (intf_name) - # Find port chennel interfaces that should be enslaved to Vnet + # Find L3 port chennel interfaces that should be enslaved to Vnet for pc_intf in pc_intfs: - if isinstance(pc_intf, tuple) == False: + # We only care about L3 port channel interfaces + if is_ip_prefix_in_key(pc_intf) == False: continue # Get port channel interface name # pc intf = (pc intf name, IP prefix) pc_intf_name = pc_intf[0] - # Get an interface that is enslaved to this port channel intf_name = None + # Get a physical interface that belongs to this port channel for pc_member in pc_members: - if isinstance(pc_member, tuple) and pc_member[0] == pc_intf_name: + if pc_member[0] == pc_intf_name: intf_name = pc_member[1] break if intf_name == None: - print >> sys.stderr, 'Warning: cannot find any interfaces enslaved to %s' % (pc_intf_name) + print >> sys.stderr, 'Warning: cannot find any interfaces that belong to %s' % (pc_intf_name) continue # Get the neighbor router of this port channel interface From a543f34f0e5ee920485c2c07b3ed6d50ccf2d115 Mon Sep 17 00:00:00 2001 From: Wei Bai Date: Sun, 7 Jul 2019 00:00:04 +0800 Subject: [PATCH 15/15] Move tests for T2 chassis frontend to separate files --- src/sonic-config-engine/tests/test_cfggen.py | 53 +------------- .../tests/test_cfggen_t2_chassis_fe.py | 72 +++++++++++++++++++ src/sonic-config-engine/tests/test_j2files.py | 34 +-------- .../tests/test_j2files_t2_chassis_fe.py | 57 +++++++++++++++ .../tests/test_minigraph_case.py | 55 +------------- 5 files changed, 135 insertions(+), 136 deletions(-) create mode 100644 src/sonic-config-engine/tests/test_cfggen_t2_chassis_fe.py create mode 100644 src/sonic-config-engine/tests/test_j2files_t2_chassis_fe.py diff --git a/src/sonic-config-engine/tests/test_cfggen.py b/src/sonic-config-engine/tests/test_cfggen.py index 2fbf475e840d..eedaf6782722 100644 --- a/src/sonic-config-engine/tests/test_cfggen.py +++ b/src/sonic-config-engine/tests/test_cfggen.py @@ -13,13 +13,9 @@ def setUp(self): self.sample_graph_metadata = os.path.join(self.test_dir, 'simple-sample-graph-metadata.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.sample_graph_t2_chassis_fe = os.path.join(self.test_dir, 't2-chassis-fe-graph.xml') - self.sample_graph_t2_chassis_fe_vni = os.path.join(self.test_dir, 't2-chassis-fe-graph-vni.xml') - self.sample_graph_t2_chassis_fe_pc = os.path.join(self.test_dir, 't2-chassis-fe-graph-pc.xml') self.sample_device_desc = os.path.join(self.test_dir, 'device.xml') self.port_config = os.path.join(self.test_dir, 't0-sample-port-config.ini') - self.t2_chassis_fe_port_config = os.path.join(self.test_dir, 't2-chassis-fe-port-config.ini') - + def run_script(self, argument, check_stderr=False): print '\n Running sonic-cfggen ' + argument if check_stderr: @@ -243,57 +239,12 @@ def test_metadata_ntp(self): output = self.run_script(argument) self.assertEqual(output.strip(), "{'10.0.10.1': {}, '10.0.10.2': {}}") - def test_minigraph_t2_chassis_fe_type(self): - argument = '-m "' + self.sample_graph_t2_chassis_fe + '" -p "' + self.t2_chassis_fe_port_config + '" -v "DEVICE_METADATA[\'localhost\'][\'type\']"' - output = self.run_script(argument) - self.assertEqual(output.strip(), 'SpineChassisFrontendRouter') - - def test_minigraph_t2_chassis_fe_interfaces(self): - argument = '-m "' + self.sample_graph_t2_chassis_fe + '" -p "' + self.t2_chassis_fe_port_config + '" -v "INTERFACE"' - output = self.run_script(argument) - self.assertEqual(output.strip(), - "{'Ethernet8': {}, " - "('Ethernet8', '172.16.0.9/30'): {}, " - "'Ethernet0': {'vnet_name': 'VnetFE'}, " - "('Ethernet4', '172.16.0.1/30'): {}, " - "('Ethernet0', '192.168.0.2/30'): {}, " - "'Ethernet4': {}}") - - def test_minigraph_t2_chassis_fe_pc_interfaces(self): - argument = '-m "' + self.sample_graph_t2_chassis_fe_pc + '" -p "' + self.t2_chassis_fe_port_config + '" -v "PORTCHANNEL_INTERFACE"' - output = self.run_script(argument) - self.assertEqual(output.strip(), - "{'PortChannel8': {}, " - "('PortChannel0', '192.168.0.2/30'): {}, " - "('PortChannel4', '172.16.0.1/30'): {}, " - "'PortChannel4': {}, " - "('PortChannel8', '172.16.0.9/30'): {}, " - "'PortChannel0': {'vnet_name': 'VnetFE'}}") - def test_minigraph_vnet(self): argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v "VNET"' output = self.run_script(argument) self.assertEqual(output.strip(), "") - - # Test a minigraph file where VNI is not specified - # Default VNI is 8000 - def test_minigraph_t2_chassis_fe_vnet_default(self): - argument = '-m "' + self.sample_graph_t2_chassis_fe + '" -p "' + self.t2_chassis_fe_port_config + '" -v "VNET"' - output = self.run_script(argument) - self.assertEqual(output.strip(), "{'VnetFE': {'vxlan_tunnel': 'TunnelInt', 'vni': 8000}}") - - # Test a minigraph file where VNI is specified - def test_minigraph_t2_chassis_fe_vnet(self): - argument = '-m "' + self.sample_graph_t2_chassis_fe_vni + '" -p "' + self.t2_chassis_fe_port_config + '" -v "VNET"' - output = self.run_script(argument) - self.assertEqual(output.strip(), "{'VnetFE': {'vxlan_tunnel': 'TunnelInt', 'vni': 9000}}") def test_minigraph_vxlan(self): argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v "VXLAN_TUNNEL"' output = self.run_script(argument) - self.assertEqual(output.strip(), "") - - def test_minigraph_t2_chassis_fe_vxlan(self): - argument = '-m "' + self.sample_graph_t2_chassis_fe + '" -p "' + self.t2_chassis_fe_port_config + '" -v "VXLAN_TUNNEL"' - output = self.run_script(argument) - self.assertEqual(output.strip(), "{'TunnelInt': {'source_ip': '4.0.0.0'}}") \ No newline at end of file + self.assertEqual(output.strip(), "") \ No newline at end of file diff --git a/src/sonic-config-engine/tests/test_cfggen_t2_chassis_fe.py b/src/sonic-config-engine/tests/test_cfggen_t2_chassis_fe.py new file mode 100644 index 000000000000..cc438896a033 --- /dev/null +++ b/src/sonic-config-engine/tests/test_cfggen_t2_chassis_fe.py @@ -0,0 +1,72 @@ +from unittest import TestCase +import subprocess +import os + +class TestCfgGenT2ChassisFe(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.sample_graph_t2_chassis_fe = os.path.join(self.test_dir, 't2-chassis-fe-graph.xml') + self.sample_graph_t2_chassis_fe_vni = os.path.join(self.test_dir, 't2-chassis-fe-graph-vni.xml') + self.sample_graph_t2_chassis_fe_pc = os.path.join(self.test_dir, 't2-chassis-fe-graph-pc.xml') + self.t2_chassis_fe_port_config = os.path.join(self.test_dir, 't2-chassis-fe-port-config.ini') + + 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 test_minigraph_t2_chassis_fe_type(self): + argument = '-m "' + self.sample_graph_t2_chassis_fe + '" -p "' + self.t2_chassis_fe_port_config + '" -v "DEVICE_METADATA[\'localhost\'][\'type\']"' + output = self.run_script(argument) + self.assertEqual(output.strip(), 'SpineChassisFrontendRouter') + + def test_minigraph_t2_chassis_fe_interfaces(self): + argument = '-m "' + self.sample_graph_t2_chassis_fe + '" -p "' + self.t2_chassis_fe_port_config + '" -v "INTERFACE"' + output = self.run_script(argument) + self.assertEqual(output.strip(), + "{'Ethernet8': {}, " + "('Ethernet8', '172.16.0.9/30'): {}, " + "'Ethernet0': {'vnet_name': 'VnetFE'}, " + "('Ethernet4', '172.16.0.1/30'): {}, " + "('Ethernet0', '192.168.0.2/30'): {}, " + "'Ethernet4': {}}") + + def test_minigraph_t2_chassis_fe_pc_interfaces(self): + argument = '-m "' + self.sample_graph_t2_chassis_fe_pc + '" -p "' + self.t2_chassis_fe_port_config + '" -v "PORTCHANNEL_INTERFACE"' + output = self.run_script(argument) + self.assertEqual(output.strip(), + "{'PortChannel8': {}, " + "('PortChannel0', '192.168.0.2/30'): {}, " + "('PortChannel4', '172.16.0.1/30'): {}, " + "'PortChannel4': {}, " + "('PortChannel8', '172.16.0.9/30'): {}, " + "'PortChannel0': {'vnet_name': 'VnetFE'}}") + + # Test a minigraph file where VNI is not specified + # Default VNI is 8000 + def test_minigraph_t2_chassis_fe_vnet_default(self): + argument = '-m "' + self.sample_graph_t2_chassis_fe + '" -p "' + self.t2_chassis_fe_port_config + '" -v "VNET"' + output = self.run_script(argument) + self.assertEqual(output.strip(), "{'VnetFE': {'vxlan_tunnel': 'TunnelInt', 'vni': 8000}}") + + # Test a minigraph file where VNI is specified + def test_minigraph_t2_chassis_fe_vnet(self): + argument = '-m "' + self.sample_graph_t2_chassis_fe_vni + '" -p "' + self.t2_chassis_fe_port_config + '" -v "VNET"' + output = self.run_script(argument) + self.assertEqual(output.strip(), "{'VnetFE': {'vxlan_tunnel': 'TunnelInt', 'vni': 9000}}") + + def test_minigraph_t2_chassis_fe_vxlan(self): + argument = '-m "' + self.sample_graph_t2_chassis_fe + '" -p "' + self.t2_chassis_fe_port_config + '" -v "VXLAN_TUNNEL"' + output = self.run_script(argument) + self.assertEqual(output.strip(), "{'TunnelInt': {'source_ip': '4.0.0.0'}}") \ No newline at end of file diff --git a/src/sonic-config-engine/tests/test_j2files.py b/src/sonic-config-engine/tests/test_j2files.py index 018dbd2e89a5..525b5e79aa2a 100644 --- a/src/sonic-config-engine/tests/test_j2files.py +++ b/src/sonic-config-engine/tests/test_j2files.py @@ -17,10 +17,6 @@ def setUp(self): self.t1_mlnx_minigraph = os.path.join(self.test_dir, 't1-sample-graph-mlnx.xml') self.mlnx_port_config = os.path.join(self.test_dir, 'sample-port-config-mlnx.ini') self.dell6100_t0_minigraph = os.path.join(self.test_dir, 'sample-dell-6100-t0-minigraph.xml') - self.t2_chassis_fe_minigraph = os.path.join(self.test_dir, 't2-chassis-fe-graph.xml') - self.t2_chassis_fe_vni_minigraph = os.path.join(self.test_dir, 't2-chassis-fe-graph-vni.xml') - self.t2_chassis_fe_pc_minigraph = os.path.join(self.test_dir, 't2-chassis-fe-graph-pc.xml') - 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): @@ -82,34 +78,6 @@ def test_config_frr(self): self.run_script(argument) self.assertTrue(filecmp.cmp(os.path.join(self.test_dir, 'sample_output', 'frr.conf'), self.output_file)) - # 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_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_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 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 @@ -168,4 +136,4 @@ def tearDown(self): try: os.remove(self.output_file) except OSError: - pass + pass \ No newline at end of file diff --git a/src/sonic-config-engine/tests/test_j2files_t2_chassis_fe.py b/src/sonic-config-engine/tests/test_j2files_t2_chassis_fe.py new file mode 100644 index 000000000000..2215d4e8ca94 --- /dev/null +++ b/src/sonic-config-engine/tests/test_j2files_t2_chassis_fe.py @@ -0,0 +1,57 @@ +import filecmp +import os +import subprocess +import json +import shutil + +from unittest import TestCase + +class TestJ2FilesT2ChassisFe(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.t2_chassis_fe_minigraph = os.path.join(self.test_dir, 't2-chassis-fe-graph.xml') + self.t2_chassis_fe_vni_minigraph = os.path.join(self.test_dir, 't2-chassis-fe-graph-vni.xml') + self.t2_chassis_fe_pc_minigraph = os.path.join(self.test_dir, 't2-chassis-fe-graph-pc.xml') + 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_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_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 + + diff --git a/src/sonic-config-engine/tests/test_minigraph_case.py b/src/sonic-config-engine/tests/test_minigraph_case.py index 5541181fbac0..093aea05b588 100644 --- a/src/sonic-config-engine/tests/test_minigraph_case.py +++ b/src/sonic-config-engine/tests/test_minigraph_case.py @@ -8,12 +8,8 @@ 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.sample_graph = os.path.join(self.test_dir, 'simple-sample-graph-case.xml') - self.sample_graph_t2_chassis_fe = os.path.join(self.test_dir, 't2-chassis-fe-graph.xml') - self.sample_graph_t2_chassis_fe_vni = os.path.join(self.test_dir, 't2-chassis-fe-graph-vni.xml') - self.sample_graph_t2_chassis_fe_pc = os.path.join(self.test_dir, 't2-chassis-fe-graph-pc.xml') self.port_config = os.path.join(self.test_dir, 't0-sample-port-config.ini') - self.t2_chassis_fe_port_config = os.path.join(self.test_dir, 't2-chassis-fe-port-config.ini') - + def run_script(self, argument, check_stderr=False): print '\n Running sonic-cfggen ' + argument if check_stderr: @@ -128,57 +124,12 @@ def test_metadata_ntp(self): output = self.run_script(argument) self.assertEqual(output.strip(), "{'10.0.10.1': {}, '10.0.10.2': {}}") - def test_minigraph_t2_chassis_fe_type(self): - argument = '-m "' + self.sample_graph_t2_chassis_fe + '" -p "' + self.t2_chassis_fe_port_config + '" -v "DEVICE_METADATA[\'localhost\'][\'type\']"' - output = self.run_script(argument) - self.assertEqual(output.strip(), 'SpineChassisFrontendRouter') - - def test_minigraph_t2_chassis_fe_interfaces(self): - argument = '-m "' + self.sample_graph_t2_chassis_fe + '" -p "' + self.t2_chassis_fe_port_config + '" -v "INTERFACE"' - output = self.run_script(argument) - self.assertEqual(output.strip(), - "{'Ethernet8': {}, " - "('Ethernet8', '172.16.0.9/30'): {}, " - "'Ethernet0': {'vnet_name': 'VnetFE'}, " - "('Ethernet4', '172.16.0.1/30'): {}, " - "('Ethernet0', '192.168.0.2/30'): {}, " - "'Ethernet4': {}}") - - def test_minigraph_t2_chassis_fe_pc_interfaces(self): - argument = '-m "' + self.sample_graph_t2_chassis_fe_pc + '" -p "' + self.t2_chassis_fe_port_config + '" -v "PORTCHANNEL_INTERFACE"' - output = self.run_script(argument) - self.assertEqual(output.strip(), - "{'PortChannel8': {}, " - "('PortChannel0', '192.168.0.2/30'): {}, " - "('PortChannel4', '172.16.0.1/30'): {}, " - "'PortChannel4': {}, " - "('PortChannel8', '172.16.0.9/30'): {}, " - "'PortChannel0': {'vnet_name': 'VnetFE'}}") - def test_minigraph_vnet(self): argument = '-m "' + self.sample_graph + '" -p "' + self.port_config + '" -v "VNET"' output = self.run_script(argument) self.assertEqual(output.strip(), "") - - # Test a minigraph file where VNI is not specified - # Default VNI is 8000 - def test_minigraph_t2_chassis_fe_vnet_default(self): - argument = '-m "' + self.sample_graph_t2_chassis_fe + '" -p "' + self.t2_chassis_fe_port_config + '" -v "VNET"' - output = self.run_script(argument) - self.assertEqual(output.strip(), "{'VnetFE': {'vxlan_tunnel': 'TunnelInt', 'vni': 8000}}") - - # Test a minigraph file where VNI is specified - def test_minigraph_t2_chassis_fe_vnet(self): - argument = '-m "' + self.sample_graph_t2_chassis_fe_vni + '" -p "' + self.t2_chassis_fe_port_config + '" -v "VNET"' - output = self.run_script(argument) - self.assertEqual(output.strip(), "{'VnetFE': {'vxlan_tunnel': 'TunnelInt', 'vni': 9000}}") - + def test_minigraph_vxlan(self): argument = '-m "' + self.sample_graph + '" -p "' + self.port_config + '" -v "VXLAN_TUNNEL"' output = self.run_script(argument) - self.assertEqual(output.strip(), "") - - def test_minigraph_t2_chassis_fe_vxlan(self): - argument = '-m "' + self.sample_graph_t2_chassis_fe + '" -p "' + self.t2_chassis_fe_port_config + '" -v "VXLAN_TUNNEL"' - output = self.run_script(argument) - self.assertEqual(output.strip(), "{'TunnelInt': {'source_ip': '4.0.0.0'}}") \ No newline at end of file + self.assertEqual(output.strip(), "") \ No newline at end of file