diff --git a/ansible/library/announce_routes.py b/ansible/library/announce_routes.py index 3128110b7ea..8704c16b8a4 100644 --- a/ansible/library/announce_routes.py +++ b/ansible/library/announce_routes.py @@ -69,6 +69,10 @@ TOR_ASN_START = 65500 IPV4_BASE_PORT = 5000 IPV6_BASE_PORT = 6000 +AGGREGATE_ROUTES_DEFAULT_VALUE = [] +IPV6_ADDRESS_PATTERN_DEFAULT_VALUE = '20%02X:%02X%02X:0:%02X::/64' +ENABLE_IPV4_ROUTES_GENERATION_DEFAULT_VALUE = True +ENABLE_IPV6_ROUTES_GENERATION_DEFAULT_VALUE = True # Describe default number of COLOs COLO_NUMBER = 30 @@ -332,7 +336,8 @@ def generate_routes(family, podset_number, tor_number, tor_subnet_number, spine_asn, leaf_asn_start, tor_asn_start, nexthop, nexthop_v6, tor_subnet_size, max_tor_subnet_number, topo, router_type="leaf", tor_index=None, set_num=None, - no_default_route=False, core_ra_asn=CORE_RA_ASN): + no_default_route=False, core_ra_asn=CORE_RA_ASN, + ipv6_address_pattern=IPV6_ADDRESS_PATTERN_DEFAULT_VALUE): routes = [] if not no_default_route and router_type != "tor": default_route_as_path = get_uplink_router_as_path( @@ -420,7 +425,7 @@ def generate_routes(family, podset_number, tor_number, tor_subnet_number, prefix = "{}.{}.{}.{}/{}".format(octet1, octet2, octet3, octet4, prefixlen_v4) - prefix_v6 = "20%02X:%02X%02X:0:%02X::/64" % ( + prefix_v6 = ipv6_address_pattern % ( octet1, octet2, octet3, octet4) leaf_asn = leaf_asn_start + podset @@ -465,24 +470,41 @@ def fib_t0(topo, ptf_ip, no_default_route=False, action="announce"): spine_asn = common_config.get("spine_asn", SPINE_ASN) leaf_asn_start = common_config.get("leaf_asn_start", LEAF_ASN_START) tor_asn_start = common_config.get("tor_asn_start", TOR_ASN_START) + ipv6_address_pattern = common_config.get("ipv6_address_pattern", IPV6_ADDRESS_PATTERN_DEFAULT_VALUE) + enable_ipv6_routes_generation = common_config.get("enable_ipv6_routes_generation", + ENABLE_IPV6_ROUTES_GENERATION_DEFAULT_VALUE) + enable_ipv4_routes_generation = common_config.get("enable_ipv4_routes_generation", + ENABLE_IPV4_ROUTES_GENERATION_DEFAULT_VALUE) vms = topo['topology']['VMs'] - for vm in vms.values(): + for vm_name, vm in vms.items(): vm_offset = vm['vm_offset'] port = IPV4_BASE_PORT + vm_offset port6 = IPV6_BASE_PORT + vm_offset + aggregate_prefixes = topo['configuration'][vm_name].get("aggregate_routes", AGGREGATE_ROUTES_DEFAULT_VALUE) + aggregate_routes = [(prefix, nhipv4 if "." in prefix else nhipv6, "") for prefix in aggregate_prefixes] + aggregate_routes_v4 = get_ipv4_routes(aggregate_routes) + aggregate_routes_v6 = get_ipv6_routes(aggregate_routes) - routes_v4 = generate_routes("v4", podset_number, tor_number, tor_subnet_number, - spine_asn, leaf_asn_start, tor_asn_start, - nhipv4, nhipv4, tor_subnet_size, max_tor_subnet_number, "t0", - no_default_route=no_default_route) - routes_v6 = generate_routes("v6", podset_number, tor_number, tor_subnet_number, - spine_asn, leaf_asn_start, tor_asn_start, - nhipv6, nhipv6, tor_subnet_size, max_tor_subnet_number, "t0", - no_default_route=no_default_route) - - change_routes(action, ptf_ip, port, routes_v4) - change_routes(action, ptf_ip, port6, routes_v6) + if enable_ipv4_routes_generation: + routes_v4 = generate_routes("v4", podset_number, tor_number, tor_subnet_number, + spine_asn, leaf_asn_start, tor_asn_start, + nhipv4, nhipv4, tor_subnet_size, max_tor_subnet_number, "t0", + no_default_route=no_default_route) + if aggregate_routes_v4: + filterout_subnet_ipv4(aggregate_routes, routes_v4) + routes_v4.extend(aggregate_routes_v4) + change_routes(action, ptf_ip, port, routes_v4) + if enable_ipv6_routes_generation: + routes_v6 = generate_routes("v6", podset_number, tor_number, tor_subnet_number, + spine_asn, leaf_asn_start, tor_asn_start, + nhipv6, nhipv6, tor_subnet_size, max_tor_subnet_number, "t0", + no_default_route=no_default_route, + ipv6_address_pattern=ipv6_address_pattern) + if aggregate_routes_v6: + filterout_subnet_ipv6(aggregate_routes, routes_v6) + routes_v6.extend(aggregate_routes_v6) + change_routes(action, ptf_ip, port6, routes_v6) def fib_t1_lag(topo, ptf_ip, no_default_route=False, action="announce"): @@ -498,6 +520,11 @@ def fib_t1_lag(topo, ptf_ip, no_default_route=False, action="announce"): nhipv6 = common_config.get("nhipv6", NHIPV6) leaf_asn_start = common_config.get("leaf_asn_start", LEAF_ASN_START) tor_asn_start = common_config.get("tor_asn_start", TOR_ASN_START) + ipv6_address_pattern = common_config.get("ipv6_address_pattern", IPV6_ADDRESS_PATTERN_DEFAULT_VALUE) + enable_ipv6_routes_generation = common_config.get("enable_ipv6_routes_generation", + ENABLE_IPV6_ROUTES_GENERATION_DEFAULT_VALUE) + enable_ipv4_routes_generation = common_config.get("enable_ipv4_routes_generation", + ENABLE_IPV4_ROUTES_GENERATION_DEFAULT_VALUE) vms = topo['topology']['VMs'] vms_config = topo['configuration'] @@ -506,6 +533,10 @@ def fib_t1_lag(topo, ptf_ip, no_default_route=False, action="announce"): vm_offset = vms[k]['vm_offset'] port = IPV4_BASE_PORT + vm_offset port6 = IPV6_BASE_PORT + vm_offset + aggregate_prefixes = v.get("aggregate_routes", AGGREGATE_ROUTES_DEFAULT_VALUE) + aggregate_routes = [(prefix, nhipv4 if "." in prefix else nhipv6, "") for prefix in aggregate_prefixes] + aggregate_routes_v4 = get_ipv4_routes(aggregate_routes) + aggregate_routes_v6 = get_ipv6_routes(aggregate_routes) router_type = None if 'spine' in v['properties']: @@ -515,18 +546,27 @@ def fib_t1_lag(topo, ptf_ip, no_default_route=False, action="announce"): tornum = v.get('tornum', None) tor_index = tornum - 1 if tornum is not None else None if router_type: - routes_v4 = generate_routes("v4", podset_number, tor_number, tor_subnet_number, - None, leaf_asn_start, tor_asn_start, - nhipv4, nhipv6, tor_subnet_size, max_tor_subnet_number, "t1", - router_type=router_type, tor_index=tor_index, - no_default_route=no_default_route) - routes_v6 = generate_routes("v6", podset_number, tor_number, tor_subnet_number, - None, leaf_asn_start, tor_asn_start, - nhipv4, nhipv6, tor_subnet_size, max_tor_subnet_number, "t1", - router_type=router_type, tor_index=tor_index, - no_default_route=no_default_route) - change_routes(action, ptf_ip, port, routes_v4) - change_routes(action, ptf_ip, port6, routes_v6) + if enable_ipv4_routes_generation: + routes_v4 = generate_routes("v4", podset_number, tor_number, tor_subnet_number, + None, leaf_asn_start, tor_asn_start, + nhipv4, nhipv6, tor_subnet_size, max_tor_subnet_number, "t1", + router_type=router_type, tor_index=tor_index, + no_default_route=no_default_route) + if aggregate_routes_v4: + filterout_subnet_ipv4(aggregate_routes, routes_v4) + routes_v4.extend(aggregate_routes_v4) + change_routes(action, ptf_ip, port, routes_v4) + if enable_ipv6_routes_generation: + routes_v6 = generate_routes("v6", podset_number, tor_number, tor_subnet_number, + None, leaf_asn_start, tor_asn_start, + nhipv4, nhipv6, tor_subnet_size, max_tor_subnet_number, "t1", + router_type=router_type, tor_index=tor_index, + no_default_route=no_default_route, + ipv6_address_pattern=ipv6_address_pattern) + if aggregate_routes_v6: + filterout_subnet_ipv6(aggregate_routes, routes_v6) + routes_v6.extend(aggregate_routes_v6) + change_routes(action, ptf_ip, port6, routes_v6) if 'vips' in v: routes_vips = [] @@ -918,6 +958,11 @@ def generate_t2_routes(dut_vm_dict, topo, ptf_ip, action="announce"): leaf_asn_start = common_config.get("leaf_asn_start", LEAF_ASN_START) tor_asn_start = common_config.get("tor_asn_start", TOR_ASN_START) core_ra_asn = common_config.get("core_ra_asn", CORE_RA_ASN) + ipv6_address_pattern = common_config.get("ipv6_address_pattern", IPV6_ADDRESS_PATTERN_DEFAULT_VALUE) + enable_ipv6_routes_generation = common_config.get("enable_ipv6_routes_generation", + ENABLE_IPV6_ROUTES_GENERATION_DEFAULT_VALUE) + enable_ipv4_routes_generation = common_config.get("enable_ipv4_routes_generation", + ENABLE_IPV4_ROUTES_GENERATION_DEFAULT_VALUE) # generate routes for t1 vms for a_dut_index in dut_vm_dict: @@ -937,6 +982,10 @@ def generate_t2_routes(dut_vm_dict, topo, ptf_ip, action="announce"): vm_offset = vms[a_vm]['vm_offset'] port = IPV4_BASE_PORT + vm_offset port6 = IPV6_BASE_PORT + vm_offset + aggregate_prefixes = vms_config[a_vm].get("aggregate_routes", AGGREGATE_ROUTES_DEFAULT_VALUE) + aggregate_routes = [(prefix, nhipv4 if "." in prefix else nhipv6, "") for prefix in aggregate_prefixes] + aggregate_routes_v4 = get_ipv4_routes(aggregate_routes) + aggregate_routes_v6 = get_ipv6_routes(aggregate_routes) router_type = None if 'leaf' in vms_config[a_vm]['properties']: @@ -947,20 +996,28 @@ def generate_t2_routes(dut_vm_dict, topo, ptf_ip, action="announce"): tor_index = None if router_type: - routes_v4 = generate_routes("v4", podset_number, tor_number, tor_subnet_number, - common_config['dut_asn'], leaf_asn_start, tor_asn_start, - nhipv4, nhipv6, tor_subnet_size, max_tor_subnet_number, "t2", - router_type=router_type, tor_index=tor_index, set_num=set_num, - core_ra_asn=core_ra_asn) - routes_v6 = generate_routes("v6", podset_number, tor_number, tor_subnet_number, - common_config['dut_asn'], leaf_asn_start, tor_asn_start, - nhipv4, nhipv6, tor_subnet_size, max_tor_subnet_number, "t2", - router_type=router_type, tor_index=tor_index, set_num=set_num, - core_ra_asn=core_ra_asn) - random.shuffle(routes_v4) - random.shuffle(routes_v6) - r_set.append((routes_v4, port, action, ptf_ip)) - r_set.append((routes_v6, port6, action, ptf_ip)) + if enable_ipv4_routes_generation: + routes_v4 = generate_routes("v4", podset_number, tor_number, tor_subnet_number, + common_config['dut_asn'], leaf_asn_start, tor_asn_start, + nhipv4, nhipv6, tor_subnet_size, max_tor_subnet_number, "t2", + router_type=router_type, tor_index=tor_index, set_num=set_num, + core_ra_asn=core_ra_asn) + if aggregate_routes_v4: + filterout_subnet_ipv4(aggregate_routes, routes_v4) + routes_v4.extend(aggregate_routes_v4) + random.shuffle(routes_v4) + r_set.append((routes_v4, port, action, ptf_ip)) + if enable_ipv6_routes_generation: + routes_v6 = generate_routes("v6", podset_number, tor_number, tor_subnet_number, + common_config['dut_asn'], leaf_asn_start, tor_asn_start, + nhipv4, nhipv6, tor_subnet_size, max_tor_subnet_number, "t2", + router_type=router_type, tor_index=tor_index, set_num=set_num, + core_ra_asn=core_ra_asn, ipv6_address_pattern=ipv6_address_pattern) + if aggregate_routes_v6: + filterout_subnet_ipv6(aggregate_routes, routes_v6) + routes_v6.extend(aggregate_routes_v6) + random.shuffle(routes_v6) + r_set.append((routes_v6, port6, action, ptf_ip)) if 'vips' in vms_config[a_vm]: routes_vips = [] @@ -985,6 +1042,11 @@ def fib_t0_mclag(topo, ptf_ip, action="announce"): spine_asn = common_config.get("spine_asn", SPINE_ASN) leaf_asn_start = common_config.get("leaf_asn_start", LEAF_ASN_START) tor_asn_start = common_config.get("tor_asn_start", TOR_ASN_START) + ipv6_address_pattern = common_config.get("ipv6_address_pattern", IPV6_ADDRESS_PATTERN_DEFAULT_VALUE) + enable_ipv6_routes_generation = common_config.get("enable_ipv6_routes_generation", + ENABLE_IPV6_ROUTES_GENERATION_DEFAULT_VALUE) + enable_ipv4_routes_generation = common_config.get("enable_ipv4_routes_generation", + ENABLE_IPV4_ROUTES_GENERATION_DEFAULT_VALUE) vms = topo['topology']['VMs'] all_vms = sorted(vms.keys()) @@ -998,18 +1060,30 @@ def fib_t0_mclag(topo, ptf_ip, action="announce"): vm_offset = vms[vm]['vm_offset'] port = IPV4_BASE_PORT + vm_offset port6 = IPV6_BASE_PORT + vm_offset + aggregate_prefixes = topo['configuration'][vm].get("aggregate_routes", AGGREGATE_ROUTES_DEFAULT_VALUE) + aggregate_routes = [(prefix, nhipv4 if "." in prefix else nhipv6, "") for prefix in aggregate_prefixes] + aggregate_routes_v4 = get_ipv4_routes(aggregate_routes) + aggregate_routes_v6 = get_ipv6_routes(aggregate_routes) - routes_v4 = generate_routes("v4", podset_number, tor_number, tor_subnet_number, - spine_asn, leaf_asn_start, tor_asn_start, - nhipv4, nhipv4, tor_subnet_size, max_tor_subnet_number, - "t0-mclag", set_num=set_num) - routes_v6 = generate_routes("v6", podset_number, tor_number, tor_subnet_number, - spine_asn, leaf_asn_start, tor_asn_start, - nhipv6, nhipv6, tor_subnet_size, max_tor_subnet_number, - "t0-mclag", set_num=set_num) - - change_routes(action, ptf_ip, port, routes_v4) - change_routes(action, ptf_ip, port6, routes_v6) + if enable_ipv4_routes_generation: + routes_v4 = generate_routes("v4", podset_number, tor_number, tor_subnet_number, + spine_asn, leaf_asn_start, tor_asn_start, + nhipv4, nhipv4, tor_subnet_size, max_tor_subnet_number, + "t0-mclag", set_num=set_num) + if aggregate_routes_v4: + filterout_subnet_ipv4(aggregate_routes, routes_v4) + routes_v4.extend(aggregate_routes_v4) + change_routes(action, ptf_ip, port, routes_v4) + if enable_ipv6_routes_generation: + routes_v6 = generate_routes("v6", podset_number, tor_number, tor_subnet_number, + spine_asn, leaf_asn_start, tor_asn_start, + nhipv6, nhipv6, tor_subnet_size, max_tor_subnet_number, + "t0-mclag", set_num=set_num, + ipv6_address_pattern=ipv6_address_pattern) + if aggregate_routes_v6: + filterout_subnet_ipv6(aggregate_routes, routes_v6) + routes_v6.extend(aggregate_routes_v6) + change_routes(action, ptf_ip, port6, routes_v6) def fib_dpu(topo, ptf_ip, action="announce"): @@ -1033,6 +1107,34 @@ def fib_dpu(topo, ptf_ip, action="announce"): change_routes(action, ptf_ip, port6, routes_v6) +def get_ipv4_routes(routes): + return [r for r in routes if ipaddress.ip_network(UNICODE_TYPE(r[0])).version == 4] + + +def get_ipv6_routes(routes): + return [r for r in routes if ipaddress.ip_network(UNICODE_TYPE(r[0])).version == 6] + + +def filterout_subnet_ipv4(aggregate_routes, candidate_routes): + ars_ipv4 = get_ipv4_routes(aggregate_routes) + return filterout_subnet(ars_ipv4, candidate_routes) + + +def filterout_subnet_ipv6(aggregate_routes, candidate_routes): + ars_ipv6 = get_ipv6_routes(aggregate_routes) + return filterout_subnet(ars_ipv6, candidate_routes) + + +def filterout_subnet(aggregate_routes, candidate_routes): + subnets = [] + for ar in aggregate_routes: + ar_net = ipaddress.ip_network(UNICODE_TYPE(ar[0])) + for cr in candidate_routes: + if ipaddress.ip_network(UNICODE_TYPE(cr[0])).subnet_of(ar_net): + subnets.append(cr) + return list(set(candidate_routes) - set(subnets)) + + def main(): module = AnsibleModule( argument_spec=dict( diff --git a/ansible/roles/vm_set/tasks/announce_routes.yml b/ansible/roles/vm_set/tasks/announce_routes.yml index fe309231cb0..b4cbbc93c14 100644 --- a/ansible/roles/vm_set/tasks/announce_routes.yml +++ b/ansible/roles/vm_set/tasks/announce_routes.yml @@ -24,98 +24,107 @@ when: exabgp_action is not defined - block: - - name: Set facts - set_fact: - ptf_local_ipv4: "{{ configuration_properties.common.nhipv4|default('10.10.246.254') }}" - ptf_local_ipv6: "{{ configuration_properties.common.nhipv6|default('fc0a::ff') }}" - - - name: Configure exabgp processes for IPv4 on PTF - exabgp: - name: "{{ vm_item.key }}" - state: "configure" - router_id: "{{ ptf_local_ipv4 }}" - local_ip: "{{ ptf_local_ipv4 }}" - peer_ip: "{{ configuration[vm_item.key].bp_interface.ipv4.split('/')[0] }}" - local_asn: "{{ configuration[vm_item.key].bgp.asn }}" - peer_asn: "{{ configuration[vm_item.key].bgp.asn }}" - port: "{{ 5000 + vm_item.value.vm_offset|int }}" - loop: "{{ topology['VMs']|dict2items }}" - loop_control: - loop_var: vm_item - delegate_to: "{{ ptf_host }}" - - - name: Gather exabgp v4 programs - set_fact: - program_group_name: "exabgpv4" - program_group_programs: "{{ topology['VMs'].keys() | map('regex_replace', '^(.*)$', 'exabgp-\\1') | join(',')}}" - - - name: Configure exabgpv4 group - template: - src: "roles/vm_set/templates/exabgp.conf.j2" - dest: "/etc/supervisor/conf.d/exabgpv4.conf" - delegate_to: "{{ ptf_host }}" - - - name: configure exabgp processes for IPv6 on PTF - exabgp: - name: "{{ vm_item.key }}-v6" - state: "configure" - router_id: "{{ ptf_local_ipv4 }}" - local_ip: "{{ ptf_local_ipv6 }}" - peer_ip: "{{ configuration[vm_item.key].bp_interface.ipv6.split('/')[0] }}" - local_asn: "{{ configuration[vm_item.key].bgp.asn }}" - peer_asn: "{{ configuration[vm_item.key].bgp.asn }}" - port: "{{ 6000 + vm_item.value.vm_offset|int }}" - loop: "{{ topology['VMs']|dict2items }}" - loop_control: - loop_var: vm_item - delegate_to: "{{ ptf_host }}" - - - name: Gather exabgp v6 programs - set_fact: - program_group_name: "exabgpv6" - program_group_programs: "{{ topology['VMs'].keys() | map('regex_replace', '^(.*)$', 'exabgp-\\1-v6') | join(',')}}" - - - name: Configure exabgpv6 group - template: - src: "roles/vm_set/templates/exabgp.conf.j2" - dest: "/etc/supervisor/conf.d/exabgpv6.conf" - delegate_to: "{{ ptf_host }}" - - - name: Add exabgpv4 supervisor config and start related processes - when: "{{ topology['VMs'] | length > 0 }}" - supervisorctl: - name: "exabgpv4:" - state: present # present contains `supervisorctl reread` and `supervisorctl add` - delegate_to: "{{ ptf_host }}" - - - name: Add exabgpv6 supervisor config and start related processes - when: "{{ topology['VMs'] | length > 0 }}" - supervisorctl: - name: "exabgpv6:" - state: present # present contains `supervisorctl reread` and `supervisorctl add` - delegate_to: "{{ ptf_host }}" - - - name: Verify that exabgp processes for IPv4 are started - wait_for: - host: "{{ ptf_host_ip }}" - port: "{{ 5000 + topology.VMs[vm_item.key].vm_offset|int }}" - state: "started" - timeout: 180 - loop: "{{ topology['VMs']|dict2items }}" - loop_control: - loop_var: vm_item - delegate_to: localhost + - name: Configure and start exabpg process for IPV4 + when: configuration_properties.common.enable_ipv4_routes_generation | default(True) + block: - - name: Verify that exabgp processes for IPv6 are started - wait_for: - host: "{{ ptf_host_ip }}" - port: "{{ 6000 + topology.VMs[vm_item.key].vm_offset|int }}" - state: "started" - timeout: 180 - loop: "{{ topology['VMs']|dict2items }}" - loop_control: - loop_var: vm_item - delegate_to: localhost + - set_fact: + ptf_local_ipv4: "{{ configuration_properties.common.nhipv4|default('10.10.246.254') }}" + + - name: Configure exabgp processes for IPv4 on PTF + exabgp: + name: "{{ vm_item.key }}" + state: "configure" + router_id: "{{ ptf_local_ipv4 }}" + local_ip: "{{ ptf_local_ipv4 }}" + peer_ip: "{{ configuration[vm_item.key].bp_interface.ipv4.split('/')[0] }}" + local_asn: "{{ configuration[vm_item.key].bgp.asn }}" + peer_asn: "{{ configuration[vm_item.key].bgp.asn }}" + port: "{{ 5000 + vm_item.value.vm_offset|int }}" + loop: "{{ topology['VMs']|dict2items }}" + loop_control: + loop_var: vm_item + delegate_to: "{{ ptf_host }}" + + - name: Gather exabgp v4 programs + set_fact: + program_group_name: "exabgpv4" + program_group_programs: "{{ topology['VMs'].keys() | map('regex_replace', '^(.*)$', 'exabgp-\\1') | join(',')}}" + + - name: Configure exabgpv4 group + template: + src: "roles/vm_set/templates/exabgp.conf.j2" + dest: "/etc/supervisor/conf.d/exabgpv4.conf" + delegate_to: "{{ ptf_host }}" + + - name: Add exabgpv4 supervisor config and start related processes + when: "{{ topology['VMs'] | length > 0 }}" + supervisorctl: + name: "exabgpv4:" + state: present # present contains `supervisorctl reread` and `supervisorctl add` + delegate_to: "{{ ptf_host }}" + + - name: Verify that exabgp processes for IPv4 are started + wait_for: + host: "{{ ptf_host_ip }}" + port: "{{ 5000 + topology['VMs'][vm_item.key].vm_offset|int }}" + state: "started" + timeout: 180 + loop: "{{ topology['VMs']|dict2items }}" + loop_control: + loop_var: vm_item + delegate_to: localhost + + - name: Configure and start exabpg process for IPV6 + when: configuration_properties.common.enable_ipv6_routes_generation | default(True) + block: + + - set_fact: + ptf_local_ipv6: "{{ configuration_properties.common.nhipv6|default('fc0a::ff') }}" + + - name: configure exabgp processes for IPv6 on PTF + exabgp: + name: "{{ vm_item.key }}-v6" + state: "configure" + router_id: "{{ ptf_local_ipv4 }}" + local_ip: "{{ ptf_local_ipv6 }}" + peer_ip: "{{ configuration[vm_item.key].bp_interface.ipv6.split('/')[0] }}" + local_asn: "{{ configuration[vm_item.key].bgp.asn }}" + peer_asn: "{{ configuration[vm_item.key].bgp.asn }}" + port: "{{ 6000 + vm_item.value.vm_offset|int }}" + loop: "{{ topology['VMs']|dict2items }}" + loop_control: + loop_var: vm_item + delegate_to: "{{ ptf_host }}" + + - name: Gather exabgp v6 programs + set_fact: + program_group_name: "exabgpv6" + program_group_programs: "{{ topology['VMs'].keys() | map('regex_replace', '^(.*)$', 'exabgp-\\1-v6') | join(',')}}" + + - name: Configure exabgpv6 group + template: + src: "roles/vm_set/templates/exabgp.conf.j2" + dest: "/etc/supervisor/conf.d/exabgpv6.conf" + delegate_to: "{{ ptf_host }}" + + - name: Add exabgpv6 supervisor config and start related processes + when: "{{ topology['VMs'] | length > 0 }}" + supervisorctl: + name: "exabgpv6:" + state: present # present contains `supervisorctl reread` and `supervisorctl add` + delegate_to: "{{ ptf_host }}" + + - name: Verify that exabgp processes for IPv6 are started + wait_for: + host: "{{ ptf_host_ip }}" + port: "{{ 6000 + topology.VMs[vm_item.key].vm_offset|int }}" + state: "started" + timeout: 180 + loop: "{{ topology['VMs']|dict2items }}" + loop_control: + loop_var: vm_item + delegate_to: localhost - name: Announce routes announce_routes: