21 #include <netlink-private/netlink.h>
22 #include <netlink/netlink.h>
23 #include <netlink/attr.h>
24 #include <netlink/utils.h>
25 #include <netlink/object.h>
26 #include <netlink/hashtable.h>
27 #include <netlink/route/rtnl.h>
28 #include <netlink/route/link.h>
29 #include <netlink-private/route/link/api.h>
32 #define LINK_ATTR_MTU (1 << 0)
33 #define LINK_ATTR_LINK (1 << 1)
34 #define LINK_ATTR_TXQLEN (1 << 2)
35 #define LINK_ATTR_WEIGHT (1 << 3)
36 #define LINK_ATTR_MASTER (1 << 4)
37 #define LINK_ATTR_QDISC (1 << 5)
38 #define LINK_ATTR_MAP (1 << 6)
39 #define LINK_ATTR_ADDR (1 << 7)
40 #define LINK_ATTR_BRD (1 << 8)
41 #define LINK_ATTR_FLAGS (1 << 9)
42 #define LINK_ATTR_IFNAME (1 << 10)
43 #define LINK_ATTR_IFINDEX (1 << 11)
44 #define LINK_ATTR_FAMILY (1 << 12)
45 #define LINK_ATTR_ARPTYPE (1 << 13)
46 #define LINK_ATTR_STATS (1 << 14)
47 #define LINK_ATTR_CHANGE (1 << 15)
48 #define LINK_ATTR_OPERSTATE (1 << 16)
49 #define LINK_ATTR_LINKMODE (1 << 17)
50 #define LINK_ATTR_LINKINFO (1 << 18)
51 #define LINK_ATTR_IFALIAS (1 << 19)
52 #define LINK_ATTR_NUM_VF (1 << 20)
53 #define LINK_ATTR_PROMISCUITY (1 << 21)
54 #define LINK_ATTR_NUM_TX_QUEUES (1 << 22)
55 #define LINK_ATTR_NUM_RX_QUEUES (1 << 23)
56 #define LINK_ATTR_GROUP (1 << 24)
57 #define LINK_ATTR_CARRIER (1 << 25)
58 #define LINK_ATTR_PROTINFO (1 << 26)
59 #define LINK_ATTR_AF_SPEC (1 << 27)
61 static struct nl_cache_ops rtnl_link_ops;
62 static struct nl_object_ops link_obj_ops;
65 static struct rtnl_link_af_ops *af_lookup_and_alloc(
struct rtnl_link *link,
68 struct rtnl_link_af_ops *af_ops;
81 static int af_free(
struct rtnl_link *link,
struct rtnl_link_af_ops *ops,
82 void *data,
void *arg)
85 ops->ao_free(link, data);
92 static int af_clone(
struct rtnl_link *link,
struct rtnl_link_af_ops *ops,
93 void *data,
void *arg)
98 !(dst->l_af_data[ops->ao_family] = ops->ao_clone(dst, data)))
104 static int af_fill(
struct rtnl_link *link,
struct rtnl_link_af_ops *ops,
105 void *data,
void *arg)
107 struct nl_msg *msg = arg;
108 struct nlattr *af_attr;
111 if (!ops->ao_fill_af)
117 if ((err = ops->ao_fill_af(link, arg, data)) < 0)
125 static int af_dump_line(
struct rtnl_link *link,
struct rtnl_link_af_ops *ops,
126 void *data,
void *arg)
136 static int af_dump_details(
struct rtnl_link *link,
struct rtnl_link_af_ops *ops,
137 void *data,
void *arg)
147 static int af_dump_stats(
struct rtnl_link *link,
struct rtnl_link_af_ops *ops,
148 void *data,
void *arg)
158 static int do_foreach_af(
struct rtnl_link *link,
160 struct rtnl_link_af_ops *,
void *,
void *),
165 for (i = 0; i < AF_MAX; i++) {
166 if (link->l_af_data[i]) {
167 struct rtnl_link_af_ops *ops;
172 if ((err = cb(link, ops, link->l_af_data[i], arg)) < 0)
180 static void release_link_info(
struct rtnl_link *link)
182 struct rtnl_link_info_ops *io = link->l_info_ops;
188 link->l_info_ops = NULL;
192 static void link_free_data(
struct nl_object *c)
194 struct rtnl_link *link = nl_object_priv(c);
197 struct rtnl_link_info_ops *io;
199 if ((io = link->l_info_ops) != NULL)
200 release_link_info(link);
202 nl_addr_put(link->l_addr);
203 nl_addr_put(link->l_bcast);
205 free(link->l_ifalias);
206 free(link->l_info_kind);
208 do_foreach_af(link, af_free, NULL);
212 static int link_clone(
struct nl_object *_dst,
struct nl_object *_src)
214 struct rtnl_link *dst = nl_object_priv(_dst);
215 struct rtnl_link *src = nl_object_priv(_src);
227 if (!(dst->l_ifalias = strdup(src->l_ifalias)))
230 if (src->l_info_kind)
231 if (!(dst->l_info_kind = strdup(src->l_info_kind)))
234 if (src->l_info_ops && src->l_info_ops->io_clone) {
235 err = src->l_info_ops->io_clone(dst, src);
240 if ((err = do_foreach_af(src, af_clone, dst)) < 0)
246 static struct nla_policy link_policy[IFLA_MAX+1] = {
248 .maxlen = IFNAMSIZ },
249 [IFLA_MTU] = { .type =
NLA_U32 },
250 [IFLA_TXQLEN] = { .type =
NLA_U32 },
251 [IFLA_LINK] = { .type =
NLA_U32 },
252 [IFLA_WEIGHT] = { .type =
NLA_U32 },
253 [IFLA_MASTER] = { .type =
NLA_U32 },
254 [IFLA_OPERSTATE] = { .type =
NLA_U8 },
255 [IFLA_LINKMODE] = { .type =
NLA_U8 },
258 .maxlen = IFQDISCSIZ },
259 [IFLA_STATS] = { .minlen =
sizeof(
struct rtnl_link_stats) },
260 [IFLA_STATS64] = { .minlen =
sizeof(
struct rtnl_link_stats64)},
261 [IFLA_MAP] = { .minlen =
sizeof(
struct rtnl_link_ifmap) },
262 [IFLA_IFALIAS] = { .type =
NLA_STRING, .maxlen = IFALIASZ },
263 [IFLA_NUM_VF] = { .type =
NLA_U32 },
265 [IFLA_PROMISCUITY] = { .type =
NLA_U32 },
266 [IFLA_NUM_TX_QUEUES] = { .type =
NLA_U32 },
267 [IFLA_NUM_RX_QUEUES] = { .type =
NLA_U32 },
268 [IFLA_GROUP] = { .type =
NLA_U32 },
269 [IFLA_CARRIER] = { .type =
NLA_U8 },
272 static struct nla_policy link_info_policy[IFLA_INFO_MAX+1] = {
278 static int link_msg_parser(
struct nl_cache_ops *ops,
struct sockaddr_nl *who,
279 struct nlmsghdr *n,
struct nl_parser_param *pp)
282 struct ifinfomsg *ifi;
283 struct nlattr *tb[IFLA_MAX+1];
284 struct rtnl_link_af_ops *af_ops = NULL;
293 link->ce_msgtype = n->nlmsg_type;
295 if (!nlmsg_valid_hdr(n,
sizeof(*ifi)))
296 return -NLE_MSG_TOOSHORT;
299 link->l_family = family = ifi->ifi_family;
300 link->l_arptype = ifi->ifi_type;
301 link->l_index = ifi->ifi_index;
302 link->l_flags = ifi->ifi_flags;
303 link->l_change = ifi->ifi_change;
304 link->ce_mask = (LINK_ATTR_IFNAME | LINK_ATTR_FAMILY |
305 LINK_ATTR_ARPTYPE| LINK_ATTR_IFINDEX |
306 LINK_ATTR_FLAGS | LINK_ATTR_CHANGE);
308 if ((af_ops = af_lookup_and_alloc(link, family))) {
309 if (af_ops->ao_protinfo_policy) {
310 memcpy(&link_policy[IFLA_PROTINFO],
311 af_ops->ao_protinfo_policy,
316 err =
nlmsg_parse(n,
sizeof(*ifi), tb, IFLA_MAX, link_policy);
320 if (tb[IFLA_IFNAME] == NULL) {
321 err = -NLE_MISSING_ATTR;
325 nla_strlcpy(link->l_name, tb[IFLA_IFNAME], IFNAMSIZ);
328 if (tb[IFLA_STATS]) {
329 struct rtnl_link_stats *st =
nla_data(tb[IFLA_STATS]);
358 link->ce_mask |= LINK_ATTR_STATS;
361 if (tb[IFLA_STATS64]) {
369 struct rtnl_link_stats64 st;
372 sizeof(
struct rtnl_link_stats64));
401 link->ce_mask |= LINK_ATTR_STATS;
404 if (tb[IFLA_TXQLEN]) {
406 link->ce_mask |= LINK_ATTR_TXQLEN;
411 link->ce_mask |= LINK_ATTR_MTU;
414 if (tb[IFLA_ADDRESS]) {
416 if (link->l_addr == NULL) {
420 nl_addr_set_family(link->l_addr,
422 link->ce_mask |= LINK_ATTR_ADDR;
425 if (tb[IFLA_BROADCAST]) {
428 if (link->l_bcast == NULL) {
432 nl_addr_set_family(link->l_bcast,
434 link->ce_mask |= LINK_ATTR_BRD;
439 link->ce_mask |= LINK_ATTR_LINK;
442 if (tb[IFLA_WEIGHT]) {
444 link->ce_mask |= LINK_ATTR_WEIGHT;
447 if (tb[IFLA_QDISC]) {
448 nla_strlcpy(link->l_qdisc, tb[IFLA_QDISC], IFQDISCSIZ);
449 link->ce_mask |= LINK_ATTR_QDISC;
454 sizeof(
struct rtnl_link_ifmap));
455 link->ce_mask |= LINK_ATTR_MAP;
458 if (tb[IFLA_MASTER]) {
460 link->ce_mask |= LINK_ATTR_MASTER;
463 if (tb[IFLA_CARRIER]) {
464 link->l_carrier =
nla_get_u8(tb[IFLA_CARRIER]);
465 link->ce_mask |= LINK_ATTR_CARRIER;
468 if (tb[IFLA_OPERSTATE]) {
469 link->l_operstate =
nla_get_u8(tb[IFLA_OPERSTATE]);
470 link->ce_mask |= LINK_ATTR_OPERSTATE;
473 if (tb[IFLA_LINKMODE]) {
474 link->l_linkmode =
nla_get_u8(tb[IFLA_LINKMODE]);
475 link->ce_mask |= LINK_ATTR_LINKMODE;
478 if (tb[IFLA_IFALIAS]) {
479 link->l_ifalias = nla_strdup(tb[IFLA_IFALIAS]);
480 if (link->l_ifalias == NULL) {
484 link->ce_mask |= LINK_ATTR_IFALIAS;
487 if (tb[IFLA_NUM_VF]) {
489 link->ce_mask |= LINK_ATTR_NUM_VF;
492 if (tb[IFLA_LINKINFO]) {
493 struct nlattr *li[IFLA_INFO_MAX+1];
500 if (li[IFLA_INFO_KIND]) {
501 struct rtnl_link_info_ops *ops;
504 kind = nla_strdup(li[IFLA_INFO_KIND]);
509 link->l_info_kind = kind;
510 link->ce_mask |= LINK_ATTR_LINKINFO;
513 link->l_info_ops = ops;
517 (li[IFLA_INFO_DATA] || li[IFLA_INFO_XSTATS])) {
518 err = ops->io_parse(link, li[IFLA_INFO_DATA],
519 li[IFLA_INFO_XSTATS]);
527 link->ce_mask |= LINK_ATTR_LINKINFO;
530 if (tb[IFLA_PROTINFO] && af_ops && af_ops->ao_parse_protinfo) {
531 err = af_ops->ao_parse_protinfo(link, tb[IFLA_PROTINFO],
532 link->l_af_data[link->l_family]);
535 link->ce_mask |= LINK_ATTR_PROTINFO;
538 if (tb[IFLA_AF_SPEC]) {
539 struct nlattr *af_attr;
543 af_ops = af_lookup_and_alloc(link,
nla_type(af_attr));
544 if (af_ops && af_ops->ao_parse_af) {
545 char *af_data = link->l_af_data[
nla_type(af_attr)];
547 err = af_ops->ao_parse_af(link, af_attr, af_data);
556 link->ce_mask |= LINK_ATTR_AF_SPEC;
559 if (tb[IFLA_PROMISCUITY]) {
560 link->l_promiscuity =
nla_get_u32(tb[IFLA_PROMISCUITY]);
561 link->ce_mask |= LINK_ATTR_PROMISCUITY;
564 if (tb[IFLA_NUM_TX_QUEUES]) {
565 link->l_num_tx_queues =
nla_get_u32(tb[IFLA_NUM_TX_QUEUES]);
566 link->ce_mask |= LINK_ATTR_NUM_TX_QUEUES;
569 if (tb[IFLA_NUM_RX_QUEUES]) {
570 link->l_num_rx_queues =
nla_get_u32(tb[IFLA_NUM_RX_QUEUES]);
571 link->ce_mask |= LINK_ATTR_NUM_RX_QUEUES;
574 if (tb[IFLA_GROUP]) {
576 link->ce_mask |= LINK_ATTR_GROUP;
579 err = pp->pp_cb((
struct nl_object *) link, pp);
586 static int link_request_update(
struct nl_cache *cache,
struct nl_sock *sk)
588 int family = cache->c_iarg1;
593 static void link_dump_line(
struct nl_object *obj,
struct nl_dump_params *p)
596 struct nl_cache *cache = obj->ce_cache;
599 nl_dump_line(p,
"%s %s ", link->l_name,
600 nl_llproto2str(link->l_arptype, buf,
sizeof(buf)));
605 if (link->ce_mask & LINK_ATTR_MASTER) {
607 nl_dump(p,
"master %s ", master ? master->l_name :
"inv");
612 rtnl_link_flags2str(link->l_flags, buf,
sizeof(buf));
616 if (link->ce_mask & LINK_ATTR_LINK) {
618 nl_dump(p,
"slave-of %s ", ll ? ll->l_name :
"NONE");
623 if (link->ce_mask & LINK_ATTR_GROUP)
624 nl_dump(p,
"group %u ", link->l_group);
626 if (link->l_info_ops && link->l_info_ops->io_dump[
NL_DUMP_LINE])
629 do_foreach_af(link, af_dump_line, p);
634 static void link_dump_details(
struct nl_object *obj,
struct nl_dump_params *p)
639 link_dump_line(obj, p);
641 nl_dump_line(p,
" mtu %u ", link->l_mtu);
642 nl_dump(p,
"txqlen %u weight %u ", link->l_txqlen, link->l_weight);
644 if (link->ce_mask & LINK_ATTR_QDISC)
645 nl_dump(p,
"qdisc %s ", link->l_qdisc);
647 if (link->ce_mask & LINK_ATTR_MAP && link->l_map.lm_irq)
648 nl_dump(p,
"irq %u ", link->l_map.lm_irq);
650 if (link->ce_mask & LINK_ATTR_IFINDEX)
651 nl_dump(p,
"index %u ", link->l_index);
653 if (link->ce_mask & LINK_ATTR_PROMISCUITY && link->l_promiscuity > 0)
654 nl_dump(p,
"promisc-mode (%u users) ", link->l_promiscuity);
658 if (link->ce_mask & LINK_ATTR_IFALIAS)
659 nl_dump_line(p,
" alias %s\n", link->l_ifalias);
661 nl_dump_line(p,
" ");
663 if (link->ce_mask & LINK_ATTR_NUM_TX_QUEUES)
664 nl_dump(p,
"txq %u ", link->l_num_tx_queues);
666 if (link->ce_mask & LINK_ATTR_NUM_RX_QUEUES)
667 nl_dump(p,
"rxq %u ", link->l_num_rx_queues);
669 if (link->ce_mask & LINK_ATTR_BRD)
673 if ((link->ce_mask & LINK_ATTR_OPERSTATE) &&
674 link->l_operstate != IF_OPER_UNKNOWN) {
675 rtnl_link_operstate2str(link->l_operstate, buf,
sizeof(buf));
679 if (link->ce_mask & LINK_ATTR_NUM_VF)
680 nl_dump(p,
"num-vf %u ", link->l_num_vf);
683 rtnl_link_mode2str(link->l_linkmode, buf,
sizeof(buf)));
686 rtnl_link_carrier2str(link->l_carrier, buf,
sizeof(buf)));
693 do_foreach_af(link, af_dump_details, p);
696 static void link_dump_stats(
struct nl_object *obj,
struct nl_dump_params *p)
702 link_dump_details(obj, p);
704 nl_dump_line(p,
" Stats: bytes packets errors "
705 " dropped fifo-err compressed\n");
709 strcpy(fmt,
" RX %X.2f %s %10" PRIu64
" %10" PRIu64
" %10" PRIu64
" %10" PRIu64
" %10" PRIu64
"\n");
710 fmt[9] = *unit ==
'B' ?
'9' :
'7';
712 nl_dump_line(p, fmt, res, unit,
721 strcpy(fmt,
" TX %X.2f %s %10" PRIu64
" %10" PRIu64
" %10" PRIu64
" %10" PRIu64
" %10" PRIu64
"\n");
722 fmt[9] = *unit ==
'B' ?
'9' :
'7';
724 nl_dump_line(p, fmt, res, unit,
731 nl_dump_line(p,
" Errors: length over crc "
732 " frame missed multicast\n");
734 nl_dump_line(p,
" RX %10" PRIu64
" %10" PRIu64
" %10"
735 PRIu64
" %10" PRIu64
" %10" PRIu64
" %10"
744 nl_dump_line(p,
" aborted carrier heartbeat "
745 " window collision\n");
747 nl_dump_line(p,
" TX %10" PRIu64
" %10" PRIu64
" %10"
748 PRIu64
" %10" PRIu64
" %10" PRIu64
"\n",
755 if (link->l_info_ops && link->l_info_ops->io_dump[
NL_DUMP_STATS])
758 do_foreach_af(link, af_dump_stats, p);
762 static int link_handle_event(
struct nl_object *a,
struct rtnl_link_event_cb *cb)
765 struct nl_cache *c = dp_cache(a);
768 if (l->l_change == ~0U) {
769 if (l->ce_msgtype == RTM_NEWLINK)
772 cb->le_unregister(l);
777 if (l->l_change & IFF_SLAVE) {
778 if (l->l_flags & IFF_SLAVE) {
780 cb->le_new_bonding(l, m);
784 cb->le_cancel_bonding(l);
788 if (l->l_change & IFF_UP && l->l_change & IFF_RUNNING)
789 dp_dump_line(p, line++,
"link %s changed state to %s.\n",
790 l->l_name, l->l_flags & IFF_UP ?
"up" :
"down");
792 if (l->l_change & IFF_PROMISC) {
793 dp_new_line(p, line++);
794 dp_dump(p,
"link %s %s promiscuous mode.\n",
795 l->l_name, l->l_flags & IFF_PROMISC ?
"entered" :
"left");
799 dp_dump_line(p, line++,
"link %s sent unknown event.\n",
808 static void link_keygen(
struct nl_object *obj, uint32_t *hashkey,
812 unsigned int lkey_sz;
813 struct link_hash_key {
816 } __attribute__((packed)) lkey;
818 lkey_sz = sizeof(lkey);
819 lkey.l_index = link->l_index;
820 lkey.l_family = link->l_family;
822 *hashkey = nl_hash(&lkey, lkey_sz, 0) % table_sz;
824 NL_DBG(5, "link %p key (dev %d fam %d) keysz %d, hash 0x%x\n",
825 link, lkey.l_index, lkey.l_family, lkey_sz, *hashkey);
830 static
int link_compare(struct nl_object *_a, struct nl_object *_b,
831 uint32_t attrs,
int flags)
837 #define LINK_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, LINK_ATTR_##ATTR, a, b, EXPR)
839 diff |= LINK_DIFF(IFINDEX, a->l_index != b->l_index);
840 diff |= LINK_DIFF(MTU, a->l_mtu != b->l_mtu);
841 diff |= LINK_DIFF(LINK, a->l_link != b->l_link);
842 diff |= LINK_DIFF(TXQLEN, a->l_txqlen != b->l_txqlen);
843 diff |= LINK_DIFF(WEIGHT, a->l_weight != b->l_weight);
844 diff |= LINK_DIFF(MASTER, a->l_master != b->l_master);
845 diff |= LINK_DIFF(FAMILY, a->l_family != b->l_family);
846 diff |= LINK_DIFF(OPERSTATE, a->l_operstate != b->l_operstate);
847 diff |= LINK_DIFF(LINKMODE, a->l_linkmode != b->l_linkmode);
848 diff |= LINK_DIFF(QDISC, strcmp(a->l_qdisc, b->l_qdisc));
849 diff |= LINK_DIFF(IFNAME, strcmp(a->l_name, b->l_name));
850 diff |= LINK_DIFF(ADDR,
nl_addr_cmp(a->l_addr, b->l_addr));
851 diff |= LINK_DIFF(BRD,
nl_addr_cmp(a->l_bcast, b->l_bcast));
852 diff |= LINK_DIFF(IFALIAS, strcmp(a->l_ifalias, b->l_ifalias));
853 diff |= LINK_DIFF(NUM_VF, a->l_num_vf != b->l_num_vf);
854 diff |= LINK_DIFF(PROMISCUITY, a->l_promiscuity != b->l_promiscuity);
855 diff |= LINK_DIFF(NUM_TX_QUEUES,a->l_num_tx_queues != b->l_num_tx_queues);
856 diff |= LINK_DIFF(NUM_RX_QUEUES,a->l_num_rx_queues != b->l_num_rx_queues);
857 diff |= LINK_DIFF(GROUP, a->l_group != b->l_group);
862 if (a->l_family == b->l_family) {
864 goto protinfo_mismatch;
867 if (flags & LOOSE_COMPARISON)
868 diff |= LINK_DIFF(FLAGS,
869 (a->l_flags ^ b->l_flags) & b->l_flag_mask);
871 diff |= LINK_DIFF(FLAGS, a->l_flags != b->l_flags);
877 diff |= LINK_DIFF(PROTINFO, 1);
883 static const struct trans_tbl link_attrs[] = {
884 __ADD(LINK_ATTR_MTU, mtu)
885 __ADD(LINK_ATTR_LINK, link)
886 __ADD(LINK_ATTR_TXQLEN, txqlen)
887 __ADD(LINK_ATTR_WEIGHT, weight)
888 __ADD(LINK_ATTR_MASTER, master)
889 __ADD(LINK_ATTR_QDISC, qdisc)
890 __ADD(LINK_ATTR_MAP, map)
891 __ADD(LINK_ATTR_ADDR, address)
892 __ADD(LINK_ATTR_BRD, broadcast)
893 __ADD(LINK_ATTR_FLAGS, flags)
894 __ADD(LINK_ATTR_IFNAME, name)
895 __ADD(LINK_ATTR_IFINDEX, ifindex)
896 __ADD(LINK_ATTR_FAMILY, family)
897 __ADD(LINK_ATTR_ARPTYPE, arptype)
898 __ADD(LINK_ATTR_STATS, stats)
899 __ADD(LINK_ATTR_CHANGE, change)
900 __ADD(LINK_ATTR_OPERSTATE, operstate)
901 __ADD(LINK_ATTR_LINKMODE, linkmode)
902 __ADD(LINK_ATTR_IFALIAS, ifalias)
903 __ADD(LINK_ATTR_NUM_VF, num_vf)
904 __ADD(LINK_ATTR_PROMISCUITY, promiscuity)
905 __ADD(LINK_ATTR_NUM_TX_QUEUES, num_tx_queues)
906 __ADD(LINK_ATTR_NUM_RX_QUEUES, num_rx_queues)
907 __ADD(LINK_ATTR_GROUP, group)
908 __ADD(LINK_ATTR_CARRIER, carrier)
911 static
char *link_attrs2str(
int attrs,
char *buf,
size_t len)
913 return __flags2str(attrs, buf, len, link_attrs,
914 ARRAY_SIZE(link_attrs));
948 struct nl_cache * cache;
955 cache->c_iarg1 = family;
985 if (cache->c_ops != &rtnl_link_ops)
988 nl_list_for_each_entry(link, &cache->c_items, ce_list) {
989 if (link->l_family == AF_UNSPEC && link->l_index == ifindex) {
1018 if (cache->c_ops != &rtnl_link_ops)
1021 nl_list_for_each_entry(link, &cache->c_items, ce_list) {
1022 if (link->l_family == AF_UNSPEC &&
1023 !strcmp(name, link->l_name)) {
1047 struct nl_msg **result)
1049 struct ifinfomsg ifi;
1052 if (ifindex <= 0 && !name) {
1053 APPBUG(
"ifindex or name must be specified");
1054 return -NLE_MISSING_ATTR;
1057 memset(&ifi, 0,
sizeof(ifi));
1063 ifi.ifi_index = ifindex;
1065 if (
nlmsg_append(msg, &ifi,
sizeof(ifi), NLMSG_ALIGNTO) < 0)
1066 goto nla_put_failure;
1076 return -NLE_MSGSIZE;
1098 struct nl_msg *msg = NULL;
1099 struct nl_object *obj;
1110 if ((err =
nl_pickup(sk, link_msg_parser, &obj)) < 0)
1117 if (err == 0 && obj)
1143 strncpy(dst, link->l_name, len - 1);
1167 ifindex = link->l_index;
1176 static int build_link_msg(
int cmd,
struct ifinfomsg *hdr,
1177 struct rtnl_link *link,
int flags,
struct nl_msg **result)
1180 struct nlattr *af_spec;
1186 if (
nlmsg_append(msg, hdr,
sizeof(*hdr), NLMSG_ALIGNTO) < 0)
1187 goto nla_put_failure;
1189 if (link->ce_mask & LINK_ATTR_ADDR)
1192 if (link->ce_mask & LINK_ATTR_BRD)
1195 if (link->ce_mask & LINK_ATTR_MTU)
1198 if (link->ce_mask & LINK_ATTR_TXQLEN)
1201 if (link->ce_mask & LINK_ATTR_WEIGHT)
1204 if (link->ce_mask & LINK_ATTR_IFNAME)
1207 if (link->ce_mask & LINK_ATTR_OPERSTATE)
1208 NLA_PUT_U8(msg, IFLA_OPERSTATE, link->l_operstate);
1210 if (link->ce_mask & LINK_ATTR_CARRIER)
1211 NLA_PUT_U8(msg, IFLA_CARRIER, link->l_carrier);
1213 if (link->ce_mask & LINK_ATTR_LINKMODE)
1214 NLA_PUT_U8(msg, IFLA_LINKMODE, link->l_linkmode);
1216 if (link->ce_mask & LINK_ATTR_IFALIAS)
1219 if (link->ce_mask & LINK_ATTR_LINK)
1222 if (link->ce_mask & LINK_ATTR_MASTER)
1225 if (link->ce_mask & LINK_ATTR_NUM_TX_QUEUES)
1226 NLA_PUT_U32(msg, IFLA_NUM_TX_QUEUES, link->l_num_tx_queues);
1228 if (link->ce_mask & LINK_ATTR_NUM_RX_QUEUES)
1229 NLA_PUT_U32(msg, IFLA_NUM_RX_QUEUES, link->l_num_rx_queues);
1231 if (link->ce_mask & LINK_ATTR_GROUP)
1234 if (link->ce_mask & LINK_ATTR_LINKINFO) {
1235 struct nlattr *info;
1238 goto nla_put_failure;
1242 if (link->l_info_ops) {
1243 if (link->l_info_ops->io_put_attrs &&
1244 link->l_info_ops->io_put_attrs(msg, link) < 0)
1245 goto nla_put_failure;
1252 goto nla_put_failure;
1254 if (do_foreach_af(link, af_fill, msg) < 0)
1255 goto nla_put_failure;
1264 return -NLE_MSGSIZE;
1289 struct nl_msg **result)
1291 struct ifinfomsg ifi = {
1292 .ifi_family = link->l_family,
1293 .ifi_index = link->l_index,
1294 .ifi_flags = link->l_flags,
1297 return build_link_msg(RTM_NEWLINK, &ifi, link, flags, result);
1351 struct nl_msg **result)
1353 struct ifinfomsg ifi = {
1354 .ifi_family = orig->l_family,
1355 .ifi_index = orig->l_index,
1359 if (changes->ce_mask & LINK_ATTR_FLAGS) {
1360 ifi.ifi_flags = orig->l_flags & ~changes->l_flag_mask;
1361 ifi.ifi_flags |= changes->l_flags;
1364 if (changes->l_family && changes->l_family != orig->l_family) {
1365 APPBUG(
"link change: family is immutable");
1366 return -NLE_IMMUTABLE;
1370 if (orig->ce_mask & LINK_ATTR_IFINDEX &&
1371 orig->ce_mask & LINK_ATTR_IFNAME &&
1372 changes->ce_mask & LINK_ATTR_IFNAME &&
1373 !strcmp(orig->l_name, changes->l_name))
1374 changes->ce_mask &= ~LINK_ATTR_IFNAME;
1376 if ((err = build_link_msg(RTM_NEWLINK, &ifi, changes, flags, result)) < 0)
1431 err = wait_for_ack(sk);
1432 if (err == -NLE_OPNOTSUPP && msg->nm_nlh->nlmsg_type == RTM_NEWLINK) {
1433 msg->nm_nlh->nlmsg_type = RTM_SETLINK;
1463 struct nl_msg **result)
1466 struct ifinfomsg ifi = {
1467 .ifi_index = link->l_index,
1470 if (!(link->ce_mask & (LINK_ATTR_IFINDEX | LINK_ATTR_IFNAME))) {
1471 APPBUG(
"ifindex or name must be specified");
1472 return -NLE_MISSING_ATTR;
1478 if (
nlmsg_append(msg, &ifi,
sizeof(ifi), NLMSG_ALIGNTO) < 0)
1479 goto nla_put_failure;
1481 if (link->ce_mask & LINK_ATTR_IFNAME)
1489 return -NLE_MSGSIZE;
1570 strncpy(link->l_name, name,
sizeof(link->l_name) - 1);
1571 link->ce_mask |= LINK_ATTR_IFNAME;
1584 return link->ce_mask & LINK_ATTR_IFNAME ? link->l_name : NULL;
1594 link->l_group = group;
1595 link->ce_mask |= LINK_ATTR_GROUP;
1606 return link->l_group;
1609 static inline void __assign_addr(
struct rtnl_link *link,
struct nl_addr **pos,
1610 struct nl_addr *
new,
int flag)
1618 link->ce_mask |= flag;
1634 __assign_addr(link, &link->l_addr, addr, LINK_ATTR_ADDR);
1648 return link->ce_mask & LINK_ATTR_ADDR ? link->l_addr : NULL;
1665 __assign_addr(link, &link->l_bcast, addr, LINK_ATTR_BRD);
1679 return link->ce_mask & LINK_ATTR_BRD ? link->l_bcast : NULL;
1692 link->l_flag_mask |= flags;
1693 link->l_flags |= flags;
1694 link->ce_mask |= LINK_ATTR_FLAGS;
1707 link->l_flag_mask |= flags;
1708 link->l_flags &= ~flags;
1709 link->ce_mask |= LINK_ATTR_FLAGS;
1723 return link->l_flags;
1733 link->l_family = family;
1734 link->ce_mask |= LINK_ATTR_FAMILY;
1746 return link->ce_mask & LINK_ATTR_FAMILY ? link->l_family : AF_UNSPEC;
1760 link->l_arptype = arptype;
1761 link->ce_mask |= LINK_ATTR_ARPTYPE;
1774 if (link->ce_mask & LINK_ATTR_ARPTYPE)
1775 return link->l_arptype;
1790 link->l_index = ifindex;
1791 link->ce_mask |= LINK_ATTR_IFINDEX;
1805 return link->l_index;
1819 link->ce_mask |= LINK_ATTR_MTU;
1847 link->l_txqlen = txqlen;
1848 link->ce_mask |= LINK_ATTR_TXQLEN;
1863 return link->ce_mask & LINK_ATTR_TXQLEN ? link->l_txqlen : 0;
1866 void rtnl_link_set_link(
struct rtnl_link *link,
int ifindex)
1868 link->l_link = ifindex;
1869 link->ce_mask |= LINK_ATTR_LINK;
1872 int rtnl_link_get_link(
struct rtnl_link *link)
1874 return link->l_link;
1886 link->l_master = ifindex;
1887 link->ce_mask |= LINK_ATTR_MASTER;
1899 return link->l_master;
1911 link->l_carrier = status;
1912 link->ce_mask |= LINK_ATTR_CARRIER;
1924 return link->l_carrier;
1937 link->l_operstate = status;
1938 link->ce_mask |= LINK_ATTR_OPERSTATE;
1951 return link->l_operstate;
1964 link->l_linkmode = mode;
1965 link->ce_mask |= LINK_ATTR_LINKMODE;
1978 return link->l_linkmode;
1991 return link->l_ifalias;
2008 free(link->l_ifalias);
2009 link->ce_mask &= ~LINK_ATTR_IFALIAS;
2012 link->l_ifalias = strdup(alias);
2013 link->ce_mask |= LINK_ATTR_IFALIAS;
2032 strncpy(link->l_qdisc, name,
sizeof(link->l_qdisc) - 1);
2033 link->ce_mask |= LINK_ATTR_QDISC;
2046 return link->ce_mask & LINK_ATTR_QDISC ? link->l_qdisc : NULL;
2059 if (link->ce_mask & LINK_ATTR_NUM_VF) {
2060 *num_vf = link->l_num_vf;
2063 return -NLE_OPNOTSUPP;
2075 if (
id > RTNL_LINK_STATS_MAX)
2078 return link->l_stats[id];
2093 const uint64_t value)
2095 if (
id > RTNL_LINK_STATS_MAX)
2098 link->l_stats[id] = value;
2117 struct rtnl_link_info_ops *io;
2121 free(link->l_info_kind);
2122 link->ce_mask &= ~LINK_ATTR_LINKINFO;
2123 if (link->l_info_ops)
2124 release_link_info(link);
2129 kind = strdup(type);
2135 if (io->io_alloc && (err = io->io_alloc(link)) < 0)
2138 link->l_info_ops = io;
2141 link->l_info_kind = kind;
2142 link->ce_mask |= LINK_ATTR_LINKINFO;
2160 return link->l_info_kind;
2174 link->l_promiscuity = count;
2175 link->ce_mask |= LINK_ATTR_PROMISCUITY;
2187 return link->l_promiscuity;
2206 link->l_num_tx_queues = nqueues;
2207 link->ce_mask |= LINK_ATTR_NUM_TX_QUEUES;
2218 return link->l_num_tx_queues;
2237 link->l_num_rx_queues = nqueues;
2238 link->ce_mask |= LINK_ATTR_NUM_RX_QUEUES;
2249 return link->l_num_rx_queues;
2299 err = -NLE_OPNOTSUPP;
2382 static const struct trans_tbl link_flags[] = {
2383 __ADD(IFF_LOOPBACK, loopback)
2384 __ADD(IFF_BROADCAST, broadcast)
2385 __ADD(IFF_POINTOPOINT, pointopoint)
2386 __ADD(IFF_MULTICAST, multicast)
2387 __ADD(IFF_NOARP, noarp)
2388 __ADD(IFF_ALLMULTI, allmulti)
2389 __ADD(IFF_PROMISC, promisc)
2390 __ADD(IFF_MASTER, master)
2391 __ADD(IFF_SLAVE, slave)
2392 __ADD(IFF_DEBUG, debug)
2393 __ADD(IFF_DYNAMIC, dynamic)
2394 __ADD(IFF_AUTOMEDIA, automedia)
2395 __ADD(IFF_PORTSEL, portsel)
2396 __ADD(IFF_NOTRAILERS, notrailers)
2398 __ADD(IFF_RUNNING, running)
2399 __ADD(IFF_LOWER_UP, lowerup)
2400 __ADD(IFF_DORMANT, dormant)
2401 __ADD(IFF_ECHO, echo)
2404 char *rtnl_link_flags2str(
int flags,
char *buf,
size_t len)
2406 return __flags2str(flags, buf, len, link_flags,
2407 ARRAY_SIZE(link_flags));
2410 int rtnl_link_str2flags(
const char *name)
2412 return __str2flags(name, link_flags, ARRAY_SIZE(link_flags));
2415 static const struct trans_tbl link_stats[] = {
2475 char *rtnl_link_stat2str(
int st,
char *buf,
size_t len)
2477 return __type2str(st, buf, len, link_stats, ARRAY_SIZE(link_stats));
2480 int rtnl_link_str2stat(
const char *name)
2482 return __str2type(name, link_stats, ARRAY_SIZE(link_stats));
2485 static const struct trans_tbl link_operstates[] = {
2486 __ADD(IF_OPER_UNKNOWN, unknown)
2487 __ADD(IF_OPER_NOTPRESENT, notpresent)
2488 __ADD(IF_OPER_DOWN, down)
2489 __ADD(IF_OPER_LOWERLAYERDOWN, lowerlayerdown)
2490 __ADD(IF_OPER_TESTING, testing)
2491 __ADD(IF_OPER_DORMANT, dormant)
2492 __ADD(IF_OPER_UP, up)
2495 char *rtnl_link_operstate2str(uint8_t st,
char *buf,
size_t len)
2497 return __type2str(st, buf, len, link_operstates,
2498 ARRAY_SIZE(link_operstates));
2501 int rtnl_link_str2operstate(
const char *name)
2503 return __str2type(name, link_operstates,
2504 ARRAY_SIZE(link_operstates));
2507 static const struct trans_tbl link_modes[] = {
2508 __ADD(IF_LINK_MODE_DEFAULT,
default)
2509 __ADD(IF_LINK_MODE_DORMANT, dormant)
2512 static const struct trans_tbl carrier_states[] = {
2513 __ADD(IF_CARRIER_DOWN, down)
2514 __ADD(IF_CARRIER_UP, up)
2517 char *rtnl_link_mode2str(uint8_t st,
char *buf,
size_t len)
2519 return __type2str(st, buf, len, link_modes, ARRAY_SIZE(link_modes));
2522 int rtnl_link_str2mode(
const char *name)
2524 return __str2type(name, link_modes, ARRAY_SIZE(link_modes));
2527 char *rtnl_link_carrier2str(uint8_t st,
char *buf,
size_t len)
2529 return __type2str(st, buf, len, carrier_states,
2530 ARRAY_SIZE(carrier_states));
2533 int rtnl_link_str2carrier(
const char *name)
2535 return __str2type(name, carrier_states, ARRAY_SIZE(carrier_states));
2565 link->l_weight = weight;
2566 link->ce_mask |= LINK_ATTR_WEIGHT;
2574 return link->l_weight;
2579 static struct nl_object_ops link_obj_ops = {
2580 .oo_name =
"route/link",
2582 .oo_free_data = link_free_data,
2583 .oo_clone = link_clone,
2589 .oo_compare = link_compare,
2590 .oo_keygen = link_keygen,
2591 .oo_attrs2str = link_attrs2str,
2592 .oo_id_attrs = LINK_ATTR_IFINDEX | LINK_ATTR_FAMILY,
2595 static struct nl_af_group link_groups[] = {
2596 { AF_UNSPEC, RTNLGRP_LINK },
2597 { AF_BRIDGE, RTNLGRP_LINK },
2598 { END_OF_GROUP_LIST },
2601 static struct nl_cache_ops rtnl_link_ops = {
2602 .co_name =
"route/link",
2603 .co_hdrsize =
sizeof(
struct ifinfomsg),
2605 { RTM_NEWLINK, NL_ACT_NEW,
"new" },
2606 { RTM_DELLINK, NL_ACT_DEL,
"del" },
2607 { RTM_GETLINK, NL_ACT_GET,
"get" },
2608 { RTM_SETLINK, NL_ACT_CHANGE,
"set" },
2609 END_OF_MSGTYPES_LIST,
2611 .co_protocol = NETLINK_ROUTE,
2612 .co_groups = link_groups,
2613 .co_request_update = link_request_update,
2614 .co_msg_parser = link_msg_parser,
2615 .co_obj_ops = &link_obj_ops,
2618 static void __init link_init(
void)
2623 static void __exit link_exit(
void)