def configure_vpp_nsim(node, vpp_nsim_attr, interface0, interface1=None): """Configure nsim on the specified VPP node. :param node: Topology node. :param vpp_nsim_attr: VPP NSIM configuration attributes :param interface0: Interface name. :param interface1: 2nd Interface name for cross-connect feature :type node: dict :type vpp_nsim_attr: dict :type interface0: str or int :type interface1: str or int :raises RuntimeError: if no NSIM features are enabled or vpp papi command fails. """ host = node[u"host"] if not vpp_nsim_attr[u"output_nsim_enable"] \ and not vpp_nsim_attr[u"xc_nsim_enable"]: raise RuntimeError(f"No NSIM features enabled on host {host}:\n" f"vpp_nsim_attr = {vpp_nsim_attr}") cmd = u"nsim_configure2" args = dict(delay_in_usec=vpp_nsim_attr[u"delay_in_usec"], average_packet_size=vpp_nsim_attr[u"average_packet_size"], bandwidth_in_bits_per_second=vpp_nsim_attr[ u"bw_in_bits_per_second"], packets_per_drop=vpp_nsim_attr[u"packets_per_drop"], packets_per_reorder=vpp_nsim_attr.get( u"packets_per_reorder", 0)) err_msg = f"Failed to configure NSIM on host {host}" with PapiSocketExecutor(node) as papi_exec: papi_exec.add(cmd, **args).get_reply(err_msg) if vpp_nsim_attr[u"output_nsim_enable"]: cmd = u"nsim_output_feature_enable_disable" args = dict( enable_disable=vpp_nsim_attr[u"output_nsim_enable"], sw_if_index=InterfaceUtil.get_interface_index( node, interface0), ) err_msg = f"Failed to enable NSIM output feature on " \ f"host {host} interface {interface0}" with PapiSocketExecutor(node) as papi_exec: papi_exec.add(cmd, **args).get_reply(err_msg) elif vpp_nsim_attr[u"xc_nsim_enable"]: cmd = u"nsim_cross_connect_feature_enable_disable" args = dict( enable_disable=vpp_nsim_attr[u"xc_nsim_enable"], sw_if_index0=InterfaceUtil.get_interface_index( node, interface0), sw_if_index1=InterfaceUtil.get_interface_index( node, interface1), ) err_msg = f"Failed to enable NSIM output feature on " \ f"host {host} interface {interface0}" with PapiSocketExecutor(node) as papi_exec: papi_exec.add(cmd, **args).get_reply(err_msg)
def get_interface_vrf_table(node, interface, ip_version='ipv4'): """Get vrf ID for the given interface. :param node: VPP node. :param interface: Name or sw_if_index of a specific interface. :type node: dict :param ip_version: IP protocol version (ipv4 or ipv6). :type interface: str or int :type ip_version: str :returns: vrf ID of the specified interface. :rtype: int """ sw_if_index = InterfaceUtil.get_interface_index(node, interface) cmd = u"sw_interface_get_table" args = dict( sw_if_index=sw_if_index, is_ipv6=bool(ip_version == u"ipv6") ) err_msg = f"Failed to get VRF id assigned to interface {interface}" with PapiSocketExecutor(node) as papi_exec: reply = papi_exec.add(cmd, **args).get_reply(err_msg) return reply[u"vrf_id"]
def vpp_interface_set_ip_address(node, interface, address, prefix_length=None): """Set IP address to VPP interface. :param node: VPP node. :param interface: Interface name. :param address: IP address. :param prefix_length: Prefix length. :type node: dict :type interface: str :type address: str :type prefix_length: int """ ip_addr = ip_address(address) cmd = u"sw_interface_add_del_address" args = dict(sw_if_index=InterfaceUtil.get_interface_index( node, interface), is_add=True, del_all=False, prefix=IPUtil.create_prefix_object( ip_addr, prefix_length if prefix_length else 128 if ip_addr.version == 6 else 32)) err_msg = f"Failed to add IP address on interface {interface}" with PapiSocketExecutor(node) as papi_exec: papi_exec.add(cmd, **args).get_reply(err_msg)
def vpp_get_interface_ip_addresses(node, interface, ip_version): """Get list of IP addresses from an interface on a VPP node. :param node: VPP node. :param interface: Name of an interface on the VPP node. :param ip_version: IP protocol version (ipv4 or ipv6). :type node: dict :type interface: str :type ip_version: str :returns: List of dictionaries, each containing IP address, subnet prefix length and also the subnet mask for ipv4 addresses. Note: A single interface may have multiple IP addresses assigned. :rtype: list """ sw_if_index = InterfaceUtil.get_interface_index(node, interface) if not sw_if_index: return list() cmd = u"ip_address_dump" args = dict(sw_if_index=sw_if_index, is_ipv6=bool(ip_version == u"ipv6")) err_msg = f"Failed to get L2FIB dump on host {node[u'host']}" with PapiSocketExecutor(node) as papi_exec: details = papi_exec.add(cmd, **args).get_details(err_msg) # TODO: CSIT currently looks only whether the list is empty. # Add proper value processing if values become important. return details
def get_interface_vrf_table(node, interface, ip_version='ipv4'): """Get vrf ID for the given interface. :param node: VPP node. :param interface: Name or sw_if_index of a specific interface. :type node: dict :param ip_version: IP protocol version (ipv4 or ipv6). :type interface: str or int :type ip_version: str :returns: vrf ID of the specified interface. :rtype: int """ sw_if_index = InterfaceUtil.get_interface_index(node, interface) is_ipv6 = 1 if ip_version == 'ipv6' else 0 cmd = 'sw_interface_get_table' args = dict(sw_if_index=sw_if_index, is_ipv6=is_ipv6) err_msg = 'Failed to get VRF id assigned to interface {ifc}'.format( ifc=interface) with PapiExecutor(node) as papi_exec: reply = papi_exec.add(cmd, **args).get_reply(err_msg) return reply['vrf_id']
def vpp_interface_set_ip_address(node, interface, address, prefix_length=None): """Set IP address to VPP interface. :param node: VPP node. :param interface: Interface name. :param address: IP address. :param prefix_length: Prefix length. :type node: dict :type interface: str :type address: str :type prefix_length: int """ ip_addr = ip_address(unicode(address)) cmd = 'sw_interface_add_del_address' args = dict(sw_if_index=InterfaceUtil.get_interface_index( node, interface), is_add=1, is_ipv6=1 if ip_addr.version == 6 else 0, del_all=0, address_length=int(prefix_length) if prefix_length else 128 if ip_addr.version == 6 else 32, address=ip_addr.packed) err_msg = 'Failed to add IP address on interface {ifc}'.format( ifc=interface) with PapiExecutor(node) as papi_exec: papi_exec.add(cmd, **args).get_reply(err_msg)
def _get_sr_steer_policy_args(node, mode, interface=None, ip_addr=None, prefix=None): """Return values of sw_if_index, mask_width, prefix_addr and traffic_type for sr_steering_add_del API. :param node: Given node to create/delete steering policy on. :param mode: Mode of operation - L2 or L3. :param interface: Interface name (Optional, required in case of L2 mode). :param ip_addr: IPv4/IPv6 address (Optional, required in case of L3 mode). :param prefix: IP address prefix (Optional, required in case of L3 mode). :type node: dict :type mode: str :type interface: str :type ip_addr: str :type prefix: int :returns: Values for sw_if_index, prefix and traffic_type :rtype: tuple :raises ValueError: If unsupported mode used or required parameter is missing. """ if mode.lower() == u"l2": if interface is None: raise ValueError(f"Required data missing.\n" f"interface: {interface}") sw_if_index = InterfaceUtil.get_interface_index(node, interface) prefix = 0 traffic_type = getattr(SRv6PolicySteeringTypes, u"SR_STEER_L2").value elif mode.lower() == u"l3": if ip_addr is None or prefix is None: raise ValueError(f"Required data missing.\n" f"IP address:{ip_addr}\n" f"mask:{prefix}") sw_if_index = Constants.BITWISE_NON_ZERO ip_addr = ip_address(ip_addr) prefix = IPUtil.create_prefix_object(ip_addr, int(prefix)) traffic_type = getattr( SRv6PolicySteeringTypes, u"SR_STEER_IPV4").value if ip_addr.version == 4 else getattr( SRv6PolicySteeringTypes, u"SR_STEER_IPV6").value else: raise ValueError(f"Unsupported mode: {mode}") return sw_if_index, prefix, traffic_type
def flush_ip_addresses(node, interface): """Flush all IP addresses from specified interface. :param node: VPP node. :param interface: Interface name. :type node: dict :type interface: str """ cmd = 'sw_interface_add_del_address' args = dict(sw_if_index=InterfaceUtil.get_interface_index( node, interface), del_all=1) err_msg = 'Failed to flush IP address on interface {ifc}'.format( ifc=interface) with PapiExecutor(node) as papi_exec: papi_exec.add(cmd, **args).get_reply(err_msg)
def vpp_ip_source_check_setup(node, if_name): """Setup Reverse Path Forwarding source check on interface. :param node: VPP node. :param if_name: Interface name to setup RPF source check. :type node: dict :type if_name: str """ cmd = u"ip_source_check_interface_add_del" args = dict(sw_if_index=InterfaceUtil.get_interface_index( node, if_name), is_add=1, loose=0) err_msg = f"Failed to enable source check on interface {if_name}" with PapiSocketExecutor(node) as papi_exec: papi_exec.add(cmd, **args).get_reply(err_msg)
def vpp_ra_suppress_link_layer(node, interface): """Suppress ICMPv6 router advertisement message for link scope address. :param node: VPP node. :param interface: Interface name. :type node: dict :type interface: str """ cmd = 'sw_interface_ip6nd_ra_config' args = dict(sw_if_index=InterfaceUtil.get_interface_index( node, interface), suppress=1) err_msg = 'Failed to suppress ICMPv6 router advertisement message on ' \ 'interface {ifc}'.format(ifc=interface) with PapiExecutor(node) as papi_exec: papi_exec.add(cmd, **args).get_reply(err_msg)
def vpp_proxy_arp_interface_enable(node, interface): """Enable proxy ARP on interface. :param node: VPP node to enable proxy ARP on interface. :param interface: Interface to enable proxy ARP. :type node: dict :type interface: str or int """ cmd = 'proxy_arp_intfc_enable_disable' args = dict( sw_if_index=InterfaceUtil.get_interface_index(node, interface), enable_disable=1) err_msg = 'Failed to enable proxy ARP on interface {ifc}'.format( ifc=interface) with PapiExecutor(node) as papi_exec: papi_exec.add(cmd, **args).get_reply(err_msg)
def vpp_ra_suppress_link_layer(node, interface): """Suppress ICMPv6 router advertisement message for link scope address. :param node: VPP node. :param interface: Interface name. :type node: dict :type interface: str """ cmd = u"sw_interface_ip6nd_ra_config" args = dict(sw_if_index=InterfaceUtil.get_interface_index( node, interface), suppress=1) err_msg = f"Failed to suppress ICMPv6 router advertisement message " \ f"on interface {interface}" with PapiSocketExecutor(node) as papi_exec: papi_exec.add(cmd, **args).get_reply(err_msg)
def flush_ip_addresses(node, interface): """Flush all IP addresses from specified interface. :param node: VPP node. :param interface: Interface name. :type node: dict :type interface: str """ cmd = u"sw_interface_add_del_address" args = dict(sw_if_index=InterfaceUtil.get_interface_index( node, interface), is_add=False, del_all=True) err_msg = f"Failed to flush IP address on interface {interface}" with PapiSocketExecutor(node) as papi_exec: papi_exec.add(cmd, **args).get_reply(err_msg)
def vpp_ip_probe(node, interface, addr): """Run ip probe on VPP node. :param node: VPP node. :param interface: Interface key or name. :param addr: IPv4/IPv6 address. :type node: dict :type interface: str :type addr: str """ cmd = u"ip_probe_neighbor" args = dict(sw_if_index=InterfaceUtil.get_interface_index( node, interface), dst=str(addr)) err_msg = f"VPP ip probe {interface} {addr} failed on {node[u'host']}" with PapiSocketExecutor(node) as papi_exec: papi_exec.add(cmd, **args).get_reply(err_msg)
def vpp_interface_ra_suppress(node, interface): """Disable sending ICMPv6 router-advertisement messages on an interface on a VPP node. :param node: VPP node. :param interface: Interface name. :type node: dict :type interface: str """ cmd = u"sw_interface_ip6nd_ra_config" args = dict(sw_if_index=InterfaceUtil.get_interface_index( node, interface), suppress=1) err_msg = f"Failed to disable sending ICMPv6 router-advertisement " \ f"messages on interface {interface}" with PapiSocketExecutor(node) as papi_exec: papi_exec.add(cmd, **args).get_reply(err_msg)
def vpp_ip_source_check_setup(node, if_name): """Setup Reverse Path Forwarding source check on interface. :param node: VPP node. :param if_name: Interface name to setup RPF source check. :type node: dict :type if_name: str """ cmd = 'ip_source_check_interface_add_del' args = dict( sw_if_index=InterfaceUtil.get_interface_index(node, if_name), is_add=1, loose=0) err_msg = 'Failed to enable source check on interface {ifc}'.format( ifc=if_name) with PapiExecutor(node) as papi_exec: papi_exec.add(cmd, **args).get_replies(err_msg). \ verify_reply(err_msg=err_msg)
def vpp_get_interface_ip_addresses(node, interface, ip_version): """Get list of IP addresses from an interface on a VPP node. :param node: VPP node. :param interface: Name of an interface on the VPP node. :param ip_version: IP protocol version (ipv4 or ipv6). :type node: dict :type interface: str :type ip_version: str :returns: List of dictionaries, each containing IP address, subnet prefix length and also the subnet mask for ipv4 addresses. Note: A single interface may have multiple IP addresses assigned. :rtype: list """ sw_if_index = InterfaceUtil.get_interface_index(node, interface) data = list() if sw_if_index: is_ipv6 = 1 if ip_version == 'ipv6' else 0 cmd = 'ip_address_dump' cmd_reply = 'ip_address_details' args = dict(sw_if_index=sw_if_index, is_ipv6=is_ipv6) err_msg = 'Failed to get L2FIB dump on host {host}'.format( host=node['host']) with PapiExecutor(node) as papi_exec: papi_resp = papi_exec.add(cmd, **args).get_dump(err_msg) for item in papi_resp.reply[0]['api_reply']: item[cmd_reply]['ip'] = item[cmd_reply]['prefix'].split('/')[0] item[cmd_reply]['prefix_length'] = int( item[cmd_reply]['prefix'].split('/')[1]) item[cmd_reply]['is_ipv6'] = is_ipv6 item[cmd_reply]['netmask'] = \ str(IPv6Network(unicode('::/{pl}'.format( pl=item[cmd_reply]['prefix_length']))).netmask) \ if is_ipv6 \ else str(IPv4Network(unicode('0.0.0.0/{pl}'.format( pl=item[cmd_reply]['prefix_length']))).netmask) data.append(item[cmd_reply]) return data
def set_acl_list_for_interface(node, interface, acl_type, acl_idx=None): """Set the list of input or output ACLs applied to the interface. It unapplies any previously applied ACLs. :param node: VPP node to set ACL on. :param interface: Interface name or sw_if_index. :param acl_type: Type of ACL(s) - input or output. :param acl_idx: Index(ies) of ACLs to be applied on the interface. :type node: dict :type interface: str or int :type acl_type: str :type acl_idx: list """ Classify._acl_interface_set_acl_list( node=node, sw_if_index=int(InterfaceUtil.get_interface_index(node, interface)), acl_type=acl_type, acls=acl_idx if isinstance(acl_idx, list) else list())
def vpp_ip_probe(node, interface, addr): """Run ip probe on VPP node. :param node: VPP node. :param interface: Interface key or name. :param addr: IPv4/IPv6 address. :type node: dict :type interface: str :type addr: str """ cmd = 'ip_probe_neighbor' args = dict(sw_if_index=InterfaceUtil.get_interface_index( node, interface), dst=str(addr)) err_msg = 'VPP ip probe {dev} {ip} failed on {h}'.format( dev=interface, ip=addr, h=node['host']) with PapiExecutor(node) as papi_exec: papi_exec.add(cmd, **args).get_reply(err_msg)
def vpp_ra_send_after_interval(node, interface, interval=2): """Setup vpp router advertisement(RA) in such way it sends RA packet after every interval value. :param node: VPP node. :param interface: Interface name. :param interval: Interval in seconds for RA resend. :type node: dict :type interface: str :type interval: int """ cmd = u"sw_interface_ip6nd_ra_config" args = dict(sw_if_index=InterfaceUtil.get_interface_index( node, interface), initial_interval=int(interval)) err_msg = f"Failed to set router advertisement interval " \ f"on interface {interface}" with PapiSocketExecutor(node) as papi_exec: papi_exec.add(cmd, **args).get_reply(err_msg)
def vpp_ra_send_after_interval(node, interface, interval=2): """Setup vpp router advertisement(RA) in such way it sends RA packet after every interval value. :param node: VPP node. :param interface: Interface name. :param interval: Interval in seconds for RA resend. :type node: dict :type interface: str :type interval: int """ cmd = 'sw_interface_ip6nd_ra_config' args = dict(sw_if_index=InterfaceUtil.get_interface_index( node, interface), initial_interval=int(interval)) err_msg = 'Failed to set router advertisement interval on ' \ 'interface {ifc}'.format(ifc=interface) with PapiExecutor(node) as papi_exec: papi_exec.add(cmd, **args).get_replies(err_msg). \ verify_reply(err_msg=err_msg)
def add_del_macip_acl_interface(node, interface, action, acl_idx): """Apply/un-apply the MACIP ACL to/from a given interface. :param node: VPP node to set MACIP ACL on. :param interface: Interface name or sw_if_index. :param action: Required action - add or del. :param acl_idx: ACL index to be applied on the interface. :type node: dict :type interface: str or int :type action: str :type acl_idx: str or int :raises RuntimeError: If unable to set MACIP ACL for the interface. """ cmd = u"macip_acl_interface_add_del" err_msg = f"Failed to get 'macip_acl_interface' on host {node[u'host']}" args = dict(is_add=bool(action == u"add"), sw_if_index=int( InterfaceUtil.get_interface_index(node, interface)), acl_index=int(acl_idx)) with PapiSocketExecutor(node) as papi_exec: papi_exec.add(cmd, **args).get_reply(err_msg)
def vpp_create_vxlan_and_vlan_interfaces( node, node_vxlan_if, node_vlan_if, vxlan_count, vni_start, src_ip_start, dst_ip_start, ip_step): """ Configure IPs, create VXLAN interfaces and VLAN sub-interfaces on VPP node. :param node: VPP node. :param node_vxlan_if: VPP node interface key to create VXLAN tunnel interfaces. :param node_vlan_if: VPP node interface key to create VLAN sub-interface. :param vxlan_count: Number of tunnel interfaces to create. :param vni_start: VNI start ID. :param src_ip_start: VXLAN tunnel source IP address start. :param dst_ip_start: VXLAN tunnel destination IP address start. :param ip_step: IP address incremental step. :type node: dict :type node_vxlan_if: str :type node_vlan_if: str :type vxlan_count: int :type vni_start: int :type src_ip_start: str :type dst_ip_start: str :type ip_step: int :returns: Number of created VXLAN interfaces. :rtype: int """ src_ip_start = ip_address(src_ip_start) dst_ip_start = ip_address(dst_ip_start) if vxlan_count > 10: commands = list() for i in range(0, vxlan_count): try: src_ip = src_ip_start + i * ip_step dst_ip = dst_ip_start + i * ip_step except AddressValueError: logger.warn( u"Can't do more iterations - IP address limit " u"has been reached." ) vxlan_count = i break commands.append( f"sw_interface_add_del_address sw_if_index " f"{Topology.get_interface_sw_index(node, node_vxlan_if)} " f"{src_ip}/{128 if src_ip.version == 6 else 32}\n" ) commands.append( f"vxlan_add_del_tunnel src {src_ip} dst {dst_ip} " f"vni {vni_start + i}\n" ) commands.append( f"create_vlan_subif sw_if_index " f"{Topology.get_interface_sw_index(node, node_vlan_if)} " f"vlan {i + 1}\n" ) VatExecutor().write_and_execute_script( node, u"/tmp/create_vxlan_interfaces.config", commands ) return vxlan_count cmd1 = u"sw_interface_add_del_address" args1 = dict( sw_if_index=InterfaceUtil.get_interface_index(node, node_vxlan_if), is_add=True, del_all=False, prefix=None ) cmd2 = u"vxlan_add_del_tunnel_v3" args2 = dict( is_add=True, instance=Constants.BITWISE_NON_ZERO, src_address=None, dst_address=None, mcast_sw_if_index=Constants.BITWISE_NON_ZERO, encap_vrf_id=0, decap_next_index=Constants.BITWISE_NON_ZERO, vni=None ) cmd3 = u"create_vlan_subif" args3 = dict( sw_if_index=InterfaceUtil.get_interface_index( node, node_vlan_if), vlan_id=None ) with PapiSocketExecutor(node) as papi_exec: for i in range(0, vxlan_count): try: src_ip = src_ip_start + i * ip_step dst_ip = dst_ip_start + i * ip_step except AddressValueError: logger.warn( u"Can't do more iterations - IP address limit " u"has been reached." ) vxlan_count = i break args1[u"prefix"] = IPUtil.create_prefix_object( src_ip, 128 if src_ip_start.version == 6 else 32 ) args2[u"src_address"] = IPAddress.create_ip_address_object( src_ip ) args2[u"dst_address"] = IPAddress.create_ip_address_object( dst_ip ) args2[u"vni"] = int(vni_start) + i args3[u"vlan_id"] = i + 1 history = bool(not 1 < i < vxlan_count - 1) papi_exec.add(cmd1, history=history, **args1).\ add(cmd2, history=history, **args2).\ add(cmd3, history=history, **args3) papi_exec.get_replies() return vxlan_count
def vpp_create_vxlan_and_vlan_interfaces(node, node_vxlan_if, node_vlan_if, vxlan_count, vni_start, src_ip_start, dst_ip_start, ip_step): """ Configure IPs, create VXLAN interfaces and VLAN sub-interfaces on VPP node. :param node: VPP node. :param node_vxlan_if: VPP node interface key to create VXLAN tunnel interfaces. :param node_vlan_if: VPP node interface key to create VLAN sub-interface. :param vxlan_count: Number of tunnel interfaces to create. :param vni_start: VNI start ID. :param src_ip_start: VXLAN tunnel source IP address start. :param dst_ip_start: VXLAN tunnel destination IP address start. :param ip_step: IP address incremental step. :type node: dict :type node_vxlan_if: str :type node_vlan_if: str :type vxlan_count: int :type vni_start: int :type src_ip_start: str :type dst_ip_start: str :type ip_step: int :returns: Number of created VXLAN interfaces. :rtype: int """ src_ip_addr_start = ip_address(unicode(src_ip_start)) dst_ip_addr_start = ip_address(unicode(dst_ip_start)) if vxlan_count > 10: commands = list() tmp_fn = '/tmp/create_vxlan_interfaces.config' for i in xrange(0, vxlan_count): try: src_ip = src_ip_addr_start + i * ip_step dst_ip = dst_ip_addr_start + i * ip_step except AddressValueError: logger.warn("Can't do more iterations - IP address limit " "has been reached.") vxlan_count = i break commands.append( 'sw_interface_add_del_address sw_if_index {sw_idx} ' '{ip}/{ip_len}\n'.format( sw_idx=Topology.get_interface_sw_index( node, node_vxlan_if), ip=src_ip, ip_len=128 if src_ip.version == 6 else 32)) commands.append( 'vxlan_add_del_tunnel src {srcip} dst {dstip} vni {vni}\n'\ .format(srcip=src_ip, dstip=dst_ip, vni=vni_start + i)) commands.append( 'create_vlan_subif sw_if_index {sw_idx} vlan {vlan}\n'\ .format(sw_idx=Topology.get_interface_sw_index( node, node_vlan_if), vlan=i + 1)) VatExecutor().write_and_execute_script(node, tmp_fn, commands) return vxlan_count cmd1 = 'sw_interface_add_del_address' args1 = dict( sw_if_index=InterfaceUtil.get_interface_index(node, node_vxlan_if), is_add=1, is_ipv6=1 if src_ip_addr_start.version == 6 else 0, del_all=0, address_length=128 if src_ip_addr_start.version == 6 else 32, address=None) cmd2 = 'vxlan_add_del_tunnel' args2 = dict(is_add=1, is_ipv6=0, instance=Constants.BITWISE_NON_ZERO, src_address=None, dst_address=None, mcast_sw_if_index=Constants.BITWISE_NON_ZERO, encap_vrf_id=0, decap_next_index=Constants.BITWISE_NON_ZERO, vni=None) cmd3 = 'create_vlan_subif' args3 = dict(sw_if_index=InterfaceUtil.get_interface_index( node, node_vlan_if), vlan_id=None) err_msg = 'Failed to create VXLAN and VLAN interfaces on host {host}'.\ format(host=node['host']) with PapiExecutor(node) as papi_exec: for i in xrange(0, vxlan_count): try: src_ip = src_ip_addr_start + i * ip_step dst_ip = dst_ip_addr_start + i * ip_step except AddressValueError: logger.warn("Can't do more iterations - IP address limit " "has been reached.") vxlan_count = i break args1['address'] = src_ip.packed args2['src_address'] = src_ip.packed args2['dst_address'] = dst_ip.packed args2['vni'] = int(vni_start) + i args3['vlan_id'] = i + 1 history = False if 1 < i < vxlan_count else True papi_exec.add(cmd1, history=history, **args1).\ add(cmd2, history=history, **args2).\ add(cmd3, history=history, **args3) if i > 0 and i % (Constants.PAPI_MAX_API_BULK / 3) == 0: papi_exec.get_replies(err_msg) papi_exec.get_replies() return vxlan_count
def vpp_route_add(node, network, prefix_len, **kwargs): """Add route to the VPP node. :param node: VPP node. :param network: Route destination network address. :param prefix_len: Route destination network prefix length. :param kwargs: Optional key-value arguments: gateway: Route gateway address. (str) interface: Route interface. (str) vrf: VRF table ID. (int) count: number of IP addresses to add starting from network IP (int) local: The route is local with same prefix (increment is 1). If None, then is not used. (bool) lookup_vrf: VRF table ID for lookup. (int) multipath: Enable multipath routing. (bool) weight: Weight value for unequal cost multipath routing. (int) :type node: dict :type network: str :type prefix_len: int :type kwargs: dict """ count = kwargs.get("count", 1) if count > 100: gateway = kwargs.get("gateway", '') interface = kwargs.get("interface", '') vrf = kwargs.get("vrf", None) multipath = kwargs.get("multipath", False) with VatTerminal(node, json_param=False) as vat: vat.vat_terminal_exec_cmd_from_template( 'vpp_route_add.vat', network=network, prefix_length=prefix_len, via='via {}'.format(gateway) if gateway else '', sw_if_index='sw_if_index {}'.format( InterfaceUtil.get_interface_index(node, interface)) if interface else '', vrf='vrf {}'.format(vrf) if vrf else '', count='count {}'.format(count) if count else '', multipath='multipath' if multipath else '') return net_addr = ip_address(unicode(network)) cmd = 'ip_route_add_del' route = IPUtil.compose_vpp_route_structure(node, network, prefix_len, **kwargs) args = dict(is_add=1, is_multipath=int(kwargs.get('multipath', False)), route=route) err_msg = 'Failed to add route(s) on host {host}'.format( host=node['host']) with PapiExecutor(node) as papi_exec: for i in xrange(kwargs.get('count', 1)): args['route']['prefix']['address']['un'] = \ IPUtil.union_addr(net_addr + i) history = False if 1 < i < kwargs.get('count', 1) else True papi_exec.add(cmd, history=history, **args) if i > 0 and i % Constants.PAPI_MAX_API_BULK == 0: papi_exec.get_replies(err_msg) papi_exec.get_replies(err_msg)
def configure_sr_localsid(node, local_sid, behavior, interface=None, next_hop=None, fib_table=None, out_if=None, in_if=None, src_addr=None, sid_list=None): """Create SRv6 LocalSID and binds it to a particular behaviour on the given node. :param node: Given node to create localSID on. :param local_sid: LocalSID IPv6 address. :param behavior: SRv6 LocalSID function. :param interface: Interface name (Optional, required for L2/L3 xconnects). :param next_hop: Next hop IPv4/IPv6 address (Optional, required for L3 xconnects). :param fib_table: FIB table for IPv4/IPv6 lookup (Optional, required for L3 routing). :param out_if: Interface name of local interface for sending traffic towards the Service Function (Optional, required for SRv6 endpoint to SR-unaware appliance). :param in_if: Interface name of local interface receiving the traffic coming back from the Service Function (Optional, required for SRv6 endpoint to SR-unaware appliance). :param src_addr: Source address on the packets coming back on in_if interface (Optional, required for SRv6 endpoint to SR-unaware appliance via static proxy). :param sid_list: SID list (Optional, required for SRv6 endpoint to SR-unaware appliance via static proxy). :type node: dict :type local_sid: str :type behavior: str :type interface: str :type next_hop: str :type fib_table: str :type out_if: str :type in_if: str :type src_addr: str :type sid_list: list :raises ValueError: If required parameter is missing. """ beh = behavior.replace(u".", u"_").upper() # There is no SRv6Behaviour enum defined for functions from SRv6 plugins # so we need to use CLI command to configure it. if beh in (getattr(SRv6Behavior, u"END_AD").name, getattr(SRv6Behavior, u"END_AS").name, getattr(SRv6Behavior, u"END_AM").name): if beh == getattr(SRv6Behavior, u"END_AS").name: if next_hop is None or out_if is None or in_if is None or \ src_addr is None or sid_list is None: raise ValueError(f"Required parameter(s) missing.\n" f"next_hop:{next_hop}\n " f"out_if:{out_if}\n" f"in_if:{in_if}\n" f"src_addr:{src_addr}\n" f"sid_list:{sid_list}") sid_conf = f"next {u' next '.join(sid_list)}" params = f"nh {next_hop} oif {out_if} iif {in_if} " \ f"src {src_addr} {sid_conf}" else: if next_hop is None or out_if is None or in_if is None: raise ValueError(f"Required parameter(s) missing.\n" f"next_hop:{next_hop}\n" f"out_if:{out_if}\n" f"in_if:{in_if}") params = f"nh {next_hop} oif {out_if} iif {in_if}" cli_cmd = f"sr localsid address {local_sid} behavior {behavior} " \ f"{params}" PapiSocketExecutor.run_cli_cmd(node, cli_cmd) return cmd = u"sr_localsid_add_del" args = dict(is_del=False, localsid=IPv6Address(local_sid).packed, end_psp=False, behavior=getattr(SRv6Behavior, beh).value, sw_if_index=Constants.BITWISE_NON_ZERO, vlan_index=0, fib_table=0, nh_addr=0) err_msg = f"Failed to add SR localSID {local_sid} " \ f"host {node[u'host']}" if beh in (getattr(SRv6Behavior, u"END_X").name, getattr(SRv6Behavior, u"END_DX4").name, getattr(SRv6Behavior, u"END_DX6").name): if interface is None or next_hop is None: raise ValueError(f"Required parameter(s) missing.\n" f"interface:{interface}\n" f"next_hop:{next_hop}") args[u"sw_if_index"] = InterfaceUtil.get_interface_index( node, interface) args[u"nh_addr"] = IPAddress.create_ip_address_object( ip_address(next_hop)) elif beh == getattr(SRv6Behavior, u"END_DX2").name: if interface is None: raise ValueError( f"Required parameter missing.\ninterface: {interface}") args[u"sw_if_index"] = InterfaceUtil.get_interface_index( node, interface) elif beh in (getattr(SRv6Behavior, u"END_DT4").name, getattr(SRv6Behavior, u"END_DT6").name): if fib_table is None: raise ValueError(f"Required parameter missing.\n" f"fib_table: {fib_table}") args[u"fib_table"] = fib_table with PapiSocketExecutor(node) as papi_exec: papi_exec.add(cmd, **args).get_reply(err_msg)
def vpp_route_add(node, network, prefix_len, strict=True, **kwargs): """Add route to the VPP node. Prefer multipath behavior. :param node: VPP node. :param network: Route destination network address. :param prefix_len: Route destination network prefix length. :param strict: If true, fail if address has host bits set. :param kwargs: Optional key-value arguments: gateway: Route gateway address. (str) interface: Route interface. (str) vrf: VRF table ID. (int) count: number of IP addresses to add starting from network IP (int) local: The route is local with same prefix (increment is 1 network) If None, then is not used. (bool) lookup_vrf: VRF table ID for lookup. (int) multipath: Enable multipath routing. (bool) Default: True. weight: Weight value for unequal cost multipath routing. (int) :type node: dict :type network: str :type prefix_len: int :type strict: bool :type kwargs: dict :raises RuntimeError: If the argument combination is not supported. """ count = kwargs.get(u"count", 1) if count > 100: if not kwargs.get(u"multipath", True): raise RuntimeError( u"VAT exec supports only multipath behavior") gateway = kwargs.get(u"gateway", u"") interface = kwargs.get(u"interface", u"") local = kwargs.get(u"local", u"") if interface: interface = InterfaceUtil.vpp_get_interface_name( node, InterfaceUtil.get_interface_index(node, interface)) vrf = kwargs.get(u"vrf", None) trailers = list() if vrf: trailers.append(f"table {vrf}") if gateway: trailers.append(f"via {gateway}") if interface: trailers.append(interface) elif interface: trailers.append(f"via {interface}") if local: if gateway or interface: raise RuntimeError(u"Unsupported combination with local.") trailers.append(u"local") trailer = u" ".join(trailers) command_parts = [u"exec ip route add", u"network goes here"] if trailer: command_parts.append(trailer) netiter = NetworkIncrement(ip_network(f"{network}/{prefix_len}", strict=strict), format=u"slash") tmp_filename = u"/tmp/routes.config" with open(tmp_filename, u"w") as tmp_file: for _ in range(count): command_parts[1] = netiter.inc_fmt() print(u" ".join(command_parts), file=tmp_file) VatExecutor().execute_script(tmp_filename, node, timeout=1800, json_out=False, copy_on_execute=True, history=False) os.remove(tmp_filename) return cmd = u"ip_route_add_del" args = dict(is_add=True, is_multipath=kwargs.get(u"multipath", True), route=None) err_msg = f"Failed to add route(s) on host {node[u'host']}" netiter = NetworkIncrement(ip_network(f"{network}/{prefix_len}", strict=strict), format=u"addr") with PapiSocketExecutor(node) as papi_exec: for i in range(count): args[u"route"] = IPUtil.compose_vpp_route_structure( node, netiter.inc_fmt(), prefix_len, **kwargs) history = bool(not 0 < i < count - 1) papi_exec.add(cmd, history=history, **args) papi_exec.get_replies(err_msg)
def compose_vpp_route_structure(node, network, prefix_len, **kwargs): """Create route object for ip_route_add_del api call. :param node: VPP node. :param network: Route destination network address. :param prefix_len: Route destination network prefix length. :param kwargs: Optional key-value arguments: gateway: Route gateway address. (str) interface: Route interface. (str) vrf: VRF table ID. (int) count: number of IP addresses to add starting from network IP (int) local: The route is local with same prefix (increment is 1). If None, then is not used. (bool) lookup_vrf: VRF table ID for lookup. (int) multipath: Enable multipath routing. (bool) weight: Weight value for unequal cost multipath routing. (int) :type node: dict :type network: str :type prefix_len: int :type kwargs: dict :returns: route parameter basic structure :rtype: dict """ interface = kwargs.get(u"interface", u"") gateway = kwargs.get(u"gateway", u"") net_addr = ip_address(network) prefix = IPUtil.create_prefix_object(net_addr, prefix_len) paths = list() n_hop = dict(address=IPAddress.union_addr(ip_address(gateway)) if gateway else 0, via_label=MPLS_LABEL_INVALID, obj_id=Constants.BITWISE_NON_ZERO) path = dict(sw_if_index=InterfaceUtil.get_interface_index( node, interface) if interface else Constants.BITWISE_NON_ZERO, table_id=int(kwargs.get(u"lookup_vrf", 0)), rpf_id=Constants.BITWISE_NON_ZERO, weight=int(kwargs.get(u"weight", 1)), preference=1, type=getattr( FibPathType, u"FIB_PATH_TYPE_LOCAL" if kwargs.get(u"local", False) else u"FIB_PATH_TYPE_NORMAL").value, flags=getattr(FibPathFlags, u"FIB_PATH_FLAG_NONE").value, proto=getattr( FibPathNhProto, u"FIB_PATH_NH_PROTO_IP6" if net_addr.version == 6 else u"FIB_PATH_NH_PROTO_IP4").value, nh=n_hop, n_labels=0, label_stack=list(0 for _ in range(16))) paths.append(path) route = dict(table_id=int(kwargs.get(u"vrf", 0)), prefix=prefix, n_paths=len(paths), paths=paths) return route