diff --git a/ansible/config_sonic_basedon_testbed.yml b/ansible/config_sonic_basedon_testbed.yml index af2afae4b13..02ff61af3be 100644 --- a/ansible/config_sonic_basedon_testbed.yml +++ b/ansible/config_sonic_basedon_testbed.yml @@ -41,17 +41,16 @@ testbed_file: testbed.csv when: testbed_file is not defined - - name: Set default dut index - set_fact: - dut_index: 0 - when: dut_index is not defined - - name: Gathering testbed information test_facts: testbed_name="{{ testbed_name }}" testbed_file="{{ testbed_file }}" delegate_to: localhost - fail: msg="The DUT you are trying to run test does not belongs to this testbed" - when: testbed_facts['duts'][dut_index] != inventory_hostname + when: inventory_hostname not in testbed_facts['duts'] + + - name: Set default dut index + set_fact: + dut_index: "{{ testbed_facts['duts_map'][inventory_hostname]|int }}" - name: set testbed_type set_fact: @@ -85,13 +84,13 @@ - name: find all enabled host_interfaces set_fact: - host_if_indexes: "{{ vm_topo_config['host_interfaces'] | difference(vm_topo_config['disabled_host_interfaces']) }}" + host_if_indexes: "{{ vm_topo_config['host_interfaces_by_dut'][dut_index|int] | difference(vm_topo_config['disabled_host_interfaces_by_dut'][dut_index|int]) }}" - name: find all vlan interface names for T0 topology set_fact: vlan_intfs: "{{ vlan_intfs|default([])}} + ['{{ port_alias[item] }}' ]" with_items: "{{ host_if_indexes }}" - when: "('host_interfaces' in vm_topo_config) and ('tor' in vm_topo_config['dut_type'] | lower)" + when: "('host_interfaces_by_dut' in vm_topo_config) and ('tor' in vm_topo_config['dut_type'] | lower)" - name: find all vlan configurations for T0 topology vlan_config: @@ -99,16 +98,16 @@ port_alias: "{{ port_alias }}" vlan_config: "{{ vlan_config | default(None) }}" delegate_to: localhost - when: "('host_interfaces' in vm_topo_config) and ('tor' in vm_topo_config['dut_type'] | lower)" + when: "('host_interfaces_by_dut' in vm_topo_config) and ('tor' in vm_topo_config['dut_type'] | lower)" - name: find all interface indexes mapping connecting to VM set_fact: - interface_to_vms: "{{ interface_to_vms|default({}) | combine({ item.key: item.value['interface_indexes'] }) }}" + interface_to_vms: "{{ interface_to_vms|default({}) | combine({ item.key: item.value['interface_indexes'][dut_index|int] }) }}" with_dict: "{{ vm_topo_config['vm'] }}" - name: find all interface indexes connecting to VM set_fact: - ifindex_to_vms: "{{ ifindex_to_vms|default([]) }} + {{ item.value['interface_indexes']}}" + ifindex_to_vms: "{{ ifindex_to_vms|default([]) }} + {{ item.value['interface_indexes'][dut_index|int] }}" with_dict: "{{ vm_topo_config['vm'] }}" - name: find all interface names @@ -163,7 +162,7 @@ mode: '0755' become: true - # {{ server_cer }}/ streamingtelemetryserver.cer need to be copied on PTFDocker and renamed as dsmsroot.cer + # {{ server_cer }}/ streamingtelemetryserver.cer need to be copied on PTFDocker and renamed as dsmsroot.cer - name: Generate server cert using openssl. command: openssl req \ -x509 \ @@ -172,7 +171,7 @@ -newkey rsa:2048 \ -keyout "{{ server_key }}" -subj "/CN=ndastreamingservertest" - -out "{{ server_cer }}" + -out "{{ server_cer }}" become: true # {{ dsmsroot_cer }}/ dsmsroot.cer need to be copied on PTFDocker and renamed as streamingtelemetryclient.cer diff --git a/ansible/lab b/ansible/lab index bbb55f1d495..fc8de3bb98c 100644 --- a/ansible/lab +++ b/ansible/lab @@ -73,6 +73,12 @@ sonic_s6000: vlab-04: ansible_host: 10.250.0.107 ansible_hostv6: fec0::ffff:afa:7 + vlab-05: + ansible_host: 10.250.0.110 + ansible_hostv6: fec0::ffff:afa:a + vlab-06: + ansible_host: 10.250.0.111 + ansible_hostv6: fec0::ffff:afa:b sonic_s6100: vars: diff --git a/ansible/library/conn_graph_facts.py b/ansible/library/conn_graph_facts.py index df64b0a8267..f6e8f614e13 100755 --- a/ansible/library/conn_graph_facts.py +++ b/ansible/library/conn_graph_facts.py @@ -326,6 +326,7 @@ def main(): device_port_vlans = [] device_vlan_range = [] device_vlan_list = [] + device_vlan_map_list = {} for hostname in hostnames: dev = lab_graph.get_host_device_info(hostname) if dev is None: @@ -337,6 +338,7 @@ def main(): if host_vlan: device_vlan_range.append(host_vlan["VlanRange"]) device_vlan_list.append(host_vlan["VlanList"]) + device_vlan_map_list[hostname] = host_vlan["VlanList"] device_port_vlans.append(lab_graph.get_host_port_vlans(hostname)) results = {k: v for k, v in locals().items() if (k.startswith("device_") and v)} diff --git a/ansible/library/test_facts.py b/ansible/library/test_facts.py index 0e26a0e1b7e..e3c9fa364d7 100644 --- a/ansible/library/test_facts.py +++ b/ansible/library/test_facts.py @@ -131,6 +131,7 @@ def read_testbed_topo(self): line['ptf_netmask_v6'] = str(ptfaddress.netmask) line['duts'] = line['dut'].translate(string.maketrans("", ""), "[] ").split(';') + line['duts_map'] = {dut:line['duts'].index(dut) for dut in line['duts']} del line['dut'] self.testbed_topo[line['conf-name']] = line diff --git a/ansible/library/topo_facts.py b/ansible/library/topo_facts.py index 0a2fd10b769..15c31f59ced 100644 --- a/ansible/library/topo_facts.py +++ b/ansible/library/topo_facts.py @@ -1,7 +1,7 @@ #!/usr/bin/env python import os import traceback -import ipaddr as ipaddress +import ipaddress import csv from operator import itemgetter from itertools import groupby @@ -19,6 +19,45 @@ required: True ''' +def parse_vm_vlan_port(vlan): + """ + parse vm vlan port + + old format (non multi-dut): vlan_index + new format (multi-dut): dut_index.vlan_index@ptf_index + + """ + if isinstance(vlan, int): + dut_index = 0 + vlan_index = vlan + ptf_index = vlan + else: + m = re.match("(\d+)\.(\d+)@(\d+)", vlan) + (dut_index, vlan_index, ptf_index) = (int(m.group(1)), int(m.group(2)), int(m.group(3))) + + return (dut_index, vlan_index, ptf_index) + +def parse_host_interfaces(hifs): + """ + parse host interfaces + + old format (non multi-dut): vlan_index + new format (multi-dut): dut_index.vlan_index,dut_index.vlan_index + """ + + if isinstance(hifs, int): + dut_index = 0 + vlan_index = int(hifs) + + return [(dut_index, vlan_index)] + + ret = [] + for hif in hifs.split(','): + (dut_index, port_index) = [int(x) for x in hif.split('.')] + ret.append((dut_index, port_index)) + + return ret + class ParseTestbedTopoinfo(): ''' Parse topology yml file @@ -36,6 +75,7 @@ def get_topo_config(self, topo_name): topo_name = re.sub(CLET_SUFFIX + "$", "", topo_name) topo_filename = 'vars/topo_' + topo_name + '.yml' vm_topo_config = dict() + po_map = [None] * 16 # maximum 16 port channel interfaces ### read topology definition if not os.path.isfile(topo_filename): @@ -45,6 +85,11 @@ def get_topo_config(self, topo_name): topo_definition = yaml.load(f) ### parse topo file specified in vars/ to reverse as dut config + dut_num = 1 + if 'dut_num' in topo_definition['topology']: + dut_num = topo_definition['topology']['dut_num'] + vm_topo_config['dut_num'] = dut_num + if 'VMs' in topo_definition['topology']: dut_asn = topo_definition['configuration_properties']['common']['dut_asn'] vm_topo_config['dut_asn'] = dut_asn @@ -52,36 +97,87 @@ def get_topo_config(self, topo_name): vmconfig = dict() for vm in topo_definition['topology']['VMs']: vmconfig[vm] = dict() - vmconfig[vm]['intfs'] = [] + vmconfig[vm]['intfs'] = [[] for i in range(dut_num)] vmconfig[vm]['properties']=topo_definition['configuration'][vm]['properties'] - vmconfig[vm]['interface_indexes'] = topo_definition['topology']['VMs'][vm]['vlans'] - vmconfig[vm]['bgp_asn'] = topo_definition['configuration'][vm]['bgp']['asn'] + vmconfig[vm]['interface_indexes'] = [[] for i in range(dut_num)] + for vlan in topo_definition['topology']['VMs'][vm]['vlans']: + (dut_index, vlan_index, _) = parse_vm_vlan_port(vlan) + vmconfig[vm]['interface_indexes'][dut_index].append(vlan_index) + + # physical interface + for intf in topo_definition['configuration'][vm]['interfaces']: + if 'Ethernet' in intf: + dut_index = 0 + if 'dut_index' in topo_definition['configuration'][vm]['interfaces'][intf]: + dut_index = topo_definition['configuration'][vm]['interfaces'][intf]['dut_index'] + if 'lacp' in topo_definition['configuration'][vm]['interfaces'][intf]: + po_map[topo_definition['configuration'][vm]['interfaces'][intf]['lacp']] = dut_index + + vmconfig[vm]['intfs'][dut_index].append(intf) + + # ip interface + vmconfig[vm]['ip_intf'] = [None] * dut_num + vmconfig[vm]['peer_ipv4'] = [None] * dut_num + vmconfig[vm]['ipv4mask'] = [None] * dut_num + vmconfig[vm]['peer_ipv6'] = [None] * dut_num + vmconfig[vm]['ipv6mask'] = [None] * dut_num + + for intf in topo_definition['configuration'][vm]['interfaces']: + dut_index = 0 + if 'Ethernet' in intf: + if 'dut_index' in topo_definition['configuration'][vm]['interfaces'][intf]: + dut_index = topo_definition['configuration'][vm]['interfaces'][intf]['dut_index'] + elif 'Port-Channel' in intf: + m = re.search("(\d+)", intf) + dut_index = po_map[int(m.group(1))] + if 'ipv4' in topo_definition['configuration'][vm]['interfaces'][intf] and ('loopback' not in intf.lower()): - (vmconfig[vm]['peer_ipv4'], vmconfig[vm]['ipv4mask']) = topo_definition['configuration'][vm]['interfaces'][intf]['ipv4'].split('/') - vmconfig[vm]['ip_intf'] = intf + (peer_ipv4, ipv4_mask) = topo_definition['configuration'][vm]['interfaces'][intf]['ipv4'].split('/') + vmconfig[vm]['peer_ipv4'][dut_index] = peer_ipv4 + vmconfig[vm]['ipv4mask'][dut_index] = ipv4_mask + vmconfig[vm]['ip_intf'][dut_index] = intf if 'ipv6' in topo_definition['configuration'][vm]['interfaces'][intf] and ('loopback' not in intf.lower()): - (ipv6_addr, vmconfig[vm]['ipv6mask']) = topo_definition['configuration'][vm]['interfaces'][intf]['ipv6'].split('/') - vmconfig[vm]['ip_intf'] = intf - vmconfig[vm]['peer_ipv6'] = ipv6_addr.upper() - if 'Ethernet' in intf: - vmconfig[vm]['intfs'].append(intf) - for ip in topo_definition['configuration'][vm]['bgp']['peers'][dut_asn]: - if ip[0:5].upper() in vmconfig[vm]['peer_ipv4'].upper(): - vmconfig[vm]['bgp_ipv4'] = ip.upper() - if ip[0:5].upper() in vmconfig[vm]['peer_ipv6'].upper(): - vmconfig[vm]['bgp_ipv6'] = ip.upper() + (ipv6_addr, ipv6_mask) = topo_definition['configuration'][vm]['interfaces'][intf]['ipv6'].split('/') + vmconfig[vm]['peer_ipv6'][dut_index] = ipv6_addr.upper() + vmconfig[vm]['ipv6mask'][dut_index] = ipv6_mask + vmconfig[vm]['ip_intf'][dut_index] = intf + + # bgp + vmconfig[vm]['bgp_ipv4'] = [None] * dut_num + vmconfig[vm]['bgp_ipv6'] = [None] * dut_num + vmconfig[vm]['bgp_asn'] = topo_definition['configuration'][vm]['bgp']['asn'] + for ipstr in topo_definition['configuration'][vm]['bgp']['peers'][dut_asn]: + ip = ipaddress.ip_address(ipstr.decode('utf8')) + for dut_index in range(0, dut_num): + if ip.version == 4: + ipsubnet_str = vmconfig[vm]['peer_ipv4'][dut_index]+'/'+vmconfig[vm]['ipv4mask'][dut_index] + ipsubnet = ipaddress.ip_interface(ipsubnet_str.decode('utf8')) + if ip in ipsubnet.network: + vmconfig[vm]['bgp_ipv4'][dut_index] = ipstr.upper() + elif ip.version == 6: + ipsubnet_str = vmconfig[vm]['peer_ipv6'][dut_index]+'/'+vmconfig[vm]['ipv6mask'][dut_index] + ipsubnet = ipaddress.ip_interface(ipsubnet_str.decode('utf8')) + if ip in ipsubnet.network: + vmconfig[vm]['bgp_ipv6'][dut_index] = ipstr.upper() + vm_topo_config['vm'] = vmconfig + vm_topo_config['host_interfaces_by_dut'] = [[] for i in range(dut_num)] if 'host_interfaces' in topo_definition['topology']: vm_topo_config['host_interfaces'] = topo_definition['topology']['host_interfaces'] - else: - vm_topo_config['host_interfaces'] = [] + for host_if in topo_definition['topology']['host_interfaces']: + hifs = parse_host_interfaces(host_if) + for hif in hifs: + vm_topo_config['host_interfaces_by_dut'][hif[0]].append(hif[1]) + vm_topo_config['disabled_host_interfaces_by_dut'] = [[] for i in range(dut_num)] if 'disabled_host_interfaces' in topo_definition['topology']: vm_topo_config['disabled_host_interfaces'] = topo_definition['topology']['disabled_host_interfaces'] - else: - vm_topo_config['disabled_host_interfaces'] = [] + for host_if in topo_definition['topology']['disabled_host_interfaces']: + hifs = parse_host_interfaces(host_if) + for hif in hifs: + vm_topo_config['disabled_host_interfaces_by_dut'][hif[0]].append(hif[1]) if 'DUT' in topo_definition['topology']: vm_topo_config['DUT'] = topo_definition['topology']['DUT'] @@ -91,6 +187,7 @@ def get_topo_config(self, topo_name): self.vm_topo_config = vm_topo_config return vm_topo_config + def main(): module = AnsibleModule( argument_spec=dict( diff --git a/ansible/roles/eos/templates/dualtor-leaf.j2 b/ansible/roles/eos/templates/dualtor-leaf.j2 new file mode 120000 index 00000000000..8430cb1debd --- /dev/null +++ b/ansible/roles/eos/templates/dualtor-leaf.j2 @@ -0,0 +1 @@ +t0-leaf.j2 \ No newline at end of file diff --git a/ansible/roles/vm_set/library/vm_topology.py b/ansible/roles/vm_set/library/vm_topology.py index dde570608ec..27a79403323 100644 --- a/ansible/roles/vm_set/library/vm_topology.py +++ b/ansible/roles/vm_set/library/vm_topology.py @@ -56,8 +56,9 @@ - ptf_bp_ip_addr: ipv6 address with prefixlen for the injected docker container - ptf_bp_ipv6_addr: ipv6 address with prefixlen for the injected docker container - mgmt_bridge: a bridge which is used as mgmt bridge on the host - - dut_fp_ports: dut ports - - dut_mgmt_port: dut mgmt port + - duts_fp_ports: duts front panel ports + - duts_mgmt_port: duts mgmt port + - duts_name: duts names - fp_mtu: MTU for FP ports ''' @@ -81,8 +82,9 @@ ptf_bp_ip_addr: "{{ ptf_ip }}" ptf_bp_ipv6_addr: "{{ ptf_ip }}" mgmt_bridge: "{{ mgmt_bridge }}" - dut_mgmt_port: "{{ dut_mgmt_port }}" - dut_fp_ports: "{{ dut_fp_ports }}" + duts_mgmt_port: "{{ duts_mgmt_port }}" + duts_fp_ports: "{{ duts_fp_ports }}" + duts_name: "{{ duts_name }}" fp_mtu: "{{ fp_mtu_size }}" max_fp_num: "{{ max_fp_num }} ''' @@ -101,6 +103,8 @@ OVS_FP_TAP_TEMPLATE = '%s-t%d' OVS_BP_TAP_TEMPLATE = '%s-back' INJECTED_INTERFACES_TEMPLATE = 'inje-%s-%d' +MUXY_INTERFACES_TEMPLATE = 'muxy-%s-%d' +MUXY_BRIDGE_TEMPLATE = 'mbr-%s-%d' PTF_NAME_TEMPLATE = 'ptf_%s' PTF_MGMT_IF_TEMPLATE = 'ptf-%s-m' PTF_BP_IF_TEMPLATE = 'ptf-%s-b' @@ -118,12 +122,31 @@ def __get__(self, obj, objtype): return obj._host_interfaces def __set__(self, obj, host_interfaces): - """Parse and set host interfaces.""" + """ + Parse and set host interfaces. + + for single DUT, host interface like [0, 1, 2, ...], + where the number is the port index starting from 0. + + For multi DUT, host interface like [(0, 1), (0, 2), (1, 1), (1, 2), ...], + where the tuple is (dut_index, port_index), both starting + from 0. + + For dual-tor, host interface look like [[(0, 1), (1, 1)], [(0, 2), (1,2)], ...], + where one interface consists of multiple ports to DUT. + For example, ((0, 1), (1, 1)) means the host interface connects + to port1@dut0 and port1@dut1. + """ if obj._is_multi_duts: obj._host_interfaces = [] for intf in host_interfaces: - obj._host_interfaces.append( - tuple(map(int, intf.strip().split(".")))) + intfs = intf.split(',') + if len(intfs) > 1: + obj._host_interfaces.append( + [tuple(map(int, x.split('.'))) for x in intfs]) + else: + obj._host_interfaces.append( + tuple(map(int, intfs[0].strip().split(".")))) else: obj._host_interfaces = host_interfaces @@ -141,9 +164,9 @@ def __init__(self, vm_names, fp_mtu, max_fp_num): return - def init(self, vm_set_name, topo, vm_base, dut_fp_ports, ptf_exists=True, - is_multi_duts=False): + def init(self, vm_set_name, topo, vm_base, duts_fp_ports, duts_name, ptf_exists=True): self.vm_set_name = vm_set_name + self.duts_name = duts_name self.VMs = {} if 'VMs' in topo: self.vm_base = vm_base @@ -160,13 +183,13 @@ def init(self, vm_set_name, topo, vm_base, dut_fp_ports, ptf_exists=True, if len(attrs['vlans']) > len(self.get_bridges(vmname)): raise Exception("Wrong vlans parameter for hostname %s, vm %s. Too many vlans. Maximum is %d" % (hostname, vmname, len(self.get_bridges(vmname)))) - self._is_multi_duts = is_multi_duts + self._is_multi_duts = True if len(self.duts_name) > 1 else False if 'host_interfaces' in topo: self.host_interfaces = topo['host_interfaces'] else: self.host_interfaces = [] - self.dut_fp_ports = dut_fp_ports + self.duts_fp_ports = duts_fp_ports self.injected_fp_ports = self.extract_vm_vlans() @@ -251,10 +274,18 @@ def get_bridges(self, vmname): return brs - def add_veth_ports_to_docker(self): + def add_injected_fp_ports_to_docker(self): + """ + add injected front panel ports to docker + + + PTF (int_if) ----------- injected port (ext_if) + + """ for vlan in self.injected_fp_ports: - ext_if = INJECTED_INTERFACES_TEMPLATE % (self.vm_set_name, vlan) - int_if = PTF_FP_IFACE_TEMPLATE % vlan + (_, _, ptf_index) = VMTopology.parse_vm_vlan_port(vlan) + ext_if = INJECTED_INTERFACES_TEMPLATE % (self.vm_set_name, ptf_index) + int_if = PTF_FP_IFACE_TEMPLATE % ptf_index self.add_veth_if_to_docker(ext_if, int_if) return @@ -382,12 +413,28 @@ def unbind_mgmt_port(self, mgmt_port): return def bind_fp_ports(self, disconnect_vm=False): + """ + bind dut front panel ports to VMs + + +----------------------+ + | OVS_FP_BRIDGE | + +----+ | | + | VM +-----+ vm_iface | +-----+ + +----+ | duts_fp_port +------+ DUT | + | | +-----+ + +-----+ | | + | PTF +----+ injected_iface | + +-----+ | | + +----------------------+ + + """ for attr in self.VMs.values(): - for vlan_num, vlan in enumerate(attr['vlans']): - injected_iface = INJECTED_INTERFACES_TEMPLATE % (self.vm_set_name, vlan) - br_name = OVS_FP_BRIDGE_TEMPLATE % (self.vm_names[self.vm_base_index + attr['vm_offset']], vlan_num) - vm_iface = OVS_FP_TAP_TEMPLATE % (self.vm_names[self.vm_base_index + attr['vm_offset']], vlan_num) - self.bind_ovs_ports(br_name, self.dut_fp_ports[vlan], injected_iface, vm_iface, disconnect_vm) + for idx, vlan in enumerate(attr['vlans']): + br_name = OVS_FP_BRIDGE_TEMPLATE % (self.vm_names[self.vm_base_index + attr['vm_offset']], idx) + vm_iface = OVS_FP_TAP_TEMPLATE % (self.vm_names[self.vm_base_index + attr['vm_offset']], idx) + (dut_index, vlan_index, ptf_index) = VMTopology.parse_vm_vlan_port(vlan) + injected_iface = INJECTED_INTERFACES_TEMPLATE % (self.vm_set_name, ptf_index) + self.bind_ovs_ports(br_name, self.duts_fp_ports[self.duts_name[dut_index]][vlan_index], injected_iface, vm_iface, disconnect_vm) return @@ -429,7 +476,15 @@ def unbind_vm_backplane(self): return def bind_ovs_ports(self, br_name, dut_iface, injected_iface, vm_iface, disconnect_vm=False): - """bind dut/injected/vm ports under an ovs bridge""" + """ + bind dut/injected/vm ports under an ovs bridge as follows + + +----------------------+ + | +---- dut_iface + PTF (injected_iface) --+ OVS bridge (br_name) | + | +---- vm_iface + +----------------------+ + """ br = VMTopology.get_ovs_bridge_by_port(injected_iface) if br is not None and br != br_name: VMTopology.cmd('ovs-vsctl del-port %s %s' % (br, injected_iface)) @@ -445,7 +500,7 @@ def bind_ovs_ports(self, br_name, dut_iface, injected_iface, vm_iface, disconnec if dut_iface not in ports: VMTopology.cmd('ovs-vsctl add-port %s %s' % (br_name, dut_iface)) - bindings = VMTopology.get_ovs_port_bindings(br_name, dut_iface) + bindings = VMTopology.get_ovs_port_bindings(br_name, [dut_iface]) dut_iface_id = bindings[dut_iface] injected_iface_id = bindings[injected_iface] vm_iface_id = bindings[vm_iface] @@ -491,31 +546,109 @@ def unbind_ovs_port(self, br_name, port): return - def inject_host_ports(self): - """inject dut port into the ptf docker""" + def create_muxy_cable(self, host_ifindex, host_if, upper_if, lower_if, active_if_index=0): + """ + create muxy cable + + +--------------+ + | +----- upper_if + PTF (host_if) --+ OVS bridge | + | +----- lower_if + +--------------+ + """ + + br_name = MUXY_BRIDGE_TEMPLATE % (self.vm_set_name, host_ifindex) + + self.create_ovs_bridge(br_name, self.fp_mtu) + + for intf in [host_if, upper_if, lower_if]: + br = VMTopology.get_ovs_bridge_by_port(intf) + if br is not None and br != br_name: + VMTopology.cmd('ovs-vsctl del-port %s %s' % (br, intf)) + + ports = VMTopology.get_ovs_br_ports(br_name) + for intf in [host_if, upper_if, lower_if]: + if intf not in ports: + VMTopology.cmd('ovs-vsctl add-port %s %s' % (br_name, intf)) + + bindings = VMTopology.get_ovs_port_bindings(br_name, [upper_if, lower_if]) + host_if_id = bindings[host_if] + upper_if_id = bindings[upper_if] + lower_if_id = bindings[lower_if] + + # clear old bindings + VMTopology.cmd('ovs-ofctl del-flows %s' % br_name) + + VMTopology.cmd("ovs-ofctl add-flow %s table=0,in_port=%s,action=output:%s,%s" % (br_name, host_if_id, upper_if_id, lower_if_id)) + if active_if_index == 0: + VMTopology.cmd("ovs-ofctl add-flow %s table=0,in_port=%s,action=output:%s" % (br_name, upper_if_id, host_if_id)) + else: + VMTopology.cmd("ovs-ofctl add-flow %s table=0,in_port=%s,action=output:%s" % (br_name, lower_if_id, host_if_id)) + + return + + def remove_muxy_cable(self, host_ifindex): + """ + remove muxy cable + """ + + br_name = MUXY_BRIDGE_TEMPLATE % (self.vm_set_name, host_ifindex) + + self.destroy_ovs_bridge(br_name) + + return + + + def add_host_ports(self): + """ + add dut port in the ptf docker + + for non-dual topo, inject the dut port into ptf docker. + for dual-tor topo, create ovs port and add to ptf docker. + """ + self.update() for i, intf in enumerate(self.host_interfaces): if self._is_multi_duts: - fp_port = self.dut_fp_ports[intf[0]][intf[1]] - ptf_intf = PTF_FP_IFACE_TEMPLATE % i + if isinstance(intf, list): + # create veth link and inject one end into the ptf docker + muxy_if = MUXY_INTERFACES_TEMPLATE % (self.vm_set_name, i) + ptf_if = PTF_FP_IFACE_TEMPLATE % i + self.add_veth_if_to_docker(muxy_if, ptf_if) + + # create muxy cable + upper_tor_if = self.duts_fp_ports[self.duts_name[intf[0][0]]][intf[0][1]] + lower_tor_if = self.duts_fp_ports[self.duts_name[intf[1][0]]][intf[1][1]] + self.create_muxy_cable(i, muxy_if, upper_tor_if, lower_tor_if) + else: + fp_port = self.duts_fp_ports[self.duts_name[intf[0]]][intf[1]] + ptf_if = PTF_FP_IFACE_TEMPLATE % i + self.add_dut_if_to_docker(ptf_if, fp_port) else: - fp_port = self.dut_fp_ports[intf] - ptf_intf = PTF_FP_IFACE_TEMPLATE % intf - self.add_dut_if_to_docker(ptf_intf, fp_port) + fp_port = self.duts_fp_ports[self.duts_name[0]][intf] + ptf_if = PTF_FP_IFACE_TEMPLATE % intf + self.add_dut_if_to_docker(ptf_if, fp_port) return - def deject_host_ports(self): - """deject dut port from the ptf docker""" + def remove_host_ports(self): + """ + remove dut port from the ptf docker + """ + self.update() for i, intf in enumerate(self.host_interfaces): if self._is_multi_duts: - fp_port = self.dut_fp_ports[intf[0]][intf[1]] - ptf_intf = PTF_FP_IFACE_TEMPLATE % i + if isinstance(intf, list): + self.remove_muxy_cable(i) + else: + fp_port = self.duts_fp_ports[self.duts_name[intf[0]]][intf[1]] + ptf_if = PTF_FP_IFACE_TEMPLATE % i + self.remove_dut_if_from_docker(ptf_if, fp_port) else: - fp_port = self.dut_fp_ports[intf] - ptf_intf = PTF_FP_IFACE_TEMPLATE % intf - self.remove_dut_if_from_docker(ptf_intf, fp_port) + fp_port = self.duts_fp_ports[self.duts_name[0]][intf] + ptf_if = PTF_FP_IFACE_TEMPLATE % intf + self.remove_dut_if_from_docker(ptf_if, fp_port) @staticmethod def iface_up(iface_name, pid=None): @@ -575,7 +708,7 @@ def get_ovs_bridge_by_port(port): return bridge @staticmethod - def get_ovs_port_bindings(bridge, vlan_iface = None): + def get_ovs_port_bindings(bridge, vlan_iface = []): # Vlan interface addition may take few secs to reflect in OVS Command, # Let`s retry few times in that case. for retries in range(RETRIES): @@ -589,7 +722,7 @@ def get_ovs_port_bindings(bridge, vlan_iface = None): iface_name = matched.group(2) result[iface_name] = port_id # Check if we have vlan_iface populated - if vlan_iface is None or vlan_iface in result: + if len(vlan_iface) == 0 or all([intf in result for intf in vlan_iface]): return result time.sleep(2*retries+1) # Flow reaches here when vlan_iface not present in result @@ -646,6 +779,25 @@ def brctl_show(): return br_to_ifs, if_to_br + @staticmethod + def parse_vm_vlan_port(vlan): + """ + parse vm vlan port + + old format (non multi-dut): vlan_index + new format (multi-dut): dut_index.vlan_index@ptf_index + + """ + if isinstance(vlan, int): + dut_index = 0 + vlan_index = vlan + ptf_index = vlan + else: + m = re.match("(\d+)\.(\d+)@(\d+)", vlan) + (dut_index, vlan_index, ptf_index) = (int(m.group(1)), int(m.group(2)), int(m.group(3))) + + return (dut_index, vlan_index, ptf_index) + def check_topo(topo, is_multi_duts=False): @@ -665,19 +817,23 @@ def _assert(condition, exctype, msg): for vlan in vlans: if is_multi_duts: - condition = (isinstance(vlan, str) and - re.match(r"\d+.\d+", vlan)) - _assert(condition, ValueError, - "topo['host_interfaces'] should be a " - "list of strings of format '.'") + for p in vlan.split(','): + condition = (isinstance(p, str) and + re.match(r"^\d+.\d+$", p)) + _assert(condition, ValueError, + "topo['host_interfaces'] should be a " + "list of strings of format '.' or '.,.'") + _assert(p not in all_vlans, ValueError, + "topo['host_interfaces'] double use of vlan: %s" % p) + all_vlans.add(p) else: condition = isinstance(vlan, int) and vlan >= 0 _assert(condition, ValueError, "topo['host_interfaces'] should be a " "list of positive integers") - _assert(vlan not in all_vlans, ValueError, - "topo['host_interfaces'] double use of vlan: %s" % vlan) - all_vlans.add(vlan) + _assert(vlan not in all_vlans, ValueError, + "topo['host_interfaces'] double use of vlan: %s" % vlan) + all_vlans.add(vlan) hostif_exists = True @@ -700,10 +856,17 @@ def _assert(condition, exctype, msg): "'vm_offset' with a number" % hostname) for vlan in attrs['vlans']: - _assert(isinstance(vlan, int) and vlan >= 0, - ValueError, - "topo['VMs'][%s]['vlans'] should contain" - " a list with integers" % hostname) + if is_multi_duts: + condition = (isinstance(p, str) and + re.match(r"^\d+.\d+$", p)) + _assert(condition, ValueError, + "topo['VMs'][%s]['vlans'] should be " + "list of strings of format '.'. vlan=%s" % (hostname, vlan)) + else: + _assert(isinstance(vlan, int) and vlan >= 0, + ValueError, + "topo['VMs'][%s]['vlans'] should contain" + " a list with integers. vlan=%s" % (hostname, vlan)) _assert(vlan not in all_vlans, ValueError, "topo['VMs'][%s]['vlans'] double use " @@ -737,11 +900,11 @@ def main(): ptf_bp_ip_addr=dict(required=False, type='str'), ptf_bp_ipv6_addr=dict(required=False, type='str'), mgmt_bridge=dict(required=False, type='str'), - dut_fp_ports=dict(required=False, type='list'), - dut_mgmt_port=dict(required=False, type='str'), + duts_fp_ports=dict(required=False, type='dict'), + duts_mgmt_port=dict(required=False, type='list'), + duts_name=dict(required=False, type='list'), fp_mtu=dict(required=False, type='int', default=DEFAULT_MTU), max_fp_num=dict(required=False, type='int', default=NUM_FP_VLANS_PER_FP), - is_multi_duts=dict(required=False, type='bool', default=False), ), supports_check_mode=False) @@ -749,7 +912,7 @@ def main(): vm_names = module.params['vm_names'] fp_mtu = module.params['fp_mtu'] max_fp_num = module.params['max_fp_num'] - dut_mgmt_port = None + duts_mgmt_port = [] curtime = datetime.datetime.now().isoformat() @@ -776,12 +939,13 @@ def main(): 'ptf_bp_ip_addr', 'ptf_bp_ipv6_addr', 'mgmt_bridge', - 'dut_fp_ports'], cmd) + 'duts_fp_ports'], cmd) vm_set_name = module.params['vm_set_name'] topo = module.params['topo'] - dut_fp_ports = module.params['dut_fp_ports'] - is_multi_duts = module.params['is_multi_duts'] + duts_fp_ports = module.params['duts_fp_ports'] + duts_name = module.params['duts_name'] + is_multi_duts = True if len(duts_name) > 1 else False if len(vm_set_name) > VM_SET_NAME_MAX_LEN: raise Exception("vm_set_name can't be longer than %d characters: %s (%d)" % (VM_SET_NAME_MAX_LEN, vm_set_name, len(vm_set_name))) @@ -794,8 +958,7 @@ def main(): else: vm_base = None - net.init(vm_set_name, topo, vm_base, dut_fp_ports, - is_multi_duts=is_multi_duts) + net.init(vm_set_name, topo, vm_base, duts_fp_ports, duts_name) ptf_mgmt_ip_addr = module.params['ptf_mgmt_ip_addr'] ptf_mgmt_ipv6_addr = module.params['ptf_mgmt_ipv6_addr'] @@ -807,26 +970,29 @@ def main(): ptf_bp_ip_addr = module.params['ptf_bp_ip_addr'] ptf_bp_ipv6_addr = module.params['ptf_bp_ipv6_addr'] - if module.params['dut_mgmt_port']: - net.bind_mgmt_port(mgmt_bridge, module.params['dut_mgmt_port']) + if module.params['duts_mgmt_port']: + for dut_mgmt_port in module.params['duts_mgmt_port']: + if dut_mgmt_port != "": + net.bind_mgmt_port(mgmt_bridge, dut_mgmt_port) if vms_exists: - net.add_veth_ports_to_docker() + net.add_injected_fp_ports_to_docker() net.bind_fp_ports() net.bind_vm_backplane() net.add_bp_port_to_docker(ptf_bp_ip_addr, ptf_bp_ipv6_addr) if hostif_exists: - net.inject_host_ports() + net.add_host_ports() elif cmd == 'unbind': check_params(module, ['vm_set_name', 'topo', - 'dut_fp_ports'], cmd) + 'duts_fp_ports'], cmd) vm_set_name = module.params['vm_set_name'] topo = module.params['topo'] - dut_fp_ports = module.params['dut_fp_ports'] - is_multi_duts = module.params['is_multi_duts'] + duts_fp_ports = module.params['duts_fp_ports'] + duts_name = module.params['duts_name'] + is_multi_duts = True if len(duts_name) > 1 else False if len(vm_set_name) > VM_SET_NAME_MAX_LEN: raise Exception("vm_set_name can't be longer than %d characters: %s (%d)" % (VM_SET_NAME_MAX_LEN, vm_set_name, len(vm_set_name))) @@ -839,18 +1005,19 @@ def main(): else: vm_base = None - net.init(vm_set_name, topo, vm_base, dut_fp_ports, - is_multi_duts=is_multi_duts) + net.init(vm_set_name, topo, vm_base, duts_fp_ports, duts_name) - if module.params['dut_mgmt_port']: - net.unbind_mgmt_port(module.params['dut_mgmt_port']) + if module.params['duts_mgmt_port']: + for dut_mgmt_port in module.params['duts_mgmt_port']: + if dut_mgmt_port != "": + net.unbind_mgmt_port(dut_mgmt_port) if vms_exists: net.unbind_vm_backplane() net.unbind_fp_ports() if hostif_exists: - net.deject_host_ports() + net.remove_host_ports() elif cmd == 'renumber': check_params(module, ['vm_set_name', 'topo', @@ -860,12 +1027,13 @@ def main(): 'ptf_bp_ip_addr', 'ptf_bp_ipv6_addr', 'mgmt_bridge', - 'dut_fp_ports'], cmd) + 'duts_fp_ports'], cmd) vm_set_name = module.params['vm_set_name'] topo = module.params['topo'] - dut_fp_ports = module.params['dut_fp_ports'] - is_multi_duts = module.params['is_multi_duts'] + duts_fp_ports = module.params['duts_fp_ports'] + duts_name = module.params['duts_name'] + is_multi_duts = True if len(duts_name) > 1 else False if len(vm_set_name) > VM_SET_NAME_MAX_LEN: raise Exception("vm_set_name can't be longer than %d characters: %s (%d)" % (VM_SET_NAME_MAX_LEN, vm_set_name, len(vm_set_name))) @@ -878,8 +1046,7 @@ def main(): else: vm_base = None - net.init(vm_set_name, topo, vm_base, dut_fp_ports, True, - is_multi_duts) + net.init(vm_set_name, topo, vm_base, duts_fp_ports, duts_name, True) ptf_mgmt_ip_addr = module.params['ptf_mgmt_ip_addr'] ptf_mgmt_ipv6_addr = module.params['ptf_mgmt_ipv6_addr'] @@ -893,19 +1060,20 @@ def main(): if vms_exists: net.unbind_fp_ports() - net.add_veth_ports_to_docker() + net.add_injected_fp_ports_to_docker() net.bind_fp_ports() if hostif_exists: - net.inject_host_ports() + net.add_host_ports() elif cmd == 'connect-vms' or cmd == 'disconnect-vms': check_params(module, ['vm_set_name', 'topo', - 'dut_fp_ports'], cmd) + 'duts_fp_ports'], cmd) vm_set_name = module.params['vm_set_name'] topo = module.params['topo'] - dut_fp_ports = module.params['dut_fp_ports'] - is_multi_duts = module.params['is_multi_duts'] + duts_fp_ports = module.params['duts_fp_ports'] + duts_name = module.params['duts_name'] + is_multi_duts = True if len(duts_name) > 1 else False if len(vm_set_name) > VM_SET_NAME_MAX_LEN: raise Exception("vm_set_name can't be longer than %d characters: %s (%d)" % (VM_SET_NAME_MAX_LEN, vm_set_name, len(vm_set_name))) @@ -918,8 +1086,7 @@ def main(): else: vm_base = None - net.init(vm_set_name, topo, vm_base, dut_fp_ports, - is_multi_duts=is_multi_duts) + net.init(vm_set_name, topo, vm_base, duts_fp_ports, duts_name) if vms_exists: if cmd == 'connect-vms': diff --git a/ansible/roles/vm_set/tasks/add_topo.yml b/ansible/roles/vm_set/tasks/add_topo.yml index 01871d8ad97..8838501eb0d 100644 --- a/ansible/roles/vm_set/tasks/add_topo.yml +++ b/ansible/roles/vm_set/tasks/add_topo.yml @@ -75,17 +75,21 @@ command: docker exec -i ptf_{{ vm_set_name }} sysctl -w net.ipv6.conf.all.disable_ipv6=0 become: yes - - name: Set front panel/mgmt port for dut - include_tasks: set_dut_port.yml - - - name: Setup vlan port for vlan tunnel - vlan_port: - external_port: "{{ external_port }}" - vlan_ids: "{{ device_vlan_list }}" - is_multi_duts: "{{ dut_name is defined and dut_name.split(',')|length > 1 }}" - cmd: "create" - become: yes + - name: Get dut ports + include_tasks: get_dut_port.yml + loop: "{{ duts_name.split(',') }}" + loop_control: + loop_var: dut_name + + - name: Create vlan ports for dut + include_tasks: create_dut_port.yml when: external_port is defined + loop: "{{ duts_name.split(',') }}" + loop_control: + loop_var: dut_name + + - debug: msg="{{ duts_fp_ports }}" + - debug: msg="{{ duts_mgmt_port }}" - include_tasks: add_ceos_list.yml when: vm_type is defined and vm_type == "ceos" @@ -103,11 +107,11 @@ ptf_bp_ip_addr: "{{ ptf_bp_ip }}" ptf_bp_ipv6_addr: "{{ ptf_bp_ipv6 }}" mgmt_bridge: "{{ mgmt_bridge }}" - dut_fp_ports: "{{ dut_fp_ports }}" - dut_mgmt_port: "{{ dut_mgmt_port }}" + duts_fp_ports: "{{ duts_fp_ports }}" + duts_mgmt_port: "{{ duts_mgmt_port }}" + duts_name: "{{ duts_name.split(',') }}" fp_mtu: "{{ fp_mtu_size }}" max_fp_num: "{{ max_fp_num }}" - is_multi_duts: "{{ dut_name is defined and dut_name.split(',')|length > 1 }}" become: yes - name: Send arp ping packet to gw for flusing the ARP table diff --git a/ansible/roles/vm_set/tasks/connect_vms.yml b/ansible/roles/vm_set/tasks/connect_vms.yml index c99fd4262cc..80524696cb7 100644 --- a/ansible/roles/vm_set/tasks/connect_vms.yml +++ b/ansible/roles/vm_set/tasks/connect_vms.yml @@ -1,5 +1,8 @@ -- name: Set front panel/mgmt port for dut - include_tasks: set_dut_port.yml +- name: Get duts ports + include_tasks: get_dut_port.yml + loop: "{{ duts_name.split(',') }}" + loop_control: + loop_var: dut_name - name: Connect VMs to {{ topo }}. base vm = {{ VM_base }} vm_topology: @@ -8,8 +11,9 @@ topo: "{{ topology }}" vm_names: "{{ VM_hosts }}" vm_base: "{{ VM_base }}" - dut_fp_ports: "{{ dut_fp_ports }}" - dut_mgmt_port: "{{ dut_mgmt_port }}" + duts_fp_ports: "{{ duts_fp_ports }}" + duts_mgmt_port: "{{ duts_mgmt_port }}" + duts_name: "{{ duts_name.split(',') }}" fp_mtu: "{{ fp_mtu_size }}" max_fp_num: "{{ max_fp_num }}" become: yes diff --git a/ansible/roles/vm_set/tasks/create_dut_port.yml b/ansible/roles/vm_set/tasks/create_dut_port.yml new file mode 100644 index 00000000000..c2d396e2990 --- /dev/null +++ b/ansible/roles/vm_set/tasks/create_dut_port.yml @@ -0,0 +1,9 @@ +- name: Setup vlan port for vlan tunnel + vlan_port: + external_port: "{{ external_port }}" + vlan_ids: "{{ device_vlan_map_list[dut_name] }}" + cmd: "create" + become: yes + +- set_fact: + duts_fp_ports: "{{ duts_fp_ports|default({}) | combine( { dut_name: dut_fp_ports } ) }}" diff --git a/ansible/roles/vm_set/tasks/disconnect_vms.yml b/ansible/roles/vm_set/tasks/disconnect_vms.yml index 28743968b91..43d6938fa1e 100644 --- a/ansible/roles/vm_set/tasks/disconnect_vms.yml +++ b/ansible/roles/vm_set/tasks/disconnect_vms.yml @@ -1,5 +1,8 @@ -- name: Set front panel/mgmt port for dut - include_tasks: set_dut_port.yml +- name: Get duts ports + include_tasks: get_dut_port.yml + loop: "{{ duts_name.split(',') }}" + loop_control: + loop_var: dut_name - name: Disconnect VMs to {{ topo }}. base vm = {{ VM_base }} vm_topology: @@ -8,7 +11,8 @@ topo: "{{ topology }}" vm_names: "{{ VM_hosts }}" vm_base: "{{ VM_base }}" - dut_fp_ports: "{{ dut_fp_ports }}" - dut_mgmt_port: "{{ dut_mgmt_port }}" + duts_fp_ports: "{{ duts_fp_ports }}" + duts_mgmt_port: "{{ duts_mgmt_port }}" + duts_name: "{{ duts_name.split(',') }}" max_fp_num: "{{ max_fp_num }}" become: yes diff --git a/ansible/roles/vm_set/tasks/set_dut_port.yml b/ansible/roles/vm_set/tasks/get_dut_port.yml similarity index 70% rename from ansible/roles/vm_set/tasks/set_dut_port.yml rename to ansible/roles/vm_set/tasks/get_dut_port.yml index b8ed60f385f..8d5a8a352b1 100644 --- a/ansible/roles/vm_set/tasks/set_dut_port.yml +++ b/ansible/roles/vm_set/tasks/get_dut_port.yml @@ -1,8 +1,7 @@ -- name: Set front panel port for vlan tunnel +- name: Get front panel port for vlan tunnel vlan_port: external_port: "{{ external_port }}" - vlan_ids: "{{ device_vlan_list }}" - is_multi_duts: "{{ dut_name is defined and dut_name.split(',')|length > 1 }}" + vlan_ids: "{{ device_vlan_map_list[dut_name] }}" cmd: "list" become: yes when: external_port is defined @@ -23,3 +22,7 @@ vmname: "{{ dut_name }}" when: external_port is not defined and hostvars[dut_name].type is defined and hostvars[dut_name]['type'] == 'simx' become: yes + +- set_fact: + duts_fp_ports: "{{ duts_fp_ports|default({}) | combine( { dut_name: dut_fp_ports } ) }}" + duts_mgmt_port: "{{ duts_mgmt_port|default([]) + [ dut_mgmt_port ] }}" diff --git a/ansible/roles/vm_set/tasks/main.yml b/ansible/roles/vm_set/tasks/main.yml index 6d65c734d5c..66e6c016607 100644 --- a/ansible/roles/vm_set/tasks/main.yml +++ b/ansible/roles/vm_set/tasks/main.yml @@ -162,8 +162,8 @@ - name: veos VMs not needed when setting up Kubernetes master set_fact: - veos_vm_required: false - when: + veos_vm_required: false + when: - k8s is defined - name: VMs not needed in case of Keysight API Server @@ -191,7 +191,7 @@ uri=qemu:///system state=pause register: vm_list_paused - become: true + become: true - block: - name: Ensure {{ root_path }} exists @@ -260,24 +260,8 @@ include_tasks: start_k8s.yml when: action == 'start_k8s' -- block: - - name: Start SONiC VM - include_tasks: start_sonic_vm.yml - when: action == 'start_sonic_vm' and hostvars[dut_name]['type'] == 'kvm' - - - name: Stop SONiC VM - include_tasks: stop_sonic_vm.yml - when: action == 'stop_sonic_vm' and hostvars[dut_name]['type'] == 'kvm' - - - name: Start SID - include_tasks: start_sid.yml - when: action == 'start_sid' and hostvars[dut_name]['type'] == 'simx' - - - name: Stop SID - include_tasks: stop_sid.yml - when: action == 'stop_sid' and hostvars[dut_name]['type'] == 'simx' - when: - - dut_name is defined - - dut_name.split(',')|length == 1 - - hostvars[dut_name] is defined - - hostvars[dut_name].type is defined +- name: Manage the dut state + include_tasks: manage_duts.yml + loop: "{{ duts_name.split(',') }}" + loop_control: + loop_var: dut_name diff --git a/ansible/roles/vm_set/tasks/manage_duts.yml b/ansible/roles/vm_set/tasks/manage_duts.yml new file mode 100644 index 00000000000..9457c4ca2c1 --- /dev/null +++ b/ansible/roles/vm_set/tasks/manage_duts.yml @@ -0,0 +1,19 @@ +- block: + - name: Start SONiC VM + include_tasks: start_sonic_vm.yml + when: action == 'start_sonic_vm' and hostvars[dut_name]['type'] == 'kvm' + + - name: Stop SONiC VM + include_tasks: stop_sonic_vm.yml + when: action == 'stop_sonic_vm' and hostvars[dut_name]['type'] == 'kvm' + + - name: Start SID + include_tasks: start_sid.yml + when: action == 'start_sid' and hostvars[dut_name]['type'] == 'simx' + + - name: Stop SID + include_tasks: stop_sid.yml + when: action == 'stop_sid' and hostvars[dut_name]['type'] == 'simx' + when: + - hostvars[dut_name] is defined + - hostvars[dut_name].type is defined diff --git a/ansible/roles/vm_set/tasks/remove_dut_port.yml b/ansible/roles/vm_set/tasks/remove_dut_port.yml new file mode 100644 index 00000000000..c9f9a67a6c4 --- /dev/null +++ b/ansible/roles/vm_set/tasks/remove_dut_port.yml @@ -0,0 +1,8 @@ +- name: Remove vlan port for vlan tunnel + vlan_port: + external_port: "{{ external_port }}" + vlan_ids: "{{ device_vlan_map_list[dut_name] }}" + cmd: "create" + become: yes + + diff --git a/ansible/roles/vm_set/tasks/remove_topo.yml b/ansible/roles/vm_set/tasks/remove_topo.yml index 9c081b7b649..4e956187146 100644 --- a/ansible/roles/vm_set/tasks/remove_topo.yml +++ b/ansible/roles/vm_set/tasks/remove_topo.yml @@ -8,8 +8,11 @@ when: ptf_imagename is defined and ptf_imagename == "docker-keysight-api-server" - block: - - name: Set front panel/mgmt port for dut - include_tasks: set_dut_port.yml + - name: Get duts ports + include_tasks: get_dut_port.yml + loop: "{{ duts_name.split(',') }}" + loop_control: + loop_var: dut_name - name: Unbind topology {{ topo }} to VMs. base vm = {{ VM_base }} vm_topology: @@ -18,23 +21,21 @@ topo: "{{ topology }}" vm_names: "{{ VM_hosts }}" vm_base: "{{ VM_base }}" - dut_fp_ports: "{{ dut_fp_ports }}" - dut_mgmt_port: "{{ dut_mgmt_port }}" + duts_fp_ports: "{{ duts_fp_ports }}" + duts_mgmt_port: "{{ duts_mgmt_port }}" + duts_name: "{{ duts_name.split(',') }}" max_fp_num: "{{ max_fp_num }}" - is_multi_duts: "{{ dut_name is defined and dut_name.split(',')|length > 1 }}" become: yes - include_tasks: remove_ceos_list.yml when: vm_type is defined and vm_type == "ceos" - - name: Remove vlan port for vlan tunnel - vlan_port: - external_port: "{{ external_port }}" - vlan_ids: "{{ device_vlan_list }}" - is_multi_duts: "{{ dut_name is defined and dut_name.split(',')|length > 1 }}" - cmd: "remove" - become: yes + - name: Remove duts ports + include_tasks: remove_dut_port.yml when: external_port is defined + loop: "{{ duts_name.split(',') }}" + loop_control: + loop_var: dut_name - name: Remove ptf docker container ptf_{{ vm_set_name }} docker_container: @@ -45,7 +46,7 @@ when: container_type == "PTF" -- block: +- block: - name: Remove Keysight API Server container docker_container: name: apiserver diff --git a/ansible/roles/vm_set/tasks/renumber_topo.yml b/ansible/roles/vm_set/tasks/renumber_topo.yml index 018ee0143f6..a2d61465686 100644 --- a/ansible/roles/vm_set/tasks/renumber_topo.yml +++ b/ansible/roles/vm_set/tasks/renumber_topo.yml @@ -19,7 +19,7 @@ become: yes - name: Set front panel/mgmt port for dut - include_tasks: set_dut_port.yml + include_tasks: get_dut_port.yml - name: Renumber topology {{ topo }} to VMs. base vm = {{ VM_base }} vm_topology: diff --git a/ansible/templates/minigraph_cpg.j2 b/ansible/templates/minigraph_cpg.j2 index 574fa3bf558..7a16d667869 100644 --- a/ansible/templates/minigraph_cpg.j2 +++ b/ansible/templates/minigraph_cpg.j2 @@ -3,24 +3,24 @@ {% for index in range(vms_number) %} {% set vm=vms[index] %} -{% if vm_topo_config['vm'][vm]['peer_ipv4'] %} +{% if vm_topo_config['vm'][vm]['peer_ipv4'][dut_index|int] %} false {{ inventory_hostname }} - {{ vm_topo_config['vm'][vm]['bgp_ipv4'] }} + {{ vm_topo_config['vm'][vm]['bgp_ipv4'][dut_index|int] }} {{ vm }} - {{ vm_topo_config['vm'][vm]['peer_ipv4'] }} + {{ vm_topo_config['vm'][vm]['peer_ipv4'][dut_index|int] }} 1 10 3 {% endif %} -{% if vm_topo_config['vm'][vm]['peer_ipv6'] %} +{% if vm_topo_config['vm'][vm]['peer_ipv6'][dut_index|int] %} {{ inventory_hostname }} - {{ vm_topo_config['vm'][vm]['bgp_ipv6'] }} + {{ vm_topo_config['vm'][vm]['bgp_ipv6'][dut_index|int] }} {{ vm }} - {{ vm_topo_config['vm'][vm]['peer_ipv6'] }} + {{ vm_topo_config['vm'][vm]['peer_ipv6'][dut_index|int] }} 1 10 3 @@ -35,7 +35,7 @@ {% for index in range(vms_number) %} -
{{ vm_topo_config['vm'][vms[index]]['peer_ipv4'] }}
+
{{ vm_topo_config['vm'][vms[index]]['peer_ipv4'][dut_index|int] }}
@@ -44,7 +44,7 @@ {% if 'tor' in vm_topo_config['dut_type'] | lower %} BGPPeer -
10.1.0.32
+
{{ lp_ipv4_addr }}
@@ -53,7 +53,7 @@
BGPPeer -
10.1.0.32
+
{{ lp_ipv4_addr }}
diff --git a/ansible/templates/minigraph_dpg.j2 b/ansible/templates/minigraph_dpg.j2 index 92d6ea3dd62..6ffc36682d4 100644 --- a/ansible/templates/minigraph_dpg.j2 +++ b/ansible/templates/minigraph_dpg.j2 @@ -6,17 +6,17 @@ HostIP Loopback0 - 10.1.0.32/32 + {{ lp_ipv4 }} - 10.1.0.32/32 + {{ lp_ipv4 }} HostIP1 Loopback0 - FC00:1::32/128 + {{ lp_ipv6 }} - FC00:1::32/128 + {{ lp_ipv6 }} @@ -44,7 +44,7 @@ {{ inventory_hostname }} {% for index in range(vms_number) %} -{% if 'port-channel' in vm_topo_config['vm'][vms[index]]['ip_intf']|lower %} +{% if 'port-channel' in vm_topo_config['vm'][vms[index]]['ip_intf'][dut_index|int]|lower %} {% set port_channel_intf=';'.join(intf_names[vms[index]]) %} PortChannel{{ ((index+1)|string).zfill(4) }} @@ -80,18 +80,18 @@ {% if 'port-channel' in vm_topo_config['vm'][vms[index]]['ip_intf']|lower %} PortChannel{{ ((index+1) |string).zfill(4) }} {% else %} - {{ port_alias[vm_topo_config['vm'][vms[index]]['interface_indexes'][0]] }} + {{ port_alias[vm_topo_config['vm'][vms[index]]['interface_indexes'][dut_index|int][0]] }} {% endif %} - {{ vm_topo_config['vm'][vms[index]]['bgp_ipv4'] }}/{{ vm_topo_config['vm'][vms[index]]['ipv4mask'] }} + {{ vm_topo_config['vm'][vms[index]]['bgp_ipv4'][dut_index|int] }}/{{ vm_topo_config['vm'][vms[index]]['ipv4mask'][dut_index|int] }} {% if 'port-channel' in (vm_topo_config['vm'][vms[index]]['ip_intf']|lower) %} PortChannel{{ ((index+1) |string).zfill(4) }} {% else %} - {{ port_alias[vm_topo_config['vm'][vms[index]]['interface_indexes'][0]] }} + {{ port_alias[vm_topo_config['vm'][vms[index]]['interface_indexes'][dut_index|int][0]] }} {% endif %} - {{ vm_topo_config['vm'][vms[index]]['bgp_ipv6'] }}/{{ vm_topo_config['vm'][vms[index]]['ipv6mask'] }} + {{ vm_topo_config['vm'][vms[index]]['bgp_ipv6'][dut_index|int] }}/{{ vm_topo_config['vm'][vms[index]]['ipv6mask'][dut_index|int] }} {% endfor %} {% if 'tor' in vm_topo_config['dut_type'] | lower %} @@ -139,13 +139,13 @@ {%- for index in range(vms_number) %} -{% if 'port-channel' in vm_topo_config['vm'][vms[index]]['ip_intf']|lower %} +{% if 'port-channel' in vm_topo_config['vm'][vms[index]]['ip_intf'][dut_index|int]|lower %} PortChannel{{ ((index+1) |string).zfill(4) }}{% if not loop.last %};{% endif %} {% endif %} {% endfor %} {% for index in range(vms_number) %} {% if 'port-channel' not in vm_topo_config['vm'][vms[index]]['ip_intf']|lower %} -{{ port_alias[vm_topo_config['vm'][vms[index]]['interface_indexes'][0]] }}{% if not loop.last %};{% endif %} +{{ port_alias[vm_topo_config['vm'][vms[index]]['interface_indexes'][dut_index|int][0]] }}{% if not loop.last %};{% endif %} {% endif %} {% endfor -%} diff --git a/ansible/templates/minigraph_png.j2 b/ansible/templates/minigraph_png.j2 index ca59de7ff1b..81d24929629 100644 --- a/ansible/templates/minigraph_png.j2 +++ b/ansible/templates/minigraph_png.j2 @@ -1,8 +1,8 @@ {% for index in range(vms_number) %} -{% set vm_intfs=vm_topo_config['vm'][vms[index]]['intfs']|sort %} -{% set dut_intfs=vm_topo_config['vm'][vms[index]]['interface_indexes']|sort %} +{% set vm_intfs=vm_topo_config['vm'][vms[index]]['intfs'][dut_index|int]|sort %} +{% set dut_intfs=vm_topo_config['vm'][vms[index]]['interface_indexes'][dut_index|int]|sort %} {% for if_index in range(vm_intfs | length) %} DeviceInterfaceLink @@ -13,7 +13,7 @@ {% endfor %} {% endfor %} -{% if vm_topo_config['host_interfaces'] | length > 0 %} +{% if vm_topo_config['host_interfaces_by_dut'][dut_index|int] | length > 0 %} {% for host_index in range(vlan_intfs | length) %} DeviceInterfaceLink diff --git a/ansible/templates/minigraph_template.j2 b/ansible/templates/minigraph_template.j2 index 9cbe62ad202..6adb606dd4e 100644 --- a/ansible/templates/minigraph_template.j2 +++ b/ansible/templates/minigraph_template.j2 @@ -1,6 +1,17 @@ {% set vms=vm_topo_config['vm'].keys() | sort %} {% set vms_number = vms | length %} +{% if 'loopback' in vm_topo_config['DUT'] %} +{% set lp_ipv4 = vm_topo_config['DUT']['loopback']['ipv4'][dut_index|int] %} +{% set lp_ipv4_addr = lp_ipv4.split('/')[0] %} +{% set lp_ipv6 = vm_topo_config['DUT']['loopback']['ipv6'][dut_index|int] %} +{% set lp_ipv6_addr = lp_ipv6.split('/')[0] %} +{% else %} +{% set lp_ipv4 = '10.1.0.32/32' %} +{% set lp_ipv4_addr = '10.1.0.32' %} +{% set lp_ipv6 = 'FC00:1::32/128' %} +{% set lp_ipv6_addr = 'FC00:1::32' %} +{% endif %} {% include 'minigraph_cpg.j2' %} {% include 'minigraph_dpg.j2' %} {% include 'minigraph_png.j2' %} diff --git a/ansible/testbed-cli.sh b/ansible/testbed-cli.sh index d7ac633a7ea..2271b3d8cde 100755 --- a/ansible/testbed-cli.sh +++ b/ansible/testbed-cli.sh @@ -13,8 +13,8 @@ function usage echo " $0 [options] (connect-vms | disconnect-vms) " echo " $0 [options] config-vm " echo " $0 [options] (gen-mg | deploy-mg | test-mg) " - echo " $0 [options] (create-master | destroy-master) " - echo + echo " $0 [options] (create-master | destroy-master) " + echo echo "Options:" echo " -t : testbed CSV file name (default: 'testbed.csv')" echo " -m : virtual machine file name (default: 'veos')" @@ -159,7 +159,9 @@ function add_topo read_file ${topology} - ANSIBLE_SCP_IF_SSH=y ansible-playbook -i $vmfile testbed_add_vm_topology.yml --vault-password-file="${passwd}" -l "$server" -e topo_name="$topo_name" -e dut_name="$duts" -e VM_base="$vm_base" -e ptf_ip="$ptf_ip" -e topo="$topo" -e vm_set_name="$testbed_name" -e ptf_imagename="$ptf_imagename" -e vm_type="$vm_type" -e ptf_ipv6="$ptf_ipv6" $@ + echo "$dut" "$duts" + + ANSIBLE_SCP_IF_SSH=y ansible-playbook -i $vmfile testbed_add_vm_topology.yml --vault-password-file="${passwd}" -l "$server" -e topo_name="$topo_name" -e duts_name="$duts" -e VM_base="$vm_base" -e ptf_ip="$ptf_ip" -e topo="$topo" -e vm_set_name="$testbed_name" -e ptf_imagename="$ptf_imagename" -e vm_type="$vm_type" -e ptf_ipv6="$ptf_ipv6" $@ ansible-playbook fanout_connect.yml -i $vmfile --limit "$server" --vault-password-file="${passwd}" -e "dut=$duts" $@ @@ -179,7 +181,7 @@ function remove_topo read_file ${topology} - ANSIBLE_SCP_IF_SSH=y ansible-playbook -i $vmfile testbed_remove_vm_topology.yml --vault-password-file="${passwd}" -l "$server" -e topo_name="$topo_name" -e dut_name="$duts" -e VM_base="$vm_base" -e ptf_ip="$ptf_ip" -e topo="$topo" -e vm_set_name="$testbed_name" -e ptf_imagename="$ptf_imagename" -e vm_type="$vm_type" -e ptf_ipv6="$ptf_ipv6" $@ + ANSIBLE_SCP_IF_SSH=y ansible-playbook -i $vmfile testbed_remove_vm_topology.yml --vault-password-file="${passwd}" -l "$server" -e topo_name="$topo_name" -e duts_name="$duts" -e VM_base="$vm_base" -e ptf_ip="$ptf_ip" -e topo="$topo" -e vm_set_name="$testbed_name" -e ptf_imagename="$ptf_imagename" -e vm_type="$vm_type" -e ptf_ipv6="$ptf_ipv6" $@ echo Done } @@ -197,7 +199,7 @@ function connect_topo ANSIBLE_SCP_IF_SSH=y ansible-playbook -i $vmfile testbed_connect_topo.yml \ --vault-password-file="${passwd}" --limit "$server" \ - -e topo_name="$topo_name" -e dut_name="$duts" \ + -e topo_name="$topo_name" -e duts_name="$duts" \ -e VM_base="$vm_base" -e ptf_ip="$ptf_ip" \ -e topo="$topo" -e vm_set_name="$testbed_name" \ -e ptf_imagename="$ptf_imagename" -e vm_type="$vm_type" -e ptf_ipv6="$ptf_ipv6" $@ @@ -217,7 +219,7 @@ function renumber_topo read_file ${topology} - ANSIBLE_SCP_IF_SSH=y ansible-playbook -i $vmfile testbed_renumber_vm_topology.yml --vault-password-file="${passwd}" -l "$server" -e topo_name="$topo_name" -e dut_name="$duts" -e VM_base="$vm_base" -e ptf_ip="$ptf_ip" -e topo="$topo" -e vm_set_name="$testbed_name" -e ptf_imagename="$ptf_imagename" -e ptf_ipv6="$ptf_ipv6"$@ + ANSIBLE_SCP_IF_SSH=y ansible-playbook -i $vmfile testbed_renumber_vm_topology.yml --vault-password-file="${passwd}" -l "$server" -e topo_name="$topo_name" -e duts_name="$duts" -e VM_base="$vm_base" -e ptf_ip="$ptf_ip" -e topo="$topo" -e vm_set_name="$testbed_name" -e ptf_imagename="$ptf_imagename" -e ptf_ipv6="$ptf_ipv6"$@ ansible-playbook fanout_connect.yml -i $vmfile --limit "$server" --vault-password-file="${passwd}" -e "dut=$duts" $@ @@ -234,7 +236,7 @@ function refresh_dut read_file ${topology} - ANSIBLE_SCP_IF_SSH=y ansible-playbook -i $vmfile testbed_refresh_dut.yml --vault-password-file="${passwd}" -l "$server" -e topo_name="$topo_name" -e dut_name="$duts" -e VM_base="$vm_base" -e ptf_ip="$ptf_ip" -e topo="$topo" -e vm_set_name="$testbed_name" -e ptf_imagename="$ptf_imagename" -e ptf_ipv6="$ptf_ipv6" $@ + ANSIBLE_SCP_IF_SSH=y ansible-playbook -vvv -i $vmfile testbed_refresh_dut.yml --vault-password-file="${passwd}" -l "$server" -e topo_name="$topo_name" -e duts_name="$duts" -e VM_base="$vm_base" -e ptf_ip="$ptf_ip" -e topo="$topo" -e vm_set_name="$testbed_name" -e ptf_imagename="$ptf_imagename" -e ptf_ipv6="$ptf_ipv6" $@ echo Done } @@ -245,7 +247,7 @@ function connect_vms read_file $1 - ANSIBLE_SCP_IF_SSH=y ansible-playbook -i $vmfile testbed_connect_vms.yml --vault-password-file="$2" -l "$server" -e topo_name="$topo_name" -e dut_name="$duts" -e VM_base="$vm_base" -e topo="$topo" -e vm_set_name="$testbed_name" + ANSIBLE_SCP_IF_SSH=y ansible-playbook -i $vmfile testbed_connect_vms.yml --vault-password-file="$2" -l "$server" -e topo_name="$topo_name" -e duts_name="$duts" -e VM_base="$vm_base" -e topo="$topo" -e vm_set_name="$testbed_name" echo Done } @@ -256,7 +258,7 @@ function disconnect_vms read_file $1 - ANSIBLE_SCP_IF_SSH=y ansible-playbook -i $vmfile testbed_disconnect_vms.yml --vault-password-file="$2" -l "$server" -e topo_name="$topo_name" -e dut_name="$duts" -e VM_base="$vm_base" -e topo="$topo" -e vm_set_name="$testbed_name" + ANSIBLE_SCP_IF_SSH=y ansible-playbook -i $vmfile testbed_disconnect_vms.yml --vault-password-file="$2" -l "$server" -e topo_name="$topo_name" -e duts_name="$duts" -e VM_base="$vm_base" -e topo="$topo" -e vm_set_name="$testbed_name" echo Done } @@ -346,7 +348,7 @@ function setup_k8s_vms passwd=$2 echo "Setting up Kubernetes VMs on server '${server}'" - + ANSIBLE_SCP_IF_SSH=y ansible-playbook -i $vmfile testbed_setup_k8s_master.yml -e servernumber="${servernumber}" -e k8s="true" -e msetnumber="${msetnumber}" } @@ -357,7 +359,7 @@ function stop_k8s_vms passwd=$2 shift shift - + echo "Stopping Kubernetes VMs on server '${server}'" ANSIBLE_SCP_IF_SSH=y ansible-playbook -i $vmfile testbed_stop_k8s_VMs.yml --vault-password-file="${passwd}" -l "${server}" -e k8s="true" $@ @@ -435,7 +437,7 @@ case "${subcmd}" in setup_k8s_vms $@ ;; destroy-master) stop_k8s_vms $@ - ;; + ;; *) usage ;; esac diff --git a/ansible/testbed_add_vm_topology.yml b/ansible/testbed_add_vm_topology.yml index 7893ec5d451..23dc985f932 100644 --- a/ansible/testbed_add_vm_topology.yml +++ b/ansible/testbed_add_vm_topology.yml @@ -21,7 +21,7 @@ # Parameters # -l server_3 - this playbook have to be limited to run only on one server # -e vm_set_name=first - the name of vm_set -# -e dut_name=str-msn2700-01 - the name of target dut +# -e duts_name=str-msn2700-01 - the name of target duts # -e VM_base=VM0300 - the VM name which is used to as base to calculate VM name for this set # -e ptf_ip=10.255.0.255/23 - the ip address and prefix of ptf container mgmt interface # -e ptf_ipv6=fec0::ffff:afa:1/64 - the ipv6 address and prefix of ptf container mgmt interface @@ -42,9 +42,9 @@ fail: msg="Define vm_set_name variable with -e vm_set_name=something" when: vm_set_name is not defined - - name: Check that variable dut_name is defined - fail: msg="Define dut_name variable with -e dut_name=something" - when: dut_name is not defined + - name: Check that variable duts_name is defined + fail: msg="Define duts_name variable with -e duts_name=something" + when: duts_name is not defined - name: Check that variable VM_base is defined fail: msg="Define VM_base variable with -e VM_base=something" @@ -73,17 +73,17 @@ - name: Load topo variables include_vars: "vars/topo_{{ topo }}.yml" - - name: Read dut minigraph + - name: Read duts minigraph conn_graph_facts: - host: "{{ dut_name }}" + host: "{{ duts_name }}" delegate_to: localhost - when: dut_name.split(',')|length == 1 + when: duts_name.split(',')|length == 1 - name: Read duts minigraph conn_graph_facts: - hosts: "{{ dut_name.split(',') }}" + hosts: "{{ duts_name.split(',') }}" delegate_to: localhost - when: dut_name.split(',')|length > 1 + when: duts_name.split(',')|length > 1 roles: - { role: vm_set, action: 'start_sonic_vm' } diff --git a/ansible/testbed_connect_topo.yml b/ansible/testbed_connect_topo.yml index 898017aa0eb..727ff5f986b 100644 --- a/ansible/testbed_connect_topo.yml +++ b/ansible/testbed_connect_topo.yml @@ -11,9 +11,9 @@ fail: msg="Define vm_set_name variable with -e vm_set_name=something" when: vm_set_name is not defined - - name: Check that variable dut_name is defined - fail: msg="Define dut_name variable with -e dut_name=something" - when: dut_name is not defined + - name: Check that variable duts_name is defined + fail: msg="Define duts_name variable with -e duts_name=something" + when: duts_name is not defined - name: Check that variable VM_base is defined fail: msg="Define VM_base variable with -e VM_base=something" @@ -44,15 +44,15 @@ - name: Read dut minigraph conn_graph_facts: - host: "{{ dut_name }}" + host: "{{ duts_name }}" delegate_to: localhost - when: dut_name.split(',')|length == 1 + when: duts_name.split(',')|length == 1 - name: Read duts minigraph conn_graph_facts: - hosts: "{{ dut_name.split(',') }}" + hosts: "{{ duts_name.split(',') }}" delegate_to: localhost - when: dut_name.split(',')|length > 1 + when: duts_name.split(',')|length > 1 roles: - { role: vm_set, action: 'add_topo', when external_port is not defined } diff --git a/ansible/testbed_connect_vms.yml b/ansible/testbed_connect_vms.yml index b5aae29394d..e88f7bf22dd 100644 --- a/ansible/testbed_connect_vms.yml +++ b/ansible/testbed_connect_vms.yml @@ -2,12 +2,12 @@ # # # To renumber a topology please use following command -# ANSIBLE_SCP_IF_SSH=y ansible-playbook -i veos testbed_connect_vms.yml --vault-password-file=~/.password -l server_3 -e vm_set_name=first -e VM_base=VM0300 -e ptf_ip=10.255.0.255/23 -e topo=t0 -e dut_name=str-msn-2700-05 -e ptf_imagename="docker_ptf" +# ANSIBLE_SCP_IF_SSH=y ansible-playbook -i veos testbed_connect_vms.yml --vault-password-file=~/.password -l server_3 -e vm_set_name=first -e VM_base=VM0300 -e ptf_ip=10.255.0.255/23 -e topo=t0 -e duts_name=str-msn-2700-05 -e ptf_imagename="docker_ptf" # # Parameters # -l server_3 - this playbook have to be limited to run only on one server # -e vm_set_name=first - the name of vm_set -# -e dut_name=str-msn2700-02 - the new value of a dut name, the dut will be connected to the current testbed +# -e duts_name=str-msn2700-02 - the new value of a dut name, the dut will be connected to the current testbed # -e VM_base=VM0300 - the VM name which is used to as base to calculate VM name for this set # -e ptf_ip=10.255.0.255/23 - the ip address and prefix of ptf container mgmt interface # -e topo=t0 - the name of removed topo @@ -26,9 +26,9 @@ fail: msg="Define vm_set_name variable with -e vm_set_name=something" when: vm_set_name is not defined - - name: Check that variable dut_name is defined - fail: msg="Define dut_name variable with -e dut_name=something" - when: dut_name is not defined + - name: Check that variable duts_name is defined + fail: msg="Define duts_name variable with -e duts_name=something" + when: duts_name is not defined - name: Check that variable VM_base is defined fail: msg="Define VM_base variable with -e VM_base=something" @@ -42,8 +42,16 @@ include_vars: "vars/topo_{{ topo }}.yml" - name: Read dut minigraph - conn_graph_facts: host={{ dut_name }} + conn_graph_facts: + host: "{{ duts_name }}" delegate_to: localhost + when: duts_name.split(',')|length == 1 + + - name: Read duts minigraph + conn_graph_facts: + hosts: "{{ duts_name.split(',') }}" + delegate_to: localhost + when: duts_name.split(',')|length > 1 roles: - { role: vm_set, action: 'connect_vms' } diff --git a/ansible/testbed_disconnect_vms.yml b/ansible/testbed_disconnect_vms.yml index a75593a4ea8..55d4fb5fdf4 100644 --- a/ansible/testbed_disconnect_vms.yml +++ b/ansible/testbed_disconnect_vms.yml @@ -2,12 +2,12 @@ # # # To renumber a topology please use following command -# ANSIBLE_SCP_IF_SSH=y ansible-playbook -i veos testbed_disconnect_vms.yml --vault-password-file=~/.password -l server_3 -e vm_set_name=first -e VM_base=VM0300 -e ptf_ip=10.255.0.255/23 -e topo=t0 -e dut_name=str-msn-2700-05 -e ptf_imagename="docker_ptf" +# ANSIBLE_SCP_IF_SSH=y ansible-playbook -i veos testbed_disconnect_vms.yml --vault-password-file=~/.password -l server_3 -e vm_set_name=first -e VM_base=VM0300 -e ptf_ip=10.255.0.255/23 -e topo=t0 -e duts_name=str-msn-2700-05 -e ptf_imagename="docker_ptf" # # Parameters # -l server_3 - this playbook have to be limited to run only on one server # -e vm_set_name=first - the name of vm_set -# -e dut_name=str-msn2700-02 - the new value of a dut name, the dut will be connected to the current testbed +# -e duts_name=str-msn2700-02 - the new value of a dut name, the dut will be connected to the current testbed # -e VM_base=VM0300 - the VM name which is used to as base to calculate VM name for this set # -e ptf_ip=10.255.0.255/23 - the ip address and prefix of ptf container mgmt interface # -e topo=t0 - the name of removed topo @@ -26,9 +26,9 @@ fail: msg="Define vm_set_name variable with -e vm_set_name=something" when: vm_set_name is not defined - - name: Check that variable dut_name is defined - fail: msg="Define dut_name variable with -e dut_name=something" - when: dut_name is not defined + - name: Check that variable duts_name is defined + fail: msg="Define duts_name variable with -e duts_name=something" + when: duts_name is not defined - name: Check that variable VM_base is defined fail: msg="Define VM_base variable with -e VM_base=something" @@ -42,8 +42,16 @@ include_vars: "vars/topo_{{ topo }}.yml" - name: Read dut minigraph - conn_graph_facts: host={{ dut_name }} + conn_graph_facts: + host: "{{ duts_name }}" delegate_to: localhost + when: duts_name.split(',')|length == 1 + + - name: Read duts minigraph + conn_graph_facts: + hosts: "{{ duts_name.split(',') }}" + delegate_to: localhost + when: duts_name.split(',')|length > 1 roles: - { role: vm_set, action: 'disconnect_vms' } diff --git a/ansible/testbed_refresh_dut.yml b/ansible/testbed_refresh_dut.yml index 1ad3638e43a..36bda351671 100644 --- a/ansible/testbed_refresh_dut.yml +++ b/ansible/testbed_refresh_dut.yml @@ -16,12 +16,12 @@ # Every topology contains a ptf container which will be used as placeholder for the injected interfaces from VMs, or direct connections to PTF host # # To add a topology please use following command -# ANSIBLE_SCP_IF_SSH=y ansible-playbook -i veos testbed_add_vm_topology.yml --vault-password-file=~/.password -l server_3 -e vm_set_name=first -e dut_name=str-msn2700-01 -e VM_base=VM0300 -e ptf_ip=10.255.0.255/23 -e topo=t0 -e ptf_imagename="docker_ptf" +# ANSIBLE_SCP_IF_SSH=y ansible-playbook -i veos testbed_add_vm_topology.yml --vault-password-file=~/.password -l server_3 -e vm_set_name=first -e duts_name=str-msn2700-01 -e VM_base=VM0300 -e ptf_ip=10.255.0.255/23 -e topo=t0 -e ptf_imagename="docker_ptf" # # Parameters # -l server_3 - this playbook have to be limited to run only on one server # -e vm_set_name=first - the name of vm_set -# -e dut_name=str-msn2700-01 - the name of target dut +# -e duts_name=str-msn2700-01 - the name of target dut # -e VM_base=VM0300 - the VM name which is used to as base to calculate VM name for this set # -e ptf_ip=10.255.0.255/23 - the ip address and prefix of ptf container mgmt interface # -e ptf_ipv6=fec0::ffff:afa:1/64 - the ipv6 address and prefix of ptf container mgmt interface @@ -41,9 +41,9 @@ fail: msg="Define vm_set_name variable with -e vm_set_name=something" when: vm_set_name is not defined - - name: Check that variable dut_name is defined - fail: msg="Define dut_name variable with -e dut_name=something" - when: dut_name is not defined + - name: Check that variable duts_name is defined + fail: msg="Define duts_name variable with -e duts_name=something" + when: duts_name is not defined - name: Check that variable VM_base is defined fail: msg="Define VM_base variable with -e VM_base=something" @@ -73,8 +73,16 @@ include_vars: "vars/topo_{{ topo }}.yml" - name: Read dut minigraph - conn_graph_facts: host={{ dut_name }} + conn_graph_facts: + host: "{{ duts_name }}" delegate_to: localhost + when: duts_name.split(',')|length == 1 + + - name: Read duts minigraph + conn_graph_facts: + hosts: "{{ duts_name.split(',') }}" + delegate_to: localhost + when: duts_name.split(',')|length > 1 roles: - { role: vm_set, action: 'stop_sonic_vm' } diff --git a/ansible/testbed_remove_vm_topology.yml b/ansible/testbed_remove_vm_topology.yml index 4f9f9c67f2a..4f2891441eb 100644 --- a/ansible/testbed_remove_vm_topology.yml +++ b/ansible/testbed_remove_vm_topology.yml @@ -3,12 +3,12 @@ # For additional details see playbook testbed_add_vm_topology.yml # # To remove a topology please use following command -# ANSIBLE_SCP_IF_SSH=y ansible-playbook -i veos testbed_remove_vm_topology.yml --vault-password-file=~/.password -l server_3 -e vm_set_name=first -e -e dut_name=str-msn2700-01 -e VM_base=VM0300 -e ptf_ip=10.255.0.255/23 -e topo=t0 -e ptf_imagename="docker_ptf" +# ANSIBLE_SCP_IF_SSH=y ansible-playbook -i veos testbed_remove_vm_topology.yml --vault-password-file=~/.password -l server_3 -e vm_set_name=first -e -e duts_name=str-msn2700-01 -e VM_base=VM0300 -e ptf_ip=10.255.0.255/23 -e topo=t0 -e ptf_imagename="docker_ptf" # # Parameters # -l server_3 - this playbook have to be limited to run only on one server # -e vm_set_name=first - the name of vm_set -# -e dut_name=str-msn2700-01 - the name of target dut +# -e duts_name=str-msn2700-01 - the name of target dut # -e VM_base=VM0300 - the VM name which is used to as base to calculate VM name for this set # -e ptf_ip=10.255.0.255/23 - the ip address and prefix of ptf container mgmt interface # -e topo=t0 - the name of removed topo @@ -27,9 +27,9 @@ fail: msg="Define vm_set_name variable with -e vm_set_name=something" when: vm_set_name is not defined - - name: Check that variable dut_name is defined - fail: msg="Define dut_name variable with -e dut_name=something" - when: dut_name is not defined + - name: Check that variable duts_name is defined + fail: msg="Define duts_name variable with -e duts_name=something" + when: duts_name is not defined - name: Check that variable VM_base is defined fail: msg="Define VM_base variable with -e VM_base=something" @@ -52,15 +52,15 @@ - name: Read dut minigraph conn_graph_facts: - host: "{{ dut_name }}" + host: "{{ duts_name }}" delegate_to: localhost - when: dut_name.split(',')|length == 1 + when: duts_name.split(',')|length == 1 - name: Read duts minigraph conn_graph_facts: - hosts: "{{ dut_name.split(',') }}" + hosts: "{{ duts_name.split(',') }}" delegate_to: localhost - when: dut_name.split(',')|length > 1 + when: duts_name.split(',')|length > 1 roles: - { role: vm_set, action: 'remove_topo' } diff --git a/ansible/testbed_renumber_vm_topology.yml b/ansible/testbed_renumber_vm_topology.yml index 5179a855f59..75b230bcd48 100644 --- a/ansible/testbed_renumber_vm_topology.yml +++ b/ansible/testbed_renumber_vm_topology.yml @@ -2,12 +2,12 @@ # # # To renumber a topology please use following command -# ANSIBLE_SCP_IF_SSH=y ansible-playbook -i veos testbed_renumber_vm_topology.yml --vault-password-file=~/.password -l server_3 -e vm_set_name=first -e VM_base=VM0300 -e ptf_ip=10.255.0.255/23 -e topo=t0 -e dut_name=str-msn-2700-05 -e ptf_imagename="docker_ptf" +# ANSIBLE_SCP_IF_SSH=y ansible-playbook -i veos testbed_renumber_vm_topology.yml --vault-password-file=~/.password -l server_3 -e vm_set_name=first -e VM_base=VM0300 -e ptf_ip=10.255.0.255/23 -e topo=t0 -e duts_name=str-msn-2700-05 -e ptf_imagename="docker_ptf" # # Parameters # -l server_3 - this playbook have to be limited to run only on one server # -e vm_set_name=first - the name of vm_set -# -e dut_name=str-msn2700-02 - the new value of a dut name, the dut will be connected to the current testbed +# -e duts_name=str-msn2700-02 - the new value of a dut name, the dut will be connected to the current testbed # -e VM_base=VM0300 - the VM name which is used to as base to calculate VM name for this set # -e ptf_ip=10.255.0.255/23 - the ip address and prefix of ptf container mgmt interface # -e topo=t0 - the name of removed topo @@ -26,9 +26,9 @@ fail: msg="Define vm_set_name variable with -e vm_set_name=something" when: vm_set_name is not defined - - name: Check that variable dut_name is defined - fail: msg="Define dut_name variable with -e dut_name=something" - when: dut_name is not defined + - name: Check that variable duts_name is defined + fail: msg="Define duts_name variable with -e duts_name=something" + when: duts_name is not defined - name: Check that variable VM_base is defined fail: msg="Define VM_base variable with -e VM_base=something" @@ -54,8 +54,16 @@ include_vars: "vars/topo_{{ topo }}.yml" - name: Read dut minigraph - conn_graph_facts: host={{ dut_name }} + conn_graph_facts: + host: "{{ duts_name }}" delegate_to: localhost + when: duts_name.split(',')|length == 1 + + - name: Read duts minigraph + conn_graph_facts: + hosts: "{{ duts_name.split(',') }}" + delegate_to: localhost + when: duts_name.split(',')|length > 1 roles: - { role: vm_set, action: 'renumber_topo' } diff --git a/ansible/vars/topo_dualtor.yml b/ansible/vars/topo_dualtor.yml new file mode 100644 index 00000000000..e4d86c10794 --- /dev/null +++ b/ansible/vars/topo_dualtor.yml @@ -0,0 +1,220 @@ +topology: + dut_num: 2 + host_interfaces: + - 0.0,1.0 + - 0.1,1.1 + - 0.2,1.2 + - 0.3,1.3 + - 0.4,1.4 + - 0.5,1.5 + - 0.6,1.6 + - 0.7,1.7 + - 0.8,1.8 + - 0.9,1.9 + - 0.10,1.10 + - 0.11,1.11 + - 0.12,1.12 + - 0.13,1.13 + - 0.14,1.14 + - 0.15,1.15 + - 0.16,1.16 + - 0.17,1.17 + - 0.18,1.18 + - 0.19,1.19 + - 0.20,1.20 + - 0.21,1.21 + - 0.22,1.22 + - 0.23,1.23 + - 0.24,1.24 + - 0.25,1.25 + - 0.26,1.26 + - 0.27,1.27 + disabled_host_interfaces: + - 0.0,1.0 + - 0.25,1.25 + - 0.26,1.26 + - 0.27,1.27 + VMs: + ARISTA01T1: + vlans: + - "0.28@28" + - "1.28@29" + vm_offset: 0 + ARISTA02T1: + vlans: + - "0.29@30" + - "1.29@31" + vm_offset: 1 + ARISTA03T1: + vlans: + - "0.30@32" + - "1.30@33" + vm_offset: 2 + ARISTA04T1: + vlans: + - "0.31@34" + - "1.31@35" + vm_offset: 3 + DUT: + loopback: + ipv4: + - 10.1.0.32/32 + - 10.1.0.33/32 + ipv6: + - FC00:1::32/128 + - FC00:1::33/128 + vlan_configs: + default_vlan_config: one_vlan_a + one_vlan_a: + Vlan1000: + id: 1000 + intfs: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24] + prefix: 192.168.0.1/21 + prefix_v6: fc02:1000::1/64 + tag: 1000 + two_vlan_a: + Vlan100: + id: 100 + intfs: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] + prefix: 192.168.100.1/21 + prefix_v6: fc02:100::1/64 + tag: 100 + Vlan200: + id: 200 + intfs: [13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24] + prefix: 192.168.200.1/21 + prefix_v6: fc02:200::1/64 + tag: 200 + +configuration_properties: + common: + dut_asn: 65100 + dut_type: ToRRouter + swrole: leaf + nhipv4: 10.10.246.254 + nhipv6: FC0A::FF + +configuration: + ARISTA01T1: + properties: + - common + bgp: + asn: 64600 + peers: + 65100: + - 10.0.0.56 + - FC00::71 + - 10.0.1.56 + - FC00::1:71 + interfaces: + Loopback0: + ipv4: 100.1.0.29/32 + ipv6: 2064:100::1d/128 + Ethernet1: + lacp: 1 + dut_index: 0 + Ethernet2: + lacp: 2 + dut_index: 1 + Port-Channel1: + ipv4: 10.0.0.57/31 + ipv6: fc00::72/126 + Port-Channel2: + ipv4: 10.0.1.57/31 + ipv6: fc00::1:72/126 + bp_interface: + ipv4: 10.10.246.29/24 + ipv6: fc0a::1d/64 + + ARISTA02T1: + properties: + - common + bgp: + asn: 64600 + peers: + 65100: + - 10.0.0.58 + - FC00::75 + - 10.0.1.58 + - FC00::1:75 + interfaces: + Loopback0: + ipv4: 100.1.0.30/32 + ipv6: 2064:100::1e/128 + Ethernet1: + lacp: 1 + dut_index: 0 + Ethernet2: + lacp: 2 + dut_index: 1 + Port-Channel1: + ipv4: 10.0.0.59/31 + ipv6: fc00::76/126 + Port-Channel2: + ipv4: 10.0.1.59/31 + ipv6: fc00::1:76/126 + bp_interface: + ipv4: 10.10.246.30/24 + ipv6: fc0a::1e/64 + + ARISTA03T1: + properties: + - common + bgp: + asn: 64600 + peers: + 65100: + - 10.0.0.60 + - FC00::79 + - 10.0.1.60 + - FC00::1:79 + interfaces: + Loopback0: + ipv4: 100.1.0.31/32 + ipv6: 2064:100::1f/128 + Ethernet1: + lacp: 1 + dut_index: 0 + Ethernet2: + lacp: 2 + dut_index: 1 + Port-Channel1: + ipv4: 10.0.0.61/31 + ipv6: fc00::7a/126 + Port-Channel2: + ipv4: 10.0.1.61/31 + ipv6: fc00::1:7a/126 + bp_interface: + ipv4: 10.10.246.31/24 + ipv6: fc0a::1f/64 + + ARISTA04T1: + properties: + - common + bgp: + asn: 64600 + peers: + 65100: + - 10.0.0.62 + - FC00::7D + - 10.0.1.62 + - FC00::1:7D + interfaces: + Loopback0: + ipv4: 100.1.0.32/32 + ipv6: 2064:100::20/128 + Ethernet1: + lacp: 1 + dut_index: 0 + Ethernet2: + lacp: 2 + dut_index: 1 + Port-Channel1: + ipv4: 10.0.0.63/31 + ipv6: fc00::7e/126 + Port-Channel2: + ipv4: 10.0.1.63/31 + ipv6: fc00::1:7e/126 + bp_interface: + ipv4: 10.10.246.32/24 + ipv6: fc0a::20/64 diff --git a/ansible/veos_vtb b/ansible/veos_vtb index 9ea109341c2..393f6045348 100644 --- a/ansible/veos_vtb +++ b/ansible/veos_vtb @@ -22,6 +22,7 @@ all: - t0-64 - t0-64-32 - t0-116 + - dualtor children: server_1: lab: @@ -29,6 +30,9 @@ all: vlab-01: vlab-02: vlab-03: + vlab-04: + vlab-05: + vlab-06: sonic: hosts: vlab-01: @@ -63,6 +67,22 @@ all: serial_port: 9002 ansible_password: password ansible_user: admin + vlab-05: + ansible_host: 10.250.0.110 + ansible_hostv6: fec0::ffff:afa:a + type: kvm + hwsku: Force10-S6000 + serial_port: 9003 + ansible_password: password + ansible_user: admin + vlab-06: + ansible_host: 10.250.0.111 + ansible_hostv6: fec0::ffff:afa:b + type: kvm + hwsku: Force10-S6000 + serial_port: 9004 + ansible_password: password + ansible_user: admin vlab-simx-01: ansible_host: 10.250.0.103 ansible_hostv6: fec0::ffff:afa:3 @@ -88,6 +108,11 @@ all: ansible_hostv6: fec0::ffff:afa:8 ansible_user: root ansible_password: root + ptf-04: + ansible_host: 10.250.0.109 + ansible_hostv6: fec0::ffff:afa:9 + ansible_user: root + ansible_password: root # The groups below are helpers to limit running playbooks to a specific server only server_1: diff --git a/ansible/vtestbed.csv b/ansible/vtestbed.csv index a4f578c8eed..48ece8bdf10 100644 --- a/ansible/vtestbed.csv +++ b/ansible/vtestbed.csv @@ -3,3 +3,4 @@ vms-kvm-t0,vms6-1,t0,docker-ptf,ptf-01,10.250.0.102/24,fec0::ffff:afa:2/64,serve vms-kvm-t0-64,vms6-1,t0-64,docker-ptf,ptf-01,10.250.0.102/24,fec0::ffff:afa:2/64,server_1,VM0100,[vlab-02],Tests virtual switch vm vms-kvm-t1-lag,vms6-2,t1-lag,docker-ptf,ptf-02,10.250.0.106/24,fec0::ffff:afa:6/64,server_1,VM0104,[vlab-03],Tests virtual switch vm vms-kvm-t0-2,vms6-3,t0,docker-ptf,ptf-03,10.250.0.108/24,fec0::ffff:afa:8/64,server_1,VM0104,[vlab-04],Tests virtual switch vm +vms-kvm-dual-t0,vms6-4,dualtor,docker-ptf,ptf-04,10.250.0.109/24,fec0::ffff:afa:9/64,server_1,VM0108,[vlab-05;vlab-06],Dual-TOR testbed diff --git a/tests/conftest.py b/tests/conftest.py index 5f0759ab5a0..3b9ce2d5893 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -85,7 +85,7 @@ def __init__(self, testbed_file): self.testbed_topo[line['conf-name']] = line def get_testbed_type(self, topo_name): - pattern = re.compile(r'^(t0|t1|ptf|fullmesh)') + pattern = re.compile(r'^(t0|t1|ptf|fullmesh|dualtor)') match = pattern.match(topo_name) if match == None: raise Exception("Unsupported testbed type - {}".format(topo_name))