libnl 3.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-2010 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, 0); 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/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 #define LINK_ATTR_IFALIAS 0x80000 00180 #define LINK_ATTR_NUM_VF 0x100000 00181 00182 static struct nl_cache_ops rtnl_link_ops; 00183 static struct nl_object_ops link_obj_ops; 00184 /** @endcond */ 00185 00186 static struct rtnl_link_af_ops *af_lookup_and_alloc(struct rtnl_link *link, 00187 int family) 00188 { 00189 struct rtnl_link_af_ops *af_ops; 00190 void *data; 00191 00192 af_ops = rtnl_link_af_ops_lookup(family); 00193 if (!af_ops) 00194 return NULL; 00195 00196 if (!(data = rtnl_link_af_alloc(link, af_ops))) 00197 return NULL; 00198 00199 return af_ops; 00200 } 00201 00202 static int af_free(struct rtnl_link *link, struct rtnl_link_af_ops *ops, 00203 void *data, void *arg) 00204 { 00205 if (ops->ao_free) 00206 ops->ao_free(link, data); 00207 00208 rtnl_link_af_ops_put(ops); 00209 00210 return 0; 00211 } 00212 00213 static int af_clone(struct rtnl_link *link, struct rtnl_link_af_ops *ops, 00214 void *data, void *arg) 00215 { 00216 struct rtnl_link *dst = arg; 00217 00218 if (ops->ao_clone && 00219 !(dst->l_af_data[ops->ao_family] = ops->ao_clone(link, data))) 00220 return -NLE_NOMEM; 00221 00222 return 0; 00223 } 00224 00225 static int af_fill(struct rtnl_link *link, struct rtnl_link_af_ops *ops, 00226 void *data, void *arg) 00227 { 00228 struct nl_msg *msg = arg; 00229 struct nlattr *af_attr; 00230 int err; 00231 00232 if (!ops->ao_fill_af) 00233 return 0; 00234 00235 if (!(af_attr = nla_nest_start(msg, ops->ao_family))) 00236 return -NLE_MSGSIZE; 00237 00238 if ((err = ops->ao_fill_af(link, arg, data)) < 0) 00239 return err; 00240 00241 nla_nest_end(msg, af_attr); 00242 00243 return 0; 00244 } 00245 00246 static int af_dump_line(struct rtnl_link *link, struct rtnl_link_af_ops *ops, 00247 void *data, void *arg) 00248 { 00249 struct nl_dump_params *p = arg; 00250 00251 if (ops->ao_dump[NL_DUMP_LINE]) 00252 ops->ao_dump[NL_DUMP_LINE](link, p, data); 00253 00254 return 0; 00255 } 00256 00257 static int af_dump_details(struct rtnl_link *link, struct rtnl_link_af_ops *ops, 00258 void *data, void *arg) 00259 { 00260 struct nl_dump_params *p = arg; 00261 00262 if (ops->ao_dump[NL_DUMP_DETAILS]) 00263 ops->ao_dump[NL_DUMP_DETAILS](link, p, data); 00264 00265 return 0; 00266 } 00267 00268 static int af_dump_stats(struct rtnl_link *link, struct rtnl_link_af_ops *ops, 00269 void *data, void *arg) 00270 { 00271 struct nl_dump_params *p = arg; 00272 00273 if (ops->ao_dump[NL_DUMP_STATS]) 00274 ops->ao_dump[NL_DUMP_STATS](link, p, data); 00275 00276 return 0; 00277 } 00278 00279 static int do_foreach_af(struct rtnl_link *link, 00280 int (*cb)(struct rtnl_link *, 00281 struct rtnl_link_af_ops *, void *, void *), 00282 void *arg) 00283 { 00284 int i, err; 00285 00286 for (i = 0; i < AF_MAX; i++) { 00287 if (link->l_af_data[i]) { 00288 struct rtnl_link_af_ops *ops; 00289 00290 if (!(ops = rtnl_link_af_ops_lookup(i))) 00291 BUG(); 00292 00293 if ((err = cb(link, ops, link->l_af_data[i], arg)) < 0) 00294 return err; 00295 } 00296 } 00297 00298 return 0; 00299 } 00300 00301 static void release_link_info(struct rtnl_link *link) 00302 { 00303 struct rtnl_link_info_ops *io = link->l_info_ops; 00304 00305 if (io != NULL) { 00306 io->io_free(link); 00307 rtnl_link_info_ops_put(io); 00308 link->l_info_ops = NULL; 00309 } 00310 } 00311 00312 static void link_free_data(struct nl_object *c) 00313 { 00314 struct rtnl_link *link = nl_object_priv(c); 00315 00316 if (link) { 00317 struct rtnl_link_info_ops *io; 00318 00319 if ((io = link->l_info_ops) != NULL) 00320 release_link_info(link); 00321 00322 nl_addr_put(link->l_addr); 00323 nl_addr_put(link->l_bcast); 00324 00325 free(link->l_ifalias); 00326 00327 do_foreach_af(link, af_free, NULL); 00328 } 00329 } 00330 00331 static int link_clone(struct nl_object *_dst, struct nl_object *_src) 00332 { 00333 struct rtnl_link *dst = nl_object_priv(_dst); 00334 struct rtnl_link *src = nl_object_priv(_src); 00335 int err; 00336 00337 if (src->l_addr) 00338 if (!(dst->l_addr = nl_addr_clone(src->l_addr))) 00339 return -NLE_NOMEM; 00340 00341 if (src->l_bcast) 00342 if (!(dst->l_bcast = nl_addr_clone(src->l_bcast))) 00343 return -NLE_NOMEM; 00344 00345 if (src->l_ifalias) 00346 if (!(dst->l_ifalias = strdup(src->l_ifalias))) 00347 return -NLE_NOMEM; 00348 00349 if (src->l_info_ops && src->l_info_ops->io_clone) { 00350 err = src->l_info_ops->io_clone(dst, src); 00351 if (err < 0) 00352 return err; 00353 } 00354 00355 if ((err = do_foreach_af(src, af_clone, dst)) < 0) 00356 return err; 00357 00358 return 0; 00359 } 00360 00361 static struct nla_policy link_policy[IFLA_MAX+1] = { 00362 [IFLA_IFNAME] = { .type = NLA_STRING, 00363 .maxlen = IFNAMSIZ }, 00364 [IFLA_MTU] = { .type = NLA_U32 }, 00365 [IFLA_TXQLEN] = { .type = NLA_U32 }, 00366 [IFLA_LINK] = { .type = NLA_U32 }, 00367 [IFLA_WEIGHT] = { .type = NLA_U32 }, 00368 [IFLA_MASTER] = { .type = NLA_U32 }, 00369 [IFLA_OPERSTATE]= { .type = NLA_U8 }, 00370 [IFLA_LINKMODE] = { .type = NLA_U8 }, 00371 [IFLA_LINKINFO] = { .type = NLA_NESTED }, 00372 [IFLA_QDISC] = { .type = NLA_STRING, 00373 .maxlen = IFQDISCSIZ }, 00374 [IFLA_STATS] = { .minlen = sizeof(struct rtnl_link_stats) }, 00375 [IFLA_STATS64] = { .minlen = sizeof(struct rtnl_link_stats64) }, 00376 [IFLA_MAP] = { .minlen = sizeof(struct rtnl_link_ifmap) }, 00377 [IFLA_IFALIAS] = { .type = NLA_STRING, .maxlen = IFALIASZ }, 00378 [IFLA_NUM_VF] = { .type = NLA_U32 }, 00379 [IFLA_AF_SPEC] = { .type = NLA_NESTED }, 00380 }; 00381 00382 static struct nla_policy link_info_policy[IFLA_INFO_MAX+1] = { 00383 [IFLA_INFO_KIND] = { .type = NLA_STRING }, 00384 [IFLA_INFO_DATA] = { .type = NLA_NESTED }, 00385 [IFLA_INFO_XSTATS] = { .type = NLA_NESTED }, 00386 }; 00387 00388 static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, 00389 struct nlmsghdr *n, struct nl_parser_param *pp) 00390 { 00391 struct rtnl_link *link; 00392 struct ifinfomsg *ifi; 00393 struct nlattr *tb[IFLA_MAX+1]; 00394 struct rtnl_link_af_ops *af_ops = NULL; 00395 int err, family; 00396 00397 link = rtnl_link_alloc(); 00398 if (link == NULL) { 00399 err = -NLE_NOMEM; 00400 goto errout; 00401 } 00402 00403 link->ce_msgtype = n->nlmsg_type; 00404 00405 if (!nlmsg_valid_hdr(n, sizeof(*ifi))) 00406 return -NLE_MSG_TOOSHORT; 00407 00408 ifi = nlmsg_data(n); 00409 link->l_family = family = ifi->ifi_family; 00410 link->l_arptype = ifi->ifi_type; 00411 link->l_index = ifi->ifi_index; 00412 link->l_flags = ifi->ifi_flags; 00413 link->l_change = ifi->ifi_change; 00414 link->ce_mask = (LINK_ATTR_IFNAME | LINK_ATTR_FAMILY | 00415 LINK_ATTR_ARPTYPE| LINK_ATTR_IFINDEX | 00416 LINK_ATTR_FLAGS | LINK_ATTR_CHANGE); 00417 00418 if ((af_ops = af_lookup_and_alloc(link, family))) { 00419 if (af_ops->ao_protinfo_policy) { 00420 memcpy(&link_policy[IFLA_PROTINFO], 00421 af_ops->ao_protinfo_policy, 00422 sizeof(struct nla_policy)); 00423 } 00424 } 00425 00426 err = nlmsg_parse(n, sizeof(*ifi), tb, IFLA_MAX, link_policy); 00427 if (err < 0) 00428 goto errout; 00429 00430 if (tb[IFLA_IFNAME] == NULL) { 00431 err = -NLE_MISSING_ATTR; 00432 goto errout; 00433 } 00434 00435 nla_strlcpy(link->l_name, tb[IFLA_IFNAME], IFNAMSIZ); 00436 00437 00438 if (tb[IFLA_STATS]) { 00439 struct rtnl_link_stats *st = nla_data(tb[IFLA_STATS]); 00440 00441 link->l_stats[RTNL_LINK_RX_PACKETS] = st->rx_packets; 00442 link->l_stats[RTNL_LINK_TX_PACKETS] = st->tx_packets; 00443 link->l_stats[RTNL_LINK_RX_BYTES] = st->rx_bytes; 00444 link->l_stats[RTNL_LINK_TX_BYTES] = st->tx_bytes; 00445 link->l_stats[RTNL_LINK_RX_ERRORS] = st->rx_errors; 00446 link->l_stats[RTNL_LINK_TX_ERRORS] = st->tx_errors; 00447 link->l_stats[RTNL_LINK_RX_DROPPED] = st->rx_dropped; 00448 link->l_stats[RTNL_LINK_TX_DROPPED] = st->tx_dropped; 00449 link->l_stats[RTNL_LINK_MULTICAST] = st->multicast; 00450 link->l_stats[RTNL_LINK_COLLISIONS] = st->collisions; 00451 00452 link->l_stats[RTNL_LINK_RX_LEN_ERR] = st->rx_length_errors; 00453 link->l_stats[RTNL_LINK_RX_OVER_ERR] = st->rx_over_errors; 00454 link->l_stats[RTNL_LINK_RX_CRC_ERR] = st->rx_crc_errors; 00455 link->l_stats[RTNL_LINK_RX_FRAME_ERR] = st->rx_frame_errors; 00456 link->l_stats[RTNL_LINK_RX_FIFO_ERR] = st->rx_fifo_errors; 00457 link->l_stats[RTNL_LINK_RX_MISSED_ERR] = st->rx_missed_errors; 00458 00459 link->l_stats[RTNL_LINK_TX_ABORT_ERR] = st->tx_aborted_errors; 00460 link->l_stats[RTNL_LINK_TX_CARRIER_ERR] = st->tx_carrier_errors; 00461 link->l_stats[RTNL_LINK_TX_FIFO_ERR] = st->tx_fifo_errors; 00462 link->l_stats[RTNL_LINK_TX_HBEAT_ERR] = st->tx_heartbeat_errors; 00463 link->l_stats[RTNL_LINK_TX_WIN_ERR] = st->tx_window_errors; 00464 00465 link->l_stats[RTNL_LINK_RX_COMPRESSED] = st->rx_compressed; 00466 link->l_stats[RTNL_LINK_TX_COMPRESSED] = st->tx_compressed; 00467 00468 link->ce_mask |= LINK_ATTR_STATS; 00469 } 00470 00471 if (tb[IFLA_STATS64]) { 00472 struct rtnl_link_stats64 *st = nla_data(tb[IFLA_STATS64]); 00473 00474 link->l_stats[RTNL_LINK_RX_PACKETS] = st->rx_packets; 00475 link->l_stats[RTNL_LINK_TX_PACKETS] = st->tx_packets; 00476 link->l_stats[RTNL_LINK_RX_BYTES] = st->rx_bytes; 00477 link->l_stats[RTNL_LINK_TX_BYTES] = st->tx_bytes; 00478 link->l_stats[RTNL_LINK_RX_ERRORS] = st->rx_errors; 00479 link->l_stats[RTNL_LINK_TX_ERRORS] = st->tx_errors; 00480 link->l_stats[RTNL_LINK_RX_DROPPED] = st->rx_dropped; 00481 link->l_stats[RTNL_LINK_TX_DROPPED] = st->tx_dropped; 00482 link->l_stats[RTNL_LINK_MULTICAST] = st->multicast; 00483 link->l_stats[RTNL_LINK_COLLISIONS] = st->collisions; 00484 00485 link->l_stats[RTNL_LINK_RX_LEN_ERR] = st->rx_length_errors; 00486 link->l_stats[RTNL_LINK_RX_OVER_ERR] = st->rx_over_errors; 00487 link->l_stats[RTNL_LINK_RX_CRC_ERR] = st->rx_crc_errors; 00488 link->l_stats[RTNL_LINK_RX_FRAME_ERR] = st->rx_frame_errors; 00489 link->l_stats[RTNL_LINK_RX_FIFO_ERR] = st->rx_fifo_errors; 00490 link->l_stats[RTNL_LINK_RX_MISSED_ERR] = st->rx_missed_errors; 00491 00492 link->l_stats[RTNL_LINK_TX_ABORT_ERR] = st->tx_aborted_errors; 00493 link->l_stats[RTNL_LINK_TX_CARRIER_ERR] = st->tx_carrier_errors; 00494 link->l_stats[RTNL_LINK_TX_FIFO_ERR] = st->tx_fifo_errors; 00495 link->l_stats[RTNL_LINK_TX_HBEAT_ERR] = st->tx_heartbeat_errors; 00496 link->l_stats[RTNL_LINK_TX_WIN_ERR] = st->tx_window_errors; 00497 00498 link->l_stats[RTNL_LINK_RX_COMPRESSED] = st->rx_compressed; 00499 link->l_stats[RTNL_LINK_TX_COMPRESSED] = st->tx_compressed; 00500 00501 link->ce_mask |= LINK_ATTR_STATS; 00502 } 00503 00504 if (tb[IFLA_TXQLEN]) { 00505 link->l_txqlen = nla_get_u32(tb[IFLA_TXQLEN]); 00506 link->ce_mask |= LINK_ATTR_TXQLEN; 00507 } 00508 00509 if (tb[IFLA_MTU]) { 00510 link->l_mtu = nla_get_u32(tb[IFLA_MTU]); 00511 link->ce_mask |= LINK_ATTR_MTU; 00512 } 00513 00514 if (tb[IFLA_ADDRESS]) { 00515 link->l_addr = nl_addr_alloc_attr(tb[IFLA_ADDRESS], AF_UNSPEC); 00516 if (link->l_addr == NULL) { 00517 err = -NLE_NOMEM; 00518 goto errout; 00519 } 00520 nl_addr_set_family(link->l_addr, 00521 nl_addr_guess_family(link->l_addr)); 00522 link->ce_mask |= LINK_ATTR_ADDR; 00523 } 00524 00525 if (tb[IFLA_BROADCAST]) { 00526 link->l_bcast = nl_addr_alloc_attr(tb[IFLA_BROADCAST], 00527 AF_UNSPEC); 00528 if (link->l_bcast == NULL) { 00529 err = -NLE_NOMEM; 00530 goto errout; 00531 } 00532 nl_addr_set_family(link->l_bcast, 00533 nl_addr_guess_family(link->l_bcast)); 00534 link->ce_mask |= LINK_ATTR_BRD; 00535 } 00536 00537 if (tb[IFLA_LINK]) { 00538 link->l_link = nla_get_u32(tb[IFLA_LINK]); 00539 link->ce_mask |= LINK_ATTR_LINK; 00540 } 00541 00542 if (tb[IFLA_WEIGHT]) { 00543 link->l_weight = nla_get_u32(tb[IFLA_WEIGHT]); 00544 link->ce_mask |= LINK_ATTR_WEIGHT; 00545 } 00546 00547 if (tb[IFLA_QDISC]) { 00548 nla_strlcpy(link->l_qdisc, tb[IFLA_QDISC], IFQDISCSIZ); 00549 link->ce_mask |= LINK_ATTR_QDISC; 00550 } 00551 00552 if (tb[IFLA_MAP]) { 00553 nla_memcpy(&link->l_map, tb[IFLA_MAP], 00554 sizeof(struct rtnl_link_ifmap)); 00555 link->ce_mask |= LINK_ATTR_MAP; 00556 } 00557 00558 if (tb[IFLA_MASTER]) { 00559 link->l_master = nla_get_u32(tb[IFLA_MASTER]); 00560 link->ce_mask |= LINK_ATTR_MASTER; 00561 } 00562 00563 if (tb[IFLA_OPERSTATE]) { 00564 link->l_operstate = nla_get_u8(tb[IFLA_OPERSTATE]); 00565 link->ce_mask |= LINK_ATTR_OPERSTATE; 00566 } 00567 00568 if (tb[IFLA_LINKMODE]) { 00569 link->l_linkmode = nla_get_u8(tb[IFLA_LINKMODE]); 00570 link->ce_mask |= LINK_ATTR_LINKMODE; 00571 } 00572 00573 if (tb[IFLA_IFALIAS]) { 00574 link->l_ifalias = nla_strdup(tb[IFLA_IFALIAS]); 00575 if (link->l_ifalias == NULL) { 00576 err = -NLE_NOMEM; 00577 goto errout; 00578 } 00579 link->ce_mask |= LINK_ATTR_IFALIAS; 00580 } 00581 00582 if (tb[IFLA_NUM_VF]) { 00583 link->l_num_vf = nla_get_u32(tb[IFLA_NUM_VF]); 00584 link->ce_mask |= LINK_ATTR_NUM_VF; 00585 } 00586 00587 if (tb[IFLA_LINKINFO]) { 00588 struct nlattr *li[IFLA_INFO_MAX+1]; 00589 00590 err = nla_parse_nested(li, IFLA_INFO_MAX, tb[IFLA_LINKINFO], 00591 link_info_policy); 00592 if (err < 0) 00593 goto errout; 00594 00595 if (li[IFLA_INFO_KIND] && 00596 (li[IFLA_INFO_DATA] || li[IFLA_INFO_XSTATS])) { 00597 struct rtnl_link_info_ops *ops; 00598 char *kind; 00599 00600 kind = nla_get_string(li[IFLA_INFO_KIND]); 00601 ops = rtnl_link_info_ops_lookup(kind); 00602 if (ops != NULL) { 00603 link->l_info_ops = ops; 00604 err = ops->io_parse(link, li[IFLA_INFO_DATA], 00605 li[IFLA_INFO_XSTATS]); 00606 if (err < 0) 00607 goto errout; 00608 } else { 00609 /* XXX: Warn about unparsed info? */ 00610 } 00611 } 00612 } 00613 00614 if (tb[IFLA_PROTINFO] && af_ops && af_ops->ao_parse_protinfo) { 00615 err = af_ops->ao_parse_protinfo(link, tb[IFLA_PROTINFO], 00616 link->l_af_data[link->l_family]); 00617 if (err < 0) 00618 goto errout; 00619 } 00620 00621 if (tb[IFLA_AF_SPEC]) { 00622 struct nlattr *af_attr; 00623 int remaining; 00624 00625 nla_for_each_nested(af_attr, tb[IFLA_AF_SPEC], remaining) { 00626 af_ops = af_lookup_and_alloc(link, nla_type(af_attr)); 00627 if (af_ops && af_ops->ao_parse_af) { 00628 char *af_data = link->l_af_data[nla_type(af_attr)]; 00629 00630 err = af_ops->ao_parse_af(link, af_attr, af_data); 00631 00632 rtnl_link_af_ops_put(af_ops); 00633 00634 if (err < 0) 00635 goto errout; 00636 } 00637 00638 } 00639 } 00640 00641 err = pp->pp_cb((struct nl_object *) link, pp); 00642 errout: 00643 rtnl_link_af_ops_put(af_ops); 00644 rtnl_link_put(link); 00645 return err; 00646 } 00647 00648 static int link_request_update(struct nl_cache *cache, struct nl_sock *sk) 00649 { 00650 int family = cache->c_iarg1; 00651 00652 return nl_rtgen_request(sk, RTM_GETLINK, family, NLM_F_DUMP); 00653 } 00654 00655 static void link_dump_line(struct nl_object *obj, struct nl_dump_params *p) 00656 { 00657 char buf[128]; 00658 struct nl_cache *cache = dp_cache(obj); 00659 struct rtnl_link *link = (struct rtnl_link *) obj; 00660 00661 nl_dump_line(p, "%s %s ", link->l_name, 00662 nl_llproto2str(link->l_arptype, buf, sizeof(buf))); 00663 00664 if (link->l_addr && !nl_addr_iszero(link->l_addr)) 00665 nl_dump(p, "%s ", nl_addr2str(link->l_addr, buf, sizeof(buf))); 00666 00667 if (link->ce_mask & LINK_ATTR_MASTER) { 00668 struct rtnl_link *master = rtnl_link_get(cache, link->l_master); 00669 nl_dump(p, "master %s ", master ? master->l_name : "inv"); 00670 if (master) 00671 rtnl_link_put(master); 00672 } 00673 00674 rtnl_link_flags2str(link->l_flags, buf, sizeof(buf)); 00675 if (buf[0]) 00676 nl_dump(p, "<%s> ", buf); 00677 00678 if (link->ce_mask & LINK_ATTR_LINK) { 00679 struct rtnl_link *ll = rtnl_link_get(cache, link->l_link); 00680 nl_dump(p, "slave-of %s ", ll ? ll->l_name : "NONE"); 00681 if (ll) 00682 rtnl_link_put(ll); 00683 } 00684 00685 if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_LINE]) 00686 link->l_info_ops->io_dump[NL_DUMP_LINE](link, p); 00687 00688 do_foreach_af(link, af_dump_line, p); 00689 00690 nl_dump(p, "\n"); 00691 } 00692 00693 static void link_dump_details(struct nl_object *obj, struct nl_dump_params *p) 00694 { 00695 struct rtnl_link *link = (struct rtnl_link *) obj; 00696 char buf[64]; 00697 00698 link_dump_line(obj, p); 00699 00700 nl_dump_line(p, " mtu %u ", link->l_mtu); 00701 nl_dump(p, "txqlen %u weight %u ", link->l_txqlen, link->l_weight); 00702 00703 if (link->ce_mask & LINK_ATTR_QDISC) 00704 nl_dump(p, "qdisc %s ", link->l_qdisc); 00705 00706 if (link->ce_mask & LINK_ATTR_MAP && link->l_map.lm_irq) 00707 nl_dump(p, "irq %u ", link->l_map.lm_irq); 00708 00709 if (link->ce_mask & LINK_ATTR_IFINDEX) 00710 nl_dump(p, "index %u ", link->l_index); 00711 00712 00713 nl_dump(p, "\n"); 00714 00715 if (link->ce_mask & LINK_ATTR_IFALIAS) 00716 nl_dump_line(p, " alias %s\n", link->l_ifalias); 00717 00718 nl_dump_line(p, " "); 00719 00720 if (link->ce_mask & LINK_ATTR_BRD) 00721 nl_dump(p, "brd %s ", nl_addr2str(link->l_bcast, buf, 00722 sizeof(buf))); 00723 00724 if ((link->ce_mask & LINK_ATTR_OPERSTATE) && 00725 link->l_operstate != IF_OPER_UNKNOWN) { 00726 rtnl_link_operstate2str(link->l_operstate, buf, sizeof(buf)); 00727 nl_dump(p, "state %s ", buf); 00728 } 00729 00730 if (link->ce_mask & LINK_ATTR_NUM_VF) 00731 nl_dump(p, "num-vf %u ", link->l_num_vf); 00732 00733 nl_dump(p, "mode %s\n", 00734 rtnl_link_mode2str(link->l_linkmode, buf, sizeof(buf))); 00735 00736 if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_DETAILS]) 00737 link->l_info_ops->io_dump[NL_DUMP_DETAILS](link, p); 00738 00739 do_foreach_af(link, af_dump_details, p); 00740 } 00741 00742 static void link_dump_stats(struct nl_object *obj, struct nl_dump_params *p) 00743 { 00744 struct rtnl_link *link = (struct rtnl_link *) obj; 00745 char *unit, fmt[64]; 00746 float res; 00747 00748 link_dump_details(obj, p); 00749 00750 nl_dump_line(p, " Stats: bytes packets errors " 00751 " dropped fifo-err compressed\n"); 00752 00753 res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_RX_BYTES], &unit); 00754 00755 strcpy(fmt, " RX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n"); 00756 fmt[9] = *unit == 'B' ? '9' : '7'; 00757 00758 nl_dump_line(p, fmt, res, unit, 00759 link->l_stats[RTNL_LINK_RX_PACKETS], 00760 link->l_stats[RTNL_LINK_RX_ERRORS], 00761 link->l_stats[RTNL_LINK_RX_DROPPED], 00762 link->l_stats[RTNL_LINK_RX_FIFO_ERR], 00763 link->l_stats[RTNL_LINK_RX_COMPRESSED]); 00764 00765 res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_TX_BYTES], &unit); 00766 00767 strcpy(fmt, " TX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n"); 00768 fmt[9] = *unit == 'B' ? '9' : '7'; 00769 00770 nl_dump_line(p, fmt, res, unit, 00771 link->l_stats[RTNL_LINK_TX_PACKETS], 00772 link->l_stats[RTNL_LINK_TX_ERRORS], 00773 link->l_stats[RTNL_LINK_TX_DROPPED], 00774 link->l_stats[RTNL_LINK_TX_FIFO_ERR], 00775 link->l_stats[RTNL_LINK_TX_COMPRESSED]); 00776 00777 nl_dump_line(p, " Errors: length over crc " 00778 " frame missed multicast\n"); 00779 00780 nl_dump_line(p, " RX %10" PRIu64 " %10" PRIu64 " %10" 00781 PRIu64 " %10" PRIu64 " %10" PRIu64 " %10" 00782 PRIu64 "\n", 00783 link->l_stats[RTNL_LINK_RX_LEN_ERR], 00784 link->l_stats[RTNL_LINK_RX_OVER_ERR], 00785 link->l_stats[RTNL_LINK_RX_CRC_ERR], 00786 link->l_stats[RTNL_LINK_RX_FRAME_ERR], 00787 link->l_stats[RTNL_LINK_RX_MISSED_ERR], 00788 link->l_stats[RTNL_LINK_MULTICAST]); 00789 00790 nl_dump_line(p, " aborted carrier heartbeat " 00791 " window collision\n"); 00792 00793 nl_dump_line(p, " TX %10" PRIu64 " %10" PRIu64 " %10" 00794 PRIu64 " %10" PRIu64 " %10" PRIu64 "\n", 00795 link->l_stats[RTNL_LINK_TX_ABORT_ERR], 00796 link->l_stats[RTNL_LINK_TX_CARRIER_ERR], 00797 link->l_stats[RTNL_LINK_TX_HBEAT_ERR], 00798 link->l_stats[RTNL_LINK_TX_WIN_ERR], 00799 link->l_stats[RTNL_LINK_COLLISIONS]); 00800 00801 if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_STATS]) 00802 link->l_info_ops->io_dump[NL_DUMP_STATS](link, p); 00803 00804 do_foreach_af(link, af_dump_stats, p); 00805 } 00806 00807 #if 0 00808 static int link_handle_event(struct nl_object *a, struct rtnl_link_event_cb *cb) 00809 { 00810 struct rtnl_link *l = (struct rtnl_link *) a; 00811 struct nl_cache *c = dp_cache(a); 00812 int nevents = 0; 00813 00814 if (l->l_change == ~0U) { 00815 if (l->ce_msgtype == RTM_NEWLINK) 00816 cb->le_register(l); 00817 else 00818 cb->le_unregister(l); 00819 00820 return 1; 00821 } 00822 00823 if (l->l_change & IFF_SLAVE) { 00824 if (l->l_flags & IFF_SLAVE) { 00825 struct rtnl_link *m = rtnl_link_get(c, l->l_master); 00826 cb->le_new_bonding(l, m); 00827 if (m) 00828 rtnl_link_put(m); 00829 } else 00830 cb->le_cancel_bonding(l); 00831 } 00832 00833 #if 0 00834 if (l->l_change & IFF_UP && l->l_change & IFF_RUNNING) 00835 dp_dump_line(p, line++, "link %s changed state to %s.\n", 00836 l->l_name, l->l_flags & IFF_UP ? "up" : "down"); 00837 00838 if (l->l_change & IFF_PROMISC) { 00839 dp_new_line(p, line++); 00840 dp_dump(p, "link %s %s promiscuous mode.\n", 00841 l->l_name, l->l_flags & IFF_PROMISC ? "entered" : "left"); 00842 } 00843 00844 if (line == 0) 00845 dp_dump_line(p, line++, "link %s sent unknown event.\n", 00846 l->l_name); 00847 #endif 00848 00849 return nevents; 00850 } 00851 #endif 00852 00853 static int link_compare(struct nl_object *_a, struct nl_object *_b, 00854 uint32_t attrs, int flags) 00855 { 00856 struct rtnl_link *a = (struct rtnl_link *) _a; 00857 struct rtnl_link *b = (struct rtnl_link *) _b; 00858 int diff = 0; 00859 00860 #define LINK_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, LINK_ATTR_##ATTR, a, b, EXPR) 00861 00862 diff |= LINK_DIFF(IFINDEX, a->l_index != b->l_index); 00863 diff |= LINK_DIFF(MTU, a->l_mtu != b->l_mtu); 00864 diff |= LINK_DIFF(LINK, a->l_link != b->l_link); 00865 diff |= LINK_DIFF(TXQLEN, a->l_txqlen != b->l_txqlen); 00866 diff |= LINK_DIFF(WEIGHT, a->l_weight != b->l_weight); 00867 diff |= LINK_DIFF(MASTER, a->l_master != b->l_master); 00868 diff |= LINK_DIFF(FAMILY, a->l_family != b->l_family); 00869 diff |= LINK_DIFF(OPERSTATE, a->l_operstate != b->l_operstate); 00870 diff |= LINK_DIFF(LINKMODE, a->l_linkmode != b->l_linkmode); 00871 diff |= LINK_DIFF(QDISC, strcmp(a->l_qdisc, b->l_qdisc)); 00872 diff |= LINK_DIFF(IFNAME, strcmp(a->l_name, b->l_name)); 00873 diff |= LINK_DIFF(ADDR, nl_addr_cmp(a->l_addr, b->l_addr)); 00874 diff |= LINK_DIFF(BRD, nl_addr_cmp(a->l_bcast, b->l_bcast)); 00875 diff |= LINK_DIFF(IFALIAS, strcmp(a->l_ifalias, b->l_ifalias)); 00876 diff |= LINK_DIFF(NUM_VF, a->l_num_vf != b->l_num_vf); 00877 00878 if (flags & LOOSE_COMPARISON) 00879 diff |= LINK_DIFF(FLAGS, 00880 (a->l_flags ^ b->l_flags) & b->l_flag_mask); 00881 else 00882 diff |= LINK_DIFF(FLAGS, a->l_flags != b->l_flags); 00883 00884 #undef LINK_DIFF 00885 00886 return diff; 00887 } 00888 00889 static const struct trans_tbl link_attrs[] = { 00890 __ADD(LINK_ATTR_MTU, mtu) 00891 __ADD(LINK_ATTR_LINK, link) 00892 __ADD(LINK_ATTR_TXQLEN, txqlen) 00893 __ADD(LINK_ATTR_WEIGHT, weight) 00894 __ADD(LINK_ATTR_MASTER, master) 00895 __ADD(LINK_ATTR_QDISC, qdisc) 00896 __ADD(LINK_ATTR_MAP, map) 00897 __ADD(LINK_ATTR_ADDR, address) 00898 __ADD(LINK_ATTR_BRD, broadcast) 00899 __ADD(LINK_ATTR_FLAGS, flags) 00900 __ADD(LINK_ATTR_IFNAME, name) 00901 __ADD(LINK_ATTR_IFINDEX, ifindex) 00902 __ADD(LINK_ATTR_FAMILY, family) 00903 __ADD(LINK_ATTR_ARPTYPE, arptype) 00904 __ADD(LINK_ATTR_STATS, stats) 00905 __ADD(LINK_ATTR_CHANGE, change) 00906 __ADD(LINK_ATTR_OPERSTATE, operstate) 00907 __ADD(LINK_ATTR_LINKMODE, linkmode) 00908 __ADD(LINK_ATTR_IFALIAS, ifalias) 00909 __ADD(LINK_ATTR_NUM_VF, num_vf) 00910 }; 00911 00912 static char *link_attrs2str(int attrs, char *buf, size_t len) 00913 { 00914 return __flags2str(attrs, buf, len, link_attrs, 00915 ARRAY_SIZE(link_attrs)); 00916 } 00917 00918 /** 00919 * @name Allocation/Freeing 00920 * @{ 00921 */ 00922 00923 struct rtnl_link *rtnl_link_alloc(void) 00924 { 00925 return (struct rtnl_link *) nl_object_alloc(&link_obj_ops); 00926 } 00927 00928 void rtnl_link_put(struct rtnl_link *link) 00929 { 00930 nl_object_put((struct nl_object *) link); 00931 } 00932 00933 /** @} */ 00934 00935 /** 00936 * @name Cache Management 00937 * @{ 00938 */ 00939 00940 00941 /** 00942 * Allocate link cache and fill in all configured links. 00943 * @arg sk Netlink socket. 00944 * @arg family Link address family or AF_UNSPEC 00945 * @arg result Pointer to store resulting cache. 00946 * 00947 * Allocates a new link cache, initializes it properly and updates it 00948 * to include all links currently configured in the kernel. 00949 * 00950 * @return 0 on success or a negative error code. 00951 */ 00952 int rtnl_link_alloc_cache(struct nl_sock *sk, int family, struct nl_cache **result) 00953 { 00954 struct nl_cache * cache; 00955 int err; 00956 00957 cache = nl_cache_alloc(&rtnl_link_ops); 00958 if (!cache) 00959 return -NLE_NOMEM; 00960 00961 cache->c_iarg1 = family; 00962 00963 if (sk && (err = nl_cache_refill(sk, cache)) < 0) { 00964 nl_cache_free(cache); 00965 return err; 00966 } 00967 00968 *result = cache; 00969 return 0; 00970 } 00971 00972 /** 00973 * Look up link by interface index in the provided cache 00974 * @arg cache link cache 00975 * @arg ifindex link interface index 00976 * 00977 * The caller owns a reference on the returned object and 00978 * must give the object back via rtnl_link_put(). 00979 * 00980 * @return pointer to link inside the cache or NULL if no match was found. 00981 */ 00982 struct rtnl_link *rtnl_link_get(struct nl_cache *cache, int ifindex) 00983 { 00984 struct rtnl_link *link; 00985 00986 if (cache->c_ops != &rtnl_link_ops) 00987 return NULL; 00988 00989 nl_list_for_each_entry(link, &cache->c_items, ce_list) { 00990 if (link->l_index == ifindex) { 00991 nl_object_get((struct nl_object *) link); 00992 return link; 00993 } 00994 } 00995 00996 return NULL; 00997 } 00998 00999 /** 01000 * Look up link by link name in the provided cache 01001 * @arg cache link cache 01002 * @arg name link name 01003 * 01004 * The caller owns a reference on the returned object and 01005 * must give the object back via rtnl_link_put(). 01006 * 01007 * @return pointer to link inside the cache or NULL if no match was found. 01008 */ 01009 struct rtnl_link *rtnl_link_get_by_name(struct nl_cache *cache, 01010 const char *name) 01011 { 01012 struct rtnl_link *link; 01013 01014 if (cache->c_ops != &rtnl_link_ops) 01015 return NULL; 01016 01017 nl_list_for_each_entry(link, &cache->c_items, ce_list) { 01018 if (!strcmp(name, link->l_name)) { 01019 nl_object_get((struct nl_object *) link); 01020 return link; 01021 } 01022 } 01023 01024 return NULL; 01025 } 01026 01027 /** @} */ 01028 01029 /** 01030 * @name Link Modifications 01031 * @{ 01032 */ 01033 01034 /** 01035 * Builds a netlink change request message to change link attributes 01036 * @arg old link to be changed 01037 * @arg tmpl template with requested changes 01038 * @arg flags additional netlink message flags 01039 * 01040 * Builds a new netlink message requesting a change of link attributes. 01041 * The netlink message header isn't fully equipped with all relevant 01042 * fields and must be sent out via nl_send_auto_complete() or 01043 * supplemented as needed. 01044 * \a old must point to a link currently configured in the kernel 01045 * and \a tmpl must contain the attributes to be changed set via 01046 * \c rtnl_link_set_* functions. 01047 * 01048 * @return New netlink message 01049 * @note Not all attributes can be changed, see 01050 * \ref link_changeable "Changeable Attributes" for more details. 01051 */ 01052 int rtnl_link_build_change_request(struct rtnl_link *old, 01053 struct rtnl_link *tmpl, int flags, 01054 struct nl_msg **result) 01055 { 01056 struct nl_msg *msg; 01057 struct nlattr *af_spec; 01058 struct ifinfomsg ifi = { 01059 .ifi_family = old->l_family, 01060 .ifi_index = old->l_index, 01061 }; 01062 01063 if (tmpl->ce_mask & LINK_ATTR_FLAGS) { 01064 ifi.ifi_flags = old->l_flags & ~tmpl->l_flag_mask; 01065 ifi.ifi_flags |= tmpl->l_flags; 01066 } 01067 01068 msg = nlmsg_alloc_simple(RTM_SETLINK, flags); 01069 if (!msg) 01070 return -NLE_NOMEM; 01071 01072 if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0) 01073 goto nla_put_failure; 01074 01075 if (tmpl->ce_mask & LINK_ATTR_ADDR) 01076 NLA_PUT_ADDR(msg, IFLA_ADDRESS, tmpl->l_addr); 01077 01078 if (tmpl->ce_mask & LINK_ATTR_BRD) 01079 NLA_PUT_ADDR(msg, IFLA_BROADCAST, tmpl->l_bcast); 01080 01081 if (tmpl->ce_mask & LINK_ATTR_MTU) 01082 NLA_PUT_U32(msg, IFLA_MTU, tmpl->l_mtu); 01083 01084 if (tmpl->ce_mask & LINK_ATTR_TXQLEN) 01085 NLA_PUT_U32(msg, IFLA_TXQLEN, tmpl->l_txqlen); 01086 01087 if (tmpl->ce_mask & LINK_ATTR_WEIGHT) 01088 NLA_PUT_U32(msg, IFLA_WEIGHT, tmpl->l_weight); 01089 01090 if (tmpl->ce_mask & LINK_ATTR_IFNAME) 01091 NLA_PUT_STRING(msg, IFLA_IFNAME, tmpl->l_name); 01092 01093 if (tmpl->ce_mask & LINK_ATTR_OPERSTATE) 01094 NLA_PUT_U8(msg, IFLA_OPERSTATE, tmpl->l_operstate); 01095 01096 if (tmpl->ce_mask & LINK_ATTR_LINKMODE) 01097 NLA_PUT_U8(msg, IFLA_LINKMODE, tmpl->l_linkmode); 01098 01099 if (tmpl->ce_mask & LINK_ATTR_IFALIAS) 01100 NLA_PUT_STRING(msg, IFLA_IFALIAS, tmpl->l_ifalias); 01101 01102 if ((tmpl->ce_mask & LINK_ATTR_LINKINFO) && tmpl->l_info_ops && 01103 tmpl->l_info_ops->io_put_attrs) { 01104 struct nlattr *info; 01105 01106 if (!(info = nla_nest_start(msg, IFLA_LINKINFO))) 01107 goto nla_put_failure; 01108 01109 NLA_PUT_STRING(msg, IFLA_INFO_KIND, tmpl->l_info_ops->io_name); 01110 01111 if (tmpl->l_info_ops->io_put_attrs(msg, tmpl) < 0) 01112 goto nla_put_failure; 01113 01114 nla_nest_end(msg, info); 01115 } 01116 01117 if (!(af_spec = nla_nest_start(msg, IFLA_AF_SPEC))) 01118 goto nla_put_failure; 01119 01120 if (do_foreach_af(tmpl, af_fill, msg) < 0) 01121 goto nla_put_failure; 01122 01123 nla_nest_end(msg, af_spec); 01124 01125 *result = msg; 01126 return 0; 01127 01128 nla_put_failure: 01129 nlmsg_free(msg); 01130 return -NLE_MSGSIZE; 01131 } 01132 01133 /** 01134 * Change link attributes 01135 * @arg sk Netlink socket. 01136 * @arg old link to be changed 01137 * @arg tmpl template with requested changes 01138 * @arg flags additional netlink message flags 01139 * 01140 * Builds a new netlink message by calling rtnl_link_build_change_request(), 01141 * sends the request to the kernel and waits for the next ACK to be 01142 * received, i.e. blocks until the request has been processed. 01143 * 01144 * @return 0 on success or a negative error code 01145 * @note Not all attributes can be changed, see 01146 * \ref link_changeable "Changeable Attributes" for more details. 01147 */ 01148 int rtnl_link_change(struct nl_sock *sk, struct rtnl_link *old, 01149 struct rtnl_link *tmpl, int flags) 01150 { 01151 struct nl_msg *msg; 01152 int err; 01153 01154 if ((err = rtnl_link_build_change_request(old, tmpl, flags, &msg)) < 0) 01155 return err; 01156 01157 err = nl_send_auto_complete(sk, msg); 01158 nlmsg_free(msg); 01159 if (err < 0) 01160 return err; 01161 01162 return wait_for_ack(sk); 01163 } 01164 01165 /** @} */ 01166 01167 /** 01168 * @name Name <-> Index Translations 01169 * @{ 01170 */ 01171 01172 /** 01173 * Translate an interface index to the corresponding link name 01174 * @arg cache link cache 01175 * @arg ifindex link interface index 01176 * @arg dst destination buffer 01177 * @arg len length of destination buffer 01178 * 01179 * Translates the specified interface index to the corresponding 01180 * link name and stores the name in the destination buffer. 01181 * 01182 * @return link name or NULL if no match was found. 01183 */ 01184 char * rtnl_link_i2name(struct nl_cache *cache, int ifindex, char *dst, 01185 size_t len) 01186 { 01187 struct rtnl_link *link = rtnl_link_get(cache, ifindex); 01188 01189 if (link) { 01190 strncpy(dst, link->l_name, len - 1); 01191 rtnl_link_put(link); 01192 return dst; 01193 } 01194 01195 return NULL; 01196 } 01197 01198 /** 01199 * Translate a link name to the corresponding interface index 01200 * @arg cache link cache 01201 * @arg name link name 01202 * 01203 * @return interface index or 0 if no match was found. 01204 */ 01205 int rtnl_link_name2i(struct nl_cache *cache, const char *name) 01206 { 01207 int ifindex = 0; 01208 struct rtnl_link *link; 01209 01210 link = rtnl_link_get_by_name(cache, name); 01211 if (link) { 01212 ifindex = link->l_index; 01213 rtnl_link_put(link); 01214 } 01215 01216 return ifindex; 01217 } 01218 01219 /** @} */ 01220 01221 /** 01222 * @name Link Flags Translations 01223 * @{ 01224 */ 01225 01226 static const struct trans_tbl link_flags[] = { 01227 __ADD(IFF_LOOPBACK, loopback) 01228 __ADD(IFF_BROADCAST, broadcast) 01229 __ADD(IFF_POINTOPOINT, pointopoint) 01230 __ADD(IFF_MULTICAST, multicast) 01231 __ADD(IFF_NOARP, noarp) 01232 __ADD(IFF_ALLMULTI, allmulti) 01233 __ADD(IFF_PROMISC, promisc) 01234 __ADD(IFF_MASTER, master) 01235 __ADD(IFF_SLAVE, slave) 01236 __ADD(IFF_DEBUG, debug) 01237 __ADD(IFF_DYNAMIC, dynamic) 01238 __ADD(IFF_AUTOMEDIA, automedia) 01239 __ADD(IFF_PORTSEL, portsel) 01240 __ADD(IFF_NOTRAILERS, notrailers) 01241 __ADD(IFF_UP, up) 01242 __ADD(IFF_RUNNING, running) 01243 __ADD(IFF_LOWER_UP, lowerup) 01244 __ADD(IFF_DORMANT, dormant) 01245 __ADD(IFF_ECHO, echo) 01246 }; 01247 01248 char * rtnl_link_flags2str(int flags, char *buf, size_t len) 01249 { 01250 return __flags2str(flags, buf, len, link_flags, 01251 ARRAY_SIZE(link_flags)); 01252 } 01253 01254 int rtnl_link_str2flags(const char *name) 01255 { 01256 return __str2flags(name, link_flags, ARRAY_SIZE(link_flags)); 01257 } 01258 01259 /** @} */ 01260 01261 /** 01262 * @name Link Statistics Translations 01263 * @{ 01264 */ 01265 01266 static const struct trans_tbl link_stats[] = { 01267 __ADD(RTNL_LINK_RX_PACKETS, rx_packets) 01268 __ADD(RTNL_LINK_TX_PACKETS, tx_packets) 01269 __ADD(RTNL_LINK_RX_BYTES, rx_bytes) 01270 __ADD(RTNL_LINK_TX_BYTES, tx_bytes) 01271 __ADD(RTNL_LINK_RX_ERRORS, rx_errors) 01272 __ADD(RTNL_LINK_TX_ERRORS, tx_errors) 01273 __ADD(RTNL_LINK_RX_DROPPED, rx_dropped) 01274 __ADD(RTNL_LINK_TX_DROPPED, tx_dropped) 01275 __ADD(RTNL_LINK_RX_COMPRESSED, rx_compressed) 01276 __ADD(RTNL_LINK_TX_COMPRESSED, tx_compressed) 01277 __ADD(RTNL_LINK_RX_FIFO_ERR, rx_fifo_err) 01278 __ADD(RTNL_LINK_TX_FIFO_ERR, tx_fifo_err) 01279 __ADD(RTNL_LINK_RX_LEN_ERR, rx_len_err) 01280 __ADD(RTNL_LINK_RX_OVER_ERR, rx_over_err) 01281 __ADD(RTNL_LINK_RX_CRC_ERR, rx_crc_err) 01282 __ADD(RTNL_LINK_RX_FRAME_ERR, rx_frame_err) 01283 __ADD(RTNL_LINK_RX_MISSED_ERR, rx_missed_err) 01284 __ADD(RTNL_LINK_TX_ABORT_ERR, tx_abort_err) 01285 __ADD(RTNL_LINK_TX_CARRIER_ERR, tx_carrier_err) 01286 __ADD(RTNL_LINK_TX_HBEAT_ERR, tx_hbeat_err) 01287 __ADD(RTNL_LINK_TX_WIN_ERR, tx_win_err) 01288 __ADD(RTNL_LINK_COLLISIONS, collisions) 01289 __ADD(RTNL_LINK_MULTICAST, multicast) 01290 __ADD(RTNL_LINK_IP6_INPKTS, Ip6InReceives) 01291 __ADD(RTNL_LINK_IP6_INHDRERRORS, Ip6InHdrErrors) 01292 __ADD(RTNL_LINK_IP6_INTOOBIGERRORS, Ip6InTooBigErrors) 01293 __ADD(RTNL_LINK_IP6_INNOROUTES, Ip6InNoRoutes) 01294 __ADD(RTNL_LINK_IP6_INADDRERRORS, Ip6InAddrErrors) 01295 __ADD(RTNL_LINK_IP6_INUNKNOWNPROTOS, Ip6InUnknownProtos) 01296 __ADD(RTNL_LINK_IP6_INTRUNCATEDPKTS, Ip6InTruncatedPkts) 01297 __ADD(RTNL_LINK_IP6_INDISCARDS, Ip6InDiscards) 01298 __ADD(RTNL_LINK_IP6_INDELIVERS, Ip6InDelivers) 01299 __ADD(RTNL_LINK_IP6_OUTFORWDATAGRAMS, Ip6OutForwDatagrams) 01300 __ADD(RTNL_LINK_IP6_OUTPKTS, Ip6OutRequests) 01301 __ADD(RTNL_LINK_IP6_OUTDISCARDS, Ip6OutDiscards) 01302 __ADD(RTNL_LINK_IP6_OUTNOROUTES, Ip6OutNoRoutes) 01303 __ADD(RTNL_LINK_IP6_REASMTIMEOUT, Ip6ReasmTimeout) 01304 __ADD(RTNL_LINK_IP6_REASMREQDS, Ip6ReasmReqds) 01305 __ADD(RTNL_LINK_IP6_REASMOKS, Ip6ReasmOKs) 01306 __ADD(RTNL_LINK_IP6_REASMFAILS, Ip6ReasmFails) 01307 __ADD(RTNL_LINK_IP6_FRAGOKS, Ip6FragOKs) 01308 __ADD(RTNL_LINK_IP6_FRAGFAILS, Ip6FragFails) 01309 __ADD(RTNL_LINK_IP6_FRAGCREATES, Ip6FragCreates) 01310 __ADD(RTNL_LINK_IP6_INMCASTPKTS, Ip6InMcastPkts) 01311 __ADD(RTNL_LINK_IP6_OUTMCASTPKTS, Ip6OutMcastPkts) 01312 __ADD(RTNL_LINK_IP6_INBCASTPKTS, Ip6InBcastPkts) 01313 __ADD(RTNL_LINK_IP6_OUTBCASTPKTS, Ip6OutBcastPkts) 01314 __ADD(RTNL_LINK_IP6_INOCTETS, Ip6InOctets) 01315 __ADD(RTNL_LINK_IP6_OUTOCTETS, Ip6OutOctets) 01316 __ADD(RTNL_LINK_IP6_INMCASTOCTETS, Ip6InMcastOctets) 01317 __ADD(RTNL_LINK_IP6_OUTMCASTOCTETS, Ip6OutMcastOctets) 01318 __ADD(RTNL_LINK_IP6_INBCASTOCTETS, Ip6InBcastOctets) 01319 __ADD(RTNL_LINK_IP6_OUTBCASTOCTETS, Ip6OutBcastOctets) 01320 __ADD(RTNL_LINK_ICMP6_INMSGS, ICMP6_InMsgs) 01321 __ADD(RTNL_LINK_ICMP6_INERRORS, ICMP6_InErrors) 01322 __ADD(RTNL_LINK_ICMP6_OUTMSGS, ICMP6_OutMsgs) 01323 __ADD(RTNL_LINK_ICMP6_OUTERRORS, ICMP6_OutErrors) 01324 }; 01325 01326 char *rtnl_link_stat2str(int st, char *buf, size_t len) 01327 { 01328 return __type2str(st, buf, len, link_stats, ARRAY_SIZE(link_stats)); 01329 } 01330 01331 int rtnl_link_str2stat(const char *name) 01332 { 01333 return __str2type(name, link_stats, ARRAY_SIZE(link_stats)); 01334 } 01335 01336 /** @} */ 01337 01338 /** 01339 * @name Link Operstate Translations 01340 * @{ 01341 */ 01342 01343 static const struct trans_tbl link_operstates[] = { 01344 __ADD(IF_OPER_UNKNOWN, unknown) 01345 __ADD(IF_OPER_NOTPRESENT, notpresent) 01346 __ADD(IF_OPER_DOWN, down) 01347 __ADD(IF_OPER_LOWERLAYERDOWN, lowerlayerdown) 01348 __ADD(IF_OPER_TESTING, testing) 01349 __ADD(IF_OPER_DORMANT, dormant) 01350 __ADD(IF_OPER_UP, up) 01351 }; 01352 01353 char *rtnl_link_operstate2str(int st, char *buf, size_t len) 01354 { 01355 return __type2str(st, buf, len, link_operstates, 01356 ARRAY_SIZE(link_operstates)); 01357 } 01358 01359 int rtnl_link_str2operstate(const char *name) 01360 { 01361 return __str2type(name, link_operstates, 01362 ARRAY_SIZE(link_operstates)); 01363 } 01364 01365 /** @} */ 01366 01367 /** 01368 * @name Link Mode Translations 01369 * @{ 01370 */ 01371 01372 static const struct trans_tbl link_modes[] = { 01373 __ADD(IF_LINK_MODE_DEFAULT, default) 01374 __ADD(IF_LINK_MODE_DORMANT, dormant) 01375 }; 01376 01377 char *rtnl_link_mode2str(int st, char *buf, size_t len) 01378 { 01379 return __type2str(st, buf, len, link_modes, ARRAY_SIZE(link_modes)); 01380 } 01381 01382 int rtnl_link_str2mode(const char *name) 01383 { 01384 return __str2type(name, link_modes, ARRAY_SIZE(link_modes)); 01385 } 01386 01387 /** @} */ 01388 01389 /** 01390 * @name Attributes 01391 * @{ 01392 */ 01393 01394 void rtnl_link_set_qdisc(struct rtnl_link *link, const char *qdisc) 01395 { 01396 strncpy(link->l_qdisc, qdisc, sizeof(link->l_qdisc) - 1); 01397 link->ce_mask |= LINK_ATTR_QDISC; 01398 } 01399 01400 char *rtnl_link_get_qdisc(struct rtnl_link *link) 01401 { 01402 if (link->ce_mask & LINK_ATTR_QDISC) 01403 return link->l_qdisc; 01404 else 01405 return NULL; 01406 } 01407 01408 void rtnl_link_set_name(struct rtnl_link *link, const char *name) 01409 { 01410 strncpy(link->l_name, name, sizeof(link->l_name) - 1); 01411 link->ce_mask |= LINK_ATTR_IFNAME; 01412 } 01413 01414 char *rtnl_link_get_name(struct rtnl_link *link) 01415 { 01416 if (link->ce_mask & LINK_ATTR_IFNAME) 01417 return link->l_name; 01418 else 01419 return NULL; 01420 } 01421 01422 static inline void __assign_addr(struct rtnl_link *link, struct nl_addr **pos, 01423 struct nl_addr *new, int flag) 01424 { 01425 if (*pos) 01426 nl_addr_put(*pos); 01427 01428 nl_addr_get(new); 01429 *pos = new; 01430 01431 link->ce_mask |= flag; 01432 } 01433 01434 void rtnl_link_set_addr(struct rtnl_link *link, struct nl_addr *addr) 01435 { 01436 __assign_addr(link, &link->l_addr, addr, LINK_ATTR_ADDR); 01437 } 01438 01439 struct nl_addr *rtnl_link_get_addr(struct rtnl_link *link) 01440 { 01441 if (link->ce_mask & LINK_ATTR_ADDR) 01442 return link->l_addr; 01443 else 01444 return NULL; 01445 } 01446 01447 void rtnl_link_set_broadcast(struct rtnl_link *link, struct nl_addr *brd) 01448 { 01449 __assign_addr(link, &link->l_bcast, brd, LINK_ATTR_BRD); 01450 } 01451 01452 struct nl_addr *rtnl_link_get_broadcast(struct rtnl_link *link) 01453 { 01454 if (link->ce_mask & LINK_ATTR_BRD) 01455 return link->l_bcast; 01456 else 01457 return NULL; 01458 } 01459 01460 void rtnl_link_set_flags(struct rtnl_link *link, unsigned int flags) 01461 { 01462 link->l_flag_mask |= flags; 01463 link->l_flags |= flags; 01464 link->ce_mask |= LINK_ATTR_FLAGS; 01465 } 01466 01467 void rtnl_link_unset_flags(struct rtnl_link *link, unsigned int flags) 01468 { 01469 link->l_flag_mask |= flags; 01470 link->l_flags &= ~flags; 01471 link->ce_mask |= LINK_ATTR_FLAGS; 01472 } 01473 01474 unsigned int rtnl_link_get_flags(struct rtnl_link *link) 01475 { 01476 return link->l_flags; 01477 } 01478 01479 void rtnl_link_set_family(struct rtnl_link *link, int family) 01480 { 01481 link->l_family = family; 01482 link->ce_mask |= LINK_ATTR_FAMILY; 01483 } 01484 01485 int rtnl_link_get_family(struct rtnl_link *link) 01486 { 01487 if (link->ce_mask & LINK_ATTR_FAMILY) 01488 return link->l_family; 01489 else 01490 return AF_UNSPEC; 01491 } 01492 01493 void rtnl_link_set_arptype(struct rtnl_link *link, unsigned int arptype) 01494 { 01495 link->l_arptype = arptype; 01496 } 01497 01498 unsigned int rtnl_link_get_arptype(struct rtnl_link *link) 01499 { 01500 return link->l_arptype; 01501 } 01502 01503 void rtnl_link_set_ifindex(struct rtnl_link *link, int ifindex) 01504 { 01505 link->l_index = ifindex; 01506 link->ce_mask |= LINK_ATTR_IFINDEX; 01507 } 01508 01509 int rtnl_link_get_ifindex(struct rtnl_link *link) 01510 { 01511 return link->l_index; 01512 } 01513 01514 void rtnl_link_set_mtu(struct rtnl_link *link, unsigned int mtu) 01515 { 01516 link->l_mtu = mtu; 01517 link->ce_mask |= LINK_ATTR_MTU; 01518 } 01519 01520 unsigned int rtnl_link_get_mtu(struct rtnl_link *link) 01521 { 01522 if (link->ce_mask & LINK_ATTR_MTU) 01523 return link->l_mtu; 01524 else 01525 return 0; 01526 } 01527 01528 void rtnl_link_set_txqlen(struct rtnl_link *link, unsigned int txqlen) 01529 { 01530 link->l_txqlen = txqlen; 01531 link->ce_mask |= LINK_ATTR_TXQLEN; 01532 } 01533 01534 unsigned int rtnl_link_get_txqlen(struct rtnl_link *link) 01535 { 01536 if (link->ce_mask & LINK_ATTR_TXQLEN) 01537 return link->l_txqlen; 01538 else 01539 return UINT_MAX; 01540 } 01541 01542 void rtnl_link_set_weight(struct rtnl_link *link, unsigned int weight) 01543 { 01544 link->l_weight = weight; 01545 link->ce_mask |= LINK_ATTR_WEIGHT; 01546 } 01547 01548 unsigned int rtnl_link_get_weight(struct rtnl_link *link) 01549 { 01550 if (link->ce_mask & LINK_ATTR_WEIGHT) 01551 return link->l_weight; 01552 else 01553 return UINT_MAX; 01554 } 01555 01556 void rtnl_link_set_link(struct rtnl_link *link, int ifindex) 01557 { 01558 link->l_link = ifindex; 01559 link->ce_mask |= LINK_ATTR_LINK; 01560 } 01561 01562 int rtnl_link_get_link(struct rtnl_link *link) 01563 { 01564 return link->l_link; 01565 } 01566 01567 void rtnl_link_set_master(struct rtnl_link *link, int ifindex) 01568 { 01569 link->l_master = ifindex; 01570 link->ce_mask |= LINK_ATTR_MASTER; 01571 } 01572 01573 int rtnl_link_get_master(struct rtnl_link *link) 01574 { 01575 return link->l_master; 01576 } 01577 01578 void rtnl_link_set_operstate(struct rtnl_link *link, uint8_t operstate) 01579 { 01580 link->l_operstate = operstate; 01581 link->ce_mask |= LINK_ATTR_OPERSTATE; 01582 } 01583 01584 uint8_t rtnl_link_get_operstate(struct rtnl_link *link) 01585 { 01586 if (link->ce_mask & LINK_ATTR_OPERSTATE) 01587 return link->l_operstate; 01588 else 01589 return IF_OPER_UNKNOWN; 01590 } 01591 01592 void rtnl_link_set_linkmode(struct rtnl_link *link, uint8_t linkmode) 01593 { 01594 link->l_linkmode = linkmode; 01595 link->ce_mask |= LINK_ATTR_LINKMODE; 01596 } 01597 01598 uint8_t rtnl_link_get_linkmode(struct rtnl_link *link) 01599 { 01600 if (link->ce_mask & LINK_ATTR_LINKMODE) 01601 return link->l_linkmode; 01602 else 01603 return IF_LINK_MODE_DEFAULT; 01604 } 01605 01606 /** 01607 * Return alias name of link (SNMP IfAlias) 01608 * @arg link Link object 01609 * 01610 * @return Alias name or NULL if not set. 01611 */ 01612 const char *rtnl_link_get_ifalias(struct rtnl_link *link) 01613 { 01614 return link->l_ifalias; 01615 } 01616 01617 /** 01618 * Set alias name of link (SNMP IfAlias) 01619 * @arg link Link object 01620 * @arg alias Alias name or NULL to unset 01621 * 01622 * Sets the alias name of the link to the specified name. The alias 01623 * name can be unset by specyfing NULL as the alias. The name will 01624 * be strdup()ed, so no need to provide a persistent character string. 01625 */ 01626 void rtnl_link_set_ifalias(struct rtnl_link *link, const char *alias) 01627 { 01628 free(link->l_ifalias); 01629 link->ce_mask &= ~LINK_ATTR_IFALIAS; 01630 01631 if (alias) { 01632 link->l_ifalias = strdup(alias); 01633 link->ce_mask |= LINK_ATTR_IFALIAS; 01634 } 01635 } 01636 01637 /** 01638 * Retrieve number of PCI VFs of link 01639 * @arg link Link object 01640 * @arg num_vf Pointer to store number of VFs 01641 * 01642 * @return 0 if value is available or -NLE_OPNOTSUPP if not. 01643 */ 01644 int rtnl_link_get_num_vf(struct rtnl_link *link, uint32_t *num_vf) 01645 { 01646 if (link->ce_mask & LINK_ATTR_NUM_VF) { 01647 *num_vf = link->l_num_vf; 01648 return 0; 01649 } else 01650 return -NLE_OPNOTSUPP; 01651 } 01652 01653 uint64_t rtnl_link_get_stat(struct rtnl_link *link, int id) 01654 { 01655 if (id < 0 || id > RTNL_LINK_STATS_MAX) 01656 return 0; 01657 01658 return link->l_stats[id]; 01659 } 01660 01661 /** 01662 * Set value of a link statistics counter 01663 * @arg link Link object 01664 * @arg id Counter ID 01665 * @arg value New value 01666 * 01667 * @return 0 on success or a negative error code 01668 */ 01669 int rtnl_link_set_stat(struct rtnl_link *link, const unsigned int id, 01670 const uint64_t value) 01671 { 01672 if (id > RTNL_LINK_STATS_MAX) 01673 return -NLE_INVAL; 01674 01675 link->l_stats[id] = value; 01676 01677 return 0; 01678 } 01679 01680 /** 01681 * Specify the info type of a link 01682 * @arg link link object 01683 * @arg type info type 01684 * 01685 * Looks up the info type and prepares the link to store info type 01686 * specific attributes. If an info type has been assigned already 01687 * it will be released with all changes lost. 01688 * 01689 * @return 0 on success or a negative errror code. 01690 */ 01691 int rtnl_link_set_info_type(struct rtnl_link *link, const char *type) 01692 { 01693 struct rtnl_link_info_ops *io; 01694 int err; 01695 01696 if ((io = rtnl_link_info_ops_lookup(type)) == NULL) 01697 return -NLE_OPNOTSUPP; 01698 01699 if (link->l_info_ops) 01700 release_link_info(link); 01701 01702 if ((err = io->io_alloc(link)) < 0) 01703 return err; 01704 01705 link->l_info_ops = io; 01706 01707 return 0; 01708 } 01709 01710 /** 01711 * Return info type of a link 01712 * @arg link link object 01713 * 01714 * @note The returned pointer is only valid as long as the link exists 01715 * @return Info type name or NULL if unknown. 01716 */ 01717 char *rtnl_link_get_info_type(struct rtnl_link *link) 01718 { 01719 if (link->l_info_ops) 01720 return link->l_info_ops->io_name; 01721 else 01722 return NULL; 01723 } 01724 01725 /** @} */ 01726 01727 static struct nl_object_ops link_obj_ops = { 01728 .oo_name = "route/link", 01729 .oo_size = sizeof(struct rtnl_link), 01730 .oo_free_data = link_free_data, 01731 .oo_clone = link_clone, 01732 .oo_dump = { 01733 [NL_DUMP_LINE] = link_dump_line, 01734 [NL_DUMP_DETAILS] = link_dump_details, 01735 [NL_DUMP_STATS] = link_dump_stats, 01736 }, 01737 .oo_compare = link_compare, 01738 .oo_attrs2str = link_attrs2str, 01739 .oo_id_attrs = LINK_ATTR_IFINDEX, 01740 }; 01741 01742 static struct nl_af_group link_groups[] = { 01743 { AF_UNSPEC, RTNLGRP_LINK }, 01744 { END_OF_GROUP_LIST }, 01745 }; 01746 01747 static struct nl_cache_ops rtnl_link_ops = { 01748 .co_name = "route/link", 01749 .co_hdrsize = sizeof(struct ifinfomsg), 01750 .co_msgtypes = { 01751 { RTM_NEWLINK, NL_ACT_NEW, "new" }, 01752 { RTM_DELLINK, NL_ACT_DEL, "del" }, 01753 { RTM_GETLINK, NL_ACT_GET, "get" }, 01754 { RTM_SETLINK, NL_ACT_CHANGE, "set" }, 01755 END_OF_MSGTYPES_LIST, 01756 }, 01757 .co_protocol = NETLINK_ROUTE, 01758 .co_groups = link_groups, 01759 .co_request_update = link_request_update, 01760 .co_msg_parser = link_msg_parser, 01761 .co_obj_ops = &link_obj_ops, 01762 }; 01763 01764 static void __init link_init(void) 01765 { 01766 nl_cache_mngt_register(&rtnl_link_ops); 01767 } 01768 01769 static void __exit link_exit(void) 01770 { 01771 nl_cache_mngt_unregister(&rtnl_link_ops); 01772 } 01773 01774 /** @} */