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