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