Linux systems — pyroute2 0.9.4 documentation

# Linux systems

class pyroute2.iproute.linux.RTNL_API

  A mixin RTNL API class.

  RTNL_API should not be instantiated by itself, it is intended to be used as a mixin class. Following classes use RTNL_API:

  - AsyncIPRoute – Asynchronous RTNL API

  - IPRoute – Synchronous RTNL API

  - NetNS – Legace netns-enabled RTNL API

  This class was started as iproute2 ip/tc equivalent, but as a Python API. It does not provide any complicated logic, but instead runs simple RTNL queries: It is an old-school API, that provides access to rtnetlink as is. It helps you to retrieve and change almost all the data, available through rtnetlink:

      from pyroute2 import IPRoute

      ipr = IPRoute()

      # create an interface
      ipr.link("add", ifname="brx", kind="bridge")

      # lookup the index
      dev = ipr.link_lookup(ifname="brx")[0]

      # bring it up
      ipr.link("set", index=dev, state="up")

      # change the interface MAC address and rename it just for fun
      ipr.link(
          "set",
          index=dev,
          address="00:11:22:33:44:55",
          ifname="br-ctrl",
      )

      # add primary IP address
      ipr.addr(
          "add",
          index=dev,
          address="10.0.0.1",
          prefixlen=24,
          broadcast="10.0.0.255",
      )
      # add secondary IP address
      ipr.addr(
          "add",
          index=dev,
          address="10.0.0.2",
          prefixlen=24,
          broadcast="10.0.0.255",
      )

  filter_messages(dump_filter, msgs)

    Filter messages using dump_filter. The filter might be a callable, then it will be called for every message in the list. Or it might be a dict, where keys are used to get values from messages, and dict values are used to match the message.

    The method might be called directly. It is also used by calls like ipr.link(‘dump’, ….), where keyword arguments work as dump_filter for ipr.filter_messages().

    A callable dump_filter must return True or False:

        # get all links with names starting with eth:
        #
        for link in ipr.filter_messages(
            lambda x: x.get("ifname").startswith("eth"),
            ipr.link("dump"),
        ):
            print(link.get("ifname"))

        eth0

    A dict dump_filter can have callables as values:

        # get all links with names starting with eth, and
        # MAC address in a database:
        #
        database = [
            "52:54:00:72:58:b2",
        ]

        for link in ipr.filter_messages(
            {
                "ifname": lambda x: x.startswith("eth"),
                "address": lambda x: x in database,
            },
            ipr.link("dump"),
        ):
            print(link.get("ifname"))

        eth0

    … or constants to compare with:

        # get all links in state up:
        #
        for link in ipr.filter_messages(
            {"state": "up"}, ipr.link("dump"),
        ):
            print(link.get("ifname"))

        lo
        eth0

  async dump(groups=None)

    Dump network objects.

    - get_links()

    - get_addr()

    - get_neighbours()

    - get_vlans()

    - dump FDB

    - IPv4 and IPv6 rules

  async ensure(method, present=True, timeout=10, interval=0.2, **spec)

    Ensure object’s state.

    The issue with RTNL calls is that they are not synchronous: even if the kernel returns success for a call, the changes may become visible after some short time. Because of that adding dependant object immediately one after another may fail. Say, adding a route directly after the required interface address.

    Since pyroute2 RTNL API is more or less one to one mapping of the kernel RTNL, it has the same problem.

    This method aims to mitigate this issue.

    - if present == True, try to add/set an object by the spec.

    - if present == False, try to remove

    - and finally wait up to timeout for the changes to be applied.

    Example:

        interface = ipr.ensure(ipr.link,
            present=True,
            ifname='test0',
            kind='dummy',
            state='up',
        )
        ipr.ensure(ipr.addr,
            present=True,
            index=interface,
            address='192.168.0.2/24',
        )

  async poll(method, command, present=True, timeout=10, interval=0.2, **spec)

    Wait for a method to succeed.

    Run method with a positional argument command and keyword arguments **spec every interval seconds, but not more than timeout, until it returns a result which doesn’t evaluate to False.

    Example:

        # create a bridge interface and wait for it:
        #
        spec = {
            'ifname': 'br0',
            'kind': 'bridge',
            'state': 'up',
        }
        ipr.link('add', **spec)
        ret = ipr.poll(ipr.link, 'dump', **spec)

        assert ret[0].get('ifname') == 'br0'
        assert ret[0].get('flags') & 1
        assert ret[0].get('state') == 'up'
        assert ret[0].get(('linkinfo', 'kind')) == 'bridge'

  async probe(command, **kwarg)

    Run a network probe.

    The API will trigger a network probe from the environment it works in. For NetNS it will be the network namespace, for remote IPRoute instances it will be the host it runs on.

    Running probes via API allows to test network connectivity between the environments in a simple uniform way.

    Supported arguments:

    - kind – probe type, for now only ping is supported

    - dst – target to run the probe against

    - num – number of probes to run

    - timeout – timeout for the whole request

    Examples:

        ipr.probe("add", kind="ping", dst="10.0.0.1")

    By default ping probe will send one ICMP request towards the target. To change this, use num argument:

        ipr.probe(
            "add",
            kind="ping",
            dst="10.0.0.1",
            num=4,
            timeout=10
        )

    Timeout for the ping probe by default is 1 second, which may not be enough to run multiple requests.

    In the next release more probe types are planned, like TCP port probe.

  async route_dump(fd, family=AddressFamily.AF_UNSPEC, fmt='iproute2')

    Save routes as a binary dump into a file object.

    fd – an open file object, must support write() family – AF_UNSPEC, AF_INET, etc. – filter routes by family fmt – dump format, “iproute2” (default) or “raw”

    The binary dump is just a set of unparsed netlink messages. The iproute2 prepends the dump with a magic uint32, so IPRoute does the same for compatibility. If you want a raw dump without any additional magic data, use fmt=”raw”.

    This routine neither close the file object, nor uses seek() to rewind, it’s up to the user.

  async route_dumps(family=AddressFamily.AF_UNSPEC, fmt='iproute2')

    Save routes and returns as a bytes object.

    The same as .route_dump(), but returns bytes.

  async route_load(fd, fmt='iproute2')

    Load routes from a binary dump.

    fd – an open file object, must support read() fmt – dump format, “iproute2” (default) or “raw”

    The current version parses the dump and loads routes one by one. This behavior will be changed in the future to optimize the performance, but the result will be the same.

    If fmt == “iproute2”, then the loader checks the magic iproute2 prefix in the dump. Otherwise it parses the data from byte 0.

  async route_loads(data, fmt='iproute2')

    Load routes from a bytes object.

    Like .route_load(), but accepts bytes instead of an file file.

  async get_qdiscs(index=None)

    Get all queue disciplines for all interfaces or for the selected one.

    A compatibility method, == .tc(“dump”)

  async get_filters(index=0, handle=0, parent=0)

    Get filters for specified interface, handle and parent.

  async get_classes(index=0)

    Get classes for specified interface.

  async get_vlans(**kwarg)

    Dump available vlan info on bridge ports

  async get_links(*argv, **kwarg)

    Get network interfaces.

    By default returns all interfaces. Arguments vector can contain interface indices or a special keyword ‘all’:

        ip.get_links()
        ip.get_links('all')
        ip.get_links(1, 2, 3)

        interfaces = [1, 2, 3]
        ip.get_links(*interfaces)

  async get_neighbours(family=AddressFamily.AF_UNSPEC, match=None, **kwarg)

    Dump ARP cache records.

    The family keyword sets the family for the request: e.g. AF_INET or AF_INET6 for arp cache, AF_BRIDGE for fdb.

    If other keyword arguments not empty, they are used as filter. Also, one can explicitly set filter as a function with the match parameter.

    Examples:

        # get neighbours on the 3rd link:
        ip.get_neighbours(ifindex=3)

        # get a particular record by dst:
        ip.get_neighbours(dst='172.16.0.1')

        # get fdb records:
        ip.get_neighbours(AF_BRIDGE)

        # and filter them by a function:
        ip.get_neighbours(AF_BRIDGE, match=lambda x: x['state'] == 2)

  async get_ntables(family=AddressFamily.AF_UNSPEC)

    Get neighbour tables

  async get_addr(family=AddressFamily.AF_UNSPEC, match=None, **kwarg)

    Dump addresses.

    If family is not specified, both AF_INET and AF_INET6 addresses will be dumped:

        # get all addresses
        ip.get_addr()

    It is possible to apply filters on the results:

        # get addresses for the 2nd interface
        ip.get_addr(index=2)

        # get addresses with IFA_LABEL == 'eth0'
        ip.get_addr(label='eth0')

        # get all the subnet addresses on the interface, identified
        # by broadcast address (should be explicitly specified upon
        # creation)
        ip.get_addr(index=2, broadcast='192.168.1.255')

    A custom predicate can be used as a filter:

        ip.get_addr(match=lambda x: x['index'] == 1)

  async get_rules(family=AddressFamily.AF_UNSPEC, match=None, **kwarg)

    Get all rules. By default return all rules. To explicitly request the IPv4 rules use family=AF_INET.

    Example::

      ip.get_rules() # get all the rules for all families ip.get_rules(family=AF_INET6) # get only IPv6 rules

  async get_routes(family=255, match=None, **kwarg)

    Get all routes. You can specify the table. There are up to 4294967295 routing classes (tables), and the kernel returns all the routes on each request. So the routine filters routes from full output. Note the number of tables is increased from 255 in Linux 2.6+.

    Example:

        ip.get_routes()  # get all the routes for all families
        ip.get_routes(family=AF_INET6)  # get only IPv6 routes
        ip.get_routes(table=254)  # get routes from 254 table

    The default family=255 is a hack. Despite the specs, the kernel returns only IPv4 routes for AF_UNSPEC family. But it returns all the routes for all the families if one uses an invalid value here. Hack but true. And let’s hope the kernel team will not fix this bug.

  static open_file(path)

    Open a file (read only) and return its (fd, inode).

  static close_file(fd)

    Close a file that was previously opened with open_file().

  static get_pid()

    Return the PID of the current process.

  async get_netnsid(nsid=None, pid=None, fd=None, target_nsid=None)

    Return a dict containing the result of a RTM_GETNSID query. This loosely corresponds to the “ip netns list-id” command.

  async get_netns_info(list_proc=False)

    A prototype method to list available netns and associated interfaces. A bit weird to have it here and not under pyroute2.netns, but it uses RTNL to get all the info.

  set_netnsid(nsid=None, pid=None, fd=None)

    Assigns an id to a peer netns using RTM_NEWNSID query. The kernel chooses an unique id if nsid is omitted. This corresponds to the “ip netns set” command.

  async get_default_routes(family=AddressFamily.AF_UNSPEC, table=254)

    Get default routes

  async link_lookup(match=None, **kwarg)

    Lookup interface index (indeces) by first level NLA value.

    Example:

        ip.link_lookup(address="52:54:00:9d:4e:3d")
        ip.link_lookup(ifname="lo")
        ip.link_lookup(operstate="UP")

    Please note, that link_lookup() returns list, not one value.

  async flush_routes(*argv, **kwarg)

    Flush routes – purge route records from a table. Arguments are the same as for get_routes() routine. Actually, this routine implements a pipe from get_routes() to nlm_request().

  async flush_addr(*argv, **kwarg)

    Flush IP addresses.

    Examples:

        # flush all addresses on the interface with index 2:
        ipr.flush_addr(index=2)

        # flush all addresses with IFA_LABEL='eth0':
        ipr.flush_addr(label='eth0')

  async flush_rules(*argv, **kwarg)

    Flush rules. Please keep in mind, that by default the function operates on all rules of all families. To work only on IPv4 rules, one should explicitly specify family=AF_INET.

    Examples:

        # flush all IPv4 rule with priorities above 5 and below 32000
        ipr.flush_rules(family=AF_INET, priority=lambda x: 5 < x < 32000)

        # flush all IPv6 rules that point to table 250:
        ipr.flush_rules(family=socket.AF_INET6, table=250)

  async brport(command, **kwarg)

    Set bridge port parameters. Example:

        idx = ip.link_lookup(ifname='eth0')
        ip.brport("set", index=idx, unicast_flood=0, cost=200)
        ip.brport("show", index=idx)

    Possible keywords are NLA names for the protinfo_bridge class, without the prefix and in lower letters.

  async vlan_filter(command, **kwarg)

    Vlan filters is another approach to support vlans in Linux. Before vlan filters were introduced, there was only one way to bridge vlans: one had to create vlan interfaces and then add them as ports:

    It means that one has to create as many bridges, as there were vlans. Vlan filters allow to bridge together underlying interfaces and create vlans already on the bridge:

    In this example vlan 500 will be allowed only on ports eth0 and eth2, though all three eth nics are bridged.

    Some example code:

        # create bridge
        ip.link("add",
                ifname="br0",
                kind="bridge")

        # attach a port
        ip.link("set",
                index=ip.link_lookup(ifname="eth0")[0],
                master=ip.link_lookup(ifname="br0")[0])

        # set vlan filter
        ip.vlan_filter("add",
                       index=ip.link_lookup(ifname="eth0")[0],
                       vlan_info={"vid": 500})

        # create vlan interface on the bridge
        ip.link("add",
                ifname="br0v500",
                kind="vlan",
                link=ip.link_lookup(ifname="br0")[0],
                vlan_id=500)

        # set all UP
        ip.link("set",
                index=ip.link_lookup(ifname="br0")[0],
                state="up")
        ip.link("set",
                index=ip.link_lookup(ifname="br0v500")[0],
                state="up")
        ip.link("set",
                index=ip.link_lookup(ifname="eth0")[0],
                state="up")

        # set IP address
        ip.addr("add",
                index=ip.link_lookup(ifname="br0v500")[0],
                address="172.16.5.2",
                mask=24)

        Now all the traffic to the network 172.16.5.2/24 will go
        to vlan 500 only via ports that have such vlan filter.

    Required arguments for vlan_filter(): index and vlan_info.

    Vlan info dict:

        ip.vlan_filter('add',
                        index=<ifindex>,
                        vlan_info =
                        {'vid': <single or range>,
                        'pvid': <bool>,
                        'flags': int or list}

    More details:

      - kernel:Documentation/networking/switchdev.txt

      - pyroute2.netlink.rtnl.ifinfmsg:… vlan_info

    Setting PVID or specifying a range will specify the approprate flags.

    One can specify flags as int or as a list of flag names:

      - master == 0x1

      - pvid == 0x2

      - untagged == 0x4

      - range_begin == 0x8

      - range_end == 0x10

      - brentry == 0x20

    E.g.:

        {'vid': 20, 'pvid': true }

        # is equal to
        {'vid': 20, 'flags': ['pvid', 'untagged']}

        # is equal to
        {'vid': 20, 'flags': 6}

        # range
        {'vid': '100-199'}

    Required arguments for vlan_filter(): index and vlan_tunnel_info.

    Vlan tunnel info dict:

        ip.vlan_filter('add',
                      index=<ifindex>,
                      vlan_tunnel_info =
                      {'vid': <single or range>,
                      'id': <single or range>}

    vlan_tunnel_info appears to only use the ‘range_begin’ and ‘range_end’ flags from vlan_info. Specifying a range will automatically send the needed flags.

    Example:

        {'vid': 20, 'id: 20}
        {'vid': '200-299', 'id': '200-299'}

    The above directives can be combined as in the example:

        ip.vlan_filter('add',
                      index=7,
                      vlan_info={'vid': 600},
                      vlan_tunnel_info={'vid': 600, 'id': 600})

    Commands:

    add

    Add vlan filter to a bridge port. Example:

        ip.vlan_filter("add", index=2, vlan_info={"vid": 200})

    del

    Remove vlan filter from a bridge port. Example:

        ip.vlan_filter("del", index=2, vlan_info={"vid": 200})

  async fdb(command, **kwarg)

    Bridge forwarding database management.

    More details:

      - kernel:Documentation/networking/switchdev.txt

      - pyroute2.netlink.rtnl.ndmsg

    add

    Add a new FDB record. Works in the same way as ARP cache management, but some additional NLAs can be used:

        # simple FDB record
        #
        ip.fdb('add',
               ifindex=ip.link_lookup(ifname='br0')[0],
               lladdr='00:11:22:33:44:55',
               dst='10.0.0.1')

        # specify vlan
        # NB: vlan should exist on the device, use
        # `vlan_filter()`
        #
        ip.fdb('add',
               ifindex=ip.link_lookup(ifname='br0')[0],
               lladdr='00:11:22:33:44:55',
               dst='10.0.0.1',
               vlan=200)

        # specify vxlan id and port
        # NB: works only for vxlan devices, use
        # `link("add", kind="vxlan", ...)`
        #
        # if port is not specified, the default one is used
        # by the kernel.
        #
        # if vni (vxlan id) is equal to the device vni,
        # the kernel doesn't report it back
        #
        ip.fdb('add',
               ifindex=ip.link_lookup(ifname='vx500')[0]
               lladdr='00:11:22:33:44:55',
               dst='10.0.0.1',
               port=5678,
               vni=600)

        # or specify src_vni for a vlan-aware vxlan device
        ip.fdb('add',
               ifindex=ip.link_lookup(ifname='vx500')[0]
               lladdr='00:11:22:33:44:55',
               dst='10.0.0.1',
               port=5678,
               src_vni=600)

    append

    Append a new FDB record. The same syntax as for add.

    del

    Remove an existing FDB record. The same syntax as for add.

    dump

    Dump all the FDB records. If any **kwarg is provided, results will be filtered:

        # dump all the records
        ip.fdb('dump')

        # show only specific lladdr, dst, vlan etc.
        ip.fdb('dump', lladdr='00:11:22:33:44:55')
        ip.fdb('dump', dst='10.0.0.1')
        ip.fdb('dump', vlan=200)

  async neigh(command, **kwarg)

    Neighbours operations, same as ip neigh or bridge fdb

    add

    Add a neighbour record, e.g.:

        from pyroute2 import IPRoute
        from pyroute2.netlink.rtnl import ndmsg

        # add a permanent record on veth0
        idx = ip.link_lookup(ifname='veth0')[0]
        ip.neigh('add',
                 dst='172.16.45.1',
                 lladdr='00:11:22:33:44:55',
                 ifindex=idx,
                 state=ndmsg.states['permanent'])

    set

    Set an existing record or create a new one, if it doesn’t exist. The same as above, but the command is “set”:

        ip.neigh('set',
                 dst='172.16.45.1',
                 lladdr='00:11:22:33:44:55',
                 ifindex=idx,
                 state=ndmsg.states['permanent'])

    change

    Change an existing record. If the record doesn’t exist, fail.

    del

    Delete an existing record.

    dump

    Dump all the records in the NDB:

        ip.neigh('dump')

    get

    Get specific record (dst and ifindex are mandatory). Available only on recent kernel:

        ip.neigh('get',
                 dst='172.16.45.1',
                 ifindex=idx)

  async link(command, **kwarg)

    Link operations.

    Keywords to set up ifinfmsg fields:

      - index – interface index

      - family – AF_BRIDGE for bridge operations, otherwise 0

      - flags – device flags

      - change – change mask

    All other keywords will be translated to NLA names, e.g. mtu -> IFLA_MTU, af_spec -> IFLA_AF_SPEC etc. You can provide a complete NLA structure or let filters do it for you. E.g., these pairs show equal statements:

        # set device MTU
        ip.link("set", index=x, mtu=1000)
        ip.link("set", index=x, IFLA_MTU=1000)

        # add vlan device
        ip.link("add", ifname="test", kind="dummy")
        ip.link("add", ifname="test",
                IFLA_LINKINFO={'attrs': [['IFLA_INFO_KIND', 'dummy']]})

    Filters are implemented in the pyroute2.iproute.req module. You can contribute your own if you miss shortcuts.

    Commands:

    add

    To create an interface, one should specify the interface kind:

        ip.link("add",
                ifname="test",
                kind="dummy")

    The kind can be any of those supported by kernel. It can be dummy, bridge, bond etc. On modern kernels one can specify even interface index:

        ip.link("add",
                ifname="br-test",
                kind="bridge",
                index=2345)

    Specific type notes:

    ► geneve

    Create GENEVE tunnel:

        ip.link("add",
                ifname="genx",
                kind="geneve",
                geneve_id=42,
                geneve_remote="172.16.0.101")

    Support for GENEVE over IPv6 is also included; use geneve_remote6 to configure a remote IPv6 address.

    ► gre

    Create GRE tunnel:

        ip.link("add",
                ifname="grex",
                kind="gre",
                gre_local="172.16.0.1",
                gre_remote="172.16.0.101",
                gre_ttl=16)

    The keyed GRE requires explicit iflags/oflags specification:

        ip.link("add",
                ifname="grex",
                kind="gre",
                gre_local="172.16.0.1",
                gre_remote="172.16.0.101",
                gre_ttl=16,
                gre_ikey=10,
                gre_okey=10,
                gre_iflags=32,
                gre_oflags=32)

    Support for GRE over IPv6 is also included; use kind=ip6gre and ip6gre_ as the prefix for its values.

    ► ipip

    Create ipip tunnel:

        ip.link("add",
                ifname="tun1",
                kind="ipip",
                ipip_local="172.16.0.1",
                ipip_remote="172.16.0.101",
                ipip_ttl=16)

    Support for sit and ip6tnl is also included; use kind=sit and sit_ as prefix for sit tunnels, and kind=ip6tnl and ip6tnl_ prefix for ip6tnl tunnels.

    ► macvlan

    Macvlan interfaces act like VLANs within OS. The macvlan driver provides an ability to add several MAC addresses on one interface, where every MAC address is reflected with a virtual interface in the system.

    In some setups macvlan interfaces can replace bridge interfaces, providing more simple and at the same time high-performance solution:

        ip.link("add",
                ifname="mvlan0",
                kind="macvlan",
                link=ip.link_lookup(ifname="em1")[0],
                macvlan_mode="private").commit()

    Several macvlan modes are available: “private”, “vepa”, “bridge”, “passthru”. Ususally the default is “vepa”.

    ► macvtap

    Almost the same as macvlan, but creates also a character tap device:

        ip.link("add",
                ifname="mvtap0",
                kind="macvtap",
                link=ip.link_lookup(ifname="em1")[0],
                macvtap_mode="vepa").commit()

    Will create a device file “/dev/tap%s” % index

    ► tuntap

    Possible tuntap keywords:

    - mode — “tun” or “tap”

    - uid — integer

    - gid — integer

    - ifr — dict of tuntap flags (see ifinfmsg:… tuntap_data)

    Create a tap interface:

        ip.link("add",
                ifname="tap0",
                kind="tuntap",
                mode="tap")

    Tun/tap interfaces are created using ioctl(), but the library provides a transparent way to manage them using netlink API.

    ► veth

    To properly create veth interface, one should specify peer also, since veth interfaces are created in pairs:

        # simple call
        ip.link("add", ifname="v1p0", kind="veth", peer="v1p1")

        # set up specific veth peer attributes
        ip.link("add",
                ifname="v1p0",
                kind="veth",
                peer={"ifname": "v1p1",
                      "net_ns_fd": "test_netns"})

    ► vlan

    VLAN interfaces require additional parameters, vlan_id and link, where link is a master interface to create VLAN on:

        ip.link("add",
                ifname="v100",
                kind="vlan",
                link=ip.link_lookup(ifname="eth0")[0],
                vlan_id=100)

    There is a possibility to create also 802.1ad interfaces:

        # create external vlan 802.1ad, s-tag
        ip.link("add",
                ifname="v100s",
                kind="vlan",
                link=ip.link_lookup(ifname="eth0")[0],
                vlan_id=100,
                vlan_protocol=0x88a8)

        # create internal vlan 802.1q, c-tag
        ip.link("add",
                ifname="v200c",
                kind="vlan",
                link=ip.link_lookup(ifname="v100s")[0],
                vlan_id=200,
                vlan_protocol=0x8100)

    ► vrf

    VRF interfaces (see linux/Documentation/networking/vrf.txt):

        ip.link("add",
                ifname="vrf-foo",
                kind="vrf",
                vrf_table=42)

    ► vxlan

    VXLAN interfaces are like VLAN ones, but require a bit more parameters:

        ip.link("add",
                ifname="vx101",
                kind="vxlan",
                vxlan_link=ip.link_lookup(ifname="eth0")[0],
                vxlan_id=101,
                vxlan_group='239.1.1.1',
                vxlan_ttl=16)

    All possible vxlan parameters are listed in the module pyroute2.netlink.rtnl.ifinfmsg:… vxlan_data.

    ► ipoib

    IPoIB driver provides an ability to create several ip interfaces on one interface. IPoIB interfaces requires the following parameter:

    link : The master interface to create IPoIB on.

    The following parameters can also be provided:

    - pkey- Inifiniband partition key the ip interface is associated with

    - mode- Underlying infiniband transport mode. One of: [‘datagram’ ,’connected’]

    - umcast- If set(1), multicast group membership for this interface is handled by user space.

    Example:

        ip.link("add",
                ifname="ipoib1",
                kind="ipoib",
                link=ip.link_lookup(ifname="ib0")[0],
                pkey=10)

    set

    Set interface attributes:

        # get interface index
        x = ip.link_lookup(ifname="eth0")[0]
        # put link down
        ip.link("set", index=x, state="down")
        # rename and set MAC addr
        ip.link("set", index=x, address="00:11:22:33:44:55", name="bala")
        # set MTU and TX queue length
        ip.link("set", index=x, mtu=1000, txqlen=2000)
        # bring link up
        ip.link("set", index=x, state="up")

    Seting bridge or tunnel attributes require kind to be specified in order to properly encode IFLA_LINKINFO:

        ip.link("set",
                index=x,
                kind="bridge",
                br_forward_delay=2000)

        ip.link("set",
                index=x,
                kind="gre",
                gre_local="10.0.0.1",
                gre_remote="10.1.0.103")

    Keyword “state” is reserved. State can be “up” or “down”, it is a shortcut:

        state="up":   flags=1, change=1
        state="down": flags=0, change=1

    SR-IOV virtual function setup:

        # get PF index
        x = ip.link_lookup(ifname="eth0")[0]
        # setup macaddr
        ip.link("set",
                index=x,                          # PF index
                vf={"vf": 0,                      # VF index
                    "mac": "00:11:22:33:44:55"})  # address
        # setup vlan
        ip.link("set",
                index=x,           # PF index
                vf={"vf": 0,       # VF index
                    "vlan": 100})  # the simplest case
        # setup QinQ
        ip.link("set",
                index=x,                           # PF index
                vf={"vf": 0,                       # VF index
                    "vlan": [{"vlan": 100,         # vlan id
                              "proto": 0x88a8},    # 802.1ad
                             {"vlan": 200,         # vlan id
                              "proto": 0x8100}]})  # 802.1q

    update

    Almost the same as set, except it uses different flags and message type. Mostly does the same, but in some cases differs. If you’re not sure what to use, use set.

    del

    Destroy the interface:

        ip.link("del", index=ip.link_lookup(ifname="dummy0")[0])

    dump

    Dump info for all interfaces

    get

    Get specific interface info:

        ip.link("get", index=ip.link_lookup(ifname="br0")[0])

    Get extended attributes like SR-IOV setup:

        ip.link("get", index=3, ext_mask=1)

  async addr(command, **kwarg)

    Address operations

    - command – add, delete, replace, dump

    - index – device index

    - address – IPv4 or IPv6 address

    - mask – address mask

    - family – socket.AF_INET for IPv4 or socket.AF_INET6 for IPv6

    - scope – the address scope, see /etc/iproute2/rt_scopes

    - kwarg – dictionary, any ifaddrmsg field or NLA

    Later the method signature will be changed to:

        def addr(self, command, match=None, **kwarg):
            # the method body

    So only keyword arguments (except of the command) will be accepted. The reason for this change is an unification of API.

    Example:

        idx = 62
        ip.addr('add', index=idx, address='10.0.0.1', mask=24)
        ip.addr('add', index=idx, address='10.0.0.2', mask=24)

    With more NLAs:

        # explicitly set broadcast address
        ip.addr('add', index=idx,
                address='10.0.0.3',
                broadcast='10.0.0.255',
                prefixlen=24)

        # make the secondary address visible to ifconfig: add label
        ip.addr('add', index=idx,
                address='10.0.0.4',
                broadcast='10.0.0.255',
                prefixlen=24,
                label='eth0:1')

    Configure p2p address on an interface:

        ip.addr('add', index=idx,
                address='10.1.1.2',
                mask=24,
                local='10.1.1.1')

  async tc(command, kind=None, index=None, handle=None, **kwarg)

    “Swiss knife” for traffic control. With the method you can dump, add, delete or modify qdiscs, classes and filters.

    - command – add or delete qdisc, class, filter.

    - kind – a string identifier – “sfq”, “htb”, “u32” and so on.

    - handle – integer or string

    Command can be one of (“add”, “del”, “add-class”, “del-class”, “add-filter”, “del-filter”) (see commands dict in the code).

    Handle notice: traditional iproute2 notation, like “1:0”, actually represents two parts in one four-bytes integer:

        1:0    ->    0x10000
        1:1    ->    0x10001
        ff:0   ->   0xff0000
        ffff:1 -> 0xffff0001

    Target notice: if your target is a class/qdisc that applies an algorithm that can only apply to upstream traffic profile, but your keys variable explicitly references a match that is only relevant for upstream traffic, the kernel will reject the filter. Unless you’re dealing with devices like IMQs

    For pyroute2 tc() you can use both forms: integer like 0xffff0000 or string like ‘ffff:0000’. By default, handle is 0, so you can add simple classless queues w/o need to specify handle. Ingress queue causes handle to be 0xffff0000.

    So, to set up sfq queue on interface 1, the function call will be like that:

        ip = IPRoute()
        ip.tc("add", "sfq", 1)

    Instead of string commands (“add”, “del”…), you can use also module constants, RTM_NEWQDISC, RTM_DELQDISC and so on:

        ip = IPRoute()
        flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL
        ip.tc((RTM_NEWQDISC, flags), "sfq", 1)

    It should be noted that “change”, “change-class” and “change-filter” work like “replace”, “replace-class” and “replace-filter”, except they will fail if the node doesn’t exist (while it would have been created by “replace”). This is not the same behaviour as with “tc” where “change” can be used to modify the value of some options while leaving the others unchanged. However, as not all entities support this operation, we believe the “change” commands as implemented here are more useful.

    Also available “modules” (returns tc plugins dict) and “help” commands:

        help(ip.tc("modules")["htb"])
        print(ip.tc("help", "htb"))

  async route(command, **kwarg)

    Route operations.

    Keywords to set up rtmsg fields:

    - dst_len, src_len – destination and source mask(see dst below)

    - tos – type of service

    - table – routing table

    - proto – redirect, boot, static (see rt_proto)

    - scope – routing realm

    - type – unicast, local, etc. (see rt_type)

    pyroute2/netlink/rtnl/rtmsg.py rtmsg.nla_map:

    - table – routing table to use (default: 254)

    - gateway – via address

    - prefsrc – preferred source IP address

    - dst – the same as prefix

    - iif – incoming traffic interface

    - oif – outgoing traffic interface

    etc.

    One can specify mask not as dst_len, but as a part of dst, e.g.: dst=”10.0.0.0/24”.

    Commands:

    add

    Example:

        ipr.route("add", dst="10.0.0.0/24", gateway="192.168.0.1")

    …

    More route() examples. Blackhole route:

        ipr.route(
            "add",
            dst="10.0.0.0/24",
            type="blackhole",
        )

    Create a route with metrics:

        ipr.route(
            "add",
            dst="172.16.0.0/24",
            gateway="10.0.0.10",
            metrics={
                "mtu": 1400,
                "hoplimit": 16,
            },
        )

    Multipath route:

        ipr.route(
            "add",
            dst="10.0.0.0/24",
            multipath=[
                {"gateway": "192.168.0.1", "hops": 2},
                {"gateway": "192.168.0.2", "hops": 1},
                {"gateway": "192.168.0.3"},
            ],
        )

    MPLS lwtunnel on eth0:

        ipr.route(
            "add",
            dst="10.0.0.0/24",
            oif=ipr.link_lookup(ifname="eth0"),
            encap={
                "type": "mpls",
                "labels": "200/300",
            },
        )

    IPv6 next hop for IPv4 dst:

        ipr.route(
            "add",
            prefsrc="10.127.30.4",
            dst="172.16.0.0/24",
            via={"family": AF_INET6, "addr": "fe80::1337"},
            oif=ipr.link_lookup(ifname="eth0"),
            table=100,
        )

    Create MPLS route: push label:

        # $ sudo modprobe mpls_router
        # $ sudo sysctl net.mpls.platform_labels=1024
        ipr.route(
            "add",
            family=AF_MPLS,
            oif=ipr.link_lookup(ifname="eth0"),
            dst=0x200,
            newdst=[0x200, 0x300],
        )

    MPLS multipath:

        ipr.route(
            "add",
            dst="10.0.0.0/24",
            table=20,
            multipath=[
                {
                    "gateway": "192.168.0.1",
                    "encap": {"type": "mpls", "labels": 200},
                },
                {
                    "ifindex": ipr.link_lookup(ifname="eth0"),
                    "encap": {"type": "mpls", "labels": 300},
                },
            ],
        )

    MPLS target can be int, string, dict or list:

        "labels": 300    # simple label
        "labels": "300"  # the same
        "labels": (200, 300)  # stacked
        "labels": "200/300"   # the same

        # explicit label definition
        "labels": {
            "bos": 1,
            "label": 300,
            "tc": 0,
            "ttl": 16,
        }

    Create SEG6 tunnel encap mode (kernel >= 4.10):

        ipr.route(
            "add",
            dst="2001:0:0:10::2/128",
            oif=idx,
            encap={
                "type": "seg6",
                "mode": "encap",
                "segs": "2000::5,2000::6",
            },
        )

    Create SEG6 tunnel inline mode (kernel >= 4.10):

        ipr.route(
            "add",
            dst="2001:0:0:10::2/128",
            oif=idx,
            encap={
                "type": "seg6",
                "mode": "inline",
                "segs": ["2000::5", "2000::6"],
            },
        )

    Create SEG6 tunnel inline mode with hmac (kernel >= 4.10):

        ipr.route(
            "add",
            dst="2001:0:0:22::2/128",
            oif=idx,
            encap={
                "type": "seg6",
                "mode": "inline",
                "segs": "2000::5,2000::6,2000::7,2000::8",
                "hmac": 0xf,
            },
        )

    Create SEG6 tunnel with ip4ip6 encapsulation (kernel >= 4.14):

        ipr.route(
            "add",
            dst="172.16.0.0/24",
            oif=idx,
            encap={
                "type": "seg6",
                "mode": "encap",
                "segs": "2000::5,2000::6",
            },
        )

    Create SEG6LOCAL tunnel End.DX4 action (kernel >= 4.14):

        ipr.route(
            "add",
            dst="2001:0:0:10::2/128",
            oif=idx,
            encap={
                "type": "seg6local",
                "action": "End.DX4",
                "nh4": "172.16.0.10",
            },
        )

    Create SEG6LOCAL tunnel End.DT6 action (kernel >= 4.14):

        ipr.route(
            "add",
            dst="2001:0:0:10::2/128",
            oif=idx,
            encap={
                "type": "seg6local",
                "action": "End.DT6",
                "table": "10",
            },
        )

    Create SEG6LOCAL tunnel End.DT4 action (kernel >= 5.11):

        # $ sudo modprobe vrf
        # $ sudo sysctl -w net.vrf.strict_mode=1
        ipr.link(
            "add",
            ifname="vrf-foo",
            kind="vrf",
            vrf_table=10,
        )
        ipr.route(
            "add",
            dst="2001:0:0:10::2/128",
            oif=idx,
            encap={
                "type": "seg6local",
                "action": "End.DT4",
                "vrf_table": 10,
            },
        )

    Create SEG6LOCAL tunnel End.DT46 action (kernel >= 5.14):

        # $ sudo modprobe vrf
        # $ sudo sysctl -w net.vrf.strict_mode=1

        ip.link('add',
                ifname='vrf-foo',
                kind='vrf',
                vrf_table=10)

        ip.route('add',
                 dst='2001:0:0:10::2/128',
                 oif=idx,
                 encap={'type': 'seg6local',
                        'action': 'End.DT46',
                        'vrf_table': 10})

    Create SEG6LOCAL tunnel End.B6 action (kernel >= 4.14):

        ipr.route(
            "add",
            dst="2001:0:0:10::2/128",
            oif=idx,
            encap={
                "type": "seg6local",
                "action": "End.B6",
                "srh": {"segs": "2000::5,2000::6"},
            },
        )

    Create SEG6LOCAL tunnel End.B6 action with hmac (kernel >= 4.14):

        ipr.route(
            "add",
            dst="2001:0:0:10::2/128",
            oif=idx,
            encap={
                "type": "seg6local",
                "action": "End.B6",
                "srh": {
                    "segs": "2000::5,2000::6",
                    "hmac": 0xf,
                },
            },
        )

    change, replace, append

    Commands change, replace and append have the same meanings as in ip-route(8): change modifies only existing route, while replace creates a new one, if there is no such route yet. append allows to create an IPv6 multipath route.

    del

    Remove the route. The same syntax as for add.

    get

    Get route by spec.

    dump

    Dump all routes.

  async rule(command, **kwarg)

    Rule operations

    > - command — add, delete

    > - table — 0 < table id < 253

    > - priority — 0 < rule’s priority < 32766

    > - action — type of rule, default ‘FR_ACT_NOP’ (see fibmsg.py)

    > - rtscope — routing scope, default RT_SCOPE_UNIVERSE

    >     (RT_SCOPE_UNIVERSE|RT_SCOPE_SITE| RT_SCOPE_LINK|RT_SCOPE_HOST|RT_SCOPE_NOWHERE)

    > - family — rule’s family (socket.AF_INET (default) or

    >     socket.AF_INET6)

    > - src — IP source for Source Based (Policy Based) routing’s rule

    > - dst — IP for Destination Based (Policy Based) routing’s rule

    > - src_len — Mask for Source Based (Policy Based) routing’s rule

    > - dst_len — Mask for Destination Based (Policy Based) routing’s

    >     rule

    > - iifname — Input interface for Interface Based (Policy Based)

    >     routing’s rule

    > - oifname — Output interface for Interface Based (Policy Based)

    >     routing’s rule

    > - uid_range — Range of user identifiers, a string like “1000:1234”

    > - dport_range — Range of destination ports, a string like “80-120”

    > - sport_range — Range of source ports, as a string like “80-120”

    All packets route via table 10:

        # 32000: from all lookup 10
        # ...
        ip.rule('add', table=10, priority=32000)

    Default action:

        # 32001: from all lookup 11 unreachable
        # ...
        iproute.rule('add',
                     table=11,
                     priority=32001,
                     action='FR_ACT_UNREACHABLE')

    Use source address to choose a routing table:

        # 32004: from 10.64.75.141 lookup 14
        # ...
        iproute.rule('add',
                     table=14,
                     priority=32004,
                     src='10.64.75.141')

    Use dst address to choose a routing table:

        # 32005: from 10.64.75.141/24 lookup 15
        # ...
        iproute.rule('add',
                     table=15,
                     priority=32005,
                     dst='10.64.75.141',
                     dst_len=24)

    Match fwmark:

        # 32006: from 10.64.75.141 fwmark 0xa lookup 15
        # ...
        iproute.rule('add',
                     table=15,
                     priority=32006,
                     dst='10.64.75.141',
                     fwmark=10)

  async stats(command, **kwarg)

    Stats prototype.