21 #include <netlink-local.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/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)
79 void *data,
void *arg)
90 void *data,
void *arg)
102 void *data,
void *arg)
104 struct nl_msg *msg = arg;
105 struct nlattr *af_attr;
114 if ((err = ops->
ao_fill_af(link, arg, data)) < 0)
123 void *data,
void *arg)
134 void *data,
void *arg)
145 void *data,
void *arg)
155 static int do_foreach_af(
struct rtnl_link *link,
162 for (i = 0; i < AF_MAX; i++) {
163 if (link->l_af_data[i]) {
169 if ((err = cb(link, ops, link->l_af_data[i], arg)) < 0)
177 static void release_link_info(
struct rtnl_link *link)
185 link->l_info_ops = NULL;
189 static void link_free_data(
struct nl_object *c)
191 struct rtnl_link *link = nl_object_priv(c);
196 if ((io = link->l_info_ops) != NULL)
197 release_link_info(link);
199 nl_addr_put(link->l_addr);
200 nl_addr_put(link->l_bcast);
202 free(link->l_ifalias);
203 free(link->l_info_kind);
205 do_foreach_af(link, af_free, NULL);
211 struct rtnl_link *dst = nl_object_priv(_dst);
212 struct rtnl_link *src = nl_object_priv(_src);
224 if (!(dst->l_ifalias = strdup(src->l_ifalias)))
227 if (src->l_info_kind)
228 if (!(dst->l_info_kind = strdup(src->l_info_kind)))
231 if (src->l_info_ops && src->l_info_ops->io_clone) {
232 err = src->l_info_ops->io_clone(dst, src);
237 if ((err = do_foreach_af(src, af_clone, dst)) < 0)
243 static struct nla_policy link_policy[IFLA_MAX+1] = {
245 .maxlen = IFNAMSIZ },
246 [IFLA_MTU] = { .type =
NLA_U32 },
247 [IFLA_TXQLEN] = { .type =
NLA_U32 },
248 [IFLA_LINK] = { .type =
NLA_U32 },
249 [IFLA_WEIGHT] = { .type =
NLA_U32 },
250 [IFLA_MASTER] = { .type =
NLA_U32 },
251 [IFLA_OPERSTATE] = { .type =
NLA_U8 },
252 [IFLA_LINKMODE] = { .type =
NLA_U8 },
255 .maxlen = IFQDISCSIZ },
256 [IFLA_STATS] = { .minlen =
sizeof(
struct rtnl_link_stats) },
257 [IFLA_STATS64] = { .minlen =
sizeof(
struct rtnl_link_stats64)},
258 [IFLA_MAP] = { .minlen =
sizeof(
struct rtnl_link_ifmap) },
259 [IFLA_IFALIAS] = { .type =
NLA_STRING, .maxlen = IFALIASZ },
260 [IFLA_NUM_VF] = { .type =
NLA_U32 },
262 [IFLA_PROMISCUITY] = { .type =
NLA_U32 },
263 [IFLA_NUM_TX_QUEUES] = { .type =
NLA_U32 },
264 [IFLA_NUM_RX_QUEUES] = { .type =
NLA_U32 },
265 [IFLA_GROUP] = { .type =
NLA_U32 },
268 static struct nla_policy link_info_policy[IFLA_INFO_MAX+1] = {
274 static int link_msg_parser(
struct nl_cache_ops *ops,
struct sockaddr_nl *who,
278 struct ifinfomsg *ifi;
279 struct nlattr *tb[IFLA_MAX+1];
289 link->ce_msgtype = n->nlmsg_type;
291 if (!nlmsg_valid_hdr(n,
sizeof(*ifi)))
292 return -NLE_MSG_TOOSHORT;
295 link->l_family = family = ifi->ifi_family;
296 link->l_arptype = ifi->ifi_type;
297 link->l_index = ifi->ifi_index;
298 link->l_flags = ifi->ifi_flags;
299 link->l_change = ifi->ifi_change;
300 link->ce_mask = (LINK_ATTR_IFNAME | LINK_ATTR_FAMILY |
301 LINK_ATTR_ARPTYPE| LINK_ATTR_IFINDEX |
302 LINK_ATTR_FLAGS | LINK_ATTR_CHANGE);
304 if ((af_ops = af_lookup_and_alloc(link, family))) {
306 memcpy(&link_policy[IFLA_PROTINFO],
312 err =
nlmsg_parse(n,
sizeof(*ifi), tb, IFLA_MAX, link_policy);
316 if (tb[IFLA_IFNAME] == NULL) {
317 err = -NLE_MISSING_ATTR;
321 nla_strlcpy(link->l_name, tb[IFLA_IFNAME], IFNAMSIZ);
324 if (tb[IFLA_STATS]) {
325 struct rtnl_link_stats *st =
nla_data(tb[IFLA_STATS]);
354 link->ce_mask |= LINK_ATTR_STATS;
357 if (tb[IFLA_STATS64]) {
365 struct rtnl_link_stats64 st;
368 sizeof(
struct rtnl_link_stats64));
397 link->ce_mask |= LINK_ATTR_STATS;
400 if (tb[IFLA_TXQLEN]) {
402 link->ce_mask |= LINK_ATTR_TXQLEN;
407 link->ce_mask |= LINK_ATTR_MTU;
410 if (tb[IFLA_ADDRESS]) {
412 if (link->l_addr == NULL) {
416 nl_addr_set_family(link->l_addr,
418 link->ce_mask |= LINK_ATTR_ADDR;
421 if (tb[IFLA_BROADCAST]) {
424 if (link->l_bcast == NULL) {
428 nl_addr_set_family(link->l_bcast,
430 link->ce_mask |= LINK_ATTR_BRD;
435 link->ce_mask |= LINK_ATTR_LINK;
438 if (tb[IFLA_WEIGHT]) {
440 link->ce_mask |= LINK_ATTR_WEIGHT;
443 if (tb[IFLA_QDISC]) {
444 nla_strlcpy(link->l_qdisc, tb[IFLA_QDISC], IFQDISCSIZ);
445 link->ce_mask |= LINK_ATTR_QDISC;
450 sizeof(
struct rtnl_link_ifmap));
451 link->ce_mask |= LINK_ATTR_MAP;
454 if (tb[IFLA_MASTER]) {
456 link->ce_mask |= LINK_ATTR_MASTER;
459 if (tb[IFLA_OPERSTATE]) {
460 link->l_operstate =
nla_get_u8(tb[IFLA_OPERSTATE]);
461 link->ce_mask |= LINK_ATTR_OPERSTATE;
464 if (tb[IFLA_LINKMODE]) {
465 link->l_linkmode =
nla_get_u8(tb[IFLA_LINKMODE]);
466 link->ce_mask |= LINK_ATTR_LINKMODE;
469 if (tb[IFLA_IFALIAS]) {
470 link->l_ifalias = nla_strdup(tb[IFLA_IFALIAS]);
471 if (link->l_ifalias == NULL) {
475 link->ce_mask |= LINK_ATTR_IFALIAS;
478 if (tb[IFLA_NUM_VF]) {
480 link->ce_mask |= LINK_ATTR_NUM_VF;
483 if (tb[IFLA_LINKINFO]) {
484 struct nlattr *li[IFLA_INFO_MAX+1];
491 if (li[IFLA_INFO_KIND]) {
495 kind = nla_strdup(li[IFLA_INFO_KIND]);
500 link->l_info_kind = kind;
501 link->ce_mask |= LINK_ATTR_LINKINFO;
504 link->l_info_ops = ops;
508 (li[IFLA_INFO_DATA] || li[IFLA_INFO_XSTATS])) {
509 err = ops->
io_parse(link, li[IFLA_INFO_DATA],
510 li[IFLA_INFO_XSTATS]);
522 link->l_af_data[link->l_family]);
527 if (tb[IFLA_AF_SPEC]) {
528 struct nlattr *af_attr;
532 af_ops = af_lookup_and_alloc(link,
nla_type(af_attr));
534 char *af_data = link->l_af_data[
nla_type(af_attr)];
547 if (tb[IFLA_PROMISCUITY]) {
548 link->l_promiscuity =
nla_get_u32(tb[IFLA_PROMISCUITY]);
549 link->ce_mask |= LINK_ATTR_PROMISCUITY;
552 if (tb[IFLA_NUM_TX_QUEUES]) {
553 link->l_num_tx_queues =
nla_get_u32(tb[IFLA_NUM_TX_QUEUES]);
554 link->ce_mask |= LINK_ATTR_NUM_TX_QUEUES;
557 if (tb[IFLA_NUM_RX_QUEUES]) {
558 link->l_num_rx_queues =
nla_get_u32(tb[IFLA_NUM_RX_QUEUES]);
559 link->ce_mask |= LINK_ATTR_NUM_RX_QUEUES;
562 if (tb[IFLA_GROUP]) {
564 link->ce_mask |= LINK_ATTR_GROUP;
574 static int link_request_update(
struct nl_cache *cache,
struct nl_sock *sk)
576 int family = cache->c_iarg1;
584 struct nl_cache *cache = obj->ce_cache;
587 nl_dump_line(p,
"%s %s ", link->l_name,
588 nl_llproto2str(link->l_arptype, buf,
sizeof(buf)));
593 if (link->ce_mask & LINK_ATTR_MASTER) {
595 nl_dump(p,
"master %s ", master ? master->l_name :
"inv");
600 rtnl_link_flags2str(link->l_flags, buf,
sizeof(buf));
604 if (link->ce_mask & LINK_ATTR_LINK) {
606 nl_dump(p,
"slave-of %s ", ll ? ll->l_name :
"NONE");
611 if (link->ce_mask & LINK_ATTR_GROUP)
612 nl_dump(p,
"group %u ", link->l_group);
614 if (link->l_info_ops && link->l_info_ops->io_dump[
NL_DUMP_LINE])
617 do_foreach_af(link, af_dump_line, p);
627 link_dump_line(obj, p);
629 nl_dump_line(p,
" mtu %u ", link->l_mtu);
630 nl_dump(p,
"txqlen %u weight %u ", link->l_txqlen, link->l_weight);
632 if (link->ce_mask & LINK_ATTR_QDISC)
633 nl_dump(p,
"qdisc %s ", link->l_qdisc);
635 if (link->ce_mask & LINK_ATTR_MAP && link->l_map.lm_irq)
636 nl_dump(p,
"irq %u ", link->l_map.lm_irq);
638 if (link->ce_mask & LINK_ATTR_IFINDEX)
639 nl_dump(p,
"index %u ", link->l_index);
641 if (link->ce_mask & LINK_ATTR_PROMISCUITY && link->l_promiscuity > 0)
642 nl_dump(p,
"promisc-mode (%u users) ", link->l_promiscuity);
646 if (link->ce_mask & LINK_ATTR_IFALIAS)
647 nl_dump_line(p,
" alias %s\n", link->l_ifalias);
649 nl_dump_line(p,
" ");
651 if (link->ce_mask & LINK_ATTR_NUM_TX_QUEUES)
652 nl_dump(p,
"txq %u ", link->l_num_tx_queues);
654 if (link->ce_mask & LINK_ATTR_NUM_RX_QUEUES)
655 nl_dump(p,
"rxq %u ", link->l_num_rx_queues);
657 if (link->ce_mask & LINK_ATTR_BRD)
661 if ((link->ce_mask & LINK_ATTR_OPERSTATE) &&
662 link->l_operstate != IF_OPER_UNKNOWN) {
663 rtnl_link_operstate2str(link->l_operstate, buf,
sizeof(buf));
667 if (link->ce_mask & LINK_ATTR_NUM_VF)
668 nl_dump(p,
"num-vf %u ", link->l_num_vf);
671 rtnl_link_mode2str(link->l_linkmode, buf,
sizeof(buf)));
676 do_foreach_af(link, af_dump_details, p);
685 link_dump_details(obj, p);
687 nl_dump_line(p,
" Stats: bytes packets errors "
688 " dropped fifo-err compressed\n");
692 strcpy(fmt,
" RX %X.2f %s %10" PRIu64
" %10" PRIu64
" %10" PRIu64
" %10" PRIu64
" %10" PRIu64
"\n");
693 fmt[9] = *unit ==
'B' ?
'9' :
'7';
695 nl_dump_line(p, fmt, res, unit,
704 strcpy(fmt,
" TX %X.2f %s %10" PRIu64
" %10" PRIu64
" %10" PRIu64
" %10" PRIu64
" %10" PRIu64
"\n");
705 fmt[9] = *unit ==
'B' ?
'9' :
'7';
707 nl_dump_line(p, fmt, res, unit,
714 nl_dump_line(p,
" Errors: length over crc "
715 " frame missed multicast\n");
717 nl_dump_line(p,
" RX %10" PRIu64
" %10" PRIu64
" %10"
718 PRIu64
" %10" PRIu64
" %10" PRIu64
" %10"
727 nl_dump_line(p,
" aborted carrier heartbeat "
728 " window collision\n");
730 nl_dump_line(p,
" TX %10" PRIu64
" %10" PRIu64
" %10"
731 PRIu64
" %10" PRIu64
" %10" PRIu64
"\n",
738 if (link->l_info_ops && link->l_info_ops->io_dump[
NL_DUMP_STATS])
741 do_foreach_af(link, af_dump_stats, p);
745 static int link_handle_event(
struct nl_object *a,
struct rtnl_link_event_cb *cb)
748 struct nl_cache *c = dp_cache(a);
751 if (l->l_change == ~0U) {
752 if (l->ce_msgtype == RTM_NEWLINK)
755 cb->le_unregister(l);
760 if (l->l_change & IFF_SLAVE) {
761 if (l->l_flags & IFF_SLAVE) {
763 cb->le_new_bonding(l, m);
767 cb->le_cancel_bonding(l);
771 if (l->l_change & IFF_UP && l->l_change & IFF_RUNNING)
772 dp_dump_line(p, line++,
"link %s changed state to %s.\n",
773 l->l_name, l->l_flags & IFF_UP ?
"up" :
"down");
775 if (l->l_change & IFF_PROMISC) {
776 dp_new_line(p, line++);
777 dp_dump(p,
"link %s %s promiscuous mode.\n",
778 l->l_name, l->l_flags & IFF_PROMISC ?
"entered" :
"left");
782 dp_dump_line(p, line++,
"link %s sent unknown event.\n",
791 static void link_keygen(
struct nl_object *obj, uint32_t *hashkey,
795 unsigned int lkey_sz;
796 struct link_hash_key {
799 } __attribute__((packed)) lkey;
801 lkey_sz = sizeof(lkey);
802 lkey.l_index = link->l_index;
803 lkey.l_family = link->l_family;
805 *hashkey = nl_hash(&lkey, lkey_sz, 0) % table_sz;
807 NL_DBG(5, "link %p key (dev %d fam %d) keysz %d, hash 0x%x\n",
808 link, lkey.l_index, lkey.l_family, lkey_sz, *hashkey);
814 uint32_t attrs,
int flags)
820 #define LINK_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, LINK_ATTR_##ATTR, a, b, EXPR)
822 diff |= LINK_DIFF(IFINDEX, a->l_index != b->l_index);
823 diff |= LINK_DIFF(MTU, a->l_mtu != b->l_mtu);
824 diff |= LINK_DIFF(LINK, a->l_link != b->l_link);
825 diff |= LINK_DIFF(TXQLEN, a->l_txqlen != b->l_txqlen);
826 diff |= LINK_DIFF(WEIGHT, a->l_weight != b->l_weight);
827 diff |= LINK_DIFF(MASTER, a->l_master != b->l_master);
828 diff |= LINK_DIFF(FAMILY, a->l_family != b->l_family);
829 diff |= LINK_DIFF(OPERSTATE, a->l_operstate != b->l_operstate);
830 diff |= LINK_DIFF(LINKMODE, a->l_linkmode != b->l_linkmode);
831 diff |= LINK_DIFF(QDISC, strcmp(a->l_qdisc, b->l_qdisc));
832 diff |= LINK_DIFF(IFNAME, strcmp(a->l_name, b->l_name));
833 diff |= LINK_DIFF(ADDR,
nl_addr_cmp(a->l_addr, b->l_addr));
834 diff |= LINK_DIFF(BRD,
nl_addr_cmp(a->l_bcast, b->l_bcast));
835 diff |= LINK_DIFF(IFALIAS, strcmp(a->l_ifalias, b->l_ifalias));
836 diff |= LINK_DIFF(NUM_VF, a->l_num_vf != b->l_num_vf);
837 diff |= LINK_DIFF(PROMISCUITY, a->l_promiscuity != b->l_promiscuity);
838 diff |= LINK_DIFF(NUM_TX_QUEUES,a->l_num_tx_queues != b->l_num_tx_queues);
839 diff |= LINK_DIFF(NUM_RX_QUEUES,a->l_num_rx_queues != b->l_num_rx_queues);
840 diff |= LINK_DIFF(GROUP, a->l_group != b->l_group);
842 if (flags & LOOSE_COMPARISON)
843 diff |= LINK_DIFF(FLAGS,
844 (a->l_flags ^ b->l_flags) & b->l_flag_mask);
846 diff |= LINK_DIFF(FLAGS, a->l_flags != b->l_flags);
853 static const struct trans_tbl link_attrs[] = {
854 __ADD(LINK_ATTR_MTU, mtu)
855 __ADD(LINK_ATTR_LINK, link)
856 __ADD(LINK_ATTR_TXQLEN, txqlen)
857 __ADD(LINK_ATTR_WEIGHT, weight)
858 __ADD(LINK_ATTR_MASTER, master)
859 __ADD(LINK_ATTR_QDISC, qdisc)
860 __ADD(LINK_ATTR_MAP, map)
861 __ADD(LINK_ATTR_ADDR, address)
862 __ADD(LINK_ATTR_BRD, broadcast)
863 __ADD(LINK_ATTR_FLAGS, flags)
864 __ADD(LINK_ATTR_IFNAME, name)
865 __ADD(LINK_ATTR_IFINDEX, ifindex)
866 __ADD(LINK_ATTR_FAMILY, family)
867 __ADD(LINK_ATTR_ARPTYPE, arptype)
868 __ADD(LINK_ATTR_STATS, stats)
869 __ADD(LINK_ATTR_CHANGE, change)
870 __ADD(LINK_ATTR_OPERSTATE, operstate)
871 __ADD(LINK_ATTR_LINKMODE, linkmode)
872 __ADD(LINK_ATTR_IFALIAS, ifalias)
873 __ADD(LINK_ATTR_NUM_VF, num_vf)
874 __ADD(LINK_ATTR_PROMISCUITY, promiscuity)
875 __ADD(LINK_ATTR_NUM_TX_QUEUES, num_tx_queues)
876 __ADD(LINK_ATTR_NUM_RX_QUEUES, num_rx_queues)
877 __ADD(LINK_ATTR_GROUP, group)
880 static
char *link_attrs2str(
int attrs,
char *buf,
size_t len)
882 return __flags2str(attrs, buf, len, link_attrs,
883 ARRAY_SIZE(link_attrs));
917 struct nl_cache * cache;
924 cache->c_iarg1 = family;
954 if (cache->c_ops != &rtnl_link_ops)
957 nl_list_for_each_entry(link, &cache->c_items, ce_list) {
958 if (link->l_family == AF_UNSPEC && link->l_index == ifindex) {
987 if (cache->c_ops != &rtnl_link_ops)
990 nl_list_for_each_entry(link, &cache->c_items, ce_list) {
991 if (link->l_family == AF_UNSPEC &&
992 !strcmp(name, link->l_name)) {
1016 struct nl_msg **result)
1018 struct ifinfomsg ifi;
1021 if (ifindex <= 0 && !name) {
1022 APPBUG(
"ifindex or name must be specified");
1023 return -NLE_MISSING_ATTR;
1026 memset(&ifi, 0,
sizeof(ifi));
1032 ifi.ifi_index = ifindex;
1034 if (
nlmsg_append(msg, &ifi,
sizeof(ifi), NLMSG_ALIGNTO) < 0)
1035 goto nla_put_failure;
1045 return -NLE_MSGSIZE;
1067 struct nl_msg *msg = NULL;
1079 if ((err =
nl_pickup(sk, link_msg_parser, &obj)) < 0)
1086 if (err == 0 && obj)
1112 strncpy(dst, link->l_name, len - 1);
1136 ifindex = link->l_index;
1145 static int build_link_msg(
int cmd,
struct ifinfomsg *hdr,
1146 struct rtnl_link *link,
int flags,
struct nl_msg **result)
1149 struct nlattr *af_spec;
1155 if (
nlmsg_append(msg, hdr,
sizeof(*hdr), NLMSG_ALIGNTO) < 0)
1156 goto nla_put_failure;
1158 if (link->ce_mask & LINK_ATTR_ADDR)
1161 if (link->ce_mask & LINK_ATTR_BRD)
1164 if (link->ce_mask & LINK_ATTR_MTU)
1167 if (link->ce_mask & LINK_ATTR_TXQLEN)
1170 if (link->ce_mask & LINK_ATTR_WEIGHT)
1173 if (link->ce_mask & LINK_ATTR_IFNAME)
1176 if (link->ce_mask & LINK_ATTR_OPERSTATE)
1177 NLA_PUT_U8(msg, IFLA_OPERSTATE, link->l_operstate);
1179 if (link->ce_mask & LINK_ATTR_LINKMODE)
1180 NLA_PUT_U8(msg, IFLA_LINKMODE, link->l_linkmode);
1182 if (link->ce_mask & LINK_ATTR_IFALIAS)
1185 if (link->ce_mask & LINK_ATTR_LINK)
1188 if (link->ce_mask & LINK_ATTR_MASTER)
1191 if (link->ce_mask & LINK_ATTR_NUM_TX_QUEUES)
1192 NLA_PUT_U32(msg, IFLA_NUM_TX_QUEUES, link->l_num_tx_queues);
1194 if (link->ce_mask & LINK_ATTR_NUM_RX_QUEUES)
1195 NLA_PUT_U32(msg, IFLA_NUM_RX_QUEUES, link->l_num_rx_queues);
1197 if (link->ce_mask & LINK_ATTR_GROUP)
1200 if (link->ce_mask & LINK_ATTR_LINKINFO) {
1201 struct nlattr *info;
1204 goto nla_put_failure;
1208 if (link->l_info_ops) {
1209 if (link->l_info_ops->io_put_attrs &&
1210 link->l_info_ops->io_put_attrs(msg, link) < 0)
1211 goto nla_put_failure;
1218 goto nla_put_failure;
1220 if (do_foreach_af(link, af_fill, msg) < 0)
1221 goto nla_put_failure;
1230 return -NLE_MSGSIZE;
1255 struct nl_msg **result)
1257 struct ifinfomsg ifi = {
1258 .ifi_family = link->l_family,
1259 .ifi_index = link->l_index,
1260 .ifi_flags = link->l_flags,
1263 return build_link_msg(RTM_NEWLINK, &ifi, link, flags, result);
1317 struct nl_msg **result)
1319 struct ifinfomsg ifi = {
1320 .ifi_family = orig->l_family,
1321 .ifi_index = orig->l_index,
1325 if (changes->ce_mask & LINK_ATTR_FLAGS) {
1326 ifi.ifi_flags = orig->l_flags & ~changes->l_flag_mask;
1327 ifi.ifi_flags |= changes->l_flags;
1330 if (changes->l_family && changes->l_family != orig->l_family) {
1331 APPBUG(
"link change: family is immutable");
1332 return -NLE_IMMUTABLE;
1336 if (orig->ce_mask & LINK_ATTR_IFINDEX &&
1337 orig->ce_mask & LINK_ATTR_IFNAME &&
1338 changes->ce_mask & LINK_ATTR_IFNAME &&
1339 !strcmp(orig->l_name, changes->l_name))
1340 changes->ce_mask &= ~LINK_ATTR_IFNAME;
1342 if ((err = build_link_msg(RTM_NEWLINK, &ifi, changes, flags, result)) < 0)
1397 err = wait_for_ack(sk);
1398 if (err == -NLE_OPNOTSUPP && msg->nm_nlh->nlmsg_type == RTM_NEWLINK) {
1399 msg->nm_nlh->nlmsg_type = RTM_SETLINK;
1429 struct nl_msg **result)
1432 struct ifinfomsg ifi = {
1433 .ifi_index = link->l_index,
1436 if (!(link->ce_mask & (LINK_ATTR_IFINDEX | LINK_ATTR_IFNAME))) {
1437 APPBUG(
"ifindex or name must be specified");
1438 return -NLE_MISSING_ATTR;
1444 if (
nlmsg_append(msg, &ifi,
sizeof(ifi), NLMSG_ALIGNTO) < 0)
1445 goto nla_put_failure;
1447 if (link->ce_mask & LINK_ATTR_IFNAME)
1455 return -NLE_MSGSIZE;
1536 strncpy(link->l_name, name,
sizeof(link->l_name) - 1);
1537 link->ce_mask |= LINK_ATTR_IFNAME;
1550 return link->ce_mask & LINK_ATTR_IFNAME ? link->l_name : NULL;
1560 link->l_group = group;
1561 link->ce_mask |= LINK_ATTR_GROUP;
1572 return link->l_group;
1575 static inline void __assign_addr(
struct rtnl_link *link,
struct nl_addr **pos,
1576 struct nl_addr *
new,
int flag)
1584 link->ce_mask |= flag;
1600 __assign_addr(link, &link->l_addr, addr, LINK_ATTR_ADDR);
1614 return link->ce_mask & LINK_ATTR_ADDR ? link->l_addr : NULL;
1631 __assign_addr(link, &link->l_bcast, addr, LINK_ATTR_BRD);
1645 return link->ce_mask & LINK_ATTR_BRD ? link->l_bcast : NULL;
1658 link->l_flag_mask |= flags;
1659 link->l_flags |= flags;
1660 link->ce_mask |= LINK_ATTR_FLAGS;
1673 link->l_flag_mask |= flags;
1674 link->l_flags &= ~flags;
1675 link->ce_mask |= LINK_ATTR_FLAGS;
1689 return link->l_flags;
1699 link->l_family = family;
1700 link->ce_mask |= LINK_ATTR_FAMILY;
1712 return link->ce_mask & LINK_ATTR_FAMILY ? link->l_family : AF_UNSPEC;
1726 link->l_arptype = arptype;
1727 link->ce_mask |= LINK_ATTR_ARPTYPE;
1740 if (link->ce_mask & LINK_ATTR_ARPTYPE)
1741 return link->l_arptype;
1756 link->l_index = ifindex;
1757 link->ce_mask |= LINK_ATTR_IFINDEX;
1771 return link->l_index;
1785 link->ce_mask |= LINK_ATTR_MTU;
1813 link->l_txqlen = txqlen;
1814 link->ce_mask |= LINK_ATTR_TXQLEN;
1829 return link->ce_mask & LINK_ATTR_TXQLEN ? link->l_txqlen : 0;
1832 void rtnl_link_set_link(
struct rtnl_link *link,
int ifindex)
1834 link->l_link = ifindex;
1835 link->ce_mask |= LINK_ATTR_LINK;
1838 int rtnl_link_get_link(
struct rtnl_link *link)
1840 return link->l_link;
1852 link->l_master = ifindex;
1853 link->ce_mask |= LINK_ATTR_MASTER;
1865 return link->l_master;
1878 link->l_operstate = status;
1879 link->ce_mask |= LINK_ATTR_OPERSTATE;
1892 return link->l_operstate;
1905 link->l_linkmode = mode;
1906 link->ce_mask |= LINK_ATTR_LINKMODE;
1919 return link->l_linkmode;
1932 return link->l_ifalias;
1949 free(link->l_ifalias);
1950 link->ce_mask &= ~LINK_ATTR_IFALIAS;
1953 link->l_ifalias = strdup(alias);
1954 link->ce_mask |= LINK_ATTR_IFALIAS;
1973 strncpy(link->l_qdisc, name,
sizeof(link->l_qdisc) - 1);
1974 link->ce_mask |= LINK_ATTR_QDISC;
1987 return link->ce_mask & LINK_ATTR_QDISC ? link->l_qdisc : NULL;
2000 if (link->ce_mask & LINK_ATTR_NUM_VF) {
2001 *num_vf = link->l_num_vf;
2004 return -NLE_OPNOTSUPP;
2016 if (
id > RTNL_LINK_STATS_MAX)
2019 return link->l_stats[id];
2034 const uint64_t value)
2036 if (
id > RTNL_LINK_STATS_MAX)
2039 link->l_stats[id] = value;
2062 free(link->l_info_kind);
2063 link->ce_mask &= ~LINK_ATTR_LINKINFO;
2064 if (link->l_info_ops)
2065 release_link_info(link);
2070 kind = strdup(type);
2079 link->l_info_ops = io;
2082 link->l_info_kind = kind;
2083 link->ce_mask |= LINK_ATTR_LINKINFO;
2101 return link->l_info_kind;
2115 link->l_promiscuity = count;
2116 link->ce_mask |= LINK_ATTR_PROMISCUITY;
2128 return link->l_promiscuity;
2147 link->l_num_tx_queues = nqueues;
2148 link->ce_mask |= LINK_ATTR_NUM_TX_QUEUES;
2159 return link->l_num_tx_queues;
2178 link->l_num_rx_queues = nqueues;
2179 link->ce_mask |= LINK_ATTR_NUM_RX_QUEUES;
2190 return link->l_num_rx_queues;
2240 err = -NLE_OPNOTSUPP;
2323 static const struct trans_tbl link_flags[] = {
2324 __ADD(IFF_LOOPBACK, loopback)
2325 __ADD(IFF_BROADCAST, broadcast)
2326 __ADD(IFF_POINTOPOINT, pointopoint)
2327 __ADD(IFF_MULTICAST, multicast)
2328 __ADD(IFF_NOARP, noarp)
2329 __ADD(IFF_ALLMULTI, allmulti)
2330 __ADD(IFF_PROMISC, promisc)
2331 __ADD(IFF_MASTER, master)
2332 __ADD(IFF_SLAVE, slave)
2333 __ADD(IFF_DEBUG, debug)
2334 __ADD(IFF_DYNAMIC, dynamic)
2335 __ADD(IFF_AUTOMEDIA, automedia)
2336 __ADD(IFF_PORTSEL, portsel)
2337 __ADD(IFF_NOTRAILERS, notrailers)
2339 __ADD(IFF_RUNNING, running)
2340 __ADD(IFF_LOWER_UP, lowerup)
2341 __ADD(IFF_DORMANT, dormant)
2342 __ADD(IFF_ECHO, echo)
2345 char *rtnl_link_flags2str(
int flags,
char *buf,
size_t len)
2347 return __flags2str(flags, buf, len, link_flags,
2348 ARRAY_SIZE(link_flags));
2351 int rtnl_link_str2flags(
const char *name)
2353 return __str2flags(name, link_flags, ARRAY_SIZE(link_flags));
2356 static const struct trans_tbl link_stats[] = {
2416 char *rtnl_link_stat2str(
int st,
char *buf,
size_t len)
2418 return __type2str(st, buf, len, link_stats, ARRAY_SIZE(link_stats));
2421 int rtnl_link_str2stat(
const char *name)
2423 return __str2type(name, link_stats, ARRAY_SIZE(link_stats));
2426 static const struct trans_tbl link_operstates[] = {
2427 __ADD(IF_OPER_UNKNOWN, unknown)
2428 __ADD(IF_OPER_NOTPRESENT, notpresent)
2429 __ADD(IF_OPER_DOWN, down)
2430 __ADD(IF_OPER_LOWERLAYERDOWN, lowerlayerdown)
2431 __ADD(IF_OPER_TESTING, testing)
2432 __ADD(IF_OPER_DORMANT, dormant)
2433 __ADD(IF_OPER_UP, up)
2436 char *rtnl_link_operstate2str(uint8_t st,
char *buf,
size_t len)
2438 return __type2str(st, buf, len, link_operstates,
2439 ARRAY_SIZE(link_operstates));
2442 int rtnl_link_str2operstate(
const char *name)
2444 return __str2type(name, link_operstates,
2445 ARRAY_SIZE(link_operstates));
2448 static const struct trans_tbl link_modes[] = {
2449 __ADD(IF_LINK_MODE_DEFAULT,
default)
2450 __ADD(IF_LINK_MODE_DORMANT, dormant)
2453 char *rtnl_link_mode2str(uint8_t st,
char *buf,
size_t len)
2455 return __type2str(st, buf, len, link_modes, ARRAY_SIZE(link_modes));
2458 int rtnl_link_str2mode(
const char *name)
2460 return __str2type(name, link_modes, ARRAY_SIZE(link_modes));
2490 link->l_weight = weight;
2491 link->ce_mask |= LINK_ATTR_WEIGHT;
2499 return link->l_weight;
2507 .oo_free_data = link_free_data,
2508 .oo_clone = link_clone,
2514 .oo_compare = link_compare,
2515 .oo_keygen = link_keygen,
2516 .oo_attrs2str = link_attrs2str,
2517 .oo_id_attrs = LINK_ATTR_IFINDEX | LINK_ATTR_FAMILY,
2521 { AF_UNSPEC, RTNLGRP_LINK },
2522 { AF_BRIDGE, RTNLGRP_LINK },
2523 { END_OF_GROUP_LIST },
2528 .co_hdrsize =
sizeof(
struct ifinfomsg),
2530 { RTM_NEWLINK, NL_ACT_NEW,
"new" },
2531 { RTM_DELLINK, NL_ACT_DEL,
"del" },
2532 { RTM_GETLINK, NL_ACT_GET,
"get" },
2533 { RTM_SETLINK, NL_ACT_CHANGE,
"set" },
2534 END_OF_MSGTYPES_LIST,
2536 .co_protocol = NETLINK_ROUTE,
2537 .co_groups = link_groups,
2538 .co_request_update = link_request_update,
2539 .co_msg_parser = link_msg_parser,
2540 .co_obj_ops = &link_obj_ops,
2543 static void __init link_init(
void)
2548 static void __exit link_exit(
void)