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/info-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
00180 static struct nl_cache_ops rtnl_link_ops;
00181 static struct nl_object_ops link_obj_ops;
00182
00183
00184 static void release_link_info(struct rtnl_link *link)
00185 {
00186 struct rtnl_link_info_ops *io = link->l_info_ops;
00187
00188 if (io != NULL) {
00189 io->io_refcnt--;
00190 io->io_free(link);
00191 link->l_info_ops = NULL;
00192 }
00193 }
00194
00195 static void link_free_data(struct nl_object *c)
00196 {
00197 struct rtnl_link *link = nl_object_priv(c);
00198
00199 if (link) {
00200 struct rtnl_link_info_ops *io;
00201
00202 if ((io = link->l_info_ops) != NULL)
00203 release_link_info(link);
00204
00205 nl_addr_put(link->l_addr);
00206 nl_addr_put(link->l_bcast);
00207 }
00208 }
00209
00210 static int link_clone(struct nl_object *_dst, struct nl_object *_src)
00211 {
00212 struct rtnl_link *dst = nl_object_priv(_dst);
00213 struct rtnl_link *src = nl_object_priv(_src);
00214 int err;
00215
00216 if (src->l_addr)
00217 if (!(dst->l_addr = nl_addr_clone(src->l_addr)))
00218 return -NLE_NOMEM;
00219
00220 if (src->l_bcast)
00221 if (!(dst->l_bcast = nl_addr_clone(src->l_bcast)))
00222 return -NLE_NOMEM;
00223
00224 if (src->l_info_ops && src->l_info_ops->io_clone) {
00225 err = src->l_info_ops->io_clone(dst, src);
00226 if (err < 0)
00227 return err;
00228 }
00229
00230 return 0;
00231 }
00232
00233 static struct nla_policy link_policy[IFLA_MAX+1] = {
00234 [IFLA_IFNAME] = { .type = NLA_STRING,
00235 .maxlen = IFNAMSIZ },
00236 [IFLA_MTU] = { .type = NLA_U32 },
00237 [IFLA_TXQLEN] = { .type = NLA_U32 },
00238 [IFLA_LINK] = { .type = NLA_U32 },
00239 [IFLA_WEIGHT] = { .type = NLA_U32 },
00240 [IFLA_MASTER] = { .type = NLA_U32 },
00241 [IFLA_OPERSTATE]= { .type = NLA_U8 },
00242 [IFLA_LINKMODE] = { .type = NLA_U8 },
00243 [IFLA_LINKINFO] = { .type = NLA_NESTED },
00244 [IFLA_QDISC] = { .type = NLA_STRING,
00245 .maxlen = IFQDISCSIZ },
00246 [IFLA_STATS] = { .minlen = sizeof(struct rtnl_link_stats) },
00247 [IFLA_MAP] = { .minlen = sizeof(struct rtnl_link_ifmap) },
00248 };
00249
00250 static struct nla_policy link_info_policy[IFLA_INFO_MAX+1] = {
00251 [IFLA_INFO_KIND] = { .type = NLA_STRING },
00252 [IFLA_INFO_DATA] = { .type = NLA_NESTED },
00253 [IFLA_INFO_XSTATS] = { .type = NLA_NESTED },
00254 };
00255
00256 static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
00257 struct nlmsghdr *n, struct nl_parser_param *pp)
00258 {
00259 struct rtnl_link *link;
00260 struct ifinfomsg *ifi;
00261 struct nlattr *tb[IFLA_MAX+1];
00262 int err;
00263
00264 link = rtnl_link_alloc();
00265 if (link == NULL) {
00266 err = -NLE_NOMEM;
00267 goto errout;
00268 }
00269
00270 link->ce_msgtype = n->nlmsg_type;
00271
00272 err = nlmsg_parse(n, sizeof(*ifi), tb, IFLA_MAX, link_policy);
00273 if (err < 0)
00274 goto errout;
00275
00276 if (tb[IFLA_IFNAME] == NULL) {
00277 err = -NLE_MISSING_ATTR;
00278 goto errout;
00279 }
00280
00281 nla_strlcpy(link->l_name, tb[IFLA_IFNAME], IFNAMSIZ);
00282
00283 ifi = nlmsg_data(n);
00284 link->l_family = ifi->ifi_family;
00285 link->l_arptype = ifi->ifi_type;
00286 link->l_index = ifi->ifi_index;
00287 link->l_flags = ifi->ifi_flags;
00288 link->l_change = ifi->ifi_change;
00289 link->ce_mask = (LINK_ATTR_IFNAME | LINK_ATTR_FAMILY |
00290 LINK_ATTR_ARPTYPE| LINK_ATTR_IFINDEX |
00291 LINK_ATTR_FLAGS | LINK_ATTR_CHANGE);
00292
00293 if (tb[IFLA_STATS]) {
00294 struct rtnl_link_stats *st = nla_data(tb[IFLA_STATS]);
00295
00296 link->l_stats[RTNL_LINK_RX_PACKETS] = st->rx_packets;
00297 link->l_stats[RTNL_LINK_RX_BYTES] = st->rx_bytes;
00298 link->l_stats[RTNL_LINK_RX_ERRORS] = st->rx_errors;
00299 link->l_stats[RTNL_LINK_RX_DROPPED] = st->rx_dropped;
00300 link->l_stats[RTNL_LINK_RX_COMPRESSED] = st->rx_compressed;
00301 link->l_stats[RTNL_LINK_RX_FIFO_ERR] = st->rx_fifo_errors;
00302 link->l_stats[RTNL_LINK_TX_PACKETS] = st->tx_packets;
00303 link->l_stats[RTNL_LINK_TX_BYTES] = st->tx_bytes;
00304 link->l_stats[RTNL_LINK_TX_ERRORS] = st->tx_errors;
00305 link->l_stats[RTNL_LINK_TX_DROPPED] = st->tx_dropped;
00306 link->l_stats[RTNL_LINK_TX_COMPRESSED] = st->tx_compressed;
00307 link->l_stats[RTNL_LINK_TX_FIFO_ERR] = st->tx_fifo_errors;
00308 link->l_stats[RTNL_LINK_RX_LEN_ERR] = st->rx_length_errors;
00309 link->l_stats[RTNL_LINK_RX_OVER_ERR] = st->rx_over_errors;
00310 link->l_stats[RTNL_LINK_RX_CRC_ERR] = st->rx_crc_errors;
00311 link->l_stats[RTNL_LINK_RX_FRAME_ERR] = st->rx_frame_errors;
00312 link->l_stats[RTNL_LINK_RX_MISSED_ERR] = st->rx_missed_errors;
00313 link->l_stats[RTNL_LINK_TX_ABORT_ERR] = st->tx_aborted_errors;
00314 link->l_stats[RTNL_LINK_TX_CARRIER_ERR] = st->tx_carrier_errors;
00315 link->l_stats[RTNL_LINK_TX_HBEAT_ERR] = st->tx_heartbeat_errors;
00316 link->l_stats[RTNL_LINK_TX_WIN_ERR] = st->tx_window_errors;
00317 link->l_stats[RTNL_LINK_MULTICAST] = st->multicast;
00318
00319 link->ce_mask |= LINK_ATTR_STATS;
00320 }
00321
00322 if (tb[IFLA_TXQLEN]) {
00323 link->l_txqlen = nla_get_u32(tb[IFLA_TXQLEN]);
00324 link->ce_mask |= LINK_ATTR_TXQLEN;
00325 }
00326
00327 if (tb[IFLA_MTU]) {
00328 link->l_mtu = nla_get_u32(tb[IFLA_MTU]);
00329 link->ce_mask |= LINK_ATTR_MTU;
00330 }
00331
00332 if (tb[IFLA_ADDRESS]) {
00333 link->l_addr = nl_addr_alloc_attr(tb[IFLA_ADDRESS], AF_UNSPEC);
00334 if (link->l_addr == NULL) {
00335 err = -NLE_NOMEM;
00336 goto errout;
00337 }
00338 nl_addr_set_family(link->l_addr,
00339 nl_addr_guess_family(link->l_addr));
00340 link->ce_mask |= LINK_ATTR_ADDR;
00341 }
00342
00343 if (tb[IFLA_BROADCAST]) {
00344 link->l_bcast = nl_addr_alloc_attr(tb[IFLA_BROADCAST],
00345 AF_UNSPEC);
00346 if (link->l_bcast == NULL) {
00347 err = -NLE_NOMEM;
00348 goto errout;
00349 }
00350 nl_addr_set_family(link->l_bcast,
00351 nl_addr_guess_family(link->l_bcast));
00352 link->ce_mask |= LINK_ATTR_BRD;
00353 }
00354
00355 if (tb[IFLA_LINK]) {
00356 link->l_link = nla_get_u32(tb[IFLA_LINK]);
00357 link->ce_mask |= LINK_ATTR_LINK;
00358 }
00359
00360 if (tb[IFLA_WEIGHT]) {
00361 link->l_weight = nla_get_u32(tb[IFLA_WEIGHT]);
00362 link->ce_mask |= LINK_ATTR_WEIGHT;
00363 }
00364
00365 if (tb[IFLA_QDISC]) {
00366 nla_strlcpy(link->l_qdisc, tb[IFLA_QDISC], IFQDISCSIZ);
00367 link->ce_mask |= LINK_ATTR_QDISC;
00368 }
00369
00370 if (tb[IFLA_MAP]) {
00371 nla_memcpy(&link->l_map, tb[IFLA_MAP],
00372 sizeof(struct rtnl_link_ifmap));
00373 link->ce_mask |= LINK_ATTR_MAP;
00374 }
00375
00376 if (tb[IFLA_MASTER]) {
00377 link->l_master = nla_get_u32(tb[IFLA_MASTER]);
00378 link->ce_mask |= LINK_ATTR_MASTER;
00379 }
00380
00381 if (tb[IFLA_OPERSTATE]) {
00382 link->l_operstate = nla_get_u8(tb[IFLA_OPERSTATE]);
00383 link->ce_mask |= LINK_ATTR_OPERSTATE;
00384 }
00385
00386 if (tb[IFLA_LINKMODE]) {
00387 link->l_linkmode = nla_get_u8(tb[IFLA_LINKMODE]);
00388 link->ce_mask |= LINK_ATTR_LINKMODE;
00389 }
00390
00391 if (tb[IFLA_LINKINFO]) {
00392 struct nlattr *li[IFLA_INFO_MAX+1];
00393
00394 err = nla_parse_nested(li, IFLA_INFO_MAX, tb[IFLA_LINKINFO],
00395 link_info_policy);
00396 if (err < 0)
00397 goto errout;
00398
00399 if (li[IFLA_INFO_KIND] &&
00400 (li[IFLA_INFO_DATA] || li[IFLA_INFO_XSTATS])) {
00401 struct rtnl_link_info_ops *ops;
00402 char *kind;
00403
00404 kind = nla_get_string(li[IFLA_INFO_KIND]);
00405 ops = rtnl_link_info_ops_lookup(kind);
00406 if (ops != NULL) {
00407 ops->io_refcnt++;
00408 link->l_info_ops = ops;
00409 err = ops->io_parse(link, li[IFLA_INFO_DATA],
00410 li[IFLA_INFO_XSTATS]);
00411 if (err < 0)
00412 goto errout;
00413 } else {
00414
00415 }
00416 }
00417 }
00418
00419 err = pp->pp_cb((struct nl_object *) link, pp);
00420 errout:
00421 rtnl_link_put(link);
00422 return err;
00423 }
00424
00425 static int link_request_update(struct nl_cache *cache, struct nl_sock *sk)
00426 {
00427 return nl_rtgen_request(sk, RTM_GETLINK, AF_UNSPEC, NLM_F_DUMP);
00428 }
00429
00430 static void link_dump_line(struct nl_object *obj, struct nl_dump_params *p)
00431 {
00432 char buf[128];
00433 struct nl_cache *cache = dp_cache(obj);
00434 struct rtnl_link *link = (struct rtnl_link *) obj;
00435
00436 nl_dump_line(p, "%s %s ", link->l_name,
00437 nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
00438
00439 if (link->l_addr && !nl_addr_iszero(link->l_addr))
00440 nl_dump(p, "%s ", nl_addr2str(link->l_addr, buf, sizeof(buf)));
00441
00442 if (link->ce_mask & LINK_ATTR_MASTER) {
00443 struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
00444 nl_dump(p, "master %s ", master ? master->l_name : "inv");
00445 if (master)
00446 rtnl_link_put(master);
00447 }
00448
00449 rtnl_link_flags2str(link->l_flags, buf, sizeof(buf));
00450 if (buf[0])
00451 nl_dump(p, "<%s> ", buf);
00452
00453 if (link->ce_mask & LINK_ATTR_LINK) {
00454 struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
00455 nl_dump(p, "slave-of %s ", ll ? ll->l_name : "NONE");
00456 if (ll)
00457 rtnl_link_put(ll);
00458 }
00459
00460 if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_LINE])
00461 link->l_info_ops->io_dump[NL_DUMP_LINE](link, p);
00462
00463 nl_dump(p, "\n");
00464 }
00465
00466 static void link_dump_details(struct nl_object *obj, struct nl_dump_params *p)
00467 {
00468 struct rtnl_link *link = (struct rtnl_link *) obj;
00469 char buf[64];
00470
00471 link_dump_line(obj, p);
00472
00473 nl_dump_line(p, " mtu %u ", link->l_mtu);
00474 nl_dump(p, "txqlen %u weight %u ", link->l_txqlen, link->l_weight);
00475
00476 if (link->ce_mask & LINK_ATTR_QDISC)
00477 nl_dump(p, "qdisc %s ", link->l_qdisc);
00478
00479 if (link->ce_mask & LINK_ATTR_MAP && link->l_map.lm_irq)
00480 nl_dump(p, "irq %u ", link->l_map.lm_irq);
00481
00482 if (link->ce_mask & LINK_ATTR_IFINDEX)
00483 nl_dump(p, "index %u ", link->l_index);
00484
00485
00486 nl_dump(p, "\n");
00487 nl_dump_line(p, " ");
00488
00489 if (link->ce_mask & LINK_ATTR_BRD)
00490 nl_dump(p, "brd %s ", nl_addr2str(link->l_bcast, buf,
00491 sizeof(buf)));
00492
00493 if ((link->ce_mask & LINK_ATTR_OPERSTATE) &&
00494 link->l_operstate != IF_OPER_UNKNOWN) {
00495 rtnl_link_operstate2str(link->l_operstate, buf, sizeof(buf));
00496 nl_dump(p, "state %s ", buf);
00497 }
00498
00499 nl_dump(p, "mode %s\n",
00500 rtnl_link_mode2str(link->l_linkmode, buf, sizeof(buf)));
00501
00502 if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_DETAILS])
00503 link->l_info_ops->io_dump[NL_DUMP_DETAILS](link, p);
00504 }
00505
00506 static void link_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
00507 {
00508 struct rtnl_link *link = (struct rtnl_link *) obj;
00509 char *unit, fmt[64];
00510 float res;
00511
00512 link_dump_details(obj, p);
00513
00514 nl_dump_line(p, " Stats: bytes packets errors "
00515 " dropped fifo-err compressed\n");
00516
00517 res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_RX_BYTES], &unit);
00518
00519 strcpy(fmt, " RX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n");
00520 fmt[9] = *unit == 'B' ? '9' : '7';
00521
00522 nl_dump_line(p, fmt, res, unit,
00523 link->l_stats[RTNL_LINK_RX_PACKETS],
00524 link->l_stats[RTNL_LINK_RX_ERRORS],
00525 link->l_stats[RTNL_LINK_RX_DROPPED],
00526 link->l_stats[RTNL_LINK_RX_FIFO_ERR],
00527 link->l_stats[RTNL_LINK_RX_COMPRESSED]);
00528
00529 res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_TX_BYTES], &unit);
00530
00531 strcpy(fmt, " TX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n");
00532 fmt[9] = *unit == 'B' ? '9' : '7';
00533
00534 nl_dump_line(p, fmt, res, unit,
00535 link->l_stats[RTNL_LINK_TX_PACKETS],
00536 link->l_stats[RTNL_LINK_TX_ERRORS],
00537 link->l_stats[RTNL_LINK_TX_DROPPED],
00538 link->l_stats[RTNL_LINK_TX_FIFO_ERR],
00539 link->l_stats[RTNL_LINK_TX_COMPRESSED]);
00540
00541 nl_dump_line(p, " Errors: length over crc "
00542 " frame missed multicast\n");
00543
00544 nl_dump_line(p, " RX %10" PRIu64 " %10" PRIu64 " %10"
00545 PRIu64 " %10" PRIu64 " %10" PRIu64 " %10"
00546 PRIu64 "\n",
00547 link->l_stats[RTNL_LINK_RX_LEN_ERR],
00548 link->l_stats[RTNL_LINK_RX_OVER_ERR],
00549 link->l_stats[RTNL_LINK_RX_CRC_ERR],
00550 link->l_stats[RTNL_LINK_RX_FRAME_ERR],
00551 link->l_stats[RTNL_LINK_RX_MISSED_ERR],
00552 link->l_stats[RTNL_LINK_MULTICAST]);
00553
00554 nl_dump_line(p, " aborted carrier heartbeat "
00555 " window collision\n");
00556
00557 nl_dump_line(p, " TX %10" PRIu64 " %10" PRIu64 " %10"
00558 PRIu64 " %10" PRIu64 " %10" PRIu64 "\n",
00559 link->l_stats[RTNL_LINK_TX_ABORT_ERR],
00560 link->l_stats[RTNL_LINK_TX_CARRIER_ERR],
00561 link->l_stats[RTNL_LINK_TX_HBEAT_ERR],
00562 link->l_stats[RTNL_LINK_TX_WIN_ERR],
00563 link->l_stats[RTNL_LINK_TX_COLLISIONS]);
00564
00565 if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_STATS])
00566 link->l_info_ops->io_dump[NL_DUMP_STATS](link, p);
00567 }
00568
00569 static void link_dump_env(struct nl_object *obj, struct nl_dump_params *p)
00570 {
00571 struct rtnl_link *link = (struct rtnl_link *) obj;
00572 struct nl_cache *cache = dp_cache(obj);
00573 char buf[128];
00574 int i;
00575
00576 nl_dump_line(p, "LINK_NAME=%s\n", link->l_name);
00577 nl_dump_line(p, "LINK_IFINDEX=%u\n", link->l_index);
00578 nl_dump_line(p, "LINK_FAMILY=%s\n",
00579 nl_af2str(link->l_family, buf, sizeof(buf)));
00580 nl_dump_line(p, "LINK_TYPE=%s\n",
00581 nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
00582 if (link->ce_mask & LINK_ATTR_ADDR)
00583 nl_dump_line(p, "LINK_ADDRESS=%s\n",
00584 nl_addr2str(link->l_addr, buf, sizeof(buf)));
00585 nl_dump_line(p, "LINK_MTU=%u\n", link->l_mtu);
00586 nl_dump_line(p, "LINK_TXQUEUELEN=%u\n", link->l_txqlen);
00587 nl_dump_line(p, "LINK_WEIGHT=%u\n", link->l_weight);
00588
00589 rtnl_link_flags2str(link->l_flags & ~IFF_RUNNING, buf, sizeof(buf));
00590 if (buf[0])
00591 nl_dump_line(p, "LINK_FLAGS=%s\n", buf);
00592
00593 if (link->ce_mask & LINK_ATTR_QDISC)
00594 nl_dump_line(p, "LINK_QDISC=%s\n", link->l_qdisc);
00595
00596 if (link->ce_mask & LINK_ATTR_LINK) {
00597 struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
00598
00599 nl_dump_line(p, "LINK_LINK_IFINDEX=%d\n", link->l_link);
00600 if (ll) {
00601 nl_dump_line(p, "LINK_LINK_IFNAME=%s\n", ll->l_name);
00602 rtnl_link_put(ll);
00603 }
00604 }
00605
00606 if (link->ce_mask & LINK_ATTR_MASTER) {
00607 struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
00608 nl_dump_line(p, "LINK_MASTER=%s\n",
00609 master ? master->l_name : "none");
00610 if (master)
00611 rtnl_link_put(master);
00612 }
00613
00614 if (link->ce_mask & LINK_ATTR_BRD)
00615 nl_dump_line(p, "LINK_BROADCAST=%s\n",
00616 nl_addr2str(link->l_bcast, buf, sizeof(buf)));
00617
00618 if (link->ce_mask & LINK_ATTR_STATS) {
00619 for (i = 0; i <= RTNL_LINK_STATS_MAX; i++) {
00620 char *c = buf;
00621
00622 sprintf(buf, "LINK_");
00623 rtnl_link_stat2str(i, buf + 5, sizeof(buf) - 5);
00624 while (*c) {
00625 *c = toupper(*c);
00626 c++;
00627 }
00628 nl_dump_line(p, "%s=%" PRIu64 "\n", buf, link->l_stats[i]);
00629 }
00630 }
00631
00632 if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_ENV])
00633 link->l_info_ops->io_dump[NL_DUMP_ENV](link, p);
00634 }
00635
00636 #if 0
00637 static int link_handle_event(struct nl_object *a, struct rtnl_link_event_cb *cb)
00638 {
00639 struct rtnl_link *l = (struct rtnl_link *) a;
00640 struct nl_cache *c = dp_cache(a);
00641 int nevents = 0;
00642
00643 if (l->l_change == ~0U) {
00644 if (l->ce_msgtype == RTM_NEWLINK)
00645 cb->le_register(l);
00646 else
00647 cb->le_unregister(l);
00648
00649 return 1;
00650 }
00651
00652 if (l->l_change & IFF_SLAVE) {
00653 if (l->l_flags & IFF_SLAVE) {
00654 struct rtnl_link *m = rtnl_link_get(c, l->l_master);
00655 cb->le_new_bonding(l, m);
00656 if (m)
00657 rtnl_link_put(m);
00658 } else
00659 cb->le_cancel_bonding(l);
00660 }
00661
00662 #if 0
00663 if (l->l_change & IFF_UP && l->l_change & IFF_RUNNING)
00664 dp_dump_line(p, line++, "link %s changed state to %s.\n",
00665 l->l_name, l->l_flags & IFF_UP ? "up" : "down");
00666
00667 if (l->l_change & IFF_PROMISC) {
00668 dp_new_line(p, line++);
00669 dp_dump(p, "link %s %s promiscuous mode.\n",
00670 l->l_name, l->l_flags & IFF_PROMISC ? "entered" : "left");
00671 }
00672
00673 if (line == 0)
00674 dp_dump_line(p, line++, "link %s sent unknown event.\n",
00675 l->l_name);
00676 #endif
00677
00678 return nevents;
00679 }
00680 #endif
00681
00682 static int link_compare(struct nl_object *_a, struct nl_object *_b,
00683 uint32_t attrs, int flags)
00684 {
00685 struct rtnl_link *a = (struct rtnl_link *) _a;
00686 struct rtnl_link *b = (struct rtnl_link *) _b;
00687 int diff = 0;
00688
00689 #define LINK_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, LINK_ATTR_##ATTR, a, b, EXPR)
00690
00691 diff |= LINK_DIFF(IFINDEX, a->l_index != b->l_index);
00692 diff |= LINK_DIFF(MTU, a->l_mtu != b->l_mtu);
00693 diff |= LINK_DIFF(LINK, a->l_link != b->l_link);
00694 diff |= LINK_DIFF(TXQLEN, a->l_txqlen != b->l_txqlen);
00695 diff |= LINK_DIFF(WEIGHT, a->l_weight != b->l_weight);
00696 diff |= LINK_DIFF(MASTER, a->l_master != b->l_master);
00697 diff |= LINK_DIFF(FAMILY, a->l_family != b->l_family);
00698 diff |= LINK_DIFF(OPERSTATE, a->l_operstate != b->l_operstate);
00699 diff |= LINK_DIFF(LINKMODE, a->l_linkmode != b->l_linkmode);
00700 diff |= LINK_DIFF(QDISC, strcmp(a->l_qdisc, b->l_qdisc));
00701 diff |= LINK_DIFF(IFNAME, strcmp(a->l_name, b->l_name));
00702 diff |= LINK_DIFF(ADDR, nl_addr_cmp(a->l_addr, b->l_addr));
00703 diff |= LINK_DIFF(BRD, nl_addr_cmp(a->l_bcast, b->l_bcast));
00704
00705 if (flags & LOOSE_COMPARISON)
00706 diff |= LINK_DIFF(FLAGS,
00707 (a->l_flags ^ b->l_flags) & b->l_flag_mask);
00708 else
00709 diff |= LINK_DIFF(FLAGS, a->l_flags != b->l_flags);
00710
00711 #undef LINK_DIFF
00712
00713 return diff;
00714 }
00715
00716 static struct trans_tbl link_attrs[] = {
00717 __ADD(LINK_ATTR_MTU, mtu)
00718 __ADD(LINK_ATTR_LINK, link)
00719 __ADD(LINK_ATTR_TXQLEN, txqlen)
00720 __ADD(LINK_ATTR_WEIGHT, weight)
00721 __ADD(LINK_ATTR_MASTER, master)
00722 __ADD(LINK_ATTR_QDISC, qdisc)
00723 __ADD(LINK_ATTR_MAP, map)
00724 __ADD(LINK_ATTR_ADDR, address)
00725 __ADD(LINK_ATTR_BRD, broadcast)
00726 __ADD(LINK_ATTR_FLAGS, flags)
00727 __ADD(LINK_ATTR_IFNAME, name)
00728 __ADD(LINK_ATTR_IFINDEX, ifindex)
00729 __ADD(LINK_ATTR_FAMILY, family)
00730 __ADD(LINK_ATTR_ARPTYPE, arptype)
00731 __ADD(LINK_ATTR_STATS, stats)
00732 __ADD(LINK_ATTR_CHANGE, change)
00733 __ADD(LINK_ATTR_OPERSTATE, operstate)
00734 __ADD(LINK_ATTR_LINKMODE, linkmode)
00735 };
00736
00737 static char *link_attrs2str(int attrs, char *buf, size_t len)
00738 {
00739 return __flags2str(attrs, buf, len, link_attrs,
00740 ARRAY_SIZE(link_attrs));
00741 }
00742
00743
00744
00745
00746
00747
00748 struct rtnl_link *rtnl_link_alloc(void)
00749 {
00750 return (struct rtnl_link *) nl_object_alloc(&link_obj_ops);
00751 }
00752
00753 void rtnl_link_put(struct rtnl_link *link)
00754 {
00755 nl_object_put((struct nl_object *) link);
00756 }
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776 int rtnl_link_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
00777 {
00778 return nl_cache_alloc_and_fill(&rtnl_link_ops, sk, result);
00779 }
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791 struct rtnl_link *rtnl_link_get(struct nl_cache *cache, int ifindex)
00792 {
00793 struct rtnl_link *link;
00794
00795 if (cache->c_ops != &rtnl_link_ops)
00796 return NULL;
00797
00798 nl_list_for_each_entry(link, &cache->c_items, ce_list) {
00799 if (link->l_index == ifindex) {
00800 nl_object_get((struct nl_object *) link);
00801 return link;
00802 }
00803 }
00804
00805 return NULL;
00806 }
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818 struct rtnl_link *rtnl_link_get_by_name(struct nl_cache *cache,
00819 const char *name)
00820 {
00821 struct rtnl_link *link;
00822
00823 if (cache->c_ops != &rtnl_link_ops)
00824 return NULL;
00825
00826 nl_list_for_each_entry(link, &cache->c_items, ce_list) {
00827 if (!strcmp(name, link->l_name)) {
00828 nl_object_get((struct nl_object *) link);
00829 return link;
00830 }
00831 }
00832
00833 return NULL;
00834 }
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861 int rtnl_link_build_change_request(struct rtnl_link *old,
00862 struct rtnl_link *tmpl, int flags,
00863 struct nl_msg **result)
00864 {
00865 struct nl_msg *msg;
00866 struct ifinfomsg ifi = {
00867 .ifi_family = old->l_family,
00868 .ifi_index = old->l_index,
00869 };
00870
00871 if (tmpl->ce_mask & LINK_ATTR_FLAGS) {
00872 ifi.ifi_flags = old->l_flags & ~tmpl->l_flag_mask;
00873 ifi.ifi_flags |= tmpl->l_flags;
00874 }
00875
00876 msg = nlmsg_alloc_simple(RTM_SETLINK, flags);
00877 if (!msg)
00878 return -NLE_NOMEM;
00879
00880 if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
00881 goto nla_put_failure;
00882
00883 if (tmpl->ce_mask & LINK_ATTR_ADDR)
00884 NLA_PUT_ADDR(msg, IFLA_ADDRESS, tmpl->l_addr);
00885
00886 if (tmpl->ce_mask & LINK_ATTR_BRD)
00887 NLA_PUT_ADDR(msg, IFLA_BROADCAST, tmpl->l_bcast);
00888
00889 if (tmpl->ce_mask & LINK_ATTR_MTU)
00890 NLA_PUT_U32(msg, IFLA_MTU, tmpl->l_mtu);
00891
00892 if (tmpl->ce_mask & LINK_ATTR_TXQLEN)
00893 NLA_PUT_U32(msg, IFLA_TXQLEN, tmpl->l_txqlen);
00894
00895 if (tmpl->ce_mask & LINK_ATTR_WEIGHT)
00896 NLA_PUT_U32(msg, IFLA_WEIGHT, tmpl->l_weight);
00897
00898 if (tmpl->ce_mask & LINK_ATTR_IFNAME)
00899 NLA_PUT_STRING(msg, IFLA_IFNAME, tmpl->l_name);
00900
00901 if (tmpl->ce_mask & LINK_ATTR_OPERSTATE)
00902 NLA_PUT_U8(msg, IFLA_OPERSTATE, tmpl->l_operstate);
00903
00904 if (tmpl->ce_mask & LINK_ATTR_LINKMODE)
00905 NLA_PUT_U8(msg, IFLA_LINKMODE, tmpl->l_linkmode);
00906
00907 if ((tmpl->ce_mask & LINK_ATTR_LINKINFO) && tmpl->l_info_ops &&
00908 tmpl->l_info_ops->io_put_attrs) {
00909 struct nlattr *info;
00910
00911 if (!(info = nla_nest_start(msg, IFLA_LINKINFO)))
00912 goto nla_put_failure;
00913
00914 NLA_PUT_STRING(msg, IFLA_INFO_KIND, tmpl->l_info_ops->io_name);
00915
00916 if (tmpl->l_info_ops->io_put_attrs(msg, tmpl) < 0)
00917 goto nla_put_failure;
00918
00919 nla_nest_end(msg, info);
00920 }
00921
00922 *result = msg;
00923 return 0;
00924
00925 nla_put_failure:
00926 nlmsg_free(msg);
00927 return -NLE_MSGSIZE;
00928 }
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945 int rtnl_link_change(struct nl_sock *sk, struct rtnl_link *old,
00946 struct rtnl_link *tmpl, int flags)
00947 {
00948 struct nl_msg *msg;
00949 int err;
00950
00951 if ((err = rtnl_link_build_change_request(old, tmpl, flags, &msg)) < 0)
00952 return err;
00953
00954 err = nl_send_auto_complete(sk, msg);
00955 nlmsg_free(msg);
00956 if (err < 0)
00957 return err;
00958
00959 return wait_for_ack(sk);
00960 }
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981 char * rtnl_link_i2name(struct nl_cache *cache, int ifindex, char *dst,
00982 size_t len)
00983 {
00984 struct rtnl_link *link = rtnl_link_get(cache, ifindex);
00985
00986 if (link) {
00987 strncpy(dst, link->l_name, len - 1);
00988 rtnl_link_put(link);
00989 return dst;
00990 }
00991
00992 return NULL;
00993 }
00994
00995
00996
00997
00998
00999
01000
01001
01002 int rtnl_link_name2i(struct nl_cache *cache, const char *name)
01003 {
01004 int ifindex = 0;
01005 struct rtnl_link *link;
01006
01007 link = rtnl_link_get_by_name(cache, name);
01008 if (link) {
01009 ifindex = link->l_index;
01010 rtnl_link_put(link);
01011 }
01012
01013 return ifindex;
01014 }
01015
01016
01017
01018
01019
01020
01021
01022
01023 static struct trans_tbl link_flags[] = {
01024 __ADD(IFF_LOOPBACK, loopback)
01025 __ADD(IFF_BROADCAST, broadcast)
01026 __ADD(IFF_POINTOPOINT, pointopoint)
01027 __ADD(IFF_MULTICAST, multicast)
01028 __ADD(IFF_NOARP, noarp)
01029 __ADD(IFF_ALLMULTI, allmulti)
01030 __ADD(IFF_PROMISC, promisc)
01031 __ADD(IFF_MASTER, master)
01032 __ADD(IFF_SLAVE, slave)
01033 __ADD(IFF_DEBUG, debug)
01034 __ADD(IFF_DYNAMIC, dynamic)
01035 __ADD(IFF_AUTOMEDIA, automedia)
01036 __ADD(IFF_PORTSEL, portsel)
01037 __ADD(IFF_NOTRAILERS, notrailers)
01038 __ADD(IFF_UP, up)
01039 __ADD(IFF_RUNNING, running)
01040 __ADD(IFF_LOWER_UP, lowerup)
01041 __ADD(IFF_DORMANT, dormant)
01042 __ADD(IFF_ECHO, echo)
01043 };
01044
01045 char * rtnl_link_flags2str(int flags, char *buf, size_t len)
01046 {
01047 return __flags2str(flags, buf, len, link_flags,
01048 ARRAY_SIZE(link_flags));
01049 }
01050
01051 int rtnl_link_str2flags(const char *name)
01052 {
01053 return __str2flags(name, link_flags, ARRAY_SIZE(link_flags));
01054 }
01055
01056
01057
01058
01059
01060
01061
01062
01063 static struct trans_tbl link_stats[] = {
01064 __ADD(RTNL_LINK_RX_PACKETS, rx_packets)
01065 __ADD(RTNL_LINK_TX_PACKETS, tx_packets)
01066 __ADD(RTNL_LINK_RX_BYTES, rx_bytes)
01067 __ADD(RTNL_LINK_TX_BYTES, tx_bytes)
01068 __ADD(RTNL_LINK_RX_ERRORS, rx_errors)
01069 __ADD(RTNL_LINK_TX_ERRORS, tx_errors)
01070 __ADD(RTNL_LINK_RX_DROPPED, rx_dropped)
01071 __ADD(RTNL_LINK_TX_DROPPED, tx_dropped)
01072 __ADD(RTNL_LINK_RX_COMPRESSED, rx_compressed)
01073 __ADD(RTNL_LINK_TX_COMPRESSED, tx_compressed)
01074 __ADD(RTNL_LINK_RX_FIFO_ERR, rx_fifo_err)
01075 __ADD(RTNL_LINK_TX_FIFO_ERR, tx_fifo_err)
01076 __ADD(RTNL_LINK_RX_LEN_ERR, rx_len_err)
01077 __ADD(RTNL_LINK_RX_OVER_ERR, rx_over_err)
01078 __ADD(RTNL_LINK_RX_CRC_ERR, rx_crc_err)
01079 __ADD(RTNL_LINK_RX_FRAME_ERR, rx_frame_err)
01080 __ADD(RTNL_LINK_RX_MISSED_ERR, rx_missed_err)
01081 __ADD(RTNL_LINK_TX_ABORT_ERR, tx_abort_err)
01082 __ADD(RTNL_LINK_TX_CARRIER_ERR, tx_carrier_err)
01083 __ADD(RTNL_LINK_TX_HBEAT_ERR, tx_hbeat_err)
01084 __ADD(RTNL_LINK_TX_WIN_ERR, tx_win_err)
01085 __ADD(RTNL_LINK_TX_COLLISIONS, tx_collision)
01086 __ADD(RTNL_LINK_MULTICAST, multicast)
01087 };
01088
01089 char *rtnl_link_stat2str(int st, char *buf, size_t len)
01090 {
01091 return __type2str(st, buf, len, link_stats, ARRAY_SIZE(link_stats));
01092 }
01093
01094 int rtnl_link_str2stat(const char *name)
01095 {
01096 return __str2type(name, link_stats, ARRAY_SIZE(link_stats));
01097 }
01098
01099
01100
01101
01102
01103
01104
01105
01106 static struct trans_tbl link_operstates[] = {
01107 __ADD(IF_OPER_UNKNOWN, unknown)
01108 __ADD(IF_OPER_NOTPRESENT, notpresent)
01109 __ADD(IF_OPER_DOWN, down)
01110 __ADD(IF_OPER_LOWERLAYERDOWN, lowerlayerdown)
01111 __ADD(IF_OPER_TESTING, testing)
01112 __ADD(IF_OPER_DORMANT, dormant)
01113 __ADD(IF_OPER_UP, up)
01114 };
01115
01116 char *rtnl_link_operstate2str(int st, char *buf, size_t len)
01117 {
01118 return __type2str(st, buf, len, link_operstates,
01119 ARRAY_SIZE(link_operstates));
01120 }
01121
01122 int rtnl_link_str2operstate(const char *name)
01123 {
01124 return __str2type(name, link_operstates,
01125 ARRAY_SIZE(link_operstates));
01126 }
01127
01128
01129
01130
01131
01132
01133
01134
01135 static struct trans_tbl link_modes[] = {
01136 __ADD(IF_LINK_MODE_DEFAULT, default)
01137 __ADD(IF_LINK_MODE_DORMANT, dormant)
01138 };
01139
01140 char *rtnl_link_mode2str(int st, char *buf, size_t len)
01141 {
01142 return __type2str(st, buf, len, link_modes, ARRAY_SIZE(link_modes));
01143 }
01144
01145 int rtnl_link_str2mode(const char *name)
01146 {
01147 return __str2type(name, link_modes, ARRAY_SIZE(link_modes));
01148 }
01149
01150
01151
01152
01153
01154
01155
01156
01157 void rtnl_link_set_qdisc(struct rtnl_link *link, const char *qdisc)
01158 {
01159 strncpy(link->l_qdisc, qdisc, sizeof(link->l_qdisc) - 1);
01160 link->ce_mask |= LINK_ATTR_QDISC;
01161 }
01162
01163 char *rtnl_link_get_qdisc(struct rtnl_link *link)
01164 {
01165 if (link->ce_mask & LINK_ATTR_QDISC)
01166 return link->l_qdisc;
01167 else
01168 return NULL;
01169 }
01170
01171 void rtnl_link_set_name(struct rtnl_link *link, const char *name)
01172 {
01173 strncpy(link->l_name, name, sizeof(link->l_name) - 1);
01174 link->ce_mask |= LINK_ATTR_IFNAME;
01175 }
01176
01177 char *rtnl_link_get_name(struct rtnl_link *link)
01178 {
01179 if (link->ce_mask & LINK_ATTR_IFNAME)
01180 return link->l_name;
01181 else
01182 return NULL;
01183 }
01184
01185 static inline void __assign_addr(struct rtnl_link *link, struct nl_addr **pos,
01186 struct nl_addr *new, int flag)
01187 {
01188 if (*pos)
01189 nl_addr_put(*pos);
01190
01191 nl_addr_get(new);
01192 *pos = new;
01193
01194 link->ce_mask |= flag;
01195 }
01196
01197 void rtnl_link_set_addr(struct rtnl_link *link, struct nl_addr *addr)
01198 {
01199 __assign_addr(link, &link->l_addr, addr, LINK_ATTR_ADDR);
01200 }
01201
01202 struct nl_addr *rtnl_link_get_addr(struct rtnl_link *link)
01203 {
01204 if (link->ce_mask & LINK_ATTR_ADDR)
01205 return link->l_addr;
01206 else
01207 return NULL;
01208 }
01209
01210 void rtnl_link_set_broadcast(struct rtnl_link *link, struct nl_addr *brd)
01211 {
01212 __assign_addr(link, &link->l_bcast, brd, LINK_ATTR_BRD);
01213 }
01214
01215 struct nl_addr *rtnl_link_get_broadcast(struct rtnl_link *link)
01216 {
01217 if (link->ce_mask & LINK_ATTR_BRD)
01218 return link->l_bcast;
01219 else
01220 return NULL;
01221 }
01222
01223 void rtnl_link_set_flags(struct rtnl_link *link, unsigned int flags)
01224 {
01225 link->l_flag_mask |= flags;
01226 link->l_flags |= flags;
01227 link->ce_mask |= LINK_ATTR_FLAGS;
01228 }
01229
01230 void rtnl_link_unset_flags(struct rtnl_link *link, unsigned int flags)
01231 {
01232 link->l_flag_mask |= flags;
01233 link->l_flags &= ~flags;
01234 link->ce_mask |= LINK_ATTR_FLAGS;
01235 }
01236
01237 unsigned int rtnl_link_get_flags(struct rtnl_link *link)
01238 {
01239 return link->l_flags;
01240 }
01241
01242 void rtnl_link_set_family(struct rtnl_link *link, int family)
01243 {
01244 link->l_family = family;
01245 link->ce_mask |= LINK_ATTR_FAMILY;
01246 }
01247
01248 int rtnl_link_get_family(struct rtnl_link *link)
01249 {
01250 if (link->l_family & LINK_ATTR_FAMILY)
01251 return link->l_family;
01252 else
01253 return AF_UNSPEC;
01254 }
01255
01256 void rtnl_link_set_arptype(struct rtnl_link *link, unsigned int arptype)
01257 {
01258 link->l_arptype = arptype;
01259 }
01260
01261 unsigned int rtnl_link_get_arptype(struct rtnl_link *link)
01262 {
01263 return link->l_arptype;
01264 }
01265
01266 void rtnl_link_set_ifindex(struct rtnl_link *link, int ifindex)
01267 {
01268 link->l_index = ifindex;
01269 link->ce_mask |= LINK_ATTR_IFINDEX;
01270 }
01271
01272 int rtnl_link_get_ifindex(struct rtnl_link *link)
01273 {
01274 return link->l_index;
01275 }
01276
01277 void rtnl_link_set_mtu(struct rtnl_link *link, unsigned int mtu)
01278 {
01279 link->l_mtu = mtu;
01280 link->ce_mask |= LINK_ATTR_MTU;
01281 }
01282
01283 unsigned int rtnl_link_get_mtu(struct rtnl_link *link)
01284 {
01285 if (link->ce_mask & LINK_ATTR_MTU)
01286 return link->l_mtu;
01287 else
01288 return 0;
01289 }
01290
01291 void rtnl_link_set_txqlen(struct rtnl_link *link, unsigned int txqlen)
01292 {
01293 link->l_txqlen = txqlen;
01294 link->ce_mask |= LINK_ATTR_TXQLEN;
01295 }
01296
01297 unsigned int rtnl_link_get_txqlen(struct rtnl_link *link)
01298 {
01299 if (link->ce_mask & LINK_ATTR_TXQLEN)
01300 return link->l_txqlen;
01301 else
01302 return UINT_MAX;
01303 }
01304
01305 void rtnl_link_set_weight(struct rtnl_link *link, unsigned int weight)
01306 {
01307 link->l_weight = weight;
01308 link->ce_mask |= LINK_ATTR_WEIGHT;
01309 }
01310
01311 unsigned int rtnl_link_get_weight(struct rtnl_link *link)
01312 {
01313 if (link->ce_mask & LINK_ATTR_WEIGHT)
01314 return link->l_weight;
01315 else
01316 return UINT_MAX;
01317 }
01318
01319 void rtnl_link_set_link(struct rtnl_link *link, int ifindex)
01320 {
01321 link->l_link = ifindex;
01322 link->ce_mask |= LINK_ATTR_LINK;
01323 }
01324
01325 int rtnl_link_get_link(struct rtnl_link *link)
01326 {
01327 return link->l_link;
01328 }
01329
01330 void rtnl_link_set_master(struct rtnl_link *link, int ifindex)
01331 {
01332 link->l_master = ifindex;
01333 link->ce_mask |= LINK_ATTR_MASTER;
01334 }
01335
01336 int rtnl_link_get_master(struct rtnl_link *link)
01337 {
01338 return link->l_master;
01339 }
01340
01341 void rtnl_link_set_operstate(struct rtnl_link *link, uint8_t operstate)
01342 {
01343 link->l_operstate = operstate;
01344 link->ce_mask |= LINK_ATTR_OPERSTATE;
01345 }
01346
01347 uint8_t rtnl_link_get_operstate(struct rtnl_link *link)
01348 {
01349 if (link->ce_mask & LINK_ATTR_OPERSTATE)
01350 return link->l_operstate;
01351 else
01352 return IF_OPER_UNKNOWN;
01353 }
01354
01355 void rtnl_link_set_linkmode(struct rtnl_link *link, uint8_t linkmode)
01356 {
01357 link->l_linkmode = linkmode;
01358 link->ce_mask |= LINK_ATTR_LINKMODE;
01359 }
01360
01361 uint8_t rtnl_link_get_linkmode(struct rtnl_link *link)
01362 {
01363 if (link->ce_mask & LINK_ATTR_LINKMODE)
01364 return link->l_linkmode;
01365 else
01366 return IF_LINK_MODE_DEFAULT;
01367 }
01368
01369 uint64_t rtnl_link_get_stat(struct rtnl_link *link, int id)
01370 {
01371 if (id < 0 || id > RTNL_LINK_STATS_MAX)
01372 return 0;
01373
01374 return link->l_stats[id];
01375 }
01376
01377
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387
01388 int rtnl_link_set_info_type(struct rtnl_link *link, const char *type)
01389 {
01390 struct rtnl_link_info_ops *io;
01391 int err;
01392
01393 if ((io = rtnl_link_info_ops_lookup(type)) == NULL)
01394 return -NLE_OPNOTSUPP;
01395
01396 if (link->l_info_ops)
01397 release_link_info(link);
01398
01399 if ((err = io->io_alloc(link)) < 0)
01400 return err;
01401
01402 link->l_info_ops = io;
01403
01404 return 0;
01405 }
01406
01407
01408
01409
01410
01411
01412
01413
01414 char *rtnl_link_get_info_type(struct rtnl_link *link)
01415 {
01416 if (link->l_info_ops)
01417 return link->l_info_ops->io_name;
01418 else
01419 return NULL;
01420 }
01421
01422
01423
01424 static struct nl_object_ops link_obj_ops = {
01425 .oo_name = "route/link",
01426 .oo_size = sizeof(struct rtnl_link),
01427 .oo_free_data = link_free_data,
01428 .oo_clone = link_clone,
01429 .oo_dump = {
01430 [NL_DUMP_LINE] = link_dump_line,
01431 [NL_DUMP_DETAILS] = link_dump_details,
01432 [NL_DUMP_STATS] = link_dump_stats,
01433 [NL_DUMP_ENV] = link_dump_env,
01434 },
01435 .oo_compare = link_compare,
01436 .oo_attrs2str = link_attrs2str,
01437 .oo_id_attrs = LINK_ATTR_IFINDEX,
01438 };
01439
01440 static struct nl_af_group link_groups[] = {
01441 { AF_UNSPEC, RTNLGRP_LINK },
01442 { END_OF_GROUP_LIST },
01443 };
01444
01445 static struct nl_cache_ops rtnl_link_ops = {
01446 .co_name = "route/link",
01447 .co_hdrsize = sizeof(struct ifinfomsg),
01448 .co_msgtypes = {
01449 { RTM_NEWLINK, NL_ACT_NEW, "new" },
01450 { RTM_DELLINK, NL_ACT_DEL, "del" },
01451 { RTM_GETLINK, NL_ACT_GET, "get" },
01452 END_OF_MSGTYPES_LIST,
01453 },
01454 .co_protocol = NETLINK_ROUTE,
01455 .co_groups = link_groups,
01456 .co_request_update = link_request_update,
01457 .co_msg_parser = link_msg_parser,
01458 .co_obj_ops = &link_obj_ops,
01459 };
01460
01461 static void __init link_init(void)
01462 {
01463 nl_cache_mngt_register(&rtnl_link_ops);
01464 }
01465
01466 static void __exit link_exit(void)
01467 {
01468 nl_cache_mngt_unregister(&rtnl_link_ops);
01469 }
01470
01471