NLMSG_ERROR responses — pyroute2 0.9.4 documentation

# NLMSG_ERROR responses

Some kernel subsystems return NLMSG_ERROR in response to any request. This is acceptable as long as nlmsg["header"]["error"] is None. If it is not None, an exception will be raised by the parser.

If you receive an NLMSG_ERROR message instead of an exception, it means error == 0, which is equivalent to $? == 0 in bash.

# How to work with messages

Every netlink message contains a header, fields, and NLAs (netlink attributes). Each NLA is itself a netlink message (see "recursion").

The library parses messages according to this structure. Each RTNL message includes the following:

- nlmsg['header'] -- parsed header

- nlmsg['attrs'] -- NLA chain (parsed on demand)

- data fields, e.g. nlmsg['flags'] etc.

- nlmsg.header -- the header fields spec

- nlmsg.fields -- the data fields spec

- nlmsg.nla_map -- NLA spec

One key feature of the parser is that NLAs are parsed only on demand, i.e., when accessed. This prevents unnecessary CPU usage.

The NLA chain is a list-like structure rather than a dictionary because the netlink standard does not require NLAs to be unique within a single message:

    {'attrs': [('IFLA_IFNAME', 'lo'),    # [1]
               ('IFLA_TXQLEN', 1),
               ('IFLA_OPERSTATE', 'UNKNOWN'),
               ('IFLA_LINKMODE', 0),
               ('IFLA_MTU', 65536),
               ('IFLA_GROUP', 0),
               ('IFLA_PROMISCUITY', 0),
               ('IFLA_NUM_TX_QUEUES', 1),
               ('IFLA_NUM_RX_QUEUES', 1),
               ('IFLA_CARRIER', 1),
               ...],
     'change': 0,
     'event': 'RTM_NEWLINK',             # [2]
     'family': 0,
     'flags': 65609,
     'header': {'error': None,           # [3]
                'flags': 2,
                'length': 1180,
                'pid': 28233,
                'sequence_number': 257,  # [4]
                'type': 16},             # [5]
     'ifi_type': 772,
     'index': 1}

     # [1] every NLA is parsed upon access
     # [2] this field is injected by the RTNL parser
     # [3] if not None, an exception will be raised
     # [4] more details in the netlink description
     # [5] 16 == RTM_NEWLINK

To access fields or NLAs, use the .get() method. To retrieve nested NLAs, pass a tuple of NLA names to the .get() call to navigate through the hierarchy:

    from pyroute2 import IPRoute

    with IPRoute() as ipr:
        lo = tuple(ipr.link("get", index=1))[0]
        # get a field
        assert lo.get("index") == 1
        # get an NLA
        assert lo.get("ifname") == "lo"
        # get a nested NLA
        assert lo.get(("stats64", "rx_bytes")) == 43309665

If an NLA with the specified name is not present in the chain, .get() returns None. To retrieve a list of all NLAs with the specified name, use .get_attrs().

Below is an example demonstrating the usage of .get() and .get_attrs() with an NLA hierarchy:

    # for macvlan interfaces there may be several
    # IFLA_MACVLAN_MACADDR NLA provided, so use
    # get_attrs() to get all the list, not only
    # the first one

    (msg
     .get('IFLA_LINKINFO')                # one NLA
     .get('IFLA_INFO_DATA')               # one NLA
     .get_attrs('IFLA_MACVLAN_MACADDR'))  # a list of

The protocol itself does not impose a limit on the number of NLAs of the same type within a single message. This is why we cannot represent them as a dictionary, unlike with PF_ROUTE messages.