[config engine] Parser changes to support parsing of multi-asic device minigraph (#4222)
- Changes to minigraph.py to parse minigraph.xml of a multi asic platform - Changes to portconfig.py to parse additional column "asic_port_name" in port_config.ini - Add a new option -n to sonic-cfggen for multi asic platforms - Add unit tests for config generation for multi asic platforms Signed-off-by: SuvarnaMeenakshi <sumeenak@microsoft.com> Signed-off-by: Arvindsrinivasan Lakshmi Narasimhan <arlakshm@microsoft.com>
This commit is contained in:
parent
86e13907b4
commit
8ac1c60b2a
@ -14,6 +14,7 @@ from lxml import etree as ET
|
||||
from lxml.etree import QName
|
||||
|
||||
from portconfig import get_port_config
|
||||
from sonic_device_util import get_npu_id_from_name
|
||||
|
||||
"""minigraph.py
|
||||
version_added: "1.9"
|
||||
@ -118,14 +119,13 @@ def parse_png(png, hname):
|
||||
startport = link.find(str(QName(ns, "StartPort"))).text
|
||||
bandwidth_node = link.find(str(QName(ns, "Bandwidth")))
|
||||
bandwidth = bandwidth_node.text if bandwidth_node is not None else None
|
||||
|
||||
if enddevice.lower() == hname.lower():
|
||||
if port_alias_map.has_key(endport):
|
||||
endport = port_alias_map[endport]
|
||||
neighbors[endport] = {'name': startdevice, 'port': startport}
|
||||
if bandwidth:
|
||||
port_speeds[endport] = bandwidth
|
||||
else:
|
||||
elif startdevice.lower() == hname.lower():
|
||||
if port_alias_map.has_key(startport):
|
||||
startport = port_alias_map[startport]
|
||||
neighbors[startport] = {'name': enddevice, 'port': endport}
|
||||
@ -159,9 +159,103 @@ def parse_png(png, hname):
|
||||
|
||||
return (neighbors, devices, console_dev, console_port, mgmt_dev, mgmt_port, port_speeds, console_ports)
|
||||
|
||||
def parse_asic_external_link(link, asic_name, hostname):
|
||||
neighbors = {}
|
||||
port_speeds = {}
|
||||
enddevice = link.find(str(QName(ns, "EndDevice"))).text
|
||||
endport = link.find(str(QName(ns, "EndPort"))).text
|
||||
startdevice = link.find(str(QName(ns, "StartDevice"))).text
|
||||
startport = link.find(str(QName(ns, "StartPort"))).text
|
||||
bandwidth_node = link.find(str(QName(ns, "Bandwidth")))
|
||||
bandwidth = bandwidth_node.text if bandwidth_node is not None else None
|
||||
# if chassis internal is false, the interface name will be
|
||||
# interface alias which should be converted to asic port name
|
||||
if (enddevice.lower() == hostname.lower()):
|
||||
if ((port_alias_asic_map.has_key(endport)) and
|
||||
(asic_name.lower() in port_alias_asic_map[endport].lower())):
|
||||
endport = port_alias_asic_map[endport]
|
||||
neighbors[port_alias_map[endport]] = {'name': startdevice, 'port': startport}
|
||||
if bandwidth:
|
||||
port_speeds[port_alias_map[endport]] = bandwidth
|
||||
elif (startdevice.lower() == hostname.lower()):
|
||||
if ((port_alias_asic_map.has_key(startport)) and
|
||||
(asic_name.lower() in port_alias_asic_map[startport].lower())):
|
||||
startport = port_alias_asic_map[startport]
|
||||
neighbors[port_alias_map[startport]] = {'name': enddevice, 'port': endport}
|
||||
if bandwidth:
|
||||
port_speeds[port_alias_map[startport]] = bandwidth
|
||||
|
||||
return neighbors, port_speeds
|
||||
|
||||
def parse_asic_internal_link(link, asic_name, hostname):
|
||||
neighbors = {}
|
||||
port_speeds = {}
|
||||
enddevice = link.find(str(QName(ns, "EndDevice"))).text
|
||||
endport = link.find(str(QName(ns, "EndPort"))).text
|
||||
startdevice = link.find(str(QName(ns, "StartDevice"))).text
|
||||
startport = link.find(str(QName(ns, "StartPort"))).text
|
||||
bandwidth_node = link.find(str(QName(ns, "Bandwidth")))
|
||||
bandwidth = bandwidth_node.text if bandwidth_node is not None else None
|
||||
if ((enddevice.lower() == asic_name.lower()) and
|
||||
(startdevice.lower() != hostname.lower())):
|
||||
if port_alias_map.has_key(endport):
|
||||
endport = port_alias_map[endport]
|
||||
neighbors[endport] = {'name': startdevice, 'port': startport}
|
||||
if bandwidth:
|
||||
port_speeds[endport] = bandwidth
|
||||
elif ((startdevice.lower() == asic_name.lower()) and
|
||||
(enddevice.lower() != hostname.lower())):
|
||||
if port_alias_map.has_key(startport):
|
||||
startport = port_alias_map[startport]
|
||||
neighbors[startport] = {'name': enddevice, 'port': endport}
|
||||
if bandwidth:
|
||||
port_speeds[startport] = bandwidth
|
||||
|
||||
return neighbors, port_speeds
|
||||
|
||||
def parse_asic_png(png, asic_name, hostname):
|
||||
neighbors = {}
|
||||
devices = {}
|
||||
port_speeds = {}
|
||||
for child in png:
|
||||
if child.tag == str(QName(ns, "DeviceInterfaceLinks")):
|
||||
for link in child.findall(str(QName(ns, "DeviceLinkBase"))):
|
||||
# Chassis internal node is used in multi-asic device or chassis minigraph
|
||||
# where the minigraph will contain the internal asic connectivity and
|
||||
# external neighbor information. The ChassisInternal node will be used to
|
||||
# determine if the link is internal to the device or chassis.
|
||||
chassis_internal_node = link.find(str(QName(ns, "ChassisInternal")))
|
||||
chassis_internal = chassis_internal_node.text if chassis_internal_node is not None else "false"
|
||||
|
||||
# If the link is an external link include the external neighbor
|
||||
# information in ASIC ports table
|
||||
if chassis_internal.lower() == "false":
|
||||
ext_neighbors, ext_port_speeds = parse_asic_external_link(link, asic_name, hostname)
|
||||
neighbors.update(ext_neighbors)
|
||||
port_speeds.update(ext_port_speeds)
|
||||
else:
|
||||
int_neighbors, int_port_speeds = parse_asic_internal_link(link, asic_name, hostname)
|
||||
neighbors.update(int_neighbors)
|
||||
port_speeds.update(int_port_speeds)
|
||||
|
||||
if child.tag == str(QName(ns, "Devices")):
|
||||
for device in child.findall(str(QName(ns, "Device"))):
|
||||
(lo_prefix, mgmt_prefix, name, hwsku, d_type, deployment_id) = parse_device(device)
|
||||
device_data = {'lo_addr': lo_prefix, 'type': d_type, 'mgmt_addr': mgmt_prefix, 'hwsku': hwsku }
|
||||
if deployment_id:
|
||||
device_data['deployment_id'] = deployment_id
|
||||
devices[name] = device_data
|
||||
return (neighbors, devices, port_speeds)
|
||||
|
||||
def parse_dpg(dpg, hname):
|
||||
for child in dpg:
|
||||
"""In Multi-NPU platforms the acl intfs are defined only for the host not for individual asic.
|
||||
There is just one aclintf node in the minigraph
|
||||
Get the aclintfs node first.
|
||||
"""
|
||||
if child.find(str(QName(ns, "AclInterfaces"))) is not None:
|
||||
aclintfs = child.find(str(QName(ns, "AclInterfaces")))
|
||||
|
||||
hostname = child.find(str(QName(ns, "Hostname")))
|
||||
if hostname.text.lower() != hname.lower():
|
||||
continue
|
||||
@ -254,7 +348,6 @@ def parse_dpg(dpg, hname):
|
||||
vlan_attributes['alias'] = vintfname
|
||||
vlans[sonic_vlan_name] = vlan_attributes
|
||||
|
||||
aclintfs = child.find(str(QName(ns, "AclInterfaces")))
|
||||
acls = {}
|
||||
for aclintf in aclintfs.findall(str(QName(ns, "AclInterface"))):
|
||||
if aclintf.find(str(QName(ns, "InAcl"))) is not None:
|
||||
@ -369,7 +462,7 @@ def parse_cpg(cpg, hname):
|
||||
'keepalive': keepalive,
|
||||
'nhopself': nhopself
|
||||
}
|
||||
else:
|
||||
elif start_router.lower() == hname.lower():
|
||||
bgp_sessions[end_peer.lower()] = {
|
||||
'name': end_router,
|
||||
'local_addr': start_peer.lower(),
|
||||
@ -446,6 +539,19 @@ def parse_meta(meta, hname):
|
||||
region = value
|
||||
return syslog_servers, dhcp_servers, ntp_servers, tacacs_servers, mgmt_routes, erspan_dst, deployment_id, region
|
||||
|
||||
def parse_asic_meta(meta, hname):
|
||||
sub_role = None
|
||||
device_metas = meta.find(str(QName(ns, "Devices")))
|
||||
for device in device_metas.findall(str(QName(ns1, "DeviceMetadata"))):
|
||||
if device.find(str(QName(ns1, "Name"))).text.lower() == hname.lower():
|
||||
properties = device.find(str(QName(ns1, "Properties")))
|
||||
for device_property in properties.findall(str(QName(ns1, "DeviceProperty"))):
|
||||
name = device_property.find(str(QName(ns1, "Name"))).text
|
||||
value = device_property.find(str(QName(ns1, "Value"))).text
|
||||
if name == "SubRole":
|
||||
sub_role = value
|
||||
return sub_role
|
||||
|
||||
def parse_deviceinfo(meta, hwsku):
|
||||
port_speeds = {}
|
||||
port_descriptions = {}
|
||||
@ -480,8 +586,7 @@ def parse_spine_chassis_fe(results, vni, lo_intfs, phyport_intfs, pc_intfs, pc_m
|
||||
lo_network = ipaddress.IPNetwork(lo[1])
|
||||
if lo_network.version == 4:
|
||||
lo_addr = str(lo_network.ip)
|
||||
break
|
||||
|
||||
break
|
||||
results['VXLAN_TUNNEL'] = {chassis_vxlan_tunnel: {
|
||||
'src_ip': lo_addr
|
||||
}}
|
||||
@ -520,7 +625,7 @@ def parse_spine_chassis_fe(results, vni, lo_intfs, phyport_intfs, pc_intfs, pc_m
|
||||
for pc_member in pc_members:
|
||||
if pc_member[0] == pc_intf:
|
||||
intf_name = pc_member[1]
|
||||
break
|
||||
break
|
||||
|
||||
if intf_name == None:
|
||||
print >> sys.stderr, 'Warning: cannot find any interfaces that belong to %s' % (pc_intf)
|
||||
@ -567,8 +672,16 @@ def filter_acl_mirror_table_bindings(acls, neighbors, port_channels):
|
||||
# Main functions
|
||||
#
|
||||
###############################################################################
|
||||
def parse_xml(filename, platform=None, port_config_file=None, asic_name=None):
|
||||
""" Parse minigraph xml file.
|
||||
|
||||
def parse_xml(filename, platform=None, port_config_file=None):
|
||||
Keyword arguments:
|
||||
filename -- minigraph file name
|
||||
platform -- device platform
|
||||
port_config_file -- port config file name
|
||||
asic_name -- asic name; to parse multi-asic device minigraph to
|
||||
generate asic specific configuration.
|
||||
"""
|
||||
root = ET.parse(filename).getroot()
|
||||
mini_graph_path = filename
|
||||
|
||||
@ -588,7 +701,7 @@ def parse_xml(filename, platform=None, port_config_file=None):
|
||||
lo_intfs = None
|
||||
neighbors = None
|
||||
devices = None
|
||||
hostname = None
|
||||
sub_role = None
|
||||
docker_routing_config_mode = "separated"
|
||||
port_speeds_default = {}
|
||||
port_speed_png = {}
|
||||
@ -603,6 +716,13 @@ def parse_xml(filename, platform=None, port_config_file=None):
|
||||
bgp_peers_with_range = None
|
||||
deployment_id = None
|
||||
region = None
|
||||
hostname = None
|
||||
|
||||
#hostname is the asic_name, get the asic_id from the asic_name
|
||||
if asic_name is not None:
|
||||
asic_id = get_npu_id_from_name(asic_name)
|
||||
else:
|
||||
asic_id = None
|
||||
|
||||
hwsku_qn = QName(ns, "HwSku")
|
||||
hostname_qn = QName(ns, "Hostname")
|
||||
@ -615,34 +735,59 @@ def parse_xml(filename, platform=None, port_config_file=None):
|
||||
if child.tag == str(docker_routing_config_mode_qn):
|
||||
docker_routing_config_mode = child.text
|
||||
|
||||
(ports, alias_map) = get_port_config(hwsku, platform, port_config_file)
|
||||
(ports, alias_map, alias_asic_map) = get_port_config(hwsku=hwsku, platform=platform, port_config_file=port_config_file, asic=asic_id)
|
||||
port_alias_map.update(alias_map)
|
||||
for child in root:
|
||||
if child.tag == str(QName(ns, "DpgDec")):
|
||||
(intfs, lo_intfs, mvrf, 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, bgp_monitors) = parse_cpg(child, hostname)
|
||||
elif child.tag == str(QName(ns, "PngDec")):
|
||||
(neighbors, devices, console_dev, console_port, mgmt_dev, mgmt_port, port_speed_png, console_ports) = parse_png(child, hostname)
|
||||
elif child.tag == str(QName(ns, "UngDec")):
|
||||
(u_neighbors, u_devices, _, _, _, _, _, _) = parse_png(child, hostname)
|
||||
elif child.tag == str(QName(ns, "MetadataDeclaration")):
|
||||
(syslog_servers, dhcp_servers, ntp_servers, tacacs_servers, mgmt_routes, erspan_dst, deployment_id, region) = parse_meta(child, hostname)
|
||||
elif child.tag == str(QName(ns, "DeviceInfos")):
|
||||
(port_speeds_default, port_descriptions) = parse_deviceinfo(child, hwsku)
|
||||
port_alias_asic_map.update(alias_asic_map)
|
||||
|
||||
for child in root:
|
||||
if asic_name is None:
|
||||
if child.tag == str(QName(ns, "DpgDec")):
|
||||
(intfs, lo_intfs, mvrf, 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, bgp_monitors) = parse_cpg(child, hostname)
|
||||
elif child.tag == str(QName(ns, "PngDec")):
|
||||
(neighbors, devices, console_dev, console_port, mgmt_dev, mgmt_port, port_speed_png, console_ports) = parse_png(child, hostname)
|
||||
elif child.tag == str(QName(ns, "UngDec")):
|
||||
(u_neighbors, u_devices, _, _, _, _, _, _) = parse_png(child, device_hostname)
|
||||
elif child.tag == str(QName(ns, "MetadataDeclaration")):
|
||||
(syslog_servers, dhcp_servers, ntp_servers, tacacs_servers, mgmt_routes, erspan_dst, deployment_id, region) = parse_meta(child, hostname)
|
||||
elif child.tag == str(QName(ns, "DeviceInfos")):
|
||||
(port_speeds_default, port_descriptions) = parse_deviceinfo(child, hwsku)
|
||||
else:
|
||||
if child.tag == str(QName(ns, "DpgDec")):
|
||||
(intfs, lo_intfs, mvrf, mgmt_intf, vlans, vlan_members, pcs, pc_members, acls, vni) = parse_dpg(child, asic_name)
|
||||
elif child.tag == str(QName(ns, "CpgDec")):
|
||||
(bgp_sessions, bgp_asn, bgp_peers_with_range, bgp_monitors) = parse_cpg(child, asic_name)
|
||||
elif child.tag == str(QName(ns, "PngDec")):
|
||||
(neighbors, devices, port_speed_png) = parse_asic_png(child, asic_name, hostname)
|
||||
elif child.tag == str(QName(ns, "MetadataDeclaration")):
|
||||
(sub_role) = parse_asic_meta(child, asic_name)
|
||||
elif child.tag == str(QName(ns, "DeviceInfos")):
|
||||
(port_speeds_default, port_descriptions) = parse_deviceinfo(child, hwsku)
|
||||
|
||||
if asic_name is None:
|
||||
current_device = [devices[key] for key in devices if key.lower() == hostname.lower()][0]
|
||||
name = hostname
|
||||
else:
|
||||
current_device = [devices[key] for key in devices if key.lower() == asic_name.lower()][0]
|
||||
name = asic_name
|
||||
|
||||
current_device = [devices[key] for key in devices if key.lower() == hostname.lower()][0]
|
||||
results = {}
|
||||
results['DEVICE_METADATA'] = {'localhost': {
|
||||
'bgp_asn': bgp_asn,
|
||||
'deployment_id': deployment_id,
|
||||
'region': region,
|
||||
'docker_routing_config_mode': docker_routing_config_mode,
|
||||
'hostname': hostname,
|
||||
'hostname': name,
|
||||
'hwsku': hwsku,
|
||||
'type': current_device['type']
|
||||
}
|
||||
}
|
||||
# for this hostname, if sub_role is defined, add sub_role in
|
||||
# device_metadata
|
||||
if sub_role is not None:
|
||||
current_device['sub_role'] = sub_role
|
||||
results['DEVICE_METADATA']['localhost']['sub_role'] = sub_role
|
||||
results['BGP_NEIGHBOR'] = bgp_sessions
|
||||
results['BGP_MONITORS'] = bgp_monitors
|
||||
results['BGP_PEER_RANGE'] = bgp_peers_with_range
|
||||
@ -703,9 +848,11 @@ def parse_xml(filename, platform=None, port_config_file=None):
|
||||
|
||||
for port_name in port_speed_png:
|
||||
# not consider port not in port_config.ini
|
||||
if port_name not in ports:
|
||||
print >> sys.stderr, "Warning: ignore interface '%s' as it is not in the port_config.ini" % port_name
|
||||
continue
|
||||
#If no port_config_file is found ports is empty so ignore this error
|
||||
if port_config_file is not None:
|
||||
if port_name not in ports:
|
||||
print >> sys.stderr, "Warning: ignore interface '%s' as it is not in the port_config.ini" % port_name
|
||||
continue
|
||||
|
||||
ports.setdefault(port_name, {})['speed'] = port_speed_png[port_name]
|
||||
|
||||
@ -809,11 +956,14 @@ def parse_xml(filename, platform=None, port_config_file=None):
|
||||
for nghbr in neighbors.keys():
|
||||
# remove port not in port_config.ini
|
||||
if nghbr not in ports:
|
||||
print >> sys.stderr, "Warning: ignore interface '%s' in DEVICE_NEIGHBOR as it is not in the port_config.ini" % nghbr
|
||||
if port_config_file is not None:
|
||||
print >> sys.stderr, "Warning: ignore interface '%s' in DEVICE_NEIGHBOR as it is not in the port_config.ini" % nghbr
|
||||
del neighbors[nghbr]
|
||||
|
||||
results['DEVICE_NEIGHBOR'] = neighbors
|
||||
results['DEVICE_NEIGHBOR_METADATA'] = { key:devices[key] for key in devices if key.lower() != hostname.lower() }
|
||||
if asic_name is None:
|
||||
results['DEVICE_NEIGHBOR_METADATA'] = { key:devices[key] for key in devices if key.lower() != hostname.lower() }
|
||||
else:
|
||||
results['DEVICE_NEIGHBOR_METADATA'] = { key:devices[key] for key in devices if key in {device['name'] for device in neighbors.values()} }
|
||||
results['SYSLOG_SERVER'] = dict((item, {}) for item in syslog_servers)
|
||||
results['DHCP_SERVER'] = dict((item, {}) for item in dhcp_servers)
|
||||
results['NTP_SERVER'] = dict((item, {}) for item in ntp_servers)
|
||||
@ -890,8 +1040,17 @@ def parse_device_desc_xml(filename):
|
||||
|
||||
return results
|
||||
|
||||
def parse_asic_sub_role(filename, asic_name):
|
||||
if not os.path.isfile(filename):
|
||||
return None
|
||||
root = ET.parse(filename).getroot()
|
||||
for child in root:
|
||||
if child.tag == str(QName(ns, "MetadataDeclaration")):
|
||||
sub_role = parse_asic_meta(child, asic_name)
|
||||
return sub_role
|
||||
|
||||
port_alias_map = {}
|
||||
port_alias_asic_map = {}
|
||||
|
||||
|
||||
def print_parse_xml(filename):
|
||||
|
@ -3,11 +3,13 @@ import os
|
||||
import sys
|
||||
|
||||
|
||||
def get_port_config_file_name(hwsku=None, platform=None):
|
||||
def get_port_config_file_name(hwsku=None, platform=None, asic=None):
|
||||
port_config_candidates = []
|
||||
port_config_candidates.append('/usr/share/sonic/hwsku/port_config.ini')
|
||||
if hwsku:
|
||||
if platform:
|
||||
if asic:
|
||||
port_config_candidates.append(os.path.join('/usr/share/sonic/device', platform, hwsku, asic,'port_config.ini'))
|
||||
port_config_candidates.append(os.path.join('/usr/share/sonic/device', platform, hwsku, 'port_config.ini'))
|
||||
port_config_candidates.append(os.path.join('/usr/share/sonic/platform', hwsku, 'port_config.ini'))
|
||||
port_config_candidates.append(os.path.join('/usr/share/sonic', hwsku, 'port_config.ini'))
|
||||
@ -17,17 +19,19 @@ def get_port_config_file_name(hwsku=None, platform=None):
|
||||
return None
|
||||
|
||||
|
||||
def get_port_config(hwsku=None, platform=None, port_config_file=None):
|
||||
|
||||
def get_port_config(hwsku=None, platform=None, port_config_file=None, asic=None):
|
||||
if not port_config_file:
|
||||
port_config_file = get_port_config_file_name(hwsku, platform)
|
||||
port_config_file = get_port_config_file_name(hwsku, platform, asic)
|
||||
if not port_config_file:
|
||||
return ({}, {})
|
||||
return ({}, {}, {})
|
||||
return parse_port_config_file(port_config_file)
|
||||
|
||||
|
||||
def parse_port_config_file(port_config_file):
|
||||
ports = {}
|
||||
port_alias_map = {}
|
||||
port_alias_asic_map = {}
|
||||
# Default column definition
|
||||
titles = ['name', 'lanes', 'alias', 'index']
|
||||
with open(port_config_file) as data:
|
||||
@ -49,6 +53,14 @@ def parse_port_config_file(port_config_file):
|
||||
data.setdefault('alias', name)
|
||||
ports[name] = data
|
||||
port_alias_map[data['alias']] = name
|
||||
return (ports, port_alias_map)
|
||||
# asic_port_name to sonic_name mapping also included in
|
||||
# port_alias_map
|
||||
if (('asic_port_name' in data) and
|
||||
(data['asic_port_name'] != name)):
|
||||
port_alias_map[data['asic_port_name']] = name
|
||||
# alias to asic_port_name mapping
|
||||
if 'asic_port_name' in data:
|
||||
port_alias_asic_map[data['alias']] = data['asic_port_name'].strip()
|
||||
return (ports, port_alias_map, port_alias_asic_map)
|
||||
|
||||
|
||||
|
@ -37,10 +37,12 @@ from functools import partial
|
||||
from minigraph import minigraph_encoder
|
||||
from minigraph import parse_xml
|
||||
from minigraph import parse_device_desc_xml
|
||||
from minigraph import parse_asic_sub_role
|
||||
from portconfig import get_port_config
|
||||
from sonic_device_util import get_machine_info
|
||||
from sonic_device_util import get_platform_info
|
||||
from sonic_device_util import get_system_mac
|
||||
from sonic_device_util import get_npu_id_from_name
|
||||
from config_samples import generate_sample_config
|
||||
from config_samples import get_available_config
|
||||
from swsssdk import SonicV2Connector, ConfigDBConnector
|
||||
@ -195,6 +197,7 @@ def main():
|
||||
group.add_argument("-m", "--minigraph", help="minigraph xml file", nargs='?', const='/etc/sonic/minigraph.xml')
|
||||
group.add_argument("-M", "--device-description", help="device description xml file")
|
||||
group.add_argument("-k", "--hwsku", help="HwSKU")
|
||||
parser.add_argument("-n", "--namespace", help="namespace name, used with -m or -k", nargs='?', const=None)
|
||||
parser.add_argument("-p", "--port-config", help="port config file, used with -m or -k", nargs='?', const=None)
|
||||
parser.add_argument("-y", "--yaml", help="yaml file that contains additional variables", action='append', default=[])
|
||||
parser.add_argument("-j", "--json", help="json file that contains additional variables", action='append', default=[])
|
||||
@ -222,13 +225,18 @@ def main():
|
||||
|
||||
data = {}
|
||||
hwsku = args.hwsku
|
||||
asic_name = args.namespace
|
||||
asic_id = None
|
||||
if asic_name is not None:
|
||||
asic_id = get_npu_id_from_name(asic_name)
|
||||
|
||||
|
||||
if hwsku is not None:
|
||||
hardware_data = {'DEVICE_METADATA': {'localhost': {
|
||||
'hwsku': hwsku
|
||||
}}}
|
||||
deep_update(data, hardware_data)
|
||||
(ports, _) = get_port_config(hwsku, platform, args.port_config)
|
||||
(ports, _, _) = get_port_config(hwsku, platform, args.port_config, asic_id)
|
||||
if not ports:
|
||||
print('Failed to get port config', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
@ -242,11 +250,11 @@ def main():
|
||||
minigraph = args.minigraph
|
||||
if platform:
|
||||
if args.port_config != None:
|
||||
deep_update(data, parse_xml(minigraph, platform, args.port_config))
|
||||
deep_update(data, parse_xml(minigraph, platform, args.port_config, asic_name=asic_name))
|
||||
else:
|
||||
deep_update(data, parse_xml(minigraph, platform))
|
||||
deep_update(data, parse_xml(minigraph, platform, asic_name=asic_name))
|
||||
else:
|
||||
deep_update(data, parse_xml(minigraph, port_config_file=args.port_config))
|
||||
deep_update(data, parse_xml(minigraph, port_config_file=args.port_config, asic_name=asic_name))
|
||||
|
||||
if args.device_description != None:
|
||||
deep_update(data, parse_device_desc_xml(args.device_description))
|
||||
@ -267,11 +275,28 @@ def main():
|
||||
configdb.connect()
|
||||
deep_update(data, FormatConverter.db_to_output(configdb.get_config()))
|
||||
|
||||
|
||||
# the minigraph file must be provided to get the mac address for backend asics
|
||||
if args.platform_info:
|
||||
asic_role = None
|
||||
if asic_name is not None:
|
||||
if args.minigraph is not None:
|
||||
asic_role = parse_asic_sub_role(args.minigraph, asic_name)
|
||||
|
||||
if asic_role is not None and asic_role.lower() == "backend":
|
||||
mac = get_system_mac(namespace=asic_name)
|
||||
else:
|
||||
mac = get_system_mac()
|
||||
else:
|
||||
mac = get_system_mac()
|
||||
|
||||
hardware_data = {'DEVICE_METADATA': {'localhost': {
|
||||
'platform': platform,
|
||||
'mac': get_system_mac()
|
||||
'mac': mac,
|
||||
}}}
|
||||
# The ID needs to be passed to the SAI to identify the asic.
|
||||
if asic_name is not None:
|
||||
hardware_data['DEVICE_METADATA']['localhost'].update(asic_id=asic_id)
|
||||
deep_update(data, hardware_data)
|
||||
|
||||
if args.template is not None:
|
||||
|
@ -3,7 +3,8 @@ import os
|
||||
import yaml
|
||||
import subprocess
|
||||
import re
|
||||
|
||||
from natsort import natsorted
|
||||
import glob
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: sonic_device_util
|
||||
@ -17,6 +18,9 @@ description:
|
||||
TODO: this file shall be renamed and moved to other places in future
|
||||
to have it shared with multiple applications.
|
||||
'''
|
||||
SONIC_DEVICE_PATH = '/usr/share/sonic/device'
|
||||
NPU_NAME_PREFIX = 'asic'
|
||||
NAMESPACE_PATH_GLOB = '/run/netns/*'
|
||||
def get_machine_info():
|
||||
if not os.path.isfile('/host/machine.conf'):
|
||||
return None
|
||||
@ -27,7 +31,38 @@ def get_machine_info():
|
||||
if len(tokens) < 2:
|
||||
continue
|
||||
machine_vars[tokens[0]] = tokens[1].strip()
|
||||
return machine_vars
|
||||
return machine_vars
|
||||
|
||||
def get_npu_id_from_name(npu_name):
|
||||
if npu_name.startswith(NPU_NAME_PREFIX):
|
||||
return npu_name[len(NPU_NAME_PREFIX):]
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_num_npus():
|
||||
platform = get_platform_info(get_machine_info())
|
||||
asic_conf_file_path = os.path.join(SONIC_DEVICE_PATH, platform, 'asic.conf')
|
||||
if not os.path.isfile(asic_conf_file_path):
|
||||
return 1
|
||||
with open(asic_conf_file_path) as asic_conf_file:
|
||||
for line in asic_conf_file:
|
||||
tokens = line.split('=')
|
||||
if len(tokens) < 2:
|
||||
continue
|
||||
if tokens[0].lower() == 'num_asic':
|
||||
num_npus = tokens[1].strip()
|
||||
return num_npus
|
||||
|
||||
def get_namespaces():
|
||||
"""
|
||||
In a multi NPU platform, each NPU is in a Linux Namespace.
|
||||
This method returns list of all the Namespace present on the device
|
||||
"""
|
||||
ns_list = []
|
||||
for path in glob.glob(NAMESPACE_PATH_GLOB):
|
||||
ns = os.path.basename(path)
|
||||
ns_list.append(ns)
|
||||
return natsorted(ns_list)
|
||||
|
||||
def get_platform_info(machine_info):
|
||||
if machine_info != None:
|
||||
@ -51,7 +86,7 @@ def get_sonic_version_info():
|
||||
def valid_mac_address(mac):
|
||||
return bool(re.match("^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$", mac))
|
||||
|
||||
def get_system_mac():
|
||||
def get_system_mac(namespace=None):
|
||||
version_info = get_sonic_version_info()
|
||||
|
||||
if (version_info['asic_type'] == 'mellanox'):
|
||||
@ -73,10 +108,14 @@ def get_system_mac():
|
||||
# Try valid mac in eeprom, else fetch it from eth0
|
||||
platform = get_platform_info(get_machine_info())
|
||||
hwsku = get_machine_info()['onie_machine']
|
||||
profile_cmd = 'cat /usr/share/sonic/device/' + platform +'/'+ hwsku +'/profile.ini | cut -f2 -d='
|
||||
profile_cmd = 'cat' + SONIC_DEVICE_PATH + '/' + platform +'/'+ hwsku +'/profile.ini | cut -f2 -d='
|
||||
hw_mac_entry_cmds = [ profile_cmd, "sudo decode-syseeprom -m", "ip link show eth0 | grep ether | awk '{print $2}'" ]
|
||||
else:
|
||||
hw_mac_entry_cmds = [ "ip link show eth0 | grep ether | awk '{print $2}'" ]
|
||||
mac_address_cmd = "cat /sys/class/net/eth0/address"
|
||||
if namespace is not None:
|
||||
mac_address_cmd = "sudo ip netns exec {} {}".format(namespace, mac_address_cmd)
|
||||
|
||||
hw_mac_entry_cmds = [mac_address_cmd]
|
||||
|
||||
for get_mac_cmd in hw_mac_entry_cmds:
|
||||
proc = subprocess.Popen(get_mac_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
|
1214
src/sonic-config-engine/tests/multi_npu_data/sample-minigraph.xml
Normal file
1214
src/sonic-config-engine/tests/multi_npu_data/sample-minigraph.xml
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,9 @@
|
||||
# name lanes alias asic_port_name
|
||||
Ethernet0 33,34,35,36 Ethernet1/1 Eth0-ASIC0
|
||||
Ethernet4 29,30,31,32 Ethernet1/2 Eth1-ASIC0
|
||||
Ethernet8 41,42,43,44 Ethernet1/3 Eth2-ASIC0
|
||||
Ethernet12 37,38,39,40 Ethernet1/4 Eth3-ASIC0
|
||||
Ethernet-BP0 13,14,15,16 Ethernet-BP0 Eth4-ASIC0
|
||||
Ethernet-BP4 17,18,19,20 Ethernet-BP4 Eth5-ASIC0
|
||||
Ethernet-BP8 21,22,23,24 Ethernet-BP8 Eth6-ASIC0
|
||||
Ethernet-BP12 25,26,27,28 Ethernet-BP12 Eth7-ASIC0
|
@ -0,0 +1,9 @@
|
||||
# name lanes alias asic_port_name
|
||||
Ethernet16 33,34,35,36 Ethernet1/5 Eth0-ASIC1
|
||||
Ethernet20 29,30,31,32 Ethernet1/6 Eth1-ASIC1
|
||||
Ethernet24 41,42,43,44 Ethernet1/7 Eth2-ASIC1
|
||||
Ethernet28 37,38,39,40 Ethernet1/8 Eth3-ASIC1
|
||||
Ethernet-BP16 13,14,15,16 Ethernet-BP16 Eth4-ASIC1
|
||||
Ethernet-BP20 17,18,19,20 Ethernet-BP20 Eth5-ASIC1
|
||||
Ethernet-BP24 21,22,23,24 Ethernet-BP24 Eth6-ASIC1
|
||||
Ethernet-BP28 25,26,27,28 Ethernet-BP28 Eth7-ASIC1
|
@ -0,0 +1,9 @@
|
||||
# name lanes alias asic_port_name
|
||||
Ethernet-BP256 61,62,63,64 Ethernet-BP256 Eth0-ASIC2
|
||||
Ethernet-BP260 57,58,59,60 Ethernet-BP260 Eth1-ASIC2
|
||||
Ethernet-BP264 53,54,55,56 Ethernet-BP264 Eth2-ASIC2
|
||||
Ethernet-BP268 49,50,51,52 Ethernet-BP268 Eth3-ASIC2
|
||||
Ethernet-BP272 45,46,47,48 Ethernet-BP272 Eth4-ASIC2
|
||||
Ethernet-BP276 41,42,43,44 Ethernet-BP276 Eth5-ASIC2
|
||||
Ethernet-BP280 37,38,39,40 Ethernet-BP280 Eth6-ASIC2
|
||||
Ethernet-BP284 33,34,35,36 Ethernet-BP284 Eth7-ASIC2
|
@ -0,0 +1,9 @@
|
||||
# name lanes alias asic_port_name
|
||||
Ethernet-BP384 29,30,31,32 Ethernet-BP384 Eth0-ASIC3
|
||||
Ethernet-BP388 25,26,27,28 Ethernet-BP388 Eth1-ASIC3
|
||||
Ethernet-BP392 21,22,23,24 Ethernet-BP392 Eth2-ASIC3
|
||||
Ethernet-BP396 17,18,19,20 Ethernet-BP396 Eth3-ASIC3
|
||||
Ethernet-BP400 13,14,15,16 Ethernet-BP400 Eth4-ASIC3
|
||||
Ethernet-BP404 9,10,11,12 Ethernet-BP404 Eth5-ASIC3
|
||||
Ethernet-BP408 5,6,7,8 Ethernet-BP408 Eth6-ASIC3
|
||||
Ethernet-BP412 1,2,3,4 Ethernet-BP412 Eth7-ASIC3
|
221
src/sonic-config-engine/tests/test_multinpu_cfggen.py
Normal file
221
src/sonic-config-engine/tests/test_multinpu_cfggen.py
Normal file
@ -0,0 +1,221 @@
|
||||
import unittest
|
||||
from unittest import TestCase
|
||||
import subprocess
|
||||
import os
|
||||
import json
|
||||
import yaml
|
||||
|
||||
SKU = 'multi-npu-01'
|
||||
ASIC_SKU = 'multi-npu-asic'
|
||||
NUM_ASIC = 4
|
||||
HOSTNAME = 'multi_npu_platform_01'
|
||||
|
||||
|
||||
class TestMultiNpuCfgGen(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.test_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
self.test_data_dir = os.path.join(self.test_dir, 'multi_npu_data')
|
||||
self.script_file = os.path.join(self.test_dir, '..', 'sonic-cfggen')
|
||||
self.sample_graph = os.path.join(self.test_data_dir, 'sample-minigraph.xml')
|
||||
self.port_config = []
|
||||
for asic in range(NUM_ASIC):
|
||||
self.port_config.append(os.path.join(self.test_data_dir, "sample_port_config-{}.ini".format(asic)))
|
||||
|
||||
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 run_diff(self, file1, file2):
|
||||
return subprocess.check_output('diff -u {} {} || true'.format(file1, file2), shell=True)
|
||||
|
||||
def run_script_for_asic(self,argument,asic, port_config=None):
|
||||
argument = "{} -n asic{} ".format(argument, asic)
|
||||
if port_config:
|
||||
argument += "-p {}".format(port_config)
|
||||
output = self.run_script(argument)
|
||||
return output
|
||||
|
||||
def test_dummy_run(self):
|
||||
argument = ''
|
||||
output = self.run_script(argument)
|
||||
self.assertEqual(output, '')
|
||||
|
||||
def test_hwsku(self):
|
||||
argument = "-v \"DEVICE_METADATA[\'localhost\'][\'hwsku\']\" -m \"{}\"".format(self.sample_graph)
|
||||
output = self.run_script(argument)
|
||||
self.assertEqual(output.strip(), SKU)
|
||||
for asic in range(NUM_ASIC):
|
||||
output = self.run_script_for_asic(argument, asic)
|
||||
self.assertEqual(output.strip(), SKU)
|
||||
|
||||
def test_print_data(self):
|
||||
argument = "-m \"{}\" --print-data".format(self.sample_graph)
|
||||
output = self.run_script(argument)
|
||||
self.assertGreater(len(output.strip()) , 0)
|
||||
for asic in range(NUM_ASIC):
|
||||
output = self.run_script_for_asic(argument, asic)
|
||||
self.assertGreater(len(output.strip()) , 0)
|
||||
|
||||
def test_additional_json_data(self):
|
||||
argument = '-a \'{"key1":"value1"}\' -v key1'
|
||||
output = self.run_script(argument)
|
||||
self.assertEqual(output.strip(), 'value1')
|
||||
for asic in range(NUM_ASIC):
|
||||
output = self.run_script_for_asic(argument, asic)
|
||||
self.assertEqual(output.strip(), 'value1')
|
||||
|
||||
def test_read_yaml(self):
|
||||
argument = '-v yml_item -y ' + os.path.join(self.test_dir, 'test.yml')
|
||||
output = yaml.load(self.run_script(argument))
|
||||
self.assertListEqual(output, ['value1', 'value2'])
|
||||
for asic in range(NUM_ASIC):
|
||||
output = yaml.load(self.run_script_for_asic(argument, asic))
|
||||
self.assertListEqual(output, ['value1', 'value2'])
|
||||
|
||||
def test_render_template(self):
|
||||
argument = '-y ' + os.path.join(self.test_dir, 'test.yml') + ' -t ' + os.path.join(self.test_dir, 'test.j2')
|
||||
output = self.run_script(argument)
|
||||
self.assertEqual(output.strip(), 'value1\nvalue2')
|
||||
for asic in range(NUM_ASIC):
|
||||
output = self.run_script_for_asic(argument, asic)
|
||||
self.assertEqual(output.strip(), 'value1\nvalue2')
|
||||
|
||||
def test_metadata_tacacs(self):
|
||||
argument = '-m "' + self.sample_graph + '" --var-json "TACPLUS_SERVER"'
|
||||
output = json.loads(self.run_script(argument))
|
||||
self.assertDictEqual(output, {'123.46.98.21': {'priority': '1', 'tcp_port': '49'}})
|
||||
#TACPLUS_SERVER not present in the asic configuration.
|
||||
for asic in range(NUM_ASIC):
|
||||
output = json.loads(self.run_script_for_asic(argument, asic, self.port_config[asic]))
|
||||
self.assertDictEqual(output, {})
|
||||
|
||||
def test_metadata_ntp(self):
|
||||
argument = '-m "' + self.sample_graph + '" --var-json "NTP_SERVER"'
|
||||
output = json.loads(self.run_script(argument))
|
||||
self.assertDictEqual(output, {'17.39.1.130': {}, '17.39.1.129': {}})
|
||||
#NTP data is present only in the host config
|
||||
for asic in range(NUM_ASIC):
|
||||
output = json.loads(self.run_script_for_asic(argument, asic, self.port_config[asic]))
|
||||
print "Log:asic{} sku {}".format(asic,output)
|
||||
self.assertDictEqual(output, {})
|
||||
|
||||
def test_mgmt_port(self):
|
||||
argument = '-m "' + self.sample_graph + '" --var-json "MGMT_PORT"'
|
||||
output = json.loads(self.run_script(argument))
|
||||
self.assertDictEqual(output, {'eth0': {'alias': 'eth0', 'admin_status': 'up'}})
|
||||
for asic in range(NUM_ASIC):
|
||||
output = json.loads(self.run_script_for_asic(argument, asic, self.port_config[asic]))
|
||||
self.assertDictEqual(output, {})
|
||||
|
||||
def test_frontend_asic_portchannels(self):
|
||||
argument = "-m {} -p {} -n asic0 --var-json \"PORTCHANNEL\"".format(self.sample_graph, self.port_config[0])
|
||||
output = json.loads(self.run_script(argument))
|
||||
self.assertDictEqual(output, \
|
||||
{'PortChannel0002': {'admin_status': 'up', 'min_links': '2', 'members': ['Ethernet0', 'Ethernet4'], 'mtu': '9100'},
|
||||
'PortChannel4001': {'admin_status': 'up', 'min_links': '2', 'members': ['Ethernet-BP0', 'Ethernet-BP4'], 'mtu': '9100'},
|
||||
'PortChannel4002': {'admin_status': 'up', 'min_links': '2', 'members': ['Ethernet-BP8', 'Ethernet-BP12'], 'mtu': '9100'}})
|
||||
|
||||
def test_backend_asic_portchannels(self):
|
||||
argument = "-m {} -p {} -n asic3 --var-json \"PORTCHANNEL\"".format(self.sample_graph, self.port_config[3])
|
||||
output = json.loads(self.run_script(argument))
|
||||
self.assertDictEqual(output, \
|
||||
{'PortChannel4013': {'admin_status': 'up', 'min_links': '2', 'members': ['Ethernet-BP384', 'Ethernet-BP388'], 'mtu': '9100'},
|
||||
'PortChannel4014': {'admin_status': 'up', 'min_links': '2', 'members': ['Ethernet-BP392', 'Ethernet-BP396'], 'mtu': '9100'}})
|
||||
|
||||
def test_frontend_asic_portchannel_mem(self):
|
||||
argument = "-m {} -p {} -n asic0 --var-json \"PORTCHANNEL_MEMBER\"".format(self.sample_graph, self.port_config[0])
|
||||
output = json.loads(self.run_script(argument))
|
||||
self.assertListEqual(output.keys(), \
|
||||
['PortChannel4002|Ethernet-BP8', 'PortChannel0002|Ethernet0', 'PortChannel0002|Ethernet4', 'PortChannel4002|Ethernet-BP12', 'PortChannel4001|Ethernet-BP0', 'PortChannel4001|Ethernet-BP4'])
|
||||
|
||||
def test_backend_asic_portchannels_mem(self):
|
||||
argument = "-m {} -p {} -n asic3 --var-json \"PORTCHANNEL_MEMBER\"".format(self.sample_graph, self.port_config[3])
|
||||
output = json.loads(self.run_script(argument))
|
||||
self.assertListEqual(output.keys(), \
|
||||
['PortChannel4013|Ethernet-BP384', 'PortChannel4014|Ethernet-BP392', 'PortChannel4014|Ethernet-BP396', 'PortChannel4013|Ethernet-BP388'])
|
||||
|
||||
def test_frontend_asic_portchannel_intf(self):
|
||||
argument = "-m {} -p {} -n asic0 --var-json \"PORTCHANNEL_INTERFACE\"".format(self.sample_graph, self.port_config[0])
|
||||
output = json.loads(self.run_script(argument))
|
||||
self.assertListEqual(output.keys(), \
|
||||
['PortChannel4001|10.1.0.1/31', 'PortChannel0002|FC00::1/126', 'PortChannel4002|10.1.0.3/31', 'PortChannel0002', 'PortChannel0002|10.0.0.0/31', 'PortChannel4001', 'PortChannel4002'])
|
||||
|
||||
def test_backend_asic_portchannel_intf(self):
|
||||
argument = "-m {} -p {} -n asic3 --var-json \"PORTCHANNEL_INTERFACE\"".format(self.sample_graph, self.port_config[3])
|
||||
output = json.loads(self.run_script(argument))
|
||||
self.assertListEqual(output.keys(), \
|
||||
['PortChannel4013', 'PortChannel4013|10.1.0.2/31', 'PortChannel4014', 'PortChannel4014|10.1.0.6/31'])
|
||||
|
||||
def test_frontend_asic_device_neigh(self):
|
||||
argument = "-m {} -p {} -n asic0 --var-json \"DEVICE_NEIGHBOR\"".format(self.sample_graph, self.port_config[0])
|
||||
output = json.loads(self.run_script(argument))
|
||||
self.assertDictEqual(output, \
|
||||
{'Ethernet0': {'name': '01T2', 'port': 'Ethernet1'},
|
||||
'Ethernet4': {'name': '01T2', 'port': 'Ethernet2'},
|
||||
'Ethernet-BP4': {'name': 'ASIC2', 'port': 'Eth1-ASIC2'},
|
||||
'Ethernet-BP12': {'name': 'ASIC3', 'port': 'Eth1-ASIC3'},
|
||||
'Ethernet-BP0': {'name': 'ASIC2', 'port': 'Eth0-ASIC2'},
|
||||
'Ethernet-BP8': {'name': 'ASIC3', 'port': 'Eth0-ASIC3'}})
|
||||
|
||||
def test_frontend_asic_device_neigh_metadata(self):
|
||||
argument = "-m {} -p {} -n asic0 --var-json \"DEVICE_NEIGHBOR_METADATA\"".format(self.sample_graph, self.port_config[0])
|
||||
output = json.loads(self.run_script(argument))
|
||||
self.assertDictEqual(output, \
|
||||
{'01T2': {'lo_addr': None, 'mgmt_addr': '89.139.132.40', 'hwsku': 'VM', 'type': 'SpineRouter'},
|
||||
'ASIC3': {'lo_addr': '0.0.0.0/0', 'mgmt_addr': '0.0.0.0/0', 'hwsku': 'multi-npu-asic', 'type': 'Asic'},
|
||||
'ASIC2': {'lo_addr': '0.0.0.0/0', 'mgmt_addr': '0.0.0.0/0', 'hwsku': 'multi-npu-asic', 'type': 'Asic'}})
|
||||
|
||||
def test_backend_asic_device_neigh(self):
|
||||
argument = "-m {} -p {} -n asic3 --var-json \"DEVICE_NEIGHBOR\"".format(self.sample_graph, self.port_config[3])
|
||||
output = json.loads(self.run_script(argument))
|
||||
self.assertDictEqual(output, \
|
||||
{'Ethernet-BP396': {'name': 'ASIC1', 'port': 'Eth7-ASIC1'},
|
||||
'Ethernet-BP384': {'name': 'ASIC0', 'port': 'Eth6-ASIC0'},
|
||||
'Ethernet-BP392': {'name': 'ASIC1', 'port': 'Eth6-ASIC1'},
|
||||
'Ethernet-BP388': {'name': 'ASIC0', 'port': 'Eth7-ASIC0'}})
|
||||
|
||||
def test_backend_device_neigh_metadata(self):
|
||||
argument = "-m {} -p {} -n asic3 --var-json \"DEVICE_NEIGHBOR_METADATA\"".format(self.sample_graph, self.port_config[3])
|
||||
output = json.loads(self.run_script(argument))
|
||||
self.assertDictEqual(output, \
|
||||
{'ASIC1': {'lo_addr': '0.0.0.0/0', 'mgmt_addr': '0.0.0.0/0', 'hwsku': 'multi-npu-asic', 'type': 'Asic'},
|
||||
'ASIC0': {'lo_addr': '0.0.0.0/0', 'mgmt_addr': '0.0.0.0/0', 'hwsku': 'multi-npu-asic', 'type': 'Asic'}})
|
||||
|
||||
def test_frontend_bgp_neighbor(self):
|
||||
argument = "-m {} -p {} -n asic0 --var-json \"BGP_NEIGHBOR\"".format(self.sample_graph, self.port_config[0])
|
||||
output = json.loads(self.run_script(argument))
|
||||
self.assertDictEqual(output, \
|
||||
{'10.0.0.1': {'rrclient': 0, 'name': '01T2', 'local_addr': '10.0.0.0', 'nhopself': 0, 'holdtime': '10', 'asn': '65200', 'keepalive': '3'},
|
||||
'10.1.0.0': {'rrclient': 0, 'name': 'ASIC2', 'local_addr': '10.1.0.1', 'nhopself': 0, 'holdtime': '0', 'asn': '65100', 'keepalive': '0'},
|
||||
'fc00::2': {'rrclient': 0, 'name': '01T2', 'local_addr': 'fc00::1', 'nhopself': 0, 'holdtime': '10', 'asn': '65200', 'keepalive': '3'},
|
||||
'10.1.0.2': {'rrclient': 0, 'name': 'ASIC3', 'local_addr': '10.1.0.3', 'nhopself': 0, 'holdtime': '0', 'asn': '65100', 'keepalive': '0'}})
|
||||
|
||||
def test_backend_asic_bgp_neighbor(self):
|
||||
argument = "-m {} -p {} -n asic3 --var-json \"BGP_NEIGHBOR\"".format(self.sample_graph, self.port_config[3])
|
||||
output = json.loads(self.run_script(argument))
|
||||
self.assertDictEqual(output, \
|
||||
{'10.1.0.7': {'rrclient': 0, 'name': 'ASIC1', 'local_addr': '10.1.0.6', 'nhopself': 0, 'holdtime': '0', 'asn': '65100', 'keepalive': '0'},
|
||||
'10.1.0.3': {'rrclient': 0, 'name': 'ASIC0', 'local_addr': '10.1.0.2', 'nhopself': 0, 'holdtime': '0', 'asn': '65100', 'keepalive': '0'}})
|
||||
|
||||
def test_device_asic_metadata(self):
|
||||
argument = "-m {} --var-json DEVICE_METADATA".format(self.sample_graph)
|
||||
for asic in range(NUM_ASIC):
|
||||
output = json.loads(self.run_script_for_asic(argument, asic,self.port_config[asic]))
|
||||
asic_name = "asic{}".format(asic)
|
||||
self.assertEqual(output['localhost']['hostname'], asic_name)
|
||||
self.assertEqual(output['localhost']['type'], 'Asic')
|
||||
if asic == 0 or asic == 1:
|
||||
self.assertEqual(output['localhost']['sub_role'], 'FrontEnd')
|
||||
else:
|
||||
self.assertEqual(output['localhost']['sub_role'], 'BackEnd')
|
Reference in New Issue
Block a user