Example #1
0
    def add_geneve_tunnel(node,
                          local_address,
                          remote_address,
                          vni,
                          multicast_if=None,
                          encap_vrf=0,
                          l3_mode=False,
                          next_index=None):
        """Add GENEVE tunnel on the specified VPP node.

        :param node: Topology node.
        :param local_address: Local IP address.
        :param remote_address: Remote IP address.
        :param vni: Virtual network ID.
        :param multicast_if: Interface key of multicast interface; used only if
            remote is multicast. (Default value = None)
        :param encap_vrf: The FIB ID for sending unicast GENEVE encap packets or
            receiving multicast packets. (Default value = 0)
        :param l3_mode: Use geneve tunnel in L3 mode (ip routing) if Tue else in
            L2 mode (L2 switching). (Default value = False)
        :param next_index: The index of the next node.
        :type node: dict
        :type local_address: str
        :type remote_address: str
        :type vni: int
        :type multicast_if: str
        :type encap_vrf: int
        :type l3_mode: bool
        :type next_index: int
        :returns: SW interface index of created geneve tunnel.
        :rtype: int
        """
        cmd = u"geneve_add_del_tunnel2"
        args = dict(is_add=True,
                    local_address=IPAddress.create_ip_address_object(
                        ip_address(local_address)),
                    remote_address=IPAddress.create_ip_address_object(
                        ip_address(remote_address)),
                    mcast_sw_if_index=Topology.get_interface_sw_index(
                        node, multicast_if)
                    if multicast_if else Constants.BITWISE_NON_ZERO,
                    encap_vrf_id=int(encap_vrf),
                    decap_next_index=next_index
                    if l3_mode else Constants.BITWISE_NON_ZERO,
                    vni=int(vni),
                    l3_mode=l3_mode)
        err_msg = f"Failed to configure GENEVE tunnel on host {node[u'host']}!"
        with PapiSocketExecutor(node) as papi_exec:
            sw_if_index = papi_exec.add(cmd, **args).get_sw_if_index(err_msg)

        if_key = Topology.add_new_port(node, u"geneve_tunnel")
        Topology.update_interface_sw_if_index(node, if_key, sw_if_index)

        ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_if_index)
        Topology.update_interface_name(node, if_key, ifc_name)

        ifc_mac = InterfaceUtil.vpp_get_interface_mac(node, sw_if_index)
        Topology.update_interface_mac_address(node, if_key, ifc_mac)

        return sw_if_index
Example #2
0
File: GBP.py Project: yossihan/csit
    def gbp_endpoint_add(node, sw_if_index, ip_addr, mac_addr, sclass):
        """Add GBP endpoint.

        :param node: Node to add GBP endpoint on.
        :param sw_if_index: SW index of interface.
        :param ip_addr: GBP route domain ID.
        :param mac_addr: MAC address.
        :param sclass: Source CLASS.
        :type node: dict
        :type sw_if_index: int
        :type ip_addr: str
        :type mac_addr: str
        :type sclass: int
        """
        cmd = u"gbp_endpoint_add"
        err_msg = f"Failed to add GBP endpoint on {node[u'host']}!"

        ips = list()
        ips.append(IPAddress.create_ip_address_object(ip_address(ip_addr)))
        tun_src = IPAddress.create_ip_address_object(ip_address(u"0.0.0.0"))
        tun_dst = IPAddress.create_ip_address_object(ip_address(u"0.0.0.0"))

        args_in = dict(endpoint=dict(
            sw_if_index=sw_if_index,
            ips=ips,
            n_ips=len(ips),
            mac=L2Util.mac_to_bin(mac_addr),
            sclass=sclass,
            flags=getattr(GBPEndpointFlags,
                          u"GBP_API_ENDPOINT_FLAG_EXTERNAL").value,
            tun=dict(src=tun_src, dst=tun_dst)))

        with PapiSocketExecutor(node) as papi_exec:
            papi_exec.add(cmd, **args_in).get_reply(err_msg)
Example #3
0
    def create_prefix_object(ip_addr, addr_len):
        """Create prefix object.

        :param ip_addr: IPv4 or IPv6 address.
        :param addr_len: Length of IP address.
        :type ip_addr: IPv4Address or IPv6Address
        :type addr_len: int
        :returns: Prefix object.
        :rtype: dict
        """
        addr = IPAddress.create_ip_address_object(ip_addr)

        return dict(len=int(addr_len), address=addr)
Example #4
0
File: GBP.py Project: yossihan/csit
    def gbp_subnet_add_del(node,
                           address,
                           subnet_length,
                           sclass,
                           rd_id=1,
                           sw_if_index=0xffffffff):
        """Add external interface to GBP.

        :param node: Node to add GBP subnet on.
        :param address: IPv4 adddress.
        :param subnet_length: IPv4 address subnet.
        :param sclass: Source CLASS.
        :param rd_id: GBP route domain ID.
        :param sw_if_index: Interface index.
        :type node: dict
        :type address: int
        :type subnet_length: int
        :type sclass: int
        :type rd_id: int
        :type sw_if_index: int
        """
        cmd = u"gbp_subnet_add_del"
        err_msg = f"Failed to add GBP subnet on {node[u'host']}!"

        args_in = dict(
            is_add=True,
            subnet=dict(type=getattr(GBPSubnetType,
                                     u"GBP_API_SUBNET_L3_OUT").value,
                        sw_if_index=sw_if_index,
                        sclass=sclass,
                        prefix=dict(address=IPAddress.create_ip_address_object(
                            ip_address(address)),
                                    len=int(subnet_length)),
                        rd_id=rd_id))

        with PapiSocketExecutor(node) as papi_exec:
            papi_exec.add(cmd, **args_in).get_reply(err_msg)
