link.c revision d84430702496f617c01c5e2d27d0e82e02390bb7
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@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
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			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
233static 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
250static 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
256static 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);
420errout:
421	rtnl_link_put(link);
422	return err;
423}
424
425static 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
430static 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
466static 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
506static 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
569static void link_dump_xml(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\" index=\"%u\">\n",
577		     link->l_name, link->l_index);
578	nl_dump_line(p, "  <family>%s</family>\n",
579		     nl_af2str(link->l_family, buf, sizeof(buf)));
580	nl_dump_line(p, "  <arptype>%s</arptype>\n",
581		     nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
582	nl_dump_line(p, "  <address>%s</address>\n",
583		     nl_addr2str(link->l_addr, buf, sizeof(buf)));
584	nl_dump_line(p, "  <mtu>%u</mtu>\n", link->l_mtu);
585	nl_dump_line(p, "  <txqlen>%u</txqlen>\n", link->l_txqlen);
586	nl_dump_line(p, "  <weight>%u</weight>\n", link->l_weight);
587
588	rtnl_link_flags2str(link->l_flags, buf, sizeof(buf));
589	if (buf[0])
590		nl_dump_line(p, "  <flags>%s</flags>\n", buf);
591
592	if (link->ce_mask & LINK_ATTR_QDISC)
593		nl_dump_line(p, "  <qdisc>%s</qdisc>\n", link->l_qdisc);
594
595	if (link->ce_mask & LINK_ATTR_LINK) {
596		struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
597		nl_dump_line(p, "  <link>%s</link>\n",
598			     ll ? ll->l_name : "none");
599		if (ll)
600			rtnl_link_put(ll);
601	}
602
603	if (link->ce_mask & LINK_ATTR_MASTER) {
604		struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
605		nl_dump_line(p, "  <master>%s</master>\n",
606			     master ? master->l_name : "none");
607		if (master)
608			rtnl_link_put(master);
609	}
610
611	if (link->ce_mask & LINK_ATTR_BRD)
612		nl_dump_line(p, "  <broadcast>%s</broadcast>\n",
613			     nl_addr2str(link->l_bcast, buf, sizeof(buf)));
614
615	if (link->ce_mask & LINK_ATTR_STATS) {
616		nl_dump_line(p, "  <stats>\n");
617		for (i = 0; i <= RTNL_LINK_STATS_MAX; i++) {
618			rtnl_link_stat2str(i, buf, sizeof(buf));
619			nl_dump_line(p, "    <%s>%" PRIu64 "</%s>\n",
620				     buf, link->l_stats[i], buf);
621		}
622		nl_dump_line(p, "  </stats>\n");
623	}
624
625	if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_XML]) {
626		nl_dump_line(p, "  <info>\n");
627		link->l_info_ops->io_dump[NL_DUMP_XML](link, p);
628		nl_dump_line(p, "  </info>\n");
629	}
630
631	nl_dump_line(p, "</link>\n");
632
633#if 0
634	uint32_t	l_change;	/**< Change mask */
635	struct rtnl_lifmap l_map;	/**< Interface device mapping */
636#endif
637}
638
639static void link_dump_env(struct nl_object *obj, struct nl_dump_params *p)
640{
641	struct rtnl_link *link = (struct rtnl_link *) obj;
642	struct nl_cache *cache = dp_cache(obj);
643	char buf[128];
644	int i;
645
646	nl_dump_line(p, "LINK_NAME=%s\n", link->l_name);
647	nl_dump_line(p, "LINK_IFINDEX=%u\n", link->l_index);
648	nl_dump_line(p, "LINK_FAMILY=%s\n",
649		     nl_af2str(link->l_family, buf, sizeof(buf)));
650	nl_dump_line(p, "LINK_TYPE=%s\n",
651		     nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
652	if (link->ce_mask & LINK_ATTR_ADDR)
653		nl_dump_line(p, "LINK_ADDRESS=%s\n",
654			     nl_addr2str(link->l_addr, buf, sizeof(buf)));
655	nl_dump_line(p, "LINK_MTU=%u\n", link->l_mtu);
656	nl_dump_line(p, "LINK_TXQUEUELEN=%u\n", link->l_txqlen);
657	nl_dump_line(p, "LINK_WEIGHT=%u\n", link->l_weight);
658
659	rtnl_link_flags2str(link->l_flags & ~IFF_RUNNING, buf, sizeof(buf));
660	if (buf[0])
661		nl_dump_line(p, "LINK_FLAGS=%s\n", buf);
662
663	if (link->ce_mask & LINK_ATTR_QDISC)
664		nl_dump_line(p, "LINK_QDISC=%s\n", link->l_qdisc);
665
666	if (link->ce_mask & LINK_ATTR_LINK) {
667		struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
668
669		nl_dump_line(p, "LINK_LINK_IFINDEX=%d\n", link->l_link);
670		if (ll) {
671			nl_dump_line(p, "LINK_LINK_IFNAME=%s\n", ll->l_name);
672			rtnl_link_put(ll);
673		}
674	}
675
676	if (link->ce_mask & LINK_ATTR_MASTER) {
677		struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
678		nl_dump_line(p, "LINK_MASTER=%s\n",
679			     master ? master->l_name : "none");
680		if (master)
681			rtnl_link_put(master);
682	}
683
684	if (link->ce_mask & LINK_ATTR_BRD)
685		nl_dump_line(p, "LINK_BROADCAST=%s\n",
686			     nl_addr2str(link->l_bcast, buf, sizeof(buf)));
687
688	if (link->ce_mask & LINK_ATTR_STATS) {
689		for (i = 0; i <= RTNL_LINK_STATS_MAX; i++) {
690			char *c = buf;
691
692			sprintf(buf, "LINK_");
693			rtnl_link_stat2str(i, buf + 5, sizeof(buf) - 5);
694			while (*c) {
695				*c = toupper(*c);
696				c++;
697			}
698			nl_dump_line(p, "%s=%" PRIu64 "\n", buf, link->l_stats[i]);
699		}
700	}
701
702	if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_ENV])
703		link->l_info_ops->io_dump[NL_DUMP_ENV](link, p);
704}
705
706#if 0
707static int link_handle_event(struct nl_object *a, struct rtnl_link_event_cb *cb)
708{
709	struct rtnl_link *l = (struct rtnl_link *) a;
710	struct nl_cache *c = dp_cache(a);
711	int nevents = 0;
712
713	if (l->l_change == ~0U) {
714		if (l->ce_msgtype == RTM_NEWLINK)
715			cb->le_register(l);
716		else
717			cb->le_unregister(l);
718
719		return 1;
720	}
721
722	if (l->l_change & IFF_SLAVE) {
723		if (l->l_flags & IFF_SLAVE) {
724			struct rtnl_link *m = rtnl_link_get(c, l->l_master);
725			cb->le_new_bonding(l, m);
726			if (m)
727				rtnl_link_put(m);
728		} else
729			cb->le_cancel_bonding(l);
730	}
731
732#if 0
733	if (l->l_change & IFF_UP && l->l_change & IFF_RUNNING)
734		dp_dump_line(p, line++, "link %s changed state to %s.\n",
735			l->l_name, l->l_flags & IFF_UP ? "up" : "down");
736
737	if (l->l_change & IFF_PROMISC) {
738		dp_new_line(p, line++);
739		dp_dump(p, "link %s %s promiscuous mode.\n",
740		    l->l_name, l->l_flags & IFF_PROMISC ? "entered" : "left");
741	}
742
743	if (line == 0)
744		dp_dump_line(p, line++, "link %s sent unknown event.\n",
745			     l->l_name);
746#endif
747
748	return nevents;
749}
750#endif
751
752static int link_compare(struct nl_object *_a, struct nl_object *_b,
753			uint32_t attrs, int flags)
754{
755	struct rtnl_link *a = (struct rtnl_link *) _a;
756	struct rtnl_link *b = (struct rtnl_link *) _b;
757	int diff = 0;
758
759#define LINK_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, LINK_ATTR_##ATTR, a, b, EXPR)
760
761	diff |= LINK_DIFF(IFINDEX,	a->l_index != b->l_index);
762	diff |= LINK_DIFF(MTU,		a->l_mtu != b->l_mtu);
763	diff |= LINK_DIFF(LINK,		a->l_link != b->l_link);
764	diff |= LINK_DIFF(TXQLEN,	a->l_txqlen != b->l_txqlen);
765	diff |= LINK_DIFF(WEIGHT,	a->l_weight != b->l_weight);
766	diff |= LINK_DIFF(MASTER,	a->l_master != b->l_master);
767	diff |= LINK_DIFF(FAMILY,	a->l_family != b->l_family);
768	diff |= LINK_DIFF(OPERSTATE,	a->l_operstate != b->l_operstate);
769	diff |= LINK_DIFF(LINKMODE,	a->l_linkmode != b->l_linkmode);
770	diff |= LINK_DIFF(QDISC,	strcmp(a->l_qdisc, b->l_qdisc));
771	diff |= LINK_DIFF(IFNAME,	strcmp(a->l_name, b->l_name));
772	diff |= LINK_DIFF(ADDR,		nl_addr_cmp(a->l_addr, b->l_addr));
773	diff |= LINK_DIFF(BRD,		nl_addr_cmp(a->l_bcast, b->l_bcast));
774
775	if (flags & LOOSE_COMPARISON)
776		diff |= LINK_DIFF(FLAGS,
777				  (a->l_flags ^ b->l_flags) & b->l_flag_mask);
778	else
779		diff |= LINK_DIFF(FLAGS, a->l_flags != b->l_flags);
780
781#undef LINK_DIFF
782
783	return diff;
784}
785
786static struct trans_tbl link_attrs[] = {
787	__ADD(LINK_ATTR_MTU, mtu)
788	__ADD(LINK_ATTR_LINK, link)
789	__ADD(LINK_ATTR_TXQLEN, txqlen)
790	__ADD(LINK_ATTR_WEIGHT, weight)
791	__ADD(LINK_ATTR_MASTER, master)
792	__ADD(LINK_ATTR_QDISC, qdisc)
793	__ADD(LINK_ATTR_MAP, map)
794	__ADD(LINK_ATTR_ADDR, address)
795	__ADD(LINK_ATTR_BRD, broadcast)
796	__ADD(LINK_ATTR_FLAGS, flags)
797	__ADD(LINK_ATTR_IFNAME, name)
798	__ADD(LINK_ATTR_IFINDEX, ifindex)
799	__ADD(LINK_ATTR_FAMILY, family)
800	__ADD(LINK_ATTR_ARPTYPE, arptype)
801	__ADD(LINK_ATTR_STATS, stats)
802	__ADD(LINK_ATTR_CHANGE, change)
803	__ADD(LINK_ATTR_OPERSTATE, operstate)
804	__ADD(LINK_ATTR_LINKMODE, linkmode)
805};
806
807static char *link_attrs2str(int attrs, char *buf, size_t len)
808{
809	return __flags2str(attrs, buf, len, link_attrs,
810			   ARRAY_SIZE(link_attrs));
811}
812
813/**
814 * @name Allocation/Freeing
815 * @{
816 */
817
818struct rtnl_link *rtnl_link_alloc(void)
819{
820	return (struct rtnl_link *) nl_object_alloc(&link_obj_ops);
821}
822
823void rtnl_link_put(struct rtnl_link *link)
824{
825	nl_object_put((struct nl_object *) link);
826}
827
828/** @} */
829
830/**
831 * @name Cache Management
832 * @{
833 */
834
835
836/**
837 * Allocate link cache and fill in all configured links.
838 * @arg sk		Netlink socket.
839 * @arg result		Pointer to store resulting cache.
840 *
841 * Allocates a new link cache, initializes it properly and updates it
842 * to include all links currently configured in the kernel.
843 *
844 * @return 0 on success or a negative error code.
845 */
846int rtnl_link_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
847{
848	return nl_cache_alloc_and_fill(&rtnl_link_ops, sk, result);
849}
850
851/**
852 * Look up link by interface index in the provided cache
853 * @arg cache		link cache
854 * @arg ifindex		link interface index
855 *
856 * The caller owns a reference on the returned object and
857 * must give the object back via rtnl_link_put().
858 *
859 * @return pointer to link inside the cache or NULL if no match was found.
860 */
861struct rtnl_link *rtnl_link_get(struct nl_cache *cache, int ifindex)
862{
863	struct rtnl_link *link;
864
865	if (cache->c_ops != &rtnl_link_ops)
866		return NULL;
867
868	nl_list_for_each_entry(link, &cache->c_items, ce_list) {
869		if (link->l_index == ifindex) {
870			nl_object_get((struct nl_object *) link);
871			return link;
872		}
873	}
874
875	return NULL;
876}
877
878/**
879 * Look up link by link name in the provided cache
880 * @arg cache		link cache
881 * @arg name		link name
882 *
883 * The caller owns a reference on the returned object and
884 * must give the object back via rtnl_link_put().
885 *
886 * @return pointer to link inside the cache or NULL if no match was found.
887 */
888struct rtnl_link *rtnl_link_get_by_name(struct nl_cache *cache,
889					 const char *name)
890{
891	struct rtnl_link *link;
892
893	if (cache->c_ops != &rtnl_link_ops)
894		return NULL;
895
896	nl_list_for_each_entry(link, &cache->c_items, ce_list) {
897		if (!strcmp(name, link->l_name)) {
898			nl_object_get((struct nl_object *) link);
899			return link;
900		}
901	}
902
903	return NULL;
904}
905
906/** @} */
907
908/**
909 * @name Link Modifications
910 * @{
911 */
912
913/**
914 * Builds a netlink change request message to change link attributes
915 * @arg old		link to be changed
916 * @arg tmpl		template with requested changes
917 * @arg flags		additional netlink message flags
918 *
919 * Builds a new netlink message requesting a change of link attributes.
920 * The netlink message header isn't fully equipped with all relevant
921 * fields and must be sent out via nl_send_auto_complete() or
922 * supplemented as needed.
923 * \a old must point to a link currently configured in the kernel
924 * and \a tmpl must contain the attributes to be changed set via
925 * \c rtnl_link_set_* functions.
926 *
927 * @return New netlink message
928 * @note Not all attributes can be changed, see
929 *       \ref link_changeable "Changeable Attributes" for more details.
930 */
931int rtnl_link_build_change_request(struct rtnl_link *old,
932				   struct rtnl_link *tmpl, int flags,
933				   struct nl_msg **result)
934{
935	struct nl_msg *msg;
936	struct ifinfomsg ifi = {
937		.ifi_family = old->l_family,
938		.ifi_index = old->l_index,
939	};
940
941	if (tmpl->ce_mask & LINK_ATTR_FLAGS) {
942		ifi.ifi_flags = old->l_flags & ~tmpl->l_flag_mask;
943		ifi.ifi_flags |= tmpl->l_flags;
944	}
945
946	msg = nlmsg_alloc_simple(RTM_SETLINK, flags);
947	if (!msg)
948		return -NLE_NOMEM;
949
950	if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
951		goto nla_put_failure;
952
953	if (tmpl->ce_mask & LINK_ATTR_ADDR)
954		NLA_PUT_ADDR(msg, IFLA_ADDRESS, tmpl->l_addr);
955
956	if (tmpl->ce_mask & LINK_ATTR_BRD)
957		NLA_PUT_ADDR(msg, IFLA_BROADCAST, tmpl->l_bcast);
958
959	if (tmpl->ce_mask & LINK_ATTR_MTU)
960		NLA_PUT_U32(msg, IFLA_MTU, tmpl->l_mtu);
961
962	if (tmpl->ce_mask & LINK_ATTR_TXQLEN)
963		NLA_PUT_U32(msg, IFLA_TXQLEN, tmpl->l_txqlen);
964
965	if (tmpl->ce_mask & LINK_ATTR_WEIGHT)
966		NLA_PUT_U32(msg, IFLA_WEIGHT, tmpl->l_weight);
967
968	if (tmpl->ce_mask & LINK_ATTR_IFNAME)
969		NLA_PUT_STRING(msg, IFLA_IFNAME, tmpl->l_name);
970
971	if (tmpl->ce_mask & LINK_ATTR_OPERSTATE)
972		NLA_PUT_U8(msg, IFLA_OPERSTATE, tmpl->l_operstate);
973
974	if (tmpl->ce_mask & LINK_ATTR_LINKMODE)
975		NLA_PUT_U8(msg, IFLA_LINKMODE, tmpl->l_linkmode);
976
977	if ((tmpl->ce_mask & LINK_ATTR_LINKINFO) && tmpl->l_info_ops &&
978	    tmpl->l_info_ops->io_put_attrs) {
979		struct nlattr *info;
980
981		if (!(info = nla_nest_start(msg, IFLA_LINKINFO)))
982			goto nla_put_failure;
983
984		NLA_PUT_STRING(msg, IFLA_INFO_KIND, tmpl->l_info_ops->io_name);
985
986		if (tmpl->l_info_ops->io_put_attrs(msg, tmpl) < 0)
987			goto nla_put_failure;
988
989		nla_nest_end(msg, info);
990	}
991
992	*result = msg;
993	return 0;
994
995nla_put_failure:
996	nlmsg_free(msg);
997	return -NLE_MSGSIZE;
998}
999
1000/**
1001 * Change link attributes
1002 * @arg sk		Netlink socket.
1003 * @arg old		link to be changed
1004 * @arg tmpl		template with requested changes
1005 * @arg flags		additional netlink message flags
1006 *
1007 * Builds a new netlink message by calling rtnl_link_build_change_request(),
1008 * sends the request to the kernel and waits for the next ACK to be
1009 * received, i.e. blocks until the request has been processed.
1010 *
1011 * @return 0 on success or a negative error code
1012 * @note Not all attributes can be changed, see
1013 *       \ref link_changeable "Changeable Attributes" for more details.
1014 */
1015int rtnl_link_change(struct nl_sock *sk, struct rtnl_link *old,
1016		     struct rtnl_link *tmpl, int flags)
1017{
1018	struct nl_msg *msg;
1019	int err;
1020
1021	if ((err = rtnl_link_build_change_request(old, tmpl, flags, &msg)) < 0)
1022		return err;
1023
1024	err = nl_send_auto_complete(sk, msg);
1025	nlmsg_free(msg);
1026	if (err < 0)
1027		return err;
1028
1029	return nl_wait_for_ack(sk);
1030}
1031
1032/** @} */
1033
1034/**
1035 * @name Name <-> Index Translations
1036 * @{
1037 */
1038
1039/**
1040 * Translate an interface index to the corresponding link name
1041 * @arg cache		link cache
1042 * @arg ifindex		link interface index
1043 * @arg dst		destination buffer
1044 * @arg len		length of destination buffer
1045 *
1046 * Translates the specified interface index to the corresponding
1047 * link name and stores the name in the destination buffer.
1048 *
1049 * @return link name or NULL if no match was found.
1050 */
1051char * rtnl_link_i2name(struct nl_cache *cache, int ifindex, char *dst,
1052			size_t len)
1053{
1054	struct rtnl_link *link = rtnl_link_get(cache, ifindex);
1055
1056	if (link) {
1057		strncpy(dst, link->l_name, len - 1);
1058		rtnl_link_put(link);
1059		return dst;
1060	}
1061
1062	return NULL;
1063}
1064
1065/**
1066 * Translate a link name to the corresponding interface index
1067 * @arg cache		link cache
1068 * @arg name		link name
1069 *
1070 * @return interface index or 0 if no match was found.
1071 */
1072int rtnl_link_name2i(struct nl_cache *cache, const char *name)
1073{
1074	int ifindex = 0;
1075	struct rtnl_link *link;
1076
1077	link = rtnl_link_get_by_name(cache, name);
1078	if (link) {
1079		ifindex = link->l_index;
1080		rtnl_link_put(link);
1081	}
1082
1083	return ifindex;
1084}
1085
1086/** @} */
1087
1088/**
1089 * @name Link Flags Translations
1090 * @{
1091 */
1092
1093static struct trans_tbl link_flags[] = {
1094	__ADD(IFF_LOOPBACK, loopback)
1095	__ADD(IFF_BROADCAST, broadcast)
1096	__ADD(IFF_POINTOPOINT, pointopoint)
1097	__ADD(IFF_MULTICAST, multicast)
1098	__ADD(IFF_NOARP, noarp)
1099	__ADD(IFF_ALLMULTI, allmulti)
1100	__ADD(IFF_PROMISC, promisc)
1101	__ADD(IFF_MASTER, master)
1102	__ADD(IFF_SLAVE, slave)
1103	__ADD(IFF_DEBUG, debug)
1104	__ADD(IFF_DYNAMIC, dynamic)
1105	__ADD(IFF_AUTOMEDIA, automedia)
1106	__ADD(IFF_PORTSEL, portsel)
1107	__ADD(IFF_NOTRAILERS, notrailers)
1108	__ADD(IFF_UP, up)
1109	__ADD(IFF_RUNNING, running)
1110	__ADD(IFF_LOWER_UP, lowerup)
1111	__ADD(IFF_DORMANT, dormant)
1112	__ADD(IFF_ECHO, echo)
1113};
1114
1115char * rtnl_link_flags2str(int flags, char *buf, size_t len)
1116{
1117	return __flags2str(flags, buf, len, link_flags,
1118			   ARRAY_SIZE(link_flags));
1119}
1120
1121int rtnl_link_str2flags(const char *name)
1122{
1123	return __str2flags(name, link_flags, ARRAY_SIZE(link_flags));
1124}
1125
1126/** @} */
1127
1128/**
1129 * @name Link Statistics Translations
1130 * @{
1131 */
1132
1133static struct trans_tbl link_stats[] = {
1134	__ADD(RTNL_LINK_RX_PACKETS, rx_packets)
1135	__ADD(RTNL_LINK_TX_PACKETS, tx_packets)
1136	__ADD(RTNL_LINK_RX_BYTES, rx_bytes)
1137	__ADD(RTNL_LINK_TX_BYTES, tx_bytes)
1138	__ADD(RTNL_LINK_RX_ERRORS, rx_errors)
1139	__ADD(RTNL_LINK_TX_ERRORS, tx_errors)
1140	__ADD(RTNL_LINK_RX_DROPPED, rx_dropped)
1141	__ADD(RTNL_LINK_TX_DROPPED, tx_dropped)
1142	__ADD(RTNL_LINK_RX_COMPRESSED, rx_compressed)
1143	__ADD(RTNL_LINK_TX_COMPRESSED, tx_compressed)
1144	__ADD(RTNL_LINK_RX_FIFO_ERR, rx_fifo_err)
1145	__ADD(RTNL_LINK_TX_FIFO_ERR, tx_fifo_err)
1146	__ADD(RTNL_LINK_RX_LEN_ERR, rx_len_err)
1147	__ADD(RTNL_LINK_RX_OVER_ERR, rx_over_err)
1148	__ADD(RTNL_LINK_RX_CRC_ERR, rx_crc_err)
1149	__ADD(RTNL_LINK_RX_FRAME_ERR, rx_frame_err)
1150	__ADD(RTNL_LINK_RX_MISSED_ERR, rx_missed_err)
1151	__ADD(RTNL_LINK_TX_ABORT_ERR, tx_abort_err)
1152	__ADD(RTNL_LINK_TX_CARRIER_ERR, tx_carrier_err)
1153	__ADD(RTNL_LINK_TX_HBEAT_ERR, tx_hbeat_err)
1154	__ADD(RTNL_LINK_TX_WIN_ERR, tx_win_err)
1155	__ADD(RTNL_LINK_TX_COLLISIONS, tx_collision)
1156	__ADD(RTNL_LINK_MULTICAST, multicast)
1157};
1158
1159char *rtnl_link_stat2str(int st, char *buf, size_t len)
1160{
1161	return __type2str(st, buf, len, link_stats, ARRAY_SIZE(link_stats));
1162}
1163
1164int rtnl_link_str2stat(const char *name)
1165{
1166	return __str2type(name, link_stats, ARRAY_SIZE(link_stats));
1167}
1168
1169/** @} */
1170
1171/**
1172 * @name Link Operstate Translations
1173 * @{
1174 */
1175
1176static struct trans_tbl link_operstates[] = {
1177	__ADD(IF_OPER_UNKNOWN, unknown)
1178	__ADD(IF_OPER_NOTPRESENT, notpresent)
1179	__ADD(IF_OPER_DOWN, down)
1180	__ADD(IF_OPER_LOWERLAYERDOWN, lowerlayerdown)
1181	__ADD(IF_OPER_TESTING, testing)
1182	__ADD(IF_OPER_DORMANT, dormant)
1183	__ADD(IF_OPER_UP, up)
1184};
1185
1186char *rtnl_link_operstate2str(int st, char *buf, size_t len)
1187{
1188	return __type2str(st, buf, len, link_operstates,
1189			  ARRAY_SIZE(link_operstates));
1190}
1191
1192int rtnl_link_str2operstate(const char *name)
1193{
1194	return __str2type(name, link_operstates,
1195			  ARRAY_SIZE(link_operstates));
1196}
1197
1198/** @} */
1199
1200/**
1201 * @name Link Mode Translations
1202 * @{
1203 */
1204
1205static struct trans_tbl link_modes[] = {
1206	__ADD(IF_LINK_MODE_DEFAULT, default)
1207	__ADD(IF_LINK_MODE_DORMANT, dormant)
1208};
1209
1210char *rtnl_link_mode2str(int st, char *buf, size_t len)
1211{
1212	return __type2str(st, buf, len, link_modes, ARRAY_SIZE(link_modes));
1213}
1214
1215int rtnl_link_str2mode(const char *name)
1216{
1217	return __str2type(name, link_modes, ARRAY_SIZE(link_modes));
1218}
1219
1220/** @} */
1221
1222/**
1223 * @name Attributes
1224 * @{
1225 */
1226
1227void rtnl_link_set_qdisc(struct rtnl_link *link, const char *qdisc)
1228{
1229	strncpy(link->l_qdisc, qdisc, sizeof(link->l_qdisc) - 1);
1230	link->ce_mask |= LINK_ATTR_QDISC;
1231}
1232
1233char *rtnl_link_get_qdisc(struct rtnl_link *link)
1234{
1235	if (link->ce_mask & LINK_ATTR_QDISC)
1236		return link->l_qdisc;
1237	else
1238		return NULL;
1239}
1240
1241void rtnl_link_set_name(struct rtnl_link *link, const char *name)
1242{
1243	strncpy(link->l_name, name, sizeof(link->l_name) - 1);
1244	link->ce_mask |= LINK_ATTR_IFNAME;
1245}
1246
1247char *rtnl_link_get_name(struct rtnl_link *link)
1248{
1249	if (link->ce_mask & LINK_ATTR_IFNAME)
1250		return link->l_name;
1251	else
1252		return NULL;
1253}
1254
1255static inline void __assign_addr(struct rtnl_link *link, struct nl_addr **pos,
1256				 struct nl_addr *new, int flag)
1257{
1258	if (*pos)
1259		nl_addr_put(*pos);
1260
1261	nl_addr_get(new);
1262	*pos = new;
1263
1264	link->ce_mask |= flag;
1265}
1266
1267void rtnl_link_set_addr(struct rtnl_link *link, struct nl_addr *addr)
1268{
1269	__assign_addr(link, &link->l_addr, addr, LINK_ATTR_ADDR);
1270}
1271
1272struct nl_addr *rtnl_link_get_addr(struct rtnl_link *link)
1273{
1274	if (link->ce_mask & LINK_ATTR_ADDR)
1275		return link->l_addr;
1276	else
1277		return NULL;
1278}
1279
1280void rtnl_link_set_broadcast(struct rtnl_link *link, struct nl_addr *brd)
1281{
1282	__assign_addr(link, &link->l_bcast, brd, LINK_ATTR_BRD);
1283}
1284
1285struct nl_addr *rtnl_link_get_broadcast(struct rtnl_link *link)
1286{
1287	if (link->ce_mask & LINK_ATTR_BRD)
1288		return link->l_bcast;
1289	else
1290		return NULL;
1291}
1292
1293void rtnl_link_set_flags(struct rtnl_link *link, unsigned int flags)
1294{
1295	link->l_flag_mask |= flags;
1296	link->l_flags |= flags;
1297	link->ce_mask |= LINK_ATTR_FLAGS;
1298}
1299
1300void rtnl_link_unset_flags(struct rtnl_link *link, unsigned int flags)
1301{
1302	link->l_flag_mask |= flags;
1303	link->l_flags &= ~flags;
1304	link->ce_mask |= LINK_ATTR_FLAGS;
1305}
1306
1307unsigned int rtnl_link_get_flags(struct rtnl_link *link)
1308{
1309	return link->l_flags;
1310}
1311
1312void rtnl_link_set_family(struct rtnl_link *link, int family)
1313{
1314	link->l_family = family;
1315	link->ce_mask |= LINK_ATTR_FAMILY;
1316}
1317
1318int rtnl_link_get_family(struct rtnl_link *link)
1319{
1320	if (link->l_family & LINK_ATTR_FAMILY)
1321		return link->l_family;
1322	else
1323		return AF_UNSPEC;
1324}
1325
1326void rtnl_link_set_arptype(struct rtnl_link *link, unsigned int arptype)
1327{
1328	link->l_arptype = arptype;
1329}
1330
1331unsigned int rtnl_link_get_arptype(struct rtnl_link *link)
1332{
1333	return link->l_arptype;
1334}
1335
1336void rtnl_link_set_ifindex(struct rtnl_link *link, int ifindex)
1337{
1338	link->l_index = ifindex;
1339	link->ce_mask |= LINK_ATTR_IFINDEX;
1340}
1341
1342int rtnl_link_get_ifindex(struct rtnl_link *link)
1343{
1344	return link->l_index;
1345}
1346
1347void rtnl_link_set_mtu(struct rtnl_link *link, unsigned int mtu)
1348{
1349	link->l_mtu = mtu;
1350	link->ce_mask |= LINK_ATTR_MTU;
1351}
1352
1353unsigned int rtnl_link_get_mtu(struct rtnl_link *link)
1354{
1355	if (link->ce_mask & LINK_ATTR_MTU)
1356		return link->l_mtu;
1357	else
1358		return 0;
1359}
1360
1361void rtnl_link_set_txqlen(struct rtnl_link *link, unsigned int txqlen)
1362{
1363	link->l_txqlen = txqlen;
1364	link->ce_mask |= LINK_ATTR_TXQLEN;
1365}
1366
1367unsigned int rtnl_link_get_txqlen(struct rtnl_link *link)
1368{
1369	if (link->ce_mask & LINK_ATTR_TXQLEN)
1370		return link->l_txqlen;
1371	else
1372		return UINT_MAX;
1373}
1374
1375void rtnl_link_set_weight(struct rtnl_link *link, unsigned int weight)
1376{
1377	link->l_weight = weight;
1378	link->ce_mask |= LINK_ATTR_WEIGHT;
1379}
1380
1381unsigned int rtnl_link_get_weight(struct rtnl_link *link)
1382{
1383	if (link->ce_mask & LINK_ATTR_WEIGHT)
1384		return link->l_weight;
1385	else
1386		return UINT_MAX;
1387}
1388
1389void rtnl_link_set_link(struct rtnl_link *link, int ifindex)
1390{
1391	link->l_link = ifindex;
1392	link->ce_mask |= LINK_ATTR_LINK;
1393}
1394
1395int rtnl_link_get_link(struct rtnl_link *link)
1396{
1397	return link->l_link;
1398}
1399
1400void rtnl_link_set_master(struct rtnl_link *link, int ifindex)
1401{
1402	link->l_master = ifindex;
1403	link->ce_mask |= LINK_ATTR_MASTER;
1404}
1405
1406int rtnl_link_get_master(struct rtnl_link *link)
1407{
1408	return link->l_master;
1409}
1410
1411void rtnl_link_set_operstate(struct rtnl_link *link, uint8_t operstate)
1412{
1413	link->l_operstate = operstate;
1414	link->ce_mask |= LINK_ATTR_OPERSTATE;
1415}
1416
1417uint8_t rtnl_link_get_operstate(struct rtnl_link *link)
1418{
1419	if (link->ce_mask & LINK_ATTR_OPERSTATE)
1420		return link->l_operstate;
1421	else
1422		return IF_OPER_UNKNOWN;
1423}
1424
1425void rtnl_link_set_linkmode(struct rtnl_link *link, uint8_t linkmode)
1426{
1427	link->l_linkmode = linkmode;
1428	link->ce_mask |= LINK_ATTR_LINKMODE;
1429}
1430
1431uint8_t rtnl_link_get_linkmode(struct rtnl_link *link)
1432{
1433	if (link->ce_mask & LINK_ATTR_LINKMODE)
1434		return link->l_linkmode;
1435	else
1436		return IF_LINK_MODE_DEFAULT;
1437}
1438
1439uint64_t rtnl_link_get_stat(struct rtnl_link *link, int id)
1440{
1441	if (id < 0 || id > RTNL_LINK_STATS_MAX)
1442		return 0;
1443
1444	return link->l_stats[id];
1445}
1446
1447/**
1448 * Specify the info type of a link
1449 * @arg link	link object
1450 * @arg type	info type
1451 *
1452 * Looks up the info type and prepares the link to store info type
1453 * specific attributes. If an info type has been assigned already
1454 * it will be released with all changes lost.
1455 *
1456 * @return 0 on success or a negative errror code.
1457 */
1458int rtnl_link_set_info_type(struct rtnl_link *link, const char *type)
1459{
1460	struct rtnl_link_info_ops *io;
1461	int err;
1462
1463	if ((io = rtnl_link_info_ops_lookup(type)) == NULL)
1464		return -NLE_OPNOTSUPP;
1465
1466	if (link->l_info_ops)
1467		release_link_info(link);
1468
1469	if ((err = io->io_alloc(link)) < 0)
1470		return err;
1471
1472	link->l_info_ops = io;
1473
1474	return 0;
1475}
1476
1477/**
1478 * Return info type of a link
1479 * @arg link	link object
1480 *
1481 * @note The returned pointer is only valid as long as the link exists
1482 * @return Info type name or NULL if unknown.
1483 */
1484char *rtnl_link_get_info_type(struct rtnl_link *link)
1485{
1486	if (link->l_info_ops)
1487		return link->l_info_ops->io_name;
1488	else
1489		return NULL;
1490}
1491
1492/** @} */
1493
1494static struct nl_object_ops link_obj_ops = {
1495	.oo_name		= "route/link",
1496	.oo_size		= sizeof(struct rtnl_link),
1497	.oo_free_data		= link_free_data,
1498	.oo_clone		= link_clone,
1499	.oo_dump = {
1500	    [NL_DUMP_LINE]	= link_dump_line,
1501	    [NL_DUMP_DETAILS]	= link_dump_details,
1502	    [NL_DUMP_STATS]	= link_dump_stats,
1503	    [NL_DUMP_XML]	= link_dump_xml,
1504	    [NL_DUMP_ENV]	= link_dump_env,
1505	},
1506	.oo_compare		= link_compare,
1507	.oo_attrs2str		= link_attrs2str,
1508	.oo_id_attrs		= LINK_ATTR_IFINDEX,
1509};
1510
1511static struct nl_af_group link_groups[] = {
1512	{ AF_UNSPEC,	RTNLGRP_LINK },
1513	{ END_OF_GROUP_LIST },
1514};
1515
1516static struct nl_cache_ops rtnl_link_ops = {
1517	.co_name		= "route/link",
1518	.co_hdrsize		= sizeof(struct ifinfomsg),
1519	.co_msgtypes		= {
1520					{ RTM_NEWLINK, NL_ACT_NEW, "new" },
1521					{ RTM_DELLINK, NL_ACT_DEL, "del" },
1522					{ RTM_GETLINK, NL_ACT_GET, "get" },
1523					END_OF_MSGTYPES_LIST,
1524				  },
1525	.co_protocol		= NETLINK_ROUTE,
1526	.co_groups		= link_groups,
1527	.co_request_update	= link_request_update,
1528	.co_msg_parser		= link_msg_parser,
1529	.co_obj_ops		= &link_obj_ops,
1530};
1531
1532static void __init link_init(void)
1533{
1534	nl_cache_mngt_register(&rtnl_link_ops);
1535}
1536
1537static void __exit link_exit(void)
1538{
1539	nl_cache_mngt_unregister(&rtnl_link_ops);
1540}
1541
1542/** @} */
1543