00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150 #include <netlink-local.h>
00151 #include <netlink/netlink.h>
00152 #include <netlink/attr.h>
00153 #include <netlink/utils.h>
00154 #include <netlink/object.h>
00155 #include <netlink/route/rtnl.h>
00156 #include <netlink/route/link.h>
00157 #include <netlink/route/link/api.h>
00158
00159
00160 #define LINK_ATTR_MTU 0x0001
00161 #define LINK_ATTR_LINK 0x0002
00162 #define LINK_ATTR_TXQLEN 0x0004
00163 #define LINK_ATTR_WEIGHT 0x0008
00164 #define LINK_ATTR_MASTER 0x0010
00165 #define LINK_ATTR_QDISC 0x0020
00166 #define LINK_ATTR_MAP 0x0040
00167 #define LINK_ATTR_ADDR 0x0080
00168 #define LINK_ATTR_BRD 0x0100
00169 #define LINK_ATTR_FLAGS 0x0200
00170 #define LINK_ATTR_IFNAME 0x0400
00171 #define LINK_ATTR_IFINDEX 0x0800
00172 #define LINK_ATTR_FAMILY 0x1000
00173 #define LINK_ATTR_ARPTYPE 0x2000
00174 #define LINK_ATTR_STATS 0x4000
00175 #define LINK_ATTR_CHANGE 0x8000
00176 #define LINK_ATTR_OPERSTATE 0x10000
00177 #define LINK_ATTR_LINKMODE 0x20000
00178 #define LINK_ATTR_LINKINFO 0x40000
00179 #define LINK_ATTR_IFALIAS 0x80000
00180 #define LINK_ATTR_NUM_VF 0x100000
00181
00182 static struct nl_cache_ops rtnl_link_ops;
00183 static struct nl_object_ops link_obj_ops;
00184
00185
00186 static struct rtnl_link_af_ops *af_lookup_and_alloc(struct rtnl_link *link,
00187 int family)
00188 {
00189 struct rtnl_link_af_ops *af_ops;
00190 void *data;
00191
00192 af_ops = rtnl_link_af_ops_lookup(family);
00193 if (!af_ops)
00194 return NULL;
00195
00196 if (!(data = rtnl_link_af_alloc(link, af_ops)))
00197 return NULL;
00198
00199 return af_ops;
00200 }
00201
00202 static int af_free(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
00203 void *data, void *arg)
00204 {
00205 if (ops->ao_free)
00206 ops->ao_free(link, data);
00207
00208 rtnl_link_af_ops_put(ops);
00209
00210 return 0;
00211 }
00212
00213 static int af_clone(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
00214 void *data, void *arg)
00215 {
00216 struct rtnl_link *dst = arg;
00217
00218 if (ops->ao_clone &&
00219 !(dst->l_af_data[ops->ao_family] = ops->ao_clone(link, data)))
00220 return -NLE_NOMEM;
00221
00222 return 0;
00223 }
00224
00225 static int af_fill(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
00226 void *data, void *arg)
00227 {
00228 struct nl_msg *msg = arg;
00229 struct nlattr *af_attr;
00230 int err;
00231
00232 if (!ops->ao_fill_af)
00233 return 0;
00234
00235 if (!(af_attr = nla_nest_start(msg, ops->ao_family)))
00236 return -NLE_MSGSIZE;
00237
00238 if ((err = ops->ao_fill_af(link, arg, data)) < 0)
00239 return err;
00240
00241 nla_nest_end(msg, af_attr);
00242
00243 return 0;
00244 }
00245
00246 static int af_dump_line(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
00247 void *data, void *arg)
00248 {
00249 struct nl_dump_params *p = arg;
00250
00251 if (ops->ao_dump[NL_DUMP_LINE])
00252 ops->ao_dump[NL_DUMP_LINE](link, p, data);
00253
00254 return 0;
00255 }
00256
00257 static int af_dump_details(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
00258 void *data, void *arg)
00259 {
00260 struct nl_dump_params *p = arg;
00261
00262 if (ops->ao_dump[NL_DUMP_DETAILS])
00263 ops->ao_dump[NL_DUMP_DETAILS](link, p, data);
00264
00265 return 0;
00266 }
00267
00268 static int af_dump_stats(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
00269 void *data, void *arg)
00270 {
00271 struct nl_dump_params *p = arg;
00272
00273 if (ops->ao_dump[NL_DUMP_STATS])
00274 ops->ao_dump[NL_DUMP_STATS](link, p, data);
00275
00276 return 0;
00277 }
00278
00279 static int do_foreach_af(struct rtnl_link *link,
00280 int (*cb)(struct rtnl_link *,
00281 struct rtnl_link_af_ops *, void *, void *),
00282 void *arg)
00283 {
00284 int i, err;
00285
00286 for (i = 0; i < AF_MAX; i++) {
00287 if (link->l_af_data[i]) {
00288 struct rtnl_link_af_ops *ops;
00289
00290 if (!(ops = rtnl_link_af_ops_lookup(i)))
00291 BUG();
00292
00293 if ((err = cb(link, ops, link->l_af_data[i], arg)) < 0)
00294 return err;
00295 }
00296 }
00297
00298 return 0;
00299 }
00300
00301 static void release_link_info(struct rtnl_link *link)
00302 {
00303 struct rtnl_link_info_ops *io = link->l_info_ops;
00304
00305 if (io != NULL) {
00306 io->io_free(link);
00307 rtnl_link_info_ops_put(io);
00308 link->l_info_ops = NULL;
00309 }
00310 }
00311
00312 static void link_free_data(struct nl_object *c)
00313 {
00314 struct rtnl_link *link = nl_object_priv(c);
00315
00316 if (link) {
00317 struct rtnl_link_info_ops *io;
00318
00319 if ((io = link->l_info_ops) != NULL)
00320 release_link_info(link);
00321
00322 nl_addr_put(link->l_addr);
00323 nl_addr_put(link->l_bcast);
00324
00325 free(link->l_ifalias);
00326
00327 do_foreach_af(link, af_free, NULL);
00328 }
00329 }
00330
00331 static int link_clone(struct nl_object *_dst, struct nl_object *_src)
00332 {
00333 struct rtnl_link *dst = nl_object_priv(_dst);
00334 struct rtnl_link *src = nl_object_priv(_src);
00335 int err;
00336
00337 if (src->l_addr)
00338 if (!(dst->l_addr = nl_addr_clone(src->l_addr)))
00339 return -NLE_NOMEM;
00340
00341 if (src->l_bcast)
00342 if (!(dst->l_bcast = nl_addr_clone(src->l_bcast)))
00343 return -NLE_NOMEM;
00344
00345 if (src->l_ifalias)
00346 if (!(dst->l_ifalias = strdup(src->l_ifalias)))
00347 return -NLE_NOMEM;
00348
00349 if (src->l_info_ops && src->l_info_ops->io_clone) {
00350 err = src->l_info_ops->io_clone(dst, src);
00351 if (err < 0)
00352 return err;
00353 }
00354
00355 if ((err = do_foreach_af(src, af_clone, dst)) < 0)
00356 return err;
00357
00358 return 0;
00359 }
00360
00361 static struct nla_policy link_policy[IFLA_MAX+1] = {
00362 [IFLA_IFNAME] = { .type = NLA_STRING,
00363 .maxlen = IFNAMSIZ },
00364 [IFLA_MTU] = { .type = NLA_U32 },
00365 [IFLA_TXQLEN] = { .type = NLA_U32 },
00366 [IFLA_LINK] = { .type = NLA_U32 },
00367 [IFLA_WEIGHT] = { .type = NLA_U32 },
00368 [IFLA_MASTER] = { .type = NLA_U32 },
00369 [IFLA_OPERSTATE]= { .type = NLA_U8 },
00370 [IFLA_LINKMODE] = { .type = NLA_U8 },
00371 [IFLA_LINKINFO] = { .type = NLA_NESTED },
00372 [IFLA_QDISC] = { .type = NLA_STRING,
00373 .maxlen = IFQDISCSIZ },
00374 [IFLA_STATS] = { .minlen = sizeof(struct rtnl_link_stats) },
00375 [IFLA_STATS64] = { .minlen = sizeof(struct rtnl_link_stats64) },
00376 [IFLA_MAP] = { .minlen = sizeof(struct rtnl_link_ifmap) },
00377 [IFLA_IFALIAS] = { .type = NLA_STRING, .maxlen = IFALIASZ },
00378 [IFLA_NUM_VF] = { .type = NLA_U32 },
00379 [IFLA_AF_SPEC] = { .type = NLA_NESTED },
00380 };
00381
00382 static struct nla_policy link_info_policy[IFLA_INFO_MAX+1] = {
00383 [IFLA_INFO_KIND] = { .type = NLA_STRING },
00384 [IFLA_INFO_DATA] = { .type = NLA_NESTED },
00385 [IFLA_INFO_XSTATS] = { .type = NLA_NESTED },
00386 };
00387
00388 static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
00389 struct nlmsghdr *n, struct nl_parser_param *pp)
00390 {
00391 struct rtnl_link *link;
00392 struct ifinfomsg *ifi;
00393 struct nlattr *tb[IFLA_MAX+1];
00394 struct rtnl_link_af_ops *af_ops = NULL;
00395 int err, family;
00396
00397 link = rtnl_link_alloc();
00398 if (link == NULL) {
00399 err = -NLE_NOMEM;
00400 goto errout;
00401 }
00402
00403 link->ce_msgtype = n->nlmsg_type;
00404
00405 if (!nlmsg_valid_hdr(n, sizeof(*ifi)))
00406 return -NLE_MSG_TOOSHORT;
00407
00408 ifi = nlmsg_data(n);
00409 link->l_family = family = ifi->ifi_family;
00410 link->l_arptype = ifi->ifi_type;
00411 link->l_index = ifi->ifi_index;
00412 link->l_flags = ifi->ifi_flags;
00413 link->l_change = ifi->ifi_change;
00414 link->ce_mask = (LINK_ATTR_IFNAME | LINK_ATTR_FAMILY |
00415 LINK_ATTR_ARPTYPE| LINK_ATTR_IFINDEX |
00416 LINK_ATTR_FLAGS | LINK_ATTR_CHANGE);
00417
00418 if ((af_ops = af_lookup_and_alloc(link, family))) {
00419 if (af_ops->ao_protinfo_policy) {
00420 memcpy(&link_policy[IFLA_PROTINFO],
00421 af_ops->ao_protinfo_policy,
00422 sizeof(struct nla_policy));
00423 }
00424 }
00425
00426 err = nlmsg_parse(n, sizeof(*ifi), tb, IFLA_MAX, link_policy);
00427 if (err < 0)
00428 goto errout;
00429
00430 if (tb[IFLA_IFNAME] == NULL) {
00431 err = -NLE_MISSING_ATTR;
00432 goto errout;
00433 }
00434
00435 nla_strlcpy(link->l_name, tb[IFLA_IFNAME], IFNAMSIZ);
00436
00437
00438 if (tb[IFLA_STATS]) {
00439 struct rtnl_link_stats *st = nla_data(tb[IFLA_STATS]);
00440
00441 link->l_stats[RTNL_LINK_RX_PACKETS] = st->rx_packets;
00442 link->l_stats[RTNL_LINK_TX_PACKETS] = st->tx_packets;
00443 link->l_stats[RTNL_LINK_RX_BYTES] = st->rx_bytes;
00444 link->l_stats[RTNL_LINK_TX_BYTES] = st->tx_bytes;
00445 link->l_stats[RTNL_LINK_RX_ERRORS] = st->rx_errors;
00446 link->l_stats[RTNL_LINK_TX_ERRORS] = st->tx_errors;
00447 link->l_stats[RTNL_LINK_RX_DROPPED] = st->rx_dropped;
00448 link->l_stats[RTNL_LINK_TX_DROPPED] = st->tx_dropped;
00449 link->l_stats[RTNL_LINK_MULTICAST] = st->multicast;
00450 link->l_stats[RTNL_LINK_COLLISIONS] = st->collisions;
00451
00452 link->l_stats[RTNL_LINK_RX_LEN_ERR] = st->rx_length_errors;
00453 link->l_stats[RTNL_LINK_RX_OVER_ERR] = st->rx_over_errors;
00454 link->l_stats[RTNL_LINK_RX_CRC_ERR] = st->rx_crc_errors;
00455 link->l_stats[RTNL_LINK_RX_FRAME_ERR] = st->rx_frame_errors;
00456 link->l_stats[RTNL_LINK_RX_FIFO_ERR] = st->rx_fifo_errors;
00457 link->l_stats[RTNL_LINK_RX_MISSED_ERR] = st->rx_missed_errors;
00458
00459 link->l_stats[RTNL_LINK_TX_ABORT_ERR] = st->tx_aborted_errors;
00460 link->l_stats[RTNL_LINK_TX_CARRIER_ERR] = st->tx_carrier_errors;
00461 link->l_stats[RTNL_LINK_TX_FIFO_ERR] = st->tx_fifo_errors;
00462 link->l_stats[RTNL_LINK_TX_HBEAT_ERR] = st->tx_heartbeat_errors;
00463 link->l_stats[RTNL_LINK_TX_WIN_ERR] = st->tx_window_errors;
00464
00465 link->l_stats[RTNL_LINK_RX_COMPRESSED] = st->rx_compressed;
00466 link->l_stats[RTNL_LINK_TX_COMPRESSED] = st->tx_compressed;
00467
00468 link->ce_mask |= LINK_ATTR_STATS;
00469 }
00470
00471 if (tb[IFLA_STATS64]) {
00472 struct rtnl_link_stats64 *st = nla_data(tb[IFLA_STATS64]);
00473
00474 link->l_stats[RTNL_LINK_RX_PACKETS] = st->rx_packets;
00475 link->l_stats[RTNL_LINK_TX_PACKETS] = st->tx_packets;
00476 link->l_stats[RTNL_LINK_RX_BYTES] = st->rx_bytes;
00477 link->l_stats[RTNL_LINK_TX_BYTES] = st->tx_bytes;
00478 link->l_stats[RTNL_LINK_RX_ERRORS] = st->rx_errors;
00479 link->l_stats[RTNL_LINK_TX_ERRORS] = st->tx_errors;
00480 link->l_stats[RTNL_LINK_RX_DROPPED] = st->rx_dropped;
00481 link->l_stats[RTNL_LINK_TX_DROPPED] = st->tx_dropped;
00482 link->l_stats[RTNL_LINK_MULTICAST] = st->multicast;
00483 link->l_stats[RTNL_LINK_COLLISIONS] = st->collisions;
00484
00485 link->l_stats[RTNL_LINK_RX_LEN_ERR] = st->rx_length_errors;
00486 link->l_stats[RTNL_LINK_RX_OVER_ERR] = st->rx_over_errors;
00487 link->l_stats[RTNL_LINK_RX_CRC_ERR] = st->rx_crc_errors;
00488 link->l_stats[RTNL_LINK_RX_FRAME_ERR] = st->rx_frame_errors;
00489 link->l_stats[RTNL_LINK_RX_FIFO_ERR] = st->rx_fifo_errors;
00490 link->l_stats[RTNL_LINK_RX_MISSED_ERR] = st->rx_missed_errors;
00491
00492 link->l_stats[RTNL_LINK_TX_ABORT_ERR] = st->tx_aborted_errors;
00493 link->l_stats[RTNL_LINK_TX_CARRIER_ERR] = st->tx_carrier_errors;
00494 link->l_stats[RTNL_LINK_TX_FIFO_ERR] = st->tx_fifo_errors;
00495 link->l_stats[RTNL_LINK_TX_HBEAT_ERR] = st->tx_heartbeat_errors;
00496 link->l_stats[RTNL_LINK_TX_WIN_ERR] = st->tx_window_errors;
00497
00498 link->l_stats[RTNL_LINK_RX_COMPRESSED] = st->rx_compressed;
00499 link->l_stats[RTNL_LINK_TX_COMPRESSED] = st->tx_compressed;
00500
00501 link->ce_mask |= LINK_ATTR_STATS;
00502 }
00503
00504 if (tb[IFLA_TXQLEN]) {
00505 link->l_txqlen = nla_get_u32(tb[IFLA_TXQLEN]);
00506 link->ce_mask |= LINK_ATTR_TXQLEN;
00507 }
00508
00509 if (tb[IFLA_MTU]) {
00510 link->l_mtu = nla_get_u32(tb[IFLA_MTU]);
00511 link->ce_mask |= LINK_ATTR_MTU;
00512 }
00513
00514 if (tb[IFLA_ADDRESS]) {
00515 link->l_addr = nl_addr_alloc_attr(tb[IFLA_ADDRESS], AF_UNSPEC);
00516 if (link->l_addr == NULL) {
00517 err = -NLE_NOMEM;
00518 goto errout;
00519 }
00520 nl_addr_set_family(link->l_addr,
00521 nl_addr_guess_family(link->l_addr));
00522 link->ce_mask |= LINK_ATTR_ADDR;
00523 }
00524
00525 if (tb[IFLA_BROADCAST]) {
00526 link->l_bcast = nl_addr_alloc_attr(tb[IFLA_BROADCAST],
00527 AF_UNSPEC);
00528 if (link->l_bcast == NULL) {
00529 err = -NLE_NOMEM;
00530 goto errout;
00531 }
00532 nl_addr_set_family(link->l_bcast,
00533 nl_addr_guess_family(link->l_bcast));
00534 link->ce_mask |= LINK_ATTR_BRD;
00535 }
00536
00537 if (tb[IFLA_LINK]) {
00538 link->l_link = nla_get_u32(tb[IFLA_LINK]);
00539 link->ce_mask |= LINK_ATTR_LINK;
00540 }
00541
00542 if (tb[IFLA_WEIGHT]) {
00543 link->l_weight = nla_get_u32(tb[IFLA_WEIGHT]);
00544 link->ce_mask |= LINK_ATTR_WEIGHT;
00545 }
00546
00547 if (tb[IFLA_QDISC]) {
00548 nla_strlcpy(link->l_qdisc, tb[IFLA_QDISC], IFQDISCSIZ);
00549 link->ce_mask |= LINK_ATTR_QDISC;
00550 }
00551
00552 if (tb[IFLA_MAP]) {
00553 nla_memcpy(&link->l_map, tb[IFLA_MAP],
00554 sizeof(struct rtnl_link_ifmap));
00555 link->ce_mask |= LINK_ATTR_MAP;
00556 }
00557
00558 if (tb[IFLA_MASTER]) {
00559 link->l_master = nla_get_u32(tb[IFLA_MASTER]);
00560 link->ce_mask |= LINK_ATTR_MASTER;
00561 }
00562
00563 if (tb[IFLA_OPERSTATE]) {
00564 link->l_operstate = nla_get_u8(tb[IFLA_OPERSTATE]);
00565 link->ce_mask |= LINK_ATTR_OPERSTATE;
00566 }
00567
00568 if (tb[IFLA_LINKMODE]) {
00569 link->l_linkmode = nla_get_u8(tb[IFLA_LINKMODE]);
00570 link->ce_mask |= LINK_ATTR_LINKMODE;
00571 }
00572
00573 if (tb[IFLA_IFALIAS]) {
00574 link->l_ifalias = nla_strdup(tb[IFLA_IFALIAS]);
00575 if (link->l_ifalias == NULL) {
00576 err = -NLE_NOMEM;
00577 goto errout;
00578 }
00579 link->ce_mask |= LINK_ATTR_IFALIAS;
00580 }
00581
00582 if (tb[IFLA_NUM_VF]) {
00583 link->l_num_vf = nla_get_u32(tb[IFLA_NUM_VF]);
00584 link->ce_mask |= LINK_ATTR_NUM_VF;
00585 }
00586
00587 if (tb[IFLA_LINKINFO]) {
00588 struct nlattr *li[IFLA_INFO_MAX+1];
00589
00590 err = nla_parse_nested(li, IFLA_INFO_MAX, tb[IFLA_LINKINFO],
00591 link_info_policy);
00592 if (err < 0)
00593 goto errout;
00594
00595 if (li[IFLA_INFO_KIND] &&
00596 (li[IFLA_INFO_DATA] || li[IFLA_INFO_XSTATS])) {
00597 struct rtnl_link_info_ops *ops;
00598 char *kind;
00599
00600 kind = nla_get_string(li[IFLA_INFO_KIND]);
00601 ops = rtnl_link_info_ops_lookup(kind);
00602 if (ops != NULL) {
00603 link->l_info_ops = ops;
00604 err = ops->io_parse(link, li[IFLA_INFO_DATA],
00605 li[IFLA_INFO_XSTATS]);
00606 if (err < 0)
00607 goto errout;
00608 } else {
00609
00610 }
00611 }
00612 }
00613
00614 if (tb[IFLA_PROTINFO] && af_ops && af_ops->ao_parse_protinfo) {
00615 err = af_ops->ao_parse_protinfo(link, tb[IFLA_PROTINFO],
00616 link->l_af_data[link->l_family]);
00617 if (err < 0)
00618 goto errout;
00619 }
00620
00621 if (tb[IFLA_AF_SPEC]) {
00622 struct nlattr *af_attr;
00623 int remaining;
00624
00625 nla_for_each_nested(af_attr, tb[IFLA_AF_SPEC], remaining) {
00626 af_ops = af_lookup_and_alloc(link, nla_type(af_attr));
00627 if (af_ops && af_ops->ao_parse_af) {
00628 char *af_data = link->l_af_data[nla_type(af_attr)];
00629
00630 err = af_ops->ao_parse_af(link, af_attr, af_data);
00631
00632 rtnl_link_af_ops_put(af_ops);
00633
00634 if (err < 0)
00635 goto errout;
00636 }
00637
00638 }
00639 }
00640
00641 err = pp->pp_cb((struct nl_object *) link, pp);
00642 errout:
00643 rtnl_link_af_ops_put(af_ops);
00644 rtnl_link_put(link);
00645 return err;
00646 }
00647
00648 static int link_request_update(struct nl_cache *cache, struct nl_sock *sk)
00649 {
00650 int family = cache->c_iarg1;
00651
00652 return nl_rtgen_request(sk, RTM_GETLINK, family, NLM_F_DUMP);
00653 }
00654
00655 static void link_dump_line(struct nl_object *obj, struct nl_dump_params *p)
00656 {
00657 char buf[128];
00658 struct nl_cache *cache = dp_cache(obj);
00659 struct rtnl_link *link = (struct rtnl_link *) obj;
00660
00661 nl_dump_line(p, "%s %s ", link->l_name,
00662 nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
00663
00664 if (link->l_addr && !nl_addr_iszero(link->l_addr))
00665 nl_dump(p, "%s ", nl_addr2str(link->l_addr, buf, sizeof(buf)));
00666
00667 if (link->ce_mask & LINK_ATTR_MASTER) {
00668 struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
00669 nl_dump(p, "master %s ", master ? master->l_name : "inv");
00670 if (master)
00671 rtnl_link_put(master);
00672 }
00673
00674 rtnl_link_flags2str(link->l_flags, buf, sizeof(buf));
00675 if (buf[0])
00676 nl_dump(p, "<%s> ", buf);
00677
00678 if (link->ce_mask & LINK_ATTR_LINK) {
00679 struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
00680 nl_dump(p, "slave-of %s ", ll ? ll->l_name : "NONE");
00681 if (ll)
00682 rtnl_link_put(ll);
00683 }
00684
00685 if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_LINE])
00686 link->l_info_ops->io_dump[NL_DUMP_LINE](link, p);
00687
00688 do_foreach_af(link, af_dump_line, p);
00689
00690 nl_dump(p, "\n");
00691 }
00692
00693 static void link_dump_details(struct nl_object *obj, struct nl_dump_params *p)
00694 {
00695 struct rtnl_link *link = (struct rtnl_link *) obj;
00696 char buf[64];
00697
00698 link_dump_line(obj, p);
00699
00700 nl_dump_line(p, " mtu %u ", link->l_mtu);
00701 nl_dump(p, "txqlen %u weight %u ", link->l_txqlen, link->l_weight);
00702
00703 if (link->ce_mask & LINK_ATTR_QDISC)
00704 nl_dump(p, "qdisc %s ", link->l_qdisc);
00705
00706 if (link->ce_mask & LINK_ATTR_MAP && link->l_map.lm_irq)
00707 nl_dump(p, "irq %u ", link->l_map.lm_irq);
00708
00709 if (link->ce_mask & LINK_ATTR_IFINDEX)
00710 nl_dump(p, "index %u ", link->l_index);
00711
00712
00713 nl_dump(p, "\n");
00714
00715 if (link->ce_mask & LINK_ATTR_IFALIAS)
00716 nl_dump_line(p, " alias %s\n", link->l_ifalias);
00717
00718 nl_dump_line(p, " ");
00719
00720 if (link->ce_mask & LINK_ATTR_BRD)
00721 nl_dump(p, "brd %s ", nl_addr2str(link->l_bcast, buf,
00722 sizeof(buf)));
00723
00724 if ((link->ce_mask & LINK_ATTR_OPERSTATE) &&
00725 link->l_operstate != IF_OPER_UNKNOWN) {
00726 rtnl_link_operstate2str(link->l_operstate, buf, sizeof(buf));
00727 nl_dump(p, "state %s ", buf);
00728 }
00729
00730 if (link->ce_mask & LINK_ATTR_NUM_VF)
00731 nl_dump(p, "num-vf %u ", link->l_num_vf);
00732
00733 nl_dump(p, "mode %s\n",
00734 rtnl_link_mode2str(link->l_linkmode, buf, sizeof(buf)));
00735
00736 if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_DETAILS])
00737 link->l_info_ops->io_dump[NL_DUMP_DETAILS](link, p);
00738
00739 do_foreach_af(link, af_dump_details, p);
00740 }
00741
00742 static void link_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
00743 {
00744 struct rtnl_link *link = (struct rtnl_link *) obj;
00745 char *unit, fmt[64];
00746 float res;
00747
00748 link_dump_details(obj, p);
00749
00750 nl_dump_line(p, " Stats: bytes packets errors "
00751 " dropped fifo-err compressed\n");
00752
00753 res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_RX_BYTES], &unit);
00754
00755 strcpy(fmt, " RX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n");
00756 fmt[9] = *unit == 'B' ? '9' : '7';
00757
00758 nl_dump_line(p, fmt, res, unit,
00759 link->l_stats[RTNL_LINK_RX_PACKETS],
00760 link->l_stats[RTNL_LINK_RX_ERRORS],
00761 link->l_stats[RTNL_LINK_RX_DROPPED],
00762 link->l_stats[RTNL_LINK_RX_FIFO_ERR],
00763 link->l_stats[RTNL_LINK_RX_COMPRESSED]);
00764
00765 res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_TX_BYTES], &unit);
00766
00767 strcpy(fmt, " TX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n");
00768 fmt[9] = *unit == 'B' ? '9' : '7';
00769
00770 nl_dump_line(p, fmt, res, unit,
00771 link->l_stats[RTNL_LINK_TX_PACKETS],
00772 link->l_stats[RTNL_LINK_TX_ERRORS],
00773 link->l_stats[RTNL_LINK_TX_DROPPED],
00774 link->l_stats[RTNL_LINK_TX_FIFO_ERR],
00775 link->l_stats[RTNL_LINK_TX_COMPRESSED]);
00776
00777 nl_dump_line(p, " Errors: length over crc "
00778 " frame missed multicast\n");
00779
00780 nl_dump_line(p, " RX %10" PRIu64 " %10" PRIu64 " %10"
00781 PRIu64 " %10" PRIu64 " %10" PRIu64 " %10"
00782 PRIu64 "\n",
00783 link->l_stats[RTNL_LINK_RX_LEN_ERR],
00784 link->l_stats[RTNL_LINK_RX_OVER_ERR],
00785 link->l_stats[RTNL_LINK_RX_CRC_ERR],
00786 link->l_stats[RTNL_LINK_RX_FRAME_ERR],
00787 link->l_stats[RTNL_LINK_RX_MISSED_ERR],
00788 link->l_stats[RTNL_LINK_MULTICAST]);
00789
00790 nl_dump_line(p, " aborted carrier heartbeat "
00791 " window collision\n");
00792
00793 nl_dump_line(p, " TX %10" PRIu64 " %10" PRIu64 " %10"
00794 PRIu64 " %10" PRIu64 " %10" PRIu64 "\n",
00795 link->l_stats[RTNL_LINK_TX_ABORT_ERR],
00796 link->l_stats[RTNL_LINK_TX_CARRIER_ERR],
00797 link->l_stats[RTNL_LINK_TX_HBEAT_ERR],
00798 link->l_stats[RTNL_LINK_TX_WIN_ERR],
00799 link->l_stats[RTNL_LINK_COLLISIONS]);
00800
00801 if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_STATS])
00802 link->l_info_ops->io_dump[NL_DUMP_STATS](link, p);
00803
00804 do_foreach_af(link, af_dump_stats, p);
00805 }
00806
00807 #if 0
00808 static int link_handle_event(struct nl_object *a, struct rtnl_link_event_cb *cb)
00809 {
00810 struct rtnl_link *l = (struct rtnl_link *) a;
00811 struct nl_cache *c = dp_cache(a);
00812 int nevents = 0;
00813
00814 if (l->l_change == ~0U) {
00815 if (l->ce_msgtype == RTM_NEWLINK)
00816 cb->le_register(l);
00817 else
00818 cb->le_unregister(l);
00819
00820 return 1;
00821 }
00822
00823 if (l->l_change & IFF_SLAVE) {
00824 if (l->l_flags & IFF_SLAVE) {
00825 struct rtnl_link *m = rtnl_link_get(c, l->l_master);
00826 cb->le_new_bonding(l, m);
00827 if (m)
00828 rtnl_link_put(m);
00829 } else
00830 cb->le_cancel_bonding(l);
00831 }
00832
00833 #if 0
00834 if (l->l_change & IFF_UP && l->l_change & IFF_RUNNING)
00835 dp_dump_line(p, line++, "link %s changed state to %s.\n",
00836 l->l_name, l->l_flags & IFF_UP ? "up" : "down");
00837
00838 if (l->l_change & IFF_PROMISC) {
00839 dp_new_line(p, line++);
00840 dp_dump(p, "link %s %s promiscuous mode.\n",
00841 l->l_name, l->l_flags & IFF_PROMISC ? "entered" : "left");
00842 }
00843
00844 if (line == 0)
00845 dp_dump_line(p, line++, "link %s sent unknown event.\n",
00846 l->l_name);
00847 #endif
00848
00849 return nevents;
00850 }
00851 #endif
00852
00853 static int link_compare(struct nl_object *_a, struct nl_object *_b,
00854 uint32_t attrs, int flags)
00855 {
00856 struct rtnl_link *a = (struct rtnl_link *) _a;
00857 struct rtnl_link *b = (struct rtnl_link *) _b;
00858 int diff = 0;
00859
00860 #define LINK_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, LINK_ATTR_##ATTR, a, b, EXPR)
00861
00862 diff |= LINK_DIFF(IFINDEX, a->l_index != b->l_index);
00863 diff |= LINK_DIFF(MTU, a->l_mtu != b->l_mtu);
00864 diff |= LINK_DIFF(LINK, a->l_link != b->l_link);
00865 diff |= LINK_DIFF(TXQLEN, a->l_txqlen != b->l_txqlen);
00866 diff |= LINK_DIFF(WEIGHT, a->l_weight != b->l_weight);
00867 diff |= LINK_DIFF(MASTER, a->l_master != b->l_master);
00868 diff |= LINK_DIFF(FAMILY, a->l_family != b->l_family);
00869 diff |= LINK_DIFF(OPERSTATE, a->l_operstate != b->l_operstate);
00870 diff |= LINK_DIFF(LINKMODE, a->l_linkmode != b->l_linkmode);
00871 diff |= LINK_DIFF(QDISC, strcmp(a->l_qdisc, b->l_qdisc));
00872 diff |= LINK_DIFF(IFNAME, strcmp(a->l_name, b->l_name));
00873 diff |= LINK_DIFF(ADDR, nl_addr_cmp(a->l_addr, b->l_addr));
00874 diff |= LINK_DIFF(BRD, nl_addr_cmp(a->l_bcast, b->l_bcast));
00875 diff |= LINK_DIFF(IFALIAS, strcmp(a->l_ifalias, b->l_ifalias));
00876 diff |= LINK_DIFF(NUM_VF, a->l_num_vf != b->l_num_vf);
00877
00878 if (flags & LOOSE_COMPARISON)
00879 diff |= LINK_DIFF(FLAGS,
00880 (a->l_flags ^ b->l_flags) & b->l_flag_mask);
00881 else
00882 diff |= LINK_DIFF(FLAGS, a->l_flags != b->l_flags);
00883
00884 #undef LINK_DIFF
00885
00886 return diff;
00887 }
00888
00889 static const struct trans_tbl link_attrs[] = {
00890 __ADD(LINK_ATTR_MTU, mtu)
00891 __ADD(LINK_ATTR_LINK, link)
00892 __ADD(LINK_ATTR_TXQLEN, txqlen)
00893 __ADD(LINK_ATTR_WEIGHT, weight)
00894 __ADD(LINK_ATTR_MASTER, master)
00895 __ADD(LINK_ATTR_QDISC, qdisc)
00896 __ADD(LINK_ATTR_MAP, map)
00897 __ADD(LINK_ATTR_ADDR, address)
00898 __ADD(LINK_ATTR_BRD, broadcast)
00899 __ADD(LINK_ATTR_FLAGS, flags)
00900 __ADD(LINK_ATTR_IFNAME, name)
00901 __ADD(LINK_ATTR_IFINDEX, ifindex)
00902 __ADD(LINK_ATTR_FAMILY, family)
00903 __ADD(LINK_ATTR_ARPTYPE, arptype)
00904 __ADD(LINK_ATTR_STATS, stats)
00905 __ADD(LINK_ATTR_CHANGE, change)
00906 __ADD(LINK_ATTR_OPERSTATE, operstate)
00907 __ADD(LINK_ATTR_LINKMODE, linkmode)
00908 __ADD(LINK_ATTR_IFALIAS, ifalias)
00909 __ADD(LINK_ATTR_NUM_VF, num_vf)
00910 };
00911
00912 static char *link_attrs2str(int attrs, char *buf, size_t len)
00913 {
00914 return __flags2str(attrs, buf, len, link_attrs,
00915 ARRAY_SIZE(link_attrs));
00916 }
00917
00918
00919
00920
00921
00922
00923 struct rtnl_link *rtnl_link_alloc(void)
00924 {
00925 return (struct rtnl_link *) nl_object_alloc(&link_obj_ops);
00926 }
00927
00928 void rtnl_link_put(struct rtnl_link *link)
00929 {
00930 nl_object_put((struct nl_object *) link);
00931 }
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952 int rtnl_link_alloc_cache(struct nl_sock *sk, int family, struct nl_cache **result)
00953 {
00954 struct nl_cache * cache;
00955 int err;
00956
00957 cache = nl_cache_alloc(&rtnl_link_ops);
00958 if (!cache)
00959 return -NLE_NOMEM;
00960
00961 cache->c_iarg1 = family;
00962
00963 if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
00964 nl_cache_free(cache);
00965 return err;
00966 }
00967
00968 *result = cache;
00969 return 0;
00970 }
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982 struct rtnl_link *rtnl_link_get(struct nl_cache *cache, int ifindex)
00983 {
00984 struct rtnl_link *link;
00985
00986 if (cache->c_ops != &rtnl_link_ops)
00987 return NULL;
00988
00989 nl_list_for_each_entry(link, &cache->c_items, ce_list) {
00990 if (link->l_index == ifindex) {
00991 nl_object_get((struct nl_object *) link);
00992 return link;
00993 }
00994 }
00995
00996 return NULL;
00997 }
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009 struct rtnl_link *rtnl_link_get_by_name(struct nl_cache *cache,
01010 const char *name)
01011 {
01012 struct rtnl_link *link;
01013
01014 if (cache->c_ops != &rtnl_link_ops)
01015 return NULL;
01016
01017 nl_list_for_each_entry(link, &cache->c_items, ce_list) {
01018 if (!strcmp(name, link->l_name)) {
01019 nl_object_get((struct nl_object *) link);
01020 return link;
01021 }
01022 }
01023
01024 return NULL;
01025 }
01026
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040
01041
01042
01043
01044
01045
01046
01047
01048
01049
01050
01051
01052 int rtnl_link_build_change_request(struct rtnl_link *old,
01053 struct rtnl_link *tmpl, int flags,
01054 struct nl_msg **result)
01055 {
01056 struct nl_msg *msg;
01057 struct nlattr *af_spec;
01058 struct ifinfomsg ifi = {
01059 .ifi_family = old->l_family,
01060 .ifi_index = old->l_index,
01061 };
01062
01063 if (tmpl->ce_mask & LINK_ATTR_FLAGS) {
01064 ifi.ifi_flags = old->l_flags & ~tmpl->l_flag_mask;
01065 ifi.ifi_flags |= tmpl->l_flags;
01066 }
01067
01068 msg = nlmsg_alloc_simple(RTM_SETLINK, flags);
01069 if (!msg)
01070 return -NLE_NOMEM;
01071
01072 if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
01073 goto nla_put_failure;
01074
01075 if (tmpl->ce_mask & LINK_ATTR_ADDR)
01076 NLA_PUT_ADDR(msg, IFLA_ADDRESS, tmpl->l_addr);
01077
01078 if (tmpl->ce_mask & LINK_ATTR_BRD)
01079 NLA_PUT_ADDR(msg, IFLA_BROADCAST, tmpl->l_bcast);
01080
01081 if (tmpl->ce_mask & LINK_ATTR_MTU)
01082 NLA_PUT_U32(msg, IFLA_MTU, tmpl->l_mtu);
01083
01084 if (tmpl->ce_mask & LINK_ATTR_TXQLEN)
01085 NLA_PUT_U32(msg, IFLA_TXQLEN, tmpl->l_txqlen);
01086
01087 if (tmpl->ce_mask & LINK_ATTR_WEIGHT)
01088 NLA_PUT_U32(msg, IFLA_WEIGHT, tmpl->l_weight);
01089
01090 if (tmpl->ce_mask & LINK_ATTR_IFNAME)
01091 NLA_PUT_STRING(msg, IFLA_IFNAME, tmpl->l_name);
01092
01093 if (tmpl->ce_mask & LINK_ATTR_OPERSTATE)
01094 NLA_PUT_U8(msg, IFLA_OPERSTATE, tmpl->l_operstate);
01095
01096 if (tmpl->ce_mask & LINK_ATTR_LINKMODE)
01097 NLA_PUT_U8(msg, IFLA_LINKMODE, tmpl->l_linkmode);
01098
01099 if (tmpl->ce_mask & LINK_ATTR_IFALIAS)
01100 NLA_PUT_STRING(msg, IFLA_IFALIAS, tmpl->l_ifalias);
01101
01102 if ((tmpl->ce_mask & LINK_ATTR_LINKINFO) && tmpl->l_info_ops &&
01103 tmpl->l_info_ops->io_put_attrs) {
01104 struct nlattr *info;
01105
01106 if (!(info = nla_nest_start(msg, IFLA_LINKINFO)))
01107 goto nla_put_failure;
01108
01109 NLA_PUT_STRING(msg, IFLA_INFO_KIND, tmpl->l_info_ops->io_name);
01110
01111 if (tmpl->l_info_ops->io_put_attrs(msg, tmpl) < 0)
01112 goto nla_put_failure;
01113
01114 nla_nest_end(msg, info);
01115 }
01116
01117 if (!(af_spec = nla_nest_start(msg, IFLA_AF_SPEC)))
01118 goto nla_put_failure;
01119
01120 if (do_foreach_af(tmpl, af_fill, msg) < 0)
01121 goto nla_put_failure;
01122
01123 nla_nest_end(msg, af_spec);
01124
01125 *result = msg;
01126 return 0;
01127
01128 nla_put_failure:
01129 nlmsg_free(msg);
01130 return -NLE_MSGSIZE;
01131 }
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148 int rtnl_link_change(struct nl_sock *sk, struct rtnl_link *old,
01149 struct rtnl_link *tmpl, int flags)
01150 {
01151 struct nl_msg *msg;
01152 int err;
01153
01154 if ((err = rtnl_link_build_change_request(old, tmpl, flags, &msg)) < 0)
01155 return err;
01156
01157 err = nl_send_auto_complete(sk, msg);
01158 nlmsg_free(msg);
01159 if (err < 0)
01160 return err;
01161
01162 return wait_for_ack(sk);
01163 }
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182
01183
01184 char * rtnl_link_i2name(struct nl_cache *cache, int ifindex, char *dst,
01185 size_t len)
01186 {
01187 struct rtnl_link *link = rtnl_link_get(cache, ifindex);
01188
01189 if (link) {
01190 strncpy(dst, link->l_name, len - 1);
01191 rtnl_link_put(link);
01192 return dst;
01193 }
01194
01195 return NULL;
01196 }
01197
01198
01199
01200
01201
01202
01203
01204
01205 int rtnl_link_name2i(struct nl_cache *cache, const char *name)
01206 {
01207 int ifindex = 0;
01208 struct rtnl_link *link;
01209
01210 link = rtnl_link_get_by_name(cache, name);
01211 if (link) {
01212 ifindex = link->l_index;
01213 rtnl_link_put(link);
01214 }
01215
01216 return ifindex;
01217 }
01218
01219
01220
01221
01222
01223
01224
01225
01226 static const struct trans_tbl link_flags[] = {
01227 __ADD(IFF_LOOPBACK, loopback)
01228 __ADD(IFF_BROADCAST, broadcast)
01229 __ADD(IFF_POINTOPOINT, pointopoint)
01230 __ADD(IFF_MULTICAST, multicast)
01231 __ADD(IFF_NOARP, noarp)
01232 __ADD(IFF_ALLMULTI, allmulti)
01233 __ADD(IFF_PROMISC, promisc)
01234 __ADD(IFF_MASTER, master)
01235 __ADD(IFF_SLAVE, slave)
01236 __ADD(IFF_DEBUG, debug)
01237 __ADD(IFF_DYNAMIC, dynamic)
01238 __ADD(IFF_AUTOMEDIA, automedia)
01239 __ADD(IFF_PORTSEL, portsel)
01240 __ADD(IFF_NOTRAILERS, notrailers)
01241 __ADD(IFF_UP, up)
01242 __ADD(IFF_RUNNING, running)
01243 __ADD(IFF_LOWER_UP, lowerup)
01244 __ADD(IFF_DORMANT, dormant)
01245 __ADD(IFF_ECHO, echo)
01246 };
01247
01248 char * rtnl_link_flags2str(int flags, char *buf, size_t len)
01249 {
01250 return __flags2str(flags, buf, len, link_flags,
01251 ARRAY_SIZE(link_flags));
01252 }
01253
01254 int rtnl_link_str2flags(const char *name)
01255 {
01256 return __str2flags(name, link_flags, ARRAY_SIZE(link_flags));
01257 }
01258
01259
01260
01261
01262
01263
01264
01265
01266 static const struct trans_tbl link_stats[] = {
01267 __ADD(RTNL_LINK_RX_PACKETS, rx_packets)
01268 __ADD(RTNL_LINK_TX_PACKETS, tx_packets)
01269 __ADD(RTNL_LINK_RX_BYTES, rx_bytes)
01270 __ADD(RTNL_LINK_TX_BYTES, tx_bytes)
01271 __ADD(RTNL_LINK_RX_ERRORS, rx_errors)
01272 __ADD(RTNL_LINK_TX_ERRORS, tx_errors)
01273 __ADD(RTNL_LINK_RX_DROPPED, rx_dropped)
01274 __ADD(RTNL_LINK_TX_DROPPED, tx_dropped)
01275 __ADD(RTNL_LINK_RX_COMPRESSED, rx_compressed)
01276 __ADD(RTNL_LINK_TX_COMPRESSED, tx_compressed)
01277 __ADD(RTNL_LINK_RX_FIFO_ERR, rx_fifo_err)
01278 __ADD(RTNL_LINK_TX_FIFO_ERR, tx_fifo_err)
01279 __ADD(RTNL_LINK_RX_LEN_ERR, rx_len_err)
01280 __ADD(RTNL_LINK_RX_OVER_ERR, rx_over_err)
01281 __ADD(RTNL_LINK_RX_CRC_ERR, rx_crc_err)
01282 __ADD(RTNL_LINK_RX_FRAME_ERR, rx_frame_err)
01283 __ADD(RTNL_LINK_RX_MISSED_ERR, rx_missed_err)
01284 __ADD(RTNL_LINK_TX_ABORT_ERR, tx_abort_err)
01285 __ADD(RTNL_LINK_TX_CARRIER_ERR, tx_carrier_err)
01286 __ADD(RTNL_LINK_TX_HBEAT_ERR, tx_hbeat_err)
01287 __ADD(RTNL_LINK_TX_WIN_ERR, tx_win_err)
01288 __ADD(RTNL_LINK_COLLISIONS, collisions)
01289 __ADD(RTNL_LINK_MULTICAST, multicast)
01290 __ADD(RTNL_LINK_IP6_INPKTS, Ip6InReceives)
01291 __ADD(RTNL_LINK_IP6_INHDRERRORS, Ip6InHdrErrors)
01292 __ADD(RTNL_LINK_IP6_INTOOBIGERRORS, Ip6InTooBigErrors)
01293 __ADD(RTNL_LINK_IP6_INNOROUTES, Ip6InNoRoutes)
01294 __ADD(RTNL_LINK_IP6_INADDRERRORS, Ip6InAddrErrors)
01295 __ADD(RTNL_LINK_IP6_INUNKNOWNPROTOS, Ip6InUnknownProtos)
01296 __ADD(RTNL_LINK_IP6_INTRUNCATEDPKTS, Ip6InTruncatedPkts)
01297 __ADD(RTNL_LINK_IP6_INDISCARDS, Ip6InDiscards)
01298 __ADD(RTNL_LINK_IP6_INDELIVERS, Ip6InDelivers)
01299 __ADD(RTNL_LINK_IP6_OUTFORWDATAGRAMS, Ip6OutForwDatagrams)
01300 __ADD(RTNL_LINK_IP6_OUTPKTS, Ip6OutRequests)
01301 __ADD(RTNL_LINK_IP6_OUTDISCARDS, Ip6OutDiscards)
01302 __ADD(RTNL_LINK_IP6_OUTNOROUTES, Ip6OutNoRoutes)
01303 __ADD(RTNL_LINK_IP6_REASMTIMEOUT, Ip6ReasmTimeout)
01304 __ADD(RTNL_LINK_IP6_REASMREQDS, Ip6ReasmReqds)
01305 __ADD(RTNL_LINK_IP6_REASMOKS, Ip6ReasmOKs)
01306 __ADD(RTNL_LINK_IP6_REASMFAILS, Ip6ReasmFails)
01307 __ADD(RTNL_LINK_IP6_FRAGOKS, Ip6FragOKs)
01308 __ADD(RTNL_LINK_IP6_FRAGFAILS, Ip6FragFails)
01309 __ADD(RTNL_LINK_IP6_FRAGCREATES, Ip6FragCreates)
01310 __ADD(RTNL_LINK_IP6_INMCASTPKTS, Ip6InMcastPkts)
01311 __ADD(RTNL_LINK_IP6_OUTMCASTPKTS, Ip6OutMcastPkts)
01312 __ADD(RTNL_LINK_IP6_INBCASTPKTS, Ip6InBcastPkts)
01313 __ADD(RTNL_LINK_IP6_OUTBCASTPKTS, Ip6OutBcastPkts)
01314 __ADD(RTNL_LINK_IP6_INOCTETS, Ip6InOctets)
01315 __ADD(RTNL_LINK_IP6_OUTOCTETS, Ip6OutOctets)
01316 __ADD(RTNL_LINK_IP6_INMCASTOCTETS, Ip6InMcastOctets)
01317 __ADD(RTNL_LINK_IP6_OUTMCASTOCTETS, Ip6OutMcastOctets)
01318 __ADD(RTNL_LINK_IP6_INBCASTOCTETS, Ip6InBcastOctets)
01319 __ADD(RTNL_LINK_IP6_OUTBCASTOCTETS, Ip6OutBcastOctets)
01320 __ADD(RTNL_LINK_ICMP6_INMSGS, ICMP6_InMsgs)
01321 __ADD(RTNL_LINK_ICMP6_INERRORS, ICMP6_InErrors)
01322 __ADD(RTNL_LINK_ICMP6_OUTMSGS, ICMP6_OutMsgs)
01323 __ADD(RTNL_LINK_ICMP6_OUTERRORS, ICMP6_OutErrors)
01324 };
01325
01326 char *rtnl_link_stat2str(int st, char *buf, size_t len)
01327 {
01328 return __type2str(st, buf, len, link_stats, ARRAY_SIZE(link_stats));
01329 }
01330
01331 int rtnl_link_str2stat(const char *name)
01332 {
01333 return __str2type(name, link_stats, ARRAY_SIZE(link_stats));
01334 }
01335
01336
01337
01338
01339
01340
01341
01342
01343 static const struct trans_tbl link_operstates[] = {
01344 __ADD(IF_OPER_UNKNOWN, unknown)
01345 __ADD(IF_OPER_NOTPRESENT, notpresent)
01346 __ADD(IF_OPER_DOWN, down)
01347 __ADD(IF_OPER_LOWERLAYERDOWN, lowerlayerdown)
01348 __ADD(IF_OPER_TESTING, testing)
01349 __ADD(IF_OPER_DORMANT, dormant)
01350 __ADD(IF_OPER_UP, up)
01351 };
01352
01353 char *rtnl_link_operstate2str(int st, char *buf, size_t len)
01354 {
01355 return __type2str(st, buf, len, link_operstates,
01356 ARRAY_SIZE(link_operstates));
01357 }
01358
01359 int rtnl_link_str2operstate(const char *name)
01360 {
01361 return __str2type(name, link_operstates,
01362 ARRAY_SIZE(link_operstates));
01363 }
01364
01365
01366
01367
01368
01369
01370
01371
01372 static const struct trans_tbl link_modes[] = {
01373 __ADD(IF_LINK_MODE_DEFAULT, default)
01374 __ADD(IF_LINK_MODE_DORMANT, dormant)
01375 };
01376
01377 char *rtnl_link_mode2str(int st, char *buf, size_t len)
01378 {
01379 return __type2str(st, buf, len, link_modes, ARRAY_SIZE(link_modes));
01380 }
01381
01382 int rtnl_link_str2mode(const char *name)
01383 {
01384 return __str2type(name, link_modes, ARRAY_SIZE(link_modes));
01385 }
01386
01387
01388
01389
01390
01391
01392
01393
01394 void rtnl_link_set_qdisc(struct rtnl_link *link, const char *qdisc)
01395 {
01396 strncpy(link->l_qdisc, qdisc, sizeof(link->l_qdisc) - 1);
01397 link->ce_mask |= LINK_ATTR_QDISC;
01398 }
01399
01400 char *rtnl_link_get_qdisc(struct rtnl_link *link)
01401 {
01402 if (link->ce_mask & LINK_ATTR_QDISC)
01403 return link->l_qdisc;
01404 else
01405 return NULL;
01406 }
01407
01408 void rtnl_link_set_name(struct rtnl_link *link, const char *name)
01409 {
01410 strncpy(link->l_name, name, sizeof(link->l_name) - 1);
01411 link->ce_mask |= LINK_ATTR_IFNAME;
01412 }
01413
01414 char *rtnl_link_get_name(struct rtnl_link *link)
01415 {
01416 if (link->ce_mask & LINK_ATTR_IFNAME)
01417 return link->l_name;
01418 else
01419 return NULL;
01420 }
01421
01422 static inline void __assign_addr(struct rtnl_link *link, struct nl_addr **pos,
01423 struct nl_addr *new, int flag)
01424 {
01425 if (*pos)
01426 nl_addr_put(*pos);
01427
01428 nl_addr_get(new);
01429 *pos = new;
01430
01431 link->ce_mask |= flag;
01432 }
01433
01434 void rtnl_link_set_addr(struct rtnl_link *link, struct nl_addr *addr)
01435 {
01436 __assign_addr(link, &link->l_addr, addr, LINK_ATTR_ADDR);
01437 }
01438
01439 struct nl_addr *rtnl_link_get_addr(struct rtnl_link *link)
01440 {
01441 if (link->ce_mask & LINK_ATTR_ADDR)
01442 return link->l_addr;
01443 else
01444 return NULL;
01445 }
01446
01447 void rtnl_link_set_broadcast(struct rtnl_link *link, struct nl_addr *brd)
01448 {
01449 __assign_addr(link, &link->l_bcast, brd, LINK_ATTR_BRD);
01450 }
01451
01452 struct nl_addr *rtnl_link_get_broadcast(struct rtnl_link *link)
01453 {
01454 if (link->ce_mask & LINK_ATTR_BRD)
01455 return link->l_bcast;
01456 else
01457 return NULL;
01458 }
01459
01460 void rtnl_link_set_flags(struct rtnl_link *link, unsigned int flags)
01461 {
01462 link->l_flag_mask |= flags;
01463 link->l_flags |= flags;
01464 link->ce_mask |= LINK_ATTR_FLAGS;
01465 }
01466
01467 void rtnl_link_unset_flags(struct rtnl_link *link, unsigned int flags)
01468 {
01469 link->l_flag_mask |= flags;
01470 link->l_flags &= ~flags;
01471 link->ce_mask |= LINK_ATTR_FLAGS;
01472 }
01473
01474 unsigned int rtnl_link_get_flags(struct rtnl_link *link)
01475 {
01476 return link->l_flags;
01477 }
01478
01479 void rtnl_link_set_family(struct rtnl_link *link, int family)
01480 {
01481 link->l_family = family;
01482 link->ce_mask |= LINK_ATTR_FAMILY;
01483 }
01484
01485 int rtnl_link_get_family(struct rtnl_link *link)
01486 {
01487 if (link->ce_mask & LINK_ATTR_FAMILY)
01488 return link->l_family;
01489 else
01490 return AF_UNSPEC;
01491 }
01492
01493 void rtnl_link_set_arptype(struct rtnl_link *link, unsigned int arptype)
01494 {
01495 link->l_arptype = arptype;
01496 }
01497
01498 unsigned int rtnl_link_get_arptype(struct rtnl_link *link)
01499 {
01500 return link->l_arptype;
01501 }
01502
01503 void rtnl_link_set_ifindex(struct rtnl_link *link, int ifindex)
01504 {
01505 link->l_index = ifindex;
01506 link->ce_mask |= LINK_ATTR_IFINDEX;
01507 }
01508
01509 int rtnl_link_get_ifindex(struct rtnl_link *link)
01510 {
01511 return link->l_index;
01512 }
01513
01514 void rtnl_link_set_mtu(struct rtnl_link *link, unsigned int mtu)
01515 {
01516 link->l_mtu = mtu;
01517 link->ce_mask |= LINK_ATTR_MTU;
01518 }
01519
01520 unsigned int rtnl_link_get_mtu(struct rtnl_link *link)
01521 {
01522 if (link->ce_mask & LINK_ATTR_MTU)
01523 return link->l_mtu;
01524 else
01525 return 0;
01526 }
01527
01528 void rtnl_link_set_txqlen(struct rtnl_link *link, unsigned int txqlen)
01529 {
01530 link->l_txqlen = txqlen;
01531 link->ce_mask |= LINK_ATTR_TXQLEN;
01532 }
01533
01534 unsigned int rtnl_link_get_txqlen(struct rtnl_link *link)
01535 {
01536 if (link->ce_mask & LINK_ATTR_TXQLEN)
01537 return link->l_txqlen;
01538 else
01539 return UINT_MAX;
01540 }
01541
01542 void rtnl_link_set_weight(struct rtnl_link *link, unsigned int weight)
01543 {
01544 link->l_weight = weight;
01545 link->ce_mask |= LINK_ATTR_WEIGHT;
01546 }
01547
01548 unsigned int rtnl_link_get_weight(struct rtnl_link *link)
01549 {
01550 if (link->ce_mask & LINK_ATTR_WEIGHT)
01551 return link->l_weight;
01552 else
01553 return UINT_MAX;
01554 }
01555
01556 void rtnl_link_set_link(struct rtnl_link *link, int ifindex)
01557 {
01558 link->l_link = ifindex;
01559 link->ce_mask |= LINK_ATTR_LINK;
01560 }
01561
01562 int rtnl_link_get_link(struct rtnl_link *link)
01563 {
01564 return link->l_link;
01565 }
01566
01567 void rtnl_link_set_master(struct rtnl_link *link, int ifindex)
01568 {
01569 link->l_master = ifindex;
01570 link->ce_mask |= LINK_ATTR_MASTER;
01571 }
01572
01573 int rtnl_link_get_master(struct rtnl_link *link)
01574 {
01575 return link->l_master;
01576 }
01577
01578 void rtnl_link_set_operstate(struct rtnl_link *link, uint8_t operstate)
01579 {
01580 link->l_operstate = operstate;
01581 link->ce_mask |= LINK_ATTR_OPERSTATE;
01582 }
01583
01584 uint8_t rtnl_link_get_operstate(struct rtnl_link *link)
01585 {
01586 if (link->ce_mask & LINK_ATTR_OPERSTATE)
01587 return link->l_operstate;
01588 else
01589 return IF_OPER_UNKNOWN;
01590 }
01591
01592 void rtnl_link_set_linkmode(struct rtnl_link *link, uint8_t linkmode)
01593 {
01594 link->l_linkmode = linkmode;
01595 link->ce_mask |= LINK_ATTR_LINKMODE;
01596 }
01597
01598 uint8_t rtnl_link_get_linkmode(struct rtnl_link *link)
01599 {
01600 if (link->ce_mask & LINK_ATTR_LINKMODE)
01601 return link->l_linkmode;
01602 else
01603 return IF_LINK_MODE_DEFAULT;
01604 }
01605
01606
01607
01608
01609
01610
01611
01612 const char *rtnl_link_get_ifalias(struct rtnl_link *link)
01613 {
01614 return link->l_ifalias;
01615 }
01616
01617
01618
01619
01620
01621
01622
01623
01624
01625
01626 void rtnl_link_set_ifalias(struct rtnl_link *link, const char *alias)
01627 {
01628 free(link->l_ifalias);
01629 link->ce_mask &= ~LINK_ATTR_IFALIAS;
01630
01631 if (alias) {
01632 link->l_ifalias = strdup(alias);
01633 link->ce_mask |= LINK_ATTR_IFALIAS;
01634 }
01635 }
01636
01637
01638
01639
01640
01641
01642
01643
01644 int rtnl_link_get_num_vf(struct rtnl_link *link, uint32_t *num_vf)
01645 {
01646 if (link->ce_mask & LINK_ATTR_NUM_VF) {
01647 *num_vf = link->l_num_vf;
01648 return 0;
01649 } else
01650 return -NLE_OPNOTSUPP;
01651 }
01652
01653 uint64_t rtnl_link_get_stat(struct rtnl_link *link, int id)
01654 {
01655 if (id < 0 || id > RTNL_LINK_STATS_MAX)
01656 return 0;
01657
01658 return link->l_stats[id];
01659 }
01660
01661
01662
01663
01664
01665
01666
01667
01668
01669 int rtnl_link_set_stat(struct rtnl_link *link, const unsigned int id,
01670 const uint64_t value)
01671 {
01672 if (id > RTNL_LINK_STATS_MAX)
01673 return -NLE_INVAL;
01674
01675 link->l_stats[id] = value;
01676
01677 return 0;
01678 }
01679
01680
01681
01682
01683
01684
01685
01686
01687
01688
01689
01690
01691 int rtnl_link_set_info_type(struct rtnl_link *link, const char *type)
01692 {
01693 struct rtnl_link_info_ops *io;
01694 int err;
01695
01696 if ((io = rtnl_link_info_ops_lookup(type)) == NULL)
01697 return -NLE_OPNOTSUPP;
01698
01699 if (link->l_info_ops)
01700 release_link_info(link);
01701
01702 if ((err = io->io_alloc(link)) < 0)
01703 return err;
01704
01705 link->l_info_ops = io;
01706
01707 return 0;
01708 }
01709
01710
01711
01712
01713
01714
01715
01716
01717 char *rtnl_link_get_info_type(struct rtnl_link *link)
01718 {
01719 if (link->l_info_ops)
01720 return link->l_info_ops->io_name;
01721 else
01722 return NULL;
01723 }
01724
01725
01726
01727 static struct nl_object_ops link_obj_ops = {
01728 .oo_name = "route/link",
01729 .oo_size = sizeof(struct rtnl_link),
01730 .oo_free_data = link_free_data,
01731 .oo_clone = link_clone,
01732 .oo_dump = {
01733 [NL_DUMP_LINE] = link_dump_line,
01734 [NL_DUMP_DETAILS] = link_dump_details,
01735 [NL_DUMP_STATS] = link_dump_stats,
01736 },
01737 .oo_compare = link_compare,
01738 .oo_attrs2str = link_attrs2str,
01739 .oo_id_attrs = LINK_ATTR_IFINDEX,
01740 };
01741
01742 static struct nl_af_group link_groups[] = {
01743 { AF_UNSPEC, RTNLGRP_LINK },
01744 { END_OF_GROUP_LIST },
01745 };
01746
01747 static struct nl_cache_ops rtnl_link_ops = {
01748 .co_name = "route/link",
01749 .co_hdrsize = sizeof(struct ifinfomsg),
01750 .co_msgtypes = {
01751 { RTM_NEWLINK, NL_ACT_NEW, "new" },
01752 { RTM_DELLINK, NL_ACT_DEL, "del" },
01753 { RTM_GETLINK, NL_ACT_GET, "get" },
01754 { RTM_SETLINK, NL_ACT_CHANGE, "set" },
01755 END_OF_MSGTYPES_LIST,
01756 },
01757 .co_protocol = NETLINK_ROUTE,
01758 .co_groups = link_groups,
01759 .co_request_update = link_request_update,
01760 .co_msg_parser = link_msg_parser,
01761 .co_obj_ops = &link_obj_ops,
01762 };
01763
01764 static void __init link_init(void)
01765 {
01766 nl_cache_mngt_register(&rtnl_link_ops);
01767 }
01768
01769 static void __exit link_exit(void)
01770 {
01771 nl_cache_mngt_unregister(&rtnl_link_ops);
01772 }
01773
01774