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