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 0000000000..735cb3264a
--- /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 9153a24550..e9554806b6 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
+{% if DEVICE_METADATA['localhost']['type'] == "SpineChassisFrontendRouter" %}
+{% include "bgpd.conf.spine_chassis_frontend_router.j2" %}
+{% else%}
+{% include "bgpd.conf.default.j2" %}
{% 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 %}
!
{% 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 0000000000..9bd5ef1947
--- /dev/null
+++ b/dockers/docker-fpm-frr/bgpd.conf.spine_chassis_frontend_router.j2
@@ -0,0 +1,128 @@
+{# VNET BGP Instance #}
+! Vnet BGP instance
+{% set interfaces_in_vnets = [] %}
+{% block vnet_bgp_instance %}
+{% for vnet_name, vnet_metadata in VNET.iteritems() %}
+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 | pfx_filter %}
+{% 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 | pfx_filter %}
+{% if prefix | ipv4 and name == 'Loopback0' %}
+ bgp router-id {{ prefix | ip }}
+{% endif %}
+{% endfor %}
+{# advertise loopback #}
+{% for (name, prefix) in LOOPBACK_INTERFACE | pfx_filter %}
+{% if prefix | ipv4 and name == 'Loopback0' %}
+ network {{ prefix | ip }}/32
+{% elif prefix | ipv6 and name == 'Loopback0' %}
+ address-family ipv6
+ network {{ prefix | ip }}/64
+ exit-address-family
+{% endif %}
+{% endfor %}
+{% endblock bgp_init %}
+{% block bgp_sessions %}
+{% for neighbor_addr, bgp_session in BGP_NEIGHBOR.iteritems() %}
+{% if not bgp_session.has_key("local_addr") or bgp_session["local_addr"] not in interfaces_in_vnets %}
+{% if bgp_session['asn'] | int != 0 %}
+ neighbor {{ neighbor_addr }} remote-as {{ bgp_session['asn'] }}
+ neighbor {{ neighbor_addr }} description {{ bgp_session['name'] }}
+{# set the bgp neighbor timers if they have not default values #}
+{% if (bgp_session['keepalive'] is defined and bgp_session['keepalive'] | int != 60)
+ or (bgp_session['holdtime'] is defined and bgp_session['holdtime'] | int != 180) %}
+ neighbor {{ neighbor_addr }} timers {{ bgp_session['keepalive'] }} {{ bgp_session['holdtime'] }}
+{% endif %}
+{% if bgp_session.has_key('admin_status') and bgp_session['admin_status'] == 'down' or not bgp_session.has_key('admin_status') and DEVICE_METADATA['localhost'].has_key('default_bgp_status') and DEVICE_METADATA['localhost']['default_bgp_status'] == 'down' %}
+ neighbor {{ neighbor_addr }} shutdown
+{% endif %}
+{% if bgp_session["asn"] != DEVICE_METADATA['localhost']['bgp_asn'] %}
+{% if neighbor_addr | ipv4 %}
+ address-family ipv4 unicast
+ neighbor {{ neighbor_addr }} allowas-in 1
+ neighbor {{ neighbor_addr }} activate
+ neighbor {{ neighbor_addr }} soft-reconfiguration inbound
+ maximum-paths 64
+ exit-address-family
+{% endif %}
+{% else %}
+ address-family l2vpn evpn
+ neighbor {{ neighbor_addr }} activate
+ advertise-all-vni
+ exit-address-family
+{% endif %}
+{% endif %}
+{% endif %}
+{% endfor %}
+{% endblock bgp_sessions %}
+{% endblock default_bgp_instance %}
diff --git a/dockers/docker-fpm-frr/zebra.conf.j2 b/dockers/docker-fpm-frr/zebra.conf.j2
index c0357eaed8..7200d81fda 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 %}
diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py
index 8d08b399b4..4c1238a215 100644
--- a/src/sonic-config-engine/minigraph.py
+++ b/src/sonic-config-engine/minigraph.py
@@ -26,6 +26,13 @@ ns1 = "http://schemas.datacontract.org/2004/07/Microsoft.Search.Autopilot.Evolut
ns2 = "Microsoft.Search.Autopilot.NetMux"
ns3 = "http://www.w3.org/2001/XMLSchema-instance"
+# Device types
+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, (
@@ -149,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"))):
@@ -290,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):
@@ -413,6 +428,88 @@ 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'
+ chassis_vxlan_tunnel = 'TunnelInt'
+ chassis_vni = vni
+
+ # 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 L3 physical interfaces that should be enslaved to Vnet
+ for intf in phyport_intfs:
+ # We only care about L3 physical interfaces
+ if is_ip_prefix_in_key(intf) == 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 L3 port chennel interfaces that should be enslaved to Vnet
+ for pc_intf in pc_intfs:
+ # 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]
+
+ intf_name = None
+ # Get a physical interface that belongs to this port channel
+ for pc_member in pc_members:
+ 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 that belong 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:
+
+ # 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
@@ -462,7 +559,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")):
@@ -643,6 +740,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, vni, lo_intfs, phyport_intfs, pc_intfs, pc_members, devices)
+
return results
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 0000000000..515e0aba8d
--- /dev/null
+++ b/src/sonic-config-engine/tests/sample_output/t2-chassis-fe-bgpd.conf
@@ -0,0 +1,82 @@
+!
+! =========== 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
+agentx
+! 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
+!
+route-map set-next-hop-global-v6 permit 10
+set ipv6 next-hop prefer-global
+!
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 0000000000..8861e6d301
--- /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 0000000000..1f9dce8812
--- /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/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 0000000000..b89aeb4a38
--- /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/t2-chassis-fe-graph-pc.xml b/src/sonic-config-engine/tests/t2-chassis-fe-graph-pc.xml
new file mode 100644
index 0000000000..3fb744ce91
--- /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
+
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 0000000000..f820b180f7
--- /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 0000000000..76320b766b
--- /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 0000000000..1a9786c590
--- /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 f267651ff6..eedaf67827 100644
--- a/src/sonic-config-engine/tests/test_cfggen.py
+++ b/src/sonic-config-engine/tests/test_cfggen.py
@@ -15,7 +15,7 @@ class TestCfgGen(TestCase):
self.sample_graph_bgp_speaker = os.path.join(self.test_dir, 't0-sample-bgp-speaker.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')
-
+
def run_script(self, argument, check_stderr=False):
print '\n Running sonic-cfggen ' + argument
if check_stderr:
@@ -239,3 +239,12 @@ class TestCfgGen(TestCase):
output = self.run_script(argument)
self.assertEqual(output.strip(), "{'10.0.10.1': {}, '10.0.10.2': {}}")
+ 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(), "")
+
+ 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(), "")
\ 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 0000000000..cc438896a0
--- /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 ce7f56eccf..525b5e79aa 100644
--- a/src/sonic-config-engine/tests/test_j2files.py
+++ b/src/sonic-config-engine/tests/test_j2files.py
@@ -136,4 +136,4 @@ class TestJ2Files(TestCase):
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 0000000000..2215d4e8ca
--- /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 d363acdca0..093aea05b5 100644
--- a/src/sonic-config-engine/tests/test_minigraph_case.py
+++ b/src/sonic-config-engine/tests/test_minigraph_case.py
@@ -9,7 +9,7 @@ class TestCfgGenCaseInsensitive(TestCase):
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.port_config = os.path.join(self.test_dir, 't0-sample-port-config.ini')
-
+
def run_script(self, argument, check_stderr=False):
print '\n Running sonic-cfggen ' + argument
if check_stderr:
@@ -123,3 +123,13 @@ class TestCfgGenCaseInsensitive(TestCase):
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_vnet(self):
+ argument = '-m "' + self.sample_graph + '" -p "' + self.port_config + '" -v "VNET"'
+ output = self.run_script(argument)
+ self.assertEqual(output.strip(), "")
+
+ 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(), "")
\ No newline at end of file