Example #5
0
    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
Example #6
0
    def vpp_put_vxlan_and_vlan_interfaces_to_bridge_domain(
            node, node_vxlan_if, vxlan_count, op_node, op_node_if, dst_ip_start,
            ip_step, bd_id_start):
        """
        Configure ARPs and routes for VXLAN interfaces and put each pair of
        VXLAN tunnel interface and VLAN sub-interface to separate bridge-domain.

        :param node: VPP node.
        :param node_vxlan_if: VPP node interface key where VXLAN tunnel
            interfaces have been created.
        :param vxlan_count: Number of tunnel interfaces.
        :param op_node: Opposite VPP node for VXLAN tunnel interfaces.
        :param op_node_if: Opposite VPP node interface key for VXLAN tunnel
            interfaces.
        :param dst_ip_start: VXLAN tunnel destination IP address start.
        :param ip_step: IP address incremental step.
        :param bd_id_start: Bridge-domain ID start.
        :type node: dict
        :type node_vxlan_if: str
        :type vxlan_count: int
        :type op_node: dict
        :type op_node_if:
        :type dst_ip_start: str
        :type ip_step: int
        :type bd_id_start: int
        """
        dst_ip_start = ip_address(dst_ip_start)

        if vxlan_count > 1:
            idx_vxlan_if = Topology.get_interface_sw_index(node, node_vxlan_if)
            commands = list()
            for i in range(0, vxlan_count):
                dst_ip = dst_ip_start + i * ip_step
                commands.append(
                    f"exec ip neighbor "
                    f"{Topology.get_interface_name(node, node_vxlan_if)} "
                    f"{dst_ip} "
                    f"{Topology.get_interface_mac(op_node, op_node_if)} static "
                    f"\n"
                )
                commands.append(
                    f"ip_route_add_del "
                    f"{dst_ip}/{128 if dst_ip.version == 6 else 32} count 1 "
                    f"via {dst_ip} sw_if_index {idx_vxlan_if}\n"
                )
                sw_idx_vxlan = Topology.get_interface_sw_index(
                    node, f"vxlan_tunnel{i + 1}"
                )
                commands.append(
                    f"sw_interface_set_l2_bridge sw_if_index {sw_idx_vxlan} "
                    f"bd_id {bd_id_start + i} shg 0 enable\n"
                )
                sw_idx_vlan = Topology.get_interface_sw_index(
                    node, f"vlan_subif{i + 1}"
                )
                commands.append(
                    f"sw_interface_set_l2_bridge sw_if_index {sw_idx_vlan} "
                    f"bd_id {bd_id_start + i} shg 0 enable\n"
                )
            VatExecutor().write_and_execute_script(
                node, u"/tmp/configure_routes_and_bridge_domains.config",
                commands
            )
            return

        cmd1 = u"ip_neighbor_add_del"
        neighbor = dict(
            sw_if_index=Topology.get_interface_sw_index(node, node_vxlan_if),
            flags=0,
            mac_address=Topology.get_interface_mac(op_node, op_node_if),
            ip_address=u""
        )
        args1 = dict(
            is_add=1,
            neighbor=neighbor
        )
        cmd2 = u"ip_route_add_del"
        kwargs = dict(
            interface=node_vxlan_if,
            gateway=str(dst_ip_start)
        )
        route = IPUtil.compose_vpp_route_structure(
            node, str(dst_ip_start),
            128 if dst_ip_start.version == 6 else 32, **kwargs
        )
        args2 = dict(
            is_add=1,
            is_multipath=0,
            route=route
        )
        cmd3 = u"sw_interface_set_l2_bridge"
        args3 = dict(
            rx_sw_if_index=None,
            bd_id=None,
            shg=0,
            port_type=0,
            enable=1
        )
        args4 = dict(
            rx_sw_if_index=None,
            bd_id=None,
            shg=0,
            port_type=0,
            enable=1
        )

        with PapiSocketExecutor(node) as papi_exec:
            for i in range(0, vxlan_count):
                args1[u"neighbor"][u"ip_address"] = \
                    str(dst_ip_start + i * ip_step)
                args2[u"route"][u"prefix"][u"address"][u"un"] = \
                    IPAddress.union_addr(dst_ip_start + i * ip_step)
                args2[u"route"][u"paths"][0][u"nh"][u"address"] = \
                    IPAddress.union_addr(dst_ip_start + i * ip_step)
                args3[u"rx_sw_if_index"] = Topology.get_interface_sw_index(
                    node, f"vxlan_tunnel{i+1}"
                )
                args3[u"bd_id"] = int(bd_id_start+i)
                args4[u"rx_sw_if_index"] = Topology.get_interface_sw_index(
                    node, f"vlan_subif{i+1}"
                )
                args4[u"bd_id"] = int(bd_id_start+i)
                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). \
                    add(cmd3, history=history, **args4)
            papi_exec.get_replies()
Example #7
0
    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
Example #8
0
    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)