libnl
1.1
|
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-2006 Thomas Graf <tgraf@suug.ch> 00010 */ 00011 00012 /** 00013 * @ingroup rtnl 00014 * @defgroup link Links (Interfaces) 00015 * @brief 00016 * 00017 * @par Link Identification 00018 * A link can be identified by either its interface index or by its 00019 * name. The kernel favours the interface index but falls back to the 00020 * interface name if the interface index is lesser-than 0 for kernels 00021 * >= 2.6.11. Therefore you can request changes without mapping a 00022 * interface name to the corresponding index first. 00023 * 00024 * @par Changeable Attributes 00025 * @anchor link_changeable 00026 * - Link layer address 00027 * - Link layer broadcast address 00028 * - device mapping (ifmap) (>= 2.6.9) 00029 * - MTU (>= 2.6.9) 00030 * - Transmission queue length (>= 2.6.9) 00031 * - Weight (>= 2.6.9) 00032 * - Link name (only via access through interface index) (>= 2.6.9) 00033 * - Flags (>= 2.6.9) 00034 * - IFF_DEBUG 00035 * - IFF_NOTRAILERS 00036 * - IFF_NOARP 00037 * - IFF_DYNAMIC 00038 * - IFF_MULTICAST 00039 * - IFF_PORTSEL 00040 * - IFF_AUTOMEDIA 00041 * - IFF_UP 00042 * - IFF_PROMISC 00043 * - IFF_ALLMULTI 00044 * 00045 * @par Link Flags (linux/if.h) 00046 * @anchor link_flags 00047 * @code 00048 * IFF_UP Status of link (up|down) 00049 * IFF_BROADCAST Indicates this link allows broadcasting 00050 * IFF_MULTICAST Indicates this link allows multicasting 00051 * IFF_ALLMULTI Indicates this link is doing multicast routing 00052 * IFF_DEBUG Tell the driver to do debugging (currently unused) 00053 * IFF_LOOPBACK This is the loopback link 00054 * IFF_POINTOPOINT Point-to-point link 00055 * IFF_NOARP Link is unable to perform ARP 00056 * IFF_PROMISC Status of promiscious mode flag 00057 * IFF_MASTER Used by teql 00058 * IFF_SLAVE Used by teql 00059 * IFF_PORTSEL Indicates this link allows port selection 00060 * IFF_AUTOMEDIA Indicates this link selects port automatically 00061 * IFF_DYNAMIC Indicates the address of this link is dynamic 00062 * IFF_RUNNING Link is running and carrier is ok. 00063 * IFF_NOTRAILERS Unused, BSD compat. 00064 * @endcode 00065 * 00066 * @par Notes on IFF_PROMISC and IFF_ALLMULTI flags 00067 * Although you can query the status of IFF_PROMISC and IFF_ALLMULTI 00068 * they do not represent the actual state in the kernel but rather 00069 * whether the flag has been enabled/disabled by userspace. The link 00070 * may be in promiscious mode even if IFF_PROMISC is not set in a link 00071 * dump request response because promiscity might be needed by the driver 00072 * for a period of time. 00073 * 00074 * @note The unit of the transmission queue length depends on the 00075 * link type, a common unit is \a packets. 00076 * 00077 * @par 1) Retrieving information about available links 00078 * @code 00079 * // The first step is to retrieve a list of all available interfaces within 00080 * // the kernel and put them into a cache. 00081 * struct nl_cache *cache = rtnl_link_alloc_cache(nl_handle); 00082 * 00083 * // In a second step, a specific link may be looked up by either interface 00084 * // index or interface name. 00085 * struct rtnl_link *link = rtnl_link_get_by_name(cache, "lo"); 00086 * 00087 * // rtnl_link_get_by_name() is the short version for translating the 00088 * // interface name to an interface index first like this: 00089 * int ifindex = rtnl_link_name2i(cache, "lo"); 00090 * struct rtnl_link *link = rtnl_link_get(cache, ifindex); 00091 * 00092 * // After successful usage, the object must be given back to the cache 00093 * rtnl_link_put(link); 00094 * @endcode 00095 * 00096 * @par 2) Changing link attributes 00097 * @code 00098 * // In order to change any attributes of an existing link, we must allocate 00099 * // a new link to hold the change requests: 00100 * struct rtnl_link *request = rtnl_link_alloc(); 00101 * 00102 * // Now we can go on and specify the attributes we want to change: 00103 * rtnl_link_set_weight(request, 300); 00104 * rtnl_link_set_mtu(request, 1360); 00105 * 00106 * // We can also shut an interface down administratively 00107 * rtnl_link_unset_flags(request, rtnl_link_str2flags("up")); 00108 * 00109 * // Actually, we should know which link to change, so let's look it up 00110 * struct rtnl_link *old = rtnl_link_get(cache, "eth0"); 00111 * 00112 * // Two ways exist to commit this change request, the first one is to 00113 * // build the required netlink message and send it out in one single 00114 * // step: 00115 * rtnl_link_change(nl_handle, old, request); 00116 * 00117 * // An alternative way is to build the netlink message and send it 00118 * // out yourself using nl_send_auto_complete() 00119 * struct nl_msg *msg = rtnl_link_build_change_request(old, request); 00120 * nl_send_auto_complete(nl_handle, nlmsg_hdr(msg)); 00121 * nlmsg_free(msg); 00122 * 00123 * // Don't forget to give back the link object ;-> 00124 * rtnl_link_put(old); 00125 * @endcode 00126 * 00127 * @par 3) Link Type Specific Attributes 00128 * @code 00129 * // Some link types offer additional parameters and statistics specific 00130 * // to their type. F.e. a VLAN link can be configured like this: 00131 * // 00132 * // Allocate a new link and set the info type to "vlan". This is required 00133 * // to prepare the link to hold vlan specific attributes. 00134 * struct rtnl_link *request = rtnl_link_alloc(); 00135 * rtnl_link_set_info_type(request, "vlan"); 00136 * 00137 * // Now vlan specific attributes can be set: 00138 * rtnl_link_vlan_set_id(request, 10); 00139 * rtnl_link_vlan_set_ingress_map(request, 2, 8); 00140 * 00141 * // Of course the attributes can also be read, check the info type 00142 * // to make sure you are using the right access functions: 00143 * char *type = rtnl_link_get_info_type(link); 00144 * if (!strcmp(type, "vlan")) 00145 * int id = rtnl_link_vlan_get_id(link); 00146 * @endcode 00147 * @{ 00148 */ 00149 00150 #include <netlink-local.h> 00151 #include <netlink/netlink.h> 00152 #include <netlink/attr.h> 00153 #include <netlink/utils.h> 00154 #include <netlink/object.h> 00155 #include <netlink/route/rtnl.h> 00156 #include <netlink/route/link.h> 00157 #include <netlink/route/link/info-api.h> 00158 00159 /** @cond SKIP */ 00160 #define LINK_ATTR_MTU 0x0001 00161 #define LINK_ATTR_LINK 0x0002 00162 #define LINK_ATTR_TXQLEN 0x0004 00163 #define LINK_ATTR_WEIGHT 0x0008 00164 #define LINK_ATTR_MASTER 0x0010 00165 #define LINK_ATTR_QDISC 0x0020 00166 #define LINK_ATTR_MAP 0x0040 00167 #define LINK_ATTR_ADDR 0x0080 00168 #define LINK_ATTR_BRD 0x0100 00169 #define LINK_ATTR_FLAGS 0x0200 00170 #define LINK_ATTR_IFNAME 0x0400 00171 #define LINK_ATTR_IFINDEX 0x0800 00172 #define LINK_ATTR_FAMILY 0x1000 00173 #define LINK_ATTR_ARPTYPE 0x2000 00174 #define LINK_ATTR_STATS 0x4000 00175 #define LINK_ATTR_CHANGE 0x8000 00176 #define LINK_ATTR_OPERSTATE 0x10000 00177 #define LINK_ATTR_LINKMODE 0x20000 00178 #define LINK_ATTR_LINKINFO 0x40000 00179 00180 static struct nl_cache_ops rtnl_link_ops; 00181 static struct nl_object_ops link_obj_ops; 00182 /** @endcond */ 00183 00184 static void release_link_info(struct rtnl_link *link) 00185 { 00186 struct rtnl_link_info_ops *io = link->l_info_ops; 00187 00188 if (io != NULL) { 00189 io->io_refcnt--; 00190 io->io_free(link); 00191 link->l_info_ops = NULL; 00192 } 00193 } 00194 00195 static void link_free_data(struct nl_object *c) 00196 { 00197 struct rtnl_link *link = nl_object_priv(c); 00198 00199 if (link) { 00200 struct rtnl_link_info_ops *io; 00201 00202 if ((io = link->l_info_ops) != NULL) 00203 release_link_info(link); 00204 00205 nl_addr_put(link->l_addr); 00206 nl_addr_put(link->l_bcast); 00207 } 00208 } 00209 00210 static int link_clone(struct nl_object *_dst, struct nl_object *_src) 00211 { 00212 struct rtnl_link *dst = nl_object_priv(_dst); 00213 struct rtnl_link *src = nl_object_priv(_src); 00214 int err; 00215 00216 if (src->l_addr) 00217 if (!(dst->l_addr = nl_addr_clone(src->l_addr))) 00218 goto errout; 00219 00220 if (src->l_bcast) 00221 if (!(dst->l_bcast = nl_addr_clone(src->l_bcast))) 00222 goto errout; 00223 00224 if (src->l_info_ops && src->l_info_ops->io_clone) { 00225 err = src->l_info_ops->io_clone(dst, src); 00226 if (err < 0) 00227 goto errout; 00228 } 00229 00230 return 0; 00231 errout: 00232 return nl_get_errno(); 00233 } 00234 00235 static struct nla_policy link_policy[IFLA_MAX+1] = { 00236 [IFLA_IFNAME] = { .type = NLA_STRING, 00237 .maxlen = IFNAMSIZ }, 00238 [IFLA_MTU] = { .type = NLA_U32 }, 00239 [IFLA_TXQLEN] = { .type = NLA_U32 }, 00240 [IFLA_LINK] = { .type = NLA_U32 }, 00241 [IFLA_WEIGHT] = { .type = NLA_U32 }, 00242 [IFLA_MASTER] = { .type = NLA_U32 }, 00243 [IFLA_OPERSTATE]= { .type = NLA_U8 }, 00244 [IFLA_LINKMODE] = { .type = NLA_U8 }, 00245 [IFLA_LINKINFO] = { .type = NLA_NESTED }, 00246 [IFLA_QDISC] = { .type = NLA_STRING, 00247 .maxlen = IFQDISCSIZ }, 00248 [IFLA_STATS] = { .minlen = sizeof(struct rtnl_link_stats) }, 00249 [IFLA_MAP] = { .minlen = sizeof(struct rtnl_link_ifmap) }, 00250 }; 00251 00252 static struct nla_policy link_info_policy[IFLA_INFO_MAX+1] = { 00253 [IFLA_INFO_KIND] = { .type = NLA_STRING }, 00254 [IFLA_INFO_DATA] = { .type = NLA_NESTED }, 00255 [IFLA_INFO_XSTATS] = { .type = NLA_NESTED }, 00256 }; 00257 00258 static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, 00259 struct nlmsghdr *n, struct nl_parser_param *pp) 00260 { 00261 struct rtnl_link *link; 00262 struct ifinfomsg *ifi; 00263 struct nlattr *tb[IFLA_MAX+1]; 00264 int err; 00265 00266 link = rtnl_link_alloc(); 00267 if (link == NULL) { 00268 err = nl_errno(ENOMEM); 00269 goto errout; 00270 } 00271 00272 link->ce_msgtype = n->nlmsg_type; 00273 00274 err = nlmsg_parse(n, sizeof(*ifi), tb, IFLA_MAX, link_policy); 00275 if (err < 0) 00276 goto errout; 00277 00278 if (tb[IFLA_IFNAME] == NULL) { 00279 err = nl_error(EINVAL, "Missing link name TLV"); 00280 goto errout; 00281 } 00282 00283 nla_strlcpy(link->l_name, tb[IFLA_IFNAME], IFNAMSIZ); 00284 00285 ifi = nlmsg_data(n); 00286 link->l_family = ifi->ifi_family; 00287 link->l_arptype = ifi->ifi_type; 00288 link->l_index = ifi->ifi_index; 00289 link->l_flags = ifi->ifi_flags; 00290 link->l_change = ifi->ifi_change; 00291 link->ce_mask = (LINK_ATTR_IFNAME | LINK_ATTR_FAMILY | 00292 LINK_ATTR_ARPTYPE| LINK_ATTR_IFINDEX | 00293 LINK_ATTR_FLAGS | LINK_ATTR_CHANGE); 00294 00295 if (tb[IFLA_STATS]) { 00296 struct rtnl_link_stats *st = nla_data(tb[IFLA_STATS]); 00297 00298 link->l_stats[RTNL_LINK_RX_PACKETS] = st->rx_packets; 00299 link->l_stats[RTNL_LINK_RX_BYTES] = st->rx_bytes; 00300 link->l_stats[RTNL_LINK_RX_ERRORS] = st->rx_errors; 00301 link->l_stats[RTNL_LINK_RX_DROPPED] = st->rx_dropped; 00302 link->l_stats[RTNL_LINK_RX_COMPRESSED] = st->rx_compressed; 00303 link->l_stats[RTNL_LINK_RX_FIFO_ERR] = st->rx_fifo_errors; 00304 link->l_stats[RTNL_LINK_TX_PACKETS] = st->tx_packets; 00305 link->l_stats[RTNL_LINK_TX_BYTES] = st->tx_bytes; 00306 link->l_stats[RTNL_LINK_TX_ERRORS] = st->tx_errors; 00307 link->l_stats[RTNL_LINK_TX_DROPPED] = st->tx_dropped; 00308 link->l_stats[RTNL_LINK_TX_COMPRESSED] = st->tx_compressed; 00309 link->l_stats[RTNL_LINK_TX_FIFO_ERR] = st->tx_fifo_errors; 00310 link->l_stats[RTNL_LINK_RX_LEN_ERR] = st->rx_length_errors; 00311 link->l_stats[RTNL_LINK_RX_OVER_ERR] = st->rx_over_errors; 00312 link->l_stats[RTNL_LINK_RX_CRC_ERR] = st->rx_crc_errors; 00313 link->l_stats[RTNL_LINK_RX_FRAME_ERR] = st->rx_frame_errors; 00314 link->l_stats[RTNL_LINK_RX_MISSED_ERR] = st->rx_missed_errors; 00315 link->l_stats[RTNL_LINK_TX_ABORT_ERR] = st->tx_aborted_errors; 00316 link->l_stats[RTNL_LINK_TX_CARRIER_ERR] = st->tx_carrier_errors; 00317 link->l_stats[RTNL_LINK_TX_HBEAT_ERR] = st->tx_heartbeat_errors; 00318 link->l_stats[RTNL_LINK_TX_WIN_ERR] = st->tx_window_errors; 00319 link->l_stats[RTNL_LINK_MULTICAST] = st->multicast; 00320 00321 link->ce_mask |= LINK_ATTR_STATS; 00322 } 00323 00324 if (tb[IFLA_TXQLEN]) { 00325 link->l_txqlen = nla_get_u32(tb[IFLA_TXQLEN]); 00326 link->ce_mask |= LINK_ATTR_TXQLEN; 00327 } 00328 00329 if (tb[IFLA_MTU]) { 00330 link->l_mtu = nla_get_u32(tb[IFLA_MTU]); 00331 link->ce_mask |= LINK_ATTR_MTU; 00332 } 00333 00334 if (tb[IFLA_ADDRESS]) { 00335 link->l_addr = nla_get_addr(tb[IFLA_ADDRESS], AF_UNSPEC); 00336 if (link->l_addr == NULL) 00337 goto errout; 00338 nl_addr_set_family(link->l_addr, 00339 nl_addr_guess_family(link->l_addr)); 00340 link->ce_mask |= LINK_ATTR_ADDR; 00341 } 00342 00343 if (tb[IFLA_BROADCAST]) { 00344 link->l_bcast = nla_get_addr(tb[IFLA_BROADCAST], AF_UNSPEC); 00345 if (link->l_bcast == NULL) 00346 goto errout; 00347 nl_addr_set_family(link->l_bcast, 00348 nl_addr_guess_family(link->l_bcast)); 00349 link->ce_mask |= LINK_ATTR_BRD; 00350 } 00351 00352 if (tb[IFLA_LINK]) { 00353 link->l_link = nla_get_u32(tb[IFLA_LINK]); 00354 link->ce_mask |= LINK_ATTR_LINK; 00355 } 00356 00357 if (tb[IFLA_WEIGHT]) { 00358 link->l_weight = nla_get_u32(tb[IFLA_WEIGHT]); 00359 link->ce_mask |= LINK_ATTR_WEIGHT; 00360 } 00361 00362 if (tb[IFLA_QDISC]) { 00363 nla_strlcpy(link->l_qdisc, tb[IFLA_QDISC], IFQDISCSIZ); 00364 link->ce_mask |= LINK_ATTR_QDISC; 00365 } 00366 00367 if (tb[IFLA_MAP]) { 00368 struct rtnl_link_ifmap *map = nla_data(tb[IFLA_MAP]); 00369 link->l_map.lm_mem_start = map->mem_start; 00370 link->l_map.lm_mem_end = map->mem_end; 00371 link->l_map.lm_base_addr = map->base_addr; 00372 link->l_map.lm_irq = map->irq; 00373 link->l_map.lm_dma = map->dma; 00374 link->l_map.lm_port = map->port; 00375 link->ce_mask |= LINK_ATTR_MAP; 00376 } 00377 00378 if (tb[IFLA_MASTER]) { 00379 link->l_master = nla_get_u32(tb[IFLA_MASTER]); 00380 link->ce_mask |= LINK_ATTR_MASTER; 00381 } 00382 00383 if (tb[IFLA_OPERSTATE]) { 00384 link->l_operstate = nla_get_u8(tb[IFLA_OPERSTATE]); 00385 link->ce_mask |= LINK_ATTR_OPERSTATE; 00386 } 00387 00388 if (tb[IFLA_LINKMODE]) { 00389 link->l_linkmode = nla_get_u8(tb[IFLA_LINKMODE]); 00390 link->ce_mask |= LINK_ATTR_LINKMODE; 00391 } 00392 00393 if (tb[IFLA_LINKINFO]) { 00394 struct nlattr *li[IFLA_INFO_MAX+1]; 00395 00396 err = nla_parse_nested(li, IFLA_INFO_MAX, tb[IFLA_LINKINFO], 00397 link_info_policy); 00398 if (err < 0) 00399 goto errout; 00400 00401 if (li[IFLA_INFO_KIND] && 00402 (li[IFLA_INFO_DATA] || li[IFLA_INFO_XSTATS])) { 00403 struct rtnl_link_info_ops *ops; 00404 char *kind; 00405 00406 kind = nla_get_string(li[IFLA_INFO_KIND]); 00407 ops = rtnl_link_info_ops_lookup(kind); 00408 if (ops != NULL) { 00409 ops->io_refcnt++; 00410 link->l_info_ops = ops; 00411 err = ops->io_parse(link, li[IFLA_INFO_DATA], 00412 li[IFLA_INFO_XSTATS]); 00413 if (err < 0) 00414 goto errout; 00415 } else { 00416 /* XXX: Warn about unparsed info? */ 00417 } 00418 } 00419 } 00420 00421 err = pp->pp_cb((struct nl_object *) link, pp); 00422 if (err < 0) 00423 goto errout; 00424 00425 err = P_ACCEPT; 00426 00427 errout: 00428 rtnl_link_put(link); 00429 return err; 00430 } 00431 00432 static int link_request_update(struct nl_cache *c, struct nl_handle *h) 00433 { 00434 return nl_rtgen_request(h, RTM_GETLINK, AF_UNSPEC, NLM_F_DUMP); 00435 } 00436 00437 static int link_dump_brief(struct nl_object *obj, struct nl_dump_params *p) 00438 { 00439 char buf[128]; 00440 struct nl_cache *cache = dp_cache(obj); 00441 struct rtnl_link *link = (struct rtnl_link *) obj; 00442 int line = 1; 00443 00444 dp_dump(p, "%s %s ", link->l_name, 00445 nl_llproto2str(link->l_arptype, buf, sizeof(buf))); 00446 00447 if (link->l_addr && !nl_addr_iszero(link->l_addr)) 00448 dp_dump(p, "%s ", nl_addr2str(link->l_addr, buf, sizeof(buf))); 00449 00450 if (link->ce_mask & LINK_ATTR_MASTER) { 00451 struct rtnl_link *master = rtnl_link_get(cache, link->l_master); 00452 dp_dump(p, "master %s ", master ? master->l_name : "inv"); 00453 if (master) 00454 rtnl_link_put(master); 00455 } 00456 00457 rtnl_link_flags2str(link->l_flags, buf, sizeof(buf)); 00458 if (buf[0]) 00459 dp_dump(p, "<%s> ", buf); 00460 00461 if (link->ce_mask & LINK_ATTR_LINK) { 00462 struct rtnl_link *ll = rtnl_link_get(cache, link->l_link); 00463 dp_dump(p, "slave-of %s ", ll ? ll->l_name : "NONE"); 00464 if (ll) 00465 rtnl_link_put(ll); 00466 } 00467 00468 if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_BRIEF]) 00469 line = link->l_info_ops->io_dump[NL_DUMP_BRIEF](link, p, line); 00470 00471 dp_dump(p, "\n"); 00472 00473 return line; 00474 } 00475 00476 static int link_dump_full(struct nl_object *obj, struct nl_dump_params *p) 00477 { 00478 struct rtnl_link *link = (struct rtnl_link *) obj; 00479 char buf[64]; 00480 int line; 00481 00482 line = link_dump_brief(obj, p); 00483 dp_new_line(p, line++); 00484 00485 dp_dump(p, " mtu %u ", link->l_mtu); 00486 dp_dump(p, "txqlen %u weight %u ", link->l_txqlen, link->l_weight); 00487 00488 if (link->ce_mask & LINK_ATTR_QDISC) 00489 dp_dump(p, "qdisc %s ", link->l_qdisc); 00490 00491 if (link->ce_mask & LINK_ATTR_MAP && link->l_map.lm_irq) 00492 dp_dump(p, "irq %u ", link->l_map.lm_irq); 00493 00494 if (link->ce_mask & LINK_ATTR_IFINDEX) 00495 dp_dump(p, "index %u ", link->l_index); 00496 00497 00498 dp_dump(p, "\n"); 00499 dp_new_line(p, line++); 00500 00501 dp_dump(p, " "); 00502 00503 if (link->ce_mask & LINK_ATTR_BRD) 00504 dp_dump(p, "brd %s ", nl_addr2str(link->l_bcast, buf, 00505 sizeof(buf))); 00506 00507 if ((link->ce_mask & LINK_ATTR_OPERSTATE) && 00508 link->l_operstate != IF_OPER_UNKNOWN) { 00509 rtnl_link_operstate2str(link->l_operstate, buf, sizeof(buf)); 00510 dp_dump(p, "state %s ", buf); 00511 } 00512 00513 dp_dump(p, "mode %s\n", 00514 rtnl_link_mode2str(link->l_linkmode, buf, sizeof(buf))); 00515 00516 if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_FULL]) 00517 line = link->l_info_ops->io_dump[NL_DUMP_FULL](link, p, line); 00518 00519 return line; 00520 } 00521 00522 static int link_dump_stats(struct nl_object *obj, struct nl_dump_params *p) 00523 { 00524 struct rtnl_link *link = (struct rtnl_link *) obj; 00525 char *unit, fmt[64]; 00526 float res; 00527 int line; 00528 00529 line = link_dump_full(obj, p); 00530 00531 dp_dump_line(p, line++, " Stats: bytes packets errors " 00532 " dropped fifo-err compressed\n"); 00533 00534 res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_RX_BYTES], &unit); 00535 00536 strcpy(fmt, " RX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n"); 00537 fmt[9] = *unit == 'B' ? '9' : '7'; 00538 00539 dp_dump_line(p, line++, fmt, 00540 res, unit, 00541 link->l_stats[RTNL_LINK_RX_PACKETS], 00542 link->l_stats[RTNL_LINK_RX_ERRORS], 00543 link->l_stats[RTNL_LINK_RX_DROPPED], 00544 link->l_stats[RTNL_LINK_RX_FIFO_ERR], 00545 link->l_stats[RTNL_LINK_RX_COMPRESSED]); 00546 00547 res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_TX_BYTES], &unit); 00548 00549 strcpy(fmt, " TX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n"); 00550 fmt[9] = *unit == 'B' ? '9' : '7'; 00551 00552 dp_dump_line(p, line++, fmt, 00553 res, unit, 00554 link->l_stats[RTNL_LINK_TX_PACKETS], 00555 link->l_stats[RTNL_LINK_TX_ERRORS], 00556 link->l_stats[RTNL_LINK_TX_DROPPED], 00557 link->l_stats[RTNL_LINK_TX_FIFO_ERR], 00558 link->l_stats[RTNL_LINK_TX_COMPRESSED]); 00559 00560 dp_dump_line(p, line++, " Errors: length over crc " 00561 " frame missed multicast\n"); 00562 00563 dp_dump_line(p, line++, " RX %10" PRIu64 " %10" PRIu64 " %10" 00564 PRIu64 " %10" PRIu64 " %10" PRIu64 " %10" 00565 PRIu64 "\n", 00566 link->l_stats[RTNL_LINK_RX_LEN_ERR], 00567 link->l_stats[RTNL_LINK_RX_OVER_ERR], 00568 link->l_stats[RTNL_LINK_RX_CRC_ERR], 00569 link->l_stats[RTNL_LINK_RX_FRAME_ERR], 00570 link->l_stats[RTNL_LINK_RX_MISSED_ERR], 00571 link->l_stats[RTNL_LINK_MULTICAST]); 00572 00573 dp_dump_line(p, line++, " Errors: aborted carrier heartbeat " 00574 " window collision\n"); 00575 00576 dp_dump_line(p, line++, " TX %10" PRIu64 " %10" PRIu64 " %10" 00577 PRIu64 " %10" PRIu64 " %10" PRIu64 "\n", 00578 link->l_stats[RTNL_LINK_TX_ABORT_ERR], 00579 link->l_stats[RTNL_LINK_TX_CARRIER_ERR], 00580 link->l_stats[RTNL_LINK_TX_HBEAT_ERR], 00581 link->l_stats[RTNL_LINK_TX_WIN_ERR], 00582 link->l_stats[RTNL_LINK_TX_COLLISIONS]); 00583 00584 if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_STATS]) 00585 line = link->l_info_ops->io_dump[NL_DUMP_STATS](link, p, line); 00586 00587 return line; 00588 } 00589 00590 static int link_dump_xml(struct nl_object *obj, struct nl_dump_params *p) 00591 { 00592 struct rtnl_link *link = (struct rtnl_link *) obj; 00593 struct nl_cache *cache = dp_cache(obj); 00594 char buf[128]; 00595 int i, line = 0; 00596 00597 dp_dump_line(p, line++, "<link name=\"%s\" index=\"%u\">\n", 00598 link->l_name, link->l_index); 00599 dp_dump_line(p, line++, " <family>%s</family>\n", 00600 nl_af2str(link->l_family, buf, sizeof(buf))); 00601 dp_dump_line(p, line++, " <arptype>%s</arptype>\n", 00602 nl_llproto2str(link->l_arptype, buf, sizeof(buf))); 00603 dp_dump_line(p, line++, " <address>%s</address>\n", 00604 nl_addr2str(link->l_addr, buf, sizeof(buf))); 00605 dp_dump_line(p, line++, " <mtu>%u</mtu>\n", link->l_mtu); 00606 dp_dump_line(p, line++, " <txqlen>%u</txqlen>\n", link->l_txqlen); 00607 dp_dump_line(p, line++, " <weight>%u</weight>\n", link->l_weight); 00608 00609 rtnl_link_flags2str(link->l_flags, buf, sizeof(buf)); 00610 if (buf[0]) 00611 dp_dump_line(p, line++, " <flags>%s</flags>\n", buf); 00612 00613 if (link->ce_mask & LINK_ATTR_QDISC) 00614 dp_dump_line(p, line++, " <qdisc>%s</qdisc>\n", link->l_qdisc); 00615 00616 if (link->ce_mask & LINK_ATTR_LINK) { 00617 struct rtnl_link *ll = rtnl_link_get(cache, link->l_link); 00618 dp_dump_line(p, line++, " <link>%s</link>\n", 00619 ll ? ll->l_name : "none"); 00620 if (ll) 00621 rtnl_link_put(ll); 00622 } 00623 00624 if (link->ce_mask & LINK_ATTR_MASTER) { 00625 struct rtnl_link *master = rtnl_link_get(cache, link->l_master); 00626 dp_dump_line(p, line++, " <master>%s</master>\n", 00627 master ? master->l_name : "none"); 00628 if (master) 00629 rtnl_link_put(master); 00630 } 00631 00632 if (link->ce_mask & LINK_ATTR_BRD) 00633 dp_dump_line(p, line++, " <broadcast>%s</broadcast>\n", 00634 nl_addr2str(link->l_bcast, buf, sizeof(buf))); 00635 00636 if (link->ce_mask & LINK_ATTR_STATS) { 00637 dp_dump_line(p, line++, " <stats>\n"); 00638 for (i = 0; i <= RTNL_LINK_STATS_MAX; i++) { 00639 rtnl_link_stat2str(i, buf, sizeof(buf)); 00640 dp_dump_line(p, line++, 00641 " <%s>%" PRIu64 "</%s>\n", 00642 buf, link->l_stats[i], buf); 00643 } 00644 dp_dump_line(p, line++, " </stats>\n"); 00645 } 00646 00647 if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_XML]) { 00648 dp_dump_line(p, line++, " <info>\n"); 00649 line = link->l_info_ops->io_dump[NL_DUMP_XML](link, p, line); 00650 dp_dump_line(p, line++, " </info>\n"); 00651 } 00652 00653 dp_dump_line(p, line++, "</link>\n"); 00654 00655 #if 0 00656 uint32_t l_change; /**< Change mask */ 00657 struct rtnl_lifmap l_map; /**< Interface device mapping */ 00658 #endif 00659 00660 return line; 00661 } 00662 00663 static int link_dump_env(struct nl_object *obj, struct nl_dump_params *p) 00664 { 00665 struct rtnl_link *link = (struct rtnl_link *) obj; 00666 struct nl_cache *cache = dp_cache(obj); 00667 char buf[128]; 00668 int i, line = 0; 00669 00670 dp_dump_line(p, line++, "LINK_NAME=%s\n", link->l_name); 00671 dp_dump_line(p, line++, "LINK_IFINDEX=%u\n", link->l_index); 00672 dp_dump_line(p, line++, "LINK_FAMILY=%s\n", 00673 nl_af2str(link->l_family, buf, sizeof(buf))); 00674 dp_dump_line(p, line++, "LINK_TYPE=%s\n", 00675 nl_llproto2str(link->l_arptype, buf, sizeof(buf))); 00676 if (link->ce_mask & LINK_ATTR_ADDR) 00677 dp_dump_line(p, line++, "LINK_ADDRESS=%s\n", 00678 nl_addr2str(link->l_addr, buf, sizeof(buf))); 00679 dp_dump_line(p, line++, "LINK_MTU=%u\n", link->l_mtu); 00680 dp_dump_line(p, line++, "LINK_TXQUEUELEN=%u\n", link->l_txqlen); 00681 dp_dump_line(p, line++, "LINK_WEIGHT=%u\n", link->l_weight); 00682 00683 rtnl_link_flags2str(link->l_flags & ~IFF_RUNNING, buf, sizeof(buf)); 00684 if (buf[0]) 00685 dp_dump_line(p, line++, "LINK_FLAGS=%s\n", buf); 00686 00687 if (link->ce_mask & LINK_ATTR_QDISC) 00688 dp_dump_line(p, line++, "LINK_QDISC=%s\n", link->l_qdisc); 00689 00690 if (link->ce_mask & LINK_ATTR_LINK) { 00691 struct rtnl_link *ll = rtnl_link_get(cache, link->l_link); 00692 00693 dp_dump_line(p, line++, "LINK_LINK_IFINDEX=%d\n", link->l_link); 00694 if (ll) { 00695 dp_dump_line(p, line++, "LINK_LINK_IFNAME=%s\n", 00696 ll->l_name); 00697 rtnl_link_put(ll); 00698 } 00699 } 00700 00701 if (link->ce_mask & LINK_ATTR_MASTER) { 00702 struct rtnl_link *master = rtnl_link_get(cache, link->l_master); 00703 dp_dump_line(p, line++, "LINK_MASTER=%s\n", 00704 master ? master->l_name : "none"); 00705 if (master) 00706 rtnl_link_put(master); 00707 } 00708 00709 if (link->ce_mask & LINK_ATTR_BRD) 00710 dp_dump_line(p, line++, "LINK_BROADCAST=%s\n", 00711 nl_addr2str(link->l_bcast, buf, sizeof(buf))); 00712 00713 if (link->ce_mask & LINK_ATTR_STATS) { 00714 for (i = 0; i <= RTNL_LINK_STATS_MAX; i++) { 00715 char *c = buf; 00716 00717 sprintf(buf, "LINK_"); 00718 rtnl_link_stat2str(i, buf + 5, sizeof(buf) - 5); 00719 while (*c) { 00720 *c = toupper(*c); 00721 c++; 00722 } 00723 dp_dump_line(p, line++, 00724 "%s=%" PRIu64 "\n", buf, link->l_stats[i]); 00725 } 00726 } 00727 00728 if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_ENV]) 00729 line = link->l_info_ops->io_dump[NL_DUMP_ENV](link, p, line); 00730 00731 return line; 00732 } 00733 00734 #if 0 00735 static int link_handle_event(struct nl_object *a, struct rtnl_link_event_cb *cb) 00736 { 00737 struct rtnl_link *l = (struct rtnl_link *) a; 00738 struct nl_cache *c = dp_cache(a); 00739 int nevents = 0; 00740 00741 if (l->l_change == ~0U) { 00742 if (l->ce_msgtype == RTM_NEWLINK) 00743 cb->le_register(l); 00744 else 00745 cb->le_unregister(l); 00746 00747 return 1; 00748 } 00749 00750 if (l->l_change & IFF_SLAVE) { 00751 if (l->l_flags & IFF_SLAVE) { 00752 struct rtnl_link *m = rtnl_link_get(c, l->l_master); 00753 cb->le_new_bonding(l, m); 00754 if (m) 00755 rtnl_link_put(m); 00756 } else 00757 cb->le_cancel_bonding(l); 00758 } 00759 00760 #if 0 00761 if (l->l_change & IFF_UP && l->l_change & IFF_RUNNING) 00762 dp_dump_line(p, line++, "link %s changed state to %s.\n", 00763 l->l_name, l->l_flags & IFF_UP ? "up" : "down"); 00764 00765 if (l->l_change & IFF_PROMISC) { 00766 dp_new_line(p, line++); 00767 dp_dump(p, "link %s %s promiscuous mode.\n", 00768 l->l_name, l->l_flags & IFF_PROMISC ? "entered" : "left"); 00769 } 00770 00771 if (line == 0) 00772 dp_dump_line(p, line++, "link %s sent unknown event.\n", 00773 l->l_name); 00774 #endif 00775 00776 return nevents; 00777 } 00778 #endif 00779 00780 static int link_compare(struct nl_object *_a, struct nl_object *_b, 00781 uint32_t attrs, int flags) 00782 { 00783 struct rtnl_link *a = (struct rtnl_link *) _a; 00784 struct rtnl_link *b = (struct rtnl_link *) _b; 00785 int diff = 0; 00786 00787 #define LINK_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, LINK_ATTR_##ATTR, a, b, EXPR) 00788 00789 diff |= LINK_DIFF(IFINDEX, a->l_index != b->l_index); 00790 diff |= LINK_DIFF(MTU, a->l_mtu != b->l_mtu); 00791 diff |= LINK_DIFF(LINK, a->l_link != b->l_link); 00792 diff |= LINK_DIFF(TXQLEN, a->l_txqlen != b->l_txqlen); 00793 diff |= LINK_DIFF(WEIGHT, a->l_weight != b->l_weight); 00794 diff |= LINK_DIFF(MASTER, a->l_master != b->l_master); 00795 diff |= LINK_DIFF(FAMILY, a->l_family != b->l_family); 00796 diff |= LINK_DIFF(OPERSTATE, a->l_operstate != b->l_operstate); 00797 diff |= LINK_DIFF(LINKMODE, a->l_linkmode != b->l_linkmode); 00798 diff |= LINK_DIFF(QDISC, strcmp(a->l_qdisc, b->l_qdisc)); 00799 diff |= LINK_DIFF(IFNAME, strcmp(a->l_name, b->l_name)); 00800 diff |= LINK_DIFF(ADDR, nl_addr_cmp(a->l_addr, b->l_addr)); 00801 diff |= LINK_DIFF(BRD, nl_addr_cmp(a->l_bcast, b->l_bcast)); 00802 00803 if (flags & LOOSE_FLAG_COMPARISON) 00804 diff |= LINK_DIFF(FLAGS, 00805 (a->l_flags ^ b->l_flags) & b->l_flag_mask); 00806 else 00807 diff |= LINK_DIFF(FLAGS, a->l_flags != b->l_flags); 00808 00809 #undef LINK_DIFF 00810 00811 return diff; 00812 } 00813 00814 static struct trans_tbl link_attrs[] = { 00815 __ADD(LINK_ATTR_MTU, mtu) 00816 __ADD(LINK_ATTR_LINK, link) 00817 __ADD(LINK_ATTR_TXQLEN, txqlen) 00818 __ADD(LINK_ATTR_WEIGHT, weight) 00819 __ADD(LINK_ATTR_MASTER, master) 00820 __ADD(LINK_ATTR_QDISC, qdisc) 00821 __ADD(LINK_ATTR_MAP, map) 00822 __ADD(LINK_ATTR_ADDR, address) 00823 __ADD(LINK_ATTR_BRD, broadcast) 00824 __ADD(LINK_ATTR_FLAGS, flags) 00825 __ADD(LINK_ATTR_IFNAME, name) 00826 __ADD(LINK_ATTR_IFINDEX, ifindex) 00827 __ADD(LINK_ATTR_FAMILY, family) 00828 __ADD(LINK_ATTR_ARPTYPE, arptype) 00829 __ADD(LINK_ATTR_STATS, stats) 00830 __ADD(LINK_ATTR_CHANGE, change) 00831 __ADD(LINK_ATTR_OPERSTATE, operstate) 00832 __ADD(LINK_ATTR_LINKMODE, linkmode) 00833 }; 00834 00835 static char *link_attrs2str(int attrs, char *buf, size_t len) 00836 { 00837 return __flags2str(attrs, buf, len, link_attrs, 00838 ARRAY_SIZE(link_attrs)); 00839 } 00840 00841 /** 00842 * @name Allocation/Freeing 00843 * @{ 00844 */ 00845 00846 struct rtnl_link *rtnl_link_alloc(void) 00847 { 00848 return (struct rtnl_link *) nl_object_alloc(&link_obj_ops); 00849 } 00850 00851 void rtnl_link_put(struct rtnl_link *link) 00852 { 00853 nl_object_put((struct nl_object *) link); 00854 } 00855 00856 /** @} */ 00857 00858 /** 00859 * @name Cache Management 00860 * @{ 00861 */ 00862 00863 00864 /** 00865 * Allocate link cache and fill in all configured links. 00866 * @arg handle Netlink handle. 00867 * 00868 * Allocates a new link cache, initializes it properly and updates it 00869 * to include all links currently configured in the kernel. 00870 * 00871 * @note Free the memory after usage. 00872 * @return Newly allocated cache or NULL if an error occured. 00873 */ 00874 struct nl_cache *rtnl_link_alloc_cache(struct nl_handle *handle) 00875 { 00876 struct nl_cache * cache; 00877 00878 cache = nl_cache_alloc(&rtnl_link_ops); 00879 if (cache == NULL) 00880 return NULL; 00881 00882 if (handle && nl_cache_refill(handle, cache) < 0) { 00883 nl_cache_free(cache); 00884 return NULL; 00885 } 00886 00887 return cache; 00888 } 00889 00890 /** 00891 * Look up link by interface index in the provided cache 00892 * @arg cache link cache 00893 * @arg ifindex link interface index 00894 * 00895 * The caller owns a reference on the returned object and 00896 * must give the object back via rtnl_link_put(). 00897 * 00898 * @return pointer to link inside the cache or NULL if no match was found. 00899 */ 00900 struct rtnl_link *rtnl_link_get(struct nl_cache *cache, int ifindex) 00901 { 00902 struct rtnl_link *link; 00903 00904 if (cache->c_ops != &rtnl_link_ops) 00905 return NULL; 00906 00907 nl_list_for_each_entry(link, &cache->c_items, ce_list) { 00908 if (link->l_index == ifindex) { 00909 nl_object_get((struct nl_object *) link); 00910 return link; 00911 } 00912 } 00913 00914 return NULL; 00915 } 00916 00917 /** 00918 * Look up link by link name in the provided cache 00919 * @arg cache link cache 00920 * @arg name link name 00921 * 00922 * The caller owns a reference on the returned object and 00923 * must give the object back via rtnl_link_put(). 00924 * 00925 * @return pointer to link inside the cache or NULL if no match was found. 00926 */ 00927 struct rtnl_link *rtnl_link_get_by_name(struct nl_cache *cache, 00928 const char *name) 00929 { 00930 struct rtnl_link *link; 00931 00932 if (cache->c_ops != &rtnl_link_ops) 00933 return NULL; 00934 00935 nl_list_for_each_entry(link, &cache->c_items, ce_list) { 00936 if (!strcmp(name, link->l_name)) { 00937 nl_object_get((struct nl_object *) link); 00938 return link; 00939 } 00940 } 00941 00942 return NULL; 00943 } 00944 00945 /** @} */ 00946 00947 /** 00948 * @name Link Modifications 00949 * @{ 00950 */ 00951 00952 /** 00953 * Builds a netlink change request message to change link attributes 00954 * @arg old link to be changed 00955 * @arg tmpl template with requested changes 00956 * @arg flags additional netlink message flags 00957 * 00958 * Builds a new netlink message requesting a change of link attributes. 00959 * The netlink message header isn't fully equipped with all relevant 00960 * fields and must be sent out via nl_send_auto_complete() or 00961 * supplemented as needed. 00962 * \a old must point to a link currently configured in the kernel 00963 * and \a tmpl must contain the attributes to be changed set via 00964 * \c rtnl_link_set_* functions. 00965 * 00966 * @return New netlink message 00967 * @note Not all attributes can be changed, see 00968 * \ref link_changeable "Changeable Attributes" for more details. 00969 */ 00970 struct nl_msg * rtnl_link_build_change_request(struct rtnl_link *old, 00971 struct rtnl_link *tmpl, 00972 int flags) 00973 { 00974 struct nl_msg *msg; 00975 struct ifinfomsg ifi = { 00976 .ifi_family = old->l_family, 00977 .ifi_index = old->l_index, 00978 }; 00979 00980 if (tmpl->ce_mask & LINK_ATTR_FLAGS) { 00981 ifi.ifi_flags = old->l_flags & ~tmpl->l_flag_mask; 00982 ifi.ifi_flags |= tmpl->l_flags; 00983 } 00984 00985 msg = nlmsg_alloc_simple(RTM_SETLINK, flags); 00986 if (!msg) 00987 goto nla_put_failure; 00988 00989 if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0) 00990 goto nla_put_failure; 00991 00992 if (tmpl->ce_mask & LINK_ATTR_ADDR) 00993 NLA_PUT_ADDR(msg, IFLA_ADDRESS, tmpl->l_addr); 00994 00995 if (tmpl->ce_mask & LINK_ATTR_BRD) 00996 NLA_PUT_ADDR(msg, IFLA_BROADCAST, tmpl->l_bcast); 00997 00998 if (tmpl->ce_mask & LINK_ATTR_MTU) 00999 NLA_PUT_U32(msg, IFLA_MTU, tmpl->l_mtu); 01000 01001 if (tmpl->ce_mask & LINK_ATTR_TXQLEN) 01002 NLA_PUT_U32(msg, IFLA_TXQLEN, tmpl->l_txqlen); 01003 01004 if (tmpl->ce_mask & LINK_ATTR_WEIGHT) 01005 NLA_PUT_U32(msg, IFLA_WEIGHT, tmpl->l_weight); 01006 01007 if (tmpl->ce_mask & LINK_ATTR_IFNAME) 01008 NLA_PUT_STRING(msg, IFLA_IFNAME, tmpl->l_name); 01009 01010 if (tmpl->ce_mask & LINK_ATTR_OPERSTATE) 01011 NLA_PUT_U8(msg, IFLA_OPERSTATE, tmpl->l_operstate); 01012 01013 if (tmpl->ce_mask & LINK_ATTR_LINKMODE) 01014 NLA_PUT_U8(msg, IFLA_LINKMODE, tmpl->l_linkmode); 01015 01016 if ((tmpl->ce_mask & LINK_ATTR_LINKINFO) && tmpl->l_info_ops && 01017 tmpl->l_info_ops->io_put_attrs) { 01018 struct nlattr *info; 01019 01020 if (!(info = nla_nest_start(msg, IFLA_LINKINFO))) 01021 goto nla_put_failure; 01022 01023 NLA_PUT_STRING(msg, IFLA_INFO_KIND, tmpl->l_info_ops->io_name); 01024 01025 if (tmpl->l_info_ops->io_put_attrs(msg, tmpl) < 0) 01026 goto nla_put_failure; 01027 01028 nla_nest_end(msg, info); 01029 } 01030 01031 return msg; 01032 01033 nla_put_failure: 01034 nlmsg_free(msg); 01035 return NULL; 01036 } 01037 01038 /** 01039 * Change link attributes 01040 * @arg handle netlink handle 01041 * @arg old link to be changed 01042 * @arg tmpl template with requested changes 01043 * @arg flags additional netlink message flags 01044 * 01045 * Builds a new netlink message by calling rtnl_link_build_change_request(), 01046 * sends the request to the kernel and waits for the next ACK to be 01047 * received, i.e. blocks until the request has been processed. 01048 * 01049 * @return 0 on success or a negative error code 01050 * @note Not all attributes can be changed, see 01051 * \ref link_changeable "Changeable Attributes" for more details. 01052 */ 01053 int rtnl_link_change(struct nl_handle *handle, struct rtnl_link *old, 01054 struct rtnl_link *tmpl, int flags) 01055 { 01056 int err; 01057 struct nl_msg *msg; 01058 01059 msg = rtnl_link_build_change_request(old, tmpl, flags); 01060 if (!msg) 01061 return nl_errno(ENOMEM); 01062 01063 err = nl_send_auto_complete(handle, msg); 01064 if (err < 0) 01065 return err; 01066 01067 nlmsg_free(msg); 01068 return nl_wait_for_ack(handle); 01069 } 01070 01071 /** @} */ 01072 01073 /** 01074 * @name Name <-> Index Translations 01075 * @{ 01076 */ 01077 01078 /** 01079 * Translate an interface index to the corresponding link name 01080 * @arg cache link cache 01081 * @arg ifindex link interface index 01082 * @arg dst destination buffer 01083 * @arg len length of destination buffer 01084 * 01085 * Translates the specified interface index to the corresponding 01086 * link name and stores the name in the destination buffer. 01087 * 01088 * @return link name or NULL if no match was found. 01089 */ 01090 char * rtnl_link_i2name(struct nl_cache *cache, int ifindex, char *dst, 01091 size_t len) 01092 { 01093 struct rtnl_link *link = rtnl_link_get(cache, ifindex); 01094 01095 if (link) { 01096 strncpy(dst, link->l_name, len - 1); 01097 rtnl_link_put(link); 01098 return dst; 01099 } 01100 01101 return NULL; 01102 } 01103 01104 /** 01105 * Translate a link name to the corresponding interface index 01106 * @arg cache link cache 01107 * @arg name link name 01108 * 01109 * @return interface index or RTNL_LINK_NOT_FOUND if no match was found. 01110 */ 01111 int rtnl_link_name2i(struct nl_cache *cache, const char *name) 01112 { 01113 int ifindex = RTNL_LINK_NOT_FOUND; 01114 struct rtnl_link *link; 01115 01116 link = rtnl_link_get_by_name(cache, name); 01117 if (link) { 01118 ifindex = link->l_index; 01119 rtnl_link_put(link); 01120 } 01121 01122 return ifindex; 01123 } 01124 01125 /** @} */ 01126 01127 /** 01128 * @name Link Flags Translations 01129 * @{ 01130 */ 01131 01132 static struct trans_tbl link_flags[] = { 01133 __ADD(IFF_LOOPBACK, loopback) 01134 __ADD(IFF_BROADCAST, broadcast) 01135 __ADD(IFF_POINTOPOINT, pointopoint) 01136 __ADD(IFF_MULTICAST, multicast) 01137 __ADD(IFF_NOARP, noarp) 01138 __ADD(IFF_ALLMULTI, allmulti) 01139 __ADD(IFF_PROMISC, promisc) 01140 __ADD(IFF_MASTER, master) 01141 __ADD(IFF_SLAVE, slave) 01142 __ADD(IFF_DEBUG, debug) 01143 __ADD(IFF_DYNAMIC, dynamic) 01144 __ADD(IFF_AUTOMEDIA, automedia) 01145 __ADD(IFF_PORTSEL, portsel) 01146 __ADD(IFF_NOTRAILERS, notrailers) 01147 __ADD(IFF_UP, up) 01148 __ADD(IFF_RUNNING, running) 01149 __ADD(IFF_LOWER_UP, lowerup) 01150 __ADD(IFF_DORMANT, dormant) 01151 __ADD(IFF_ECHO, echo) 01152 }; 01153 01154 char * rtnl_link_flags2str(int flags, char *buf, size_t len) 01155 { 01156 return __flags2str(flags, buf, len, link_flags, 01157 ARRAY_SIZE(link_flags)); 01158 } 01159 01160 int rtnl_link_str2flags(const char *name) 01161 { 01162 return __str2flags(name, link_flags, ARRAY_SIZE(link_flags)); 01163 } 01164 01165 /** @} */ 01166 01167 /** 01168 * @name Link Statistics Translations 01169 * @{ 01170 */ 01171 01172 static struct trans_tbl link_stats[] = { 01173 __ADD(RTNL_LINK_RX_PACKETS, rx_packets) 01174 __ADD(RTNL_LINK_TX_PACKETS, tx_packets) 01175 __ADD(RTNL_LINK_RX_BYTES, rx_bytes) 01176 __ADD(RTNL_LINK_TX_BYTES, tx_bytes) 01177 __ADD(RTNL_LINK_RX_ERRORS, rx_errors) 01178 __ADD(RTNL_LINK_TX_ERRORS, tx_errors) 01179 __ADD(RTNL_LINK_RX_DROPPED, rx_dropped) 01180 __ADD(RTNL_LINK_TX_DROPPED, tx_dropped) 01181 __ADD(RTNL_LINK_RX_COMPRESSED, rx_compressed) 01182 __ADD(RTNL_LINK_TX_COMPRESSED, tx_compressed) 01183 __ADD(RTNL_LINK_RX_FIFO_ERR, rx_fifo_err) 01184 __ADD(RTNL_LINK_TX_FIFO_ERR, tx_fifo_err) 01185 __ADD(RTNL_LINK_RX_LEN_ERR, rx_len_err) 01186 __ADD(RTNL_LINK_RX_OVER_ERR, rx_over_err) 01187 __ADD(RTNL_LINK_RX_CRC_ERR, rx_crc_err) 01188 __ADD(RTNL_LINK_RX_FRAME_ERR, rx_frame_err) 01189 __ADD(RTNL_LINK_RX_MISSED_ERR, rx_missed_err) 01190 __ADD(RTNL_LINK_TX_ABORT_ERR, tx_abort_err) 01191 __ADD(RTNL_LINK_TX_CARRIER_ERR, tx_carrier_err) 01192 __ADD(RTNL_LINK_TX_HBEAT_ERR, tx_hbeat_err) 01193 __ADD(RTNL_LINK_TX_WIN_ERR, tx_win_err) 01194 __ADD(RTNL_LINK_TX_COLLISIONS, tx_collision) 01195 __ADD(RTNL_LINK_MULTICAST, multicast) 01196 }; 01197 01198 char *rtnl_link_stat2str(int st, char *buf, size_t len) 01199 { 01200 return __type2str(st, buf, len, link_stats, ARRAY_SIZE(link_stats)); 01201 } 01202 01203 int rtnl_link_str2stat(const char *name) 01204 { 01205 return __str2type(name, link_stats, ARRAY_SIZE(link_stats)); 01206 } 01207 01208 /** @} */ 01209 01210 /** 01211 * @name Link Operstate Translations 01212 * @{ 01213 */ 01214 01215 static struct trans_tbl link_operstates[] = { 01216 __ADD(IF_OPER_UNKNOWN, unknown) 01217 __ADD(IF_OPER_NOTPRESENT, notpresent) 01218 __ADD(IF_OPER_DOWN, down) 01219 __ADD(IF_OPER_LOWERLAYERDOWN, lowerlayerdown) 01220 __ADD(IF_OPER_TESTING, testing) 01221 __ADD(IF_OPER_DORMANT, dormant) 01222 __ADD(IF_OPER_UP, up) 01223 }; 01224 01225 char *rtnl_link_operstate2str(int st, char *buf, size_t len) 01226 { 01227 return __type2str(st, buf, len, link_operstates, 01228 ARRAY_SIZE(link_operstates)); 01229 } 01230 01231 int rtnl_link_str2operstate(const char *name) 01232 { 01233 return __str2type(name, link_operstates, 01234 ARRAY_SIZE(link_operstates)); 01235 } 01236 01237 /** @} */ 01238 01239 /** 01240 * @name Link Mode Translations 01241 * @{ 01242 */ 01243 01244 static struct trans_tbl link_modes[] = { 01245 __ADD(IF_LINK_MODE_DEFAULT, default) 01246 __ADD(IF_LINK_MODE_DORMANT, dormant) 01247 }; 01248 01249 char *rtnl_link_mode2str(int st, char *buf, size_t len) 01250 { 01251 return __type2str(st, buf, len, link_modes, ARRAY_SIZE(link_modes)); 01252 } 01253 01254 int rtnl_link_str2mode(const char *name) 01255 { 01256 return __str2type(name, link_modes, ARRAY_SIZE(link_modes)); 01257 } 01258 01259 /** @} */ 01260 01261 /** 01262 * @name Attributes 01263 * @{ 01264 */ 01265 01266 void rtnl_link_set_qdisc(struct rtnl_link *link, const char *qdisc) 01267 { 01268 strncpy(link->l_qdisc, qdisc, sizeof(link->l_qdisc) - 1); 01269 link->ce_mask |= LINK_ATTR_QDISC; 01270 } 01271 01272 char *rtnl_link_get_qdisc(struct rtnl_link *link) 01273 { 01274 if (link->ce_mask & LINK_ATTR_QDISC) 01275 return link->l_qdisc; 01276 else 01277 return NULL; 01278 } 01279 01280 void rtnl_link_set_name(struct rtnl_link *link, const char *name) 01281 { 01282 strncpy(link->l_name, name, sizeof(link->l_name) - 1); 01283 link->ce_mask |= LINK_ATTR_IFNAME; 01284 } 01285 01286 char *rtnl_link_get_name(struct rtnl_link *link) 01287 { 01288 if (link->ce_mask & LINK_ATTR_IFNAME) 01289 return link->l_name; 01290 else 01291 return NULL; 01292 } 01293 01294 static inline void __assign_addr(struct rtnl_link *link, struct nl_addr **pos, 01295 struct nl_addr *new, int flag) 01296 { 01297 if (*pos) 01298 nl_addr_put(*pos); 01299 01300 nl_addr_get(new); 01301 *pos = new; 01302 01303 link->ce_mask |= flag; 01304 } 01305 01306 void rtnl_link_set_addr(struct rtnl_link *link, struct nl_addr *addr) 01307 { 01308 __assign_addr(link, &link->l_addr, addr, LINK_ATTR_ADDR); 01309 } 01310 01311 struct nl_addr *rtnl_link_get_addr(struct rtnl_link *link) 01312 { 01313 if (link->ce_mask & LINK_ATTR_ADDR) 01314 return link->l_addr; 01315 else 01316 return NULL; 01317 } 01318 01319 void rtnl_link_set_broadcast(struct rtnl_link *link, struct nl_addr *brd) 01320 { 01321 __assign_addr(link, &link->l_bcast, brd, LINK_ATTR_BRD); 01322 } 01323 01324 struct nl_addr *rtnl_link_get_broadcast(struct rtnl_link *link) 01325 { 01326 if (link->ce_mask & LINK_ATTR_BRD) 01327 return link->l_bcast; 01328 else 01329 return NULL; 01330 } 01331 01332 void rtnl_link_set_flags(struct rtnl_link *link, unsigned int flags) 01333 { 01334 link->l_flag_mask |= flags; 01335 link->l_flags |= flags; 01336 link->ce_mask |= LINK_ATTR_FLAGS; 01337 } 01338 01339 void rtnl_link_unset_flags(struct rtnl_link *link, unsigned int flags) 01340 { 01341 link->l_flag_mask |= flags; 01342 link->l_flags &= ~flags; 01343 link->ce_mask |= LINK_ATTR_FLAGS; 01344 } 01345 01346 unsigned int rtnl_link_get_flags(struct rtnl_link *link) 01347 { 01348 return link->l_flags; 01349 } 01350 01351 void rtnl_link_set_family(struct rtnl_link *link, int family) 01352 { 01353 link->l_family = family; 01354 link->ce_mask |= LINK_ATTR_FAMILY; 01355 } 01356 01357 int rtnl_link_get_family(struct rtnl_link *link) 01358 { 01359 if (link->l_family & LINK_ATTR_FAMILY) 01360 return link->l_family; 01361 else 01362 return AF_UNSPEC; 01363 } 01364 01365 void rtnl_link_set_arptype(struct rtnl_link *link, unsigned int arptype) 01366 { 01367 link->l_arptype = arptype; 01368 } 01369 01370 unsigned int rtnl_link_get_arptype(struct rtnl_link *link) 01371 { 01372 return link->l_arptype; 01373 } 01374 01375 void rtnl_link_set_ifindex(struct rtnl_link *link, int ifindex) 01376 { 01377 link->l_index = ifindex; 01378 link->ce_mask |= LINK_ATTR_IFINDEX; 01379 } 01380 01381 int rtnl_link_get_ifindex(struct rtnl_link *link) 01382 { 01383 if (link->ce_mask & LINK_ATTR_IFINDEX) 01384 return link->l_index; 01385 else 01386 return RTNL_LINK_NOT_FOUND; 01387 } 01388 01389 void rtnl_link_set_mtu(struct rtnl_link *link, unsigned int mtu) 01390 { 01391 link->l_mtu = mtu; 01392 link->ce_mask |= LINK_ATTR_MTU; 01393 } 01394 01395 unsigned int rtnl_link_get_mtu(struct rtnl_link *link) 01396 { 01397 if (link->ce_mask & LINK_ATTR_MTU) 01398 return link->l_mtu; 01399 else 01400 return 0; 01401 } 01402 01403 void rtnl_link_set_txqlen(struct rtnl_link *link, unsigned int txqlen) 01404 { 01405 link->l_txqlen = txqlen; 01406 link->ce_mask |= LINK_ATTR_TXQLEN; 01407 } 01408 01409 unsigned int rtnl_link_get_txqlen(struct rtnl_link *link) 01410 { 01411 if (link->ce_mask & LINK_ATTR_TXQLEN) 01412 return link->l_txqlen; 01413 else 01414 return UINT_MAX; 01415 } 01416 01417 void rtnl_link_set_weight(struct rtnl_link *link, unsigned int weight) 01418 { 01419 link->l_weight = weight; 01420 link->ce_mask |= LINK_ATTR_WEIGHT; 01421 } 01422 01423 unsigned int rtnl_link_get_weight(struct rtnl_link *link) 01424 { 01425 if (link->ce_mask & LINK_ATTR_WEIGHT) 01426 return link->l_weight; 01427 else 01428 return UINT_MAX; 01429 } 01430 01431 void rtnl_link_set_link(struct rtnl_link *link, int ifindex) 01432 { 01433 link->l_link = ifindex; 01434 link->ce_mask |= LINK_ATTR_LINK; 01435 } 01436 01437 int rtnl_link_get_link(struct rtnl_link *link) 01438 { 01439 if (link->ce_mask & LINK_ATTR_LINK) 01440 return link->l_link; 01441 else 01442 return RTNL_LINK_NOT_FOUND; 01443 } 01444 01445 void rtnl_link_set_master(struct rtnl_link *link, int ifindex) 01446 { 01447 link->l_master = ifindex; 01448 link->ce_mask |= LINK_ATTR_MASTER; 01449 } 01450 01451 int rtnl_link_get_master(struct rtnl_link *link) 01452 { 01453 if (link->ce_mask & LINK_ATTR_MASTER) 01454 return link->l_master; 01455 else 01456 return RTNL_LINK_NOT_FOUND; 01457 } 01458 01459 void rtnl_link_set_operstate(struct rtnl_link *link, uint8_t operstate) 01460 { 01461 link->l_operstate = operstate; 01462 link->ce_mask |= LINK_ATTR_OPERSTATE; 01463 } 01464 01465 uint8_t rtnl_link_get_operstate(struct rtnl_link *link) 01466 { 01467 if (link->ce_mask & LINK_ATTR_OPERSTATE) 01468 return link->l_operstate; 01469 else 01470 return IF_OPER_UNKNOWN; 01471 } 01472 01473 void rtnl_link_set_linkmode(struct rtnl_link *link, uint8_t linkmode) 01474 { 01475 link->l_linkmode = linkmode; 01476 link->ce_mask |= LINK_ATTR_LINKMODE; 01477 } 01478 01479 uint8_t rtnl_link_get_linkmode(struct rtnl_link *link) 01480 { 01481 if (link->ce_mask & LINK_ATTR_LINKMODE) 01482 return link->l_linkmode; 01483 else 01484 return IF_LINK_MODE_DEFAULT; 01485 } 01486 01487 uint64_t rtnl_link_get_stat(struct rtnl_link *link, int id) 01488 { 01489 if (id < 0 || id > RTNL_LINK_STATS_MAX) 01490 return 0; 01491 01492 return link->l_stats[id]; 01493 } 01494 01495 /** 01496 * Specify the info type of a link 01497 * @arg link link object 01498 * @arg type info type 01499 * 01500 * Looks up the info type and prepares the link to store info type 01501 * specific attributes. If an info type has been assigned already 01502 * it will be released with all changes lost. 01503 * 01504 * @return 0 on success or a negative errror code. 01505 */ 01506 int rtnl_link_set_info_type(struct rtnl_link *link, const char *type) 01507 { 01508 struct rtnl_link_info_ops *io; 01509 int err; 01510 01511 if ((io = rtnl_link_info_ops_lookup(type)) == NULL) 01512 return nl_error(ENOENT, "No such link info type exists"); 01513 01514 if (link->l_info_ops) 01515 release_link_info(link); 01516 01517 if ((err = io->io_alloc(link)) < 0) 01518 return err; 01519 01520 link->l_info_ops = io; 01521 01522 return 0; 01523 } 01524 01525 /** 01526 * Return info type of a link 01527 * @arg link link object 01528 * 01529 * @note The returned pointer is only valid as long as the link exists 01530 * @return Info type name or NULL if unknown. 01531 */ 01532 char *rtnl_link_get_info_type(struct rtnl_link *link) 01533 { 01534 if (link->l_info_ops) 01535 return link->l_info_ops->io_name; 01536 else 01537 return NULL; 01538 } 01539 01540 /** @} */ 01541 01542 static struct nl_object_ops link_obj_ops = { 01543 .oo_name = "route/link", 01544 .oo_size = sizeof(struct rtnl_link), 01545 .oo_free_data = link_free_data, 01546 .oo_clone = link_clone, 01547 .oo_dump[NL_DUMP_BRIEF] = link_dump_brief, 01548 .oo_dump[NL_DUMP_FULL] = link_dump_full, 01549 .oo_dump[NL_DUMP_STATS] = link_dump_stats, 01550 .oo_dump[NL_DUMP_XML] = link_dump_xml, 01551 .oo_dump[NL_DUMP_ENV] = link_dump_env, 01552 .oo_compare = link_compare, 01553 .oo_attrs2str = link_attrs2str, 01554 .oo_id_attrs = LINK_ATTR_IFINDEX, 01555 }; 01556 01557 static struct nl_af_group link_groups[] = { 01558 { AF_UNSPEC, RTNLGRP_LINK }, 01559 { END_OF_GROUP_LIST }, 01560 }; 01561 01562 static struct nl_cache_ops rtnl_link_ops = { 01563 .co_name = "route/link", 01564 .co_hdrsize = sizeof(struct ifinfomsg), 01565 .co_msgtypes = { 01566 { RTM_NEWLINK, NL_ACT_NEW, "new" }, 01567 { RTM_DELLINK, NL_ACT_DEL, "del" }, 01568 { RTM_GETLINK, NL_ACT_GET, "get" }, 01569 END_OF_MSGTYPES_LIST, 01570 }, 01571 .co_protocol = NETLINK_ROUTE, 01572 .co_groups = link_groups, 01573 .co_request_update = link_request_update, 01574 .co_msg_parser = link_msg_parser, 01575 .co_obj_ops = &link_obj_ops, 01576 }; 01577 01578 static void __init link_init(void) 01579 { 01580 nl_cache_mngt_register(&rtnl_link_ops); 01581 } 01582 01583 static void __exit link_exit(void) 01584 { 01585 nl_cache_mngt_unregister(&rtnl_link_ops); 01586 } 01587 01588 /** @} */