link.c revision 44d362409d5469aed47d19e7908d19bd194493a4
1/* 2 * lib/route/link.c Links (Interfaces) 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation version 2.1 7 * of the License. 8 * 9 * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> 10 */ 11 12/** 13 * @ingroup rtnl 14 * @defgroup link Links (Interfaces) 15 * @brief 16 * 17 * @par Link Identification 18 * A link can be identified by either its interface index or by its 19 * name. The kernel favours the interface index but falls back to the 20 * interface name if the interface index is lesser-than 0 for kernels 21 * >= 2.6.11. Therefore you can request changes without mapping a 22 * interface name to the corresponding index first. 23 * 24 * @par Changeable Attributes 25 * @anchor link_changeable 26 * - Link layer address 27 * - Link layer broadcast address 28 * - device mapping (ifmap) (>= 2.6.9) 29 * - MTU (>= 2.6.9) 30 * - Transmission queue length (>= 2.6.9) 31 * - Weight (>= 2.6.9) 32 * - Link name (only via access through interface index) (>= 2.6.9) 33 * - Flags (>= 2.6.9) 34 * - IFF_DEBUG 35 * - IFF_NOTRAILERS 36 * - IFF_NOARP 37 * - IFF_DYNAMIC 38 * - IFF_MULTICAST 39 * - IFF_PORTSEL 40 * - IFF_AUTOMEDIA 41 * - IFF_UP 42 * - IFF_PROMISC 43 * - IFF_ALLMULTI 44 * 45 * @par Link Flags (linux/if.h) 46 * @anchor link_flags 47 * @code 48 * IFF_UP Status of link (up|down) 49 * IFF_BROADCAST Indicates this link allows broadcasting 50 * IFF_MULTICAST Indicates this link allows multicasting 51 * IFF_ALLMULTI Indicates this link is doing multicast routing 52 * IFF_DEBUG Tell the driver to do debugging (currently unused) 53 * IFF_LOOPBACK This is the loopback link 54 * IFF_POINTOPOINT Point-to-point link 55 * IFF_NOARP Link is unable to perform ARP 56 * IFF_PROMISC Status of promiscious mode flag 57 * IFF_MASTER Used by teql 58 * IFF_SLAVE Used by teql 59 * IFF_PORTSEL Indicates this link allows port selection 60 * IFF_AUTOMEDIA Indicates this link selects port automatically 61 * IFF_DYNAMIC Indicates the address of this link is dynamic 62 * IFF_RUNNING Link is running and carrier is ok. 63 * IFF_NOTRAILERS Unused, BSD compat. 64 * @endcode 65 * 66 * @par Notes on IFF_PROMISC and IFF_ALLMULTI flags 67 * Although you can query the status of IFF_PROMISC and IFF_ALLMULTI 68 * they do not represent the actual state in the kernel but rather 69 * whether the flag has been enabled/disabled by userspace. The link 70 * may be in promiscious mode even if IFF_PROMISC is not set in a link 71 * dump request response because promiscity might be needed by the driver 72 * for a period of time. 73 * 74 * @note The unit of the transmission queue length depends on the 75 * link type, a common unit is \a packets. 76 * 77 * @par 1) Retrieving information about available links 78 * @code 79 * // The first step is to retrieve a list of all available interfaces within 80 * // the kernel and put them into a cache. 81 * struct nl_cache *cache = rtnl_link_alloc_cache(nl_handle); 82 * 83 * // In a second step, a specific link may be looked up by either interface 84 * // index or interface name. 85 * struct rtnl_link *link = rtnl_link_get_by_name(cache, "lo"); 86 * 87 * // rtnl_link_get_by_name() is the short version for translating the 88 * // interface name to an interface index first like this: 89 * int ifindex = rtnl_link_name2i(cache, "lo"); 90 * struct rtnl_link *link = rtnl_link_get(cache, ifindex); 91 * 92 * // After successful usage, the object must be given back to the cache 93 * rtnl_link_put(link); 94 * @endcode 95 * 96 * @par 2) Changing link attributes 97 * @code 98 * // In order to change any attributes of an existing link, we must allocate 99 * // a new link to hold the change requests: 100 * struct rtnl_link *request = rtnl_link_alloc(); 101 * 102 * // Now we can go on and specify the attributes we want to change: 103 * rtnl_link_set_weight(request, 300); 104 * rtnl_link_set_mtu(request, 1360); 105 * 106 * // We can also shut an interface down administratively 107 * rtnl_link_unset_flags(request, rtnl_link_str2flags("up")); 108 * 109 * // Actually, we should know which link to change, so let's look it up 110 * struct rtnl_link *old = rtnl_link_get(cache, "eth0"); 111 * 112 * // Two ways exist to commit this change request, the first one is to 113 * // build the required netlink message and send it out in one single 114 * // step: 115 * rtnl_link_change(nl_handle, old, request); 116 * 117 * // An alternative way is to build the netlink message and send it 118 * // out yourself using nl_send_auto_complete() 119 * struct nl_msg *msg = rtnl_link_build_change_request(old, request); 120 * nl_send_auto_complete(nl_handle, nlmsg_hdr(msg)); 121 * nlmsg_free(msg); 122 * 123 * // Don't forget to give back the link object ;-> 124 * rtnl_link_put(old); 125 * @endcode 126 * @{ 127 */ 128 129#include <netlink-local.h> 130#include <netlink/netlink.h> 131#include <netlink/attr.h> 132#include <netlink/utils.h> 133#include <netlink/object.h> 134#include <netlink/route/rtnl.h> 135#include <netlink/route/link.h> 136 137/** @cond SKIP */ 138#define LINK_ATTR_MTU 0x0001 139#define LINK_ATTR_LINK 0x0002 140#define LINK_ATTR_TXQLEN 0x0004 141#define LINK_ATTR_WEIGHT 0x0008 142#define LINK_ATTR_MASTER 0x0010 143#define LINK_ATTR_QDISC 0x0020 144#define LINK_ATTR_MAP 0x0040 145#define LINK_ATTR_ADDR 0x0080 146#define LINK_ATTR_BRD 0x0100 147#define LINK_ATTR_FLAGS 0x0200 148#define LINK_ATTR_IFNAME 0x0400 149#define LINK_ATTR_IFINDEX 0x0800 150#define LINK_ATTR_FAMILY 0x1000 151#define LINK_ATTR_ARPTYPE 0x2000 152#define LINK_ATTR_STATS 0x4000 153#define LINK_ATTR_CHANGE 0x8000 154 155static struct nl_cache_ops rtnl_link_ops; 156static struct nl_object_ops link_obj_ops; 157/** @endcond */ 158 159static void link_free_data(struct nl_object *c) 160{ 161 struct rtnl_link *link = nl_object_priv(c); 162 163 if (link) { 164 nl_addr_put(link->l_addr); 165 nl_addr_put(link->l_bcast); 166 } 167} 168 169static int link_clone(struct nl_object *_dst, struct nl_object *_src) 170{ 171 struct rtnl_link *dst = nl_object_priv(_dst); 172 struct rtnl_link *src = nl_object_priv(_src); 173 174 if (src->l_addr) 175 if (!(dst->l_addr = nl_addr_clone(src->l_addr))) 176 goto errout; 177 178 if (src->l_bcast) 179 if (!(dst->l_bcast = nl_addr_clone(src->l_bcast))) 180 goto errout; 181 182 return 0; 183errout: 184 return nl_get_errno(); 185} 186 187static struct nla_policy link_policy[IFLA_MAX+1] = { 188 [IFLA_IFNAME] = { .type = NLA_STRING, 189 .maxlen = IFNAMSIZ }, 190 [IFLA_MTU] = { .type = NLA_U32 }, 191 [IFLA_TXQLEN] = { .type = NLA_U32 }, 192 [IFLA_LINK] = { .type = NLA_U32 }, 193 [IFLA_WEIGHT] = { .type = NLA_U32 }, 194 [IFLA_MASTER] = { .type = NLA_U32 }, 195 [IFLA_QDISC] = { .type = NLA_STRING, 196 .maxlen = IFQDISCSIZ }, 197 [IFLA_STATS] = { .minlen = sizeof(struct rtnl_link_stats) }, 198 [IFLA_MAP] = { .minlen = sizeof(struct rtnl_link_ifmap) }, 199}; 200 201static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, 202 struct nlmsghdr *n, void *arg) 203{ 204 struct rtnl_link *link; 205 struct ifinfomsg *ifi; 206 struct nlattr *tb[IFLA_MAX+1]; 207 struct nl_parser_param *pp = arg; 208 int err; 209 210 link = rtnl_link_alloc(); 211 if (link == NULL) { 212 err = nl_errno(ENOMEM); 213 goto errout; 214 } 215 216 link->ce_msgtype = n->nlmsg_type; 217 218 err = nlmsg_parse(n, sizeof(*ifi), tb, IFLA_MAX, link_policy); 219 if (err < 0) 220 goto errout; 221 222 if (tb[IFLA_IFNAME] == NULL) { 223 err = nl_error(EINVAL, "Missing link name TLV"); 224 goto errout; 225 } 226 227 nla_strlcpy(link->l_name, tb[IFLA_IFNAME], IFNAMSIZ); 228 229 ifi = nlmsg_data(n); 230 link->l_family = ifi->ifi_family; 231 link->l_arptype = ifi->ifi_type; 232 link->l_index = ifi->ifi_index; 233 link->l_flags = ifi->ifi_flags; 234 link->l_change = ifi->ifi_change; 235 link->ce_mask = (LINK_ATTR_IFNAME | LINK_ATTR_FAMILY | 236 LINK_ATTR_ARPTYPE| LINK_ATTR_IFINDEX | 237 LINK_ATTR_FLAGS | LINK_ATTR_CHANGE); 238 239 if (tb[IFLA_STATS]) { 240 struct rtnl_link_stats *st = nla_data(tb[IFLA_STATS]); 241 242 link->l_stats[RTNL_LINK_RX_PACKETS] = st->rx_packets; 243 link->l_stats[RTNL_LINK_RX_BYTES] = st->rx_bytes; 244 link->l_stats[RTNL_LINK_RX_ERRORS] = st->rx_errors; 245 link->l_stats[RTNL_LINK_RX_DROPPED] = st->rx_dropped; 246 link->l_stats[RTNL_LINK_RX_COMPRESSED] = st->rx_compressed; 247 link->l_stats[RTNL_LINK_RX_FIFO_ERR] = st->rx_fifo_errors; 248 link->l_stats[RTNL_LINK_TX_PACKETS] = st->tx_packets; 249 link->l_stats[RTNL_LINK_TX_BYTES] = st->tx_bytes; 250 link->l_stats[RTNL_LINK_TX_ERRORS] = st->tx_errors; 251 link->l_stats[RTNL_LINK_TX_DROPPED] = st->tx_dropped; 252 link->l_stats[RTNL_LINK_TX_COMPRESSED] = st->tx_compressed; 253 link->l_stats[RTNL_LINK_TX_FIFO_ERR] = st->tx_fifo_errors; 254 link->l_stats[RTNL_LINK_RX_LEN_ERR] = st->rx_length_errors; 255 link->l_stats[RTNL_LINK_RX_OVER_ERR] = st->rx_over_errors; 256 link->l_stats[RTNL_LINK_RX_CRC_ERR] = st->rx_crc_errors; 257 link->l_stats[RTNL_LINK_RX_FRAME_ERR] = st->rx_frame_errors; 258 link->l_stats[RTNL_LINK_RX_MISSED_ERR] = st->rx_missed_errors; 259 link->l_stats[RTNL_LINK_TX_ABORT_ERR] = st->tx_aborted_errors; 260 link->l_stats[RTNL_LINK_TX_CARRIER_ERR] = st->tx_carrier_errors; 261 link->l_stats[RTNL_LINK_TX_HBEAT_ERR] = st->tx_heartbeat_errors; 262 link->l_stats[RTNL_LINK_TX_WIN_ERR] = st->tx_window_errors; 263 link->l_stats[RTNL_LINK_MULTICAST] = st->multicast; 264 265 link->ce_mask |= LINK_ATTR_STATS; 266 } 267 268 if (tb[IFLA_TXQLEN]) { 269 link->l_txqlen = nla_get_u32(tb[IFLA_TXQLEN]); 270 link->ce_mask |= LINK_ATTR_TXQLEN; 271 } 272 273 if (tb[IFLA_MTU]) { 274 link->l_mtu = nla_get_u32(tb[IFLA_MTU]); 275 link->ce_mask |= LINK_ATTR_MTU; 276 } 277 278 if (tb[IFLA_ADDRESS]) { 279 link->l_addr = nla_get_addr(tb[IFLA_ADDRESS], AF_UNSPEC); 280 if (link->l_addr == NULL) 281 goto errout; 282 nl_addr_set_family(link->l_addr, 283 nl_addr_guess_family(link->l_addr)); 284 link->ce_mask |= LINK_ATTR_ADDR; 285 } 286 287 if (tb[IFLA_BROADCAST]) { 288 link->l_bcast = nla_get_addr(tb[IFLA_BROADCAST], AF_UNSPEC); 289 if (link->l_bcast == NULL) 290 goto errout; 291 nl_addr_set_family(link->l_bcast, 292 nl_addr_guess_family(link->l_bcast)); 293 link->ce_mask |= LINK_ATTR_BRD; 294 } 295 296 if (tb[IFLA_LINK]) { 297 link->l_link = nla_get_u32(tb[IFLA_LINK]); 298 link->ce_mask |= LINK_ATTR_LINK; 299 } 300 301 if (tb[IFLA_WEIGHT]) { 302 link->l_weight = nla_get_u32(tb[IFLA_WEIGHT]); 303 link->ce_mask |= LINK_ATTR_WEIGHT; 304 } 305 306 if (tb[IFLA_QDISC]) { 307 nla_strlcpy(link->l_qdisc, tb[IFLA_QDISC], IFQDISCSIZ); 308 link->ce_mask |= LINK_ATTR_QDISC; 309 } 310 311 if (tb[IFLA_MAP]) { 312 struct rtnl_link_ifmap *map = nla_data(tb[IFLA_MAP]); 313 link->l_map.lm_mem_start = map->mem_start; 314 link->l_map.lm_mem_end = map->mem_end; 315 link->l_map.lm_base_addr = map->base_addr; 316 link->l_map.lm_irq = map->irq; 317 link->l_map.lm_dma = map->dma; 318 link->l_map.lm_port = map->port; 319 link->ce_mask |= LINK_ATTR_MAP; 320 } 321 322 if (tb[IFLA_MASTER]) { 323 link->l_master = nla_get_u32(tb[IFLA_MASTER]); 324 link->ce_mask |= LINK_ATTR_MASTER; 325 } 326 327 err = pp->pp_cb((struct nl_object *) link, pp); 328 if (err < 0) 329 goto errout; 330 331 return P_ACCEPT; 332 333errout: 334 rtnl_link_put(link); 335 return err; 336} 337 338static int link_request_update(struct nl_cache *c, struct nl_handle *h) 339{ 340 return nl_rtgen_request(h, RTM_GETLINK, AF_UNSPEC, NLM_F_DUMP); 341} 342 343static int link_dump_brief(struct nl_object *obj, struct nl_dump_params *p) 344{ 345 char buf[128]; 346 struct nl_cache *cache = dp_cache(obj); 347 struct rtnl_link *link = (struct rtnl_link *) obj; 348 int line = 1; 349 350 dp_dump(p, "%s ", link->l_name); 351 352 if (link->ce_mask & LINK_ATTR_LINK) { 353 struct rtnl_link *ll = rtnl_link_get(cache, link->l_link); 354 dp_dump(p, "@%s", ll ? ll->l_name : "NONE"); 355 if (ll) 356 rtnl_link_put(ll); 357 } 358 359 dp_dump(p, "%s ", nl_llproto2str(link->l_arptype, buf, sizeof(buf))); 360 dp_dump(p, "%s ", link->l_addr ? nl_addr2str(link->l_addr, buf, 361 sizeof(buf)) : "none"); 362 dp_dump(p, "mtu %u ", link->l_mtu); 363 364 if (link->ce_mask & LINK_ATTR_MASTER) { 365 struct rtnl_link *master = rtnl_link_get(cache, link->l_master); 366 dp_dump(p, "master %s ", master ? master->l_name : "inv"); 367 if (master) 368 rtnl_link_put(master); 369 } 370 371 rtnl_link_flags2str(link->l_flags, buf, sizeof(buf)); 372 if (buf[0]) 373 dp_dump(p, "<%s>", buf); 374 375 dp_dump(p, "\n"); 376 377 return line; 378} 379 380static int link_dump_full(struct nl_object *obj, struct nl_dump_params *p) 381{ 382 struct rtnl_link *link = (struct rtnl_link *) obj; 383 char buf[64]; 384 int line; 385 386 line = link_dump_brief(obj, p); 387 dp_new_line(p, line++); 388 389 dp_dump(p, " txqlen %u weight %u ", link->l_txqlen, link->l_weight); 390 391 if (link->ce_mask & LINK_ATTR_QDISC) 392 dp_dump(p, "qdisc %s ", link->l_qdisc); 393 394 if (link->ce_mask & LINK_ATTR_MAP && link->l_map.lm_irq) 395 dp_dump(p, "irq %u ", link->l_map.lm_irq); 396 397 if (link->ce_mask & LINK_ATTR_IFINDEX) 398 dp_dump(p, "index %u ", link->l_index); 399 400 if (link->ce_mask & LINK_ATTR_BRD) 401 dp_dump(p, "brd %s", nl_addr2str(link->l_bcast, buf, 402 sizeof(buf))); 403 404 dp_dump(p, "\n"); 405 406 return line; 407} 408 409static int link_dump_stats(struct nl_object *obj, struct nl_dump_params *p) 410{ 411 struct rtnl_link *link = (struct rtnl_link *) obj; 412 char *unit, fmt[64]; 413 float res; 414 int line; 415 416 line = link_dump_full(obj, p); 417 418 dp_dump_line(p, line++, " Stats: bytes packets errors " 419 " dropped fifo-err compressed\n"); 420 421 res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_RX_BYTES], &unit); 422 423 strcpy(fmt, " RX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n"); 424 fmt[9] = *unit == 'B' ? '9' : '7'; 425 426 dp_dump_line(p, line++, fmt, 427 res, unit, 428 link->l_stats[RTNL_LINK_RX_PACKETS], 429 link->l_stats[RTNL_LINK_RX_ERRORS], 430 link->l_stats[RTNL_LINK_RX_DROPPED], 431 link->l_stats[RTNL_LINK_RX_FIFO_ERR], 432 link->l_stats[RTNL_LINK_RX_COMPRESSED]); 433 434 res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_TX_BYTES], &unit); 435 436 strcpy(fmt, " TX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n"); 437 fmt[9] = *unit == 'B' ? '9' : '7'; 438 439 dp_dump_line(p, line++, fmt, 440 res, unit, 441 link->l_stats[RTNL_LINK_TX_PACKETS], 442 link->l_stats[RTNL_LINK_TX_ERRORS], 443 link->l_stats[RTNL_LINK_TX_DROPPED], 444 link->l_stats[RTNL_LINK_TX_FIFO_ERR], 445 link->l_stats[RTNL_LINK_TX_COMPRESSED]); 446 447 dp_dump_line(p, line++, " Errors: length over crc " 448 " frame missed multicast\n"); 449 450 dp_dump_line(p, line++, " RX %10" PRIu64 " %10" PRIu64 " %10" 451 PRIu64 " %10" PRIu64 " %10" PRIu64 " %10" 452 PRIu64 "\n", 453 link->l_stats[RTNL_LINK_RX_LEN_ERR], 454 link->l_stats[RTNL_LINK_RX_OVER_ERR], 455 link->l_stats[RTNL_LINK_RX_CRC_ERR], 456 link->l_stats[RTNL_LINK_RX_FRAME_ERR], 457 link->l_stats[RTNL_LINK_RX_MISSED_ERR], 458 link->l_stats[RTNL_LINK_MULTICAST]); 459 460 dp_dump_line(p, line++, " Errors: aborted carrier heartbeat " 461 " window collision\n"); 462 463 dp_dump_line(p, line++, " TX %10" PRIu64 " %10" PRIu64 " %10" 464 PRIu64 " %10" PRIu64 " %10" PRIu64 "\n", 465 link->l_stats[RTNL_LINK_TX_ABORT_ERR], 466 link->l_stats[RTNL_LINK_TX_CARRIER_ERR], 467 link->l_stats[RTNL_LINK_TX_HBEAT_ERR], 468 link->l_stats[RTNL_LINK_TX_WIN_ERR], 469 link->l_stats[RTNL_LINK_TX_COLLISIONS]); 470 471 return line; 472} 473 474static int link_dump_xml(struct nl_object *obj, struct nl_dump_params *p) 475{ 476 struct rtnl_link *link = (struct rtnl_link *) obj; 477 struct nl_cache *cache = dp_cache(obj); 478 char buf[128]; 479 int i, line = 0; 480 481 dp_dump_line(p, line++, "<link name=\"%s\" index=\"%u\">\n", 482 link->l_name, link->l_index); 483 dp_dump_line(p, line++, " <family>%s</family>\n", 484 nl_af2str(link->l_family, buf, sizeof(buf))); 485 dp_dump_line(p, line++, " <arptype>%s</arptype>\n", 486 nl_llproto2str(link->l_arptype, buf, sizeof(buf))); 487 dp_dump_line(p, line++, " <address>%s</address>\n", 488 nl_addr2str(link->l_addr, buf, sizeof(buf))); 489 dp_dump_line(p, line++, " <mtu>%u</mtu>\n", link->l_mtu); 490 dp_dump_line(p, line++, " <txqlen>%u</txqlen>\n", link->l_txqlen); 491 dp_dump_line(p, line++, " <weight>%u</weight>\n", link->l_weight); 492 493 rtnl_link_flags2str(link->l_flags, buf, sizeof(buf)); 494 if (buf[0]) 495 dp_dump_line(p, line++, " <flags>%s</flags>\n", buf); 496 497 if (link->ce_mask & LINK_ATTR_QDISC) 498 dp_dump_line(p, line++, " <qdisc>%s</qdisc>\n", link->l_qdisc); 499 500 if (link->ce_mask & LINK_ATTR_LINK) { 501 struct rtnl_link *ll = rtnl_link_get(cache, link->l_link); 502 dp_dump_line(p, line++, " <link>%s</link>\n", 503 ll ? ll->l_name : "none"); 504 if (ll) 505 rtnl_link_put(ll); 506 } 507 508 if (link->ce_mask & LINK_ATTR_MASTER) { 509 struct rtnl_link *master = rtnl_link_get(cache, link->l_master); 510 dp_dump_line(p, line++, " <master>%s</master>\n", 511 master ? master->l_name : "none"); 512 if (master) 513 rtnl_link_put(master); 514 } 515 516 if (link->ce_mask & LINK_ATTR_BRD) 517 dp_dump_line(p, line++, " <broadcast>%s</broadcast>\n", 518 nl_addr2str(link->l_bcast, buf, sizeof(buf))); 519 520 if (link->ce_mask & LINK_ATTR_STATS) { 521 dp_dump_line(p, line++, " <stats>\n"); 522 for (i = 0; i <= RTNL_LINK_STATS_MAX; i++) { 523 rtnl_link_stat2str(i, buf, sizeof(buf)); 524 dp_dump_line(p, line++, 525 " <%s>%" PRIu64 "</%s>\n", 526 buf, link->l_stats[i], buf); 527 } 528 dp_dump_line(p, line++, " </stats>\n"); 529 } 530 531 dp_dump_line(p, line++, "</link>\n"); 532 533#if 0 534 uint32_t l_change; /**< Change mask */ 535 struct rtnl_lifmap l_map; /**< Interface device mapping */ 536#endif 537 538 return line; 539} 540 541static int link_dump_env(struct nl_object *obj, struct nl_dump_params *p) 542{ 543 struct rtnl_link *link = (struct rtnl_link *) obj; 544 struct nl_cache *cache = dp_cache(obj); 545 char buf[128]; 546 int i, line = 0; 547 548 dp_dump_line(p, line++, "LINK_NAME=%s\n", link->l_name); 549 dp_dump_line(p, line++, "LINK_IFINDEX=%u\n", link->l_index); 550 dp_dump_line(p, line++, "LINK_FAMILY=%s\n", 551 nl_af2str(link->l_family, buf, sizeof(buf))); 552 dp_dump_line(p, line++, "LINK_TYPE=%s\n", 553 nl_llproto2str(link->l_arptype, buf, sizeof(buf))); 554 if (link->ce_mask & LINK_ATTR_ADDR) 555 dp_dump_line(p, line++, "LINK_ADDRESS=%s\n", 556 nl_addr2str(link->l_addr, buf, sizeof(buf))); 557 dp_dump_line(p, line++, "LINK_MTU=%u\n", link->l_mtu); 558 dp_dump_line(p, line++, "LINK_TXQUEUELEN=%u\n", link->l_txqlen); 559 dp_dump_line(p, line++, "LINK_WEIGHT=%u\n", link->l_weight); 560 561 rtnl_link_flags2str(link->l_flags & ~IFF_RUNNING, buf, sizeof(buf)); 562 if (buf[0]) 563 dp_dump_line(p, line++, "LINK_FLAGS=%s\n", buf); 564 565 if (link->ce_mask & LINK_ATTR_QDISC) 566 dp_dump_line(p, line++, "LINK_QDISC=%s\n", link->l_qdisc); 567 568 if (link->ce_mask & LINK_ATTR_LINK) { 569 struct rtnl_link *ll = rtnl_link_get(cache, link->l_link); 570 571 dp_dump_line(p, line++, "LINK_LINK_IFINDEX=%d\n", link->l_link); 572 if (ll) { 573 dp_dump_line(p, line++, "LINK_LINK_IFNAME=%s\n", 574 ll->l_name); 575 rtnl_link_put(ll); 576 } 577 } 578 579 if (link->ce_mask & LINK_ATTR_MASTER) { 580 struct rtnl_link *master = rtnl_link_get(cache, link->l_master); 581 dp_dump_line(p, line++, "LINK_MASTER=%s\n", 582 master ? master->l_name : "none"); 583 if (master) 584 rtnl_link_put(master); 585 } 586 587 if (link->ce_mask & LINK_ATTR_BRD) 588 dp_dump_line(p, line++, "LINK_BROADCAST=%s\n", 589 nl_addr2str(link->l_bcast, buf, sizeof(buf))); 590 591 if (link->ce_mask & LINK_ATTR_STATS) { 592 for (i = 0; i <= RTNL_LINK_STATS_MAX; i++) { 593 char *c = buf; 594 595 sprintf(buf, "LINK_"); 596 rtnl_link_stat2str(i, buf + 5, sizeof(buf) - 5); 597 while (*c) { 598 *c = toupper(*c); 599 c++; 600 } 601 dp_dump_line(p, line++, 602 "%s=%" PRIu64 "\n", buf, link->l_stats[i]); 603 } 604 } 605 606 return line; 607} 608 609#if 0 610static int link_handle_event(struct nl_object *a, struct rtnl_link_event_cb *cb) 611{ 612 struct rtnl_link *l = (struct rtnl_link *) a; 613 struct nl_cache *c = dp_cache(a); 614 int nevents = 0; 615 616 if (l->l_change == ~0U) { 617 if (l->ce_msgtype == RTM_NEWLINK) 618 cb->le_register(l); 619 else 620 cb->le_unregister(l); 621 622 return 1; 623 } 624 625 if (l->l_change & IFF_SLAVE) { 626 if (l->l_flags & IFF_SLAVE) { 627 struct rtnl_link *m = rtnl_link_get(c, l->l_master); 628 cb->le_new_bonding(l, m); 629 if (m) 630 rtnl_link_put(m); 631 } else 632 cb->le_cancel_bonding(l); 633 } 634 635#if 0 636 if (l->l_change & IFF_UP && l->l_change & IFF_RUNNING) 637 dp_dump_line(p, line++, "link %s changed state to %s.\n", 638 l->l_name, l->l_flags & IFF_UP ? "up" : "down"); 639 640 if (l->l_change & IFF_PROMISC) { 641 dp_new_line(p, line++); 642 dp_dump(p, "link %s %s promiscuous mode.\n", 643 l->l_name, l->l_flags & IFF_PROMISC ? "entered" : "left"); 644 } 645 646 if (line == 0) 647 dp_dump_line(p, line++, "link %s sent unknown event.\n", 648 l->l_name); 649#endif 650 651 return nevents; 652} 653#endif 654 655static int link_compare(struct nl_object *_a, struct nl_object *_b, 656 uint32_t attrs, int flags) 657{ 658 struct rtnl_link *a = (struct rtnl_link *) _a; 659 struct rtnl_link *b = (struct rtnl_link *) _b; 660 int diff = 0; 661 662#define LINK_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, LINK_ATTR_##ATTR, a, b, EXPR) 663 664 diff |= LINK_DIFF(IFINDEX, a->l_index != b->l_index); 665 diff |= LINK_DIFF(MTU, a->l_mtu != b->l_mtu); 666 diff |= LINK_DIFF(LINK, a->l_link != b->l_link); 667 diff |= LINK_DIFF(TXQLEN, a->l_txqlen != b->l_txqlen); 668 diff |= LINK_DIFF(WEIGHT, a->l_weight != b->l_weight); 669 diff |= LINK_DIFF(MASTER, a->l_master != b->l_master); 670 diff |= LINK_DIFF(FAMILY, a->l_family != b->l_family); 671 diff |= LINK_DIFF(QDISC, strcmp(a->l_qdisc, b->l_qdisc)); 672 diff |= LINK_DIFF(IFNAME, strcmp(a->l_name, b->l_name)); 673 diff |= LINK_DIFF(ADDR, nl_addr_cmp(a->l_addr, b->l_addr)); 674 diff |= LINK_DIFF(BRD, nl_addr_cmp(a->l_bcast, b->l_bcast)); 675 676 if (flags & LOOSE_FLAG_COMPARISON) 677 diff |= LINK_DIFF(FLAGS, 678 (a->l_flags ^ b->l_flags) & b->l_flag_mask); 679 else 680 diff |= LINK_DIFF(FLAGS, a->l_flags != b->l_flags); 681 682#undef LINK_DIFF 683 684 return diff; 685} 686 687static struct trans_tbl link_attrs[] = { 688 __ADD(LINK_ATTR_MTU, mtu) 689 __ADD(LINK_ATTR_LINK, link) 690 __ADD(LINK_ATTR_TXQLEN, txqlen) 691 __ADD(LINK_ATTR_WEIGHT, weight) 692 __ADD(LINK_ATTR_MASTER, master) 693 __ADD(LINK_ATTR_QDISC, qdisc) 694 __ADD(LINK_ATTR_MAP, map) 695 __ADD(LINK_ATTR_ADDR, address) 696 __ADD(LINK_ATTR_BRD, broadcast) 697 __ADD(LINK_ATTR_FLAGS, flags) 698 __ADD(LINK_ATTR_IFNAME, name) 699 __ADD(LINK_ATTR_IFINDEX, ifindex) 700 __ADD(LINK_ATTR_FAMILY, family) 701 __ADD(LINK_ATTR_ARPTYPE, arptype) 702 __ADD(LINK_ATTR_STATS, stats) 703 __ADD(LINK_ATTR_CHANGE, change) 704}; 705 706static char *link_attrs2str(int attrs, char *buf, size_t len) 707{ 708 return __flags2str(attrs, buf, len, link_attrs, 709 ARRAY_SIZE(link_attrs)); 710} 711 712/** 713 * @name Allocation/Freeing 714 * @{ 715 */ 716 717struct rtnl_link *rtnl_link_alloc(void) 718{ 719 return (struct rtnl_link *) nl_object_alloc(&link_obj_ops); 720} 721 722void rtnl_link_put(struct rtnl_link *link) 723{ 724 nl_object_put((struct nl_object *) link); 725} 726 727/** @} */ 728 729/** 730 * @name Cache Management 731 * @{ 732 */ 733 734 735/** 736 * Allocate link cache and fill in all configured links. 737 * @arg handle Netlink handle. 738 * 739 * Allocates a new link cache, initializes it properly and updates it 740 * to include all links currently configured in the kernel. 741 * 742 * @note Free the memory after usage. 743 * @return Newly allocated cache or NULL if an error occured. 744 */ 745struct nl_cache *rtnl_link_alloc_cache(struct nl_handle *handle) 746{ 747 struct nl_cache * cache; 748 749 cache = nl_cache_alloc(&rtnl_link_ops); 750 if (cache == NULL) 751 return NULL; 752 753 if (handle && nl_cache_refill(handle, cache) < 0) { 754 nl_cache_free(cache); 755 return NULL; 756 } 757 758 return cache; 759} 760 761/** 762 * Look up link by interface index in the provided cache 763 * @arg cache link cache 764 * @arg ifindex link interface index 765 * 766 * The caller owns a reference on the returned object and 767 * must give the object back via rtnl_link_put(). 768 * 769 * @return pointer to link inside the cache or NULL if no match was found. 770 */ 771struct rtnl_link *rtnl_link_get(struct nl_cache *cache, int ifindex) 772{ 773 struct rtnl_link *link; 774 775 if (cache->c_ops != &rtnl_link_ops) 776 return NULL; 777 778 nl_list_for_each_entry(link, &cache->c_items, ce_list) { 779 if (link->l_index == ifindex) { 780 nl_object_get((struct nl_object *) link); 781 return link; 782 } 783 } 784 785 return NULL; 786} 787 788/** 789 * Look up link by link name in the provided cache 790 * @arg cache link cache 791 * @arg name link name 792 * 793 * The caller owns a reference on the returned object and 794 * must give the object back via rtnl_link_put(). 795 * 796 * @return pointer to link inside the cache or NULL if no match was found. 797 */ 798struct rtnl_link *rtnl_link_get_by_name(struct nl_cache *cache, 799 const char *name) 800{ 801 struct rtnl_link *link; 802 803 if (cache->c_ops != &rtnl_link_ops) 804 return NULL; 805 806 nl_list_for_each_entry(link, &cache->c_items, ce_list) { 807 if (!strcmp(name, link->l_name)) { 808 nl_object_get((struct nl_object *) link); 809 return link; 810 } 811 } 812 813 return NULL; 814} 815 816/** @} */ 817 818/** 819 * @name Link Modifications 820 * @{ 821 */ 822 823/** 824 * Builds a netlink change request message to change link attributes 825 * @arg old link to be changed 826 * @arg tmpl template with requested changes 827 * @arg flags additional netlink message flags 828 * 829 * Builds a new netlink message requesting a change of link attributes. 830 * The netlink message header isn't fully equipped with all relevant 831 * fields and must be sent out via nl_send_auto_complete() or 832 * supplemented as needed. 833 * \a old must point to a link currently configured in the kernel 834 * and \a tmpl must contain the attributes to be changed set via 835 * \c rtnl_link_set_* functions. 836 * 837 * @return New netlink message 838 * @note Not all attributes can be changed, see 839 * \ref link_changeable "Changeable Attributes" for more details. 840 */ 841struct nl_msg * rtnl_link_build_change_request(struct rtnl_link *old, 842 struct rtnl_link *tmpl, 843 int flags) 844{ 845 struct nl_msg *msg; 846 struct ifinfomsg ifi = { 847 .ifi_family = old->l_family, 848 .ifi_index = old->l_index, 849 }; 850 851 if (tmpl->ce_mask & LINK_ATTR_FLAGS) { 852 ifi.ifi_flags = old->l_flags & ~tmpl->l_flag_mask; 853 ifi.ifi_flags |= tmpl->l_flags; 854 } 855 856 msg = nlmsg_alloc_simple(RTM_SETLINK, flags); 857 if (!msg) 858 goto nla_put_failure; 859 860 if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0) 861 goto nla_put_failure; 862 863 if (tmpl->ce_mask & LINK_ATTR_ADDR) 864 NLA_PUT_ADDR(msg, IFLA_ADDRESS, tmpl->l_addr); 865 866 if (tmpl->ce_mask & LINK_ATTR_BRD) 867 NLA_PUT_ADDR(msg, IFLA_BROADCAST, tmpl->l_bcast); 868 869 if (tmpl->ce_mask & LINK_ATTR_MTU) 870 NLA_PUT_U32(msg, IFLA_MTU, tmpl->l_mtu); 871 872 if (tmpl->ce_mask & LINK_ATTR_TXQLEN) 873 NLA_PUT_U32(msg, IFLA_TXQLEN, tmpl->l_txqlen); 874 875 if (tmpl->ce_mask & LINK_ATTR_WEIGHT) 876 NLA_PUT_U32(msg, IFLA_WEIGHT, tmpl->l_weight); 877 878 if (tmpl->ce_mask & LINK_ATTR_IFNAME) 879 NLA_PUT_STRING(msg, IFLA_IFNAME, tmpl->l_name); 880 881 return msg; 882 883nla_put_failure: 884 nlmsg_free(msg); 885 return NULL; 886} 887 888/** 889 * Change link attributes 890 * @arg handle netlink handle 891 * @arg old link to be changed 892 * @arg tmpl template with requested changes 893 * @arg flags additional netlink message flags 894 * 895 * Builds a new netlink message by calling rtnl_link_build_change_request(), 896 * sends the request to the kernel and waits for the next ACK to be 897 * received, i.e. blocks until the request has been processed. 898 * 899 * @return 0 on success or a negative error code 900 * @note Not all attributes can be changed, see 901 * \ref link_changeable "Changeable Attributes" for more details. 902 */ 903int rtnl_link_change(struct nl_handle *handle, struct rtnl_link *old, 904 struct rtnl_link *tmpl, int flags) 905{ 906 int err; 907 struct nl_msg *msg; 908 909 msg = rtnl_link_build_change_request(old, tmpl, flags); 910 if (!msg) 911 return nl_errno(ENOMEM); 912 913 err = nl_send_auto_complete(handle, msg); 914 if (err < 0) 915 return err; 916 917 nlmsg_free(msg); 918 return nl_wait_for_ack(handle); 919} 920 921/** @} */ 922 923/** 924 * @name Name <-> Index Translations 925 * @{ 926 */ 927 928/** 929 * Translate an interface index to the corresponding link name 930 * @arg cache link cache 931 * @arg ifindex link interface index 932 * @arg dst destination buffer 933 * @arg len length of destination buffer 934 * 935 * Translates the specified interface index to the corresponding 936 * link name and stores the name in the destination buffer. 937 * 938 * @return link name or NULL if no match was found. 939 */ 940char * rtnl_link_i2name(struct nl_cache *cache, int ifindex, char *dst, 941 size_t len) 942{ 943 struct rtnl_link *link = rtnl_link_get(cache, ifindex); 944 945 if (link) { 946 strncpy(dst, link->l_name, len - 1); 947 rtnl_link_put(link); 948 return dst; 949 } 950 951 return NULL; 952} 953 954/** 955 * Translate a link name to the corresponding interface index 956 * @arg cache link cache 957 * @arg name link name 958 * 959 * @return interface index or RTNL_LINK_NOT_FOUND if no match was found. 960 */ 961int rtnl_link_name2i(struct nl_cache *cache, const char *name) 962{ 963 int ifindex = RTNL_LINK_NOT_FOUND; 964 struct rtnl_link *link; 965 966 link = rtnl_link_get_by_name(cache, name); 967 if (link) { 968 ifindex = link->l_index; 969 rtnl_link_put(link); 970 } 971 972 return ifindex; 973} 974 975/** @} */ 976 977/** 978 * @name Link Flags Translations 979 * @{ 980 */ 981 982static struct trans_tbl link_flags[] = { 983 __ADD(IFF_LOOPBACK, loopback) 984 __ADD(IFF_BROADCAST, broadcast) 985 __ADD(IFF_POINTOPOINT, pointopoint) 986 __ADD(IFF_MULTICAST, multicast) 987 __ADD(IFF_NOARP, noarp) 988 __ADD(IFF_ALLMULTI, allmulti) 989 __ADD(IFF_PROMISC, promisc) 990 __ADD(IFF_MASTER, master) 991 __ADD(IFF_SLAVE, slave) 992 __ADD(IFF_DEBUG, debug) 993 __ADD(IFF_DYNAMIC, dynamic) 994 __ADD(IFF_AUTOMEDIA, automedia) 995 __ADD(IFF_PORTSEL, portsel) 996 __ADD(IFF_NOTRAILERS, notrailers) 997 __ADD(IFF_UP, up) 998 __ADD(IFF_RUNNING, running) 999 __ADD(IFF_LOWER_UP, lowerup) 1000 __ADD(IFF_DORMANT, dormant) 1001}; 1002 1003char * rtnl_link_flags2str(int flags, char *buf, size_t len) 1004{ 1005 return __flags2str(flags, buf, len, link_flags, 1006 ARRAY_SIZE(link_flags)); 1007} 1008 1009int rtnl_link_str2flags(const char *name) 1010{ 1011 return __str2flags(name, link_flags, ARRAY_SIZE(link_flags)); 1012} 1013 1014/** @} */ 1015 1016/** 1017 * @name Link Statistics Translations 1018 * @{ 1019 */ 1020 1021static struct trans_tbl link_stats[] = { 1022 __ADD(RTNL_LINK_RX_PACKETS, rx_packets) 1023 __ADD(RTNL_LINK_TX_PACKETS, tx_packets) 1024 __ADD(RTNL_LINK_RX_BYTES, rx_bytes) 1025 __ADD(RTNL_LINK_TX_BYTES, tx_bytes) 1026 __ADD(RTNL_LINK_RX_ERRORS, rx_errors) 1027 __ADD(RTNL_LINK_TX_ERRORS, tx_errors) 1028 __ADD(RTNL_LINK_RX_DROPPED, rx_dropped) 1029 __ADD(RTNL_LINK_TX_DROPPED, tx_dropped) 1030 __ADD(RTNL_LINK_RX_COMPRESSED, rx_compressed) 1031 __ADD(RTNL_LINK_TX_COMPRESSED, tx_compressed) 1032 __ADD(RTNL_LINK_RX_FIFO_ERR, rx_fifo_err) 1033 __ADD(RTNL_LINK_TX_FIFO_ERR, tx_fifo_err) 1034 __ADD(RTNL_LINK_RX_LEN_ERR, rx_len_err) 1035 __ADD(RTNL_LINK_RX_OVER_ERR, rx_over_err) 1036 __ADD(RTNL_LINK_RX_CRC_ERR, rx_crc_err) 1037 __ADD(RTNL_LINK_RX_FRAME_ERR, rx_frame_err) 1038 __ADD(RTNL_LINK_RX_MISSED_ERR, rx_missed_err) 1039 __ADD(RTNL_LINK_TX_ABORT_ERR, tx_abort_err) 1040 __ADD(RTNL_LINK_TX_CARRIER_ERR, tx_carrier_err) 1041 __ADD(RTNL_LINK_TX_HBEAT_ERR, tx_hbeat_err) 1042 __ADD(RTNL_LINK_TX_WIN_ERR, tx_win_err) 1043 __ADD(RTNL_LINK_TX_COLLISIONS, tx_collision) 1044 __ADD(RTNL_LINK_MULTICAST, multicast) 1045}; 1046 1047char *rtnl_link_stat2str(int st, char *buf, size_t len) 1048{ 1049 return __type2str(st, buf, len, link_stats, ARRAY_SIZE(link_stats)); 1050} 1051 1052int rtnl_link_str2stat(const char *name) 1053{ 1054 return __str2type(name, link_stats, ARRAY_SIZE(link_stats)); 1055} 1056 1057/** @} */ 1058 1059/** 1060 * @name Attributes 1061 * @{ 1062 */ 1063 1064void rtnl_link_set_qdisc(struct rtnl_link *link, const char *qdisc) 1065{ 1066 strncpy(link->l_qdisc, qdisc, sizeof(link->l_qdisc) - 1); 1067 link->ce_mask |= LINK_ATTR_QDISC; 1068} 1069 1070char *rtnl_link_get_qdisc(struct rtnl_link *link) 1071{ 1072 if (link->ce_mask & LINK_ATTR_QDISC) 1073 return link->l_qdisc; 1074 else 1075 return NULL; 1076} 1077 1078void rtnl_link_set_name(struct rtnl_link *link, const char *name) 1079{ 1080 strncpy(link->l_name, name, sizeof(link->l_name) - 1); 1081 link->ce_mask |= LINK_ATTR_IFNAME; 1082} 1083 1084char *rtnl_link_get_name(struct rtnl_link *link) 1085{ 1086 if (link->ce_mask & LINK_ATTR_IFNAME) 1087 return link->l_name; 1088 else 1089 return NULL; 1090} 1091 1092static inline void __assign_addr(struct rtnl_link *link, struct nl_addr **pos, 1093 struct nl_addr *new, int flag) 1094{ 1095 if (*pos) 1096 nl_addr_put(*pos); 1097 1098 nl_addr_get(new); 1099 *pos = new; 1100 1101 link->ce_mask |= flag; 1102} 1103 1104void rtnl_link_set_addr(struct rtnl_link *link, struct nl_addr *addr) 1105{ 1106 __assign_addr(link, &link->l_addr, addr, LINK_ATTR_ADDR); 1107} 1108 1109struct nl_addr *rtnl_link_get_addr(struct rtnl_link *link) 1110{ 1111 if (link->ce_mask & LINK_ATTR_ADDR) 1112 return link->l_addr; 1113 else 1114 return NULL; 1115} 1116 1117void rtnl_link_set_broadcast(struct rtnl_link *link, struct nl_addr *brd) 1118{ 1119 __assign_addr(link, &link->l_bcast, brd, LINK_ATTR_BRD); 1120} 1121 1122struct nl_addr *rtnl_link_get_broadcast(struct rtnl_link *link) 1123{ 1124 if (link->ce_mask & LINK_ATTR_BRD) 1125 return link->l_bcast; 1126 else 1127 return NULL; 1128} 1129 1130void rtnl_link_set_flags(struct rtnl_link *link, unsigned int flags) 1131{ 1132 link->l_flag_mask |= flags; 1133 link->l_flags |= flags; 1134 link->ce_mask |= LINK_ATTR_FLAGS; 1135} 1136 1137void rtnl_link_unset_flags(struct rtnl_link *link, unsigned int flags) 1138{ 1139 link->l_flag_mask |= flags; 1140 link->l_flags &= ~flags; 1141 link->ce_mask |= LINK_ATTR_FLAGS; 1142} 1143 1144unsigned int rtnl_link_get_flags(struct rtnl_link *link) 1145{ 1146 return link->l_flags; 1147} 1148 1149void rtnl_link_set_family(struct rtnl_link *link, int family) 1150{ 1151 link->l_family = family; 1152 link->ce_mask |= LINK_ATTR_FAMILY; 1153} 1154 1155int rtnl_link_get_family(struct rtnl_link *link) 1156{ 1157 if (link->l_family & LINK_ATTR_FAMILY) 1158 return link->l_family; 1159 else 1160 return AF_UNSPEC; 1161} 1162 1163void rtnl_link_set_arptype(struct rtnl_link *link, unsigned int arptype) 1164{ 1165 link->l_arptype = arptype; 1166} 1167 1168unsigned int rtnl_link_get_arptype(struct rtnl_link *link) 1169{ 1170 return link->l_arptype; 1171} 1172 1173void rtnl_link_set_ifindex(struct rtnl_link *link, int ifindex) 1174{ 1175 link->l_index = ifindex; 1176 link->ce_mask |= LINK_ATTR_IFINDEX; 1177} 1178 1179int rtnl_link_get_ifindex(struct rtnl_link *link) 1180{ 1181 if (link->ce_mask & LINK_ATTR_IFINDEX) 1182 return link->l_index; 1183 else 1184 return RTNL_LINK_NOT_FOUND; 1185} 1186 1187void rtnl_link_set_mtu(struct rtnl_link *link, unsigned int mtu) 1188{ 1189 link->l_mtu = mtu; 1190 link->ce_mask |= LINK_ATTR_MTU; 1191} 1192 1193unsigned int rtnl_link_get_mtu(struct rtnl_link *link) 1194{ 1195 if (link->ce_mask & LINK_ATTR_MTU) 1196 return link->l_mtu; 1197 else 1198 return 0; 1199} 1200 1201void rtnl_link_set_txqlen(struct rtnl_link *link, unsigned int txqlen) 1202{ 1203 link->l_txqlen = txqlen; 1204 link->ce_mask |= LINK_ATTR_TXQLEN; 1205} 1206 1207unsigned int rtnl_link_get_txqlen(struct rtnl_link *link) 1208{ 1209 if (link->ce_mask & LINK_ATTR_TXQLEN) 1210 return link->l_txqlen; 1211 else 1212 return UINT_MAX; 1213} 1214 1215void rtnl_link_set_weight(struct rtnl_link *link, unsigned int weight) 1216{ 1217 link->l_weight = weight; 1218 link->ce_mask |= LINK_ATTR_WEIGHT; 1219} 1220 1221unsigned int rtnl_link_get_weight(struct rtnl_link *link) 1222{ 1223 if (link->ce_mask & LINK_ATTR_WEIGHT) 1224 return link->l_weight; 1225 else 1226 return UINT_MAX; 1227} 1228 1229void rtnl_link_set_link(struct rtnl_link *link, int ifindex) 1230{ 1231 link->l_link = ifindex; 1232 link->ce_mask |= LINK_ATTR_LINK; 1233} 1234 1235int rtnl_link_get_link(struct rtnl_link *link) 1236{ 1237 if (link->ce_mask & LINK_ATTR_LINK) 1238 return link->l_link; 1239 else 1240 return RTNL_LINK_NOT_FOUND; 1241} 1242 1243void rtnl_link_set_master(struct rtnl_link *link, int ifindex) 1244{ 1245 link->l_master = ifindex; 1246 link->ce_mask |= LINK_ATTR_MASTER; 1247} 1248 1249int rtnl_link_get_master(struct rtnl_link *link) 1250{ 1251 if (link->ce_mask & LINK_ATTR_MASTER) 1252 return link->l_master; 1253 else 1254 return RTNL_LINK_NOT_FOUND; 1255} 1256 1257uint64_t rtnl_link_get_stat(struct rtnl_link *link, int id) 1258{ 1259 if (id < 0 || id > RTNL_LINK_STATS_MAX) 1260 return 0; 1261 1262 return link->l_stats[id]; 1263} 1264 1265/** @} */ 1266 1267static struct nl_object_ops link_obj_ops = { 1268 .oo_name = "route/link", 1269 .oo_size = sizeof(struct rtnl_link), 1270 .oo_free_data = link_free_data, 1271 .oo_clone = link_clone, 1272 .oo_dump[NL_DUMP_BRIEF] = link_dump_brief, 1273 .oo_dump[NL_DUMP_FULL] = link_dump_full, 1274 .oo_dump[NL_DUMP_STATS] = link_dump_stats, 1275 .oo_dump[NL_DUMP_XML] = link_dump_xml, 1276 .oo_dump[NL_DUMP_ENV] = link_dump_env, 1277 .oo_compare = link_compare, 1278 .oo_attrs2str = link_attrs2str, 1279 .oo_id_attrs = LINK_ATTR_IFINDEX, 1280}; 1281 1282static struct nl_af_group link_groups[] = { 1283 { AF_UNSPEC, RTNLGRP_LINK }, 1284 { END_OF_GROUP_LIST }, 1285}; 1286 1287static struct nl_cache_ops rtnl_link_ops = { 1288 .co_name = "route/link", 1289 .co_hdrsize = sizeof(struct ifinfomsg), 1290 .co_msgtypes = { 1291 { RTM_NEWLINK, NL_ACT_NEW, "new" }, 1292 { RTM_DELLINK, NL_ACT_DEL, "del" }, 1293 { RTM_GETLINK, NL_ACT_GET, "get" }, 1294 END_OF_MSGTYPES_LIST, 1295 }, 1296 .co_protocol = NETLINK_ROUTE, 1297 .co_groups = link_groups, 1298 .co_request_update = link_request_update, 1299 .co_msg_parser = link_msg_parser, 1300 .co_obj_ops = &link_obj_ops, 1301}; 1302 1303static void __init link_init(void) 1304{ 1305 nl_cache_mngt_register(&rtnl_link_ops); 1306} 1307 1308static void __exit link_exit(void) 1309{ 1310 nl_cache_mngt_unregister(&rtnl_link_ops); 1311} 1312 1313/** @} */ 1314