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