libnl 2.0
|
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-2008 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(sk); 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(sk, 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(sk, 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 return -NLE_NOMEM; 00219 00220 if (src->l_bcast) 00221 if (!(dst->l_bcast = nl_addr_clone(src->l_bcast))) 00222 return -NLE_NOMEM; 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 return err; 00228 } 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_MAP] = { .minlen = sizeof(struct rtnl_link_ifmap) }, 00248 }; 00249 00250 static struct nla_policy link_info_policy[IFLA_INFO_MAX+1] = { 00251 [IFLA_INFO_KIND] = { .type = NLA_STRING }, 00252 [IFLA_INFO_DATA] = { .type = NLA_NESTED }, 00253 [IFLA_INFO_XSTATS] = { .type = NLA_NESTED }, 00254 }; 00255 00256 static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, 00257 struct nlmsghdr *n, struct nl_parser_param *pp) 00258 { 00259 struct rtnl_link *link; 00260 struct ifinfomsg *ifi; 00261 struct nlattr *tb[IFLA_MAX+1]; 00262 int err; 00263 00264 link = rtnl_link_alloc(); 00265 if (link == NULL) { 00266 err = -NLE_NOMEM; 00267 goto errout; 00268 } 00269 00270 link->ce_msgtype = n->nlmsg_type; 00271 00272 err = nlmsg_parse(n, sizeof(*ifi), tb, IFLA_MAX, link_policy); 00273 if (err < 0) 00274 goto errout; 00275 00276 if (tb[IFLA_IFNAME] == NULL) { 00277 err = -NLE_MISSING_ATTR; 00278 goto errout; 00279 } 00280 00281 nla_strlcpy(link->l_name, tb[IFLA_IFNAME], IFNAMSIZ); 00282 00283 ifi = nlmsg_data(n); 00284 link->l_family = ifi->ifi_family; 00285 link->l_arptype = ifi->ifi_type; 00286 link->l_index = ifi->ifi_index; 00287 link->l_flags = ifi->ifi_flags; 00288 link->l_change = ifi->ifi_change; 00289 link->ce_mask = (LINK_ATTR_IFNAME | LINK_ATTR_FAMILY | 00290 LINK_ATTR_ARPTYPE| LINK_ATTR_IFINDEX | 00291 LINK_ATTR_FLAGS | LINK_ATTR_CHANGE); 00292 00293 if (tb[IFLA_STATS]) { 00294 struct rtnl_link_stats *st = nla_data(tb[IFLA_STATS]); 00295 00296 link->l_stats[RTNL_LINK_RX_PACKETS] = st->rx_packets; 00297 link->l_stats[RTNL_LINK_RX_BYTES] = st->rx_bytes; 00298 link->l_stats[RTNL_LINK_RX_ERRORS] = st->rx_errors; 00299 link->l_stats[RTNL_LINK_RX_DROPPED] = st->rx_dropped; 00300 link->l_stats[RTNL_LINK_RX_COMPRESSED] = st->rx_compressed; 00301 link->l_stats[RTNL_LINK_RX_FIFO_ERR] = st->rx_fifo_errors; 00302 link->l_stats[RTNL_LINK_TX_PACKETS] = st->tx_packets; 00303 link->l_stats[RTNL_LINK_TX_BYTES] = st->tx_bytes; 00304 link->l_stats[RTNL_LINK_TX_ERRORS] = st->tx_errors; 00305 link->l_stats[RTNL_LINK_TX_DROPPED] = st->tx_dropped; 00306 link->l_stats[RTNL_LINK_TX_COMPRESSED] = st->tx_compressed; 00307 link->l_stats[RTNL_LINK_TX_FIFO_ERR] = st->tx_fifo_errors; 00308 link->l_stats[RTNL_LINK_RX_LEN_ERR] = st->rx_length_errors; 00309 link->l_stats[RTNL_LINK_RX_OVER_ERR] = st->rx_over_errors; 00310 link->l_stats[RTNL_LINK_RX_CRC_ERR] = st->rx_crc_errors; 00311 link->l_stats[RTNL_LINK_RX_FRAME_ERR] = st->rx_frame_errors; 00312 link->l_stats[RTNL_LINK_RX_MISSED_ERR] = st->rx_missed_errors; 00313 link->l_stats[RTNL_LINK_TX_ABORT_ERR] = st->tx_aborted_errors; 00314 link->l_stats[RTNL_LINK_TX_CARRIER_ERR] = st->tx_carrier_errors; 00315 link->l_stats[RTNL_LINK_TX_HBEAT_ERR] = st->tx_heartbeat_errors; 00316 link->l_stats[RTNL_LINK_TX_WIN_ERR] = st->tx_window_errors; 00317 link->l_stats[RTNL_LINK_MULTICAST] = st->multicast; 00318 00319 link->ce_mask |= LINK_ATTR_STATS; 00320 } 00321 00322 if (tb[IFLA_TXQLEN]) { 00323 link->l_txqlen = nla_get_u32(tb[IFLA_TXQLEN]); 00324 link->ce_mask |= LINK_ATTR_TXQLEN; 00325 } 00326 00327 if (tb[IFLA_MTU]) { 00328 link->l_mtu = nla_get_u32(tb[IFLA_MTU]); 00329 link->ce_mask |= LINK_ATTR_MTU; 00330 } 00331 00332 if (tb[IFLA_ADDRESS]) { 00333 link->l_addr = nl_addr_alloc_attr(tb[IFLA_ADDRESS], AF_UNSPEC); 00334 if (link->l_addr == NULL) { 00335 err = -NLE_NOMEM; 00336 goto errout; 00337 } 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 = nl_addr_alloc_attr(tb[IFLA_BROADCAST], 00345 AF_UNSPEC); 00346 if (link->l_bcast == NULL) { 00347 err = -NLE_NOMEM; 00348 goto errout; 00349 } 00350 nl_addr_set_family(link->l_bcast, 00351 nl_addr_guess_family(link->l_bcast)); 00352 link->ce_mask |= LINK_ATTR_BRD; 00353 } 00354 00355 if (tb[IFLA_LINK]) { 00356 link->l_link = nla_get_u32(tb[IFLA_LINK]); 00357 link->ce_mask |= LINK_ATTR_LINK; 00358 } 00359 00360 if (tb[IFLA_WEIGHT]) { 00361 link->l_weight = nla_get_u32(tb[IFLA_WEIGHT]); 00362 link->ce_mask |= LINK_ATTR_WEIGHT; 00363 } 00364 00365 if (tb[IFLA_QDISC]) { 00366 nla_strlcpy(link->l_qdisc, tb[IFLA_QDISC], IFQDISCSIZ); 00367 link->ce_mask |= LINK_ATTR_QDISC; 00368 } 00369 00370 if (tb[IFLA_MAP]) { 00371 nla_memcpy(&link->l_map, tb[IFLA_MAP], 00372 sizeof(struct rtnl_link_ifmap)); 00373 link->ce_mask |= LINK_ATTR_MAP; 00374 } 00375 00376 if (tb[IFLA_MASTER]) { 00377 link->l_master = nla_get_u32(tb[IFLA_MASTER]); 00378 link->ce_mask |= LINK_ATTR_MASTER; 00379 } 00380 00381 if (tb[IFLA_OPERSTATE]) { 00382 link->l_operstate = nla_get_u8(tb[IFLA_OPERSTATE]); 00383 link->ce_mask |= LINK_ATTR_OPERSTATE; 00384 } 00385 00386 if (tb[IFLA_LINKMODE]) { 00387 link->l_linkmode = nla_get_u8(tb[IFLA_LINKMODE]); 00388 link->ce_mask |= LINK_ATTR_LINKMODE; 00389 } 00390 00391 if (tb[IFLA_LINKINFO]) { 00392 struct nlattr *li[IFLA_INFO_MAX+1]; 00393 00394 err = nla_parse_nested(li, IFLA_INFO_MAX, tb[IFLA_LINKINFO], 00395 link_info_policy); 00396 if (err < 0) 00397 goto errout; 00398 00399 if (li[IFLA_INFO_KIND] && 00400 (li[IFLA_INFO_DATA] || li[IFLA_INFO_XSTATS])) { 00401 struct rtnl_link_info_ops *ops; 00402 char *kind; 00403 00404 kind = nla_get_string(li[IFLA_INFO_KIND]); 00405 ops = rtnl_link_info_ops_lookup(kind); 00406 if (ops != NULL) { 00407 ops->io_refcnt++; 00408 link->l_info_ops = ops; 00409 err = ops->io_parse(link, li[IFLA_INFO_DATA], 00410 li[IFLA_INFO_XSTATS]); 00411 if (err < 0) 00412 goto errout; 00413 } else { 00414 /* XXX: Warn about unparsed info? */ 00415 } 00416 } 00417 } 00418 00419 err = pp->pp_cb((struct nl_object *) link, pp); 00420 errout: 00421 rtnl_link_put(link); 00422 return err; 00423 } 00424 00425 static int link_request_update(struct nl_cache *cache, struct nl_sock *sk) 00426 { 00427 return nl_rtgen_request(sk, RTM_GETLINK, AF_UNSPEC, NLM_F_DUMP); 00428 } 00429 00430 static void link_dump_line(struct nl_object *obj, struct nl_dump_params *p) 00431 { 00432 char buf[128]; 00433 struct nl_cache *cache = dp_cache(obj); 00434 struct rtnl_link *link = (struct rtnl_link *) obj; 00435 00436 nl_dump_line(p, "%s %s ", link->l_name, 00437 nl_llproto2str(link->l_arptype, buf, sizeof(buf))); 00438 00439 if (link->l_addr && !nl_addr_iszero(link->l_addr)) 00440 nl_dump(p, "%s ", nl_addr2str(link->l_addr, buf, sizeof(buf))); 00441 00442 if (link->ce_mask & LINK_ATTR_MASTER) { 00443 struct rtnl_link *master = rtnl_link_get(cache, link->l_master); 00444 nl_dump(p, "master %s ", master ? master->l_name : "inv"); 00445 if (master) 00446 rtnl_link_put(master); 00447 } 00448 00449 rtnl_link_flags2str(link->l_flags, buf, sizeof(buf)); 00450 if (buf[0]) 00451 nl_dump(p, "<%s> ", buf); 00452 00453 if (link->ce_mask & LINK_ATTR_LINK) { 00454 struct rtnl_link *ll = rtnl_link_get(cache, link->l_link); 00455 nl_dump(p, "slave-of %s ", ll ? ll->l_name : "NONE"); 00456 if (ll) 00457 rtnl_link_put(ll); 00458 } 00459 00460 if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_LINE]) 00461 link->l_info_ops->io_dump[NL_DUMP_LINE](link, p); 00462 00463 nl_dump(p, "\n"); 00464 } 00465 00466 static void link_dump_details(struct nl_object *obj, struct nl_dump_params *p) 00467 { 00468 struct rtnl_link *link = (struct rtnl_link *) obj; 00469 char buf[64]; 00470 00471 link_dump_line(obj, p); 00472 00473 nl_dump_line(p, " mtu %u ", link->l_mtu); 00474 nl_dump(p, "txqlen %u weight %u ", link->l_txqlen, link->l_weight); 00475 00476 if (link->ce_mask & LINK_ATTR_QDISC) 00477 nl_dump(p, "qdisc %s ", link->l_qdisc); 00478 00479 if (link->ce_mask & LINK_ATTR_MAP && link->l_map.lm_irq) 00480 nl_dump(p, "irq %u ", link->l_map.lm_irq); 00481 00482 if (link->ce_mask & LINK_ATTR_IFINDEX) 00483 nl_dump(p, "index %u ", link->l_index); 00484 00485 00486 nl_dump(p, "\n"); 00487 nl_dump_line(p, " "); 00488 00489 if (link->ce_mask & LINK_ATTR_BRD) 00490 nl_dump(p, "brd %s ", nl_addr2str(link->l_bcast, buf, 00491 sizeof(buf))); 00492 00493 if ((link->ce_mask & LINK_ATTR_OPERSTATE) && 00494 link->l_operstate != IF_OPER_UNKNOWN) { 00495 rtnl_link_operstate2str(link->l_operstate, buf, sizeof(buf)); 00496 nl_dump(p, "state %s ", buf); 00497 } 00498 00499 nl_dump(p, "mode %s\n", 00500 rtnl_link_mode2str(link->l_linkmode, buf, sizeof(buf))); 00501 00502 if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_DETAILS]) 00503 link->l_info_ops->io_dump[NL_DUMP_DETAILS](link, p); 00504 } 00505 00506 static void link_dump_stats(struct nl_object *obj, struct nl_dump_params *p) 00507 { 00508 struct rtnl_link *link = (struct rtnl_link *) obj; 00509 char *unit, fmt[64]; 00510 float res; 00511 00512 link_dump_details(obj, p); 00513 00514 nl_dump_line(p, " Stats: bytes packets errors " 00515 " dropped fifo-err compressed\n"); 00516 00517 res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_RX_BYTES], &unit); 00518 00519 strcpy(fmt, " RX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n"); 00520 fmt[9] = *unit == 'B' ? '9' : '7'; 00521 00522 nl_dump_line(p, fmt, res, unit, 00523 link->l_stats[RTNL_LINK_RX_PACKETS], 00524 link->l_stats[RTNL_LINK_RX_ERRORS], 00525 link->l_stats[RTNL_LINK_RX_DROPPED], 00526 link->l_stats[RTNL_LINK_RX_FIFO_ERR], 00527 link->l_stats[RTNL_LINK_RX_COMPRESSED]); 00528 00529 res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_TX_BYTES], &unit); 00530 00531 strcpy(fmt, " TX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n"); 00532 fmt[9] = *unit == 'B' ? '9' : '7'; 00533 00534 nl_dump_line(p, fmt, res, unit, 00535 link->l_stats[RTNL_LINK_TX_PACKETS], 00536 link->l_stats[RTNL_LINK_TX_ERRORS], 00537 link->l_stats[RTNL_LINK_TX_DROPPED], 00538 link->l_stats[RTNL_LINK_TX_FIFO_ERR], 00539 link->l_stats[RTNL_LINK_TX_COMPRESSED]); 00540 00541 nl_dump_line(p, " Errors: length over crc " 00542 " frame missed multicast\n"); 00543 00544 nl_dump_line(p, " RX %10" PRIu64 " %10" PRIu64 " %10" 00545 PRIu64 " %10" PRIu64 " %10" PRIu64 " %10" 00546 PRIu64 "\n", 00547 link->l_stats[RTNL_LINK_RX_LEN_ERR], 00548 link->l_stats[RTNL_LINK_RX_OVER_ERR], 00549 link->l_stats[RTNL_LINK_RX_CRC_ERR], 00550 link->l_stats[RTNL_LINK_RX_FRAME_ERR], 00551 link->l_stats[RTNL_LINK_RX_MISSED_ERR], 00552 link->l_stats[RTNL_LINK_MULTICAST]); 00553 00554 nl_dump_line(p, " aborted carrier heartbeat " 00555 " window collision\n"); 00556 00557 nl_dump_line(p, " TX %10" PRIu64 " %10" PRIu64 " %10" 00558 PRIu64 " %10" PRIu64 " %10" PRIu64 "\n", 00559 link->l_stats[RTNL_LINK_TX_ABORT_ERR], 00560 link->l_stats[RTNL_LINK_TX_CARRIER_ERR], 00561 link->l_stats[RTNL_LINK_TX_HBEAT_ERR], 00562 link->l_stats[RTNL_LINK_TX_WIN_ERR], 00563 link->l_stats[RTNL_LINK_TX_COLLISIONS]); 00564 00565 if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_STATS]) 00566 link->l_info_ops->io_dump[NL_DUMP_STATS](link, p); 00567 } 00568 00569 static void link_dump_env(struct nl_object *obj, struct nl_dump_params *p) 00570 { 00571 struct rtnl_link *link = (struct rtnl_link *) obj; 00572 struct nl_cache *cache = dp_cache(obj); 00573 char buf[128]; 00574 int i; 00575 00576 nl_dump_line(p, "LINK_NAME=%s\n", link->l_name); 00577 nl_dump_line(p, "LINK_IFINDEX=%u\n", link->l_index); 00578 nl_dump_line(p, "LINK_FAMILY=%s\n", 00579 nl_af2str(link->l_family, buf, sizeof(buf))); 00580 nl_dump_line(p, "LINK_TYPE=%s\n", 00581 nl_llproto2str(link->l_arptype, buf, sizeof(buf))); 00582 if (link->ce_mask & LINK_ATTR_ADDR) 00583 nl_dump_line(p, "LINK_ADDRESS=%s\n", 00584 nl_addr2str(link->l_addr, buf, sizeof(buf))); 00585 nl_dump_line(p, "LINK_MTU=%u\n", link->l_mtu); 00586 nl_dump_line(p, "LINK_TXQUEUELEN=%u\n", link->l_txqlen); 00587 nl_dump_line(p, "LINK_WEIGHT=%u\n", link->l_weight); 00588 00589 rtnl_link_flags2str(link->l_flags & ~IFF_RUNNING, buf, sizeof(buf)); 00590 if (buf[0]) 00591 nl_dump_line(p, "LINK_FLAGS=%s\n", buf); 00592 00593 if (link->ce_mask & LINK_ATTR_QDISC) 00594 nl_dump_line(p, "LINK_QDISC=%s\n", link->l_qdisc); 00595 00596 if (link->ce_mask & LINK_ATTR_LINK) { 00597 struct rtnl_link *ll = rtnl_link_get(cache, link->l_link); 00598 00599 nl_dump_line(p, "LINK_LINK_IFINDEX=%d\n", link->l_link); 00600 if (ll) { 00601 nl_dump_line(p, "LINK_LINK_IFNAME=%s\n", ll->l_name); 00602 rtnl_link_put(ll); 00603 } 00604 } 00605 00606 if (link->ce_mask & LINK_ATTR_MASTER) { 00607 struct rtnl_link *master = rtnl_link_get(cache, link->l_master); 00608 nl_dump_line(p, "LINK_MASTER=%s\n", 00609 master ? master->l_name : "none"); 00610 if (master) 00611 rtnl_link_put(master); 00612 } 00613 00614 if (link->ce_mask & LINK_ATTR_BRD) 00615 nl_dump_line(p, "LINK_BROADCAST=%s\n", 00616 nl_addr2str(link->l_bcast, buf, sizeof(buf))); 00617 00618 if (link->ce_mask & LINK_ATTR_STATS) { 00619 for (i = 0; i <= RTNL_LINK_STATS_MAX; i++) { 00620 char *c = buf; 00621 00622 sprintf(buf, "LINK_"); 00623 rtnl_link_stat2str(i, buf + 5, sizeof(buf) - 5); 00624 while (*c) { 00625 *c = toupper(*c); 00626 c++; 00627 } 00628 nl_dump_line(p, "%s=%" PRIu64 "\n", buf, link->l_stats[i]); 00629 } 00630 } 00631 00632 if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_ENV]) 00633 link->l_info_ops->io_dump[NL_DUMP_ENV](link, p); 00634 } 00635 00636 #if 0 00637 static int link_handle_event(struct nl_object *a, struct rtnl_link_event_cb *cb) 00638 { 00639 struct rtnl_link *l = (struct rtnl_link *) a; 00640 struct nl_cache *c = dp_cache(a); 00641 int nevents = 0; 00642 00643 if (l->l_change == ~0U) { 00644 if (l->ce_msgtype == RTM_NEWLINK) 00645 cb->le_register(l); 00646 else 00647 cb->le_unregister(l); 00648 00649 return 1; 00650 } 00651 00652 if (l->l_change & IFF_SLAVE) { 00653 if (l->l_flags & IFF_SLAVE) { 00654 struct rtnl_link *m = rtnl_link_get(c, l->l_master); 00655 cb->le_new_bonding(l, m); 00656 if (m) 00657 rtnl_link_put(m); 00658 } else 00659 cb->le_cancel_bonding(l); 00660 } 00661 00662 #if 0 00663 if (l->l_change & IFF_UP && l->l_change & IFF_RUNNING) 00664 dp_dump_line(p, line++, "link %s changed state to %s.\n", 00665 l->l_name, l->l_flags & IFF_UP ? "up" : "down"); 00666 00667 if (l->l_change & IFF_PROMISC) { 00668 dp_new_line(p, line++); 00669 dp_dump(p, "link %s %s promiscuous mode.\n", 00670 l->l_name, l->l_flags & IFF_PROMISC ? "entered" : "left"); 00671 } 00672 00673 if (line == 0) 00674 dp_dump_line(p, line++, "link %s sent unknown event.\n", 00675 l->l_name); 00676 #endif 00677 00678 return nevents; 00679 } 00680 #endif 00681 00682 static int link_compare(struct nl_object *_a, struct nl_object *_b, 00683 uint32_t attrs, int flags) 00684 { 00685 struct rtnl_link *a = (struct rtnl_link *) _a; 00686 struct rtnl_link *b = (struct rtnl_link *) _b; 00687 int diff = 0; 00688 00689 #define LINK_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, LINK_ATTR_##ATTR, a, b, EXPR) 00690 00691 diff |= LINK_DIFF(IFINDEX, a->l_index != b->l_index); 00692 diff |= LINK_DIFF(MTU, a->l_mtu != b->l_mtu); 00693 diff |= LINK_DIFF(LINK, a->l_link != b->l_link); 00694 diff |= LINK_DIFF(TXQLEN, a->l_txqlen != b->l_txqlen); 00695 diff |= LINK_DIFF(WEIGHT, a->l_weight != b->l_weight); 00696 diff |= LINK_DIFF(MASTER, a->l_master != b->l_master); 00697 diff |= LINK_DIFF(FAMILY, a->l_family != b->l_family); 00698 diff |= LINK_DIFF(OPERSTATE, a->l_operstate != b->l_operstate); 00699 diff |= LINK_DIFF(LINKMODE, a->l_linkmode != b->l_linkmode); 00700 diff |= LINK_DIFF(QDISC, strcmp(a->l_qdisc, b->l_qdisc)); 00701 diff |= LINK_DIFF(IFNAME, strcmp(a->l_name, b->l_name)); 00702 diff |= LINK_DIFF(ADDR, nl_addr_cmp(a->l_addr, b->l_addr)); 00703 diff |= LINK_DIFF(BRD, nl_addr_cmp(a->l_bcast, b->l_bcast)); 00704 00705 if (flags & LOOSE_COMPARISON) 00706 diff |= LINK_DIFF(FLAGS, 00707 (a->l_flags ^ b->l_flags) & b->l_flag_mask); 00708 else 00709 diff |= LINK_DIFF(FLAGS, a->l_flags != b->l_flags); 00710 00711 #undef LINK_DIFF 00712 00713 return diff; 00714 } 00715 00716 static struct trans_tbl link_attrs[] = { 00717 __ADD(LINK_ATTR_MTU, mtu) 00718 __ADD(LINK_ATTR_LINK, link) 00719 __ADD(LINK_ATTR_TXQLEN, txqlen) 00720 __ADD(LINK_ATTR_WEIGHT, weight) 00721 __ADD(LINK_ATTR_MASTER, master) 00722 __ADD(LINK_ATTR_QDISC, qdisc) 00723 __ADD(LINK_ATTR_MAP, map) 00724 __ADD(LINK_ATTR_ADDR, address) 00725 __ADD(LINK_ATTR_BRD, broadcast) 00726 __ADD(LINK_ATTR_FLAGS, flags) 00727 __ADD(LINK_ATTR_IFNAME, name) 00728 __ADD(LINK_ATTR_IFINDEX, ifindex) 00729 __ADD(LINK_ATTR_FAMILY, family) 00730 __ADD(LINK_ATTR_ARPTYPE, arptype) 00731 __ADD(LINK_ATTR_STATS, stats) 00732 __ADD(LINK_ATTR_CHANGE, change) 00733 __ADD(LINK_ATTR_OPERSTATE, operstate) 00734 __ADD(LINK_ATTR_LINKMODE, linkmode) 00735 }; 00736 00737 static char *link_attrs2str(int attrs, char *buf, size_t len) 00738 { 00739 return __flags2str(attrs, buf, len, link_attrs, 00740 ARRAY_SIZE(link_attrs)); 00741 } 00742 00743 /** 00744 * @name Allocation/Freeing 00745 * @{ 00746 */ 00747 00748 struct rtnl_link *rtnl_link_alloc(void) 00749 { 00750 return (struct rtnl_link *) nl_object_alloc(&link_obj_ops); 00751 } 00752 00753 void rtnl_link_put(struct rtnl_link *link) 00754 { 00755 nl_object_put((struct nl_object *) link); 00756 } 00757 00758 /** @} */ 00759 00760 /** 00761 * @name Cache Management 00762 * @{ 00763 */ 00764 00765 00766 /** 00767 * Allocate link cache and fill in all configured links. 00768 * @arg sk Netlink socket. 00769 * @arg result Pointer to store resulting cache. 00770 * 00771 * Allocates a new link cache, initializes it properly and updates it 00772 * to include all links currently configured in the kernel. 00773 * 00774 * @return 0 on success or a negative error code. 00775 */ 00776 int rtnl_link_alloc_cache(struct nl_sock *sk, struct nl_cache **result) 00777 { 00778 return nl_cache_alloc_and_fill(&rtnl_link_ops, sk, result); 00779 } 00780 00781 /** 00782 * Look up link by interface index in the provided cache 00783 * @arg cache link cache 00784 * @arg ifindex link interface index 00785 * 00786 * The caller owns a reference on the returned object and 00787 * must give the object back via rtnl_link_put(). 00788 * 00789 * @return pointer to link inside the cache or NULL if no match was found. 00790 */ 00791 struct rtnl_link *rtnl_link_get(struct nl_cache *cache, int ifindex) 00792 { 00793 struct rtnl_link *link; 00794 00795 if (cache->c_ops != &rtnl_link_ops) 00796 return NULL; 00797 00798 nl_list_for_each_entry(link, &cache->c_items, ce_list) { 00799 if (link->l_index == ifindex) { 00800 nl_object_get((struct nl_object *) link); 00801 return link; 00802 } 00803 } 00804 00805 return NULL; 00806 } 00807 00808 /** 00809 * Look up link by link name in the provided cache 00810 * @arg cache link cache 00811 * @arg name link name 00812 * 00813 * The caller owns a reference on the returned object and 00814 * must give the object back via rtnl_link_put(). 00815 * 00816 * @return pointer to link inside the cache or NULL if no match was found. 00817 */ 00818 struct rtnl_link *rtnl_link_get_by_name(struct nl_cache *cache, 00819 const char *name) 00820 { 00821 struct rtnl_link *link; 00822 00823 if (cache->c_ops != &rtnl_link_ops) 00824 return NULL; 00825 00826 nl_list_for_each_entry(link, &cache->c_items, ce_list) { 00827 if (!strcmp(name, link->l_name)) { 00828 nl_object_get((struct nl_object *) link); 00829 return link; 00830 } 00831 } 00832 00833 return NULL; 00834 } 00835 00836 /** @} */ 00837 00838 /** 00839 * @name Link Modifications 00840 * @{ 00841 */ 00842 00843 /** 00844 * Builds a netlink change request message to change link attributes 00845 * @arg old link to be changed 00846 * @arg tmpl template with requested changes 00847 * @arg flags additional netlink message flags 00848 * 00849 * Builds a new netlink message requesting a change of link attributes. 00850 * The netlink message header isn't fully equipped with all relevant 00851 * fields and must be sent out via nl_send_auto_complete() or 00852 * supplemented as needed. 00853 * \a old must point to a link currently configured in the kernel 00854 * and \a tmpl must contain the attributes to be changed set via 00855 * \c rtnl_link_set_* functions. 00856 * 00857 * @return New netlink message 00858 * @note Not all attributes can be changed, see 00859 * \ref link_changeable "Changeable Attributes" for more details. 00860 */ 00861 int rtnl_link_build_change_request(struct rtnl_link *old, 00862 struct rtnl_link *tmpl, int flags, 00863 struct nl_msg **result) 00864 { 00865 struct nl_msg *msg; 00866 struct ifinfomsg ifi = { 00867 .ifi_family = old->l_family, 00868 .ifi_index = old->l_index, 00869 }; 00870 00871 if (tmpl->ce_mask & LINK_ATTR_FLAGS) { 00872 ifi.ifi_flags = old->l_flags & ~tmpl->l_flag_mask; 00873 ifi.ifi_flags |= tmpl->l_flags; 00874 } 00875 00876 msg = nlmsg_alloc_simple(RTM_SETLINK, flags); 00877 if (!msg) 00878 return -NLE_NOMEM; 00879 00880 if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0) 00881 goto nla_put_failure; 00882 00883 if (tmpl->ce_mask & LINK_ATTR_ADDR) 00884 NLA_PUT_ADDR(msg, IFLA_ADDRESS, tmpl->l_addr); 00885 00886 if (tmpl->ce_mask & LINK_ATTR_BRD) 00887 NLA_PUT_ADDR(msg, IFLA_BROADCAST, tmpl->l_bcast); 00888 00889 if (tmpl->ce_mask & LINK_ATTR_MTU) 00890 NLA_PUT_U32(msg, IFLA_MTU, tmpl->l_mtu); 00891 00892 if (tmpl->ce_mask & LINK_ATTR_TXQLEN) 00893 NLA_PUT_U32(msg, IFLA_TXQLEN, tmpl->l_txqlen); 00894 00895 if (tmpl->ce_mask & LINK_ATTR_WEIGHT) 00896 NLA_PUT_U32(msg, IFLA_WEIGHT, tmpl->l_weight); 00897 00898 if (tmpl->ce_mask & LINK_ATTR_IFNAME) 00899 NLA_PUT_STRING(msg, IFLA_IFNAME, tmpl->l_name); 00900 00901 if (tmpl->ce_mask & LINK_ATTR_OPERSTATE) 00902 NLA_PUT_U8(msg, IFLA_OPERSTATE, tmpl->l_operstate); 00903 00904 if (tmpl->ce_mask & LINK_ATTR_LINKMODE) 00905 NLA_PUT_U8(msg, IFLA_LINKMODE, tmpl->l_linkmode); 00906 00907 if ((tmpl->ce_mask & LINK_ATTR_LINKINFO) && tmpl->l_info_ops && 00908 tmpl->l_info_ops->io_put_attrs) { 00909 struct nlattr *info; 00910 00911 if (!(info = nla_nest_start(msg, IFLA_LINKINFO))) 00912 goto nla_put_failure; 00913 00914 NLA_PUT_STRING(msg, IFLA_INFO_KIND, tmpl->l_info_ops->io_name); 00915 00916 if (tmpl->l_info_ops->io_put_attrs(msg, tmpl) < 0) 00917 goto nla_put_failure; 00918 00919 nla_nest_end(msg, info); 00920 } 00921 00922 *result = msg; 00923 return 0; 00924 00925 nla_put_failure: 00926 nlmsg_free(msg); 00927 return -NLE_MSGSIZE; 00928 } 00929 00930 /** 00931 * Change link attributes 00932 * @arg sk Netlink socket. 00933 * @arg old link to be changed 00934 * @arg tmpl template with requested changes 00935 * @arg flags additional netlink message flags 00936 * 00937 * Builds a new netlink message by calling rtnl_link_build_change_request(), 00938 * sends the request to the kernel and waits for the next ACK to be 00939 * received, i.e. blocks until the request has been processed. 00940 * 00941 * @return 0 on success or a negative error code 00942 * @note Not all attributes can be changed, see 00943 * \ref link_changeable "Changeable Attributes" for more details. 00944 */ 00945 int rtnl_link_change(struct nl_sock *sk, struct rtnl_link *old, 00946 struct rtnl_link *tmpl, int flags) 00947 { 00948 struct nl_msg *msg; 00949 int err; 00950 00951 if ((err = rtnl_link_build_change_request(old, tmpl, flags, &msg)) < 0) 00952 return err; 00953 00954 err = nl_send_auto_complete(sk, msg); 00955 nlmsg_free(msg); 00956 if (err < 0) 00957 return err; 00958 00959 return wait_for_ack(sk); 00960 } 00961 00962 /** @} */ 00963 00964 /** 00965 * @name Name <-> Index Translations 00966 * @{ 00967 */ 00968 00969 /** 00970 * Translate an interface index to the corresponding link name 00971 * @arg cache link cache 00972 * @arg ifindex link interface index 00973 * @arg dst destination buffer 00974 * @arg len length of destination buffer 00975 * 00976 * Translates the specified interface index to the corresponding 00977 * link name and stores the name in the destination buffer. 00978 * 00979 * @return link name or NULL if no match was found. 00980 */ 00981 char * rtnl_link_i2name(struct nl_cache *cache, int ifindex, char *dst, 00982 size_t len) 00983 { 00984 struct rtnl_link *link = rtnl_link_get(cache, ifindex); 00985 00986 if (link) { 00987 strncpy(dst, link->l_name, len - 1); 00988 rtnl_link_put(link); 00989 return dst; 00990 } 00991 00992 return NULL; 00993 } 00994 00995 /** 00996 * Translate a link name to the corresponding interface index 00997 * @arg cache link cache 00998 * @arg name link name 00999 * 01000 * @return interface index or 0 if no match was found. 01001 */ 01002 int rtnl_link_name2i(struct nl_cache *cache, const char *name) 01003 { 01004 int ifindex = 0; 01005 struct rtnl_link *link; 01006 01007 link = rtnl_link_get_by_name(cache, name); 01008 if (link) { 01009 ifindex = link->l_index; 01010 rtnl_link_put(link); 01011 } 01012 01013 return ifindex; 01014 } 01015 01016 /** @} */ 01017 01018 /** 01019 * @name Link Flags Translations 01020 * @{ 01021 */ 01022 01023 static struct trans_tbl link_flags[] = { 01024 __ADD(IFF_LOOPBACK, loopback) 01025 __ADD(IFF_BROADCAST, broadcast) 01026 __ADD(IFF_POINTOPOINT, pointopoint) 01027 __ADD(IFF_MULTICAST, multicast) 01028 __ADD(IFF_NOARP, noarp) 01029 __ADD(IFF_ALLMULTI, allmulti) 01030 __ADD(IFF_PROMISC, promisc) 01031 __ADD(IFF_MASTER, master) 01032 __ADD(IFF_SLAVE, slave) 01033 __ADD(IFF_DEBUG, debug) 01034 __ADD(IFF_DYNAMIC, dynamic) 01035 __ADD(IFF_AUTOMEDIA, automedia) 01036 __ADD(IFF_PORTSEL, portsel) 01037 __ADD(IFF_NOTRAILERS, notrailers) 01038 __ADD(IFF_UP, up) 01039 __ADD(IFF_RUNNING, running) 01040 __ADD(IFF_LOWER_UP, lowerup) 01041 __ADD(IFF_DORMANT, dormant) 01042 __ADD(IFF_ECHO, echo) 01043 }; 01044 01045 char * rtnl_link_flags2str(int flags, char *buf, size_t len) 01046 { 01047 return __flags2str(flags, buf, len, link_flags, 01048 ARRAY_SIZE(link_flags)); 01049 } 01050 01051 int rtnl_link_str2flags(const char *name) 01052 { 01053 return __str2flags(name, link_flags, ARRAY_SIZE(link_flags)); 01054 } 01055 01056 /** @} */ 01057 01058 /** 01059 * @name Link Statistics Translations 01060 * @{ 01061 */ 01062 01063 static struct trans_tbl link_stats[] = { 01064 __ADD(RTNL_LINK_RX_PACKETS, rx_packets) 01065 __ADD(RTNL_LINK_TX_PACKETS, tx_packets) 01066 __ADD(RTNL_LINK_RX_BYTES, rx_bytes) 01067 __ADD(RTNL_LINK_TX_BYTES, tx_bytes) 01068 __ADD(RTNL_LINK_RX_ERRORS, rx_errors) 01069 __ADD(RTNL_LINK_TX_ERRORS, tx_errors) 01070 __ADD(RTNL_LINK_RX_DROPPED, rx_dropped) 01071 __ADD(RTNL_LINK_TX_DROPPED, tx_dropped) 01072 __ADD(RTNL_LINK_RX_COMPRESSED, rx_compressed) 01073 __ADD(RTNL_LINK_TX_COMPRESSED, tx_compressed) 01074 __ADD(RTNL_LINK_RX_FIFO_ERR, rx_fifo_err) 01075 __ADD(RTNL_LINK_TX_FIFO_ERR, tx_fifo_err) 01076 __ADD(RTNL_LINK_RX_LEN_ERR, rx_len_err) 01077 __ADD(RTNL_LINK_RX_OVER_ERR, rx_over_err) 01078 __ADD(RTNL_LINK_RX_CRC_ERR, rx_crc_err) 01079 __ADD(RTNL_LINK_RX_FRAME_ERR, rx_frame_err) 01080 __ADD(RTNL_LINK_RX_MISSED_ERR, rx_missed_err) 01081 __ADD(RTNL_LINK_TX_ABORT_ERR, tx_abort_err) 01082 __ADD(RTNL_LINK_TX_CARRIER_ERR, tx_carrier_err) 01083 __ADD(RTNL_LINK_TX_HBEAT_ERR, tx_hbeat_err) 01084 __ADD(RTNL_LINK_TX_WIN_ERR, tx_win_err) 01085 __ADD(RTNL_LINK_TX_COLLISIONS, tx_collision) 01086 __ADD(RTNL_LINK_MULTICAST, multicast) 01087 }; 01088 01089 char *rtnl_link_stat2str(int st, char *buf, size_t len) 01090 { 01091 return __type2str(st, buf, len, link_stats, ARRAY_SIZE(link_stats)); 01092 } 01093 01094 int rtnl_link_str2stat(const char *name) 01095 { 01096 return __str2type(name, link_stats, ARRAY_SIZE(link_stats)); 01097 } 01098 01099 /** @} */ 01100 01101 /** 01102 * @name Link Operstate Translations 01103 * @{ 01104 */ 01105 01106 static struct trans_tbl link_operstates[] = { 01107 __ADD(IF_OPER_UNKNOWN, unknown) 01108 __ADD(IF_OPER_NOTPRESENT, notpresent) 01109 __ADD(IF_OPER_DOWN, down) 01110 __ADD(IF_OPER_LOWERLAYERDOWN, lowerlayerdown) 01111 __ADD(IF_OPER_TESTING, testing) 01112 __ADD(IF_OPER_DORMANT, dormant) 01113 __ADD(IF_OPER_UP, up) 01114 }; 01115 01116 char *rtnl_link_operstate2str(int st, char *buf, size_t len) 01117 { 01118 return __type2str(st, buf, len, link_operstates, 01119 ARRAY_SIZE(link_operstates)); 01120 } 01121 01122 int rtnl_link_str2operstate(const char *name) 01123 { 01124 return __str2type(name, link_operstates, 01125 ARRAY_SIZE(link_operstates)); 01126 } 01127 01128 /** @} */ 01129 01130 /** 01131 * @name Link Mode Translations 01132 * @{ 01133 */ 01134 01135 static struct trans_tbl link_modes[] = { 01136 __ADD(IF_LINK_MODE_DEFAULT, default) 01137 __ADD(IF_LINK_MODE_DORMANT, dormant) 01138 }; 01139 01140 char *rtnl_link_mode2str(int st, char *buf, size_t len) 01141 { 01142 return __type2str(st, buf, len, link_modes, ARRAY_SIZE(link_modes)); 01143 } 01144 01145 int rtnl_link_str2mode(const char *name) 01146 { 01147 return __str2type(name, link_modes, ARRAY_SIZE(link_modes)); 01148 } 01149 01150 /** @} */ 01151 01152 /** 01153 * @name Attributes 01154 * @{ 01155 */ 01156 01157 void rtnl_link_set_qdisc(struct rtnl_link *link, const char *qdisc) 01158 { 01159 strncpy(link->l_qdisc, qdisc, sizeof(link->l_qdisc) - 1); 01160 link->ce_mask |= LINK_ATTR_QDISC; 01161 } 01162 01163 char *rtnl_link_get_qdisc(struct rtnl_link *link) 01164 { 01165 if (link->ce_mask & LINK_ATTR_QDISC) 01166 return link->l_qdisc; 01167 else 01168 return NULL; 01169 } 01170 01171 void rtnl_link_set_name(struct rtnl_link *link, const char *name) 01172 { 01173 strncpy(link->l_name, name, sizeof(link->l_name) - 1); 01174 link->ce_mask |= LINK_ATTR_IFNAME; 01175 } 01176 01177 char *rtnl_link_get_name(struct rtnl_link *link) 01178 { 01179 if (link->ce_mask & LINK_ATTR_IFNAME) 01180 return link->l_name; 01181 else 01182 return NULL; 01183 } 01184 01185 static inline void __assign_addr(struct rtnl_link *link, struct nl_addr **pos, 01186 struct nl_addr *new, int flag) 01187 { 01188 if (*pos) 01189 nl_addr_put(*pos); 01190 01191 nl_addr_get(new); 01192 *pos = new; 01193 01194 link->ce_mask |= flag; 01195 } 01196 01197 void rtnl_link_set_addr(struct rtnl_link *link, struct nl_addr *addr) 01198 { 01199 __assign_addr(link, &link->l_addr, addr, LINK_ATTR_ADDR); 01200 } 01201 01202 struct nl_addr *rtnl_link_get_addr(struct rtnl_link *link) 01203 { 01204 if (link->ce_mask & LINK_ATTR_ADDR) 01205 return link->l_addr; 01206 else 01207 return NULL; 01208 } 01209 01210 void rtnl_link_set_broadcast(struct rtnl_link *link, struct nl_addr *brd) 01211 { 01212 __assign_addr(link, &link->l_bcast, brd, LINK_ATTR_BRD); 01213 } 01214 01215 struct nl_addr *rtnl_link_get_broadcast(struct rtnl_link *link) 01216 { 01217 if (link->ce_mask & LINK_ATTR_BRD) 01218 return link->l_bcast; 01219 else 01220 return NULL; 01221 } 01222 01223 void rtnl_link_set_flags(struct rtnl_link *link, unsigned int flags) 01224 { 01225 link->l_flag_mask |= flags; 01226 link->l_flags |= flags; 01227 link->ce_mask |= LINK_ATTR_FLAGS; 01228 } 01229 01230 void rtnl_link_unset_flags(struct rtnl_link *link, unsigned int flags) 01231 { 01232 link->l_flag_mask |= flags; 01233 link->l_flags &= ~flags; 01234 link->ce_mask |= LINK_ATTR_FLAGS; 01235 } 01236 01237 unsigned int rtnl_link_get_flags(struct rtnl_link *link) 01238 { 01239 return link->l_flags; 01240 } 01241 01242 void rtnl_link_set_family(struct rtnl_link *link, int family) 01243 { 01244 link->l_family = family; 01245 link->ce_mask |= LINK_ATTR_FAMILY; 01246 } 01247 01248 int rtnl_link_get_family(struct rtnl_link *link) 01249 { 01250 if (link->l_family & LINK_ATTR_FAMILY) 01251 return link->l_family; 01252 else 01253 return AF_UNSPEC; 01254 } 01255 01256 void rtnl_link_set_arptype(struct rtnl_link *link, unsigned int arptype) 01257 { 01258 link->l_arptype = arptype; 01259 } 01260 01261 unsigned int rtnl_link_get_arptype(struct rtnl_link *link) 01262 { 01263 return link->l_arptype; 01264 } 01265 01266 void rtnl_link_set_ifindex(struct rtnl_link *link, int ifindex) 01267 { 01268 link->l_index = ifindex; 01269 link->ce_mask |= LINK_ATTR_IFINDEX; 01270 } 01271 01272 int rtnl_link_get_ifindex(struct rtnl_link *link) 01273 { 01274 return link->l_index; 01275 } 01276 01277 void rtnl_link_set_mtu(struct rtnl_link *link, unsigned int mtu) 01278 { 01279 link->l_mtu = mtu; 01280 link->ce_mask |= LINK_ATTR_MTU; 01281 } 01282 01283 unsigned int rtnl_link_get_mtu(struct rtnl_link *link) 01284 { 01285 if (link->ce_mask & LINK_ATTR_MTU) 01286 return link->l_mtu; 01287 else 01288 return 0; 01289 } 01290 01291 void rtnl_link_set_txqlen(struct rtnl_link *link, unsigned int txqlen) 01292 { 01293 link->l_txqlen = txqlen; 01294 link->ce_mask |= LINK_ATTR_TXQLEN; 01295 } 01296 01297 unsigned int rtnl_link_get_txqlen(struct rtnl_link *link) 01298 { 01299 if (link->ce_mask & LINK_ATTR_TXQLEN) 01300 return link->l_txqlen; 01301 else 01302 return UINT_MAX; 01303 } 01304 01305 void rtnl_link_set_weight(struct rtnl_link *link, unsigned int weight) 01306 { 01307 link->l_weight = weight; 01308 link->ce_mask |= LINK_ATTR_WEIGHT; 01309 } 01310 01311 unsigned int rtnl_link_get_weight(struct rtnl_link *link) 01312 { 01313 if (link->ce_mask & LINK_ATTR_WEIGHT) 01314 return link->l_weight; 01315 else 01316 return UINT_MAX; 01317 } 01318 01319 void rtnl_link_set_link(struct rtnl_link *link, int ifindex) 01320 { 01321 link->l_link = ifindex; 01322 link->ce_mask |= LINK_ATTR_LINK; 01323 } 01324 01325 int rtnl_link_get_link(struct rtnl_link *link) 01326 { 01327 return link->l_link; 01328 } 01329 01330 void rtnl_link_set_master(struct rtnl_link *link, int ifindex) 01331 { 01332 link->l_master = ifindex; 01333 link->ce_mask |= LINK_ATTR_MASTER; 01334 } 01335 01336 int rtnl_link_get_master(struct rtnl_link *link) 01337 { 01338 return link->l_master; 01339 } 01340 01341 void rtnl_link_set_operstate(struct rtnl_link *link, uint8_t operstate) 01342 { 01343 link->l_operstate = operstate; 01344 link->ce_mask |= LINK_ATTR_OPERSTATE; 01345 } 01346 01347 uint8_t rtnl_link_get_operstate(struct rtnl_link *link) 01348 { 01349 if (link->ce_mask & LINK_ATTR_OPERSTATE) 01350 return link->l_operstate; 01351 else 01352 return IF_OPER_UNKNOWN; 01353 } 01354 01355 void rtnl_link_set_linkmode(struct rtnl_link *link, uint8_t linkmode) 01356 { 01357 link->l_linkmode = linkmode; 01358 link->ce_mask |= LINK_ATTR_LINKMODE; 01359 } 01360 01361 uint8_t rtnl_link_get_linkmode(struct rtnl_link *link) 01362 { 01363 if (link->ce_mask & LINK_ATTR_LINKMODE) 01364 return link->l_linkmode; 01365 else 01366 return IF_LINK_MODE_DEFAULT; 01367 } 01368 01369 uint64_t rtnl_link_get_stat(struct rtnl_link *link, int id) 01370 { 01371 if (id < 0 || id > RTNL_LINK_STATS_MAX) 01372 return 0; 01373 01374 return link->l_stats[id]; 01375 } 01376 01377 /** 01378 * Specify the info type of a link 01379 * @arg link link object 01380 * @arg type info type 01381 * 01382 * Looks up the info type and prepares the link to store info type 01383 * specific attributes. If an info type has been assigned already 01384 * it will be released with all changes lost. 01385 * 01386 * @return 0 on success or a negative errror code. 01387 */ 01388 int rtnl_link_set_info_type(struct rtnl_link *link, const char *type) 01389 { 01390 struct rtnl_link_info_ops *io; 01391 int err; 01392 01393 if ((io = rtnl_link_info_ops_lookup(type)) == NULL) 01394 return -NLE_OPNOTSUPP; 01395 01396 if (link->l_info_ops) 01397 release_link_info(link); 01398 01399 if ((err = io->io_alloc(link)) < 0) 01400 return err; 01401 01402 link->l_info_ops = io; 01403 01404 return 0; 01405 } 01406 01407 /** 01408 * Return info type of a link 01409 * @arg link link object 01410 * 01411 * @note The returned pointer is only valid as long as the link exists 01412 * @return Info type name or NULL if unknown. 01413 */ 01414 char *rtnl_link_get_info_type(struct rtnl_link *link) 01415 { 01416 if (link->l_info_ops) 01417 return link->l_info_ops->io_name; 01418 else 01419 return NULL; 01420 } 01421 01422 /** @} */ 01423 01424 static struct nl_object_ops link_obj_ops = { 01425 .oo_name = "route/link", 01426 .oo_size = sizeof(struct rtnl_link), 01427 .oo_free_data = link_free_data, 01428 .oo_clone = link_clone, 01429 .oo_dump = { 01430 [NL_DUMP_LINE] = link_dump_line, 01431 [NL_DUMP_DETAILS] = link_dump_details, 01432 [NL_DUMP_STATS] = link_dump_stats, 01433 [NL_DUMP_ENV] = link_dump_env, 01434 }, 01435 .oo_compare = link_compare, 01436 .oo_attrs2str = link_attrs2str, 01437 .oo_id_attrs = LINK_ATTR_IFINDEX, 01438 }; 01439 01440 static struct nl_af_group link_groups[] = { 01441 { AF_UNSPEC, RTNLGRP_LINK }, 01442 { END_OF_GROUP_LIST }, 01443 }; 01444 01445 static struct nl_cache_ops rtnl_link_ops = { 01446 .co_name = "route/link", 01447 .co_hdrsize = sizeof(struct ifinfomsg), 01448 .co_msgtypes = { 01449 { RTM_NEWLINK, NL_ACT_NEW, "new" }, 01450 { RTM_DELLINK, NL_ACT_DEL, "del" }, 01451 { RTM_GETLINK, NL_ACT_GET, "get" }, 01452 END_OF_MSGTYPES_LIST, 01453 }, 01454 .co_protocol = NETLINK_ROUTE, 01455 .co_groups = link_groups, 01456 .co_request_update = link_request_update, 01457 .co_msg_parser = link_msg_parser, 01458 .co_obj_ops = &link_obj_ops, 01459 }; 01460 01461 static void __init link_init(void) 01462 { 01463 nl_cache_mngt_register(&rtnl_link_ops); 01464 } 01465 01466 static void __exit link_exit(void) 01467 { 01468 nl_cache_mngt_unregister(&rtnl_link_ops); 01469 } 01470 01471 /** @} */