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