Home | History | Annotate | Download | only in route
      1 /*
      2  * lib/route/link.c	Links (Interfaces)
      3  *
      4  *	This library is free software; you can redistribute it and/or
      5  *	modify it under the terms of the GNU Lesser General Public
      6  *	License as published by the Free Software Foundation version 2.1
      7  *	of the License.
      8  *
      9  * Copyright (c) 2003-2008 Thomas Graf <tgraf (at) suug.ch>
     10  */
     11 
     12 /**
     13  * @ingroup rtnl
     14  * @defgroup link Links (Interfaces)
     15  * @brief
     16  *
     17  * @par Link Identification
     18  * A link can be identified by either its interface index or by its
     19  * name. The kernel favours the interface index but falls back to the
     20  * interface name if the interface index is lesser-than 0 for kernels
     21  * >= 2.6.11. Therefore you can request changes without mapping a
     22  * interface name to the corresponding index first.
     23  *
     24  * @par Changeable Attributes
     25  * @anchor link_changeable
     26  *  - Link layer address
     27  *  - Link layer broadcast address
     28  *  - device mapping (ifmap) (>= 2.6.9)
     29  *  - MTU (>= 2.6.9)
     30  *  - Transmission queue length (>= 2.6.9)
     31  *  - Weight (>= 2.6.9)
     32  *  - Link name (only via access through interface index) (>= 2.6.9)
     33  *  - Flags (>= 2.6.9)
     34  *    - IFF_DEBUG
     35  *    - IFF_NOTRAILERS
     36  *    - IFF_NOARP
     37  *    - IFF_DYNAMIC
     38  *    - IFF_MULTICAST
     39  *    - IFF_PORTSEL
     40  *    - IFF_AUTOMEDIA
     41  *    - IFF_UP
     42  *    - IFF_PROMISC
     43  *    - IFF_ALLMULTI
     44  *
     45  * @par Link Flags (linux/if.h)
     46  * @anchor link_flags
     47  * @code
     48  *   IFF_UP            Status of link (up|down)
     49  *   IFF_BROADCAST     Indicates this link allows broadcasting
     50  *   IFF_MULTICAST     Indicates this link allows multicasting
     51  *   IFF_ALLMULTI      Indicates this link is doing multicast routing
     52  *   IFF_DEBUG         Tell the driver to do debugging (currently unused)
     53  *   IFF_LOOPBACK      This is the loopback link
     54  *   IFF_POINTOPOINT   Point-to-point link
     55  *   IFF_NOARP         Link is unable to perform ARP
     56  *   IFF_PROMISC       Status of promiscious mode flag
     57  *   IFF_MASTER        Used by teql
     58  *   IFF_SLAVE         Used by teql
     59  *   IFF_PORTSEL       Indicates this link allows port selection
     60  *   IFF_AUTOMEDIA     Indicates this link selects port automatically
     61  *   IFF_DYNAMIC       Indicates the address of this link is dynamic
     62  *   IFF_RUNNING       Link is running and carrier is ok.
     63  *   IFF_NOTRAILERS    Unused, BSD compat.
     64  * @endcode
     65  *
     66  * @par Notes on IFF_PROMISC and IFF_ALLMULTI flags
     67  * Although you can query the status of IFF_PROMISC and IFF_ALLMULTI
     68  * they do not represent the actual state in the kernel but rather
     69  * whether the flag has been enabled/disabled by userspace. The link
     70  * may be in promiscious mode even if IFF_PROMISC is not set in a link
     71  * dump request response because promiscity might be needed by the driver
     72  * for a period of time.
     73  *
     74  * @note The unit of the transmission queue length depends on the
     75  *       link type, a common unit is \a packets.
     76  *
     77  * @par 1) Retrieving information about available links
     78  * @code
     79  * // The first step is to retrieve a list of all available interfaces within
     80  * // the kernel and put them into a cache.
     81  * struct nl_cache *cache = rtnl_link_alloc_cache(sk);
     82  *
     83  * // In a second step, a specific link may be looked up by either interface
     84  * // index or interface name.
     85  * struct rtnl_link *link = rtnl_link_get_by_name(cache, "lo");
     86  *
     87  * // rtnl_link_get_by_name() is the short version for translating the
     88  * // interface name to an interface index first like this:
     89  * int ifindex = rtnl_link_name2i(cache, "lo");
     90  * struct rtnl_link *link = rtnl_link_get(cache, ifindex);
     91  *
     92  * // After successful usage, the object must be given back to the cache
     93  * rtnl_link_put(link);
     94  * @endcode
     95  *
     96  * @par 2) Changing link attributes
     97  * @code
     98  * // In order to change any attributes of an existing link, we must allocate
     99  * // a new link to hold the change requests:
    100  * struct rtnl_link *request = rtnl_link_alloc();
    101  *
    102  * // Now we can go on and specify the attributes we want to change:
    103  * rtnl_link_set_weight(request, 300);
    104  * rtnl_link_set_mtu(request, 1360);
    105  *
    106  * // We can also shut an interface down administratively
    107  * rtnl_link_unset_flags(request, rtnl_link_str2flags("up"));
    108  *
    109  * // Actually, we should know which link to change, so let's look it up
    110  * struct rtnl_link *old = rtnl_link_get(cache, "eth0");
    111  *
    112  * // Two ways exist to commit this change request, the first one is to
    113  * // build the required netlink message and send it out in one single
    114  * // step:
    115  * rtnl_link_change(sk, old, request);
    116  *
    117  * // An alternative way is to build the netlink message and send it
    118  * // out yourself using nl_send_auto_complete()
    119  * struct nl_msg *msg = rtnl_link_build_change_request(old, request);
    120  * nl_send_auto_complete(sk, nlmsg_hdr(msg));
    121  * nlmsg_free(msg);
    122  *
    123  * // Don't forget to give back the link object ;->
    124  * rtnl_link_put(old);
    125  * @endcode
    126  *
    127  * @par 3) Link Type Specific Attributes
    128  * @code
    129  * // Some link types offer additional parameters and statistics specific
    130  * // to their type. F.e. a VLAN link can be configured like this:
    131  * //
    132  * // Allocate a new link and set the info type to "vlan". This is required
    133  * // to prepare the link to hold vlan specific attributes.
    134  * struct rtnl_link *request = rtnl_link_alloc();
    135  * rtnl_link_set_info_type(request, "vlan");
    136  *
    137  * // Now vlan specific attributes can be set:
    138  * rtnl_link_vlan_set_id(request, 10);
    139  * rtnl_link_vlan_set_ingress_map(request, 2, 8);
    140  *
    141  * // Of course the attributes can also be read, check the info type
    142  * // to make sure you are using the right access functions:
    143  * char *type = rtnl_link_get_info_type(link);
    144  * if (!strcmp(type, "vlan"))
    145  * 	int id = rtnl_link_vlan_get_id(link);
    146  * @endcode
    147  * @{
    148  */
    149 
    150 #include <netlink-local.h>
    151 #include <netlink/netlink.h>
    152 #include <netlink/attr.h>
    153 #include <netlink/utils.h>
    154 #include <netlink/object.h>
    155 #include <netlink/route/rtnl.h>
    156 #include <netlink/route/link.h>
    157 #include <netlink/route/link/info-api.h>
    158 
    159 /** @cond SKIP */
    160 #define LINK_ATTR_MTU     0x0001
    161 #define LINK_ATTR_LINK    0x0002
    162 #define LINK_ATTR_TXQLEN  0x0004
    163 #define LINK_ATTR_WEIGHT  0x0008
    164 #define LINK_ATTR_MASTER  0x0010
    165 #define LINK_ATTR_QDISC   0x0020
    166 #define LINK_ATTR_MAP     0x0040
    167 #define LINK_ATTR_ADDR    0x0080
    168 #define LINK_ATTR_BRD     0x0100
    169 #define LINK_ATTR_FLAGS   0x0200
    170 #define LINK_ATTR_IFNAME  0x0400
    171 #define LINK_ATTR_IFINDEX 0x0800
    172 #define LINK_ATTR_FAMILY  0x1000
    173 #define LINK_ATTR_ARPTYPE 0x2000
    174 #define LINK_ATTR_STATS   0x4000
    175 #define LINK_ATTR_CHANGE  0x8000
    176 #define LINK_ATTR_OPERSTATE 0x10000
    177 #define LINK_ATTR_LINKMODE  0x20000
    178 #define LINK_ATTR_LINKINFO  0x40000
    179 
    180 static struct nl_cache_ops rtnl_link_ops;
    181 static struct nl_object_ops link_obj_ops;
    182 /** @endcond */
    183 
    184 static void release_link_info(struct rtnl_link *link)
    185 {
    186 	struct rtnl_link_info_ops *io = link->l_info_ops;
    187 
    188 	if (io != NULL) {
    189 		io->io_refcnt--;
    190 		io->io_free(link);
    191 		link->l_info_ops = NULL;
    192 	}
    193 }
    194 
    195 static void link_free_data(struct nl_object *c)
    196 {
    197 	struct rtnl_link *link = nl_object_priv(c);
    198 
    199 	if (link) {
    200 		struct rtnl_link_info_ops *io;
    201 
    202 		if ((io = link->l_info_ops) != NULL)
    203 			release_link_info(link);
    204 
    205 		nl_addr_put(link->l_addr);
    206 		nl_addr_put(link->l_bcast);
    207 	}
    208 }
    209 
    210 static int link_clone(struct nl_object *_dst, struct nl_object *_src)
    211 {
    212 	struct rtnl_link *dst = nl_object_priv(_dst);
    213 	struct rtnl_link *src = nl_object_priv(_src);
    214 	int err;
    215 
    216 	if (src->l_addr)
    217 		if (!(dst->l_addr = nl_addr_clone(src->l_addr)))
    218 			return -NLE_NOMEM;
    219 
    220 	if (src->l_bcast)
    221 		if (!(dst->l_bcast = nl_addr_clone(src->l_bcast)))
    222 			return -NLE_NOMEM;
    223 
    224 	if (src->l_info_ops && src->l_info_ops->io_clone) {
    225 		err = src->l_info_ops->io_clone(dst, src);
    226 		if (err < 0)
    227 			return err;
    228 	}
    229 
    230 	return 0;
    231 }
    232 
    233 static struct nla_policy link_policy[IFLA_MAX+1] = {
    234 	[IFLA_IFNAME]	= { .type = NLA_STRING,
    235 			    .maxlen = IFNAMSIZ },
    236 	[IFLA_MTU]	= { .type = NLA_U32 },
    237 	[IFLA_TXQLEN]	= { .type = NLA_U32 },
    238 	[IFLA_LINK]	= { .type = NLA_U32 },
    239 	[IFLA_WEIGHT]	= { .type = NLA_U32 },
    240 	[IFLA_MASTER]	= { .type = NLA_U32 },
    241 	[IFLA_OPERSTATE]= { .type = NLA_U8 },
    242 	[IFLA_LINKMODE] = { .type = NLA_U8 },
    243 	[IFLA_LINKINFO]	= { .type = NLA_NESTED },
    244 	[IFLA_QDISC]	= { .type = NLA_STRING,
    245 			    .maxlen = IFQDISCSIZ },
    246 	[IFLA_STATS]	= { .minlen = sizeof(struct rtnl_link_stats) },
    247 	[IFLA_MAP]	= { .minlen = sizeof(struct rtnl_link_ifmap) },
    248 };
    249 
    250 static struct nla_policy link_info_policy[IFLA_INFO_MAX+1] = {
    251 	[IFLA_INFO_KIND]	= { .type = NLA_STRING },
    252 	[IFLA_INFO_DATA]	= { .type = NLA_NESTED },
    253 	[IFLA_INFO_XSTATS]	= { .type = NLA_NESTED },
    254 };
    255 
    256 static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
    257 			   struct nlmsghdr *n, struct nl_parser_param *pp)
    258 {
    259 	struct rtnl_link *link;
    260 	struct ifinfomsg *ifi;
    261 	struct nlattr *tb[IFLA_MAX+1];
    262 	int err;
    263 
    264 	link = rtnl_link_alloc();
    265 	if (link == NULL) {
    266 		err = -NLE_NOMEM;
    267 		goto errout;
    268 	}
    269 
    270 	link->ce_msgtype = n->nlmsg_type;
    271 
    272 	err = nlmsg_parse(n, sizeof(*ifi), tb, IFLA_MAX, link_policy);
    273 	if (err < 0)
    274 		goto errout;
    275 
    276 	if (tb[IFLA_IFNAME] == NULL) {
    277 		err = -NLE_MISSING_ATTR;
    278 		goto errout;
    279 	}
    280 
    281 	nla_strlcpy(link->l_name, tb[IFLA_IFNAME], IFNAMSIZ);
    282 
    283 	ifi = nlmsg_data(n);
    284 	link->l_family = ifi->ifi_family;
    285 	link->l_arptype = ifi->ifi_type;
    286 	link->l_index = ifi->ifi_index;
    287 	link->l_flags = ifi->ifi_flags;
    288 	link->l_change = ifi->ifi_change;
    289 	link->ce_mask = (LINK_ATTR_IFNAME | LINK_ATTR_FAMILY |
    290 			  LINK_ATTR_ARPTYPE| LINK_ATTR_IFINDEX |
    291 			  LINK_ATTR_FLAGS | LINK_ATTR_CHANGE);
    292 
    293 	if (tb[IFLA_STATS]) {
    294 		struct rtnl_link_stats *st = nla_data(tb[IFLA_STATS]);
    295 
    296 		link->l_stats[RTNL_LINK_RX_PACKETS]	= st->rx_packets;
    297 		link->l_stats[RTNL_LINK_RX_BYTES]	= st->rx_bytes;
    298 		link->l_stats[RTNL_LINK_RX_ERRORS]	= st->rx_errors;
    299 		link->l_stats[RTNL_LINK_RX_DROPPED]	= st->rx_dropped;
    300 		link->l_stats[RTNL_LINK_RX_COMPRESSED]	= st->rx_compressed;
    301 		link->l_stats[RTNL_LINK_RX_FIFO_ERR]	= st->rx_fifo_errors;
    302 		link->l_stats[RTNL_LINK_TX_PACKETS]	= st->tx_packets;
    303 		link->l_stats[RTNL_LINK_TX_BYTES]	= st->tx_bytes;
    304 		link->l_stats[RTNL_LINK_TX_ERRORS]	= st->tx_errors;
    305 		link->l_stats[RTNL_LINK_TX_DROPPED]	= st->tx_dropped;
    306 		link->l_stats[RTNL_LINK_TX_COMPRESSED]	= st->tx_compressed;
    307 		link->l_stats[RTNL_LINK_TX_FIFO_ERR]	= st->tx_fifo_errors;
    308 		link->l_stats[RTNL_LINK_RX_LEN_ERR]	= st->rx_length_errors;
    309 		link->l_stats[RTNL_LINK_RX_OVER_ERR]	= st->rx_over_errors;
    310 		link->l_stats[RTNL_LINK_RX_CRC_ERR]	= st->rx_crc_errors;
    311 		link->l_stats[RTNL_LINK_RX_FRAME_ERR]	= st->rx_frame_errors;
    312 		link->l_stats[RTNL_LINK_RX_MISSED_ERR]	= st->rx_missed_errors;
    313 		link->l_stats[RTNL_LINK_TX_ABORT_ERR]	= st->tx_aborted_errors;
    314 		link->l_stats[RTNL_LINK_TX_CARRIER_ERR]	= st->tx_carrier_errors;
    315 		link->l_stats[RTNL_LINK_TX_HBEAT_ERR]	= st->tx_heartbeat_errors;
    316 		link->l_stats[RTNL_LINK_TX_WIN_ERR]	= st->tx_window_errors;
    317 		link->l_stats[RTNL_LINK_MULTICAST]	= st->multicast;
    318 
    319 		link->ce_mask |= LINK_ATTR_STATS;
    320 	}
    321 
    322 	if (tb[IFLA_TXQLEN]) {
    323 		link->l_txqlen = nla_get_u32(tb[IFLA_TXQLEN]);
    324 		link->ce_mask |= LINK_ATTR_TXQLEN;
    325 	}
    326 
    327 	if (tb[IFLA_MTU]) {
    328 		link->l_mtu = nla_get_u32(tb[IFLA_MTU]);
    329 		link->ce_mask |= LINK_ATTR_MTU;
    330 	}
    331 
    332 	if (tb[IFLA_ADDRESS]) {
    333 		link->l_addr = nl_addr_alloc_attr(tb[IFLA_ADDRESS], AF_UNSPEC);
    334 		if (link->l_addr == NULL) {
    335 			err = -NLE_NOMEM;
    336 			goto errout;
    337 		}
    338 		nl_addr_set_family(link->l_addr,
    339 				   nl_addr_guess_family(link->l_addr));
    340 		link->ce_mask |= LINK_ATTR_ADDR;
    341 	}
    342 
    343 	if (tb[IFLA_BROADCAST]) {
    344 		link->l_bcast = nl_addr_alloc_attr(tb[IFLA_BROADCAST],
    345 						   AF_UNSPEC);
    346 		if (link->l_bcast == NULL) {
    347 			err = -NLE_NOMEM;
    348 			goto errout;
    349 		}
    350 		nl_addr_set_family(link->l_bcast,
    351 				   nl_addr_guess_family(link->l_bcast));
    352 		link->ce_mask |= LINK_ATTR_BRD;
    353 	}
    354 
    355 	if (tb[IFLA_LINK]) {
    356 		link->l_link = nla_get_u32(tb[IFLA_LINK]);
    357 		link->ce_mask |= LINK_ATTR_LINK;
    358 	}
    359 
    360 	if (tb[IFLA_WEIGHT]) {
    361 		link->l_weight = nla_get_u32(tb[IFLA_WEIGHT]);
    362 		link->ce_mask |= LINK_ATTR_WEIGHT;
    363 	}
    364 
    365 	if (tb[IFLA_QDISC]) {
    366 		nla_strlcpy(link->l_qdisc, tb[IFLA_QDISC], IFQDISCSIZ);
    367 		link->ce_mask |= LINK_ATTR_QDISC;
    368 	}
    369 
    370 	if (tb[IFLA_MAP]) {
    371 		nla_memcpy(&link->l_map, tb[IFLA_MAP],
    372 			   sizeof(struct rtnl_link_ifmap));
    373 		link->ce_mask |= LINK_ATTR_MAP;
    374 	}
    375 
    376 	if (tb[IFLA_MASTER]) {
    377 		link->l_master = nla_get_u32(tb[IFLA_MASTER]);
    378 		link->ce_mask |= LINK_ATTR_MASTER;
    379 	}
    380 
    381 	if (tb[IFLA_OPERSTATE]) {
    382 		link->l_operstate = nla_get_u8(tb[IFLA_OPERSTATE]);
    383 		link->ce_mask |= LINK_ATTR_OPERSTATE;
    384 	}
    385 
    386 	if (tb[IFLA_LINKMODE]) {
    387 		link->l_linkmode = nla_get_u8(tb[IFLA_LINKMODE]);
    388 		link->ce_mask |= LINK_ATTR_LINKMODE;
    389 	}
    390 
    391 	if (tb[IFLA_LINKINFO]) {
    392 		struct nlattr *li[IFLA_INFO_MAX+1];
    393 
    394 		err = nla_parse_nested(li, IFLA_INFO_MAX, tb[IFLA_LINKINFO],
    395 				       link_info_policy);
    396 		if (err < 0)
    397 			goto errout;
    398 
    399 		if (li[IFLA_INFO_KIND] &&
    400 		    (li[IFLA_INFO_DATA] || li[IFLA_INFO_XSTATS])) {
    401 			struct rtnl_link_info_ops *ops;
    402 			char *kind;
    403 
    404 			kind = nla_get_string(li[IFLA_INFO_KIND]);
    405 			ops = rtnl_link_info_ops_lookup(kind);
    406 			if (ops != NULL) {
    407 				ops->io_refcnt++;
    408 				link->l_info_ops = ops;
    409 				err = ops->io_parse(link, li[IFLA_INFO_DATA],
    410 						    li[IFLA_INFO_XSTATS]);
    411 				if (err < 0)
    412 					goto errout;
    413 			} else {
    414 				/* XXX: Warn about unparsed info? */
    415 			}
    416 		}
    417 	}
    418 
    419 	err = pp->pp_cb((struct nl_object *) link, pp);
    420 errout:
    421 	rtnl_link_put(link);
    422 	return err;
    423 }
    424 
    425 static int link_request_update(struct nl_cache *cache, struct nl_sock *sk)
    426 {
    427 	return nl_rtgen_request(sk, RTM_GETLINK, AF_UNSPEC, NLM_F_DUMP);
    428 }
    429 
    430 static void link_dump_line(struct nl_object *obj, struct nl_dump_params *p)
    431 {
    432 	char buf[128];
    433 	struct nl_cache *cache = dp_cache(obj);
    434 	struct rtnl_link *link = (struct rtnl_link *) obj;
    435 
    436 	nl_dump_line(p, "%s %s ", link->l_name,
    437 		     nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
    438 
    439 	if (link->l_addr && !nl_addr_iszero(link->l_addr))
    440 		nl_dump(p, "%s ", nl_addr2str(link->l_addr, buf, sizeof(buf)));
    441 
    442 	if (link->ce_mask & LINK_ATTR_MASTER) {
    443 		struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
    444 		nl_dump(p, "master %s ", master ? master->l_name : "inv");
    445 		if (master)
    446 			rtnl_link_put(master);
    447 	}
    448 
    449 	rtnl_link_flags2str(link->l_flags, buf, sizeof(buf));
    450 	if (buf[0])
    451 		nl_dump(p, "<%s> ", buf);
    452 
    453 	if (link->ce_mask & LINK_ATTR_LINK) {
    454 		struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
    455 		nl_dump(p, "slave-of %s ", ll ? ll->l_name : "NONE");
    456 		if (ll)
    457 			rtnl_link_put(ll);
    458 	}
    459 
    460 	if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_LINE])
    461 		link->l_info_ops->io_dump[NL_DUMP_LINE](link, p);
    462 
    463 	nl_dump(p, "\n");
    464 }
    465 
    466 static void link_dump_details(struct nl_object *obj, struct nl_dump_params *p)
    467 {
    468 	struct rtnl_link *link = (struct rtnl_link *) obj;
    469 	char buf[64];
    470 
    471 	link_dump_line(obj, p);
    472 
    473 	nl_dump_line(p, "    mtu %u ", link->l_mtu);
    474 	nl_dump(p, "txqlen %u weight %u ", link->l_txqlen, link->l_weight);
    475 
    476 	if (link->ce_mask & LINK_ATTR_QDISC)
    477 		nl_dump(p, "qdisc %s ", link->l_qdisc);
    478 
    479 	if (link->ce_mask & LINK_ATTR_MAP && link->l_map.lm_irq)
    480 		nl_dump(p, "irq %u ", link->l_map.lm_irq);
    481 
    482 	if (link->ce_mask & LINK_ATTR_IFINDEX)
    483 		nl_dump(p, "index %u ", link->l_index);
    484 
    485 
    486 	nl_dump(p, "\n");
    487 	nl_dump_line(p, "    ");
    488 
    489 	if (link->ce_mask & LINK_ATTR_BRD)
    490 		nl_dump(p, "brd %s ", nl_addr2str(link->l_bcast, buf,
    491 						   sizeof(buf)));
    492 
    493 	if ((link->ce_mask & LINK_ATTR_OPERSTATE) &&
    494 	    link->l_operstate != IF_OPER_UNKNOWN) {
    495 		rtnl_link_operstate2str(link->l_operstate, buf, sizeof(buf));
    496 		nl_dump(p, "state %s ", buf);
    497 	}
    498 
    499 	nl_dump(p, "mode %s\n",
    500 		rtnl_link_mode2str(link->l_linkmode, buf, sizeof(buf)));
    501 
    502 	if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_DETAILS])
    503 		link->l_info_ops->io_dump[NL_DUMP_DETAILS](link, p);
    504 }
    505 
    506 static void link_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
    507 {
    508 	struct rtnl_link *link = (struct rtnl_link *) obj;
    509 	char *unit, fmt[64];
    510 	float res;
    511 
    512 	link_dump_details(obj, p);
    513 
    514 	nl_dump_line(p, "    Stats:    bytes    packets     errors "
    515 			"   dropped   fifo-err compressed\n");
    516 
    517 	res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_RX_BYTES], &unit);
    518 
    519 	strcpy(fmt, "     RX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n");
    520 	fmt[9] = *unit == 'B' ? '9' : '7';
    521 
    522 	nl_dump_line(p, fmt, res, unit,
    523 		link->l_stats[RTNL_LINK_RX_PACKETS],
    524 		link->l_stats[RTNL_LINK_RX_ERRORS],
    525 		link->l_stats[RTNL_LINK_RX_DROPPED],
    526 		link->l_stats[RTNL_LINK_RX_FIFO_ERR],
    527 		link->l_stats[RTNL_LINK_RX_COMPRESSED]);
    528 
    529 	res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_TX_BYTES], &unit);
    530 
    531 	strcpy(fmt, "     TX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n");
    532 	fmt[9] = *unit == 'B' ? '9' : '7';
    533 
    534 	nl_dump_line(p, fmt, res, unit,
    535 		link->l_stats[RTNL_LINK_TX_PACKETS],
    536 		link->l_stats[RTNL_LINK_TX_ERRORS],
    537 		link->l_stats[RTNL_LINK_TX_DROPPED],
    538 		link->l_stats[RTNL_LINK_TX_FIFO_ERR],
    539 		link->l_stats[RTNL_LINK_TX_COMPRESSED]);
    540 
    541 	nl_dump_line(p, "    Errors:  length       over        crc "
    542 			"     frame     missed  multicast\n");
    543 
    544 	nl_dump_line(p, "     RX  %10" PRIu64 " %10" PRIu64 " %10"
    545 				PRIu64 " %10" PRIu64 " %10" PRIu64 " %10"
    546 				PRIu64 "\n",
    547 		link->l_stats[RTNL_LINK_RX_LEN_ERR],
    548 		link->l_stats[RTNL_LINK_RX_OVER_ERR],
    549 		link->l_stats[RTNL_LINK_RX_CRC_ERR],
    550 		link->l_stats[RTNL_LINK_RX_FRAME_ERR],
    551 		link->l_stats[RTNL_LINK_RX_MISSED_ERR],
    552 		link->l_stats[RTNL_LINK_MULTICAST]);
    553 
    554 	nl_dump_line(p, "            aborted    carrier  heartbeat "
    555 			"    window  collision\n");
    556 
    557 	nl_dump_line(p, "     TX  %10" PRIu64 " %10" PRIu64 " %10"
    558 			PRIu64 " %10" PRIu64 " %10" PRIu64 "\n",
    559 		link->l_stats[RTNL_LINK_TX_ABORT_ERR],
    560 		link->l_stats[RTNL_LINK_TX_CARRIER_ERR],
    561 		link->l_stats[RTNL_LINK_TX_HBEAT_ERR],
    562 		link->l_stats[RTNL_LINK_TX_WIN_ERR],
    563 		link->l_stats[RTNL_LINK_TX_COLLISIONS]);
    564 
    565 	if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_STATS])
    566 		link->l_info_ops->io_dump[NL_DUMP_STATS](link, p);
    567 }
    568 
    569 static void link_dump_env(struct nl_object *obj, struct nl_dump_params *p)
    570 {
    571 	struct rtnl_link *link = (struct rtnl_link *) obj;
    572 	struct nl_cache *cache = dp_cache(obj);
    573 	char buf[128];
    574 	int i;
    575 
    576 	nl_dump_line(p, "LINK_NAME=%s\n", link->l_name);
    577 	nl_dump_line(p, "LINK_IFINDEX=%u\n", link->l_index);
    578 	nl_dump_line(p, "LINK_FAMILY=%s\n",
    579 		     nl_af2str(link->l_family, buf, sizeof(buf)));
    580 	nl_dump_line(p, "LINK_TYPE=%s\n",
    581 		     nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
    582 	if (link->ce_mask & LINK_ATTR_ADDR)
    583 		nl_dump_line(p, "LINK_ADDRESS=%s\n",
    584 			     nl_addr2str(link->l_addr, buf, sizeof(buf)));
    585 	nl_dump_line(p, "LINK_MTU=%u\n", link->l_mtu);
    586 	nl_dump_line(p, "LINK_TXQUEUELEN=%u\n", link->l_txqlen);
    587 	nl_dump_line(p, "LINK_WEIGHT=%u\n", link->l_weight);
    588 
    589 	rtnl_link_flags2str(link->l_flags & ~IFF_RUNNING, buf, sizeof(buf));
    590 	if (buf[0])
    591 		nl_dump_line(p, "LINK_FLAGS=%s\n", buf);
    592 
    593 	if (link->ce_mask & LINK_ATTR_QDISC)
    594 		nl_dump_line(p, "LINK_QDISC=%s\n", link->l_qdisc);
    595 
    596 	if (link->ce_mask & LINK_ATTR_LINK) {
    597 		struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
    598 
    599 		nl_dump_line(p, "LINK_LINK_IFINDEX=%d\n", link->l_link);
    600 		if (ll) {
    601 			nl_dump_line(p, "LINK_LINK_IFNAME=%s\n", ll->l_name);
    602 			rtnl_link_put(ll);
    603 		}
    604 	}
    605 
    606 	if (link->ce_mask & LINK_ATTR_MASTER) {
    607 		struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
    608 		nl_dump_line(p, "LINK_MASTER=%s\n",
    609 			     master ? master->l_name : "none");
    610 		if (master)
    611 			rtnl_link_put(master);
    612 	}
    613 
    614 	if (link->ce_mask & LINK_ATTR_BRD)
    615 		nl_dump_line(p, "LINK_BROADCAST=%s\n",
    616 			     nl_addr2str(link->l_bcast, buf, sizeof(buf)));
    617 
    618 	if (link->ce_mask & LINK_ATTR_STATS) {
    619 		for (i = 0; i <= RTNL_LINK_STATS_MAX; i++) {
    620 			char *c = buf;
    621 
    622 			sprintf(buf, "LINK_");
    623 			rtnl_link_stat2str(i, buf + 5, sizeof(buf) - 5);
    624 			while (*c) {
    625 				*c = toupper(*c);
    626 				c++;
    627 			}
    628 			nl_dump_line(p, "%s=%" PRIu64 "\n", buf, link->l_stats[i]);
    629 		}
    630 	}
    631 
    632 	if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_ENV])
    633 		link->l_info_ops->io_dump[NL_DUMP_ENV](link, p);
    634 }
    635 
    636 #if 0
    637 static int link_handle_event(struct nl_object *a, struct rtnl_link_event_cb *cb)
    638 {
    639 	struct rtnl_link *l = (struct rtnl_link *) a;
    640 	struct nl_cache *c = dp_cache(a);
    641 	int nevents = 0;
    642 
    643 	if (l->l_change == ~0U) {
    644 		if (l->ce_msgtype == RTM_NEWLINK)
    645 			cb->le_register(l);
    646 		else
    647 			cb->le_unregister(l);
    648 
    649 		return 1;
    650 	}
    651 
    652 	if (l->l_change & IFF_SLAVE) {
    653 		if (l->l_flags & IFF_SLAVE) {
    654 			struct rtnl_link *m = rtnl_link_get(c, l->l_master);
    655 			cb->le_new_bonding(l, m);
    656 			if (m)
    657 				rtnl_link_put(m);
    658 		} else
    659 			cb->le_cancel_bonding(l);
    660 	}
    661 
    662 #if 0
    663 	if (l->l_change & IFF_UP && l->l_change & IFF_RUNNING)
    664 		dp_dump_line(p, line++, "link %s changed state to %s.\n",
    665 			l->l_name, l->l_flags & IFF_UP ? "up" : "down");
    666 
    667 	if (l->l_change & IFF_PROMISC) {
    668 		dp_new_line(p, line++);
    669 		dp_dump(p, "link %s %s promiscuous mode.\n",
    670 		    l->l_name, l->l_flags & IFF_PROMISC ? "entered" : "left");
    671 	}
    672 
    673 	if (line == 0)
    674 		dp_dump_line(p, line++, "link %s sent unknown event.\n",
    675 			     l->l_name);
    676 #endif
    677 
    678 	return nevents;
    679 }
    680 #endif
    681 
    682 static int link_compare(struct nl_object *_a, struct nl_object *_b,
    683 			uint32_t attrs, int flags)
    684 {
    685 	struct rtnl_link *a = (struct rtnl_link *) _a;
    686 	struct rtnl_link *b = (struct rtnl_link *) _b;
    687 	int diff = 0;
    688 
    689 #define LINK_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, LINK_ATTR_##ATTR, a, b, EXPR)
    690 
    691 	diff |= LINK_DIFF(IFINDEX,	a->l_index != b->l_index);
    692 	diff |= LINK_DIFF(MTU,		a->l_mtu != b->l_mtu);
    693 	diff |= LINK_DIFF(LINK,		a->l_link != b->l_link);
    694 	diff |= LINK_DIFF(TXQLEN,	a->l_txqlen != b->l_txqlen);
    695 	diff |= LINK_DIFF(WEIGHT,	a->l_weight != b->l_weight);
    696 	diff |= LINK_DIFF(MASTER,	a->l_master != b->l_master);
    697 	diff |= LINK_DIFF(FAMILY,	a->l_family != b->l_family);
    698 	diff |= LINK_DIFF(OPERSTATE,	a->l_operstate != b->l_operstate);
    699 	diff |= LINK_DIFF(LINKMODE,	a->l_linkmode != b->l_linkmode);
    700 	diff |= LINK_DIFF(QDISC,	strcmp(a->l_qdisc, b->l_qdisc));
    701 	diff |= LINK_DIFF(IFNAME,	strcmp(a->l_name, b->l_name));
    702 	diff |= LINK_DIFF(ADDR,		nl_addr_cmp(a->l_addr, b->l_addr));
    703 	diff |= LINK_DIFF(BRD,		nl_addr_cmp(a->l_bcast, b->l_bcast));
    704 
    705 	if (flags & LOOSE_COMPARISON)
    706 		diff |= LINK_DIFF(FLAGS,
    707 				  (a->l_flags ^ b->l_flags) & b->l_flag_mask);
    708 	else
    709 		diff |= LINK_DIFF(FLAGS, a->l_flags != b->l_flags);
    710 
    711 #undef LINK_DIFF
    712 
    713 	return diff;
    714 }
    715 
    716 static struct trans_tbl link_attrs[] = {
    717 	__ADD(LINK_ATTR_MTU, mtu)
    718 	__ADD(LINK_ATTR_LINK, link)
    719 	__ADD(LINK_ATTR_TXQLEN, txqlen)
    720 	__ADD(LINK_ATTR_WEIGHT, weight)
    721 	__ADD(LINK_ATTR_MASTER, master)
    722 	__ADD(LINK_ATTR_QDISC, qdisc)
    723 	__ADD(LINK_ATTR_MAP, map)
    724 	__ADD(LINK_ATTR_ADDR, address)
    725 	__ADD(LINK_ATTR_BRD, broadcast)
    726 	__ADD(LINK_ATTR_FLAGS, flags)
    727 	__ADD(LINK_ATTR_IFNAME, name)
    728 	__ADD(LINK_ATTR_IFINDEX, ifindex)
    729 	__ADD(LINK_ATTR_FAMILY, family)
    730 	__ADD(LINK_ATTR_ARPTYPE, arptype)
    731 	__ADD(LINK_ATTR_STATS, stats)
    732 	__ADD(LINK_ATTR_CHANGE, change)
    733 	__ADD(LINK_ATTR_OPERSTATE, operstate)
    734 	__ADD(LINK_ATTR_LINKMODE, linkmode)
    735 };
    736 
    737 static char *link_attrs2str(int attrs, char *buf, size_t len)
    738 {
    739 	return __flags2str(attrs, buf, len, link_attrs,
    740 			   ARRAY_SIZE(link_attrs));
    741 }
    742 
    743 /**
    744  * @name Allocation/Freeing
    745  * @{
    746  */
    747 
    748 struct rtnl_link *rtnl_link_alloc(void)
    749 {
    750 	return (struct rtnl_link *) nl_object_alloc(&link_obj_ops);
    751 }
    752 
    753 void rtnl_link_put(struct rtnl_link *link)
    754 {
    755 	nl_object_put((struct nl_object *) link);
    756 }
    757 
    758 /** @} */
    759 
    760 /**
    761  * @name Cache Management
    762  * @{
    763  */
    764 
    765 
    766 /**
    767  * Allocate link cache and fill in all configured links.
    768  * @arg sk		Netlink socket.
    769  * @arg result		Pointer to store resulting cache.
    770  *
    771  * Allocates a new link cache, initializes it properly and updates it
    772  * to include all links currently configured in the kernel.
    773  *
    774  * @return 0 on success or a negative error code.
    775  */
    776 int rtnl_link_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
    777 {
    778 	return nl_cache_alloc_and_fill(&rtnl_link_ops, sk, result);
    779 }
    780 
    781 /**
    782  * Look up link by interface index in the provided cache
    783  * @arg cache		link cache
    784  * @arg ifindex		link interface index
    785  *
    786  * The caller owns a reference on the returned object and
    787  * must give the object back via rtnl_link_put().
    788  *
    789  * @return pointer to link inside the cache or NULL if no match was found.
    790  */
    791 struct rtnl_link *rtnl_link_get(struct nl_cache *cache, int ifindex)
    792 {
    793 	struct rtnl_link *link;
    794 
    795 	if (cache->c_ops != &rtnl_link_ops)
    796 		return NULL;
    797 
    798 	nl_list_for_each_entry(link, &cache->c_items, ce_list) {
    799 		if (link->l_index == ifindex) {
    800 			nl_object_get((struct nl_object *) link);
    801 			return link;
    802 		}
    803 	}
    804 
    805 	return NULL;
    806 }
    807 
    808 /**
    809  * Look up link by link name in the provided cache
    810  * @arg cache		link cache
    811  * @arg name		link name
    812  *
    813  * The caller owns a reference on the returned object and
    814  * must give the object back via rtnl_link_put().
    815  *
    816  * @return pointer to link inside the cache or NULL if no match was found.
    817  */
    818 struct rtnl_link *rtnl_link_get_by_name(struct nl_cache *cache,
    819 					 const char *name)
    820 {
    821 	struct rtnl_link *link;
    822 
    823 	if (cache->c_ops != &rtnl_link_ops)
    824 		return NULL;
    825 
    826 	nl_list_for_each_entry(link, &cache->c_items, ce_list) {
    827 		if (!strcmp(name, link->l_name)) {
    828 			nl_object_get((struct nl_object *) link);
    829 			return link;
    830 		}
    831 	}
    832 
    833 	return NULL;
    834 }
    835 
    836 /** @} */
    837 
    838 /**
    839  * @name Link Modifications
    840  * @{
    841  */
    842 
    843 /**
    844  * Builds a netlink change request message to change link attributes
    845  * @arg old		link to be changed
    846  * @arg tmpl		template with requested changes
    847  * @arg flags		additional netlink message flags
    848  *
    849  * Builds a new netlink message requesting a change of link attributes.
    850  * The netlink message header isn't fully equipped with all relevant
    851  * fields and must be sent out via nl_send_auto_complete() or
    852  * supplemented as needed.
    853  * \a old must point to a link currently configured in the kernel
    854  * and \a tmpl must contain the attributes to be changed set via
    855  * \c rtnl_link_set_* functions.
    856  *
    857  * @return New netlink message
    858  * @note Not all attributes can be changed, see
    859  *       \ref link_changeable "Changeable Attributes" for more details.
    860  */
    861 int rtnl_link_build_change_request(struct rtnl_link *old,
    862 				   struct rtnl_link *tmpl, int flags,
    863 				   struct nl_msg **result)
    864 {
    865 	struct nl_msg *msg;
    866 	struct ifinfomsg ifi = {
    867 		.ifi_family = old->l_family,
    868 		.ifi_index = old->l_index,
    869 	};
    870 
    871 	if (tmpl->ce_mask & LINK_ATTR_FLAGS) {
    872 		ifi.ifi_flags = old->l_flags & ~tmpl->l_flag_mask;
    873 		ifi.ifi_flags |= tmpl->l_flags;
    874 	}
    875 
    876 	msg = nlmsg_alloc_simple(RTM_SETLINK, flags);
    877 	if (!msg)
    878 		return -NLE_NOMEM;
    879 
    880 	if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
    881 		goto nla_put_failure;
    882 
    883 	if (tmpl->ce_mask & LINK_ATTR_ADDR)
    884 		NLA_PUT_ADDR(msg, IFLA_ADDRESS, tmpl->l_addr);
    885 
    886 	if (tmpl->ce_mask & LINK_ATTR_BRD)
    887 		NLA_PUT_ADDR(msg, IFLA_BROADCAST, tmpl->l_bcast);
    888 
    889 	if (tmpl->ce_mask & LINK_ATTR_MTU)
    890 		NLA_PUT_U32(msg, IFLA_MTU, tmpl->l_mtu);
    891 
    892 	if (tmpl->ce_mask & LINK_ATTR_TXQLEN)
    893 		NLA_PUT_U32(msg, IFLA_TXQLEN, tmpl->l_txqlen);
    894 
    895 	if (tmpl->ce_mask & LINK_ATTR_WEIGHT)
    896 		NLA_PUT_U32(msg, IFLA_WEIGHT, tmpl->l_weight);
    897 
    898 	if (tmpl->ce_mask & LINK_ATTR_IFNAME)
    899 		NLA_PUT_STRING(msg, IFLA_IFNAME, tmpl->l_name);
    900 
    901 	if (tmpl->ce_mask & LINK_ATTR_OPERSTATE)
    902 		NLA_PUT_U8(msg, IFLA_OPERSTATE, tmpl->l_operstate);
    903 
    904 	if (tmpl->ce_mask & LINK_ATTR_LINKMODE)
    905 		NLA_PUT_U8(msg, IFLA_LINKMODE, tmpl->l_linkmode);
    906 
    907 	if ((tmpl->ce_mask & LINK_ATTR_LINKINFO) && tmpl->l_info_ops &&
    908 	    tmpl->l_info_ops->io_put_attrs) {
    909 		struct nlattr *info;
    910 
    911 		if (!(info = nla_nest_start(msg, IFLA_LINKINFO)))
    912 			goto nla_put_failure;
    913 
    914 		NLA_PUT_STRING(msg, IFLA_INFO_KIND, tmpl->l_info_ops->io_name);
    915 
    916 		if (tmpl->l_info_ops->io_put_attrs(msg, tmpl) < 0)
    917 			goto nla_put_failure;
    918 
    919 		nla_nest_end(msg, info);
    920 	}
    921 
    922 	*result = msg;
    923 	return 0;
    924 
    925 nla_put_failure:
    926 	nlmsg_free(msg);
    927 	return -NLE_MSGSIZE;
    928 }
    929 
    930 /**
    931  * Change link attributes
    932  * @arg sk		Netlink socket.
    933  * @arg old		link to be changed
    934  * @arg tmpl		template with requested changes
    935  * @arg flags		additional netlink message flags
    936  *
    937  * Builds a new netlink message by calling rtnl_link_build_change_request(),
    938  * sends the request to the kernel and waits for the next ACK to be
    939  * received, i.e. blocks until the request has been processed.
    940  *
    941  * @return 0 on success or a negative error code
    942  * @note Not all attributes can be changed, see
    943  *       \ref link_changeable "Changeable Attributes" for more details.
    944  */
    945 int rtnl_link_change(struct nl_sock *sk, struct rtnl_link *old,
    946 		     struct rtnl_link *tmpl, int flags)
    947 {
    948 	struct nl_msg *msg;
    949 	int err;
    950 
    951 	if ((err = rtnl_link_build_change_request(old, tmpl, flags, &msg)) < 0)
    952 		return err;
    953 
    954 	err = nl_send_auto_complete(sk, msg);
    955 	nlmsg_free(msg);
    956 	if (err < 0)
    957 		return err;
    958 
    959 	return wait_for_ack(sk);
    960 }
    961 
    962 /** @} */
    963 
    964 /**
    965  * @name Name <-> Index Translations
    966  * @{
    967  */
    968 
    969 /**
    970  * Translate an interface index to the corresponding link name
    971  * @arg cache		link cache
    972  * @arg ifindex		link interface index
    973  * @arg dst		destination buffer
    974  * @arg len		length of destination buffer
    975  *
    976  * Translates the specified interface index to the corresponding
    977  * link name and stores the name in the destination buffer.
    978  *
    979  * @return link name or NULL if no match was found.
    980  */
    981 char * rtnl_link_i2name(struct nl_cache *cache, int ifindex, char *dst,
    982 			size_t len)
    983 {
    984 	struct rtnl_link *link = rtnl_link_get(cache, ifindex);
    985 
    986 	if (link) {
    987 		strncpy(dst, link->l_name, len - 1);
    988 		rtnl_link_put(link);
    989 		return dst;
    990 	}
    991 
    992 	return NULL;
    993 }
    994 
    995 /**
    996  * Translate a link name to the corresponding interface index
    997  * @arg cache		link cache
    998  * @arg name		link name
    999  *
   1000  * @return interface index or 0 if no match was found.
   1001  */
   1002 int rtnl_link_name2i(struct nl_cache *cache, const char *name)
   1003 {
   1004 	int ifindex = 0;
   1005 	struct rtnl_link *link;
   1006 
   1007 	link = rtnl_link_get_by_name(cache, name);
   1008 	if (link) {
   1009 		ifindex = link->l_index;
   1010 		rtnl_link_put(link);
   1011 	}
   1012 
   1013 	return ifindex;
   1014 }
   1015 
   1016 /** @} */
   1017 
   1018 /**
   1019  * @name Link Flags Translations
   1020  * @{
   1021  */
   1022 
   1023 static struct trans_tbl link_flags[] = {
   1024 	__ADD(IFF_LOOPBACK, loopback)
   1025 	__ADD(IFF_BROADCAST, broadcast)
   1026 	__ADD(IFF_POINTOPOINT, pointopoint)
   1027 	__ADD(IFF_MULTICAST, multicast)
   1028 	__ADD(IFF_NOARP, noarp)
   1029 	__ADD(IFF_ALLMULTI, allmulti)
   1030 	__ADD(IFF_PROMISC, promisc)
   1031 	__ADD(IFF_MASTER, master)
   1032 	__ADD(IFF_SLAVE, slave)
   1033 	__ADD(IFF_DEBUG, debug)
   1034 	__ADD(IFF_DYNAMIC, dynamic)
   1035 	__ADD(IFF_AUTOMEDIA, automedia)
   1036 	__ADD(IFF_PORTSEL, portsel)
   1037 	__ADD(IFF_NOTRAILERS, notrailers)
   1038 	__ADD(IFF_UP, up)
   1039 	__ADD(IFF_RUNNING, running)
   1040 	__ADD(IFF_LOWER_UP, lowerup)
   1041 	__ADD(IFF_DORMANT, dormant)
   1042 	__ADD(IFF_ECHO, echo)
   1043 };
   1044 
   1045 char * rtnl_link_flags2str(int flags, char *buf, size_t len)
   1046 {
   1047 	return __flags2str(flags, buf, len, link_flags,
   1048 			   ARRAY_SIZE(link_flags));
   1049 }
   1050 
   1051 int rtnl_link_str2flags(const char *name)
   1052 {
   1053 	return __str2flags(name, link_flags, ARRAY_SIZE(link_flags));
   1054 }
   1055 
   1056 /** @} */
   1057 
   1058 /**
   1059  * @name Link Statistics Translations
   1060  * @{
   1061  */
   1062 
   1063 static struct trans_tbl link_stats[] = {
   1064 	__ADD(RTNL_LINK_RX_PACKETS, rx_packets)
   1065 	__ADD(RTNL_LINK_TX_PACKETS, tx_packets)
   1066 	__ADD(RTNL_LINK_RX_BYTES, rx_bytes)
   1067 	__ADD(RTNL_LINK_TX_BYTES, tx_bytes)
   1068 	__ADD(RTNL_LINK_RX_ERRORS, rx_errors)
   1069 	__ADD(RTNL_LINK_TX_ERRORS, tx_errors)
   1070 	__ADD(RTNL_LINK_RX_DROPPED, rx_dropped)
   1071 	__ADD(RTNL_LINK_TX_DROPPED, tx_dropped)
   1072 	__ADD(RTNL_LINK_RX_COMPRESSED, rx_compressed)
   1073 	__ADD(RTNL_LINK_TX_COMPRESSED, tx_compressed)
   1074 	__ADD(RTNL_LINK_RX_FIFO_ERR, rx_fifo_err)
   1075 	__ADD(RTNL_LINK_TX_FIFO_ERR, tx_fifo_err)
   1076 	__ADD(RTNL_LINK_RX_LEN_ERR, rx_len_err)
   1077 	__ADD(RTNL_LINK_RX_OVER_ERR, rx_over_err)
   1078 	__ADD(RTNL_LINK_RX_CRC_ERR, rx_crc_err)
   1079 	__ADD(RTNL_LINK_RX_FRAME_ERR, rx_frame_err)
   1080 	__ADD(RTNL_LINK_RX_MISSED_ERR, rx_missed_err)
   1081 	__ADD(RTNL_LINK_TX_ABORT_ERR, tx_abort_err)
   1082 	__ADD(RTNL_LINK_TX_CARRIER_ERR, tx_carrier_err)
   1083 	__ADD(RTNL_LINK_TX_HBEAT_ERR, tx_hbeat_err)
   1084 	__ADD(RTNL_LINK_TX_WIN_ERR, tx_win_err)
   1085 	__ADD(RTNL_LINK_TX_COLLISIONS, tx_collision)
   1086 	__ADD(RTNL_LINK_MULTICAST, multicast)
   1087 };
   1088 
   1089 char *rtnl_link_stat2str(int st, char *buf, size_t len)
   1090 {
   1091 	return __type2str(st, buf, len, link_stats, ARRAY_SIZE(link_stats));
   1092 }
   1093 
   1094 int rtnl_link_str2stat(const char *name)
   1095 {
   1096 	return __str2type(name, link_stats, ARRAY_SIZE(link_stats));
   1097 }
   1098 
   1099 /** @} */
   1100 
   1101 /**
   1102  * @name Link Operstate Translations
   1103  * @{
   1104  */
   1105 
   1106 static struct trans_tbl link_operstates[] = {
   1107 	__ADD(IF_OPER_UNKNOWN, unknown)
   1108 	__ADD(IF_OPER_NOTPRESENT, notpresent)
   1109 	__ADD(IF_OPER_DOWN, down)
   1110 	__ADD(IF_OPER_LOWERLAYERDOWN, lowerlayerdown)
   1111 	__ADD(IF_OPER_TESTING, testing)
   1112 	__ADD(IF_OPER_DORMANT, dormant)
   1113 	__ADD(IF_OPER_UP, up)
   1114 };
   1115 
   1116 char *rtnl_link_operstate2str(int st, char *buf, size_t len)
   1117 {
   1118 	return __type2str(st, buf, len, link_operstates,
   1119 			  ARRAY_SIZE(link_operstates));
   1120 }
   1121 
   1122 int rtnl_link_str2operstate(const char *name)
   1123 {
   1124 	return __str2type(name, link_operstates,
   1125 			  ARRAY_SIZE(link_operstates));
   1126 }
   1127 
   1128 /** @} */
   1129 
   1130 /**
   1131  * @name Link Mode Translations
   1132  * @{
   1133  */
   1134 
   1135 static struct trans_tbl link_modes[] = {
   1136 	__ADD(IF_LINK_MODE_DEFAULT, default)
   1137 	__ADD(IF_LINK_MODE_DORMANT, dormant)
   1138 };
   1139 
   1140 char *rtnl_link_mode2str(int st, char *buf, size_t len)
   1141 {
   1142 	return __type2str(st, buf, len, link_modes, ARRAY_SIZE(link_modes));
   1143 }
   1144 
   1145 int rtnl_link_str2mode(const char *name)
   1146 {
   1147 	return __str2type(name, link_modes, ARRAY_SIZE(link_modes));
   1148 }
   1149 
   1150 /** @} */
   1151 
   1152 /**
   1153  * @name Attributes
   1154  * @{
   1155  */
   1156 
   1157 void rtnl_link_set_qdisc(struct rtnl_link *link, const char *qdisc)
   1158 {
   1159 	strncpy(link->l_qdisc, qdisc, sizeof(link->l_qdisc) - 1);
   1160 	link->ce_mask |= LINK_ATTR_QDISC;
   1161 }
   1162 
   1163 char *rtnl_link_get_qdisc(struct rtnl_link *link)
   1164 {
   1165 	if (link->ce_mask & LINK_ATTR_QDISC)
   1166 		return link->l_qdisc;
   1167 	else
   1168 		return NULL;
   1169 }
   1170 
   1171 void rtnl_link_set_name(struct rtnl_link *link, const char *name)
   1172 {
   1173 	strncpy(link->l_name, name, sizeof(link->l_name) - 1);
   1174 	link->ce_mask |= LINK_ATTR_IFNAME;
   1175 }
   1176 
   1177 char *rtnl_link_get_name(struct rtnl_link *link)
   1178 {
   1179 	if (link->ce_mask & LINK_ATTR_IFNAME)
   1180 		return link->l_name;
   1181 	else
   1182 		return NULL;
   1183 }
   1184 
   1185 static inline void __assign_addr(struct rtnl_link *link, struct nl_addr **pos,
   1186 				 struct nl_addr *new, int flag)
   1187 {
   1188 	if (*pos)
   1189 		nl_addr_put(*pos);
   1190 
   1191 	nl_addr_get(new);
   1192 	*pos = new;
   1193 
   1194 	link->ce_mask |= flag;
   1195 }
   1196 
   1197 void rtnl_link_set_addr(struct rtnl_link *link, struct nl_addr *addr)
   1198 {
   1199 	__assign_addr(link, &link->l_addr, addr, LINK_ATTR_ADDR);
   1200 }
   1201 
   1202 struct nl_addr *rtnl_link_get_addr(struct rtnl_link *link)
   1203 {
   1204 	if (link->ce_mask & LINK_ATTR_ADDR)
   1205 		return link->l_addr;
   1206 	else
   1207 		return NULL;
   1208 }
   1209 
   1210 void rtnl_link_set_broadcast(struct rtnl_link *link, struct nl_addr *brd)
   1211 {
   1212 	__assign_addr(link, &link->l_bcast, brd, LINK_ATTR_BRD);
   1213 }
   1214 
   1215 struct nl_addr *rtnl_link_get_broadcast(struct rtnl_link *link)
   1216 {
   1217 	if (link->ce_mask & LINK_ATTR_BRD)
   1218 		return link->l_bcast;
   1219 	else
   1220 		return NULL;
   1221 }
   1222 
   1223 void rtnl_link_set_flags(struct rtnl_link *link, unsigned int flags)
   1224 {
   1225 	link->l_flag_mask |= flags;
   1226 	link->l_flags |= flags;
   1227 	link->ce_mask |= LINK_ATTR_FLAGS;
   1228 }
   1229 
   1230 void rtnl_link_unset_flags(struct rtnl_link *link, unsigned int flags)
   1231 {
   1232 	link->l_flag_mask |= flags;
   1233 	link->l_flags &= ~flags;
   1234 	link->ce_mask |= LINK_ATTR_FLAGS;
   1235 }
   1236 
   1237 unsigned int rtnl_link_get_flags(struct rtnl_link *link)
   1238 {
   1239 	return link->l_flags;
   1240 }
   1241 
   1242 void rtnl_link_set_family(struct rtnl_link *link, int family)
   1243 {
   1244 	link->l_family = family;
   1245 	link->ce_mask |= LINK_ATTR_FAMILY;
   1246 }
   1247 
   1248 int rtnl_link_get_family(struct rtnl_link *link)
   1249 {
   1250 	if (link->l_family & LINK_ATTR_FAMILY)
   1251 		return link->l_family;
   1252 	else
   1253 		return AF_UNSPEC;
   1254 }
   1255 
   1256 void rtnl_link_set_arptype(struct rtnl_link *link, unsigned int arptype)
   1257 {
   1258 	link->l_arptype = arptype;
   1259 }
   1260 
   1261 unsigned int rtnl_link_get_arptype(struct rtnl_link *link)
   1262 {
   1263 	return link->l_arptype;
   1264 }
   1265 
   1266 void rtnl_link_set_ifindex(struct rtnl_link *link, int ifindex)
   1267 {
   1268 	link->l_index = ifindex;
   1269 	link->ce_mask |= LINK_ATTR_IFINDEX;
   1270 }
   1271 
   1272 int rtnl_link_get_ifindex(struct rtnl_link *link)
   1273 {
   1274 	return link->l_index;
   1275 }
   1276 
   1277 void rtnl_link_set_mtu(struct rtnl_link *link, unsigned int mtu)
   1278 {
   1279 	link->l_mtu = mtu;
   1280 	link->ce_mask |= LINK_ATTR_MTU;
   1281 }
   1282 
   1283 unsigned int rtnl_link_get_mtu(struct rtnl_link *link)
   1284 {
   1285 	if (link->ce_mask & LINK_ATTR_MTU)
   1286 		return link->l_mtu;
   1287 	else
   1288 		return 0;
   1289 }
   1290 
   1291 void rtnl_link_set_txqlen(struct rtnl_link *link, unsigned int txqlen)
   1292 {
   1293 	link->l_txqlen = txqlen;
   1294 	link->ce_mask |= LINK_ATTR_TXQLEN;
   1295 }
   1296 
   1297 unsigned int rtnl_link_get_txqlen(struct rtnl_link *link)
   1298 {
   1299 	if (link->ce_mask & LINK_ATTR_TXQLEN)
   1300 		return link->l_txqlen;
   1301 	else
   1302 		return UINT_MAX;
   1303 }
   1304 
   1305 void rtnl_link_set_weight(struct rtnl_link *link, unsigned int weight)
   1306 {
   1307 	link->l_weight = weight;
   1308 	link->ce_mask |= LINK_ATTR_WEIGHT;
   1309 }
   1310 
   1311 unsigned int rtnl_link_get_weight(struct rtnl_link *link)
   1312 {
   1313 	if (link->ce_mask & LINK_ATTR_WEIGHT)
   1314 		return link->l_weight;
   1315 	else
   1316 		return UINT_MAX;
   1317 }
   1318 
   1319 void rtnl_link_set_link(struct rtnl_link *link, int ifindex)
   1320 {
   1321 	link->l_link = ifindex;
   1322 	link->ce_mask |= LINK_ATTR_LINK;
   1323 }
   1324 
   1325 int rtnl_link_get_link(struct rtnl_link *link)
   1326 {
   1327 	return link->l_link;
   1328 }
   1329 
   1330 void rtnl_link_set_master(struct rtnl_link *link, int ifindex)
   1331 {
   1332 	link->l_master = ifindex;
   1333 	link->ce_mask |= LINK_ATTR_MASTER;
   1334 }
   1335 
   1336 int rtnl_link_get_master(struct rtnl_link *link)
   1337 {
   1338 	return link->l_master;
   1339 }
   1340 
   1341 void rtnl_link_set_operstate(struct rtnl_link *link, uint8_t operstate)
   1342 {
   1343 	link->l_operstate = operstate;
   1344 	link->ce_mask |= LINK_ATTR_OPERSTATE;
   1345 }
   1346 
   1347 uint8_t rtnl_link_get_operstate(struct rtnl_link *link)
   1348 {
   1349 	if (link->ce_mask & LINK_ATTR_OPERSTATE)
   1350 		return link->l_operstate;
   1351 	else
   1352 		return IF_OPER_UNKNOWN;
   1353 }
   1354 
   1355 void rtnl_link_set_linkmode(struct rtnl_link *link, uint8_t linkmode)
   1356 {
   1357 	link->l_linkmode = linkmode;
   1358 	link->ce_mask |= LINK_ATTR_LINKMODE;
   1359 }
   1360 
   1361 uint8_t rtnl_link_get_linkmode(struct rtnl_link *link)
   1362 {
   1363 	if (link->ce_mask & LINK_ATTR_LINKMODE)
   1364 		return link->l_linkmode;
   1365 	else
   1366 		return IF_LINK_MODE_DEFAULT;
   1367 }
   1368 
   1369 uint64_t rtnl_link_get_stat(struct rtnl_link *link, int id)
   1370 {
   1371 	if (id < 0 || id > RTNL_LINK_STATS_MAX)
   1372 		return 0;
   1373 
   1374 	return link->l_stats[id];
   1375 }
   1376 
   1377 /**
   1378  * Specify the info type of a link
   1379  * @arg link	link object
   1380  * @arg type	info type
   1381  *
   1382  * Looks up the info type and prepares the link to store info type
   1383  * specific attributes. If an info type has been assigned already
   1384  * it will be released with all changes lost.
   1385  *
   1386  * @return 0 on success or a negative errror code.
   1387  */
   1388 int rtnl_link_set_info_type(struct rtnl_link *link, const char *type)
   1389 {
   1390 	struct rtnl_link_info_ops *io;
   1391 	int err;
   1392 
   1393 	if ((io = rtnl_link_info_ops_lookup(type)) == NULL)
   1394 		return -NLE_OPNOTSUPP;
   1395 
   1396 	if (link->l_info_ops)
   1397 		release_link_info(link);
   1398 
   1399 	if ((err = io->io_alloc(link)) < 0)
   1400 		return err;
   1401 
   1402 	link->l_info_ops = io;
   1403 
   1404 	return 0;
   1405 }
   1406 
   1407 /**
   1408  * Return info type of a link
   1409  * @arg link	link object
   1410  *
   1411  * @note The returned pointer is only valid as long as the link exists
   1412  * @return Info type name or NULL if unknown.
   1413  */
   1414 char *rtnl_link_get_info_type(struct rtnl_link *link)
   1415 {
   1416 	if (link->l_info_ops)
   1417 		return link->l_info_ops->io_name;
   1418 	else
   1419 		return NULL;
   1420 }
   1421 
   1422 /** @} */
   1423 
   1424 static struct nl_object_ops link_obj_ops = {
   1425 	.oo_name		= "route/link",
   1426 	.oo_size		= sizeof(struct rtnl_link),
   1427 	.oo_free_data		= link_free_data,
   1428 	.oo_clone		= link_clone,
   1429 	.oo_dump = {
   1430 	    [NL_DUMP_LINE]	= link_dump_line,
   1431 	    [NL_DUMP_DETAILS]	= link_dump_details,
   1432 	    [NL_DUMP_STATS]	= link_dump_stats,
   1433 	    [NL_DUMP_ENV]	= link_dump_env,
   1434 	},
   1435 	.oo_compare		= link_compare,
   1436 	.oo_attrs2str		= link_attrs2str,
   1437 	.oo_id_attrs		= LINK_ATTR_IFINDEX,
   1438 };
   1439 
   1440 static struct nl_af_group link_groups[] = {
   1441 	{ AF_UNSPEC,	RTNLGRP_LINK },
   1442 	{ END_OF_GROUP_LIST },
   1443 };
   1444 
   1445 static struct nl_cache_ops rtnl_link_ops = {
   1446 	.co_name		= "route/link",
   1447 	.co_hdrsize		= sizeof(struct ifinfomsg),
   1448 	.co_msgtypes		= {
   1449 					{ RTM_NEWLINK, NL_ACT_NEW, "new" },
   1450 					{ RTM_DELLINK, NL_ACT_DEL, "del" },
   1451 					{ RTM_GETLINK, NL_ACT_GET, "get" },
   1452 					END_OF_MSGTYPES_LIST,
   1453 				  },
   1454 	.co_protocol		= NETLINK_ROUTE,
   1455 	.co_groups		= link_groups,
   1456 	.co_request_update	= link_request_update,
   1457 	.co_msg_parser		= link_msg_parser,
   1458 	.co_obj_ops		= &link_obj_ops,
   1459 };
   1460 
   1461 static void __init link_init(void)
   1462 {
   1463 	nl_cache_mngt_register(&rtnl_link_ops);
   1464 }
   1465 
   1466 static void __exit link_exit(void)
   1467 {
   1468 	nl_cache_mngt_unregister(&rtnl_link_ops);
   1469 }
   1470 
   1471 /** @} */
   1472