2 * lib/route/link.c Links (Interfaces)
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
9 * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
14 * @defgroup link Links (Interfaces)
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.
24 * @par Changeable Attributes
25 * @anchor link_changeable
26 * - Link layer address
27 * - Link layer broadcast address
28 * - device mapping (ifmap) (>= 2.6.9)
30 * - Transmission queue length (>= 2.6.9)
32 * - Link name (only via access through interface index) (>= 2.6.9)
45 * @par Link Flags (linux/if.h)
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.
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.
74 * @note The unit of the transmission queue length depends on the
75 * link type, a common unit is \a packets.
77 * @par 1) Retrieving information about available links
79 * // The first step is to retrieve a list of all available interfaces within
80 * // the kernel and put them into a cache.
81 * struct nl_cache *cache = rtnl_link_alloc_cache(sk);
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");
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);
92 * // After successful usage, the object must be given back to the cache
93 * rtnl_link_put(link);
96 * @par 2) Changing link attributes
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();
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);
106 * // We can also shut an interface down administratively
107 * rtnl_link_unset_flags(request, rtnl_link_str2flags("up"));
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");
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
115 * rtnl_link_change(sk, old, request);
117 * // An alternative way is to build the netlink message and send it
118 * // out yourself using nl_send_auto_complete()
119 * struct nl_msg *msg = rtnl_link_build_change_request(old, request);
120 * nl_send_auto_complete(sk, nlmsg_hdr(msg));
123 * // Don't forget to give back the link object ;->
124 * rtnl_link_put(old);
127 * @par 3) Link Type Specific Attributes
129 * // Some link types offer additional parameters and statistics specific
130 * // to their type. F.e. a VLAN link can be configured like this:
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");
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);
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);
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>
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
180 static struct nl_cache_ops rtnl_link_ops;
181 static struct nl_object_ops link_obj_ops;
184 static void release_link_info(struct rtnl_link *link)
186 struct rtnl_link_info_ops *io = link->l_info_ops;
191 link->l_info_ops = NULL;
195 static void link_free_data(struct nl_object *c)
197 struct rtnl_link *link = nl_object_priv(c);
200 struct rtnl_link_info_ops *io;
202 if ((io = link->l_info_ops) != NULL)
203 release_link_info(link);
205 nl_addr_put(link->l_addr);
206 nl_addr_put(link->l_bcast);
210 static int link_clone(struct nl_object *_dst, struct nl_object *_src)
212 struct rtnl_link *dst = nl_object_priv(_dst);
213 struct rtnl_link *src = nl_object_priv(_src);
217 if (!(dst->l_addr = nl_addr_clone(src->l_addr)))
221 if (!(dst->l_bcast = nl_addr_clone(src->l_bcast)))
224 if (src->l_info_ops && src->l_info_ops->io_clone) {
225 err = src->l_info_ops->io_clone(dst, src);
233 static struct nla_policy link_policy[IFLA_MAX+1] = {
234 [IFLA_IFNAME] = { .type = NLA_STRING,
235 .maxlen = IFNAMSIZ },
236 [IFLA_MTU] = { .type = NLA_U32 },
237 [IFLA_TXQLEN] = { .type = NLA_U32 },
238 [IFLA_LINK] = { .type = NLA_U32 },
239 [IFLA_WEIGHT] = { .type = NLA_U32 },
240 [IFLA_MASTER] = { .type = NLA_U32 },
241 [IFLA_OPERSTATE]= { .type = NLA_U8 },
242 [IFLA_LINKMODE] = { .type = NLA_U8 },
243 [IFLA_LINKINFO] = { .type = NLA_NESTED },
244 [IFLA_QDISC] = { .type = NLA_STRING,
245 .maxlen = IFQDISCSIZ },
246 [IFLA_STATS] = { .minlen = sizeof(struct rtnl_link_stats) },
247 [IFLA_MAP] = { .minlen = sizeof(struct rtnl_link_ifmap) },
250 static struct nla_policy link_info_policy[IFLA_INFO_MAX+1] = {
251 [IFLA_INFO_KIND] = { .type = NLA_STRING },
252 [IFLA_INFO_DATA] = { .type = NLA_NESTED },
253 [IFLA_INFO_XSTATS] = { .type = NLA_NESTED },
256 static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
257 struct nlmsghdr *n, struct nl_parser_param *pp)
259 struct rtnl_link *link;
260 struct ifinfomsg *ifi;
261 struct nlattr *tb[IFLA_MAX+1];
264 link = rtnl_link_alloc();
270 link->ce_msgtype = n->nlmsg_type;
272 err = nlmsg_parse(n, sizeof(*ifi), tb, IFLA_MAX, link_policy);
276 if (tb[IFLA_IFNAME] == NULL) {
277 err = -NLE_MISSING_ATTR;
281 nla_strlcpy(link->l_name, tb[IFLA_IFNAME], IFNAMSIZ);
284 link->l_family = ifi->ifi_family;
285 link->l_arptype = ifi->ifi_type;
286 link->l_index = ifi->ifi_index;
287 link->l_flags = ifi->ifi_flags;
288 link->l_change = ifi->ifi_change;
289 link->ce_mask = (LINK_ATTR_IFNAME | LINK_ATTR_FAMILY |
290 LINK_ATTR_ARPTYPE| LINK_ATTR_IFINDEX |
291 LINK_ATTR_FLAGS | LINK_ATTR_CHANGE);
293 if (tb[IFLA_STATS]) {
294 struct rtnl_link_stats *st = nla_data(tb[IFLA_STATS]);
296 link->l_stats[RTNL_LINK_RX_PACKETS] = st->rx_packets;
297 link->l_stats[RTNL_LINK_RX_BYTES] = st->rx_bytes;
298 link->l_stats[RTNL_LINK_RX_ERRORS] = st->rx_errors;
299 link->l_stats[RTNL_LINK_RX_DROPPED] = st->rx_dropped;
300 link->l_stats[RTNL_LINK_RX_COMPRESSED] = st->rx_compressed;
301 link->l_stats[RTNL_LINK_RX_FIFO_ERR] = st->rx_fifo_errors;
302 link->l_stats[RTNL_LINK_TX_PACKETS] = st->tx_packets;
303 link->l_stats[RTNL_LINK_TX_BYTES] = st->tx_bytes;
304 link->l_stats[RTNL_LINK_TX_ERRORS] = st->tx_errors;
305 link->l_stats[RTNL_LINK_TX_DROPPED] = st->tx_dropped;
306 link->l_stats[RTNL_LINK_TX_COMPRESSED] = st->tx_compressed;
307 link->l_stats[RTNL_LINK_TX_FIFO_ERR] = st->tx_fifo_errors;
308 link->l_stats[RTNL_LINK_RX_LEN_ERR] = st->rx_length_errors;
309 link->l_stats[RTNL_LINK_RX_OVER_ERR] = st->rx_over_errors;
310 link->l_stats[RTNL_LINK_RX_CRC_ERR] = st->rx_crc_errors;
311 link->l_stats[RTNL_LINK_RX_FRAME_ERR] = st->rx_frame_errors;
312 link->l_stats[RTNL_LINK_RX_MISSED_ERR] = st->rx_missed_errors;
313 link->l_stats[RTNL_LINK_TX_ABORT_ERR] = st->tx_aborted_errors;
314 link->l_stats[RTNL_LINK_TX_CARRIER_ERR] = st->tx_carrier_errors;
315 link->l_stats[RTNL_LINK_TX_HBEAT_ERR] = st->tx_heartbeat_errors;
316 link->l_stats[RTNL_LINK_TX_WIN_ERR] = st->tx_window_errors;
317 link->l_stats[RTNL_LINK_MULTICAST] = st->multicast;
319 link->ce_mask |= LINK_ATTR_STATS;
322 if (tb[IFLA_TXQLEN]) {
323 link->l_txqlen = nla_get_u32(tb[IFLA_TXQLEN]);
324 link->ce_mask |= LINK_ATTR_TXQLEN;
328 link->l_mtu = nla_get_u32(tb[IFLA_MTU]);
329 link->ce_mask |= LINK_ATTR_MTU;
332 if (tb[IFLA_ADDRESS]) {
333 link->l_addr = nl_addr_alloc_attr(tb[IFLA_ADDRESS], AF_UNSPEC);
334 if (link->l_addr == NULL) {
338 nl_addr_set_family(link->l_addr,
339 nl_addr_guess_family(link->l_addr));
340 link->ce_mask |= LINK_ATTR_ADDR;
343 if (tb[IFLA_BROADCAST]) {
344 link->l_bcast = nl_addr_alloc_attr(tb[IFLA_BROADCAST],
346 if (link->l_bcast == NULL) {
350 nl_addr_set_family(link->l_bcast,
351 nl_addr_guess_family(link->l_bcast));
352 link->ce_mask |= LINK_ATTR_BRD;
356 link->l_link = nla_get_u32(tb[IFLA_LINK]);
357 link->ce_mask |= LINK_ATTR_LINK;
360 if (tb[IFLA_WEIGHT]) {
361 link->l_weight = nla_get_u32(tb[IFLA_WEIGHT]);
362 link->ce_mask |= LINK_ATTR_WEIGHT;
365 if (tb[IFLA_QDISC]) {
366 nla_strlcpy(link->l_qdisc, tb[IFLA_QDISC], IFQDISCSIZ);
367 link->ce_mask |= LINK_ATTR_QDISC;
371 nla_memcpy(&link->l_map, tb[IFLA_MAP],
372 sizeof(struct rtnl_link_ifmap));
373 link->ce_mask |= LINK_ATTR_MAP;
376 if (tb[IFLA_MASTER]) {
377 link->l_master = nla_get_u32(tb[IFLA_MASTER]);
378 link->ce_mask |= LINK_ATTR_MASTER;
381 if (tb[IFLA_OPERSTATE]) {
382 link->l_operstate = nla_get_u8(tb[IFLA_OPERSTATE]);
383 link->ce_mask |= LINK_ATTR_OPERSTATE;
386 if (tb[IFLA_LINKMODE]) {
387 link->l_linkmode = nla_get_u8(tb[IFLA_LINKMODE]);
388 link->ce_mask |= LINK_ATTR_LINKMODE;
391 if (tb[IFLA_LINKINFO]) {
392 struct nlattr *li[IFLA_INFO_MAX+1];
394 err = nla_parse_nested(li, IFLA_INFO_MAX, tb[IFLA_LINKINFO],
399 if (li[IFLA_INFO_KIND] &&
400 (li[IFLA_INFO_DATA] || li[IFLA_INFO_XSTATS])) {
401 struct rtnl_link_info_ops *ops;
404 kind = nla_get_string(li[IFLA_INFO_KIND]);
405 ops = rtnl_link_info_ops_lookup(kind);
408 link->l_info_ops = ops;
409 err = ops->io_parse(link, li[IFLA_INFO_DATA],
410 li[IFLA_INFO_XSTATS]);
414 /* XXX: Warn about unparsed info? */
419 err = pp->pp_cb((struct nl_object *) link, pp);
425 static int link_request_update(struct nl_cache *cache, struct nl_sock *sk)
427 return nl_rtgen_request(sk, RTM_GETLINK, AF_UNSPEC, NLM_F_DUMP);
430 static void link_dump_line(struct nl_object *obj, struct nl_dump_params *p)
433 struct nl_cache *cache = dp_cache(obj);
434 struct rtnl_link *link = (struct rtnl_link *) obj;
436 nl_dump_line(p, "%s %s ", link->l_name,
437 nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
439 if (link->l_addr && !nl_addr_iszero(link->l_addr))
440 nl_dump(p, "%s ", nl_addr2str(link->l_addr, buf, sizeof(buf)));
442 if (link->ce_mask & LINK_ATTR_MASTER) {
443 struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
444 nl_dump(p, "master %s ", master ? master->l_name : "inv");
446 rtnl_link_put(master);
449 rtnl_link_flags2str(link->l_flags, buf, sizeof(buf));
451 nl_dump(p, "<%s> ", buf);
453 if (link->ce_mask & LINK_ATTR_LINK) {
454 struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
455 nl_dump(p, "slave-of %s ", ll ? ll->l_name : "NONE");
460 if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_LINE])
461 link->l_info_ops->io_dump[NL_DUMP_LINE](link, p);
466 static void link_dump_details(struct nl_object *obj, struct nl_dump_params *p)
468 struct rtnl_link *link = (struct rtnl_link *) obj;
471 link_dump_line(obj, p);
473 nl_dump_line(p, " mtu %u ", link->l_mtu);
474 nl_dump(p, "txqlen %u weight %u ", link->l_txqlen, link->l_weight);
476 if (link->ce_mask & LINK_ATTR_QDISC)
477 nl_dump(p, "qdisc %s ", link->l_qdisc);
479 if (link->ce_mask & LINK_ATTR_MAP && link->l_map.lm_irq)
480 nl_dump(p, "irq %u ", link->l_map.lm_irq);
482 if (link->ce_mask & LINK_ATTR_IFINDEX)
483 nl_dump(p, "index %u ", link->l_index);
487 nl_dump_line(p, " ");
489 if (link->ce_mask & LINK_ATTR_BRD)
490 nl_dump(p, "brd %s ", nl_addr2str(link->l_bcast, buf,
493 if ((link->ce_mask & LINK_ATTR_OPERSTATE) &&
494 link->l_operstate != IF_OPER_UNKNOWN) {
495 rtnl_link_operstate2str(link->l_operstate, buf, sizeof(buf));
496 nl_dump(p, "state %s ", buf);
499 nl_dump(p, "mode %s\n",
500 rtnl_link_mode2str(link->l_linkmode, buf, sizeof(buf)));
502 if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_DETAILS])
503 link->l_info_ops->io_dump[NL_DUMP_DETAILS](link, p);
506 static void link_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
508 struct rtnl_link *link = (struct rtnl_link *) obj;
512 link_dump_details(obj, p);
514 nl_dump_line(p, " Stats: bytes packets errors "
515 " dropped fifo-err compressed\n");
517 res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_RX_BYTES], &unit);
519 strcpy(fmt, " RX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n");
520 fmt[9] = *unit == 'B' ? '9' : '7';
522 nl_dump_line(p, fmt, res, unit,
523 link->l_stats[RTNL_LINK_RX_PACKETS],
524 link->l_stats[RTNL_LINK_RX_ERRORS],
525 link->l_stats[RTNL_LINK_RX_DROPPED],
526 link->l_stats[RTNL_LINK_RX_FIFO_ERR],
527 link->l_stats[RTNL_LINK_RX_COMPRESSED]);
529 res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_TX_BYTES], &unit);
531 strcpy(fmt, " TX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n");
532 fmt[9] = *unit == 'B' ? '9' : '7';
534 nl_dump_line(p, fmt, res, unit,
535 link->l_stats[RTNL_LINK_TX_PACKETS],
536 link->l_stats[RTNL_LINK_TX_ERRORS],
537 link->l_stats[RTNL_LINK_TX_DROPPED],
538 link->l_stats[RTNL_LINK_TX_FIFO_ERR],
539 link->l_stats[RTNL_LINK_TX_COMPRESSED]);
541 nl_dump_line(p, " Errors: length over crc "
542 " frame missed multicast\n");
544 nl_dump_line(p, " RX %10" PRIu64 " %10" PRIu64 " %10"
545 PRIu64 " %10" PRIu64 " %10" PRIu64 " %10"
547 link->l_stats[RTNL_LINK_RX_LEN_ERR],
548 link->l_stats[RTNL_LINK_RX_OVER_ERR],
549 link->l_stats[RTNL_LINK_RX_CRC_ERR],
550 link->l_stats[RTNL_LINK_RX_FRAME_ERR],
551 link->l_stats[RTNL_LINK_RX_MISSED_ERR],
552 link->l_stats[RTNL_LINK_MULTICAST]);
554 nl_dump_line(p, " aborted carrier heartbeat "
555 " window collision\n");
557 nl_dump_line(p, " TX %10" PRIu64 " %10" PRIu64 " %10"
558 PRIu64 " %10" PRIu64 " %10" PRIu64 "\n",
559 link->l_stats[RTNL_LINK_TX_ABORT_ERR],
560 link->l_stats[RTNL_LINK_TX_CARRIER_ERR],
561 link->l_stats[RTNL_LINK_TX_HBEAT_ERR],
562 link->l_stats[RTNL_LINK_TX_WIN_ERR],
563 link->l_stats[RTNL_LINK_TX_COLLISIONS]);
565 if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_STATS])
566 link->l_info_ops->io_dump[NL_DUMP_STATS](link, p);
569 static void link_dump_env(struct nl_object *obj, struct nl_dump_params *p)
571 struct rtnl_link *link = (struct rtnl_link *) obj;
572 struct nl_cache *cache = dp_cache(obj);
576 nl_dump_line(p, "LINK_NAME=%s\n", link->l_name);
577 nl_dump_line(p, "LINK_IFINDEX=%u\n", link->l_index);
578 nl_dump_line(p, "LINK_FAMILY=%s\n",
579 nl_af2str(link->l_family, buf, sizeof(buf)));
580 nl_dump_line(p, "LINK_TYPE=%s\n",
581 nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
582 if (link->ce_mask & LINK_ATTR_ADDR)
583 nl_dump_line(p, "LINK_ADDRESS=%s\n",
584 nl_addr2str(link->l_addr, buf, sizeof(buf)));
585 nl_dump_line(p, "LINK_MTU=%u\n", link->l_mtu);
586 nl_dump_line(p, "LINK_TXQUEUELEN=%u\n", link->l_txqlen);
587 nl_dump_line(p, "LINK_WEIGHT=%u\n", link->l_weight);
589 rtnl_link_flags2str(link->l_flags & ~IFF_RUNNING, buf, sizeof(buf));
591 nl_dump_line(p, "LINK_FLAGS=%s\n", buf);
593 if (link->ce_mask & LINK_ATTR_QDISC)
594 nl_dump_line(p, "LINK_QDISC=%s\n", link->l_qdisc);
596 if (link->ce_mask & LINK_ATTR_LINK) {
597 struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
599 nl_dump_line(p, "LINK_LINK_IFINDEX=%d\n", link->l_link);
601 nl_dump_line(p, "LINK_LINK_IFNAME=%s\n", ll->l_name);
606 if (link->ce_mask & LINK_ATTR_MASTER) {
607 struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
608 nl_dump_line(p, "LINK_MASTER=%s\n",
609 master ? master->l_name : "none");
611 rtnl_link_put(master);
614 if (link->ce_mask & LINK_ATTR_BRD)
615 nl_dump_line(p, "LINK_BROADCAST=%s\n",
616 nl_addr2str(link->l_bcast, buf, sizeof(buf)));
618 if (link->ce_mask & LINK_ATTR_STATS) {
619 for (i = 0; i <= RTNL_LINK_STATS_MAX; i++) {
622 sprintf(buf, "LINK_");
623 rtnl_link_stat2str(i, buf + 5, sizeof(buf) - 5);
628 nl_dump_line(p, "%s=%" PRIu64 "\n", buf, link->l_stats[i]);
632 if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_ENV])
633 link->l_info_ops->io_dump[NL_DUMP_ENV](link, p);
637 static int link_handle_event(struct nl_object *a, struct rtnl_link_event_cb *cb)
639 struct rtnl_link *l = (struct rtnl_link *) a;
640 struct nl_cache *c = dp_cache(a);
643 if (l->l_change == ~0U) {
644 if (l->ce_msgtype == RTM_NEWLINK)
647 cb->le_unregister(l);
652 if (l->l_change & IFF_SLAVE) {
653 if (l->l_flags & IFF_SLAVE) {
654 struct rtnl_link *m = rtnl_link_get(c, l->l_master);
655 cb->le_new_bonding(l, m);
659 cb->le_cancel_bonding(l);
663 if (l->l_change & IFF_UP && l->l_change & IFF_RUNNING)
664 dp_dump_line(p, line++, "link %s changed state to %s.\n",
665 l->l_name, l->l_flags & IFF_UP ? "up" : "down");
667 if (l->l_change & IFF_PROMISC) {
668 dp_new_line(p, line++);
669 dp_dump(p, "link %s %s promiscuous mode.\n",
670 l->l_name, l->l_flags & IFF_PROMISC ? "entered" : "left");
674 dp_dump_line(p, line++, "link %s sent unknown event.\n",
682 static int link_compare(struct nl_object *_a, struct nl_object *_b,
683 uint32_t attrs, int flags)
685 struct rtnl_link *a = (struct rtnl_link *) _a;
686 struct rtnl_link *b = (struct rtnl_link *) _b;
689 #define LINK_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, LINK_ATTR_##ATTR, a, b, EXPR)
691 diff |= LINK_DIFF(IFINDEX, a->l_index != b->l_index);
692 diff |= LINK_DIFF(MTU, a->l_mtu != b->l_mtu);
693 diff |= LINK_DIFF(LINK, a->l_link != b->l_link);
694 diff |= LINK_DIFF(TXQLEN, a->l_txqlen != b->l_txqlen);
695 diff |= LINK_DIFF(WEIGHT, a->l_weight != b->l_weight);
696 diff |= LINK_DIFF(MASTER, a->l_master != b->l_master);
697 diff |= LINK_DIFF(FAMILY, a->l_family != b->l_family);
698 diff |= LINK_DIFF(OPERSTATE, a->l_operstate != b->l_operstate);
699 diff |= LINK_DIFF(LINKMODE, a->l_linkmode != b->l_linkmode);
700 diff |= LINK_DIFF(QDISC, strcmp(a->l_qdisc, b->l_qdisc));
701 diff |= LINK_DIFF(IFNAME, strcmp(a->l_name, b->l_name));
702 diff |= LINK_DIFF(ADDR, nl_addr_cmp(a->l_addr, b->l_addr));
703 diff |= LINK_DIFF(BRD, nl_addr_cmp(a->l_bcast, b->l_bcast));
705 if (flags & LOOSE_COMPARISON)
706 diff |= LINK_DIFF(FLAGS,
707 (a->l_flags ^ b->l_flags) & b->l_flag_mask);
709 diff |= LINK_DIFF(FLAGS, a->l_flags != b->l_flags);
716 static struct trans_tbl link_attrs[] = {
717 __ADD(LINK_ATTR_MTU, mtu)
718 __ADD(LINK_ATTR_LINK, link)
719 __ADD(LINK_ATTR_TXQLEN, txqlen)
720 __ADD(LINK_ATTR_WEIGHT, weight)
721 __ADD(LINK_ATTR_MASTER, master)
722 __ADD(LINK_ATTR_QDISC, qdisc)
723 __ADD(LINK_ATTR_MAP, map)
724 __ADD(LINK_ATTR_ADDR, address)
725 __ADD(LINK_ATTR_BRD, broadcast)
726 __ADD(LINK_ATTR_FLAGS, flags)
727 __ADD(LINK_ATTR_IFNAME, name)
728 __ADD(LINK_ATTR_IFINDEX, ifindex)
729 __ADD(LINK_ATTR_FAMILY, family)
730 __ADD(LINK_ATTR_ARPTYPE, arptype)
731 __ADD(LINK_ATTR_STATS, stats)
732 __ADD(LINK_ATTR_CHANGE, change)
733 __ADD(LINK_ATTR_OPERSTATE, operstate)
734 __ADD(LINK_ATTR_LINKMODE, linkmode)
737 static char *link_attrs2str(int attrs, char *buf, size_t len)
739 return __flags2str(attrs, buf, len, link_attrs,
740 ARRAY_SIZE(link_attrs));
744 * @name Allocation/Freeing
748 struct rtnl_link *rtnl_link_alloc(void)
750 return (struct rtnl_link *) nl_object_alloc(&link_obj_ops);
753 void rtnl_link_put(struct rtnl_link *link)
755 nl_object_put((struct nl_object *) link);
761 * @name Cache Management
767 * Allocate link cache and fill in all configured links.
768 * @arg sk Netlink socket.
769 * @arg result Pointer to store resulting cache.
771 * Allocates a new link cache, initializes it properly and updates it
772 * to include all links currently configured in the kernel.
774 * @return 0 on success or a negative error code.
776 int rtnl_link_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
778 return nl_cache_alloc_and_fill(&rtnl_link_ops, sk, result);
782 * Look up link by interface index in the provided cache
783 * @arg cache link cache
784 * @arg ifindex link interface index
786 * The caller owns a reference on the returned object and
787 * must give the object back via rtnl_link_put().
789 * @return pointer to link inside the cache or NULL if no match was found.
791 struct rtnl_link *rtnl_link_get(struct nl_cache *cache, int ifindex)
793 struct rtnl_link *link;
795 if (cache->c_ops != &rtnl_link_ops)
798 nl_list_for_each_entry(link, &cache->c_items, ce_list) {
799 if (link->l_index == ifindex) {
800 nl_object_get((struct nl_object *) link);
809 * Look up link by link name in the provided cache
810 * @arg cache link cache
811 * @arg name link name
813 * The caller owns a reference on the returned object and
814 * must give the object back via rtnl_link_put().
816 * @return pointer to link inside the cache or NULL if no match was found.
818 struct rtnl_link *rtnl_link_get_by_name(struct nl_cache *cache,
821 struct rtnl_link *link;
823 if (cache->c_ops != &rtnl_link_ops)
826 nl_list_for_each_entry(link, &cache->c_items, ce_list) {
827 if (!strcmp(name, link->l_name)) {
828 nl_object_get((struct nl_object *) link);
839 * @name Link Modifications
844 * Builds a netlink change request message to change link attributes
845 * @arg old link to be changed
846 * @arg tmpl template with requested changes
847 * @arg flags additional netlink message flags
849 * Builds a new netlink message requesting a change of link attributes.
850 * The netlink message header isn't fully equipped with all relevant
851 * fields and must be sent out via nl_send_auto_complete() or
852 * supplemented as needed.
853 * \a old must point to a link currently configured in the kernel
854 * and \a tmpl must contain the attributes to be changed set via
855 * \c rtnl_link_set_* functions.
857 * @return New netlink message
858 * @note Not all attributes can be changed, see
859 * \ref link_changeable "Changeable Attributes" for more details.
861 int rtnl_link_build_change_request(struct rtnl_link *old,
862 struct rtnl_link *tmpl, int flags,
863 struct nl_msg **result)
866 struct ifinfomsg ifi = {
867 .ifi_family = old->l_family,
868 .ifi_index = old->l_index,
871 if (tmpl->ce_mask & LINK_ATTR_FLAGS) {
872 ifi.ifi_flags = old->l_flags & ~tmpl->l_flag_mask;
873 ifi.ifi_flags |= tmpl->l_flags;
876 msg = nlmsg_alloc_simple(RTM_SETLINK, flags);
880 if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
881 goto nla_put_failure;
883 if (tmpl->ce_mask & LINK_ATTR_ADDR)
884 NLA_PUT_ADDR(msg, IFLA_ADDRESS, tmpl->l_addr);
886 if (tmpl->ce_mask & LINK_ATTR_BRD)
887 NLA_PUT_ADDR(msg, IFLA_BROADCAST, tmpl->l_bcast);
889 if (tmpl->ce_mask & LINK_ATTR_MTU)
890 NLA_PUT_U32(msg, IFLA_MTU, tmpl->l_mtu);
892 if (tmpl->ce_mask & LINK_ATTR_TXQLEN)
893 NLA_PUT_U32(msg, IFLA_TXQLEN, tmpl->l_txqlen);
895 if (tmpl->ce_mask & LINK_ATTR_WEIGHT)
896 NLA_PUT_U32(msg, IFLA_WEIGHT, tmpl->l_weight);
898 if (tmpl->ce_mask & LINK_ATTR_IFNAME)
899 NLA_PUT_STRING(msg, IFLA_IFNAME, tmpl->l_name);
901 if (tmpl->ce_mask & LINK_ATTR_OPERSTATE)
902 NLA_PUT_U8(msg, IFLA_OPERSTATE, tmpl->l_operstate);
904 if (tmpl->ce_mask & LINK_ATTR_LINKMODE)
905 NLA_PUT_U8(msg, IFLA_LINKMODE, tmpl->l_linkmode);
907 if ((tmpl->ce_mask & LINK_ATTR_LINKINFO) && tmpl->l_info_ops &&
908 tmpl->l_info_ops->io_put_attrs) {
911 if (!(info = nla_nest_start(msg, IFLA_LINKINFO)))
912 goto nla_put_failure;
914 NLA_PUT_STRING(msg, IFLA_INFO_KIND, tmpl->l_info_ops->io_name);
916 if (tmpl->l_info_ops->io_put_attrs(msg, tmpl) < 0)
917 goto nla_put_failure;
919 nla_nest_end(msg, info);
931 * Change link attributes
932 * @arg sk Netlink socket.
933 * @arg old link to be changed
934 * @arg tmpl template with requested changes
935 * @arg flags additional netlink message flags
937 * Builds a new netlink message by calling rtnl_link_build_change_request(),
938 * sends the request to the kernel and waits for the next ACK to be
939 * received, i.e. blocks until the request has been processed.
941 * @return 0 on success or a negative error code
942 * @note Not all attributes can be changed, see
943 * \ref link_changeable "Changeable Attributes" for more details.
945 int rtnl_link_change(struct nl_sock *sk, struct rtnl_link *old,
946 struct rtnl_link *tmpl, int flags)
951 if ((err = rtnl_link_build_change_request(old, tmpl, flags, &msg)) < 0)
954 err = nl_send_auto_complete(sk, msg);
959 return wait_for_ack(sk);
965 * @name Name <-> Index Translations
970 * Translate an interface index to the corresponding link name
971 * @arg cache link cache
972 * @arg ifindex link interface index
973 * @arg dst destination buffer
974 * @arg len length of destination buffer
976 * Translates the specified interface index to the corresponding
977 * link name and stores the name in the destination buffer.
979 * @return link name or NULL if no match was found.
981 char * rtnl_link_i2name(struct nl_cache *cache, int ifindex, char *dst,
984 struct rtnl_link *link = rtnl_link_get(cache, ifindex);
987 strncpy(dst, link->l_name, len - 1);
996 * Translate a link name to the corresponding interface index
997 * @arg cache link cache
998 * @arg name link name
1000 * @return interface index or 0 if no match was found.
1002 int rtnl_link_name2i(struct nl_cache *cache, const char *name)
1005 struct rtnl_link *link;
1007 link = rtnl_link_get_by_name(cache, name);
1009 ifindex = link->l_index;
1010 rtnl_link_put(link);
1019 * @name Link Flags Translations
1023 static struct trans_tbl link_flags[] = {
1024 __ADD(IFF_LOOPBACK, loopback)
1025 __ADD(IFF_BROADCAST, broadcast)
1026 __ADD(IFF_POINTOPOINT, pointopoint)
1027 __ADD(IFF_MULTICAST, multicast)
1028 __ADD(IFF_NOARP, noarp)
1029 __ADD(IFF_ALLMULTI, allmulti)
1030 __ADD(IFF_PROMISC, promisc)
1031 __ADD(IFF_MASTER, master)
1032 __ADD(IFF_SLAVE, slave)
1033 __ADD(IFF_DEBUG, debug)
1034 __ADD(IFF_DYNAMIC, dynamic)
1035 __ADD(IFF_AUTOMEDIA, automedia)
1036 __ADD(IFF_PORTSEL, portsel)
1037 __ADD(IFF_NOTRAILERS, notrailers)
1039 __ADD(IFF_RUNNING, running)
1040 __ADD(IFF_LOWER_UP, lowerup)
1041 __ADD(IFF_DORMANT, dormant)
1042 __ADD(IFF_ECHO, echo)
1045 char * rtnl_link_flags2str(int flags, char *buf, size_t len)
1047 return __flags2str(flags, buf, len, link_flags,
1048 ARRAY_SIZE(link_flags));
1051 int rtnl_link_str2flags(const char *name)
1053 return __str2flags(name, link_flags, ARRAY_SIZE(link_flags));
1059 * @name Link Statistics Translations
1063 static struct trans_tbl link_stats[] = {
1064 __ADD(RTNL_LINK_RX_PACKETS, rx_packets)
1065 __ADD(RTNL_LINK_TX_PACKETS, tx_packets)
1066 __ADD(RTNL_LINK_RX_BYTES, rx_bytes)
1067 __ADD(RTNL_LINK_TX_BYTES, tx_bytes)
1068 __ADD(RTNL_LINK_RX_ERRORS, rx_errors)
1069 __ADD(RTNL_LINK_TX_ERRORS, tx_errors)
1070 __ADD(RTNL_LINK_RX_DROPPED, rx_dropped)
1071 __ADD(RTNL_LINK_TX_DROPPED, tx_dropped)
1072 __ADD(RTNL_LINK_RX_COMPRESSED, rx_compressed)
1073 __ADD(RTNL_LINK_TX_COMPRESSED, tx_compressed)
1074 __ADD(RTNL_LINK_RX_FIFO_ERR, rx_fifo_err)
1075 __ADD(RTNL_LINK_TX_FIFO_ERR, tx_fifo_err)
1076 __ADD(RTNL_LINK_RX_LEN_ERR, rx_len_err)
1077 __ADD(RTNL_LINK_RX_OVER_ERR, rx_over_err)
1078 __ADD(RTNL_LINK_RX_CRC_ERR, rx_crc_err)
1079 __ADD(RTNL_LINK_RX_FRAME_ERR, rx_frame_err)
1080 __ADD(RTNL_LINK_RX_MISSED_ERR, rx_missed_err)
1081 __ADD(RTNL_LINK_TX_ABORT_ERR, tx_abort_err)
1082 __ADD(RTNL_LINK_TX_CARRIER_ERR, tx_carrier_err)
1083 __ADD(RTNL_LINK_TX_HBEAT_ERR, tx_hbeat_err)
1084 __ADD(RTNL_LINK_TX_WIN_ERR, tx_win_err)
1085 __ADD(RTNL_LINK_TX_COLLISIONS, tx_collision)
1086 __ADD(RTNL_LINK_MULTICAST, multicast)
1089 char *rtnl_link_stat2str(int st, char *buf, size_t len)
1091 return __type2str(st, buf, len, link_stats, ARRAY_SIZE(link_stats));
1094 int rtnl_link_str2stat(const char *name)
1096 return __str2type(name, link_stats, ARRAY_SIZE(link_stats));
1102 * @name Link Operstate Translations
1106 static struct trans_tbl link_operstates[] = {
1107 __ADD(IF_OPER_UNKNOWN, unknown)
1108 __ADD(IF_OPER_NOTPRESENT, notpresent)
1109 __ADD(IF_OPER_DOWN, down)
1110 __ADD(IF_OPER_LOWERLAYERDOWN, lowerlayerdown)
1111 __ADD(IF_OPER_TESTING, testing)
1112 __ADD(IF_OPER_DORMANT, dormant)
1113 __ADD(IF_OPER_UP, up)
1116 char *rtnl_link_operstate2str(int st, char *buf, size_t len)
1118 return __type2str(st, buf, len, link_operstates,
1119 ARRAY_SIZE(link_operstates));
1122 int rtnl_link_str2operstate(const char *name)
1124 return __str2type(name, link_operstates,
1125 ARRAY_SIZE(link_operstates));
1131 * @name Link Mode Translations
1135 static struct trans_tbl link_modes[] = {
1136 __ADD(IF_LINK_MODE_DEFAULT, default)
1137 __ADD(IF_LINK_MODE_DORMANT, dormant)
1140 char *rtnl_link_mode2str(int st, char *buf, size_t len)
1142 return __type2str(st, buf, len, link_modes, ARRAY_SIZE(link_modes));
1145 int rtnl_link_str2mode(const char *name)
1147 return __str2type(name, link_modes, ARRAY_SIZE(link_modes));
1157 void rtnl_link_set_qdisc(struct rtnl_link *link, const char *qdisc)
1159 strncpy(link->l_qdisc, qdisc, sizeof(link->l_qdisc) - 1);
1160 link->ce_mask |= LINK_ATTR_QDISC;
1163 char *rtnl_link_get_qdisc(struct rtnl_link *link)
1165 if (link->ce_mask & LINK_ATTR_QDISC)
1166 return link->l_qdisc;
1171 void rtnl_link_set_name(struct rtnl_link *link, const char *name)
1173 strncpy(link->l_name, name, sizeof(link->l_name) - 1);
1174 link->ce_mask |= LINK_ATTR_IFNAME;
1177 char *rtnl_link_get_name(struct rtnl_link *link)
1179 if (link->ce_mask & LINK_ATTR_IFNAME)
1180 return link->l_name;
1185 static inline void __assign_addr(struct rtnl_link *link, struct nl_addr **pos,
1186 struct nl_addr *new, int flag)
1194 link->ce_mask |= flag;
1197 void rtnl_link_set_addr(struct rtnl_link *link, struct nl_addr *addr)
1199 __assign_addr(link, &link->l_addr, addr, LINK_ATTR_ADDR);
1202 struct nl_addr *rtnl_link_get_addr(struct rtnl_link *link)
1204 if (link->ce_mask & LINK_ATTR_ADDR)
1205 return link->l_addr;
1210 void rtnl_link_set_broadcast(struct rtnl_link *link, struct nl_addr *brd)
1212 __assign_addr(link, &link->l_bcast, brd, LINK_ATTR_BRD);
1215 struct nl_addr *rtnl_link_get_broadcast(struct rtnl_link *link)
1217 if (link->ce_mask & LINK_ATTR_BRD)
1218 return link->l_bcast;
1223 void rtnl_link_set_flags(struct rtnl_link *link, unsigned int flags)
1225 link->l_flag_mask |= flags;
1226 link->l_flags |= flags;
1227 link->ce_mask |= LINK_ATTR_FLAGS;
1230 void rtnl_link_unset_flags(struct rtnl_link *link, unsigned int flags)
1232 link->l_flag_mask |= flags;
1233 link->l_flags &= ~flags;
1234 link->ce_mask |= LINK_ATTR_FLAGS;
1237 unsigned int rtnl_link_get_flags(struct rtnl_link *link)
1239 return link->l_flags;
1242 void rtnl_link_set_family(struct rtnl_link *link, int family)
1244 link->l_family = family;
1245 link->ce_mask |= LINK_ATTR_FAMILY;
1248 int rtnl_link_get_family(struct rtnl_link *link)
1250 if (link->l_family & LINK_ATTR_FAMILY)
1251 return link->l_family;
1256 void rtnl_link_set_arptype(struct rtnl_link *link, unsigned int arptype)
1258 link->l_arptype = arptype;
1261 unsigned int rtnl_link_get_arptype(struct rtnl_link *link)
1263 return link->l_arptype;
1266 void rtnl_link_set_ifindex(struct rtnl_link *link, int ifindex)
1268 link->l_index = ifindex;
1269 link->ce_mask |= LINK_ATTR_IFINDEX;
1272 int rtnl_link_get_ifindex(struct rtnl_link *link)
1274 return link->l_index;
1277 void rtnl_link_set_mtu(struct rtnl_link *link, unsigned int mtu)
1280 link->ce_mask |= LINK_ATTR_MTU;
1283 unsigned int rtnl_link_get_mtu(struct rtnl_link *link)
1285 if (link->ce_mask & LINK_ATTR_MTU)
1291 void rtnl_link_set_txqlen(struct rtnl_link *link, unsigned int txqlen)
1293 link->l_txqlen = txqlen;
1294 link->ce_mask |= LINK_ATTR_TXQLEN;
1297 unsigned int rtnl_link_get_txqlen(struct rtnl_link *link)
1299 if (link->ce_mask & LINK_ATTR_TXQLEN)
1300 return link->l_txqlen;
1305 void rtnl_link_set_weight(struct rtnl_link *link, unsigned int weight)
1307 link->l_weight = weight;
1308 link->ce_mask |= LINK_ATTR_WEIGHT;
1311 unsigned int rtnl_link_get_weight(struct rtnl_link *link)
1313 if (link->ce_mask & LINK_ATTR_WEIGHT)
1314 return link->l_weight;
1319 void rtnl_link_set_link(struct rtnl_link *link, int ifindex)
1321 link->l_link = ifindex;
1322 link->ce_mask |= LINK_ATTR_LINK;
1325 int rtnl_link_get_link(struct rtnl_link *link)
1327 return link->l_link;
1330 void rtnl_link_set_master(struct rtnl_link *link, int ifindex)
1332 link->l_master = ifindex;
1333 link->ce_mask |= LINK_ATTR_MASTER;
1336 int rtnl_link_get_master(struct rtnl_link *link)
1338 return link->l_master;
1341 void rtnl_link_set_operstate(struct rtnl_link *link, uint8_t operstate)
1343 link->l_operstate = operstate;
1344 link->ce_mask |= LINK_ATTR_OPERSTATE;
1347 uint8_t rtnl_link_get_operstate(struct rtnl_link *link)
1349 if (link->ce_mask & LINK_ATTR_OPERSTATE)
1350 return link->l_operstate;
1352 return IF_OPER_UNKNOWN;
1355 void rtnl_link_set_linkmode(struct rtnl_link *link, uint8_t linkmode)
1357 link->l_linkmode = linkmode;
1358 link->ce_mask |= LINK_ATTR_LINKMODE;
1361 uint8_t rtnl_link_get_linkmode(struct rtnl_link *link)
1363 if (link->ce_mask & LINK_ATTR_LINKMODE)
1364 return link->l_linkmode;
1366 return IF_LINK_MODE_DEFAULT;
1369 uint64_t rtnl_link_get_stat(struct rtnl_link *link, int id)
1371 if (id < 0 || id > RTNL_LINK_STATS_MAX)
1374 return link->l_stats[id];
1378 * Specify the info type of a link
1379 * @arg link link object
1380 * @arg type info type
1382 * Looks up the info type and prepares the link to store info type
1383 * specific attributes. If an info type has been assigned already
1384 * it will be released with all changes lost.
1386 * @return 0 on success or a negative errror code.
1388 int rtnl_link_set_info_type(struct rtnl_link *link, const char *type)
1390 struct rtnl_link_info_ops *io;
1393 if ((io = rtnl_link_info_ops_lookup(type)) == NULL)
1394 return -NLE_OPNOTSUPP;
1396 if (link->l_info_ops)
1397 release_link_info(link);
1399 if ((err = io->io_alloc(link)) < 0)
1402 link->l_info_ops = io;
1408 * Return info type of a link
1409 * @arg link link object
1411 * @note The returned pointer is only valid as long as the link exists
1412 * @return Info type name or NULL if unknown.
1414 char *rtnl_link_get_info_type(struct rtnl_link *link)
1416 if (link->l_info_ops)
1417 return link->l_info_ops->io_name;
1424 static struct nl_object_ops link_obj_ops = {
1425 .oo_name = "route/link",
1426 .oo_size = sizeof(struct rtnl_link),
1427 .oo_free_data = link_free_data,
1428 .oo_clone = link_clone,
1430 [NL_DUMP_LINE] = link_dump_line,
1431 [NL_DUMP_DETAILS] = link_dump_details,
1432 [NL_DUMP_STATS] = link_dump_stats,
1433 [NL_DUMP_ENV] = link_dump_env,
1435 .oo_compare = link_compare,
1436 .oo_attrs2str = link_attrs2str,
1437 .oo_id_attrs = LINK_ATTR_IFINDEX,
1440 static struct nl_af_group link_groups[] = {
1441 { AF_UNSPEC, RTNLGRP_LINK },
1442 { END_OF_GROUP_LIST },
1445 static struct nl_cache_ops rtnl_link_ops = {
1446 .co_name = "route/link",
1447 .co_hdrsize = sizeof(struct ifinfomsg),
1449 { RTM_NEWLINK, NL_ACT_NEW, "new" },
1450 { RTM_DELLINK, NL_ACT_DEL, "del" },
1451 { RTM_GETLINK, NL_ACT_GET, "get" },
1452 END_OF_MSGTYPES_LIST,
1454 .co_protocol = NETLINK_ROUTE,
1455 .co_groups = link_groups,
1456 .co_request_update = link_request_update,
1457 .co_msg_parser = link_msg_parser,
1458 .co_obj_ops = &link_obj_ops,
1461 static void __init link_init(void)
1463 nl_cache_mngt_register(&rtnl_link_ops);
1466 static void __exit link_exit(void)
1468 nl_cache_mngt_unregister(&rtnl_link_ops);