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