00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <netlink-local.h>
00022 #include <netlink/netlink.h>
00023 #include <netlink/attr.h>
00024 #include <netlink/utils.h>
00025 #include <netlink/object.h>
00026 #include <netlink/route/rtnl.h>
00027 #include <netlink/route/link.h>
00028 #include <netlink/route/link/api.h>
00029
00030
00031 #define LINK_ATTR_MTU 0x0001
00032 #define LINK_ATTR_LINK 0x0002
00033 #define LINK_ATTR_TXQLEN 0x0004
00034 #define LINK_ATTR_WEIGHT 0x0008
00035 #define LINK_ATTR_MASTER 0x0010
00036 #define LINK_ATTR_QDISC 0x0020
00037 #define LINK_ATTR_MAP 0x0040
00038 #define LINK_ATTR_ADDR 0x0080
00039 #define LINK_ATTR_BRD 0x0100
00040 #define LINK_ATTR_FLAGS 0x0200
00041 #define LINK_ATTR_IFNAME 0x0400
00042 #define LINK_ATTR_IFINDEX 0x0800
00043 #define LINK_ATTR_FAMILY 0x1000
00044 #define LINK_ATTR_ARPTYPE 0x2000
00045 #define LINK_ATTR_STATS 0x4000
00046 #define LINK_ATTR_CHANGE 0x8000
00047 #define LINK_ATTR_OPERSTATE 0x10000
00048 #define LINK_ATTR_LINKMODE 0x20000
00049 #define LINK_ATTR_LINKINFO 0x40000
00050 #define LINK_ATTR_IFALIAS 0x80000
00051 #define LINK_ATTR_NUM_VF 0x100000
00052
00053 static struct nl_cache_ops rtnl_link_ops;
00054 static struct nl_object_ops link_obj_ops;
00055
00056
00057 static struct rtnl_link_af_ops *af_lookup_and_alloc(struct rtnl_link *link,
00058 int family)
00059 {
00060 struct rtnl_link_af_ops *af_ops;
00061 void *data;
00062
00063 af_ops = rtnl_link_af_ops_lookup(family);
00064 if (!af_ops)
00065 return NULL;
00066
00067 if (!(data = rtnl_link_af_alloc(link, af_ops)))
00068 return NULL;
00069
00070 return af_ops;
00071 }
00072
00073 static int af_free(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
00074 void *data, void *arg)
00075 {
00076 if (ops->ao_free)
00077 ops->ao_free(link, data);
00078
00079 rtnl_link_af_ops_put(ops);
00080
00081 return 0;
00082 }
00083
00084 static int af_clone(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
00085 void *data, void *arg)
00086 {
00087 struct rtnl_link *dst = arg;
00088
00089 if (ops->ao_clone &&
00090 !(dst->l_af_data[ops->ao_family] = ops->ao_clone(dst, data)))
00091 return -NLE_NOMEM;
00092
00093 return 0;
00094 }
00095
00096 static int af_fill(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
00097 void *data, void *arg)
00098 {
00099 struct nl_msg *msg = arg;
00100 struct nlattr *af_attr;
00101 int err;
00102
00103 if (!ops->ao_fill_af)
00104 return 0;
00105
00106 if (!(af_attr = nla_nest_start(msg, ops->ao_family)))
00107 return -NLE_MSGSIZE;
00108
00109 if ((err = ops->ao_fill_af(link, arg, data)) < 0)
00110 return err;
00111
00112 nla_nest_end(msg, af_attr);
00113
00114 return 0;
00115 }
00116
00117 static int af_dump_line(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
00118 void *data, void *arg)
00119 {
00120 struct nl_dump_params *p = arg;
00121
00122 if (ops->ao_dump[NL_DUMP_LINE])
00123 ops->ao_dump[NL_DUMP_LINE](link, p, data);
00124
00125 return 0;
00126 }
00127
00128 static int af_dump_details(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
00129 void *data, void *arg)
00130 {
00131 struct nl_dump_params *p = arg;
00132
00133 if (ops->ao_dump[NL_DUMP_DETAILS])
00134 ops->ao_dump[NL_DUMP_DETAILS](link, p, data);
00135
00136 return 0;
00137 }
00138
00139 static int af_dump_stats(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
00140 void *data, void *arg)
00141 {
00142 struct nl_dump_params *p = arg;
00143
00144 if (ops->ao_dump[NL_DUMP_STATS])
00145 ops->ao_dump[NL_DUMP_STATS](link, p, data);
00146
00147 return 0;
00148 }
00149
00150 static int do_foreach_af(struct rtnl_link *link,
00151 int (*cb)(struct rtnl_link *,
00152 struct rtnl_link_af_ops *, void *, void *),
00153 void *arg)
00154 {
00155 int i, err;
00156
00157 for (i = 0; i < AF_MAX; i++) {
00158 if (link->l_af_data[i]) {
00159 struct rtnl_link_af_ops *ops;
00160
00161 if (!(ops = rtnl_link_af_ops_lookup(i)))
00162 BUG();
00163
00164 if ((err = cb(link, ops, link->l_af_data[i], arg)) < 0)
00165 return err;
00166 }
00167 }
00168
00169 return 0;
00170 }
00171
00172 static void release_link_info(struct rtnl_link *link)
00173 {
00174 struct rtnl_link_info_ops *io = link->l_info_ops;
00175
00176 if (io != NULL) {
00177 if (io->io_free)
00178 io->io_free(link);
00179 rtnl_link_info_ops_put(io);
00180 link->l_info_ops = NULL;
00181 }
00182 }
00183
00184 static void link_free_data(struct nl_object *c)
00185 {
00186 struct rtnl_link *link = nl_object_priv(c);
00187
00188 if (link) {
00189 struct rtnl_link_info_ops *io;
00190
00191 if ((io = link->l_info_ops) != NULL)
00192 release_link_info(link);
00193
00194 nl_addr_put(link->l_addr);
00195 nl_addr_put(link->l_bcast);
00196
00197 free(link->l_ifalias);
00198 free(link->l_info_kind);
00199
00200 do_foreach_af(link, af_free, NULL);
00201 }
00202 }
00203
00204 static int link_clone(struct nl_object *_dst, struct nl_object *_src)
00205 {
00206 struct rtnl_link *dst = nl_object_priv(_dst);
00207 struct rtnl_link *src = nl_object_priv(_src);
00208 int err;
00209
00210 if (src->l_addr)
00211 if (!(dst->l_addr = nl_addr_clone(src->l_addr)))
00212 return -NLE_NOMEM;
00213
00214 if (src->l_bcast)
00215 if (!(dst->l_bcast = nl_addr_clone(src->l_bcast)))
00216 return -NLE_NOMEM;
00217
00218 if (src->l_ifalias)
00219 if (!(dst->l_ifalias = strdup(src->l_ifalias)))
00220 return -NLE_NOMEM;
00221
00222 if (src->l_info_kind)
00223 if (!(dst->l_info_kind = strdup(src->l_info_kind)))
00224 return -NLE_NOMEM;
00225
00226 if (src->l_info_ops && src->l_info_ops->io_clone) {
00227 err = src->l_info_ops->io_clone(dst, src);
00228 if (err < 0)
00229 return err;
00230 }
00231
00232 if ((err = do_foreach_af(src, af_clone, dst)) < 0)
00233 return err;
00234
00235 return 0;
00236 }
00237
00238 static struct nla_policy link_policy[IFLA_MAX+1] = {
00239 [IFLA_IFNAME] = { .type = NLA_STRING,
00240 .maxlen = IFNAMSIZ },
00241 [IFLA_MTU] = { .type = NLA_U32 },
00242 [IFLA_TXQLEN] = { .type = NLA_U32 },
00243 [IFLA_LINK] = { .type = NLA_U32 },
00244 [IFLA_WEIGHT] = { .type = NLA_U32 },
00245 [IFLA_MASTER] = { .type = NLA_U32 },
00246 [IFLA_OPERSTATE]= { .type = NLA_U8 },
00247 [IFLA_LINKMODE] = { .type = NLA_U8 },
00248 [IFLA_LINKINFO] = { .type = NLA_NESTED },
00249 [IFLA_QDISC] = { .type = NLA_STRING,
00250 .maxlen = IFQDISCSIZ },
00251 [IFLA_STATS] = { .minlen = sizeof(struct rtnl_link_stats) },
00252 [IFLA_STATS64] = { .minlen = sizeof(struct rtnl_link_stats64) },
00253 [IFLA_MAP] = { .minlen = sizeof(struct rtnl_link_ifmap) },
00254 [IFLA_IFALIAS] = { .type = NLA_STRING, .maxlen = IFALIASZ },
00255 [IFLA_NUM_VF] = { .type = NLA_U32 },
00256 [IFLA_AF_SPEC] = { .type = NLA_NESTED },
00257 };
00258
00259 static struct nla_policy link_info_policy[IFLA_INFO_MAX+1] = {
00260 [IFLA_INFO_KIND] = { .type = NLA_STRING },
00261 [IFLA_INFO_DATA] = { .type = NLA_NESTED },
00262 [IFLA_INFO_XSTATS] = { .type = NLA_NESTED },
00263 };
00264
00265 static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
00266 struct nlmsghdr *n, struct nl_parser_param *pp)
00267 {
00268 struct rtnl_link *link;
00269 struct ifinfomsg *ifi;
00270 struct nlattr *tb[IFLA_MAX+1];
00271 struct rtnl_link_af_ops *af_ops = NULL;
00272 int err, family;
00273
00274 link = rtnl_link_alloc();
00275 if (link == NULL) {
00276 err = -NLE_NOMEM;
00277 goto errout;
00278 }
00279
00280 link->ce_msgtype = n->nlmsg_type;
00281
00282 if (!nlmsg_valid_hdr(n, sizeof(*ifi)))
00283 return -NLE_MSG_TOOSHORT;
00284
00285 ifi = nlmsg_data(n);
00286 link->l_family = 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 ((af_ops = af_lookup_and_alloc(link, family))) {
00296 if (af_ops->ao_protinfo_policy) {
00297 memcpy(&link_policy[IFLA_PROTINFO],
00298 af_ops->ao_protinfo_policy,
00299 sizeof(struct nla_policy));
00300 }
00301 }
00302
00303 err = nlmsg_parse(n, sizeof(*ifi), tb, IFLA_MAX, link_policy);
00304 if (err < 0)
00305 goto errout;
00306
00307 if (tb[IFLA_IFNAME] == NULL) {
00308 err = -NLE_MISSING_ATTR;
00309 goto errout;
00310 }
00311
00312 nla_strlcpy(link->l_name, tb[IFLA_IFNAME], IFNAMSIZ);
00313
00314
00315 if (tb[IFLA_STATS]) {
00316 struct rtnl_link_stats *st = nla_data(tb[IFLA_STATS]);
00317
00318 link->l_stats[RTNL_LINK_RX_PACKETS] = st->rx_packets;
00319 link->l_stats[RTNL_LINK_TX_PACKETS] = st->tx_packets;
00320 link->l_stats[RTNL_LINK_RX_BYTES] = st->rx_bytes;
00321 link->l_stats[RTNL_LINK_TX_BYTES] = st->tx_bytes;
00322 link->l_stats[RTNL_LINK_RX_ERRORS] = st->rx_errors;
00323 link->l_stats[RTNL_LINK_TX_ERRORS] = st->tx_errors;
00324 link->l_stats[RTNL_LINK_RX_DROPPED] = st->rx_dropped;
00325 link->l_stats[RTNL_LINK_TX_DROPPED] = st->tx_dropped;
00326 link->l_stats[RTNL_LINK_MULTICAST] = st->multicast;
00327 link->l_stats[RTNL_LINK_COLLISIONS] = st->collisions;
00328
00329 link->l_stats[RTNL_LINK_RX_LEN_ERR] = st->rx_length_errors;
00330 link->l_stats[RTNL_LINK_RX_OVER_ERR] = st->rx_over_errors;
00331 link->l_stats[RTNL_LINK_RX_CRC_ERR] = st->rx_crc_errors;
00332 link->l_stats[RTNL_LINK_RX_FRAME_ERR] = st->rx_frame_errors;
00333 link->l_stats[RTNL_LINK_RX_FIFO_ERR] = st->rx_fifo_errors;
00334 link->l_stats[RTNL_LINK_RX_MISSED_ERR] = st->rx_missed_errors;
00335
00336 link->l_stats[RTNL_LINK_TX_ABORT_ERR] = st->tx_aborted_errors;
00337 link->l_stats[RTNL_LINK_TX_CARRIER_ERR] = st->tx_carrier_errors;
00338 link->l_stats[RTNL_LINK_TX_FIFO_ERR] = st->tx_fifo_errors;
00339 link->l_stats[RTNL_LINK_TX_HBEAT_ERR] = st->tx_heartbeat_errors;
00340 link->l_stats[RTNL_LINK_TX_WIN_ERR] = st->tx_window_errors;
00341
00342 link->l_stats[RTNL_LINK_RX_COMPRESSED] = st->rx_compressed;
00343 link->l_stats[RTNL_LINK_TX_COMPRESSED] = st->tx_compressed;
00344
00345 link->ce_mask |= LINK_ATTR_STATS;
00346 }
00347
00348 if (tb[IFLA_STATS64]) {
00349
00350
00351
00352
00353
00354
00355
00356 struct rtnl_link_stats64 st;
00357
00358 nla_memcpy(&st, tb[IFLA_STATS64],
00359 sizeof(struct rtnl_link_stats64));
00360
00361 link->l_stats[RTNL_LINK_RX_PACKETS] = st.rx_packets;
00362 link->l_stats[RTNL_LINK_TX_PACKETS] = st.tx_packets;
00363 link->l_stats[RTNL_LINK_RX_BYTES] = st.rx_bytes;
00364 link->l_stats[RTNL_LINK_TX_BYTES] = st.tx_bytes;
00365 link->l_stats[RTNL_LINK_RX_ERRORS] = st.rx_errors;
00366 link->l_stats[RTNL_LINK_TX_ERRORS] = st.tx_errors;
00367 link->l_stats[RTNL_LINK_RX_DROPPED] = st.rx_dropped;
00368 link->l_stats[RTNL_LINK_TX_DROPPED] = st.tx_dropped;
00369 link->l_stats[RTNL_LINK_MULTICAST] = st.multicast;
00370 link->l_stats[RTNL_LINK_COLLISIONS] = st.collisions;
00371
00372 link->l_stats[RTNL_LINK_RX_LEN_ERR] = st.rx_length_errors;
00373 link->l_stats[RTNL_LINK_RX_OVER_ERR] = st.rx_over_errors;
00374 link->l_stats[RTNL_LINK_RX_CRC_ERR] = st.rx_crc_errors;
00375 link->l_stats[RTNL_LINK_RX_FRAME_ERR] = st.rx_frame_errors;
00376 link->l_stats[RTNL_LINK_RX_FIFO_ERR] = st.rx_fifo_errors;
00377 link->l_stats[RTNL_LINK_RX_MISSED_ERR] = st.rx_missed_errors;
00378
00379 link->l_stats[RTNL_LINK_TX_ABORT_ERR] = st.tx_aborted_errors;
00380 link->l_stats[RTNL_LINK_TX_CARRIER_ERR] = st.tx_carrier_errors;
00381 link->l_stats[RTNL_LINK_TX_FIFO_ERR] = st.tx_fifo_errors;
00382 link->l_stats[RTNL_LINK_TX_HBEAT_ERR] = st.tx_heartbeat_errors;
00383 link->l_stats[RTNL_LINK_TX_WIN_ERR] = st.tx_window_errors;
00384
00385 link->l_stats[RTNL_LINK_RX_COMPRESSED] = st.rx_compressed;
00386 link->l_stats[RTNL_LINK_TX_COMPRESSED] = st.tx_compressed;
00387
00388 link->ce_mask |= LINK_ATTR_STATS;
00389 }
00390
00391 if (tb[IFLA_TXQLEN]) {
00392 link->l_txqlen = nla_get_u32(tb[IFLA_TXQLEN]);
00393 link->ce_mask |= LINK_ATTR_TXQLEN;
00394 }
00395
00396 if (tb[IFLA_MTU]) {
00397 link->l_mtu = nla_get_u32(tb[IFLA_MTU]);
00398 link->ce_mask |= LINK_ATTR_MTU;
00399 }
00400
00401 if (tb[IFLA_ADDRESS]) {
00402 link->l_addr = nl_addr_alloc_attr(tb[IFLA_ADDRESS], AF_UNSPEC);
00403 if (link->l_addr == NULL) {
00404 err = -NLE_NOMEM;
00405 goto errout;
00406 }
00407 nl_addr_set_family(link->l_addr,
00408 nl_addr_guess_family(link->l_addr));
00409 link->ce_mask |= LINK_ATTR_ADDR;
00410 }
00411
00412 if (tb[IFLA_BROADCAST]) {
00413 link->l_bcast = nl_addr_alloc_attr(tb[IFLA_BROADCAST],
00414 AF_UNSPEC);
00415 if (link->l_bcast == NULL) {
00416 err = -NLE_NOMEM;
00417 goto errout;
00418 }
00419 nl_addr_set_family(link->l_bcast,
00420 nl_addr_guess_family(link->l_bcast));
00421 link->ce_mask |= LINK_ATTR_BRD;
00422 }
00423
00424 if (tb[IFLA_LINK]) {
00425 link->l_link = nla_get_u32(tb[IFLA_LINK]);
00426 link->ce_mask |= LINK_ATTR_LINK;
00427 }
00428
00429 if (tb[IFLA_WEIGHT]) {
00430 link->l_weight = nla_get_u32(tb[IFLA_WEIGHT]);
00431 link->ce_mask |= LINK_ATTR_WEIGHT;
00432 }
00433
00434 if (tb[IFLA_QDISC]) {
00435 nla_strlcpy(link->l_qdisc, tb[IFLA_QDISC], IFQDISCSIZ);
00436 link->ce_mask |= LINK_ATTR_QDISC;
00437 }
00438
00439 if (tb[IFLA_MAP]) {
00440 nla_memcpy(&link->l_map, tb[IFLA_MAP],
00441 sizeof(struct rtnl_link_ifmap));
00442 link->ce_mask |= LINK_ATTR_MAP;
00443 }
00444
00445 if (tb[IFLA_MASTER]) {
00446 link->l_master = nla_get_u32(tb[IFLA_MASTER]);
00447 link->ce_mask |= LINK_ATTR_MASTER;
00448 }
00449
00450 if (tb[IFLA_OPERSTATE]) {
00451 link->l_operstate = nla_get_u8(tb[IFLA_OPERSTATE]);
00452 link->ce_mask |= LINK_ATTR_OPERSTATE;
00453 }
00454
00455 if (tb[IFLA_LINKMODE]) {
00456 link->l_linkmode = nla_get_u8(tb[IFLA_LINKMODE]);
00457 link->ce_mask |= LINK_ATTR_LINKMODE;
00458 }
00459
00460 if (tb[IFLA_IFALIAS]) {
00461 link->l_ifalias = nla_strdup(tb[IFLA_IFALIAS]);
00462 if (link->l_ifalias == NULL) {
00463 err = -NLE_NOMEM;
00464 goto errout;
00465 }
00466 link->ce_mask |= LINK_ATTR_IFALIAS;
00467 }
00468
00469 if (tb[IFLA_NUM_VF]) {
00470 link->l_num_vf = nla_get_u32(tb[IFLA_NUM_VF]);
00471 link->ce_mask |= LINK_ATTR_NUM_VF;
00472 }
00473
00474 if (tb[IFLA_LINKINFO]) {
00475 struct nlattr *li[IFLA_INFO_MAX+1];
00476
00477 err = nla_parse_nested(li, IFLA_INFO_MAX, tb[IFLA_LINKINFO],
00478 link_info_policy);
00479 if (err < 0)
00480 goto errout;
00481
00482 if (li[IFLA_INFO_KIND]) {
00483 struct rtnl_link_info_ops *ops;
00484 char *kind;
00485
00486 kind = nla_strdup(li[IFLA_INFO_KIND]);
00487 if (kind == NULL) {
00488 err = -NLE_NOMEM;
00489 goto errout;
00490 }
00491 link->l_info_kind = kind;
00492 link->ce_mask |= LINK_ATTR_LINKINFO;
00493
00494 ops = rtnl_link_info_ops_lookup(kind);
00495 link->l_info_ops = ops;
00496
00497 if (ops) {
00498 if (ops->io_parse &&
00499 (li[IFLA_INFO_DATA] || li[IFLA_INFO_XSTATS])) {
00500 err = ops->io_parse(link, li[IFLA_INFO_DATA],
00501 li[IFLA_INFO_XSTATS]);
00502 if (err < 0)
00503 goto errout;
00504 } else {
00505
00506 }
00507 }
00508 }
00509 }
00510
00511 if (tb[IFLA_PROTINFO] && af_ops && af_ops->ao_parse_protinfo) {
00512 err = af_ops->ao_parse_protinfo(link, tb[IFLA_PROTINFO],
00513 link->l_af_data[link->l_family]);
00514 if (err < 0)
00515 goto errout;
00516 }
00517
00518 if (tb[IFLA_AF_SPEC]) {
00519 struct nlattr *af_attr;
00520 int remaining;
00521
00522 nla_for_each_nested(af_attr, tb[IFLA_AF_SPEC], remaining) {
00523 af_ops = af_lookup_and_alloc(link, nla_type(af_attr));
00524 if (af_ops && af_ops->ao_parse_af) {
00525 char *af_data = link->l_af_data[nla_type(af_attr)];
00526
00527 err = af_ops->ao_parse_af(link, af_attr, af_data);
00528
00529 rtnl_link_af_ops_put(af_ops);
00530
00531 if (err < 0)
00532 goto errout;
00533 }
00534
00535 }
00536 }
00537
00538 err = pp->pp_cb((struct nl_object *) link, pp);
00539 errout:
00540 rtnl_link_af_ops_put(af_ops);
00541 rtnl_link_put(link);
00542 return err;
00543 }
00544
00545 static int link_event_filter(struct nl_cache *cache, struct nl_object *obj)
00546 {
00547 struct rtnl_link *link = (struct rtnl_link *) obj;
00548
00549
00550
00551
00552 if (link->l_family == AF_BRIDGE)
00553 return NL_SKIP;
00554
00555 return NL_OK;
00556 }
00557
00558 static int link_request_update(struct nl_cache *cache, struct nl_sock *sk)
00559 {
00560 int family = cache->c_iarg1;
00561
00562 return nl_rtgen_request(sk, RTM_GETLINK, family, NLM_F_DUMP);
00563 }
00564
00565 static void link_dump_line(struct nl_object *obj, struct nl_dump_params *p)
00566 {
00567 char buf[128];
00568 struct nl_cache *cache = dp_cache(obj);
00569 struct rtnl_link *link = (struct rtnl_link *) obj;
00570
00571 nl_dump_line(p, "%s %s ", link->l_name,
00572 nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
00573
00574 if (link->l_addr && !nl_addr_iszero(link->l_addr))
00575 nl_dump(p, "%s ", nl_addr2str(link->l_addr, buf, sizeof(buf)));
00576
00577 if (link->ce_mask & LINK_ATTR_MASTER) {
00578 struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
00579 nl_dump(p, "master %s ", master ? master->l_name : "inv");
00580 if (master)
00581 rtnl_link_put(master);
00582 }
00583
00584 rtnl_link_flags2str(link->l_flags, buf, sizeof(buf));
00585 if (buf[0])
00586 nl_dump(p, "<%s> ", buf);
00587
00588 if (link->ce_mask & LINK_ATTR_LINK) {
00589 struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
00590 nl_dump(p, "slave-of %s ", ll ? ll->l_name : "NONE");
00591 if (ll)
00592 rtnl_link_put(ll);
00593 }
00594
00595 if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_LINE])
00596 link->l_info_ops->io_dump[NL_DUMP_LINE](link, p);
00597
00598 do_foreach_af(link, af_dump_line, p);
00599
00600 nl_dump(p, "\n");
00601 }
00602
00603 static void link_dump_details(struct nl_object *obj, struct nl_dump_params *p)
00604 {
00605 struct rtnl_link *link = (struct rtnl_link *) obj;
00606 char buf[64];
00607
00608 link_dump_line(obj, p);
00609
00610 nl_dump_line(p, " mtu %u ", link->l_mtu);
00611 nl_dump(p, "txqlen %u weight %u ", link->l_txqlen, link->l_weight);
00612
00613 if (link->ce_mask & LINK_ATTR_QDISC)
00614 nl_dump(p, "qdisc %s ", link->l_qdisc);
00615
00616 if (link->ce_mask & LINK_ATTR_MAP && link->l_map.lm_irq)
00617 nl_dump(p, "irq %u ", link->l_map.lm_irq);
00618
00619 if (link->ce_mask & LINK_ATTR_IFINDEX)
00620 nl_dump(p, "index %u ", link->l_index);
00621
00622
00623 nl_dump(p, "\n");
00624
00625 if (link->ce_mask & LINK_ATTR_IFALIAS)
00626 nl_dump_line(p, " alias %s\n", link->l_ifalias);
00627
00628 nl_dump_line(p, " ");
00629
00630 if (link->ce_mask & LINK_ATTR_BRD)
00631 nl_dump(p, "brd %s ", nl_addr2str(link->l_bcast, buf,
00632 sizeof(buf)));
00633
00634 if ((link->ce_mask & LINK_ATTR_OPERSTATE) &&
00635 link->l_operstate != IF_OPER_UNKNOWN) {
00636 rtnl_link_operstate2str(link->l_operstate, buf, sizeof(buf));
00637 nl_dump(p, "state %s ", buf);
00638 }
00639
00640 if (link->ce_mask & LINK_ATTR_NUM_VF)
00641 nl_dump(p, "num-vf %u ", link->l_num_vf);
00642
00643 nl_dump(p, "mode %s\n",
00644 rtnl_link_mode2str(link->l_linkmode, buf, sizeof(buf)));
00645
00646 if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_DETAILS])
00647 link->l_info_ops->io_dump[NL_DUMP_DETAILS](link, p);
00648
00649 do_foreach_af(link, af_dump_details, p);
00650 }
00651
00652 static void link_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
00653 {
00654 struct rtnl_link *link = (struct rtnl_link *) obj;
00655 char *unit, fmt[64];
00656 float res;
00657
00658 link_dump_details(obj, p);
00659
00660 nl_dump_line(p, " Stats: bytes packets errors "
00661 " dropped fifo-err compressed\n");
00662
00663 res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_RX_BYTES], &unit);
00664
00665 strcpy(fmt, " RX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n");
00666 fmt[9] = *unit == 'B' ? '9' : '7';
00667
00668 nl_dump_line(p, fmt, res, unit,
00669 link->l_stats[RTNL_LINK_RX_PACKETS],
00670 link->l_stats[RTNL_LINK_RX_ERRORS],
00671 link->l_stats[RTNL_LINK_RX_DROPPED],
00672 link->l_stats[RTNL_LINK_RX_FIFO_ERR],
00673 link->l_stats[RTNL_LINK_RX_COMPRESSED]);
00674
00675 res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_TX_BYTES], &unit);
00676
00677 strcpy(fmt, " TX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n");
00678 fmt[9] = *unit == 'B' ? '9' : '7';
00679
00680 nl_dump_line(p, fmt, res, unit,
00681 link->l_stats[RTNL_LINK_TX_PACKETS],
00682 link->l_stats[RTNL_LINK_TX_ERRORS],
00683 link->l_stats[RTNL_LINK_TX_DROPPED],
00684 link->l_stats[RTNL_LINK_TX_FIFO_ERR],
00685 link->l_stats[RTNL_LINK_TX_COMPRESSED]);
00686
00687 nl_dump_line(p, " Errors: length over crc "
00688 " frame missed multicast\n");
00689
00690 nl_dump_line(p, " RX %10" PRIu64 " %10" PRIu64 " %10"
00691 PRIu64 " %10" PRIu64 " %10" PRIu64 " %10"
00692 PRIu64 "\n",
00693 link->l_stats[RTNL_LINK_RX_LEN_ERR],
00694 link->l_stats[RTNL_LINK_RX_OVER_ERR],
00695 link->l_stats[RTNL_LINK_RX_CRC_ERR],
00696 link->l_stats[RTNL_LINK_RX_FRAME_ERR],
00697 link->l_stats[RTNL_LINK_RX_MISSED_ERR],
00698 link->l_stats[RTNL_LINK_MULTICAST]);
00699
00700 nl_dump_line(p, " aborted carrier heartbeat "
00701 " window collision\n");
00702
00703 nl_dump_line(p, " TX %10" PRIu64 " %10" PRIu64 " %10"
00704 PRIu64 " %10" PRIu64 " %10" PRIu64 "\n",
00705 link->l_stats[RTNL_LINK_TX_ABORT_ERR],
00706 link->l_stats[RTNL_LINK_TX_CARRIER_ERR],
00707 link->l_stats[RTNL_LINK_TX_HBEAT_ERR],
00708 link->l_stats[RTNL_LINK_TX_WIN_ERR],
00709 link->l_stats[RTNL_LINK_COLLISIONS]);
00710
00711 if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_STATS])
00712 link->l_info_ops->io_dump[NL_DUMP_STATS](link, p);
00713
00714 do_foreach_af(link, af_dump_stats, p);
00715 }
00716
00717 #if 0
00718 static int link_handle_event(struct nl_object *a, struct rtnl_link_event_cb *cb)
00719 {
00720 struct rtnl_link *l = (struct rtnl_link *) a;
00721 struct nl_cache *c = dp_cache(a);
00722 int nevents = 0;
00723
00724 if (l->l_change == ~0U) {
00725 if (l->ce_msgtype == RTM_NEWLINK)
00726 cb->le_register(l);
00727 else
00728 cb->le_unregister(l);
00729
00730 return 1;
00731 }
00732
00733 if (l->l_change & IFF_SLAVE) {
00734 if (l->l_flags & IFF_SLAVE) {
00735 struct rtnl_link *m = rtnl_link_get(c, l->l_master);
00736 cb->le_new_bonding(l, m);
00737 if (m)
00738 rtnl_link_put(m);
00739 } else
00740 cb->le_cancel_bonding(l);
00741 }
00742
00743 #if 0
00744 if (l->l_change & IFF_UP && l->l_change & IFF_RUNNING)
00745 dp_dump_line(p, line++, "link %s changed state to %s.\n",
00746 l->l_name, l->l_flags & IFF_UP ? "up" : "down");
00747
00748 if (l->l_change & IFF_PROMISC) {
00749 dp_new_line(p, line++);
00750 dp_dump(p, "link %s %s promiscuous mode.\n",
00751 l->l_name, l->l_flags & IFF_PROMISC ? "entered" : "left");
00752 }
00753
00754 if (line == 0)
00755 dp_dump_line(p, line++, "link %s sent unknown event.\n",
00756 l->l_name);
00757 #endif
00758
00759 return nevents;
00760 }
00761 #endif
00762
00763 static int link_compare(struct nl_object *_a, struct nl_object *_b,
00764 uint32_t attrs, int flags)
00765 {
00766 struct rtnl_link *a = (struct rtnl_link *) _a;
00767 struct rtnl_link *b = (struct rtnl_link *) _b;
00768 int diff = 0;
00769
00770 #define LINK_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, LINK_ATTR_##ATTR, a, b, EXPR)
00771
00772 diff |= LINK_DIFF(IFINDEX, a->l_index != b->l_index);
00773 diff |= LINK_DIFF(MTU, a->l_mtu != b->l_mtu);
00774 diff |= LINK_DIFF(LINK, a->l_link != b->l_link);
00775 diff |= LINK_DIFF(TXQLEN, a->l_txqlen != b->l_txqlen);
00776 diff |= LINK_DIFF(WEIGHT, a->l_weight != b->l_weight);
00777 diff |= LINK_DIFF(MASTER, a->l_master != b->l_master);
00778 diff |= LINK_DIFF(FAMILY, a->l_family != b->l_family);
00779 diff |= LINK_DIFF(OPERSTATE, a->l_operstate != b->l_operstate);
00780 diff |= LINK_DIFF(LINKMODE, a->l_linkmode != b->l_linkmode);
00781 diff |= LINK_DIFF(QDISC, strcmp(a->l_qdisc, b->l_qdisc));
00782 diff |= LINK_DIFF(IFNAME, strcmp(a->l_name, b->l_name));
00783 diff |= LINK_DIFF(ADDR, nl_addr_cmp(a->l_addr, b->l_addr));
00784 diff |= LINK_DIFF(BRD, nl_addr_cmp(a->l_bcast, b->l_bcast));
00785 diff |= LINK_DIFF(IFALIAS, strcmp(a->l_ifalias, b->l_ifalias));
00786 diff |= LINK_DIFF(NUM_VF, a->l_num_vf != b->l_num_vf);
00787
00788 if (flags & LOOSE_COMPARISON)
00789 diff |= LINK_DIFF(FLAGS,
00790 (a->l_flags ^ b->l_flags) & b->l_flag_mask);
00791 else
00792 diff |= LINK_DIFF(FLAGS, a->l_flags != b->l_flags);
00793
00794 #undef LINK_DIFF
00795
00796 return diff;
00797 }
00798
00799 static const struct trans_tbl link_attrs[] = {
00800 __ADD(LINK_ATTR_MTU, mtu)
00801 __ADD(LINK_ATTR_LINK, link)
00802 __ADD(LINK_ATTR_TXQLEN, txqlen)
00803 __ADD(LINK_ATTR_WEIGHT, weight)
00804 __ADD(LINK_ATTR_MASTER, master)
00805 __ADD(LINK_ATTR_QDISC, qdisc)
00806 __ADD(LINK_ATTR_MAP, map)
00807 __ADD(LINK_ATTR_ADDR, address)
00808 __ADD(LINK_ATTR_BRD, broadcast)
00809 __ADD(LINK_ATTR_FLAGS, flags)
00810 __ADD(LINK_ATTR_IFNAME, name)
00811 __ADD(LINK_ATTR_IFINDEX, ifindex)
00812 __ADD(LINK_ATTR_FAMILY, family)
00813 __ADD(LINK_ATTR_ARPTYPE, arptype)
00814 __ADD(LINK_ATTR_STATS, stats)
00815 __ADD(LINK_ATTR_CHANGE, change)
00816 __ADD(LINK_ATTR_OPERSTATE, operstate)
00817 __ADD(LINK_ATTR_LINKMODE, linkmode)
00818 __ADD(LINK_ATTR_IFALIAS, ifalias)
00819 __ADD(LINK_ATTR_NUM_VF, num_vf)
00820 };
00821
00822 static char *link_attrs2str(int attrs, char *buf, size_t len)
00823 {
00824 return __flags2str(attrs, buf, len, link_attrs,
00825 ARRAY_SIZE(link_attrs));
00826 }
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857 int rtnl_link_alloc_cache(struct nl_sock *sk, int family, struct nl_cache **result)
00858 {
00859 struct nl_cache * cache;
00860 int err;
00861
00862 cache = nl_cache_alloc(&rtnl_link_ops);
00863 if (!cache)
00864 return -NLE_NOMEM;
00865
00866 cache->c_iarg1 = family;
00867
00868 if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
00869 nl_cache_free(cache);
00870 return err;
00871 }
00872
00873 *result = cache;
00874 return 0;
00875 }
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892 struct rtnl_link *rtnl_link_get(struct nl_cache *cache, int ifindex)
00893 {
00894 struct rtnl_link *link;
00895
00896 if (cache->c_ops != &rtnl_link_ops)
00897 return NULL;
00898
00899 nl_list_for_each_entry(link, &cache->c_items, ce_list) {
00900 if (link->l_index == ifindex) {
00901 nl_object_get((struct nl_object *) link);
00902 return link;
00903 }
00904 }
00905
00906 return NULL;
00907 }
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921
00922
00923
00924 struct rtnl_link *rtnl_link_get_by_name(struct nl_cache *cache,
00925 const char *name)
00926 {
00927 struct rtnl_link *link;
00928
00929 if (cache->c_ops != &rtnl_link_ops)
00930 return NULL;
00931
00932 nl_list_for_each_entry(link, &cache->c_items, ce_list) {
00933 if (!strcmp(name, link->l_name)) {
00934 nl_object_get((struct nl_object *) link);
00935 return link;
00936 }
00937 }
00938
00939 return NULL;
00940 }
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956 int rtnl_link_build_get_request(int ifindex, const char *name,
00957 struct nl_msg **result)
00958 {
00959 struct ifinfomsg ifi;
00960 struct nl_msg *msg;
00961
00962 if (ifindex <= 0 && !name) {
00963 APPBUG("ifindex or name must be specified");
00964 return -NLE_MISSING_ATTR;
00965 }
00966
00967 memset(&ifi, 0, sizeof(ifi));
00968
00969 if (!(msg = nlmsg_alloc_simple(RTM_GETLINK, 0)))
00970 return -NLE_NOMEM;
00971
00972 if (ifindex > 0)
00973 ifi.ifi_index = ifindex;
00974
00975 if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
00976 goto nla_put_failure;
00977
00978 if (name)
00979 NLA_PUT_STRING(msg, IFLA_IFNAME, name);
00980
00981 *result = msg;
00982 return 0;
00983
00984 nla_put_failure:
00985 nlmsg_free(msg);
00986 return -NLE_MSGSIZE;
00987 }
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005 int rtnl_link_get_kernel(struct nl_sock *sk, int ifindex, const char *name,
01006 struct rtnl_link **result)
01007 {
01008 struct nl_msg *msg = NULL;
01009 struct nl_object *obj;
01010 int err;
01011
01012 if ((err = rtnl_link_build_get_request(ifindex, name, &msg)) < 0)
01013 return err;
01014
01015 err = nl_send_auto(sk, msg);
01016 nlmsg_free(msg);
01017 if (err < 0)
01018 return err;
01019
01020 if ((err = nl_pickup(sk, link_msg_parser, &obj)) < 0)
01021 return err;
01022
01023
01024 *result = (struct rtnl_link *) obj;
01025
01026
01027 if (err == 0 && obj)
01028 nl_wait_for_ack(sk);
01029
01030 return 0;
01031 }
01032
01033
01034
01035
01036
01037
01038
01039
01040
01041
01042
01043
01044
01045
01046
01047 char * rtnl_link_i2name(struct nl_cache *cache, int ifindex, char *dst,
01048 size_t len)
01049 {
01050 struct rtnl_link *link = rtnl_link_get(cache, ifindex);
01051
01052 if (link) {
01053 strncpy(dst, link->l_name, len - 1);
01054 rtnl_link_put(link);
01055 return dst;
01056 }
01057
01058 return NULL;
01059 }
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070 int rtnl_link_name2i(struct nl_cache *cache, const char *name)
01071 {
01072 int ifindex = 0;
01073 struct rtnl_link *link;
01074
01075 link = rtnl_link_get_by_name(cache, name);
01076 if (link) {
01077 ifindex = link->l_index;
01078 rtnl_link_put(link);
01079 }
01080
01081 return ifindex;
01082 }
01083
01084
01085
01086 static int build_link_msg(int cmd, struct ifinfomsg *hdr,
01087 struct rtnl_link *link, int flags, struct nl_msg **result)
01088 {
01089 struct nl_msg *msg;
01090 struct nlattr *af_spec;
01091
01092 msg = nlmsg_alloc_simple(cmd, flags);
01093 if (!msg)
01094 return -NLE_NOMEM;
01095
01096 if (nlmsg_append(msg, hdr, sizeof(*hdr), NLMSG_ALIGNTO) < 0)
01097 goto nla_put_failure;
01098
01099 if (link->ce_mask & LINK_ATTR_ADDR)
01100 NLA_PUT_ADDR(msg, IFLA_ADDRESS, link->l_addr);
01101
01102 if (link->ce_mask & LINK_ATTR_BRD)
01103 NLA_PUT_ADDR(msg, IFLA_BROADCAST, link->l_bcast);
01104
01105 if (link->ce_mask & LINK_ATTR_MTU)
01106 NLA_PUT_U32(msg, IFLA_MTU, link->l_mtu);
01107
01108 if (link->ce_mask & LINK_ATTR_TXQLEN)
01109 NLA_PUT_U32(msg, IFLA_TXQLEN, link->l_txqlen);
01110
01111 if (link->ce_mask & LINK_ATTR_WEIGHT)
01112 NLA_PUT_U32(msg, IFLA_WEIGHT, link->l_weight);
01113
01114 if (link->ce_mask & LINK_ATTR_IFNAME)
01115 NLA_PUT_STRING(msg, IFLA_IFNAME, link->l_name);
01116
01117 if (link->ce_mask & LINK_ATTR_OPERSTATE)
01118 NLA_PUT_U8(msg, IFLA_OPERSTATE, link->l_operstate);
01119
01120 if (link->ce_mask & LINK_ATTR_LINKMODE)
01121 NLA_PUT_U8(msg, IFLA_LINKMODE, link->l_linkmode);
01122
01123 if (link->ce_mask & LINK_ATTR_IFALIAS)
01124 NLA_PUT_STRING(msg, IFLA_IFALIAS, link->l_ifalias);
01125
01126 if (link->ce_mask & LINK_ATTR_LINK)
01127 NLA_PUT_U32(msg, IFLA_LINK, link->l_link);
01128
01129 if (link->ce_mask & LINK_ATTR_MASTER)
01130 NLA_PUT_U32(msg, IFLA_MASTER, link->l_master);
01131
01132 if (link->ce_mask & LINK_ATTR_LINKINFO) {
01133 struct nlattr *info;
01134
01135 if (!(info = nla_nest_start(msg, IFLA_LINKINFO)))
01136 goto nla_put_failure;
01137
01138 NLA_PUT_STRING(msg, IFLA_INFO_KIND, link->l_info_kind);
01139
01140 if (link->l_info_ops) {
01141 if (link->l_info_ops->io_put_attrs &&
01142 link->l_info_ops->io_put_attrs(msg, link) < 0)
01143 goto nla_put_failure;
01144 }
01145
01146 nla_nest_end(msg, info);
01147 }
01148
01149 if (!(af_spec = nla_nest_start(msg, IFLA_AF_SPEC)))
01150 goto nla_put_failure;
01151
01152 if (do_foreach_af(link, af_fill, msg) < 0)
01153 goto nla_put_failure;
01154
01155 nla_nest_end(msg, af_spec);
01156
01157 *result = msg;
01158 return 0;
01159
01160 nla_put_failure:
01161 nlmsg_free(msg);
01162 return -NLE_MSGSIZE;
01163 }
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182
01183
01184
01185
01186 int rtnl_link_build_add_request(struct rtnl_link *link, int flags,
01187 struct nl_msg **result)
01188 {
01189 struct ifinfomsg ifi = {
01190 .ifi_family = link->l_family,
01191 .ifi_index = link->l_index,
01192 .ifi_flags = link->l_flags,
01193 };
01194
01195 return build_link_msg(RTM_NEWLINK, &ifi, link, flags, result);
01196 }
01197
01198
01199
01200
01201
01202
01203
01204
01205
01206
01207
01208
01209
01210
01211
01212
01213
01214
01215 int rtnl_link_add(struct nl_sock *sk, struct rtnl_link *link, int flags)
01216 {
01217 struct nl_msg *msg;
01218 int err;
01219
01220 err = rtnl_link_build_add_request(link, flags, &msg);
01221 if (err < 0)
01222 return err;
01223
01224 return nl_send_sync(sk, msg);
01225 }
01226
01227
01228
01229
01230
01231
01232
01233
01234
01235
01236
01237
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247 int rtnl_link_build_change_request(struct rtnl_link *orig,
01248 struct rtnl_link *changes, int flags,
01249 struct nl_msg **result)
01250 {
01251 struct ifinfomsg ifi = {
01252 .ifi_family = orig->l_family,
01253 .ifi_index = orig->l_index,
01254 };
01255 int err;
01256
01257 if (changes->ce_mask & LINK_ATTR_FLAGS) {
01258 ifi.ifi_flags = orig->l_flags & ~changes->l_flag_mask;
01259 ifi.ifi_flags |= changes->l_flags;
01260 }
01261
01262 if (changes->l_family && changes->l_family != orig->l_family) {
01263 APPBUG("link change: family is immutable");
01264 return -NLE_IMMUTABLE;
01265 }
01266
01267
01268 if (orig->ce_mask & LINK_ATTR_IFINDEX &&
01269 orig->ce_mask & LINK_ATTR_IFNAME &&
01270 changes->ce_mask & LINK_ATTR_IFNAME &&
01271 !strcmp(orig->l_name, changes->l_name))
01272 changes->ce_mask &= ~LINK_ATTR_IFNAME;
01273
01274 if ((err = build_link_msg(RTM_NEWLINK, &ifi, changes, flags, result)) < 0)
01275 goto errout;
01276
01277 return 0;
01278
01279 errout:
01280 return err;
01281 }
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296
01297
01298
01299
01300
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311
01312
01313
01314 int rtnl_link_change(struct nl_sock *sk, struct rtnl_link *orig,
01315 struct rtnl_link *changes, int flags)
01316 {
01317 struct nl_msg *msg;
01318 int err;
01319
01320 err = rtnl_link_build_change_request(orig, changes, flags, &msg);
01321 if (err < 0)
01322 return err;
01323
01324 retry:
01325 err = nl_send_auto_complete(sk, msg);
01326 if (err < 0)
01327 goto errout;
01328
01329 err = wait_for_ack(sk);
01330 if (err == -NLE_OPNOTSUPP && msg->nm_nlh->nlmsg_type == RTM_NEWLINK) {
01331 msg->nm_nlh->nlmsg_type = RTM_SETLINK;
01332 goto retry;
01333 }
01334
01335 errout:
01336 nlmsg_free(msg);
01337 return err;
01338 }
01339
01340
01341
01342
01343
01344
01345
01346
01347
01348
01349
01350
01351
01352
01353
01354
01355
01356
01357
01358
01359
01360 int rtnl_link_build_delete_request(const struct rtnl_link *link,
01361 struct nl_msg **result)
01362 {
01363 struct nl_msg *msg;
01364 struct ifinfomsg ifi = {
01365 .ifi_index = link->l_index,
01366 };
01367
01368 if (!(link->ce_mask & (LINK_ATTR_IFINDEX | LINK_ATTR_IFNAME))) {
01369 APPBUG("ifindex or name must be specified");
01370 return -NLE_MISSING_ATTR;
01371 }
01372
01373 if (!(msg = nlmsg_alloc_simple(RTM_DELLINK, 0)))
01374 return -NLE_NOMEM;
01375
01376 if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
01377 goto nla_put_failure;
01378
01379 if (link->ce_mask & LINK_ATTR_IFNAME)
01380 NLA_PUT_STRING(msg, IFLA_IFNAME, link->l_name);
01381
01382 *result = msg;
01383 return 0;
01384
01385 nla_put_failure:
01386 nlmsg_free(msg);
01387 return -NLE_MSGSIZE;
01388 }
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402
01403
01404
01405
01406
01407
01408
01409
01410
01411
01412
01413
01414 int rtnl_link_delete(struct nl_sock *sk, const struct rtnl_link *link)
01415 {
01416 struct nl_msg *msg;
01417 int err;
01418
01419 if ((err = rtnl_link_build_delete_request(link, &msg)) < 0)
01420 return err;
01421
01422 return nl_send_sync(sk, msg);
01423 }
01424
01425
01426
01427
01428
01429
01430
01431
01432
01433
01434
01435
01436
01437
01438 struct rtnl_link *rtnl_link_alloc(void)
01439 {
01440 return (struct rtnl_link *) nl_object_alloc(&link_obj_ops);
01441 }
01442
01443
01444
01445
01446
01447
01448 void rtnl_link_put(struct rtnl_link *link)
01449 {
01450 nl_object_put((struct nl_object *) link);
01451 }
01452
01453
01454
01455
01456
01457
01458
01459
01460
01461
01462
01463
01464
01465
01466
01467 void rtnl_link_set_name(struct rtnl_link *link, const char *name)
01468 {
01469 strncpy(link->l_name, name, sizeof(link->l_name) - 1);
01470 link->ce_mask |= LINK_ATTR_IFNAME;
01471 }
01472
01473
01474
01475
01476
01477
01478
01479
01480
01481 char *rtnl_link_get_name(struct rtnl_link *link)
01482 {
01483 return link->ce_mask & LINK_ATTR_IFNAME ? link->l_name : NULL;
01484 }
01485
01486 static inline void __assign_addr(struct rtnl_link *link, struct nl_addr **pos,
01487 struct nl_addr *new, int flag)
01488 {
01489 if (*pos)
01490 nl_addr_put(*pos);
01491
01492 nl_addr_get(new);
01493 *pos = new;
01494
01495 link->ce_mask |= flag;
01496 }
01497
01498
01499
01500
01501
01502
01503
01504
01505
01506
01507
01508
01509 void rtnl_link_set_addr(struct rtnl_link *link, struct nl_addr *addr)
01510 {
01511 __assign_addr(link, &link->l_addr, addr, LINK_ATTR_ADDR);
01512 }
01513
01514
01515
01516
01517
01518
01519
01520
01521
01522
01523 struct nl_addr *rtnl_link_get_addr(struct rtnl_link *link)
01524 {
01525 return link->ce_mask & LINK_ATTR_ADDR ? link->l_addr : NULL;
01526 }
01527
01528
01529
01530
01531
01532
01533
01534
01535
01536
01537
01538
01539
01540 void rtnl_link_set_broadcast(struct rtnl_link *link, struct nl_addr *addr)
01541 {
01542 __assign_addr(link, &link->l_bcast, addr, LINK_ATTR_BRD);
01543 }
01544
01545
01546
01547
01548
01549
01550
01551
01552
01553
01554 struct nl_addr *rtnl_link_get_broadcast(struct rtnl_link *link)
01555 {
01556 return link->ce_mask & LINK_ATTR_BRD ? link->l_bcast : NULL;
01557 }
01558
01559
01560
01561
01562
01563
01564
01565
01566
01567 void rtnl_link_set_flags(struct rtnl_link *link, unsigned int flags)
01568 {
01569 link->l_flag_mask |= flags;
01570 link->l_flags |= flags;
01571 link->ce_mask |= LINK_ATTR_FLAGS;
01572 }
01573
01574
01575
01576
01577
01578
01579
01580
01581
01582 void rtnl_link_unset_flags(struct rtnl_link *link, unsigned int flags)
01583 {
01584 link->l_flag_mask |= flags;
01585 link->l_flags &= ~flags;
01586 link->ce_mask |= LINK_ATTR_FLAGS;
01587 }
01588
01589
01590
01591
01592
01593
01594
01595
01596
01597
01598 unsigned int rtnl_link_get_flags(struct rtnl_link *link)
01599 {
01600 return link->l_flags;
01601 }
01602
01603
01604
01605
01606
01607
01608 void rtnl_link_set_family(struct rtnl_link *link, int family)
01609 {
01610 link->l_family = family;
01611 link->ce_mask |= LINK_ATTR_FAMILY;
01612 }
01613
01614
01615
01616
01617
01618
01619
01620
01621 int rtnl_link_get_family(struct rtnl_link *link)
01622 {
01623 return link->ce_mask & LINK_ATTR_FAMILY ? link->l_family : AF_UNSPEC;
01624 }
01625
01626
01627
01628
01629
01630
01631
01632
01633
01634
01635 void rtnl_link_set_arptype(struct rtnl_link *link, unsigned int arptype)
01636 {
01637 link->l_arptype = arptype;
01638 link->ce_mask |= LINK_ATTR_ARPTYPE;
01639 }
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649 unsigned int rtnl_link_get_arptype(struct rtnl_link *link)
01650 {
01651 if (link->ce_mask & LINK_ATTR_ARPTYPE)
01652 return link->l_arptype;
01653 else
01654 return ARPHRD_VOID;
01655 }
01656
01657
01658
01659
01660
01661
01662
01663
01664
01665 void rtnl_link_set_ifindex(struct rtnl_link *link, int ifindex)
01666 {
01667 link->l_index = ifindex;
01668 link->ce_mask |= LINK_ATTR_IFINDEX;
01669 }
01670
01671
01672
01673
01674
01675
01676
01677
01678
01679
01680 int rtnl_link_get_ifindex(struct rtnl_link *link)
01681 {
01682 return link->l_index;
01683 }
01684
01685
01686
01687
01688
01689
01690
01691
01692
01693 void rtnl_link_set_mtu(struct rtnl_link *link, unsigned int mtu)
01694 {
01695 link->l_mtu = mtu;
01696 link->ce_mask |= LINK_ATTR_MTU;
01697 }
01698
01699
01700
01701
01702
01703
01704
01705
01706
01707 unsigned int rtnl_link_get_mtu(struct rtnl_link *link)
01708 {
01709 return link->l_mtu;
01710 }
01711
01712
01713
01714
01715
01716
01717
01718
01719
01720
01721
01722 void rtnl_link_set_txqlen(struct rtnl_link *link, unsigned int txqlen)
01723 {
01724 link->l_txqlen = txqlen;
01725 link->ce_mask |= LINK_ATTR_TXQLEN;
01726 }
01727
01728
01729
01730
01731
01732
01733
01734
01735
01736
01737
01738 unsigned int rtnl_link_get_txqlen(struct rtnl_link *link)
01739 {
01740 return link->ce_mask & LINK_ATTR_TXQLEN ? link->l_txqlen : 0;
01741 }
01742
01743 void rtnl_link_set_link(struct rtnl_link *link, int ifindex)
01744 {
01745 link->l_link = ifindex;
01746 link->ce_mask |= LINK_ATTR_LINK;
01747 }
01748
01749 int rtnl_link_get_link(struct rtnl_link *link)
01750 {
01751 return link->l_link;
01752 }
01753
01754
01755
01756
01757
01758
01759
01760
01761 void rtnl_link_set_master(struct rtnl_link *link, int ifindex)
01762 {
01763 link->l_master = ifindex;
01764 link->ce_mask |= LINK_ATTR_MASTER;
01765 }
01766
01767
01768
01769
01770
01771
01772
01773
01774 int rtnl_link_get_master(struct rtnl_link *link)
01775 {
01776 return link->l_master;
01777 }
01778
01779
01780
01781
01782
01783
01784
01785
01786
01787 void rtnl_link_set_operstate(struct rtnl_link *link, uint8_t status)
01788 {
01789 link->l_operstate = status;
01790 link->ce_mask |= LINK_ATTR_OPERSTATE;
01791 }
01792
01793
01794
01795
01796
01797
01798
01799
01800
01801 uint8_t rtnl_link_get_operstate(struct rtnl_link *link)
01802 {
01803 return link->l_operstate;
01804 }
01805
01806
01807
01808
01809
01810
01811
01812
01813
01814 void rtnl_link_set_linkmode(struct rtnl_link *link, uint8_t mode)
01815 {
01816 link->l_linkmode = mode;
01817 link->ce_mask |= LINK_ATTR_LINKMODE;
01818 }
01819
01820
01821
01822
01823
01824
01825
01826
01827
01828 uint8_t rtnl_link_get_linkmode(struct rtnl_link *link)
01829 {
01830 return link->l_linkmode;
01831 }
01832
01833
01834
01835
01836
01837
01838
01839
01840
01841 const char *rtnl_link_get_ifalias(struct rtnl_link *link)
01842 {
01843 return link->l_ifalias;
01844 }
01845
01846
01847
01848
01849
01850
01851
01852
01853
01854
01855
01856
01857
01858 void rtnl_link_set_ifalias(struct rtnl_link *link, const char *alias)
01859 {
01860 free(link->l_ifalias);
01861 link->ce_mask &= ~LINK_ATTR_IFALIAS;
01862
01863 if (alias) {
01864 link->l_ifalias = strdup(alias);
01865 link->ce_mask |= LINK_ATTR_IFALIAS;
01866 }
01867 }
01868
01869
01870
01871
01872
01873
01874
01875
01876
01877
01878
01879
01880
01881
01882 void rtnl_link_set_qdisc(struct rtnl_link *link, const char *name)
01883 {
01884 strncpy(link->l_qdisc, name, sizeof(link->l_qdisc) - 1);
01885 link->ce_mask |= LINK_ATTR_QDISC;
01886 }
01887
01888
01889
01890
01891
01892
01893
01894
01895
01896 char *rtnl_link_get_qdisc(struct rtnl_link *link)
01897 {
01898 return link->ce_mask & LINK_ATTR_QDISC ? link->l_qdisc : NULL;
01899 }
01900
01901
01902
01903
01904
01905
01906
01907
01908
01909 int rtnl_link_get_num_vf(struct rtnl_link *link, uint32_t *num_vf)
01910 {
01911 if (link->ce_mask & LINK_ATTR_NUM_VF) {
01912 *num_vf = link->l_num_vf;
01913 return 0;
01914 } else
01915 return -NLE_OPNOTSUPP;
01916 }
01917
01918
01919
01920
01921
01922
01923
01924
01925 uint64_t rtnl_link_get_stat(struct rtnl_link *link, rtnl_link_stat_id_t id)
01926 {
01927 if (id > RTNL_LINK_STATS_MAX)
01928 return 0;
01929
01930 return link->l_stats[id];
01931 }
01932
01933
01934
01935
01936
01937
01938
01939
01940
01941
01942
01943
01944 int rtnl_link_set_stat(struct rtnl_link *link, rtnl_link_stat_id_t id,
01945 const uint64_t value)
01946 {
01947 if (id > RTNL_LINK_STATS_MAX)
01948 return -NLE_INVAL;
01949
01950 link->l_stats[id] = value;
01951
01952 return 0;
01953 }
01954
01955
01956
01957
01958
01959
01960
01961
01962
01963
01964
01965
01966
01967 int rtnl_link_set_type(struct rtnl_link *link, const char *type)
01968 {
01969 struct rtnl_link_info_ops *io;
01970 int err;
01971 char *kind;
01972
01973 free(link->l_info_kind);
01974 link->ce_mask &= ~LINK_ATTR_LINKINFO;
01975 if (link->l_info_ops)
01976 release_link_info(link);
01977
01978 if (!type)
01979 return 0;
01980
01981 kind = strdup(type);
01982 if (!kind)
01983 return -NLE_NOMEM;
01984
01985 io = rtnl_link_info_ops_lookup(type);
01986 if (io) {
01987 if (io->io_alloc && (err = io->io_alloc(link)) < 0)
01988 goto errout;
01989
01990 link->l_info_ops = io;
01991 }
01992
01993 link->l_info_kind = kind;
01994 link->ce_mask |= LINK_ATTR_LINKINFO;
01995
01996 return 0;
01997
01998 errout:
01999 free(kind);
02000 return err;
02001 }
02002
02003
02004
02005
02006
02007
02008
02009
02010 char *rtnl_link_get_type(struct rtnl_link *link)
02011 {
02012 return link->l_info_kind;
02013 }
02014
02015
02016
02017
02018
02019
02020
02021
02022
02023
02024
02025
02026
02027
02028
02029
02030
02031
02032
02033
02034
02035 int rtnl_link_enslave_ifindex(struct nl_sock *sock, int master, int slave)
02036 {
02037 struct rtnl_link *link;
02038 int err;
02039
02040 if (!(link = rtnl_link_alloc()))
02041 return -NLE_NOMEM;
02042
02043 rtnl_link_set_ifindex(link, slave);
02044 rtnl_link_set_master(link, master);
02045
02046 if ((err = rtnl_link_change(sock, link, link, 0)) < 0)
02047 goto errout;
02048
02049 rtnl_link_put(link);
02050
02051
02052
02053
02054
02055
02056
02057
02058 if ((err = rtnl_link_get_kernel(sock, slave, NULL, &link)) < 0)
02059 return err;
02060
02061 if (rtnl_link_get_master(link) != master)
02062 err = -NLE_OPNOTSUPP;
02063
02064 errout:
02065 rtnl_link_put(link);
02066
02067 return err;
02068 }
02069
02070
02071
02072
02073
02074
02075
02076
02077
02078
02079
02080
02081
02082
02083
02084
02085
02086
02087
02088
02089
02090 int rtnl_link_enslave(struct nl_sock *sock, struct rtnl_link *master,
02091 struct rtnl_link *slave)
02092 {
02093 return rtnl_link_enslave_ifindex(sock, rtnl_link_get_ifindex(master),
02094 rtnl_link_get_ifindex(slave));
02095 }
02096
02097
02098
02099
02100
02101
02102
02103
02104
02105
02106
02107
02108
02109 int rtnl_link_release_ifindex(struct nl_sock *sock, int slave)
02110 {
02111 return rtnl_link_enslave_ifindex(sock, 0, slave);
02112 }
02113
02114
02115
02116
02117
02118
02119
02120
02121
02122
02123
02124
02125
02126
02127
02128
02129
02130
02131
02132
02133 int rtnl_link_release(struct nl_sock *sock, struct rtnl_link *slave)
02134 {
02135 return rtnl_link_release_ifindex(sock, rtnl_link_get_ifindex(slave));
02136 }
02137
02138
02139
02140
02141
02142
02143
02144
02145 static const struct trans_tbl link_flags[] = {
02146 __ADD(IFF_LOOPBACK, loopback)
02147 __ADD(IFF_BROADCAST, broadcast)
02148 __ADD(IFF_POINTOPOINT, pointopoint)
02149 __ADD(IFF_MULTICAST, multicast)
02150 __ADD(IFF_NOARP, noarp)
02151 __ADD(IFF_ALLMULTI, allmulti)
02152 __ADD(IFF_PROMISC, promisc)
02153 __ADD(IFF_MASTER, master)
02154 __ADD(IFF_SLAVE, slave)
02155 __ADD(IFF_DEBUG, debug)
02156 __ADD(IFF_DYNAMIC, dynamic)
02157 __ADD(IFF_AUTOMEDIA, automedia)
02158 __ADD(IFF_PORTSEL, portsel)
02159 __ADD(IFF_NOTRAILERS, notrailers)
02160 __ADD(IFF_UP, up)
02161 __ADD(IFF_RUNNING, running)
02162 __ADD(IFF_LOWER_UP, lowerup)
02163 __ADD(IFF_DORMANT, dormant)
02164 __ADD(IFF_ECHO, echo)
02165 };
02166
02167 char *rtnl_link_flags2str(int flags, char *buf, size_t len)
02168 {
02169 return __flags2str(flags, buf, len, link_flags,
02170 ARRAY_SIZE(link_flags));
02171 }
02172
02173 int rtnl_link_str2flags(const char *name)
02174 {
02175 return __str2flags(name, link_flags, ARRAY_SIZE(link_flags));
02176 }
02177
02178 static const struct trans_tbl link_stats[] = {
02179 __ADD(RTNL_LINK_RX_PACKETS, rx_packets)
02180 __ADD(RTNL_LINK_TX_PACKETS, tx_packets)
02181 __ADD(RTNL_LINK_RX_BYTES, rx_bytes)
02182 __ADD(RTNL_LINK_TX_BYTES, tx_bytes)
02183 __ADD(RTNL_LINK_RX_ERRORS, rx_errors)
02184 __ADD(RTNL_LINK_TX_ERRORS, tx_errors)
02185 __ADD(RTNL_LINK_RX_DROPPED, rx_dropped)
02186 __ADD(RTNL_LINK_TX_DROPPED, tx_dropped)
02187 __ADD(RTNL_LINK_RX_COMPRESSED, rx_compressed)
02188 __ADD(RTNL_LINK_TX_COMPRESSED, tx_compressed)
02189 __ADD(RTNL_LINK_RX_FIFO_ERR, rx_fifo_err)
02190 __ADD(RTNL_LINK_TX_FIFO_ERR, tx_fifo_err)
02191 __ADD(RTNL_LINK_RX_LEN_ERR, rx_len_err)
02192 __ADD(RTNL_LINK_RX_OVER_ERR, rx_over_err)
02193 __ADD(RTNL_LINK_RX_CRC_ERR, rx_crc_err)
02194 __ADD(RTNL_LINK_RX_FRAME_ERR, rx_frame_err)
02195 __ADD(RTNL_LINK_RX_MISSED_ERR, rx_missed_err)
02196 __ADD(RTNL_LINK_TX_ABORT_ERR, tx_abort_err)
02197 __ADD(RTNL_LINK_TX_CARRIER_ERR, tx_carrier_err)
02198 __ADD(RTNL_LINK_TX_HBEAT_ERR, tx_hbeat_err)
02199 __ADD(RTNL_LINK_TX_WIN_ERR, tx_win_err)
02200 __ADD(RTNL_LINK_COLLISIONS, collisions)
02201 __ADD(RTNL_LINK_MULTICAST, multicast)
02202 __ADD(RTNL_LINK_IP6_INPKTS, Ip6InReceives)
02203 __ADD(RTNL_LINK_IP6_INHDRERRORS, Ip6InHdrErrors)
02204 __ADD(RTNL_LINK_IP6_INTOOBIGERRORS, Ip6InTooBigErrors)
02205 __ADD(RTNL_LINK_IP6_INNOROUTES, Ip6InNoRoutes)
02206 __ADD(RTNL_LINK_IP6_INADDRERRORS, Ip6InAddrErrors)
02207 __ADD(RTNL_LINK_IP6_INUNKNOWNPROTOS, Ip6InUnknownProtos)
02208 __ADD(RTNL_LINK_IP6_INTRUNCATEDPKTS, Ip6InTruncatedPkts)
02209 __ADD(RTNL_LINK_IP6_INDISCARDS, Ip6InDiscards)
02210 __ADD(RTNL_LINK_IP6_INDELIVERS, Ip6InDelivers)
02211 __ADD(RTNL_LINK_IP6_OUTFORWDATAGRAMS, Ip6OutForwDatagrams)
02212 __ADD(RTNL_LINK_IP6_OUTPKTS, Ip6OutRequests)
02213 __ADD(RTNL_LINK_IP6_OUTDISCARDS, Ip6OutDiscards)
02214 __ADD(RTNL_LINK_IP6_OUTNOROUTES, Ip6OutNoRoutes)
02215 __ADD(RTNL_LINK_IP6_REASMTIMEOUT, Ip6ReasmTimeout)
02216 __ADD(RTNL_LINK_IP6_REASMREQDS, Ip6ReasmReqds)
02217 __ADD(RTNL_LINK_IP6_REASMOKS, Ip6ReasmOKs)
02218 __ADD(RTNL_LINK_IP6_REASMFAILS, Ip6ReasmFails)
02219 __ADD(RTNL_LINK_IP6_FRAGOKS, Ip6FragOKs)
02220 __ADD(RTNL_LINK_IP6_FRAGFAILS, Ip6FragFails)
02221 __ADD(RTNL_LINK_IP6_FRAGCREATES, Ip6FragCreates)
02222 __ADD(RTNL_LINK_IP6_INMCASTPKTS, Ip6InMcastPkts)
02223 __ADD(RTNL_LINK_IP6_OUTMCASTPKTS, Ip6OutMcastPkts)
02224 __ADD(RTNL_LINK_IP6_INBCASTPKTS, Ip6InBcastPkts)
02225 __ADD(RTNL_LINK_IP6_OUTBCASTPKTS, Ip6OutBcastPkts)
02226 __ADD(RTNL_LINK_IP6_INOCTETS, Ip6InOctets)
02227 __ADD(RTNL_LINK_IP6_OUTOCTETS, Ip6OutOctets)
02228 __ADD(RTNL_LINK_IP6_INMCASTOCTETS, Ip6InMcastOctets)
02229 __ADD(RTNL_LINK_IP6_OUTMCASTOCTETS, Ip6OutMcastOctets)
02230 __ADD(RTNL_LINK_IP6_INBCASTOCTETS, Ip6InBcastOctets)
02231 __ADD(RTNL_LINK_IP6_OUTBCASTOCTETS, Ip6OutBcastOctets)
02232 __ADD(RTNL_LINK_ICMP6_INMSGS, ICMP6_InMsgs)
02233 __ADD(RTNL_LINK_ICMP6_INERRORS, ICMP6_InErrors)
02234 __ADD(RTNL_LINK_ICMP6_OUTMSGS, ICMP6_OutMsgs)
02235 __ADD(RTNL_LINK_ICMP6_OUTERRORS, ICMP6_OutErrors)
02236 };
02237
02238 char *rtnl_link_stat2str(int st, char *buf, size_t len)
02239 {
02240 return __type2str(st, buf, len, link_stats, ARRAY_SIZE(link_stats));
02241 }
02242
02243 int rtnl_link_str2stat(const char *name)
02244 {
02245 return __str2type(name, link_stats, ARRAY_SIZE(link_stats));
02246 }
02247
02248 static const struct trans_tbl link_operstates[] = {
02249 __ADD(IF_OPER_UNKNOWN, unknown)
02250 __ADD(IF_OPER_NOTPRESENT, notpresent)
02251 __ADD(IF_OPER_DOWN, down)
02252 __ADD(IF_OPER_LOWERLAYERDOWN, lowerlayerdown)
02253 __ADD(IF_OPER_TESTING, testing)
02254 __ADD(IF_OPER_DORMANT, dormant)
02255 __ADD(IF_OPER_UP, up)
02256 };
02257
02258 char *rtnl_link_operstate2str(uint8_t st, char *buf, size_t len)
02259 {
02260 return __type2str(st, buf, len, link_operstates,
02261 ARRAY_SIZE(link_operstates));
02262 }
02263
02264 int rtnl_link_str2operstate(const char *name)
02265 {
02266 return __str2type(name, link_operstates,
02267 ARRAY_SIZE(link_operstates));
02268 }
02269
02270 static const struct trans_tbl link_modes[] = {
02271 __ADD(IF_LINK_MODE_DEFAULT, default)
02272 __ADD(IF_LINK_MODE_DORMANT, dormant)
02273 };
02274
02275 char *rtnl_link_mode2str(uint8_t st, char *buf, size_t len)
02276 {
02277 return __type2str(st, buf, len, link_modes, ARRAY_SIZE(link_modes));
02278 }
02279
02280 int rtnl_link_str2mode(const char *name)
02281 {
02282 return __str2type(name, link_modes, ARRAY_SIZE(link_modes));
02283 }
02284
02285
02286
02287
02288
02289
02290
02291
02292
02293
02294 int rtnl_link_set_info_type(struct rtnl_link *link, const char *type)
02295 {
02296 return rtnl_link_set_type(link, type);
02297 }
02298
02299
02300
02301
02302 char *rtnl_link_get_info_type(struct rtnl_link *link)
02303 {
02304 return rtnl_link_get_type(link);
02305 }
02306
02307
02308
02309
02310 void rtnl_link_set_weight(struct rtnl_link *link, unsigned int weight)
02311 {
02312 link->l_weight = weight;
02313 link->ce_mask |= LINK_ATTR_WEIGHT;
02314 }
02315
02316
02317
02318
02319 unsigned int rtnl_link_get_weight(struct rtnl_link *link)
02320 {
02321 return link->l_weight;
02322 }
02323
02324
02325
02326 static struct nl_object_ops link_obj_ops = {
02327 .oo_name = "route/link",
02328 .oo_size = sizeof(struct rtnl_link),
02329 .oo_free_data = link_free_data,
02330 .oo_clone = link_clone,
02331 .oo_dump = {
02332 [NL_DUMP_LINE] = link_dump_line,
02333 [NL_DUMP_DETAILS] = link_dump_details,
02334 [NL_DUMP_STATS] = link_dump_stats,
02335 },
02336 .oo_compare = link_compare,
02337 .oo_attrs2str = link_attrs2str,
02338 .oo_id_attrs = LINK_ATTR_IFINDEX,
02339 };
02340
02341 static struct nl_af_group link_groups[] = {
02342 { AF_UNSPEC, RTNLGRP_LINK },
02343 { END_OF_GROUP_LIST },
02344 };
02345
02346 static struct nl_cache_ops rtnl_link_ops = {
02347 .co_name = "route/link",
02348 .co_hdrsize = sizeof(struct ifinfomsg),
02349 .co_msgtypes = {
02350 { RTM_NEWLINK, NL_ACT_NEW, "new" },
02351 { RTM_DELLINK, NL_ACT_DEL, "del" },
02352 { RTM_GETLINK, NL_ACT_GET, "get" },
02353 { RTM_SETLINK, NL_ACT_CHANGE, "set" },
02354 END_OF_MSGTYPES_LIST,
02355 },
02356 .co_protocol = NETLINK_ROUTE,
02357 .co_groups = link_groups,
02358 .co_request_update = link_request_update,
02359 .co_msg_parser = link_msg_parser,
02360 .co_event_filter = link_event_filter,
02361 .co_obj_ops = &link_obj_ops,
02362 };
02363
02364 static void __init link_init(void)
02365 {
02366 nl_cache_mngt_register(&rtnl_link_ops);
02367 }
02368
02369 static void __exit link_exit(void)
02370 {
02371 nl_cache_mngt_unregister(&rtnl_link_ops);
02372 }
02373
02374