link.c revision a7469ce758fac3631df6ce72eb3f89150070e7f8
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-2006 Thomas Graf <tgraf@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(nl_handle);
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(nl_handle, 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(nl_handle, 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
180static struct nl_cache_ops rtnl_link_ops;
181static struct nl_object_ops link_obj_ops;
182/** @endcond */
183
184static 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
195static 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
210static 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			goto errout;
219
220	if (src->l_bcast)
221		if (!(dst->l_bcast = nl_addr_clone(src->l_bcast)))
222			goto errout;
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			goto errout;
228	}
229
230	return 0;
231errout:
232	return nl_get_errno();
233}
234
235static struct nla_policy link_policy[IFLA_MAX+1] = {
236	[IFLA_IFNAME]	= { .type = NLA_STRING,
237			    .maxlen = IFNAMSIZ },
238	[IFLA_MTU]	= { .type = NLA_U32 },
239	[IFLA_TXQLEN]	= { .type = NLA_U32 },
240	[IFLA_LINK]	= { .type = NLA_U32 },
241	[IFLA_WEIGHT]	= { .type = NLA_U32 },
242	[IFLA_MASTER]	= { .type = NLA_U32 },
243	[IFLA_OPERSTATE]= { .type = NLA_U8 },
244	[IFLA_LINKMODE] = { .type = NLA_U8 },
245	[IFLA_LINKINFO]	= { .type = NLA_NESTED },
246	[IFLA_QDISC]	= { .type = NLA_STRING,
247			    .maxlen = IFQDISCSIZ },
248	[IFLA_STATS]	= { .minlen = sizeof(struct rtnl_link_stats) },
249	[IFLA_MAP]	= { .minlen = sizeof(struct rtnl_link_ifmap) },
250};
251
252static struct nla_policy link_info_policy[IFLA_INFO_MAX+1] = {
253	[IFLA_INFO_KIND]	= { .type = NLA_STRING },
254	[IFLA_INFO_DATA]	= { .type = NLA_NESTED },
255	[IFLA_INFO_XSTATS]	= { .type = NLA_NESTED },
256};
257
258static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
259			   struct nlmsghdr *n, struct nl_parser_param *pp)
260{
261	struct rtnl_link *link;
262	struct ifinfomsg *ifi;
263	struct nlattr *tb[IFLA_MAX+1];
264	int err;
265
266	link = rtnl_link_alloc();
267	if (link == NULL) {
268		err = nl_errno(ENOMEM);
269		goto errout;
270	}
271
272	link->ce_msgtype = n->nlmsg_type;
273
274	err = nlmsg_parse(n, sizeof(*ifi), tb, IFLA_MAX, link_policy);
275	if (err < 0)
276		goto errout;
277
278	if (tb[IFLA_IFNAME] == NULL) {
279		err = nl_error(EINVAL, "Missing link name TLV");
280		goto errout;
281	}
282
283	nla_strlcpy(link->l_name, tb[IFLA_IFNAME], IFNAMSIZ);
284
285	ifi = nlmsg_data(n);
286	link->l_family = ifi->ifi_family;
287	link->l_arptype = ifi->ifi_type;
288	link->l_index = ifi->ifi_index;
289	link->l_flags = ifi->ifi_flags;
290	link->l_change = ifi->ifi_change;
291	link->ce_mask = (LINK_ATTR_IFNAME | LINK_ATTR_FAMILY |
292			  LINK_ATTR_ARPTYPE| LINK_ATTR_IFINDEX |
293			  LINK_ATTR_FLAGS | LINK_ATTR_CHANGE);
294
295	if (tb[IFLA_STATS]) {
296		struct rtnl_link_stats *st = nla_data(tb[IFLA_STATS]);
297
298		link->l_stats[RTNL_LINK_RX_PACKETS]	= st->rx_packets;
299		link->l_stats[RTNL_LINK_RX_BYTES]	= st->rx_bytes;
300		link->l_stats[RTNL_LINK_RX_ERRORS]	= st->rx_errors;
301		link->l_stats[RTNL_LINK_RX_DROPPED]	= st->rx_dropped;
302		link->l_stats[RTNL_LINK_RX_COMPRESSED]	= st->rx_compressed;
303		link->l_stats[RTNL_LINK_RX_FIFO_ERR]	= st->rx_fifo_errors;
304		link->l_stats[RTNL_LINK_TX_PACKETS]	= st->tx_packets;
305		link->l_stats[RTNL_LINK_TX_BYTES]	= st->tx_bytes;
306		link->l_stats[RTNL_LINK_TX_ERRORS]	= st->tx_errors;
307		link->l_stats[RTNL_LINK_TX_DROPPED]	= st->tx_dropped;
308		link->l_stats[RTNL_LINK_TX_COMPRESSED]	= st->tx_compressed;
309		link->l_stats[RTNL_LINK_TX_FIFO_ERR]	= st->tx_fifo_errors;
310		link->l_stats[RTNL_LINK_RX_LEN_ERR]	= st->rx_length_errors;
311		link->l_stats[RTNL_LINK_RX_OVER_ERR]	= st->rx_over_errors;
312		link->l_stats[RTNL_LINK_RX_CRC_ERR]	= st->rx_crc_errors;
313		link->l_stats[RTNL_LINK_RX_FRAME_ERR]	= st->rx_frame_errors;
314		link->l_stats[RTNL_LINK_RX_MISSED_ERR]	= st->rx_missed_errors;
315		link->l_stats[RTNL_LINK_TX_ABORT_ERR]	= st->tx_aborted_errors;
316		link->l_stats[RTNL_LINK_TX_CARRIER_ERR]	= st->tx_carrier_errors;
317		link->l_stats[RTNL_LINK_TX_HBEAT_ERR]	= st->tx_heartbeat_errors;
318		link->l_stats[RTNL_LINK_TX_WIN_ERR]	= st->tx_window_errors;
319		link->l_stats[RTNL_LINK_MULTICAST]	= st->multicast;
320
321		link->ce_mask |= LINK_ATTR_STATS;
322	}
323
324	if (tb[IFLA_TXQLEN]) {
325		link->l_txqlen = nla_get_u32(tb[IFLA_TXQLEN]);
326		link->ce_mask |= LINK_ATTR_TXQLEN;
327	}
328
329	if (tb[IFLA_MTU]) {
330		link->l_mtu = nla_get_u32(tb[IFLA_MTU]);
331		link->ce_mask |= LINK_ATTR_MTU;
332	}
333
334	if (tb[IFLA_ADDRESS]) {
335		link->l_addr = nla_get_addr(tb[IFLA_ADDRESS], AF_UNSPEC);
336		if (link->l_addr == NULL)
337			goto errout;
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 = nla_get_addr(tb[IFLA_BROADCAST], AF_UNSPEC);
345		if (link->l_bcast == NULL)
346			goto errout;
347		nl_addr_set_family(link->l_bcast,
348				   nl_addr_guess_family(link->l_bcast));
349		link->ce_mask |= LINK_ATTR_BRD;
350	}
351
352	if (tb[IFLA_LINK]) {
353		link->l_link = nla_get_u32(tb[IFLA_LINK]);
354		link->ce_mask |= LINK_ATTR_LINK;
355	}
356
357	if (tb[IFLA_WEIGHT]) {
358		link->l_weight = nla_get_u32(tb[IFLA_WEIGHT]);
359		link->ce_mask |= LINK_ATTR_WEIGHT;
360	}
361
362	if (tb[IFLA_QDISC]) {
363		nla_strlcpy(link->l_qdisc, tb[IFLA_QDISC], IFQDISCSIZ);
364		link->ce_mask |= LINK_ATTR_QDISC;
365	}
366
367	if (tb[IFLA_MAP]) {
368		struct rtnl_link_ifmap *map =  nla_data(tb[IFLA_MAP]);
369		link->l_map.lm_mem_start = map->mem_start;
370		link->l_map.lm_mem_end   = map->mem_end;
371		link->l_map.lm_base_addr = map->base_addr;
372		link->l_map.lm_irq       = map->irq;
373		link->l_map.lm_dma       = map->dma;
374		link->l_map.lm_port      = map->port;
375		link->ce_mask |= LINK_ATTR_MAP;
376	}
377
378	if (tb[IFLA_MASTER]) {
379		link->l_master = nla_get_u32(tb[IFLA_MASTER]);
380		link->ce_mask |= LINK_ATTR_MASTER;
381	}
382
383	if (tb[IFLA_OPERSTATE]) {
384		link->l_operstate = nla_get_u8(tb[IFLA_OPERSTATE]);
385		link->ce_mask |= LINK_ATTR_OPERSTATE;
386	}
387
388	if (tb[IFLA_LINKMODE]) {
389		link->l_linkmode = nla_get_u8(tb[IFLA_LINKMODE]);
390		link->ce_mask |= LINK_ATTR_LINKMODE;
391	}
392
393	if (tb[IFLA_LINKINFO]) {
394		struct nlattr *li[IFLA_INFO_MAX+1];
395
396		err = nla_parse_nested(li, IFLA_INFO_MAX, tb[IFLA_LINKINFO],
397				       link_info_policy);
398		if (err < 0)
399			goto errout;
400
401		if (li[IFLA_INFO_KIND] &&
402		    (li[IFLA_INFO_DATA] || li[IFLA_INFO_XSTATS])) {
403			struct rtnl_link_info_ops *ops;
404			char *kind;
405
406			kind = nla_get_string(li[IFLA_INFO_KIND]);
407			ops = rtnl_link_info_ops_lookup(kind);
408			if (ops != NULL) {
409				ops->io_refcnt++;
410				link->l_info_ops = ops;
411				err = ops->io_parse(link, li[IFLA_INFO_DATA],
412						    li[IFLA_INFO_XSTATS]);
413				if (err < 0)
414					goto errout;
415			} else {
416				/* XXX: Warn about unparsed info? */
417			}
418		}
419	}
420
421	err = pp->pp_cb((struct nl_object *) link, pp);
422	if (err < 0)
423		goto errout;
424
425	err = P_ACCEPT;
426
427errout:
428	rtnl_link_put(link);
429	return err;
430}
431
432static int link_request_update(struct nl_cache *c, struct nl_handle *h)
433{
434	return nl_rtgen_request(h, RTM_GETLINK, AF_UNSPEC, NLM_F_DUMP);
435}
436
437static int link_dump_brief(struct nl_object *obj, struct nl_dump_params *p)
438{
439	char buf[128];
440	struct nl_cache *cache = dp_cache(obj);
441	struct rtnl_link *link = (struct rtnl_link *) obj;
442	int line = 1;
443
444	dp_dump(p, "%s %s ", link->l_name,
445			     nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
446
447	if (link->l_addr && !nl_addr_iszero(link->l_addr))
448		dp_dump(p, "%s ", nl_addr2str(link->l_addr, buf, sizeof(buf)));
449
450	if (link->ce_mask & LINK_ATTR_MASTER) {
451		struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
452		dp_dump(p, "master %s ", master ? master->l_name : "inv");
453		if (master)
454			rtnl_link_put(master);
455	}
456
457	rtnl_link_flags2str(link->l_flags, buf, sizeof(buf));
458	if (buf[0])
459		dp_dump(p, "<%s> ", buf);
460
461	if (link->ce_mask & LINK_ATTR_LINK) {
462		struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
463		dp_dump(p, "slave-of %s ", ll ? ll->l_name : "NONE");
464		if (ll)
465			rtnl_link_put(ll);
466	}
467
468	if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_BRIEF])
469		line = link->l_info_ops->io_dump[NL_DUMP_BRIEF](link, p, line);
470
471	dp_dump(p, "\n");
472
473	return line;
474}
475
476static int link_dump_full(struct nl_object *obj, struct nl_dump_params *p)
477{
478	struct rtnl_link *link = (struct rtnl_link *) obj;
479	char buf[64];
480	int line;
481
482	line = link_dump_brief(obj, p);
483	dp_new_line(p, line++);
484
485	dp_dump(p, "    mtu %u ", link->l_mtu);
486	dp_dump(p, "txqlen %u weight %u ", link->l_txqlen, link->l_weight);
487
488	if (link->ce_mask & LINK_ATTR_QDISC)
489		dp_dump(p, "qdisc %s ", link->l_qdisc);
490
491	if (link->ce_mask & LINK_ATTR_MAP && link->l_map.lm_irq)
492		dp_dump(p, "irq %u ", link->l_map.lm_irq);
493
494	if (link->ce_mask & LINK_ATTR_IFINDEX)
495		dp_dump(p, "index %u ", link->l_index);
496
497
498	dp_dump(p, "\n");
499	dp_new_line(p, line++);
500
501	dp_dump(p, "    ");
502
503	if (link->ce_mask & LINK_ATTR_BRD)
504		dp_dump(p, "brd %s ", nl_addr2str(link->l_bcast, buf,
505						   sizeof(buf)));
506
507	if ((link->ce_mask & LINK_ATTR_OPERSTATE) &&
508	    link->l_operstate != IF_OPER_UNKNOWN) {
509		rtnl_link_operstate2str(link->l_operstate, buf, sizeof(buf));
510		dp_dump(p, "state %s ", buf);
511	}
512
513	dp_dump(p, "mode %s\n",
514		rtnl_link_mode2str(link->l_linkmode, buf, sizeof(buf)));
515
516	if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_FULL])
517		line = link->l_info_ops->io_dump[NL_DUMP_FULL](link, p, line);
518
519	return line;
520}
521
522static int link_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
523{
524	struct rtnl_link *link = (struct rtnl_link *) obj;
525	char *unit, fmt[64];
526	float res;
527	int line;
528
529	line = link_dump_full(obj, p);
530
531	dp_dump_line(p, line++, "    Stats:    bytes    packets     errors "
532				"   dropped   fifo-err compressed\n");
533
534	res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_RX_BYTES], &unit);
535
536	strcpy(fmt, "    RX  %X.2f %s %10llu %10llu %10llu %10llu %10llu\n");
537	fmt[9] = *unit == 'B' ? '9' : '7';
538
539	dp_dump_line(p, line++, fmt,
540		res, unit,
541		link->l_stats[RTNL_LINK_RX_PACKETS],
542		link->l_stats[RTNL_LINK_RX_ERRORS],
543		link->l_stats[RTNL_LINK_RX_DROPPED],
544		link->l_stats[RTNL_LINK_RX_FIFO_ERR],
545		link->l_stats[RTNL_LINK_RX_COMPRESSED]);
546
547	res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_TX_BYTES], &unit);
548
549	strcpy(fmt, "    TX  %X.2f %s %10llu %10llu %10llu %10llu %10llu\n");
550	fmt[9] = *unit == 'B' ? '9' : '7';
551
552	dp_dump_line(p, line++, fmt,
553		res, unit,
554		link->l_stats[RTNL_LINK_TX_PACKETS],
555		link->l_stats[RTNL_LINK_TX_ERRORS],
556		link->l_stats[RTNL_LINK_TX_DROPPED],
557		link->l_stats[RTNL_LINK_TX_FIFO_ERR],
558		link->l_stats[RTNL_LINK_TX_COMPRESSED]);
559
560	dp_dump_line(p, line++, "    Errors:  length       over        crc "
561				"     frame     missed  multicast\n");
562
563	dp_dump_line(p, line++, "    RX   %10" PRIu64 " %10" PRIu64 " %10"
564				PRIu64 " %10" PRIu64 " %10" PRIu64 " %10"
565				PRIu64 "\n",
566		link->l_stats[RTNL_LINK_RX_LEN_ERR],
567		link->l_stats[RTNL_LINK_RX_OVER_ERR],
568		link->l_stats[RTNL_LINK_RX_CRC_ERR],
569		link->l_stats[RTNL_LINK_RX_FRAME_ERR],
570		link->l_stats[RTNL_LINK_RX_MISSED_ERR],
571		link->l_stats[RTNL_LINK_MULTICAST]);
572
573	dp_dump_line(p, line++, "    Errors: aborted    carrier  heartbeat "
574				"    window  collision\n");
575
576	dp_dump_line(p, line++, "    TX   %10" PRIu64 " %10" PRIu64 " %10"
577				PRIu64 " %10" PRIu64 " %10" PRIu64 "\n",
578		link->l_stats[RTNL_LINK_TX_ABORT_ERR],
579		link->l_stats[RTNL_LINK_TX_CARRIER_ERR],
580		link->l_stats[RTNL_LINK_TX_HBEAT_ERR],
581		link->l_stats[RTNL_LINK_TX_WIN_ERR],
582		link->l_stats[RTNL_LINK_TX_COLLISIONS]);
583
584	if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_STATS])
585		line = link->l_info_ops->io_dump[NL_DUMP_STATS](link, p, line);
586
587	return line;
588}
589
590static int link_dump_xml(struct nl_object *obj, struct nl_dump_params *p)
591{
592	struct rtnl_link *link = (struct rtnl_link *) obj;
593	struct nl_cache *cache = dp_cache(obj);
594	char buf[128];
595	int i, line = 0;
596
597	dp_dump_line(p, line++, "<link name=\"%s\" index=\"%u\">\n",
598		     link->l_name, link->l_index);
599	dp_dump_line(p, line++, "  <family>%s</family>\n",
600		     nl_af2str(link->l_family, buf, sizeof(buf)));
601	dp_dump_line(p, line++, "  <arptype>%s</arptype>\n",
602		     nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
603	dp_dump_line(p, line++, "  <address>%s</address>\n",
604		     nl_addr2str(link->l_addr, buf, sizeof(buf)));
605	dp_dump_line(p, line++, "  <mtu>%u</mtu>\n", link->l_mtu);
606	dp_dump_line(p, line++, "  <txqlen>%u</txqlen>\n", link->l_txqlen);
607	dp_dump_line(p, line++, "  <weight>%u</weight>\n", link->l_weight);
608
609	rtnl_link_flags2str(link->l_flags, buf, sizeof(buf));
610	if (buf[0])
611		dp_dump_line(p, line++, "  <flags>%s</flags>\n", buf);
612
613	if (link->ce_mask & LINK_ATTR_QDISC)
614		dp_dump_line(p, line++, "  <qdisc>%s</qdisc>\n", link->l_qdisc);
615
616	if (link->ce_mask & LINK_ATTR_LINK) {
617		struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
618		dp_dump_line(p, line++, "  <link>%s</link>\n",
619			     ll ? ll->l_name : "none");
620		if (ll)
621			rtnl_link_put(ll);
622	}
623
624	if (link->ce_mask & LINK_ATTR_MASTER) {
625		struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
626		dp_dump_line(p, line++, "  <master>%s</master>\n",
627			     master ? master->l_name : "none");
628		if (master)
629			rtnl_link_put(master);
630	}
631
632	if (link->ce_mask & LINK_ATTR_BRD)
633		dp_dump_line(p, line++, "  <broadcast>%s</broadcast>\n",
634			     nl_addr2str(link->l_bcast, buf, sizeof(buf)));
635
636	if (link->ce_mask & LINK_ATTR_STATS) {
637		dp_dump_line(p, line++, "  <stats>\n");
638		for (i = 0; i <= RTNL_LINK_STATS_MAX; i++) {
639			rtnl_link_stat2str(i, buf, sizeof(buf));
640			dp_dump_line(p, line++,
641				     "    <%s>%" PRIu64 "</%s>\n",
642				     buf, link->l_stats[i], buf);
643		}
644		dp_dump_line(p, line++, "  </stats>\n");
645	}
646
647	if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_XML]) {
648		dp_dump_line(p, line++, "  <info>\n");
649		line = link->l_info_ops->io_dump[NL_DUMP_XML](link, p, line);
650		dp_dump_line(p, line++, "  </info>\n");
651	}
652
653	dp_dump_line(p, line++, "</link>\n");
654
655#if 0
656	uint32_t	l_change;	/**< Change mask */
657	struct rtnl_lifmap l_map;	/**< Interface device mapping */
658#endif
659
660	return line;
661}
662
663static int link_dump_env(struct nl_object *obj, struct nl_dump_params *p)
664{
665	struct rtnl_link *link = (struct rtnl_link *) obj;
666	struct nl_cache *cache = dp_cache(obj);
667	char buf[128];
668	int i, line = 0;
669
670	dp_dump_line(p, line++, "LINK_NAME=%s\n", link->l_name);
671	dp_dump_line(p, line++, "LINK_IFINDEX=%u\n", link->l_index);
672	dp_dump_line(p, line++, "LINK_FAMILY=%s\n",
673		     nl_af2str(link->l_family, buf, sizeof(buf)));
674	dp_dump_line(p, line++, "LINK_TYPE=%s\n",
675		     nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
676	if (link->ce_mask & LINK_ATTR_ADDR)
677		dp_dump_line(p, line++, "LINK_ADDRESS=%s\n",
678			     nl_addr2str(link->l_addr, buf, sizeof(buf)));
679	dp_dump_line(p, line++, "LINK_MTU=%u\n", link->l_mtu);
680	dp_dump_line(p, line++, "LINK_TXQUEUELEN=%u\n", link->l_txqlen);
681	dp_dump_line(p, line++, "LINK_WEIGHT=%u\n", link->l_weight);
682
683	rtnl_link_flags2str(link->l_flags & ~IFF_RUNNING, buf, sizeof(buf));
684	if (buf[0])
685		dp_dump_line(p, line++, "LINK_FLAGS=%s\n", buf);
686
687	if (link->ce_mask & LINK_ATTR_QDISC)
688		dp_dump_line(p, line++, "LINK_QDISC=%s\n", link->l_qdisc);
689
690	if (link->ce_mask & LINK_ATTR_LINK) {
691		struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
692
693		dp_dump_line(p, line++, "LINK_LINK_IFINDEX=%d\n", link->l_link);
694		if (ll) {
695			dp_dump_line(p, line++, "LINK_LINK_IFNAME=%s\n",
696				     ll->l_name);
697			rtnl_link_put(ll);
698		}
699	}
700
701	if (link->ce_mask & LINK_ATTR_MASTER) {
702		struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
703		dp_dump_line(p, line++, "LINK_MASTER=%s\n",
704			     master ? master->l_name : "none");
705		if (master)
706			rtnl_link_put(master);
707	}
708
709	if (link->ce_mask & LINK_ATTR_BRD)
710		dp_dump_line(p, line++, "LINK_BROADCAST=%s\n",
711			     nl_addr2str(link->l_bcast, buf, sizeof(buf)));
712
713	if (link->ce_mask & LINK_ATTR_STATS) {
714		for (i = 0; i <= RTNL_LINK_STATS_MAX; i++) {
715			char *c = buf;
716
717			sprintf(buf, "LINK_");
718			rtnl_link_stat2str(i, buf + 5, sizeof(buf) - 5);
719			while (*c) {
720				*c = toupper(*c);
721				c++;
722			}
723			dp_dump_line(p, line++,
724				     "%s=%" PRIu64 "\n", buf, link->l_stats[i]);
725		}
726	}
727
728	if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_ENV])
729		line = link->l_info_ops->io_dump[NL_DUMP_ENV](link, p, line);
730
731	return line;
732}
733
734#if 0
735static int link_handle_event(struct nl_object *a, struct rtnl_link_event_cb *cb)
736{
737	struct rtnl_link *l = (struct rtnl_link *) a;
738	struct nl_cache *c = dp_cache(a);
739	int nevents = 0;
740
741	if (l->l_change == ~0U) {
742		if (l->ce_msgtype == RTM_NEWLINK)
743			cb->le_register(l);
744		else
745			cb->le_unregister(l);
746
747		return 1;
748	}
749
750	if (l->l_change & IFF_SLAVE) {
751		if (l->l_flags & IFF_SLAVE) {
752			struct rtnl_link *m = rtnl_link_get(c, l->l_master);
753			cb->le_new_bonding(l, m);
754			if (m)
755				rtnl_link_put(m);
756		} else
757			cb->le_cancel_bonding(l);
758	}
759
760#if 0
761	if (l->l_change & IFF_UP && l->l_change & IFF_RUNNING)
762		dp_dump_line(p, line++, "link %s changed state to %s.\n",
763			l->l_name, l->l_flags & IFF_UP ? "up" : "down");
764
765	if (l->l_change & IFF_PROMISC) {
766		dp_new_line(p, line++);
767		dp_dump(p, "link %s %s promiscuous mode.\n",
768		    l->l_name, l->l_flags & IFF_PROMISC ? "entered" : "left");
769	}
770
771	if (line == 0)
772		dp_dump_line(p, line++, "link %s sent unknown event.\n",
773			     l->l_name);
774#endif
775
776	return nevents;
777}
778#endif
779
780static int link_compare(struct nl_object *_a, struct nl_object *_b,
781			uint32_t attrs, int flags)
782{
783	struct rtnl_link *a = (struct rtnl_link *) _a;
784	struct rtnl_link *b = (struct rtnl_link *) _b;
785	int diff = 0;
786
787#define LINK_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, LINK_ATTR_##ATTR, a, b, EXPR)
788
789	diff |= LINK_DIFF(IFINDEX,	a->l_index != b->l_index);
790	diff |= LINK_DIFF(MTU,		a->l_mtu != b->l_mtu);
791	diff |= LINK_DIFF(LINK,		a->l_link != b->l_link);
792	diff |= LINK_DIFF(TXQLEN,	a->l_txqlen != b->l_txqlen);
793	diff |= LINK_DIFF(WEIGHT,	a->l_weight != b->l_weight);
794	diff |= LINK_DIFF(MASTER,	a->l_master != b->l_master);
795	diff |= LINK_DIFF(FAMILY,	a->l_family != b->l_family);
796	diff |= LINK_DIFF(OPERSTATE,	a->l_operstate != b->l_operstate);
797	diff |= LINK_DIFF(LINKMODE,	a->l_linkmode != b->l_linkmode);
798	diff |= LINK_DIFF(QDISC,	strcmp(a->l_qdisc, b->l_qdisc));
799	diff |= LINK_DIFF(IFNAME,	strcmp(a->l_name, b->l_name));
800	diff |= LINK_DIFF(ADDR,		nl_addr_cmp(a->l_addr, b->l_addr));
801	diff |= LINK_DIFF(BRD,		nl_addr_cmp(a->l_bcast, b->l_bcast));
802
803	if (flags & LOOSE_FLAG_COMPARISON)
804		diff |= LINK_DIFF(FLAGS,
805				  (a->l_flags ^ b->l_flags) & b->l_flag_mask);
806	else
807		diff |= LINK_DIFF(FLAGS, a->l_flags != b->l_flags);
808
809#undef LINK_DIFF
810
811	return diff;
812}
813
814static struct trans_tbl link_attrs[] = {
815	__ADD(LINK_ATTR_MTU, mtu)
816	__ADD(LINK_ATTR_LINK, link)
817	__ADD(LINK_ATTR_TXQLEN, txqlen)
818	__ADD(LINK_ATTR_WEIGHT, weight)
819	__ADD(LINK_ATTR_MASTER, master)
820	__ADD(LINK_ATTR_QDISC, qdisc)
821	__ADD(LINK_ATTR_MAP, map)
822	__ADD(LINK_ATTR_ADDR, address)
823	__ADD(LINK_ATTR_BRD, broadcast)
824	__ADD(LINK_ATTR_FLAGS, flags)
825	__ADD(LINK_ATTR_IFNAME, name)
826	__ADD(LINK_ATTR_IFINDEX, ifindex)
827	__ADD(LINK_ATTR_FAMILY, family)
828	__ADD(LINK_ATTR_ARPTYPE, arptype)
829	__ADD(LINK_ATTR_STATS, stats)
830	__ADD(LINK_ATTR_CHANGE, change)
831	__ADD(LINK_ATTR_OPERSTATE, operstate)
832	__ADD(LINK_ATTR_LINKMODE, linkmode)
833};
834
835static char *link_attrs2str(int attrs, char *buf, size_t len)
836{
837	return __flags2str(attrs, buf, len, link_attrs,
838			   ARRAY_SIZE(link_attrs));
839}
840
841/**
842 * @name Allocation/Freeing
843 * @{
844 */
845
846struct rtnl_link *rtnl_link_alloc(void)
847{
848	return (struct rtnl_link *) nl_object_alloc(&link_obj_ops);
849}
850
851void rtnl_link_put(struct rtnl_link *link)
852{
853	nl_object_put((struct nl_object *) link);
854}
855
856/** @} */
857
858/**
859 * @name Cache Management
860 * @{
861 */
862
863
864/**
865 * Allocate link cache and fill in all configured links.
866 * @arg handle		Netlink handle.
867 *
868 * Allocates a new link cache, initializes it properly and updates it
869 * to include all links currently configured in the kernel.
870 *
871 * @note Free the memory after usage.
872 * @return Newly allocated cache or NULL if an error occured.
873 */
874struct nl_cache *rtnl_link_alloc_cache(struct nl_handle *handle)
875{
876	struct nl_cache * cache;
877
878	cache = nl_cache_alloc(&rtnl_link_ops);
879	if (cache == NULL)
880		return NULL;
881
882	if (handle && nl_cache_refill(handle, cache) < 0) {
883		nl_cache_free(cache);
884		return NULL;
885	}
886
887	return cache;
888}
889
890/**
891 * Look up link by interface index in the provided cache
892 * @arg cache		link cache
893 * @arg ifindex		link interface index
894 *
895 * The caller owns a reference on the returned object and
896 * must give the object back via rtnl_link_put().
897 *
898 * @return pointer to link inside the cache or NULL if no match was found.
899 */
900struct rtnl_link *rtnl_link_get(struct nl_cache *cache, int ifindex)
901{
902	struct rtnl_link *link;
903
904	if (cache->c_ops != &rtnl_link_ops)
905		return NULL;
906
907	nl_list_for_each_entry(link, &cache->c_items, ce_list) {
908		if (link->l_index == ifindex) {
909			nl_object_get((struct nl_object *) link);
910			return link;
911		}
912	}
913
914	return NULL;
915}
916
917/**
918 * Look up link by link name in the provided cache
919 * @arg cache		link cache
920 * @arg name		link name
921 *
922 * The caller owns a reference on the returned object and
923 * must give the object back via rtnl_link_put().
924 *
925 * @return pointer to link inside the cache or NULL if no match was found.
926 */
927struct rtnl_link *rtnl_link_get_by_name(struct nl_cache *cache,
928					 const char *name)
929{
930	struct rtnl_link *link;
931
932	if (cache->c_ops != &rtnl_link_ops)
933		return NULL;
934
935	nl_list_for_each_entry(link, &cache->c_items, ce_list) {
936		if (!strcmp(name, link->l_name)) {
937			nl_object_get((struct nl_object *) link);
938			return link;
939		}
940	}
941
942	return NULL;
943}
944
945/** @} */
946
947/**
948 * @name Link Modifications
949 * @{
950 */
951
952/**
953 * Builds a netlink change request message to change link attributes
954 * @arg old		link to be changed
955 * @arg tmpl		template with requested changes
956 * @arg flags		additional netlink message flags
957 *
958 * Builds a new netlink message requesting a change of link attributes.
959 * The netlink message header isn't fully equipped with all relevant
960 * fields and must be sent out via nl_send_auto_complete() or
961 * supplemented as needed.
962 * \a old must point to a link currently configured in the kernel
963 * and \a tmpl must contain the attributes to be changed set via
964 * \c rtnl_link_set_* functions.
965 *
966 * @return New netlink message
967 * @note Not all attributes can be changed, see
968 *       \ref link_changeable "Changeable Attributes" for more details.
969 */
970struct nl_msg * rtnl_link_build_change_request(struct rtnl_link *old,
971					       struct rtnl_link *tmpl,
972					       int flags)
973{
974	struct nl_msg *msg;
975	struct ifinfomsg ifi = {
976		.ifi_family = old->l_family,
977		.ifi_index = old->l_index,
978	};
979
980	if (tmpl->ce_mask & LINK_ATTR_FLAGS) {
981		ifi.ifi_flags = old->l_flags & ~tmpl->l_flag_mask;
982		ifi.ifi_flags |= tmpl->l_flags;
983	}
984
985	msg = nlmsg_alloc_simple(RTM_SETLINK, flags);
986	if (!msg)
987		goto nla_put_failure;
988
989	if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
990		goto nla_put_failure;
991
992	if (tmpl->ce_mask & LINK_ATTR_ADDR)
993		NLA_PUT_ADDR(msg, IFLA_ADDRESS, tmpl->l_addr);
994
995	if (tmpl->ce_mask & LINK_ATTR_BRD)
996		NLA_PUT_ADDR(msg, IFLA_BROADCAST, tmpl->l_bcast);
997
998	if (tmpl->ce_mask & LINK_ATTR_MTU)
999		NLA_PUT_U32(msg, IFLA_MTU, tmpl->l_mtu);
1000
1001	if (tmpl->ce_mask & LINK_ATTR_TXQLEN)
1002		NLA_PUT_U32(msg, IFLA_TXQLEN, tmpl->l_txqlen);
1003
1004	if (tmpl->ce_mask & LINK_ATTR_WEIGHT)
1005		NLA_PUT_U32(msg, IFLA_WEIGHT, tmpl->l_weight);
1006
1007	if (tmpl->ce_mask & LINK_ATTR_IFNAME)
1008		NLA_PUT_STRING(msg, IFLA_IFNAME, tmpl->l_name);
1009
1010	if (tmpl->ce_mask & LINK_ATTR_OPERSTATE)
1011		NLA_PUT_U8(msg, IFLA_OPERSTATE, tmpl->l_operstate);
1012
1013	if (tmpl->ce_mask & LINK_ATTR_LINKMODE)
1014		NLA_PUT_U8(msg, IFLA_LINKMODE, tmpl->l_linkmode);
1015
1016	if ((tmpl->ce_mask & LINK_ATTR_LINKINFO) && tmpl->l_info_ops &&
1017	    tmpl->l_info_ops->io_put_attrs) {
1018		struct nlattr *info;
1019
1020		if (!(info = nla_nest_start(msg, IFLA_LINKINFO)))
1021			goto nla_put_failure;
1022
1023		NLA_PUT_STRING(msg, IFLA_INFO_KIND, tmpl->l_info_ops->io_name);
1024
1025		if (tmpl->l_info_ops->io_put_attrs(msg, tmpl) < 0)
1026			goto nla_put_failure;
1027
1028		nla_nest_end(msg, info);
1029	}
1030
1031	return msg;
1032
1033nla_put_failure:
1034	nlmsg_free(msg);
1035	return NULL;
1036}
1037
1038/**
1039 * Change link attributes
1040 * @arg handle		netlink handle
1041 * @arg old		link to be changed
1042 * @arg tmpl		template with requested changes
1043 * @arg flags		additional netlink message flags
1044 *
1045 * Builds a new netlink message by calling rtnl_link_build_change_request(),
1046 * sends the request to the kernel and waits for the next ACK to be
1047 * received, i.e. blocks until the request has been processed.
1048 *
1049 * @return 0 on success or a negative error code
1050 * @note Not all attributes can be changed, see
1051 *       \ref link_changeable "Changeable Attributes" for more details.
1052 */
1053int rtnl_link_change(struct nl_handle *handle, struct rtnl_link *old,
1054		     struct rtnl_link *tmpl, int flags)
1055{
1056	int err;
1057	struct nl_msg *msg;
1058
1059	msg = rtnl_link_build_change_request(old, tmpl, flags);
1060	if (!msg)
1061		return nl_errno(ENOMEM);
1062
1063	err = nl_send_auto_complete(handle, msg);
1064	if (err < 0)
1065		return err;
1066
1067	nlmsg_free(msg);
1068	return nl_wait_for_ack(handle);
1069}
1070
1071/** @} */
1072
1073/**
1074 * @name Name <-> Index Translations
1075 * @{
1076 */
1077
1078/**
1079 * Translate an interface index to the corresponding link name
1080 * @arg cache		link cache
1081 * @arg ifindex		link interface index
1082 * @arg dst		destination buffer
1083 * @arg len		length of destination buffer
1084 *
1085 * Translates the specified interface index to the corresponding
1086 * link name and stores the name in the destination buffer.
1087 *
1088 * @return link name or NULL if no match was found.
1089 */
1090char * rtnl_link_i2name(struct nl_cache *cache, int ifindex, char *dst,
1091			size_t len)
1092{
1093	struct rtnl_link *link = rtnl_link_get(cache, ifindex);
1094
1095	if (link) {
1096		strncpy(dst, link->l_name, len - 1);
1097		rtnl_link_put(link);
1098		return dst;
1099	}
1100
1101	return NULL;
1102}
1103
1104/**
1105 * Translate a link name to the corresponding interface index
1106 * @arg cache		link cache
1107 * @arg name		link name
1108 *
1109 * @return interface index or RTNL_LINK_NOT_FOUND if no match was found.
1110 */
1111int rtnl_link_name2i(struct nl_cache *cache, const char *name)
1112{
1113	int ifindex = RTNL_LINK_NOT_FOUND;
1114	struct rtnl_link *link;
1115
1116	link = rtnl_link_get_by_name(cache, name);
1117	if (link) {
1118		ifindex = link->l_index;
1119		rtnl_link_put(link);
1120	}
1121
1122	return ifindex;
1123}
1124
1125/** @} */
1126
1127/**
1128 * @name Link Flags Translations
1129 * @{
1130 */
1131
1132static struct trans_tbl link_flags[] = {
1133	__ADD(IFF_LOOPBACK, loopback)
1134	__ADD(IFF_BROADCAST, broadcast)
1135	__ADD(IFF_POINTOPOINT, pointopoint)
1136	__ADD(IFF_MULTICAST, multicast)
1137	__ADD(IFF_NOARP, noarp)
1138	__ADD(IFF_ALLMULTI, allmulti)
1139	__ADD(IFF_PROMISC, promisc)
1140	__ADD(IFF_MASTER, master)
1141	__ADD(IFF_SLAVE, slave)
1142	__ADD(IFF_DEBUG, debug)
1143	__ADD(IFF_DYNAMIC, dynamic)
1144	__ADD(IFF_AUTOMEDIA, automedia)
1145	__ADD(IFF_PORTSEL, portsel)
1146	__ADD(IFF_NOTRAILERS, notrailers)
1147	__ADD(IFF_UP, up)
1148	__ADD(IFF_RUNNING, running)
1149	__ADD(IFF_LOWER_UP, lowerup)
1150	__ADD(IFF_DORMANT, dormant)
1151	__ADD(IFF_ECHO, echo)
1152};
1153
1154char * rtnl_link_flags2str(int flags, char *buf, size_t len)
1155{
1156	return __flags2str(flags, buf, len, link_flags,
1157			   ARRAY_SIZE(link_flags));
1158}
1159
1160int rtnl_link_str2flags(const char *name)
1161{
1162	return __str2flags(name, link_flags, ARRAY_SIZE(link_flags));
1163}
1164
1165/** @} */
1166
1167/**
1168 * @name Link Statistics Translations
1169 * @{
1170 */
1171
1172static struct trans_tbl link_stats[] = {
1173	__ADD(RTNL_LINK_RX_PACKETS, rx_packets)
1174	__ADD(RTNL_LINK_TX_PACKETS, tx_packets)
1175	__ADD(RTNL_LINK_RX_BYTES, rx_bytes)
1176	__ADD(RTNL_LINK_TX_BYTES, tx_bytes)
1177	__ADD(RTNL_LINK_RX_ERRORS, rx_errors)
1178	__ADD(RTNL_LINK_TX_ERRORS, tx_errors)
1179	__ADD(RTNL_LINK_RX_DROPPED, rx_dropped)
1180	__ADD(RTNL_LINK_TX_DROPPED, tx_dropped)
1181	__ADD(RTNL_LINK_RX_COMPRESSED, rx_compressed)
1182	__ADD(RTNL_LINK_TX_COMPRESSED, tx_compressed)
1183	__ADD(RTNL_LINK_RX_FIFO_ERR, rx_fifo_err)
1184	__ADD(RTNL_LINK_TX_FIFO_ERR, tx_fifo_err)
1185	__ADD(RTNL_LINK_RX_LEN_ERR, rx_len_err)
1186	__ADD(RTNL_LINK_RX_OVER_ERR, rx_over_err)
1187	__ADD(RTNL_LINK_RX_CRC_ERR, rx_crc_err)
1188	__ADD(RTNL_LINK_RX_FRAME_ERR, rx_frame_err)
1189	__ADD(RTNL_LINK_RX_MISSED_ERR, rx_missed_err)
1190	__ADD(RTNL_LINK_TX_ABORT_ERR, tx_abort_err)
1191	__ADD(RTNL_LINK_TX_CARRIER_ERR, tx_carrier_err)
1192	__ADD(RTNL_LINK_TX_HBEAT_ERR, tx_hbeat_err)
1193	__ADD(RTNL_LINK_TX_WIN_ERR, tx_win_err)
1194	__ADD(RTNL_LINK_TX_COLLISIONS, tx_collision)
1195	__ADD(RTNL_LINK_MULTICAST, multicast)
1196};
1197
1198char *rtnl_link_stat2str(int st, char *buf, size_t len)
1199{
1200	return __type2str(st, buf, len, link_stats, ARRAY_SIZE(link_stats));
1201}
1202
1203int rtnl_link_str2stat(const char *name)
1204{
1205	return __str2type(name, link_stats, ARRAY_SIZE(link_stats));
1206}
1207
1208/** @} */
1209
1210/**
1211 * @name Link Operstate Translations
1212 * @{
1213 */
1214
1215static struct trans_tbl link_operstates[] = {
1216	__ADD(IF_OPER_UNKNOWN, unknown)
1217	__ADD(IF_OPER_NOTPRESENT, notpresent)
1218	__ADD(IF_OPER_DOWN, down)
1219	__ADD(IF_OPER_LOWERLAYERDOWN, lowerlayerdown)
1220	__ADD(IF_OPER_TESTING, testing)
1221	__ADD(IF_OPER_DORMANT, dormant)
1222	__ADD(IF_OPER_UP, up)
1223};
1224
1225char *rtnl_link_operstate2str(int st, char *buf, size_t len)
1226{
1227	return __type2str(st, buf, len, link_operstates,
1228			  ARRAY_SIZE(link_operstates));
1229}
1230
1231int rtnl_link_str2operstate(const char *name)
1232{
1233	return __str2type(name, link_operstates,
1234			  ARRAY_SIZE(link_operstates));
1235}
1236
1237/** @} */
1238
1239/**
1240 * @name Link Mode Translations
1241 * @{
1242 */
1243
1244static struct trans_tbl link_modes[] = {
1245	__ADD(IF_LINK_MODE_DEFAULT, default)
1246	__ADD(IF_LINK_MODE_DORMANT, dormant)
1247};
1248
1249char *rtnl_link_mode2str(int st, char *buf, size_t len)
1250{
1251	return __type2str(st, buf, len, link_modes, ARRAY_SIZE(link_modes));
1252}
1253
1254int rtnl_link_str2mode(const char *name)
1255{
1256	return __str2type(name, link_modes, ARRAY_SIZE(link_modes));
1257}
1258
1259/** @} */
1260
1261/**
1262 * @name Attributes
1263 * @{
1264 */
1265
1266void rtnl_link_set_qdisc(struct rtnl_link *link, const char *qdisc)
1267{
1268	strncpy(link->l_qdisc, qdisc, sizeof(link->l_qdisc) - 1);
1269	link->ce_mask |= LINK_ATTR_QDISC;
1270}
1271
1272char *rtnl_link_get_qdisc(struct rtnl_link *link)
1273{
1274	if (link->ce_mask & LINK_ATTR_QDISC)
1275		return link->l_qdisc;
1276	else
1277		return NULL;
1278}
1279
1280void rtnl_link_set_name(struct rtnl_link *link, const char *name)
1281{
1282	strncpy(link->l_name, name, sizeof(link->l_name) - 1);
1283	link->ce_mask |= LINK_ATTR_IFNAME;
1284}
1285
1286char *rtnl_link_get_name(struct rtnl_link *link)
1287{
1288	if (link->ce_mask & LINK_ATTR_IFNAME)
1289		return link->l_name;
1290	else
1291		return NULL;
1292}
1293
1294static inline void __assign_addr(struct rtnl_link *link, struct nl_addr **pos,
1295				 struct nl_addr *new, int flag)
1296{
1297	if (*pos)
1298		nl_addr_put(*pos);
1299
1300	nl_addr_get(new);
1301	*pos = new;
1302
1303	link->ce_mask |= flag;
1304}
1305
1306void rtnl_link_set_addr(struct rtnl_link *link, struct nl_addr *addr)
1307{
1308	__assign_addr(link, &link->l_addr, addr, LINK_ATTR_ADDR);
1309}
1310
1311struct nl_addr *rtnl_link_get_addr(struct rtnl_link *link)
1312{
1313	if (link->ce_mask & LINK_ATTR_ADDR)
1314		return link->l_addr;
1315	else
1316		return NULL;
1317}
1318
1319void rtnl_link_set_broadcast(struct rtnl_link *link, struct nl_addr *brd)
1320{
1321	__assign_addr(link, &link->l_bcast, brd, LINK_ATTR_BRD);
1322}
1323
1324struct nl_addr *rtnl_link_get_broadcast(struct rtnl_link *link)
1325{
1326	if (link->ce_mask & LINK_ATTR_BRD)
1327		return link->l_bcast;
1328	else
1329		return NULL;
1330}
1331
1332void rtnl_link_set_flags(struct rtnl_link *link, unsigned int flags)
1333{
1334	link->l_flag_mask |= flags;
1335	link->l_flags |= flags;
1336	link->ce_mask |= LINK_ATTR_FLAGS;
1337}
1338
1339void rtnl_link_unset_flags(struct rtnl_link *link, unsigned int flags)
1340{
1341	link->l_flag_mask |= flags;
1342	link->l_flags &= ~flags;
1343	link->ce_mask |= LINK_ATTR_FLAGS;
1344}
1345
1346unsigned int rtnl_link_get_flags(struct rtnl_link *link)
1347{
1348	return link->l_flags;
1349}
1350
1351void rtnl_link_set_family(struct rtnl_link *link, int family)
1352{
1353	link->l_family = family;
1354	link->ce_mask |= LINK_ATTR_FAMILY;
1355}
1356
1357int rtnl_link_get_family(struct rtnl_link *link)
1358{
1359	if (link->l_family & LINK_ATTR_FAMILY)
1360		return link->l_family;
1361	else
1362		return AF_UNSPEC;
1363}
1364
1365void rtnl_link_set_arptype(struct rtnl_link *link, unsigned int arptype)
1366{
1367	link->l_arptype = arptype;
1368}
1369
1370unsigned int rtnl_link_get_arptype(struct rtnl_link *link)
1371{
1372	return link->l_arptype;
1373}
1374
1375void rtnl_link_set_ifindex(struct rtnl_link *link, int ifindex)
1376{
1377	link->l_index = ifindex;
1378	link->ce_mask |= LINK_ATTR_IFINDEX;
1379}
1380
1381int rtnl_link_get_ifindex(struct rtnl_link *link)
1382{
1383	if (link->ce_mask & LINK_ATTR_IFINDEX)
1384		return link->l_index;
1385	else
1386		return RTNL_LINK_NOT_FOUND;
1387}
1388
1389void rtnl_link_set_mtu(struct rtnl_link *link, unsigned int mtu)
1390{
1391	link->l_mtu = mtu;
1392	link->ce_mask |= LINK_ATTR_MTU;
1393}
1394
1395unsigned int rtnl_link_get_mtu(struct rtnl_link *link)
1396{
1397	if (link->ce_mask & LINK_ATTR_MTU)
1398		return link->l_mtu;
1399	else
1400		return 0;
1401}
1402
1403void rtnl_link_set_txqlen(struct rtnl_link *link, unsigned int txqlen)
1404{
1405	link->l_txqlen = txqlen;
1406	link->ce_mask |= LINK_ATTR_TXQLEN;
1407}
1408
1409unsigned int rtnl_link_get_txqlen(struct rtnl_link *link)
1410{
1411	if (link->ce_mask & LINK_ATTR_TXQLEN)
1412		return link->l_txqlen;
1413	else
1414		return UINT_MAX;
1415}
1416
1417void rtnl_link_set_weight(struct rtnl_link *link, unsigned int weight)
1418{
1419	link->l_weight = weight;
1420	link->ce_mask |= LINK_ATTR_WEIGHT;
1421}
1422
1423unsigned int rtnl_link_get_weight(struct rtnl_link *link)
1424{
1425	if (link->ce_mask & LINK_ATTR_WEIGHT)
1426		return link->l_weight;
1427	else
1428		return UINT_MAX;
1429}
1430
1431void rtnl_link_set_link(struct rtnl_link *link, int ifindex)
1432{
1433	link->l_link = ifindex;
1434	link->ce_mask |= LINK_ATTR_LINK;
1435}
1436
1437int rtnl_link_get_link(struct rtnl_link *link)
1438{
1439	if (link->ce_mask & LINK_ATTR_LINK)
1440		return link->l_link;
1441	else
1442		return RTNL_LINK_NOT_FOUND;
1443}
1444
1445void rtnl_link_set_master(struct rtnl_link *link, int ifindex)
1446{
1447	link->l_master = ifindex;
1448	link->ce_mask |= LINK_ATTR_MASTER;
1449}
1450
1451int rtnl_link_get_master(struct rtnl_link *link)
1452{
1453	if (link->ce_mask & LINK_ATTR_MASTER)
1454		return link->l_master;
1455	else
1456		return RTNL_LINK_NOT_FOUND;
1457}
1458
1459void rtnl_link_set_operstate(struct rtnl_link *link, uint8_t operstate)
1460{
1461	link->l_operstate = operstate;
1462	link->ce_mask |= LINK_ATTR_OPERSTATE;
1463}
1464
1465uint8_t rtnl_link_get_operstate(struct rtnl_link *link)
1466{
1467	if (link->ce_mask & LINK_ATTR_OPERSTATE)
1468		return link->l_operstate;
1469	else
1470		return IF_OPER_UNKNOWN;
1471}
1472
1473void rtnl_link_set_linkmode(struct rtnl_link *link, uint8_t linkmode)
1474{
1475	link->l_linkmode = linkmode;
1476	link->ce_mask |= LINK_ATTR_LINKMODE;
1477}
1478
1479uint8_t rtnl_link_get_linkmode(struct rtnl_link *link)
1480{
1481	if (link->ce_mask & LINK_ATTR_LINKMODE)
1482		return link->l_linkmode;
1483	else
1484		return IF_LINK_MODE_DEFAULT;
1485}
1486
1487uint64_t rtnl_link_get_stat(struct rtnl_link *link, int id)
1488{
1489	if (id < 0 || id > RTNL_LINK_STATS_MAX)
1490		return 0;
1491
1492	return link->l_stats[id];
1493}
1494
1495/**
1496 * Specify the info type of a link
1497 * @arg link	link object
1498 * @arg type	info type
1499 *
1500 * Looks up the info type and prepares the link to store info type
1501 * specific attributes. If an info type has been assigned already
1502 * it will be released with all changes lost.
1503 *
1504 * @return 0 on success or a negative errror code.
1505 */
1506int rtnl_link_set_info_type(struct rtnl_link *link, const char *type)
1507{
1508	struct rtnl_link_info_ops *io;
1509	int err;
1510
1511	if ((io = rtnl_link_info_ops_lookup(type)) == NULL)
1512		return nl_error(ENOENT, "No such link info type exists");
1513
1514	if (link->l_info_ops)
1515		release_link_info(link);
1516
1517	if ((err = io->io_alloc(link)) < 0)
1518		return err;
1519
1520	link->l_info_ops = io;
1521
1522	return 0;
1523}
1524
1525/**
1526 * Return info type of a link
1527 * @arg link	link object
1528 *
1529 * @note The returned pointer is only valid as long as the link exists
1530 * @return Info type name or NULL if unknown.
1531 */
1532char *rtnl_link_get_info_type(struct rtnl_link *link)
1533{
1534	if (link->l_info_ops)
1535		return link->l_info_ops->io_name;
1536	else
1537		return NULL;
1538}
1539
1540/** @} */
1541
1542static struct nl_object_ops link_obj_ops = {
1543	.oo_name		= "route/link",
1544	.oo_size		= sizeof(struct rtnl_link),
1545	.oo_free_data		= link_free_data,
1546	.oo_clone		= link_clone,
1547	.oo_dump[NL_DUMP_BRIEF]	= link_dump_brief,
1548	.oo_dump[NL_DUMP_FULL]	= link_dump_full,
1549	.oo_dump[NL_DUMP_STATS]	= link_dump_stats,
1550	.oo_dump[NL_DUMP_XML]	= link_dump_xml,
1551	.oo_dump[NL_DUMP_ENV]	= link_dump_env,
1552	.oo_compare		= link_compare,
1553	.oo_attrs2str		= link_attrs2str,
1554	.oo_id_attrs		= LINK_ATTR_IFINDEX,
1555};
1556
1557static struct nl_af_group link_groups[] = {
1558	{ AF_UNSPEC,	RTNLGRP_LINK },
1559	{ END_OF_GROUP_LIST },
1560};
1561
1562static struct nl_cache_ops rtnl_link_ops = {
1563	.co_name		= "route/link",
1564	.co_hdrsize		= sizeof(struct ifinfomsg),
1565	.co_msgtypes		= {
1566					{ RTM_NEWLINK, NL_ACT_NEW, "new" },
1567					{ RTM_DELLINK, NL_ACT_DEL, "del" },
1568					{ RTM_GETLINK, NL_ACT_GET, "get" },
1569					END_OF_MSGTYPES_LIST,
1570				  },
1571	.co_protocol		= NETLINK_ROUTE,
1572	.co_groups		= link_groups,
1573	.co_request_update	= link_request_update,
1574	.co_msg_parser		= link_msg_parser,
1575	.co_obj_ops		= &link_obj_ops,
1576};
1577
1578static void __init link_init(void)
1579{
1580	nl_cache_mngt_register(&rtnl_link_ops);
1581}
1582
1583static void __exit link_exit(void)
1584{
1585	nl_cache_mngt_unregister(&rtnl_link_ops);
1586}
1587
1588/** @} */
1589