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 
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  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 
422 errout:
423  rtnl_link_put(link);
424  return err;
425 }
426 
427 static 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 
432 static 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 
471 static 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 
517 static 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 
585 static 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 
658 static 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
730 static 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 
775 static 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 
809 static 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 
830 static 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 
841 struct rtnl_link *rtnl_link_alloc(void)
842 {
843  return (struct rtnl_link *) nl_object_alloc(&link_obj_ops);
844 }
845 
846 void 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  */
869 struct 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  */
895 struct 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  */
922 struct 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  */
965 struct 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 
1028 nla_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  */
1048 int 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  */
1085 char * 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  */
1106 int 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 
1127 static 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 
1149 char * 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 
1155 int 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 
1167 static 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 
1193 char *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 
1198 int 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 
1210 static 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 
1220 char *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 
1226 int 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 
1239 static struct trans_tbl link_modes[] = {
1240  __ADD(IF_LINK_MODE_DEFAULT, default)
1241  __ADD(IF_LINK_MODE_DORMANT, dormant)
1242 };
1243 
1244 char *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 
1249 int 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 
1261 void 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 
1267 char *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 
1275 void 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 
1281 char *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 
1289 static 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 
1301 void 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 
1306 struct 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 
1314 void 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 
1319 struct 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 
1327 void 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 
1334 void 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 
1341 unsigned int rtnl_link_get_flags(struct rtnl_link *link)
1342 {
1343  return link->l_flags;
1344 }
1345 
1346 void 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 
1352 int 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 
1360 void rtnl_link_set_arptype(struct rtnl_link *link, unsigned int arptype)
1361 {
1362  link->l_arptype = arptype;
1363 }
1364 
1365 unsigned int rtnl_link_get_arptype(struct rtnl_link *link)
1366 {
1367  return link->l_arptype;
1368 }
1369 
1370 void 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 
1376 int 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 
1384 void 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 
1390 unsigned 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 
1398 void 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 
1404 unsigned 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 
1412 void 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 
1418 unsigned 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 
1426 void 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 
1432 int 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 
1440 void 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 
1446 int 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 
1454 void 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 
1460 uint8_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 
1468 void 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 
1474 uint8_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 
1482 uint64_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  */
1501 int 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  */
1527 char *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 
1537 static 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 
1552 static struct nl_af_group link_groups[] = {
1553  { AF_UNSPEC, RTNLGRP_LINK },
1554  { END_OF_GROUP_LIST },
1555 };
1556 
1557 static 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 
1573 static void __init link_init(void)
1574 {
1575  nl_cache_mngt_register(&rtnl_link_ops);
1576 }
1577 
1578 static void __exit link_exit(void)
1579 {
1580  nl_cache_mngt_unregister(&rtnl_link_ops);
1581 }
1582 
1583 /** @} */