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)
57 #define LINK_ATTR_CARRIER (1 << 25)
80 void *data,
void *arg)
91 void *data,
void *arg)
103 void *data,
void *arg)
105 struct nl_msg *msg = arg;
106 struct nlattr *af_attr;
115 if ((err = ops->
ao_fill_af(link, arg, data)) < 0)
124 void *data,
void *arg)
135 void *data,
void *arg)
146 void *data,
void *arg)
156 static int do_foreach_af(
struct rtnl_link *link,
163 for (i = 0; i < AF_MAX; i++) {
164 if (link->l_af_data[i]) {
170 if ((err = cb(link, ops, link->l_af_data[i], arg)) < 0)
178 static void release_link_info(
struct rtnl_link *link)
186 link->l_info_ops = NULL;
190 static void link_free_data(
struct nl_object *c)
192 struct rtnl_link *link = nl_object_priv(c);
197 if ((io = link->l_info_ops) != NULL)
198 release_link_info(link);
200 nl_addr_put(link->l_addr);
201 nl_addr_put(link->l_bcast);
203 free(link->l_ifalias);
204 free(link->l_info_kind);
206 do_foreach_af(link, af_free, NULL);
212 struct rtnl_link *dst = nl_object_priv(_dst);
213 struct rtnl_link *src = nl_object_priv(_src);
225 if (!(dst->l_ifalias = strdup(src->l_ifalias)))
228 if (src->l_info_kind)
229 if (!(dst->l_info_kind = strdup(src->l_info_kind)))
232 if (src->l_info_ops && src->l_info_ops->io_clone) {
233 err = src->l_info_ops->io_clone(dst, src);
238 if ((err = do_foreach_af(src, af_clone, dst)) < 0)
244 static struct nla_policy link_policy[IFLA_MAX+1] = {
246 .maxlen = IFNAMSIZ },
247 [IFLA_MTU] = { .type =
NLA_U32 },
248 [IFLA_TXQLEN] = { .type =
NLA_U32 },
249 [IFLA_LINK] = { .type =
NLA_U32 },
250 [IFLA_WEIGHT] = { .type =
NLA_U32 },
251 [IFLA_MASTER] = { .type =
NLA_U32 },
252 [IFLA_OPERSTATE] = { .type =
NLA_U8 },
253 [IFLA_LINKMODE] = { .type =
NLA_U8 },
256 .maxlen = IFQDISCSIZ },
257 [IFLA_STATS] = { .minlen =
sizeof(
struct rtnl_link_stats) },
258 [IFLA_STATS64] = { .minlen =
sizeof(
struct rtnl_link_stats64)},
259 [IFLA_MAP] = { .minlen =
sizeof(
struct rtnl_link_ifmap) },
260 [IFLA_IFALIAS] = { .type =
NLA_STRING, .maxlen = IFALIASZ },
261 [IFLA_NUM_VF] = { .type =
NLA_U32 },
263 [IFLA_PROMISCUITY] = { .type =
NLA_U32 },
264 [IFLA_NUM_TX_QUEUES] = { .type =
NLA_U32 },
265 [IFLA_NUM_RX_QUEUES] = { .type =
NLA_U32 },
266 [IFLA_GROUP] = { .type =
NLA_U32 },
267 [IFLA_CARRIER] = { .type =
NLA_U8 },
270 static struct nla_policy link_info_policy[IFLA_INFO_MAX+1] = {
276 static int link_msg_parser(
struct nl_cache_ops *ops,
struct sockaddr_nl *who,
280 struct ifinfomsg *ifi;
281 struct nlattr *tb[IFLA_MAX+1];
291 link->ce_msgtype = n->nlmsg_type;
293 if (!nlmsg_valid_hdr(n,
sizeof(*ifi)))
294 return -NLE_MSG_TOOSHORT;
297 link->l_family = family = ifi->ifi_family;
298 link->l_arptype = ifi->ifi_type;
299 link->l_index = ifi->ifi_index;
300 link->l_flags = ifi->ifi_flags;
301 link->l_change = ifi->ifi_change;
302 link->ce_mask = (LINK_ATTR_IFNAME | LINK_ATTR_FAMILY |
303 LINK_ATTR_ARPTYPE| LINK_ATTR_IFINDEX |
304 LINK_ATTR_FLAGS | LINK_ATTR_CHANGE);
306 if ((af_ops = af_lookup_and_alloc(link, family))) {
308 memcpy(&link_policy[IFLA_PROTINFO],
314 err =
nlmsg_parse(n,
sizeof(*ifi), tb, IFLA_MAX, link_policy);
318 if (tb[IFLA_IFNAME] == NULL) {
319 err = -NLE_MISSING_ATTR;
323 nla_strlcpy(link->l_name, tb[IFLA_IFNAME], IFNAMSIZ);
326 if (tb[IFLA_STATS]) {
327 struct rtnl_link_stats *st =
nla_data(tb[IFLA_STATS]);
356 link->ce_mask |= LINK_ATTR_STATS;
359 if (tb[IFLA_STATS64]) {
367 struct rtnl_link_stats64 st;
370 sizeof(
struct rtnl_link_stats64));
399 link->ce_mask |= LINK_ATTR_STATS;
402 if (tb[IFLA_TXQLEN]) {
404 link->ce_mask |= LINK_ATTR_TXQLEN;
409 link->ce_mask |= LINK_ATTR_MTU;
412 if (tb[IFLA_ADDRESS]) {
414 if (link->l_addr == NULL) {
418 nl_addr_set_family(link->l_addr,
420 link->ce_mask |= LINK_ATTR_ADDR;
423 if (tb[IFLA_BROADCAST]) {
426 if (link->l_bcast == NULL) {
430 nl_addr_set_family(link->l_bcast,
432 link->ce_mask |= LINK_ATTR_BRD;
437 link->ce_mask |= LINK_ATTR_LINK;
440 if (tb[IFLA_WEIGHT]) {
442 link->ce_mask |= LINK_ATTR_WEIGHT;
445 if (tb[IFLA_QDISC]) {
446 nla_strlcpy(link->l_qdisc, tb[IFLA_QDISC], IFQDISCSIZ);
447 link->ce_mask |= LINK_ATTR_QDISC;
452 sizeof(
struct rtnl_link_ifmap));
453 link->ce_mask |= LINK_ATTR_MAP;
456 if (tb[IFLA_MASTER]) {
458 link->ce_mask |= LINK_ATTR_MASTER;
461 if (tb[IFLA_CARRIER]) {
462 link->l_carrier =
nla_get_u8(tb[IFLA_CARRIER]);
463 link->ce_mask |= LINK_ATTR_CARRIER;
466 if (tb[IFLA_OPERSTATE]) {
467 link->l_operstate =
nla_get_u8(tb[IFLA_OPERSTATE]);
468 link->ce_mask |= LINK_ATTR_OPERSTATE;
471 if (tb[IFLA_LINKMODE]) {
472 link->l_linkmode =
nla_get_u8(tb[IFLA_LINKMODE]);
473 link->ce_mask |= LINK_ATTR_LINKMODE;
476 if (tb[IFLA_IFALIAS]) {
477 link->l_ifalias = nla_strdup(tb[IFLA_IFALIAS]);
478 if (link->l_ifalias == NULL) {
482 link->ce_mask |= LINK_ATTR_IFALIAS;
485 if (tb[IFLA_NUM_VF]) {
487 link->ce_mask |= LINK_ATTR_NUM_VF;
490 if (tb[IFLA_LINKINFO]) {
491 struct nlattr *li[IFLA_INFO_MAX+1];
498 if (li[IFLA_INFO_KIND]) {
502 kind = nla_strdup(li[IFLA_INFO_KIND]);
507 link->l_info_kind = kind;
508 link->ce_mask |= LINK_ATTR_LINKINFO;
511 link->l_info_ops = ops;
515 (li[IFLA_INFO_DATA] || li[IFLA_INFO_XSTATS])) {
516 err = ops->
io_parse(link, li[IFLA_INFO_DATA],
517 li[IFLA_INFO_XSTATS]);
529 link->l_af_data[link->l_family]);
534 if (tb[IFLA_AF_SPEC]) {
535 struct nlattr *af_attr;
539 af_ops = af_lookup_and_alloc(link,
nla_type(af_attr));
541 char *af_data = link->l_af_data[
nla_type(af_attr)];
554 if (tb[IFLA_PROMISCUITY]) {
555 link->l_promiscuity =
nla_get_u32(tb[IFLA_PROMISCUITY]);
556 link->ce_mask |= LINK_ATTR_PROMISCUITY;
559 if (tb[IFLA_NUM_TX_QUEUES]) {
560 link->l_num_tx_queues =
nla_get_u32(tb[IFLA_NUM_TX_QUEUES]);
561 link->ce_mask |= LINK_ATTR_NUM_TX_QUEUES;
564 if (tb[IFLA_NUM_RX_QUEUES]) {
565 link->l_num_rx_queues =
nla_get_u32(tb[IFLA_NUM_RX_QUEUES]);
566 link->ce_mask |= LINK_ATTR_NUM_RX_QUEUES;
569 if (tb[IFLA_GROUP]) {
571 link->ce_mask |= LINK_ATTR_GROUP;
581 static int link_request_update(
struct nl_cache *cache,
struct nl_sock *sk)
583 int family = cache->c_iarg1;
591 struct nl_cache *cache = obj->ce_cache;
594 nl_dump_line(p,
"%s %s ", link->l_name,
595 nl_llproto2str(link->l_arptype, buf,
sizeof(buf)));
600 if (link->ce_mask & LINK_ATTR_MASTER) {
602 nl_dump(p,
"master %s ", master ? master->l_name :
"inv");
607 rtnl_link_flags2str(link->l_flags, buf,
sizeof(buf));
611 if (link->ce_mask & LINK_ATTR_LINK) {
613 nl_dump(p,
"slave-of %s ", ll ? ll->l_name :
"NONE");
618 if (link->ce_mask & LINK_ATTR_GROUP)
619 nl_dump(p,
"group %u ", link->l_group);
621 if (link->l_info_ops && link->l_info_ops->io_dump[
NL_DUMP_LINE])
624 do_foreach_af(link, af_dump_line, p);
634 link_dump_line(obj, p);
636 nl_dump_line(p,
" mtu %u ", link->l_mtu);
637 nl_dump(p,
"txqlen %u weight %u ", link->l_txqlen, link->l_weight);
639 if (link->ce_mask & LINK_ATTR_QDISC)
640 nl_dump(p,
"qdisc %s ", link->l_qdisc);
642 if (link->ce_mask & LINK_ATTR_MAP && link->l_map.lm_irq)
643 nl_dump(p,
"irq %u ", link->l_map.lm_irq);
645 if (link->ce_mask & LINK_ATTR_IFINDEX)
646 nl_dump(p,
"index %u ", link->l_index);
648 if (link->ce_mask & LINK_ATTR_PROMISCUITY && link->l_promiscuity > 0)
649 nl_dump(p,
"promisc-mode (%u users) ", link->l_promiscuity);
653 if (link->ce_mask & LINK_ATTR_IFALIAS)
654 nl_dump_line(p,
" alias %s\n", link->l_ifalias);
656 nl_dump_line(p,
" ");
658 if (link->ce_mask & LINK_ATTR_NUM_TX_QUEUES)
659 nl_dump(p,
"txq %u ", link->l_num_tx_queues);
661 if (link->ce_mask & LINK_ATTR_NUM_RX_QUEUES)
662 nl_dump(p,
"rxq %u ", link->l_num_rx_queues);
664 if (link->ce_mask & LINK_ATTR_BRD)
668 if ((link->ce_mask & LINK_ATTR_OPERSTATE) &&
669 link->l_operstate != IF_OPER_UNKNOWN) {
670 rtnl_link_operstate2str(link->l_operstate, buf,
sizeof(buf));
674 if (link->ce_mask & LINK_ATTR_NUM_VF)
675 nl_dump(p,
"num-vf %u ", link->l_num_vf);
678 rtnl_link_mode2str(link->l_linkmode, buf,
sizeof(buf)));
681 rtnl_link_carrier2str(link->l_carrier, buf,
sizeof(buf)));
688 do_foreach_af(link, af_dump_details, p);
697 link_dump_details(obj, p);
699 nl_dump_line(p,
" Stats: bytes packets errors "
700 " dropped fifo-err compressed\n");
704 strcpy(fmt,
" RX %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,
716 strcpy(fmt,
" TX %X.2f %s %10" PRIu64
" %10" PRIu64
" %10" PRIu64
" %10" PRIu64
" %10" PRIu64
"\n");
717 fmt[9] = *unit ==
'B' ?
'9' :
'7';
719 nl_dump_line(p, fmt, res, unit,
726 nl_dump_line(p,
" Errors: length over crc "
727 " frame missed multicast\n");
729 nl_dump_line(p,
" RX %10" PRIu64
" %10" PRIu64
" %10"
730 PRIu64
" %10" PRIu64
" %10" PRIu64
" %10"
739 nl_dump_line(p,
" aborted carrier heartbeat "
740 " window collision\n");
742 nl_dump_line(p,
" TX %10" PRIu64
" %10" PRIu64
" %10"
743 PRIu64
" %10" PRIu64
" %10" PRIu64
"\n",
750 if (link->l_info_ops && link->l_info_ops->io_dump[
NL_DUMP_STATS])
753 do_foreach_af(link, af_dump_stats, p);
757 static int link_handle_event(
struct nl_object *a,
struct rtnl_link_event_cb *cb)
760 struct nl_cache *c = dp_cache(a);
763 if (l->l_change == ~0U) {
764 if (l->ce_msgtype == RTM_NEWLINK)
767 cb->le_unregister(l);
772 if (l->l_change & IFF_SLAVE) {
773 if (l->l_flags & IFF_SLAVE) {
775 cb->le_new_bonding(l, m);
779 cb->le_cancel_bonding(l);
783 if (l->l_change & IFF_UP && l->l_change & IFF_RUNNING)
784 dp_dump_line(p, line++,
"link %s changed state to %s.\n",
785 l->l_name, l->l_flags & IFF_UP ?
"up" :
"down");
787 if (l->l_change & IFF_PROMISC) {
788 dp_new_line(p, line++);
789 dp_dump(p,
"link %s %s promiscuous mode.\n",
790 l->l_name, l->l_flags & IFF_PROMISC ?
"entered" :
"left");
794 dp_dump_line(p, line++,
"link %s sent unknown event.\n",
803 static void link_keygen(
struct nl_object *obj, uint32_t *hashkey,
807 unsigned int lkey_sz;
808 struct link_hash_key {
811 } __attribute__((packed)) lkey;
813 lkey_sz = sizeof(lkey);
814 lkey.l_index = link->l_index;
815 lkey.l_family = link->l_family;
817 *hashkey = nl_hash(&lkey, lkey_sz, 0) % table_sz;
819 NL_DBG(5, "link %p key (dev %d fam %d) keysz %d, hash 0x%x\n",
820 link, lkey.l_index, lkey.l_family, lkey_sz, *hashkey);
826 uint32_t attrs,
int flags)
832 #define LINK_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, LINK_ATTR_##ATTR, a, b, EXPR)
834 diff |= LINK_DIFF(IFINDEX, a->l_index != b->l_index);
835 diff |= LINK_DIFF(MTU, a->l_mtu != b->l_mtu);
836 diff |= LINK_DIFF(LINK, a->l_link != b->l_link);
837 diff |= LINK_DIFF(TXQLEN, a->l_txqlen != b->l_txqlen);
838 diff |= LINK_DIFF(WEIGHT, a->l_weight != b->l_weight);
839 diff |= LINK_DIFF(MASTER, a->l_master != b->l_master);
840 diff |= LINK_DIFF(FAMILY, a->l_family != b->l_family);
841 diff |= LINK_DIFF(OPERSTATE, a->l_operstate != b->l_operstate);
842 diff |= LINK_DIFF(LINKMODE, a->l_linkmode != b->l_linkmode);
843 diff |= LINK_DIFF(QDISC, strcmp(a->l_qdisc, b->l_qdisc));
844 diff |= LINK_DIFF(IFNAME, strcmp(a->l_name, b->l_name));
845 diff |= LINK_DIFF(ADDR,
nl_addr_cmp(a->l_addr, b->l_addr));
846 diff |= LINK_DIFF(BRD,
nl_addr_cmp(a->l_bcast, b->l_bcast));
847 diff |= LINK_DIFF(IFALIAS, strcmp(a->l_ifalias, b->l_ifalias));
848 diff |= LINK_DIFF(NUM_VF, a->l_num_vf != b->l_num_vf);
849 diff |= LINK_DIFF(PROMISCUITY, a->l_promiscuity != b->l_promiscuity);
850 diff |= LINK_DIFF(NUM_TX_QUEUES,a->l_num_tx_queues != b->l_num_tx_queues);
851 diff |= LINK_DIFF(NUM_RX_QUEUES,a->l_num_rx_queues != b->l_num_rx_queues);
852 diff |= LINK_DIFF(GROUP, a->l_group != b->l_group);
854 if (flags & LOOSE_COMPARISON)
855 diff |= LINK_DIFF(FLAGS,
856 (a->l_flags ^ b->l_flags) & b->l_flag_mask);
858 diff |= LINK_DIFF(FLAGS, a->l_flags != b->l_flags);
865 static const struct trans_tbl link_attrs[] = {
866 __ADD(LINK_ATTR_MTU, mtu)
867 __ADD(LINK_ATTR_LINK, link)
868 __ADD(LINK_ATTR_TXQLEN, txqlen)
869 __ADD(LINK_ATTR_WEIGHT, weight)
870 __ADD(LINK_ATTR_MASTER, master)
871 __ADD(LINK_ATTR_QDISC, qdisc)
872 __ADD(LINK_ATTR_MAP, map)
873 __ADD(LINK_ATTR_ADDR, address)
874 __ADD(LINK_ATTR_BRD, broadcast)
875 __ADD(LINK_ATTR_FLAGS, flags)
876 __ADD(LINK_ATTR_IFNAME, name)
877 __ADD(LINK_ATTR_IFINDEX, ifindex)
878 __ADD(LINK_ATTR_FAMILY, family)
879 __ADD(LINK_ATTR_ARPTYPE, arptype)
880 __ADD(LINK_ATTR_STATS, stats)
881 __ADD(LINK_ATTR_CHANGE, change)
882 __ADD(LINK_ATTR_OPERSTATE, operstate)
883 __ADD(LINK_ATTR_LINKMODE, linkmode)
884 __ADD(LINK_ATTR_IFALIAS, ifalias)
885 __ADD(LINK_ATTR_NUM_VF, num_vf)
886 __ADD(LINK_ATTR_PROMISCUITY, promiscuity)
887 __ADD(LINK_ATTR_NUM_TX_QUEUES, num_tx_queues)
888 __ADD(LINK_ATTR_NUM_RX_QUEUES, num_rx_queues)
889 __ADD(LINK_ATTR_GROUP, group)
890 __ADD(LINK_ATTR_CARRIER, carrier)
893 static
char *link_attrs2str(
int attrs,
char *buf,
size_t len)
895 return __flags2str(attrs, buf, len, link_attrs,
896 ARRAY_SIZE(link_attrs));
930 struct nl_cache * cache;
937 cache->c_iarg1 = family;
967 if (cache->c_ops != &rtnl_link_ops)
970 nl_list_for_each_entry(link, &cache->c_items, ce_list) {
971 if (link->l_family == AF_UNSPEC && link->l_index == ifindex) {
1000 if (cache->c_ops != &rtnl_link_ops)
1003 nl_list_for_each_entry(link, &cache->c_items, ce_list) {
1004 if (link->l_family == AF_UNSPEC &&
1005 !strcmp(name, link->l_name)) {
1029 struct nl_msg **result)
1031 struct ifinfomsg ifi;
1034 if (ifindex <= 0 && !name) {
1035 APPBUG(
"ifindex or name must be specified");
1036 return -NLE_MISSING_ATTR;
1039 memset(&ifi, 0,
sizeof(ifi));
1045 ifi.ifi_index = ifindex;
1047 if (
nlmsg_append(msg, &ifi,
sizeof(ifi), NLMSG_ALIGNTO) < 0)
1048 goto nla_put_failure;
1058 return -NLE_MSGSIZE;
1080 struct nl_msg *msg = NULL;
1092 if ((err =
nl_pickup(sk, link_msg_parser, &obj)) < 0)
1099 if (err == 0 && obj)
1125 strncpy(dst, link->l_name, len - 1);
1149 ifindex = link->l_index;
1158 static int build_link_msg(
int cmd,
struct ifinfomsg *hdr,
1159 struct rtnl_link *link,
int flags,
struct nl_msg **result)
1162 struct nlattr *af_spec;
1168 if (
nlmsg_append(msg, hdr,
sizeof(*hdr), NLMSG_ALIGNTO) < 0)
1169 goto nla_put_failure;
1171 if (link->ce_mask & LINK_ATTR_ADDR)
1174 if (link->ce_mask & LINK_ATTR_BRD)
1177 if (link->ce_mask & LINK_ATTR_MTU)
1180 if (link->ce_mask & LINK_ATTR_TXQLEN)
1183 if (link->ce_mask & LINK_ATTR_WEIGHT)
1186 if (link->ce_mask & LINK_ATTR_IFNAME)
1189 if (link->ce_mask & LINK_ATTR_OPERSTATE)
1190 NLA_PUT_U8(msg, IFLA_OPERSTATE, link->l_operstate);
1192 if (link->ce_mask & LINK_ATTR_CARRIER)
1193 NLA_PUT_U8(msg, IFLA_CARRIER, link->l_carrier);
1195 if (link->ce_mask & LINK_ATTR_LINKMODE)
1196 NLA_PUT_U8(msg, IFLA_LINKMODE, link->l_linkmode);
1198 if (link->ce_mask & LINK_ATTR_IFALIAS)
1201 if (link->ce_mask & LINK_ATTR_LINK)
1204 if (link->ce_mask & LINK_ATTR_MASTER)
1207 if (link->ce_mask & LINK_ATTR_NUM_TX_QUEUES)
1208 NLA_PUT_U32(msg, IFLA_NUM_TX_QUEUES, link->l_num_tx_queues);
1210 if (link->ce_mask & LINK_ATTR_NUM_RX_QUEUES)
1211 NLA_PUT_U32(msg, IFLA_NUM_RX_QUEUES, link->l_num_rx_queues);
1213 if (link->ce_mask & LINK_ATTR_GROUP)
1216 if (link->ce_mask & LINK_ATTR_LINKINFO) {
1217 struct nlattr *info;
1220 goto nla_put_failure;
1224 if (link->l_info_ops) {
1225 if (link->l_info_ops->io_put_attrs &&
1226 link->l_info_ops->io_put_attrs(msg, link) < 0)
1227 goto nla_put_failure;
1234 goto nla_put_failure;
1236 if (do_foreach_af(link, af_fill, msg) < 0)
1237 goto nla_put_failure;
1246 return -NLE_MSGSIZE;
1271 struct nl_msg **result)
1273 struct ifinfomsg ifi = {
1274 .ifi_family = link->l_family,
1275 .ifi_index = link->l_index,
1276 .ifi_flags = link->l_flags,
1279 return build_link_msg(RTM_NEWLINK, &ifi, link, flags, result);
1333 struct nl_msg **result)
1335 struct ifinfomsg ifi = {
1336 .ifi_family = orig->l_family,
1337 .ifi_index = orig->l_index,
1341 if (changes->ce_mask & LINK_ATTR_FLAGS) {
1342 ifi.ifi_flags = orig->l_flags & ~changes->l_flag_mask;
1343 ifi.ifi_flags |= changes->l_flags;
1346 if (changes->l_family && changes->l_family != orig->l_family) {
1347 APPBUG(
"link change: family is immutable");
1348 return -NLE_IMMUTABLE;
1352 if (orig->ce_mask & LINK_ATTR_IFINDEX &&
1353 orig->ce_mask & LINK_ATTR_IFNAME &&
1354 changes->ce_mask & LINK_ATTR_IFNAME &&
1355 !strcmp(orig->l_name, changes->l_name))
1356 changes->ce_mask &= ~LINK_ATTR_IFNAME;
1358 if ((err = build_link_msg(RTM_NEWLINK, &ifi, changes, flags, result)) < 0)
1413 err = wait_for_ack(sk);
1414 if (err == -NLE_OPNOTSUPP && msg->nm_nlh->nlmsg_type == RTM_NEWLINK) {
1415 msg->nm_nlh->nlmsg_type = RTM_SETLINK;
1445 struct nl_msg **result)
1448 struct ifinfomsg ifi = {
1449 .ifi_index = link->l_index,
1452 if (!(link->ce_mask & (LINK_ATTR_IFINDEX | LINK_ATTR_IFNAME))) {
1453 APPBUG(
"ifindex or name must be specified");
1454 return -NLE_MISSING_ATTR;
1460 if (
nlmsg_append(msg, &ifi,
sizeof(ifi), NLMSG_ALIGNTO) < 0)
1461 goto nla_put_failure;
1463 if (link->ce_mask & LINK_ATTR_IFNAME)
1471 return -NLE_MSGSIZE;
1552 strncpy(link->l_name, name,
sizeof(link->l_name) - 1);
1553 link->ce_mask |= LINK_ATTR_IFNAME;
1566 return link->ce_mask & LINK_ATTR_IFNAME ? link->l_name : NULL;
1576 link->l_group = group;
1577 link->ce_mask |= LINK_ATTR_GROUP;
1588 return link->l_group;
1591 static inline void __assign_addr(
struct rtnl_link *link,
struct nl_addr **pos,
1592 struct nl_addr *
new,
int flag)
1600 link->ce_mask |= flag;
1616 __assign_addr(link, &link->l_addr, addr, LINK_ATTR_ADDR);
1630 return link->ce_mask & LINK_ATTR_ADDR ? link->l_addr : NULL;
1647 __assign_addr(link, &link->l_bcast, addr, LINK_ATTR_BRD);
1661 return link->ce_mask & LINK_ATTR_BRD ? link->l_bcast : NULL;
1674 link->l_flag_mask |= flags;
1675 link->l_flags |= flags;
1676 link->ce_mask |= LINK_ATTR_FLAGS;
1689 link->l_flag_mask |= flags;
1690 link->l_flags &= ~flags;
1691 link->ce_mask |= LINK_ATTR_FLAGS;
1705 return link->l_flags;
1715 link->l_family = family;
1716 link->ce_mask |= LINK_ATTR_FAMILY;
1728 return link->ce_mask & LINK_ATTR_FAMILY ? link->l_family : AF_UNSPEC;
1742 link->l_arptype = arptype;
1743 link->ce_mask |= LINK_ATTR_ARPTYPE;
1756 if (link->ce_mask & LINK_ATTR_ARPTYPE)
1757 return link->l_arptype;
1772 link->l_index = ifindex;
1773 link->ce_mask |= LINK_ATTR_IFINDEX;
1787 return link->l_index;
1801 link->ce_mask |= LINK_ATTR_MTU;
1829 link->l_txqlen = txqlen;
1830 link->ce_mask |= LINK_ATTR_TXQLEN;
1845 return link->ce_mask & LINK_ATTR_TXQLEN ? link->l_txqlen : 0;
1848 void rtnl_link_set_link(
struct rtnl_link *link,
int ifindex)
1850 link->l_link = ifindex;
1851 link->ce_mask |= LINK_ATTR_LINK;
1854 int rtnl_link_get_link(
struct rtnl_link *link)
1856 return link->l_link;
1868 link->l_master = ifindex;
1869 link->ce_mask |= LINK_ATTR_MASTER;
1881 return link->l_master;
1893 link->l_carrier = status;
1894 link->ce_mask |= LINK_ATTR_CARRIER;
1906 return link->l_carrier;
1919 link->l_operstate = status;
1920 link->ce_mask |= LINK_ATTR_OPERSTATE;
1933 return link->l_operstate;
1946 link->l_linkmode = mode;
1947 link->ce_mask |= LINK_ATTR_LINKMODE;
1960 return link->l_linkmode;
1973 return link->l_ifalias;
1990 free(link->l_ifalias);
1991 link->ce_mask &= ~LINK_ATTR_IFALIAS;
1994 link->l_ifalias = strdup(alias);
1995 link->ce_mask |= LINK_ATTR_IFALIAS;
2014 strncpy(link->l_qdisc, name,
sizeof(link->l_qdisc) - 1);
2015 link->ce_mask |= LINK_ATTR_QDISC;
2028 return link->ce_mask & LINK_ATTR_QDISC ? link->l_qdisc : NULL;
2041 if (link->ce_mask & LINK_ATTR_NUM_VF) {
2042 *num_vf = link->l_num_vf;
2045 return -NLE_OPNOTSUPP;
2057 if (
id > RTNL_LINK_STATS_MAX)
2060 return link->l_stats[id];
2075 const uint64_t value)
2077 if (
id > RTNL_LINK_STATS_MAX)
2080 link->l_stats[id] = value;
2103 free(link->l_info_kind);
2104 link->ce_mask &= ~LINK_ATTR_LINKINFO;
2105 if (link->l_info_ops)
2106 release_link_info(link);
2111 kind = strdup(type);
2120 link->l_info_ops = io;
2123 link->l_info_kind = kind;
2124 link->ce_mask |= LINK_ATTR_LINKINFO;
2142 return link->l_info_kind;
2156 link->l_promiscuity = count;
2157 link->ce_mask |= LINK_ATTR_PROMISCUITY;
2169 return link->l_promiscuity;
2188 link->l_num_tx_queues = nqueues;
2189 link->ce_mask |= LINK_ATTR_NUM_TX_QUEUES;
2200 return link->l_num_tx_queues;
2219 link->l_num_rx_queues = nqueues;
2220 link->ce_mask |= LINK_ATTR_NUM_RX_QUEUES;
2231 return link->l_num_rx_queues;
2281 err = -NLE_OPNOTSUPP;
2364 static const struct trans_tbl link_flags[] = {
2365 __ADD(IFF_LOOPBACK, loopback)
2366 __ADD(IFF_BROADCAST, broadcast)
2367 __ADD(IFF_POINTOPOINT, pointopoint)
2368 __ADD(IFF_MULTICAST, multicast)
2369 __ADD(IFF_NOARP, noarp)
2370 __ADD(IFF_ALLMULTI, allmulti)
2371 __ADD(IFF_PROMISC, promisc)
2372 __ADD(IFF_MASTER, master)
2373 __ADD(IFF_SLAVE, slave)
2374 __ADD(IFF_DEBUG, debug)
2375 __ADD(IFF_DYNAMIC, dynamic)
2376 __ADD(IFF_AUTOMEDIA, automedia)
2377 __ADD(IFF_PORTSEL, portsel)
2378 __ADD(IFF_NOTRAILERS, notrailers)
2380 __ADD(IFF_RUNNING, running)
2381 __ADD(IFF_LOWER_UP, lowerup)
2382 __ADD(IFF_DORMANT, dormant)
2383 __ADD(IFF_ECHO, echo)
2386 char *rtnl_link_flags2str(
int flags,
char *buf,
size_t len)
2388 return __flags2str(flags, buf, len, link_flags,
2389 ARRAY_SIZE(link_flags));
2392 int rtnl_link_str2flags(
const char *name)
2394 return __str2flags(name, link_flags, ARRAY_SIZE(link_flags));
2397 static const struct trans_tbl link_stats[] = {
2457 char *rtnl_link_stat2str(
int st,
char *buf,
size_t len)
2459 return __type2str(st, buf, len, link_stats, ARRAY_SIZE(link_stats));
2462 int rtnl_link_str2stat(
const char *name)
2464 return __str2type(name, link_stats, ARRAY_SIZE(link_stats));
2467 static const struct trans_tbl link_operstates[] = {
2468 __ADD(IF_OPER_UNKNOWN, unknown)
2469 __ADD(IF_OPER_NOTPRESENT, notpresent)
2470 __ADD(IF_OPER_DOWN, down)
2471 __ADD(IF_OPER_LOWERLAYERDOWN, lowerlayerdown)
2472 __ADD(IF_OPER_TESTING, testing)
2473 __ADD(IF_OPER_DORMANT, dormant)
2474 __ADD(IF_OPER_UP, up)
2477 char *rtnl_link_operstate2str(uint8_t st,
char *buf,
size_t len)
2479 return __type2str(st, buf, len, link_operstates,
2480 ARRAY_SIZE(link_operstates));
2483 int rtnl_link_str2operstate(
const char *name)
2485 return __str2type(name, link_operstates,
2486 ARRAY_SIZE(link_operstates));
2489 static const struct trans_tbl link_modes[] = {
2490 __ADD(IF_LINK_MODE_DEFAULT,
default)
2491 __ADD(IF_LINK_MODE_DORMANT, dormant)
2494 static const struct trans_tbl carrier_states[] = {
2495 __ADD(IF_CARRIER_DOWN, down)
2496 __ADD(IF_CARRIER_UP, up)
2499 char *rtnl_link_mode2str(uint8_t st,
char *buf,
size_t len)
2501 return __type2str(st, buf, len, link_modes, ARRAY_SIZE(link_modes));
2504 int rtnl_link_str2mode(
const char *name)
2506 return __str2type(name, link_modes, ARRAY_SIZE(link_modes));
2509 char *rtnl_link_carrier2str(uint8_t st,
char *buf,
size_t len)
2511 return __type2str(st, buf, len, carrier_states,
2512 ARRAY_SIZE(carrier_states));
2515 int rtnl_link_str2carrier(
const char *name)
2517 return __str2type(name, carrier_states, ARRAY_SIZE(carrier_states));
2547 link->l_weight = weight;
2548 link->ce_mask |= LINK_ATTR_WEIGHT;
2556 return link->l_weight;
2564 .oo_free_data = link_free_data,
2565 .oo_clone = link_clone,
2571 .oo_compare = link_compare,
2572 .oo_keygen = link_keygen,
2573 .oo_attrs2str = link_attrs2str,
2574 .oo_id_attrs = LINK_ATTR_IFINDEX | LINK_ATTR_FAMILY,
2578 { AF_UNSPEC, RTNLGRP_LINK },
2579 { AF_BRIDGE, RTNLGRP_LINK },
2580 { END_OF_GROUP_LIST },
2585 .co_hdrsize =
sizeof(
struct ifinfomsg),
2587 { RTM_NEWLINK, NL_ACT_NEW,
"new" },
2588 { RTM_DELLINK, NL_ACT_DEL,
"del" },
2589 { RTM_GETLINK, NL_ACT_GET,
"get" },
2590 { RTM_SETLINK, NL_ACT_CHANGE,
"set" },
2591 END_OF_MSGTYPES_LIST,
2593 .co_protocol = NETLINK_ROUTE,
2594 .co_groups = link_groups,
2595 .co_request_update = link_request_update,
2596 .co_msg_parser = link_msg_parser,
2597 .co_obj_ops = &link_obj_ops,
2600 static void __init link_init(
void)
2605 static void __exit link_exit(
void)