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;
83 static int af_free(
struct rtnl_link *link,
struct rtnl_link_af_ops *ops,
84 void *data,
void *arg)
87 ops->ao_free(link, data);
94 static int af_clone(
struct rtnl_link *link,
struct rtnl_link_af_ops *ops,
95 void *data,
void *arg)
100 !(dst->l_af_data[ops->ao_family] = ops->ao_clone(dst, data)))
106 static int af_fill(
struct rtnl_link *link,
struct rtnl_link_af_ops *ops,
107 void *data,
void *arg)
109 struct nl_msg *msg = arg;
110 struct nlattr *af_attr;
113 if (!ops->ao_fill_af)
119 if ((err = ops->ao_fill_af(link, arg, data)) < 0)
127 static int af_dump_line(
struct rtnl_link *link,
struct rtnl_link_af_ops *ops,
128 void *data,
void *arg)
138 static int af_dump_details(
struct rtnl_link *link,
struct rtnl_link_af_ops *ops,
139 void *data,
void *arg)
149 static int af_dump_stats(
struct rtnl_link *link,
struct rtnl_link_af_ops *ops,
150 void *data,
void *arg)
160 static int do_foreach_af(
struct rtnl_link *link,
162 struct rtnl_link_af_ops *,
void *,
void *),
167 for (i = 0; i < AF_MAX; i++) {
168 if (link->l_af_data[i]) {
169 struct rtnl_link_af_ops *ops;
174 err = cb(link, ops, link->l_af_data[i], arg);
186 static void release_link_info(
struct rtnl_link *link)
188 struct rtnl_link_info_ops *io = link->l_info_ops;
194 link->l_info_ops = NULL;
198 static void link_free_data(
struct nl_object *c)
200 struct rtnl_link *link = nl_object_priv(c);
203 struct rtnl_link_info_ops *io;
205 if ((io = link->l_info_ops) != NULL)
206 release_link_info(link);
214 free(link->l_ifalias);
215 free(link->l_info_kind);
217 do_foreach_af(link, af_free, NULL);
221 static int link_clone(
struct nl_object *_dst,
struct nl_object *_src)
223 struct rtnl_link *dst = nl_object_priv(_dst);
224 struct rtnl_link *src = nl_object_priv(_src);
236 if (!(dst->l_ifalias = strdup(src->l_ifalias)))
239 if (src->l_info_kind)
240 if (!(dst->l_info_kind = strdup(src->l_info_kind)))
243 if (src->l_info_ops && src->l_info_ops->io_clone) {
244 err = src->l_info_ops->io_clone(dst, src);
249 if ((err = do_foreach_af(src, af_clone, dst)) < 0)
255 static struct nla_policy link_policy[IFLA_MAX+1] = {
257 .maxlen = IFNAMSIZ },
258 [IFLA_MTU] = { .type =
NLA_U32 },
259 [IFLA_TXQLEN] = { .type =
NLA_U32 },
260 [IFLA_LINK] = { .type =
NLA_U32 },
261 [IFLA_WEIGHT] = { .type =
NLA_U32 },
262 [IFLA_MASTER] = { .type =
NLA_U32 },
263 [IFLA_OPERSTATE] = { .type =
NLA_U8 },
264 [IFLA_LINKMODE] = { .type =
NLA_U8 },
267 .maxlen = IFQDISCSIZ },
268 [IFLA_STATS] = { .minlen =
sizeof(
struct rtnl_link_stats) },
269 [IFLA_STATS64] = { .minlen =
sizeof(
struct rtnl_link_stats64)},
270 [IFLA_MAP] = { .minlen =
sizeof(
struct rtnl_link_ifmap) },
271 [IFLA_IFALIAS] = { .type =
NLA_STRING, .maxlen = IFALIASZ },
272 [IFLA_NUM_VF] = { .type =
NLA_U32 },
274 [IFLA_PROMISCUITY] = { .type =
NLA_U32 },
275 [IFLA_NUM_TX_QUEUES] = { .type =
NLA_U32 },
276 [IFLA_NUM_RX_QUEUES] = { .type =
NLA_U32 },
277 [IFLA_GROUP] = { .type =
NLA_U32 },
278 [IFLA_CARRIER] = { .type =
NLA_U8 },
281 static struct nla_policy link_info_policy[IFLA_INFO_MAX+1] = {
287 static int link_msg_parser(
struct nl_cache_ops *ops,
struct sockaddr_nl *who,
288 struct nlmsghdr *n,
struct nl_parser_param *pp)
291 struct ifinfomsg *ifi;
292 struct nlattr *tb[IFLA_MAX+1];
293 struct rtnl_link_af_ops *af_ops = NULL;
295 struct nla_policy real_link_policy[IFLA_MAX+1];
297 memcpy(&real_link_policy, link_policy,
sizeof(link_policy));
305 link->ce_msgtype = n->nlmsg_type;
307 if (!nlmsg_valid_hdr(n,
sizeof(*ifi)))
308 return -NLE_MSG_TOOSHORT;
311 link->l_family = family = ifi->ifi_family;
312 link->l_arptype = ifi->ifi_type;
313 link->l_index = ifi->ifi_index;
314 link->l_flags = ifi->ifi_flags;
315 link->l_change = ifi->ifi_change;
316 link->ce_mask = (LINK_ATTR_IFNAME | LINK_ATTR_FAMILY |
317 LINK_ATTR_ARPTYPE| LINK_ATTR_IFINDEX |
318 LINK_ATTR_FLAGS | LINK_ATTR_CHANGE);
320 if ((af_ops = af_lookup_and_alloc(link, family))) {
321 if (af_ops->ao_protinfo_policy) {
322 memcpy(&real_link_policy[IFLA_PROTINFO],
323 af_ops->ao_protinfo_policy,
327 link->l_af_ops = af_ops;
330 err =
nlmsg_parse(n,
sizeof(*ifi), tb, IFLA_MAX, real_link_policy);
334 if (tb[IFLA_IFNAME] == NULL) {
335 err = -NLE_MISSING_ATTR;
339 nla_strlcpy(link->l_name, tb[IFLA_IFNAME], IFNAMSIZ);
342 if (tb[IFLA_STATS]) {
343 struct rtnl_link_stats *st =
nla_data(tb[IFLA_STATS]);
372 link->ce_mask |= LINK_ATTR_STATS;
375 if (tb[IFLA_STATS64]) {
383 struct rtnl_link_stats64 st;
386 sizeof(
struct rtnl_link_stats64));
415 link->ce_mask |= LINK_ATTR_STATS;
418 if (tb[IFLA_TXQLEN]) {
420 link->ce_mask |= LINK_ATTR_TXQLEN;
425 link->ce_mask |= LINK_ATTR_MTU;
428 if (tb[IFLA_ADDRESS]) {
430 if (link->l_addr == NULL) {
436 link->ce_mask |= LINK_ATTR_ADDR;
439 if (tb[IFLA_BROADCAST]) {
442 if (link->l_bcast == NULL) {
448 link->ce_mask |= LINK_ATTR_BRD;
453 link->ce_mask |= LINK_ATTR_LINK;
456 if (tb[IFLA_WEIGHT]) {
458 link->ce_mask |= LINK_ATTR_WEIGHT;
461 if (tb[IFLA_QDISC]) {
462 nla_strlcpy(link->l_qdisc, tb[IFLA_QDISC], IFQDISCSIZ);
463 link->ce_mask |= LINK_ATTR_QDISC;
468 sizeof(
struct rtnl_link_ifmap));
469 link->ce_mask |= LINK_ATTR_MAP;
472 if (tb[IFLA_MASTER]) {
474 link->ce_mask |= LINK_ATTR_MASTER;
477 if (tb[IFLA_CARRIER]) {
478 link->l_carrier =
nla_get_u8(tb[IFLA_CARRIER]);
479 link->ce_mask |= LINK_ATTR_CARRIER;
482 if (tb[IFLA_OPERSTATE]) {
483 link->l_operstate =
nla_get_u8(tb[IFLA_OPERSTATE]);
484 link->ce_mask |= LINK_ATTR_OPERSTATE;
487 if (tb[IFLA_LINKMODE]) {
488 link->l_linkmode =
nla_get_u8(tb[IFLA_LINKMODE]);
489 link->ce_mask |= LINK_ATTR_LINKMODE;
492 if (tb[IFLA_IFALIAS]) {
493 link->l_ifalias = nla_strdup(tb[IFLA_IFALIAS]);
494 if (link->l_ifalias == NULL) {
498 link->ce_mask |= LINK_ATTR_IFALIAS;
501 if (tb[IFLA_NUM_VF]) {
503 link->ce_mask |= LINK_ATTR_NUM_VF;
506 if (tb[IFLA_LINKINFO]) {
507 struct nlattr *li[IFLA_INFO_MAX+1];
514 if (li[IFLA_INFO_KIND]) {
515 struct rtnl_link_info_ops *ops;
518 kind = nla_strdup(li[IFLA_INFO_KIND]);
523 link->l_info_kind = kind;
524 link->ce_mask |= LINK_ATTR_LINKINFO;
527 link->l_info_ops = ops;
531 (li[IFLA_INFO_DATA] || li[IFLA_INFO_XSTATS])) {
532 err = ops->io_parse(link, li[IFLA_INFO_DATA],
533 li[IFLA_INFO_XSTATS]);
541 link->ce_mask |= LINK_ATTR_LINKINFO;
544 if (tb[IFLA_PROTINFO] && af_ops && af_ops->ao_parse_protinfo) {
545 err = af_ops->ao_parse_protinfo(link, tb[IFLA_PROTINFO],
546 link->l_af_data[link->l_family]);
549 link->ce_mask |= LINK_ATTR_PROTINFO;
552 if (tb[IFLA_AF_SPEC]) {
553 struct nlattr *af_attr;
557 af_ops = af_lookup_and_alloc(link,
nla_type(af_attr));
558 if (af_ops && af_ops->ao_parse_af) {
559 char *af_data = link->l_af_data[
nla_type(af_attr)];
561 err = af_ops->ao_parse_af(link, af_attr, af_data);
567 link->ce_mask |= LINK_ATTR_AF_SPEC;
570 if (tb[IFLA_PROMISCUITY]) {
571 link->l_promiscuity =
nla_get_u32(tb[IFLA_PROMISCUITY]);
572 link->ce_mask |= LINK_ATTR_PROMISCUITY;
575 if (tb[IFLA_NUM_TX_QUEUES]) {
576 link->l_num_tx_queues =
nla_get_u32(tb[IFLA_NUM_TX_QUEUES]);
577 link->ce_mask |= LINK_ATTR_NUM_TX_QUEUES;
580 if (tb[IFLA_NUM_RX_QUEUES]) {
581 link->l_num_rx_queues =
nla_get_u32(tb[IFLA_NUM_RX_QUEUES]);
582 link->ce_mask |= LINK_ATTR_NUM_RX_QUEUES;
585 if (tb[IFLA_GROUP]) {
587 link->ce_mask |= LINK_ATTR_GROUP;
590 err = pp->pp_cb((
struct nl_object *) link, pp);
597 static int link_request_update(
struct nl_cache *cache,
struct nl_sock *sk)
599 int family = cache->c_iarg1;
604 static void link_dump_line(
struct nl_object *obj,
struct nl_dump_params *p)
607 struct nl_cache *cache = obj->ce_cache;
610 nl_dump_line(p,
"%s %s ", link->l_name,
611 nl_llproto2str(link->l_arptype, buf,
sizeof(buf)));
616 if (link->ce_mask & LINK_ATTR_MASTER) {
618 nl_dump(p,
"master %s ", master ? master->l_name :
"inv");
623 rtnl_link_flags2str(link->l_flags, buf,
sizeof(buf));
627 if (link->ce_mask & LINK_ATTR_LINK) {
629 nl_dump(p,
"slave-of %s ", ll ? ll->l_name :
"NONE");
634 if (link->ce_mask & LINK_ATTR_GROUP)
635 nl_dump(p,
"group %u ", link->l_group);
637 if (link->l_info_ops && link->l_info_ops->io_dump[
NL_DUMP_LINE])
640 do_foreach_af(link, af_dump_line, p);
645 static void link_dump_details(
struct nl_object *obj,
struct nl_dump_params *p)
650 link_dump_line(obj, p);
652 nl_dump_line(p,
" mtu %u ", link->l_mtu);
653 nl_dump(p,
"txqlen %u weight %u ", link->l_txqlen, link->l_weight);
655 if (link->ce_mask & LINK_ATTR_QDISC)
656 nl_dump(p,
"qdisc %s ", link->l_qdisc);
658 if (link->ce_mask & LINK_ATTR_MAP && link->l_map.lm_irq)
659 nl_dump(p,
"irq %u ", link->l_map.lm_irq);
661 if (link->ce_mask & LINK_ATTR_IFINDEX)
662 nl_dump(p,
"index %u ", link->l_index);
664 if (link->ce_mask & LINK_ATTR_PROMISCUITY && link->l_promiscuity > 0)
665 nl_dump(p,
"promisc-mode (%u users) ", link->l_promiscuity);
669 if (link->ce_mask & LINK_ATTR_IFALIAS)
670 nl_dump_line(p,
" alias %s\n", link->l_ifalias);
672 nl_dump_line(p,
" ");
674 if (link->ce_mask & LINK_ATTR_NUM_TX_QUEUES)
675 nl_dump(p,
"txq %u ", link->l_num_tx_queues);
677 if (link->ce_mask & LINK_ATTR_NUM_RX_QUEUES)
678 nl_dump(p,
"rxq %u ", link->l_num_rx_queues);
680 if (link->ce_mask & LINK_ATTR_BRD)
684 if ((link->ce_mask & LINK_ATTR_OPERSTATE) &&
685 link->l_operstate != IF_OPER_UNKNOWN) {
686 rtnl_link_operstate2str(link->l_operstate, buf,
sizeof(buf));
690 if (link->ce_mask & LINK_ATTR_NUM_VF)
691 nl_dump(p,
"num-vf %u ", link->l_num_vf);
694 rtnl_link_mode2str(link->l_linkmode, buf,
sizeof(buf)));
697 rtnl_link_carrier2str(link->l_carrier, buf,
sizeof(buf)));
704 do_foreach_af(link, af_dump_details, p);
707 static void link_dump_stats(
struct nl_object *obj,
struct nl_dump_params *p)
713 link_dump_details(obj, p);
715 nl_dump_line(p,
" Stats: bytes packets errors "
716 " dropped fifo-err compressed\n");
720 strcpy(fmt,
" RX %X.2f %s %10" PRIu64
" %10" PRIu64
" %10" PRIu64
" %10" PRIu64
" %10" PRIu64
"\n");
721 fmt[9] = *unit ==
'B' ?
'9' :
'7';
723 nl_dump_line(p, fmt, res, unit,
732 strcpy(fmt,
" TX %X.2f %s %10" PRIu64
" %10" PRIu64
" %10" PRIu64
" %10" PRIu64
" %10" PRIu64
"\n");
733 fmt[9] = *unit ==
'B' ?
'9' :
'7';
735 nl_dump_line(p, fmt, res, unit,
742 nl_dump_line(p,
" Errors: length over crc "
743 " frame missed multicast\n");
745 nl_dump_line(p,
" RX %10" PRIu64
" %10" PRIu64
" %10"
746 PRIu64
" %10" PRIu64
" %10" PRIu64
" %10"
755 nl_dump_line(p,
" aborted carrier heartbeat "
756 " window collision\n");
758 nl_dump_line(p,
" TX %10" PRIu64
" %10" PRIu64
" %10"
759 PRIu64
" %10" PRIu64
" %10" PRIu64
"\n",
766 if (link->l_info_ops && link->l_info_ops->io_dump[
NL_DUMP_STATS])
769 do_foreach_af(link, af_dump_stats, p);
773 static int link_handle_event(
struct nl_object *a,
struct rtnl_link_event_cb *cb)
776 struct nl_cache *c = dp_cache(a);
779 if (l->l_change == ~0U) {
780 if (l->ce_msgtype == RTM_NEWLINK)
783 cb->le_unregister(l);
788 if (l->l_change & IFF_SLAVE) {
789 if (l->l_flags & IFF_SLAVE) {
791 cb->le_new_bonding(l, m);
795 cb->le_cancel_bonding(l);
799 if (l->l_change & IFF_UP && l->l_change & IFF_RUNNING)
800 dp_dump_line(p, line++,
"link %s changed state to %s.\n",
801 l->l_name, l->l_flags & IFF_UP ?
"up" :
"down");
803 if (l->l_change & IFF_PROMISC) {
804 dp_new_line(p, line++);
805 dp_dump(p,
"link %s %s promiscuous mode.\n",
806 l->l_name, l->l_flags & IFF_PROMISC ?
"entered" :
"left");
810 dp_dump_line(p, line++,
"link %s sent unknown event.\n",
819 static void link_keygen(
struct nl_object *obj, uint32_t *hashkey,
823 unsigned int lkey_sz;
824 struct link_hash_key {
827 } __attribute__((packed)) lkey;
829 lkey_sz = sizeof(lkey);
830 lkey.l_index = link->l_index;
831 lkey.l_family = link->l_family;
833 *hashkey = nl_hash(&lkey, lkey_sz, 0) % table_sz;
835 NL_DBG(5, "link %p key (dev %d fam %d) keysz %d, hash 0x%x\n",
836 link, lkey.l_index, lkey.l_family, lkey_sz, *hashkey);
841 static
int link_compare(struct nl_object *_a, struct nl_object *_b,
842 uint32_t attrs,
int flags)
848 #define LINK_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, LINK_ATTR_##ATTR, a, b, EXPR)
850 diff |= LINK_DIFF(IFINDEX, a->l_index != b->l_index);
851 diff |= LINK_DIFF(MTU, a->l_mtu != b->l_mtu);
852 diff |= LINK_DIFF(LINK, a->l_link != b->l_link);
853 diff |= LINK_DIFF(TXQLEN, a->l_txqlen != b->l_txqlen);
854 diff |= LINK_DIFF(WEIGHT, a->l_weight != b->l_weight);
855 diff |= LINK_DIFF(MASTER, a->l_master != b->l_master);
856 diff |= LINK_DIFF(FAMILY, a->l_family != b->l_family);
857 diff |= LINK_DIFF(OPERSTATE, a->l_operstate != b->l_operstate);
858 diff |= LINK_DIFF(LINKMODE, a->l_linkmode != b->l_linkmode);
859 diff |= LINK_DIFF(QDISC, strcmp(a->l_qdisc, b->l_qdisc));
860 diff |= LINK_DIFF(IFNAME, strcmp(a->l_name, b->l_name));
861 diff |= LINK_DIFF(ADDR,
nl_addr_cmp(a->l_addr, b->l_addr));
862 diff |= LINK_DIFF(BRD,
nl_addr_cmp(a->l_bcast, b->l_bcast));
863 diff |= LINK_DIFF(IFALIAS, strcmp(a->l_ifalias, b->l_ifalias));
864 diff |= LINK_DIFF(NUM_VF, a->l_num_vf != b->l_num_vf);
865 diff |= LINK_DIFF(PROMISCUITY, a->l_promiscuity != b->l_promiscuity);
866 diff |= LINK_DIFF(NUM_TX_QUEUES,a->l_num_tx_queues != b->l_num_tx_queues);
867 diff |= LINK_DIFF(NUM_RX_QUEUES,a->l_num_rx_queues != b->l_num_rx_queues);
868 diff |= LINK_DIFF(GROUP, a->l_group != b->l_group);
870 if (flags & LOOSE_COMPARISON)
871 diff |= LINK_DIFF(FLAGS,
872 (a->l_flags ^ b->l_flags) & b->l_flag_mask);
874 diff |= LINK_DIFF(FLAGS, a->l_flags != b->l_flags);
879 if (a->l_family == b->l_family) {
881 goto protinfo_mismatch;
888 diff |= LINK_DIFF(PROTINFO, 1);
894 static const struct trans_tbl link_attrs[] = {
895 __ADD(LINK_ATTR_MTU, mtu)
896 __ADD(LINK_ATTR_LINK, link)
897 __ADD(LINK_ATTR_TXQLEN, txqlen)
898 __ADD(LINK_ATTR_WEIGHT, weight)
899 __ADD(LINK_ATTR_MASTER, master)
900 __ADD(LINK_ATTR_QDISC, qdisc)
901 __ADD(LINK_ATTR_MAP, map)
902 __ADD(LINK_ATTR_ADDR, address)
903 __ADD(LINK_ATTR_BRD, broadcast)
904 __ADD(LINK_ATTR_FLAGS, flags)
905 __ADD(LINK_ATTR_IFNAME, name)
906 __ADD(LINK_ATTR_IFINDEX, ifindex)
907 __ADD(LINK_ATTR_FAMILY, family)
908 __ADD(LINK_ATTR_ARPTYPE, arptype)
909 __ADD(LINK_ATTR_STATS, stats)
910 __ADD(LINK_ATTR_CHANGE, change)
911 __ADD(LINK_ATTR_OPERSTATE, operstate)
912 __ADD(LINK_ATTR_LINKMODE, linkmode)
913 __ADD(LINK_ATTR_IFALIAS, ifalias)
914 __ADD(LINK_ATTR_NUM_VF, num_vf)
915 __ADD(LINK_ATTR_PROMISCUITY, promiscuity)
916 __ADD(LINK_ATTR_NUM_TX_QUEUES, num_tx_queues)
917 __ADD(LINK_ATTR_NUM_RX_QUEUES, num_rx_queues)
918 __ADD(LINK_ATTR_GROUP, group)
919 __ADD(LINK_ATTR_CARRIER, carrier)
922 static
char *link_attrs2str(
int attrs,
char *buf,
size_t len)
924 return __flags2str(attrs, buf, len, link_attrs,
925 ARRAY_SIZE(link_attrs));
959 struct nl_cache * cache;
966 cache->c_iarg1 = family;
996 if (cache->c_ops != &rtnl_link_ops)
999 nl_list_for_each_entry(link, &cache->c_items, ce_list) {
1000 if (link->l_index == ifindex) {
1029 if (cache->c_ops != &rtnl_link_ops)
1032 nl_list_for_each_entry(link, &cache->c_items, ce_list) {
1033 if (!strcmp(name, link->l_name)) {
1057 struct nl_msg **result)
1059 struct ifinfomsg ifi;
1062 if (ifindex <= 0 && !name) {
1063 APPBUG(
"ifindex or name must be specified");
1064 return -NLE_MISSING_ATTR;
1067 memset(&ifi, 0,
sizeof(ifi));
1073 ifi.ifi_index = ifindex;
1075 if (
nlmsg_append(msg, &ifi,
sizeof(ifi), NLMSG_ALIGNTO) < 0)
1076 goto nla_put_failure;
1086 return -NLE_MSGSIZE;
1108 struct nl_msg *msg = NULL;
1109 struct nl_object *obj;
1120 if ((err =
nl_pickup(sk, link_msg_parser, &obj)) < 0)
1127 if (err == 0 && obj)
1153 strncpy(dst, link->l_name, len - 1);
1177 ifindex = link->l_index;
1186 static int build_link_msg(
int cmd,
struct ifinfomsg *hdr,
1187 struct rtnl_link *link,
int flags,
struct nl_msg **result)
1190 struct nlattr *af_spec;
1196 if (
nlmsg_append(msg, hdr,
sizeof(*hdr), NLMSG_ALIGNTO) < 0)
1197 goto nla_put_failure;
1199 if (link->ce_mask & LINK_ATTR_ADDR)
1202 if (link->ce_mask & LINK_ATTR_BRD)
1205 if (link->ce_mask & LINK_ATTR_MTU)
1208 if (link->ce_mask & LINK_ATTR_TXQLEN)
1211 if (link->ce_mask & LINK_ATTR_WEIGHT)
1214 if (link->ce_mask & LINK_ATTR_IFNAME)
1217 if (link->ce_mask & LINK_ATTR_OPERSTATE)
1218 NLA_PUT_U8(msg, IFLA_OPERSTATE, link->l_operstate);
1220 if (link->ce_mask & LINK_ATTR_CARRIER)
1221 NLA_PUT_U8(msg, IFLA_CARRIER, link->l_carrier);
1223 if (link->ce_mask & LINK_ATTR_LINKMODE)
1224 NLA_PUT_U8(msg, IFLA_LINKMODE, link->l_linkmode);
1226 if (link->ce_mask & LINK_ATTR_IFALIAS)
1229 if (link->ce_mask & LINK_ATTR_LINK)
1232 if (link->ce_mask & LINK_ATTR_MASTER)
1235 if (link->ce_mask & LINK_ATTR_NUM_TX_QUEUES)
1236 NLA_PUT_U32(msg, IFLA_NUM_TX_QUEUES, link->l_num_tx_queues);
1238 if (link->ce_mask & LINK_ATTR_NUM_RX_QUEUES)
1239 NLA_PUT_U32(msg, IFLA_NUM_RX_QUEUES, link->l_num_rx_queues);
1241 if (link->ce_mask & LINK_ATTR_GROUP)
1244 if (link->ce_mask & LINK_ATTR_LINKINFO) {
1245 struct nlattr *info;
1248 goto nla_put_failure;
1252 if (link->l_info_ops) {
1253 if (link->l_info_ops->io_put_attrs &&
1254 link->l_info_ops->io_put_attrs(msg, link) < 0)
1255 goto nla_put_failure;
1262 goto nla_put_failure;
1264 if (do_foreach_af(link, af_fill, msg) < 0)
1265 goto nla_put_failure;
1274 return -NLE_MSGSIZE;
1299 struct nl_msg **result)
1301 struct ifinfomsg ifi = {
1302 .ifi_family = link->l_family,
1303 .ifi_index = link->l_index,
1304 .ifi_flags = link->l_flags,
1307 return build_link_msg(RTM_NEWLINK, &ifi, link, flags, result);
1361 struct nl_msg **result)
1363 struct ifinfomsg ifi = {
1364 .ifi_family = orig->l_family,
1365 .ifi_index = orig->l_index,
1369 if (changes->ce_mask & LINK_ATTR_FLAGS) {
1370 ifi.ifi_flags = orig->l_flags & ~changes->l_flag_mask;
1371 ifi.ifi_flags |= changes->l_flags;
1374 if (changes->l_family && changes->l_family != orig->l_family) {
1375 APPBUG(
"link change: family is immutable");
1376 return -NLE_IMMUTABLE;
1380 if (orig->ce_mask & LINK_ATTR_IFINDEX &&
1381 orig->ce_mask & LINK_ATTR_IFNAME &&
1382 changes->ce_mask & LINK_ATTR_IFNAME &&
1383 !strcmp(orig->l_name, changes->l_name))
1384 changes->ce_mask &= ~LINK_ATTR_IFNAME;
1386 if ((err = build_link_msg(RTM_NEWLINK, &ifi, changes, flags, result)) < 0)
1441 err = wait_for_ack(sk);
1442 if (err == -NLE_OPNOTSUPP && msg->nm_nlh->nlmsg_type == RTM_NEWLINK) {
1443 msg->nm_nlh->nlmsg_type = RTM_SETLINK;
1473 struct nl_msg **result)
1476 struct ifinfomsg ifi = {
1477 .ifi_index = link->l_index,
1480 if (!(link->ce_mask & (LINK_ATTR_IFINDEX | LINK_ATTR_IFNAME))) {
1481 APPBUG(
"ifindex or name must be specified");
1482 return -NLE_MISSING_ATTR;
1488 if (
nlmsg_append(msg, &ifi,
sizeof(ifi), NLMSG_ALIGNTO) < 0)
1489 goto nla_put_failure;
1491 if (link->ce_mask & LINK_ATTR_IFNAME)
1499 return -NLE_MSGSIZE;
1580 strncpy(link->l_name, name,
sizeof(link->l_name) - 1);
1581 link->ce_mask |= LINK_ATTR_IFNAME;
1594 return link->ce_mask & LINK_ATTR_IFNAME ? link->l_name : NULL;
1604 link->l_group = group;
1605 link->ce_mask |= LINK_ATTR_GROUP;
1616 return link->l_group;
1619 static inline void __assign_addr(
struct rtnl_link *link,
struct nl_addr **pos,
1620 struct nl_addr *
new,
int flag)
1628 link->ce_mask |= flag;
1644 __assign_addr(link, &link->l_addr, addr, LINK_ATTR_ADDR);
1658 return link->ce_mask & LINK_ATTR_ADDR ? link->l_addr : NULL;
1675 __assign_addr(link, &link->l_bcast, addr, LINK_ATTR_BRD);
1689 return link->ce_mask & LINK_ATTR_BRD ? link->l_bcast : NULL;
1702 link->l_flag_mask |= flags;
1703 link->l_flags |= flags;
1704 link->ce_mask |= LINK_ATTR_FLAGS;
1717 link->l_flag_mask |= flags;
1718 link->l_flags &= ~flags;
1719 link->ce_mask |= LINK_ATTR_FLAGS;
1733 return link->l_flags;
1743 link->l_family = family;
1744 link->ce_mask |= LINK_ATTR_FAMILY;
1747 af_free(link, link->l_af_ops,
1748 link->l_af_data[link->l_af_ops->ao_family], NULL);
1750 link->l_af_ops = af_lookup_and_alloc(link, family);
1762 return link->ce_mask & LINK_ATTR_FAMILY ? link->l_family : AF_UNSPEC;
1776 link->l_arptype = arptype;
1777 link->ce_mask |= LINK_ATTR_ARPTYPE;
1790 if (link->ce_mask & LINK_ATTR_ARPTYPE)
1791 return link->l_arptype;
1806 link->l_index = ifindex;
1807 link->ce_mask |= LINK_ATTR_IFINDEX;
1821 return link->l_index;
1835 link->ce_mask |= LINK_ATTR_MTU;
1863 link->l_txqlen = txqlen;
1864 link->ce_mask |= LINK_ATTR_TXQLEN;
1879 return link->ce_mask & LINK_ATTR_TXQLEN ? link->l_txqlen : 0;
1882 void rtnl_link_set_link(
struct rtnl_link *link,
int ifindex)
1884 link->l_link = ifindex;
1885 link->ce_mask |= LINK_ATTR_LINK;
1888 int rtnl_link_get_link(
struct rtnl_link *link)
1890 return link->l_link;
1902 link->l_master = ifindex;
1903 link->ce_mask |= LINK_ATTR_MASTER;
1915 return link->l_master;
1927 link->l_carrier = status;
1928 link->ce_mask |= LINK_ATTR_CARRIER;
1940 return link->l_carrier;
1953 link->l_operstate = status;
1954 link->ce_mask |= LINK_ATTR_OPERSTATE;
1967 return link->l_operstate;
1980 link->l_linkmode = mode;
1981 link->ce_mask |= LINK_ATTR_LINKMODE;
1994 return link->l_linkmode;
2007 return link->l_ifalias;
2024 free(link->l_ifalias);
2025 link->ce_mask &= ~LINK_ATTR_IFALIAS;
2028 link->l_ifalias = strdup(alias);
2029 link->ce_mask |= LINK_ATTR_IFALIAS;
2048 strncpy(link->l_qdisc, name,
sizeof(link->l_qdisc) - 1);
2049 link->ce_mask |= LINK_ATTR_QDISC;
2062 return link->ce_mask & LINK_ATTR_QDISC ? link->l_qdisc : NULL;
2075 if (link->ce_mask & LINK_ATTR_NUM_VF) {
2076 *num_vf = link->l_num_vf;
2079 return -NLE_OPNOTSUPP;
2091 if (
id > RTNL_LINK_STATS_MAX)
2094 return link->l_stats[id];
2109 const uint64_t value)
2111 if (
id > RTNL_LINK_STATS_MAX)
2114 link->l_stats[id] = value;
2133 struct rtnl_link_info_ops *io;
2137 free(link->l_info_kind);
2138 link->ce_mask &= ~LINK_ATTR_LINKINFO;
2139 if (link->l_info_ops)
2140 release_link_info(link);
2145 kind = strdup(type);
2151 if (io->io_alloc && (err = io->io_alloc(link)) < 0)
2154 link->l_info_ops = io;
2157 link->l_info_kind = kind;
2158 link->ce_mask |= LINK_ATTR_LINKINFO;
2176 return link->l_info_kind;
2190 link->l_promiscuity = count;
2191 link->ce_mask |= LINK_ATTR_PROMISCUITY;
2203 return link->l_promiscuity;
2222 link->l_num_tx_queues = nqueues;
2223 link->ce_mask |= LINK_ATTR_NUM_TX_QUEUES;
2234 return link->l_num_tx_queues;
2253 link->l_num_rx_queues = nqueues;
2254 link->ce_mask |= LINK_ATTR_NUM_RX_QUEUES;
2265 return link->l_num_rx_queues;
2315 err = -NLE_OPNOTSUPP;
2398 static const struct trans_tbl link_flags[] = {
2399 __ADD(IFF_LOOPBACK, loopback)
2400 __ADD(IFF_BROADCAST, broadcast)
2401 __ADD(IFF_POINTOPOINT, pointopoint)
2402 __ADD(IFF_MULTICAST, multicast)
2403 __ADD(IFF_NOARP, noarp)
2404 __ADD(IFF_ALLMULTI, allmulti)
2405 __ADD(IFF_PROMISC, promisc)
2406 __ADD(IFF_MASTER, master)
2407 __ADD(IFF_SLAVE, slave)
2408 __ADD(IFF_DEBUG, debug)
2409 __ADD(IFF_DYNAMIC, dynamic)
2410 __ADD(IFF_AUTOMEDIA, automedia)
2411 __ADD(IFF_PORTSEL, portsel)
2412 __ADD(IFF_NOTRAILERS, notrailers)
2414 __ADD(IFF_RUNNING, running)
2415 __ADD(IFF_LOWER_UP, lowerup)
2416 __ADD(IFF_DORMANT, dormant)
2417 __ADD(IFF_ECHO, echo)
2420 char *rtnl_link_flags2str(
int flags,
char *buf,
size_t len)
2422 return __flags2str(flags, buf, len, link_flags,
2423 ARRAY_SIZE(link_flags));
2426 int rtnl_link_str2flags(
const char *name)
2428 return __str2flags(name, link_flags, ARRAY_SIZE(link_flags));
2431 static const struct trans_tbl link_stats[] = {
2491 char *rtnl_link_stat2str(
int st,
char *buf,
size_t len)
2493 return __type2str(st, buf, len, link_stats, ARRAY_SIZE(link_stats));
2496 int rtnl_link_str2stat(
const char *name)
2498 return __str2type(name, link_stats, ARRAY_SIZE(link_stats));
2501 static const struct trans_tbl link_operstates[] = {
2502 __ADD(IF_OPER_UNKNOWN, unknown)
2503 __ADD(IF_OPER_NOTPRESENT, notpresent)
2504 __ADD(IF_OPER_DOWN, down)
2505 __ADD(IF_OPER_LOWERLAYERDOWN, lowerlayerdown)
2506 __ADD(IF_OPER_TESTING, testing)
2507 __ADD(IF_OPER_DORMANT, dormant)
2508 __ADD(IF_OPER_UP, up)
2511 char *rtnl_link_operstate2str(uint8_t st,
char *buf,
size_t len)
2513 return __type2str(st, buf, len, link_operstates,
2514 ARRAY_SIZE(link_operstates));
2517 int rtnl_link_str2operstate(
const char *name)
2519 return __str2type(name, link_operstates,
2520 ARRAY_SIZE(link_operstates));
2523 static const struct trans_tbl link_modes[] = {
2524 __ADD(IF_LINK_MODE_DEFAULT,
default)
2525 __ADD(IF_LINK_MODE_DORMANT, dormant)
2528 static const struct trans_tbl carrier_states[] = {
2529 __ADD(IF_CARRIER_DOWN, down)
2530 __ADD(IF_CARRIER_UP, up)
2533 char *rtnl_link_mode2str(uint8_t st,
char *buf,
size_t len)
2535 return __type2str(st, buf, len, link_modes, ARRAY_SIZE(link_modes));
2538 int rtnl_link_str2mode(
const char *name)
2540 return __str2type(name, link_modes, ARRAY_SIZE(link_modes));
2543 char *rtnl_link_carrier2str(uint8_t st,
char *buf,
size_t len)
2545 return __type2str(st, buf, len, carrier_states,
2546 ARRAY_SIZE(carrier_states));
2549 int rtnl_link_str2carrier(
const char *name)
2551 return __str2type(name, carrier_states, ARRAY_SIZE(carrier_states));
2581 link->l_weight = weight;
2582 link->ce_mask |= LINK_ATTR_WEIGHT;
2590 return link->l_weight;
2595 static struct nl_object_ops link_obj_ops = {
2596 .oo_name =
"route/link",
2598 .oo_free_data = link_free_data,
2599 .oo_clone = link_clone,
2605 .oo_compare = link_compare,
2606 .oo_keygen = link_keygen,
2607 .oo_attrs2str = link_attrs2str,
2608 .oo_id_attrs = LINK_ATTR_IFINDEX | LINK_ATTR_FAMILY,
2611 static struct nl_af_group link_groups[] = {
2612 { AF_UNSPEC, RTNLGRP_LINK },
2613 { AF_BRIDGE, RTNLGRP_LINK },
2614 { END_OF_GROUP_LIST },
2617 static struct nl_cache_ops rtnl_link_ops = {
2618 .co_name =
"route/link",
2619 .co_hdrsize =
sizeof(
struct ifinfomsg),
2621 { RTM_NEWLINK, NL_ACT_NEW,
"new" },
2622 { RTM_DELLINK, NL_ACT_DEL,
"del" },
2623 { RTM_GETLINK, NL_ACT_GET,
"get" },
2624 { RTM_SETLINK, NL_ACT_CHANGE,
"set" },
2625 END_OF_MSGTYPES_LIST,
2627 .co_protocol = NETLINK_ROUTE,
2628 .co_groups = link_groups,
2629 .co_request_update = link_request_update,
2630 .co_msg_parser = link_msg_parser,
2631 .co_obj_ops = &link_obj_ops,
2634 static void __init link_init(
void)
2639 static void __exit link_exit(
void)