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