link.c revision a7469ce758fac3631df6ce72eb3f89150070e7f8
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 * @par 3) Link Type Specific Attributes 128 * @code 129 * // Some link types offer additional parameters and statistics specific 130 * // to their type. F.e. a VLAN link can be configured like this: 131 * // 132 * // Allocate a new link and set the info type to "vlan". This is required 133 * // to prepare the link to hold vlan specific attributes. 134 * struct rtnl_link *request = rtnl_link_alloc(); 135 * rtnl_link_set_info_type(request, "vlan"); 136 * 137 * // Now vlan specific attributes can be set: 138 * rtnl_link_vlan_set_id(request, 10); 139 * rtnl_link_vlan_set_ingress_map(request, 2, 8); 140 * 141 * // Of course the attributes can also be read, check the info type 142 * // to make sure you are using the right access functions: 143 * char *type = rtnl_link_get_info_type(link); 144 * if (!strcmp(type, "vlan")) 145 * int id = rtnl_link_vlan_get_id(link); 146 * @endcode 147 * @{ 148 */ 149 150#include <netlink-local.h> 151#include <netlink/netlink.h> 152#include <netlink/attr.h> 153#include <netlink/utils.h> 154#include <netlink/object.h> 155#include <netlink/route/rtnl.h> 156#include <netlink/route/link.h> 157#include <netlink/route/link/info-api.h> 158 159/** @cond SKIP */ 160#define LINK_ATTR_MTU 0x0001 161#define LINK_ATTR_LINK 0x0002 162#define LINK_ATTR_TXQLEN 0x0004 163#define LINK_ATTR_WEIGHT 0x0008 164#define LINK_ATTR_MASTER 0x0010 165#define LINK_ATTR_QDISC 0x0020 166#define LINK_ATTR_MAP 0x0040 167#define LINK_ATTR_ADDR 0x0080 168#define LINK_ATTR_BRD 0x0100 169#define LINK_ATTR_FLAGS 0x0200 170#define LINK_ATTR_IFNAME 0x0400 171#define LINK_ATTR_IFINDEX 0x0800 172#define LINK_ATTR_FAMILY 0x1000 173#define LINK_ATTR_ARPTYPE 0x2000 174#define LINK_ATTR_STATS 0x4000 175#define LINK_ATTR_CHANGE 0x8000 176#define LINK_ATTR_OPERSTATE 0x10000 177#define LINK_ATTR_LINKMODE 0x20000 178#define LINK_ATTR_LINKINFO 0x40000 179 180static struct nl_cache_ops rtnl_link_ops; 181static struct nl_object_ops link_obj_ops; 182/** @endcond */ 183 184static void release_link_info(struct rtnl_link *link) 185{ 186 struct rtnl_link_info_ops *io = link->l_info_ops; 187 188 if (io != NULL) { 189 io->io_refcnt--; 190 io->io_free(link); 191 link->l_info_ops = NULL; 192 } 193} 194 195static void link_free_data(struct nl_object *c) 196{ 197 struct rtnl_link *link = nl_object_priv(c); 198 199 if (link) { 200 struct rtnl_link_info_ops *io; 201 202 if ((io = link->l_info_ops) != NULL) 203 release_link_info(link); 204 205 nl_addr_put(link->l_addr); 206 nl_addr_put(link->l_bcast); 207 } 208} 209 210static int link_clone(struct nl_object *_dst, struct nl_object *_src) 211{ 212 struct rtnl_link *dst = nl_object_priv(_dst); 213 struct rtnl_link *src = nl_object_priv(_src); 214 int err; 215 216 if (src->l_addr) 217 if (!(dst->l_addr = nl_addr_clone(src->l_addr))) 218 goto errout; 219 220 if (src->l_bcast) 221 if (!(dst->l_bcast = nl_addr_clone(src->l_bcast))) 222 goto errout; 223 224 if (src->l_info_ops && src->l_info_ops->io_clone) { 225 err = src->l_info_ops->io_clone(dst, src); 226 if (err < 0) 227 goto errout; 228 } 229 230 return 0; 231errout: 232 return nl_get_errno(); 233} 234 235static struct nla_policy link_policy[IFLA_MAX+1] = { 236 [IFLA_IFNAME] = { .type = NLA_STRING, 237 .maxlen = IFNAMSIZ }, 238 [IFLA_MTU] = { .type = NLA_U32 }, 239 [IFLA_TXQLEN] = { .type = NLA_U32 }, 240 [IFLA_LINK] = { .type = NLA_U32 }, 241 [IFLA_WEIGHT] = { .type = NLA_U32 }, 242 [IFLA_MASTER] = { .type = NLA_U32 }, 243 [IFLA_OPERSTATE]= { .type = NLA_U8 }, 244 [IFLA_LINKMODE] = { .type = NLA_U8 }, 245 [IFLA_LINKINFO] = { .type = NLA_NESTED }, 246 [IFLA_QDISC] = { .type = NLA_STRING, 247 .maxlen = IFQDISCSIZ }, 248 [IFLA_STATS] = { .minlen = sizeof(struct rtnl_link_stats) }, 249 [IFLA_MAP] = { .minlen = sizeof(struct rtnl_link_ifmap) }, 250}; 251 252static struct nla_policy link_info_policy[IFLA_INFO_MAX+1] = { 253 [IFLA_INFO_KIND] = { .type = NLA_STRING }, 254 [IFLA_INFO_DATA] = { .type = NLA_NESTED }, 255 [IFLA_INFO_XSTATS] = { .type = NLA_NESTED }, 256}; 257 258static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, 259 struct nlmsghdr *n, struct nl_parser_param *pp) 260{ 261 struct rtnl_link *link; 262 struct ifinfomsg *ifi; 263 struct nlattr *tb[IFLA_MAX+1]; 264 int err; 265 266 link = rtnl_link_alloc(); 267 if (link == NULL) { 268 err = nl_errno(ENOMEM); 269 goto errout; 270 } 271 272 link->ce_msgtype = n->nlmsg_type; 273 274 err = nlmsg_parse(n, sizeof(*ifi), tb, IFLA_MAX, link_policy); 275 if (err < 0) 276 goto errout; 277 278 if (tb[IFLA_IFNAME] == NULL) { 279 err = nl_error(EINVAL, "Missing link name TLV"); 280 goto errout; 281 } 282 283 nla_strlcpy(link->l_name, tb[IFLA_IFNAME], IFNAMSIZ); 284 285 ifi = nlmsg_data(n); 286 link->l_family = ifi->ifi_family; 287 link->l_arptype = ifi->ifi_type; 288 link->l_index = ifi->ifi_index; 289 link->l_flags = ifi->ifi_flags; 290 link->l_change = ifi->ifi_change; 291 link->ce_mask = (LINK_ATTR_IFNAME | LINK_ATTR_FAMILY | 292 LINK_ATTR_ARPTYPE| LINK_ATTR_IFINDEX | 293 LINK_ATTR_FLAGS | LINK_ATTR_CHANGE); 294 295 if (tb[IFLA_STATS]) { 296 struct rtnl_link_stats *st = nla_data(tb[IFLA_STATS]); 297 298 link->l_stats[RTNL_LINK_RX_PACKETS] = st->rx_packets; 299 link->l_stats[RTNL_LINK_RX_BYTES] = st->rx_bytes; 300 link->l_stats[RTNL_LINK_RX_ERRORS] = st->rx_errors; 301 link->l_stats[RTNL_LINK_RX_DROPPED] = st->rx_dropped; 302 link->l_stats[RTNL_LINK_RX_COMPRESSED] = st->rx_compressed; 303 link->l_stats[RTNL_LINK_RX_FIFO_ERR] = st->rx_fifo_errors; 304 link->l_stats[RTNL_LINK_TX_PACKETS] = st->tx_packets; 305 link->l_stats[RTNL_LINK_TX_BYTES] = st->tx_bytes; 306 link->l_stats[RTNL_LINK_TX_ERRORS] = st->tx_errors; 307 link->l_stats[RTNL_LINK_TX_DROPPED] = st->tx_dropped; 308 link->l_stats[RTNL_LINK_TX_COMPRESSED] = st->tx_compressed; 309 link->l_stats[RTNL_LINK_TX_FIFO_ERR] = st->tx_fifo_errors; 310 link->l_stats[RTNL_LINK_RX_LEN_ERR] = st->rx_length_errors; 311 link->l_stats[RTNL_LINK_RX_OVER_ERR] = st->rx_over_errors; 312 link->l_stats[RTNL_LINK_RX_CRC_ERR] = st->rx_crc_errors; 313 link->l_stats[RTNL_LINK_RX_FRAME_ERR] = st->rx_frame_errors; 314 link->l_stats[RTNL_LINK_RX_MISSED_ERR] = st->rx_missed_errors; 315 link->l_stats[RTNL_LINK_TX_ABORT_ERR] = st->tx_aborted_errors; 316 link->l_stats[RTNL_LINK_TX_CARRIER_ERR] = st->tx_carrier_errors; 317 link->l_stats[RTNL_LINK_TX_HBEAT_ERR] = st->tx_heartbeat_errors; 318 link->l_stats[RTNL_LINK_TX_WIN_ERR] = st->tx_window_errors; 319 link->l_stats[RTNL_LINK_MULTICAST] = st->multicast; 320 321 link->ce_mask |= LINK_ATTR_STATS; 322 } 323 324 if (tb[IFLA_TXQLEN]) { 325 link->l_txqlen = nla_get_u32(tb[IFLA_TXQLEN]); 326 link->ce_mask |= LINK_ATTR_TXQLEN; 327 } 328 329 if (tb[IFLA_MTU]) { 330 link->l_mtu = nla_get_u32(tb[IFLA_MTU]); 331 link->ce_mask |= LINK_ATTR_MTU; 332 } 333 334 if (tb[IFLA_ADDRESS]) { 335 link->l_addr = nla_get_addr(tb[IFLA_ADDRESS], AF_UNSPEC); 336 if (link->l_addr == NULL) 337 goto errout; 338 nl_addr_set_family(link->l_addr, 339 nl_addr_guess_family(link->l_addr)); 340 link->ce_mask |= LINK_ATTR_ADDR; 341 } 342 343 if (tb[IFLA_BROADCAST]) { 344 link->l_bcast = nla_get_addr(tb[IFLA_BROADCAST], AF_UNSPEC); 345 if (link->l_bcast == NULL) 346 goto errout; 347 nl_addr_set_family(link->l_bcast, 348 nl_addr_guess_family(link->l_bcast)); 349 link->ce_mask |= LINK_ATTR_BRD; 350 } 351 352 if (tb[IFLA_LINK]) { 353 link->l_link = nla_get_u32(tb[IFLA_LINK]); 354 link->ce_mask |= LINK_ATTR_LINK; 355 } 356 357 if (tb[IFLA_WEIGHT]) { 358 link->l_weight = nla_get_u32(tb[IFLA_WEIGHT]); 359 link->ce_mask |= LINK_ATTR_WEIGHT; 360 } 361 362 if (tb[IFLA_QDISC]) { 363 nla_strlcpy(link->l_qdisc, tb[IFLA_QDISC], IFQDISCSIZ); 364 link->ce_mask |= LINK_ATTR_QDISC; 365 } 366 367 if (tb[IFLA_MAP]) { 368 struct rtnl_link_ifmap *map = nla_data(tb[IFLA_MAP]); 369 link->l_map.lm_mem_start = map->mem_start; 370 link->l_map.lm_mem_end = map->mem_end; 371 link->l_map.lm_base_addr = map->base_addr; 372 link->l_map.lm_irq = map->irq; 373 link->l_map.lm_dma = map->dma; 374 link->l_map.lm_port = map->port; 375 link->ce_mask |= LINK_ATTR_MAP; 376 } 377 378 if (tb[IFLA_MASTER]) { 379 link->l_master = nla_get_u32(tb[IFLA_MASTER]); 380 link->ce_mask |= LINK_ATTR_MASTER; 381 } 382 383 if (tb[IFLA_OPERSTATE]) { 384 link->l_operstate = nla_get_u8(tb[IFLA_OPERSTATE]); 385 link->ce_mask |= LINK_ATTR_OPERSTATE; 386 } 387 388 if (tb[IFLA_LINKMODE]) { 389 link->l_linkmode = nla_get_u8(tb[IFLA_LINKMODE]); 390 link->ce_mask |= LINK_ATTR_LINKMODE; 391 } 392 393 if (tb[IFLA_LINKINFO]) { 394 struct nlattr *li[IFLA_INFO_MAX+1]; 395 396 err = nla_parse_nested(li, IFLA_INFO_MAX, tb[IFLA_LINKINFO], 397 link_info_policy); 398 if (err < 0) 399 goto errout; 400 401 if (li[IFLA_INFO_KIND] && 402 (li[IFLA_INFO_DATA] || li[IFLA_INFO_XSTATS])) { 403 struct rtnl_link_info_ops *ops; 404 char *kind; 405 406 kind = nla_get_string(li[IFLA_INFO_KIND]); 407 ops = rtnl_link_info_ops_lookup(kind); 408 if (ops != NULL) { 409 ops->io_refcnt++; 410 link->l_info_ops = ops; 411 err = ops->io_parse(link, li[IFLA_INFO_DATA], 412 li[IFLA_INFO_XSTATS]); 413 if (err < 0) 414 goto errout; 415 } else { 416 /* XXX: Warn about unparsed info? */ 417 } 418 } 419 } 420 421 err = pp->pp_cb((struct nl_object *) link, pp); 422 if (err < 0) 423 goto errout; 424 425 err = P_ACCEPT; 426 427errout: 428 rtnl_link_put(link); 429 return err; 430} 431 432static int link_request_update(struct nl_cache *c, struct nl_handle *h) 433{ 434 return nl_rtgen_request(h, RTM_GETLINK, AF_UNSPEC, NLM_F_DUMP); 435} 436 437static int link_dump_brief(struct nl_object *obj, struct nl_dump_params *p) 438{ 439 char buf[128]; 440 struct nl_cache *cache = dp_cache(obj); 441 struct rtnl_link *link = (struct rtnl_link *) obj; 442 int line = 1; 443 444 dp_dump(p, "%s %s ", link->l_name, 445 nl_llproto2str(link->l_arptype, buf, sizeof(buf))); 446 447 if (link->l_addr && !nl_addr_iszero(link->l_addr)) 448 dp_dump(p, "%s ", nl_addr2str(link->l_addr, buf, sizeof(buf))); 449 450 if (link->ce_mask & LINK_ATTR_MASTER) { 451 struct rtnl_link *master = rtnl_link_get(cache, link->l_master); 452 dp_dump(p, "master %s ", master ? master->l_name : "inv"); 453 if (master) 454 rtnl_link_put(master); 455 } 456 457 rtnl_link_flags2str(link->l_flags, buf, sizeof(buf)); 458 if (buf[0]) 459 dp_dump(p, "<%s> ", buf); 460 461 if (link->ce_mask & LINK_ATTR_LINK) { 462 struct rtnl_link *ll = rtnl_link_get(cache, link->l_link); 463 dp_dump(p, "slave-of %s ", ll ? ll->l_name : "NONE"); 464 if (ll) 465 rtnl_link_put(ll); 466 } 467 468 if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_BRIEF]) 469 line = link->l_info_ops->io_dump[NL_DUMP_BRIEF](link, p, line); 470 471 dp_dump(p, "\n"); 472 473 return line; 474} 475 476static int link_dump_full(struct nl_object *obj, struct nl_dump_params *p) 477{ 478 struct rtnl_link *link = (struct rtnl_link *) obj; 479 char buf[64]; 480 int line; 481 482 line = link_dump_brief(obj, p); 483 dp_new_line(p, line++); 484 485 dp_dump(p, " mtu %u ", link->l_mtu); 486 dp_dump(p, "txqlen %u weight %u ", link->l_txqlen, link->l_weight); 487 488 if (link->ce_mask & LINK_ATTR_QDISC) 489 dp_dump(p, "qdisc %s ", link->l_qdisc); 490 491 if (link->ce_mask & LINK_ATTR_MAP && link->l_map.lm_irq) 492 dp_dump(p, "irq %u ", link->l_map.lm_irq); 493 494 if (link->ce_mask & LINK_ATTR_IFINDEX) 495 dp_dump(p, "index %u ", link->l_index); 496 497 498 dp_dump(p, "\n"); 499 dp_new_line(p, line++); 500 501 dp_dump(p, " "); 502 503 if (link->ce_mask & LINK_ATTR_BRD) 504 dp_dump(p, "brd %s ", nl_addr2str(link->l_bcast, buf, 505 sizeof(buf))); 506 507 if ((link->ce_mask & LINK_ATTR_OPERSTATE) && 508 link->l_operstate != IF_OPER_UNKNOWN) { 509 rtnl_link_operstate2str(link->l_operstate, buf, sizeof(buf)); 510 dp_dump(p, "state %s ", buf); 511 } 512 513 dp_dump(p, "mode %s\n", 514 rtnl_link_mode2str(link->l_linkmode, buf, sizeof(buf))); 515 516 if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_FULL]) 517 line = link->l_info_ops->io_dump[NL_DUMP_FULL](link, p, line); 518 519 return line; 520} 521 522static int link_dump_stats(struct nl_object *obj, struct nl_dump_params *p) 523{ 524 struct rtnl_link *link = (struct rtnl_link *) obj; 525 char *unit, fmt[64]; 526 float res; 527 int line; 528 529 line = link_dump_full(obj, p); 530 531 dp_dump_line(p, line++, " Stats: bytes packets errors " 532 " dropped fifo-err compressed\n"); 533 534 res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_RX_BYTES], &unit); 535 536 strcpy(fmt, " RX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n"); 537 fmt[9] = *unit == 'B' ? '9' : '7'; 538 539 dp_dump_line(p, line++, fmt, 540 res, unit, 541 link->l_stats[RTNL_LINK_RX_PACKETS], 542 link->l_stats[RTNL_LINK_RX_ERRORS], 543 link->l_stats[RTNL_LINK_RX_DROPPED], 544 link->l_stats[RTNL_LINK_RX_FIFO_ERR], 545 link->l_stats[RTNL_LINK_RX_COMPRESSED]); 546 547 res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_TX_BYTES], &unit); 548 549 strcpy(fmt, " TX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n"); 550 fmt[9] = *unit == 'B' ? '9' : '7'; 551 552 dp_dump_line(p, line++, fmt, 553 res, unit, 554 link->l_stats[RTNL_LINK_TX_PACKETS], 555 link->l_stats[RTNL_LINK_TX_ERRORS], 556 link->l_stats[RTNL_LINK_TX_DROPPED], 557 link->l_stats[RTNL_LINK_TX_FIFO_ERR], 558 link->l_stats[RTNL_LINK_TX_COMPRESSED]); 559 560 dp_dump_line(p, line++, " Errors: length over crc " 561 " frame missed multicast\n"); 562 563 dp_dump_line(p, line++, " RX %10" PRIu64 " %10" PRIu64 " %10" 564 PRIu64 " %10" PRIu64 " %10" PRIu64 " %10" 565 PRIu64 "\n", 566 link->l_stats[RTNL_LINK_RX_LEN_ERR], 567 link->l_stats[RTNL_LINK_RX_OVER_ERR], 568 link->l_stats[RTNL_LINK_RX_CRC_ERR], 569 link->l_stats[RTNL_LINK_RX_FRAME_ERR], 570 link->l_stats[RTNL_LINK_RX_MISSED_ERR], 571 link->l_stats[RTNL_LINK_MULTICAST]); 572 573 dp_dump_line(p, line++, " Errors: aborted carrier heartbeat " 574 " window collision\n"); 575 576 dp_dump_line(p, line++, " TX %10" PRIu64 " %10" PRIu64 " %10" 577 PRIu64 " %10" PRIu64 " %10" PRIu64 "\n", 578 link->l_stats[RTNL_LINK_TX_ABORT_ERR], 579 link->l_stats[RTNL_LINK_TX_CARRIER_ERR], 580 link->l_stats[RTNL_LINK_TX_HBEAT_ERR], 581 link->l_stats[RTNL_LINK_TX_WIN_ERR], 582 link->l_stats[RTNL_LINK_TX_COLLISIONS]); 583 584 if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_STATS]) 585 line = link->l_info_ops->io_dump[NL_DUMP_STATS](link, p, line); 586 587 return line; 588} 589 590static int link_dump_xml(struct nl_object *obj, struct nl_dump_params *p) 591{ 592 struct rtnl_link *link = (struct rtnl_link *) obj; 593 struct nl_cache *cache = dp_cache(obj); 594 char buf[128]; 595 int i, line = 0; 596 597 dp_dump_line(p, line++, "<link name=\"%s\" index=\"%u\">\n", 598 link->l_name, link->l_index); 599 dp_dump_line(p, line++, " <family>%s</family>\n", 600 nl_af2str(link->l_family, buf, sizeof(buf))); 601 dp_dump_line(p, line++, " <arptype>%s</arptype>\n", 602 nl_llproto2str(link->l_arptype, buf, sizeof(buf))); 603 dp_dump_line(p, line++, " <address>%s</address>\n", 604 nl_addr2str(link->l_addr, buf, sizeof(buf))); 605 dp_dump_line(p, line++, " <mtu>%u</mtu>\n", link->l_mtu); 606 dp_dump_line(p, line++, " <txqlen>%u</txqlen>\n", link->l_txqlen); 607 dp_dump_line(p, line++, " <weight>%u</weight>\n", link->l_weight); 608 609 rtnl_link_flags2str(link->l_flags, buf, sizeof(buf)); 610 if (buf[0]) 611 dp_dump_line(p, line++, " <flags>%s</flags>\n", buf); 612 613 if (link->ce_mask & LINK_ATTR_QDISC) 614 dp_dump_line(p, line++, " <qdisc>%s</qdisc>\n", link->l_qdisc); 615 616 if (link->ce_mask & LINK_ATTR_LINK) { 617 struct rtnl_link *ll = rtnl_link_get(cache, link->l_link); 618 dp_dump_line(p, line++, " <link>%s</link>\n", 619 ll ? ll->l_name : "none"); 620 if (ll) 621 rtnl_link_put(ll); 622 } 623 624 if (link->ce_mask & LINK_ATTR_MASTER) { 625 struct rtnl_link *master = rtnl_link_get(cache, link->l_master); 626 dp_dump_line(p, line++, " <master>%s</master>\n", 627 master ? master->l_name : "none"); 628 if (master) 629 rtnl_link_put(master); 630 } 631 632 if (link->ce_mask & LINK_ATTR_BRD) 633 dp_dump_line(p, line++, " <broadcast>%s</broadcast>\n", 634 nl_addr2str(link->l_bcast, buf, sizeof(buf))); 635 636 if (link->ce_mask & LINK_ATTR_STATS) { 637 dp_dump_line(p, line++, " <stats>\n"); 638 for (i = 0; i <= RTNL_LINK_STATS_MAX; i++) { 639 rtnl_link_stat2str(i, buf, sizeof(buf)); 640 dp_dump_line(p, line++, 641 " <%s>%" PRIu64 "</%s>\n", 642 buf, link->l_stats[i], buf); 643 } 644 dp_dump_line(p, line++, " </stats>\n"); 645 } 646 647 if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_XML]) { 648 dp_dump_line(p, line++, " <info>\n"); 649 line = link->l_info_ops->io_dump[NL_DUMP_XML](link, p, line); 650 dp_dump_line(p, line++, " </info>\n"); 651 } 652 653 dp_dump_line(p, line++, "</link>\n"); 654 655#if 0 656 uint32_t l_change; /**< Change mask */ 657 struct rtnl_lifmap l_map; /**< Interface device mapping */ 658#endif 659 660 return line; 661} 662 663static int link_dump_env(struct nl_object *obj, struct nl_dump_params *p) 664{ 665 struct rtnl_link *link = (struct rtnl_link *) obj; 666 struct nl_cache *cache = dp_cache(obj); 667 char buf[128]; 668 int i, line = 0; 669 670 dp_dump_line(p, line++, "LINK_NAME=%s\n", link->l_name); 671 dp_dump_line(p, line++, "LINK_IFINDEX=%u\n", link->l_index); 672 dp_dump_line(p, line++, "LINK_FAMILY=%s\n", 673 nl_af2str(link->l_family, buf, sizeof(buf))); 674 dp_dump_line(p, line++, "LINK_TYPE=%s\n", 675 nl_llproto2str(link->l_arptype, buf, sizeof(buf))); 676 if (link->ce_mask & LINK_ATTR_ADDR) 677 dp_dump_line(p, line++, "LINK_ADDRESS=%s\n", 678 nl_addr2str(link->l_addr, buf, sizeof(buf))); 679 dp_dump_line(p, line++, "LINK_MTU=%u\n", link->l_mtu); 680 dp_dump_line(p, line++, "LINK_TXQUEUELEN=%u\n", link->l_txqlen); 681 dp_dump_line(p, line++, "LINK_WEIGHT=%u\n", link->l_weight); 682 683 rtnl_link_flags2str(link->l_flags & ~IFF_RUNNING, buf, sizeof(buf)); 684 if (buf[0]) 685 dp_dump_line(p, line++, "LINK_FLAGS=%s\n", buf); 686 687 if (link->ce_mask & LINK_ATTR_QDISC) 688 dp_dump_line(p, line++, "LINK_QDISC=%s\n", link->l_qdisc); 689 690 if (link->ce_mask & LINK_ATTR_LINK) { 691 struct rtnl_link *ll = rtnl_link_get(cache, link->l_link); 692 693 dp_dump_line(p, line++, "LINK_LINK_IFINDEX=%d\n", link->l_link); 694 if (ll) { 695 dp_dump_line(p, line++, "LINK_LINK_IFNAME=%s\n", 696 ll->l_name); 697 rtnl_link_put(ll); 698 } 699 } 700 701 if (link->ce_mask & LINK_ATTR_MASTER) { 702 struct rtnl_link *master = rtnl_link_get(cache, link->l_master); 703 dp_dump_line(p, line++, "LINK_MASTER=%s\n", 704 master ? master->l_name : "none"); 705 if (master) 706 rtnl_link_put(master); 707 } 708 709 if (link->ce_mask & LINK_ATTR_BRD) 710 dp_dump_line(p, line++, "LINK_BROADCAST=%s\n", 711 nl_addr2str(link->l_bcast, buf, sizeof(buf))); 712 713 if (link->ce_mask & LINK_ATTR_STATS) { 714 for (i = 0; i <= RTNL_LINK_STATS_MAX; i++) { 715 char *c = buf; 716 717 sprintf(buf, "LINK_"); 718 rtnl_link_stat2str(i, buf + 5, sizeof(buf) - 5); 719 while (*c) { 720 *c = toupper(*c); 721 c++; 722 } 723 dp_dump_line(p, line++, 724 "%s=%" PRIu64 "\n", buf, link->l_stats[i]); 725 } 726 } 727 728 if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_ENV]) 729 line = link->l_info_ops->io_dump[NL_DUMP_ENV](link, p, line); 730 731 return line; 732} 733 734#if 0 735static int link_handle_event(struct nl_object *a, struct rtnl_link_event_cb *cb) 736{ 737 struct rtnl_link *l = (struct rtnl_link *) a; 738 struct nl_cache *c = dp_cache(a); 739 int nevents = 0; 740 741 if (l->l_change == ~0U) { 742 if (l->ce_msgtype == RTM_NEWLINK) 743 cb->le_register(l); 744 else 745 cb->le_unregister(l); 746 747 return 1; 748 } 749 750 if (l->l_change & IFF_SLAVE) { 751 if (l->l_flags & IFF_SLAVE) { 752 struct rtnl_link *m = rtnl_link_get(c, l->l_master); 753 cb->le_new_bonding(l, m); 754 if (m) 755 rtnl_link_put(m); 756 } else 757 cb->le_cancel_bonding(l); 758 } 759 760#if 0 761 if (l->l_change & IFF_UP && l->l_change & IFF_RUNNING) 762 dp_dump_line(p, line++, "link %s changed state to %s.\n", 763 l->l_name, l->l_flags & IFF_UP ? "up" : "down"); 764 765 if (l->l_change & IFF_PROMISC) { 766 dp_new_line(p, line++); 767 dp_dump(p, "link %s %s promiscuous mode.\n", 768 l->l_name, l->l_flags & IFF_PROMISC ? "entered" : "left"); 769 } 770 771 if (line == 0) 772 dp_dump_line(p, line++, "link %s sent unknown event.\n", 773 l->l_name); 774#endif 775 776 return nevents; 777} 778#endif 779 780static int link_compare(struct nl_object *_a, struct nl_object *_b, 781 uint32_t attrs, int flags) 782{ 783 struct rtnl_link *a = (struct rtnl_link *) _a; 784 struct rtnl_link *b = (struct rtnl_link *) _b; 785 int diff = 0; 786 787#define LINK_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, LINK_ATTR_##ATTR, a, b, EXPR) 788 789 diff |= LINK_DIFF(IFINDEX, a->l_index != b->l_index); 790 diff |= LINK_DIFF(MTU, a->l_mtu != b->l_mtu); 791 diff |= LINK_DIFF(LINK, a->l_link != b->l_link); 792 diff |= LINK_DIFF(TXQLEN, a->l_txqlen != b->l_txqlen); 793 diff |= LINK_DIFF(WEIGHT, a->l_weight != b->l_weight); 794 diff |= LINK_DIFF(MASTER, a->l_master != b->l_master); 795 diff |= LINK_DIFF(FAMILY, a->l_family != b->l_family); 796 diff |= LINK_DIFF(OPERSTATE, a->l_operstate != b->l_operstate); 797 diff |= LINK_DIFF(LINKMODE, a->l_linkmode != b->l_linkmode); 798 diff |= LINK_DIFF(QDISC, strcmp(a->l_qdisc, b->l_qdisc)); 799 diff |= LINK_DIFF(IFNAME, strcmp(a->l_name, b->l_name)); 800 diff |= LINK_DIFF(ADDR, nl_addr_cmp(a->l_addr, b->l_addr)); 801 diff |= LINK_DIFF(BRD, nl_addr_cmp(a->l_bcast, b->l_bcast)); 802 803 if (flags & LOOSE_FLAG_COMPARISON) 804 diff |= LINK_DIFF(FLAGS, 805 (a->l_flags ^ b->l_flags) & b->l_flag_mask); 806 else 807 diff |= LINK_DIFF(FLAGS, a->l_flags != b->l_flags); 808 809#undef LINK_DIFF 810 811 return diff; 812} 813 814static struct trans_tbl link_attrs[] = { 815 __ADD(LINK_ATTR_MTU, mtu) 816 __ADD(LINK_ATTR_LINK, link) 817 __ADD(LINK_ATTR_TXQLEN, txqlen) 818 __ADD(LINK_ATTR_WEIGHT, weight) 819 __ADD(LINK_ATTR_MASTER, master) 820 __ADD(LINK_ATTR_QDISC, qdisc) 821 __ADD(LINK_ATTR_MAP, map) 822 __ADD(LINK_ATTR_ADDR, address) 823 __ADD(LINK_ATTR_BRD, broadcast) 824 __ADD(LINK_ATTR_FLAGS, flags) 825 __ADD(LINK_ATTR_IFNAME, name) 826 __ADD(LINK_ATTR_IFINDEX, ifindex) 827 __ADD(LINK_ATTR_FAMILY, family) 828 __ADD(LINK_ATTR_ARPTYPE, arptype) 829 __ADD(LINK_ATTR_STATS, stats) 830 __ADD(LINK_ATTR_CHANGE, change) 831 __ADD(LINK_ATTR_OPERSTATE, operstate) 832 __ADD(LINK_ATTR_LINKMODE, linkmode) 833}; 834 835static char *link_attrs2str(int attrs, char *buf, size_t len) 836{ 837 return __flags2str(attrs, buf, len, link_attrs, 838 ARRAY_SIZE(link_attrs)); 839} 840 841/** 842 * @name Allocation/Freeing 843 * @{ 844 */ 845 846struct rtnl_link *rtnl_link_alloc(void) 847{ 848 return (struct rtnl_link *) nl_object_alloc(&link_obj_ops); 849} 850 851void rtnl_link_put(struct rtnl_link *link) 852{ 853 nl_object_put((struct nl_object *) link); 854} 855 856/** @} */ 857 858/** 859 * @name Cache Management 860 * @{ 861 */ 862 863 864/** 865 * Allocate link cache and fill in all configured links. 866 * @arg handle Netlink handle. 867 * 868 * Allocates a new link cache, initializes it properly and updates it 869 * to include all links currently configured in the kernel. 870 * 871 * @note Free the memory after usage. 872 * @return Newly allocated cache or NULL if an error occured. 873 */ 874struct nl_cache *rtnl_link_alloc_cache(struct nl_handle *handle) 875{ 876 struct nl_cache * cache; 877 878 cache = nl_cache_alloc(&rtnl_link_ops); 879 if (cache == NULL) 880 return NULL; 881 882 if (handle && nl_cache_refill(handle, cache) < 0) { 883 nl_cache_free(cache); 884 return NULL; 885 } 886 887 return cache; 888} 889 890/** 891 * Look up link by interface index in the provided cache 892 * @arg cache link cache 893 * @arg ifindex link interface index 894 * 895 * The caller owns a reference on the returned object and 896 * must give the object back via rtnl_link_put(). 897 * 898 * @return pointer to link inside the cache or NULL if no match was found. 899 */ 900struct rtnl_link *rtnl_link_get(struct nl_cache *cache, int ifindex) 901{ 902 struct rtnl_link *link; 903 904 if (cache->c_ops != &rtnl_link_ops) 905 return NULL; 906 907 nl_list_for_each_entry(link, &cache->c_items, ce_list) { 908 if (link->l_index == ifindex) { 909 nl_object_get((struct nl_object *) link); 910 return link; 911 } 912 } 913 914 return NULL; 915} 916 917/** 918 * Look up link by link name in the provided cache 919 * @arg cache link cache 920 * @arg name link name 921 * 922 * The caller owns a reference on the returned object and 923 * must give the object back via rtnl_link_put(). 924 * 925 * @return pointer to link inside the cache or NULL if no match was found. 926 */ 927struct rtnl_link *rtnl_link_get_by_name(struct nl_cache *cache, 928 const char *name) 929{ 930 struct rtnl_link *link; 931 932 if (cache->c_ops != &rtnl_link_ops) 933 return NULL; 934 935 nl_list_for_each_entry(link, &cache->c_items, ce_list) { 936 if (!strcmp(name, link->l_name)) { 937 nl_object_get((struct nl_object *) link); 938 return link; 939 } 940 } 941 942 return NULL; 943} 944 945/** @} */ 946 947/** 948 * @name Link Modifications 949 * @{ 950 */ 951 952/** 953 * Builds a netlink change request message to change link attributes 954 * @arg old link to be changed 955 * @arg tmpl template with requested changes 956 * @arg flags additional netlink message flags 957 * 958 * Builds a new netlink message requesting a change of link attributes. 959 * The netlink message header isn't fully equipped with all relevant 960 * fields and must be sent out via nl_send_auto_complete() or 961 * supplemented as needed. 962 * \a old must point to a link currently configured in the kernel 963 * and \a tmpl must contain the attributes to be changed set via 964 * \c rtnl_link_set_* functions. 965 * 966 * @return New netlink message 967 * @note Not all attributes can be changed, see 968 * \ref link_changeable "Changeable Attributes" for more details. 969 */ 970struct nl_msg * rtnl_link_build_change_request(struct rtnl_link *old, 971 struct rtnl_link *tmpl, 972 int flags) 973{ 974 struct nl_msg *msg; 975 struct ifinfomsg ifi = { 976 .ifi_family = old->l_family, 977 .ifi_index = old->l_index, 978 }; 979 980 if (tmpl->ce_mask & LINK_ATTR_FLAGS) { 981 ifi.ifi_flags = old->l_flags & ~tmpl->l_flag_mask; 982 ifi.ifi_flags |= tmpl->l_flags; 983 } 984 985 msg = nlmsg_alloc_simple(RTM_SETLINK, flags); 986 if (!msg) 987 goto nla_put_failure; 988 989 if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0) 990 goto nla_put_failure; 991 992 if (tmpl->ce_mask & LINK_ATTR_ADDR) 993 NLA_PUT_ADDR(msg, IFLA_ADDRESS, tmpl->l_addr); 994 995 if (tmpl->ce_mask & LINK_ATTR_BRD) 996 NLA_PUT_ADDR(msg, IFLA_BROADCAST, tmpl->l_bcast); 997 998 if (tmpl->ce_mask & LINK_ATTR_MTU) 999 NLA_PUT_U32(msg, IFLA_MTU, tmpl->l_mtu); 1000 1001 if (tmpl->ce_mask & LINK_ATTR_TXQLEN) 1002 NLA_PUT_U32(msg, IFLA_TXQLEN, tmpl->l_txqlen); 1003 1004 if (tmpl->ce_mask & LINK_ATTR_WEIGHT) 1005 NLA_PUT_U32(msg, IFLA_WEIGHT, tmpl->l_weight); 1006 1007 if (tmpl->ce_mask & LINK_ATTR_IFNAME) 1008 NLA_PUT_STRING(msg, IFLA_IFNAME, tmpl->l_name); 1009 1010 if (tmpl->ce_mask & LINK_ATTR_OPERSTATE) 1011 NLA_PUT_U8(msg, IFLA_OPERSTATE, tmpl->l_operstate); 1012 1013 if (tmpl->ce_mask & LINK_ATTR_LINKMODE) 1014 NLA_PUT_U8(msg, IFLA_LINKMODE, tmpl->l_linkmode); 1015 1016 if ((tmpl->ce_mask & LINK_ATTR_LINKINFO) && tmpl->l_info_ops && 1017 tmpl->l_info_ops->io_put_attrs) { 1018 struct nlattr *info; 1019 1020 if (!(info = nla_nest_start(msg, IFLA_LINKINFO))) 1021 goto nla_put_failure; 1022 1023 NLA_PUT_STRING(msg, IFLA_INFO_KIND, tmpl->l_info_ops->io_name); 1024 1025 if (tmpl->l_info_ops->io_put_attrs(msg, tmpl) < 0) 1026 goto nla_put_failure; 1027 1028 nla_nest_end(msg, info); 1029 } 1030 1031 return msg; 1032 1033nla_put_failure: 1034 nlmsg_free(msg); 1035 return NULL; 1036} 1037 1038/** 1039 * Change link attributes 1040 * @arg handle netlink handle 1041 * @arg old link to be changed 1042 * @arg tmpl template with requested changes 1043 * @arg flags additional netlink message flags 1044 * 1045 * Builds a new netlink message by calling rtnl_link_build_change_request(), 1046 * sends the request to the kernel and waits for the next ACK to be 1047 * received, i.e. blocks until the request has been processed. 1048 * 1049 * @return 0 on success or a negative error code 1050 * @note Not all attributes can be changed, see 1051 * \ref link_changeable "Changeable Attributes" for more details. 1052 */ 1053int rtnl_link_change(struct nl_handle *handle, struct rtnl_link *old, 1054 struct rtnl_link *tmpl, int flags) 1055{ 1056 int err; 1057 struct nl_msg *msg; 1058 1059 msg = rtnl_link_build_change_request(old, tmpl, flags); 1060 if (!msg) 1061 return nl_errno(ENOMEM); 1062 1063 err = nl_send_auto_complete(handle, msg); 1064 if (err < 0) 1065 return err; 1066 1067 nlmsg_free(msg); 1068 return nl_wait_for_ack(handle); 1069} 1070 1071/** @} */ 1072 1073/** 1074 * @name Name <-> Index Translations 1075 * @{ 1076 */ 1077 1078/** 1079 * Translate an interface index to the corresponding link name 1080 * @arg cache link cache 1081 * @arg ifindex link interface index 1082 * @arg dst destination buffer 1083 * @arg len length of destination buffer 1084 * 1085 * Translates the specified interface index to the corresponding 1086 * link name and stores the name in the destination buffer. 1087 * 1088 * @return link name or NULL if no match was found. 1089 */ 1090char * rtnl_link_i2name(struct nl_cache *cache, int ifindex, char *dst, 1091 size_t len) 1092{ 1093 struct rtnl_link *link = rtnl_link_get(cache, ifindex); 1094 1095 if (link) { 1096 strncpy(dst, link->l_name, len - 1); 1097 rtnl_link_put(link); 1098 return dst; 1099 } 1100 1101 return NULL; 1102} 1103 1104/** 1105 * Translate a link name to the corresponding interface index 1106 * @arg cache link cache 1107 * @arg name link name 1108 * 1109 * @return interface index or RTNL_LINK_NOT_FOUND if no match was found. 1110 */ 1111int rtnl_link_name2i(struct nl_cache *cache, const char *name) 1112{ 1113 int ifindex = RTNL_LINK_NOT_FOUND; 1114 struct rtnl_link *link; 1115 1116 link = rtnl_link_get_by_name(cache, name); 1117 if (link) { 1118 ifindex = link->l_index; 1119 rtnl_link_put(link); 1120 } 1121 1122 return ifindex; 1123} 1124 1125/** @} */ 1126 1127/** 1128 * @name Link Flags Translations 1129 * @{ 1130 */ 1131 1132static struct trans_tbl link_flags[] = { 1133 __ADD(IFF_LOOPBACK, loopback) 1134 __ADD(IFF_BROADCAST, broadcast) 1135 __ADD(IFF_POINTOPOINT, pointopoint) 1136 __ADD(IFF_MULTICAST, multicast) 1137 __ADD(IFF_NOARP, noarp) 1138 __ADD(IFF_ALLMULTI, allmulti) 1139 __ADD(IFF_PROMISC, promisc) 1140 __ADD(IFF_MASTER, master) 1141 __ADD(IFF_SLAVE, slave) 1142 __ADD(IFF_DEBUG, debug) 1143 __ADD(IFF_DYNAMIC, dynamic) 1144 __ADD(IFF_AUTOMEDIA, automedia) 1145 __ADD(IFF_PORTSEL, portsel) 1146 __ADD(IFF_NOTRAILERS, notrailers) 1147 __ADD(IFF_UP, up) 1148 __ADD(IFF_RUNNING, running) 1149 __ADD(IFF_LOWER_UP, lowerup) 1150 __ADD(IFF_DORMANT, dormant) 1151 __ADD(IFF_ECHO, echo) 1152}; 1153 1154char * rtnl_link_flags2str(int flags, char *buf, size_t len) 1155{ 1156 return __flags2str(flags, buf, len, link_flags, 1157 ARRAY_SIZE(link_flags)); 1158} 1159 1160int rtnl_link_str2flags(const char *name) 1161{ 1162 return __str2flags(name, link_flags, ARRAY_SIZE(link_flags)); 1163} 1164 1165/** @} */ 1166 1167/** 1168 * @name Link Statistics Translations 1169 * @{ 1170 */ 1171 1172static struct trans_tbl link_stats[] = { 1173 __ADD(RTNL_LINK_RX_PACKETS, rx_packets) 1174 __ADD(RTNL_LINK_TX_PACKETS, tx_packets) 1175 __ADD(RTNL_LINK_RX_BYTES, rx_bytes) 1176 __ADD(RTNL_LINK_TX_BYTES, tx_bytes) 1177 __ADD(RTNL_LINK_RX_ERRORS, rx_errors) 1178 __ADD(RTNL_LINK_TX_ERRORS, tx_errors) 1179 __ADD(RTNL_LINK_RX_DROPPED, rx_dropped) 1180 __ADD(RTNL_LINK_TX_DROPPED, tx_dropped) 1181 __ADD(RTNL_LINK_RX_COMPRESSED, rx_compressed) 1182 __ADD(RTNL_LINK_TX_COMPRESSED, tx_compressed) 1183 __ADD(RTNL_LINK_RX_FIFO_ERR, rx_fifo_err) 1184 __ADD(RTNL_LINK_TX_FIFO_ERR, tx_fifo_err) 1185 __ADD(RTNL_LINK_RX_LEN_ERR, rx_len_err) 1186 __ADD(RTNL_LINK_RX_OVER_ERR, rx_over_err) 1187 __ADD(RTNL_LINK_RX_CRC_ERR, rx_crc_err) 1188 __ADD(RTNL_LINK_RX_FRAME_ERR, rx_frame_err) 1189 __ADD(RTNL_LINK_RX_MISSED_ERR, rx_missed_err) 1190 __ADD(RTNL_LINK_TX_ABORT_ERR, tx_abort_err) 1191 __ADD(RTNL_LINK_TX_CARRIER_ERR, tx_carrier_err) 1192 __ADD(RTNL_LINK_TX_HBEAT_ERR, tx_hbeat_err) 1193 __ADD(RTNL_LINK_TX_WIN_ERR, tx_win_err) 1194 __ADD(RTNL_LINK_TX_COLLISIONS, tx_collision) 1195 __ADD(RTNL_LINK_MULTICAST, multicast) 1196}; 1197 1198char *rtnl_link_stat2str(int st, char *buf, size_t len) 1199{ 1200 return __type2str(st, buf, len, link_stats, ARRAY_SIZE(link_stats)); 1201} 1202 1203int rtnl_link_str2stat(const char *name) 1204{ 1205 return __str2type(name, link_stats, ARRAY_SIZE(link_stats)); 1206} 1207 1208/** @} */ 1209 1210/** 1211 * @name Link Operstate Translations 1212 * @{ 1213 */ 1214 1215static struct trans_tbl link_operstates[] = { 1216 __ADD(IF_OPER_UNKNOWN, unknown) 1217 __ADD(IF_OPER_NOTPRESENT, notpresent) 1218 __ADD(IF_OPER_DOWN, down) 1219 __ADD(IF_OPER_LOWERLAYERDOWN, lowerlayerdown) 1220 __ADD(IF_OPER_TESTING, testing) 1221 __ADD(IF_OPER_DORMANT, dormant) 1222 __ADD(IF_OPER_UP, up) 1223}; 1224 1225char *rtnl_link_operstate2str(int st, char *buf, size_t len) 1226{ 1227 return __type2str(st, buf, len, link_operstates, 1228 ARRAY_SIZE(link_operstates)); 1229} 1230 1231int rtnl_link_str2operstate(const char *name) 1232{ 1233 return __str2type(name, link_operstates, 1234 ARRAY_SIZE(link_operstates)); 1235} 1236 1237/** @} */ 1238 1239/** 1240 * @name Link Mode Translations 1241 * @{ 1242 */ 1243 1244static struct trans_tbl link_modes[] = { 1245 __ADD(IF_LINK_MODE_DEFAULT, default) 1246 __ADD(IF_LINK_MODE_DORMANT, dormant) 1247}; 1248 1249char *rtnl_link_mode2str(int st, char *buf, size_t len) 1250{ 1251 return __type2str(st, buf, len, link_modes, ARRAY_SIZE(link_modes)); 1252} 1253 1254int rtnl_link_str2mode(const char *name) 1255{ 1256 return __str2type(name, link_modes, ARRAY_SIZE(link_modes)); 1257} 1258 1259/** @} */ 1260 1261/** 1262 * @name Attributes 1263 * @{ 1264 */ 1265 1266void rtnl_link_set_qdisc(struct rtnl_link *link, const char *qdisc) 1267{ 1268 strncpy(link->l_qdisc, qdisc, sizeof(link->l_qdisc) - 1); 1269 link->ce_mask |= LINK_ATTR_QDISC; 1270} 1271 1272char *rtnl_link_get_qdisc(struct rtnl_link *link) 1273{ 1274 if (link->ce_mask & LINK_ATTR_QDISC) 1275 return link->l_qdisc; 1276 else 1277 return NULL; 1278} 1279 1280void rtnl_link_set_name(struct rtnl_link *link, const char *name) 1281{ 1282 strncpy(link->l_name, name, sizeof(link->l_name) - 1); 1283 link->ce_mask |= LINK_ATTR_IFNAME; 1284} 1285 1286char *rtnl_link_get_name(struct rtnl_link *link) 1287{ 1288 if (link->ce_mask & LINK_ATTR_IFNAME) 1289 return link->l_name; 1290 else 1291 return NULL; 1292} 1293 1294static inline void __assign_addr(struct rtnl_link *link, struct nl_addr **pos, 1295 struct nl_addr *new, int flag) 1296{ 1297 if (*pos) 1298 nl_addr_put(*pos); 1299 1300 nl_addr_get(new); 1301 *pos = new; 1302 1303 link->ce_mask |= flag; 1304} 1305 1306void rtnl_link_set_addr(struct rtnl_link *link, struct nl_addr *addr) 1307{ 1308 __assign_addr(link, &link->l_addr, addr, LINK_ATTR_ADDR); 1309} 1310 1311struct nl_addr *rtnl_link_get_addr(struct rtnl_link *link) 1312{ 1313 if (link->ce_mask & LINK_ATTR_ADDR) 1314 return link->l_addr; 1315 else 1316 return NULL; 1317} 1318 1319void rtnl_link_set_broadcast(struct rtnl_link *link, struct nl_addr *brd) 1320{ 1321 __assign_addr(link, &link->l_bcast, brd, LINK_ATTR_BRD); 1322} 1323 1324struct nl_addr *rtnl_link_get_broadcast(struct rtnl_link *link) 1325{ 1326 if (link->ce_mask & LINK_ATTR_BRD) 1327 return link->l_bcast; 1328 else 1329 return NULL; 1330} 1331 1332void rtnl_link_set_flags(struct rtnl_link *link, unsigned int flags) 1333{ 1334 link->l_flag_mask |= flags; 1335 link->l_flags |= flags; 1336 link->ce_mask |= LINK_ATTR_FLAGS; 1337} 1338 1339void rtnl_link_unset_flags(struct rtnl_link *link, unsigned int flags) 1340{ 1341 link->l_flag_mask |= flags; 1342 link->l_flags &= ~flags; 1343 link->ce_mask |= LINK_ATTR_FLAGS; 1344} 1345 1346unsigned int rtnl_link_get_flags(struct rtnl_link *link) 1347{ 1348 return link->l_flags; 1349} 1350 1351void rtnl_link_set_family(struct rtnl_link *link, int family) 1352{ 1353 link->l_family = family; 1354 link->ce_mask |= LINK_ATTR_FAMILY; 1355} 1356 1357int rtnl_link_get_family(struct rtnl_link *link) 1358{ 1359 if (link->l_family & LINK_ATTR_FAMILY) 1360 return link->l_family; 1361 else 1362 return AF_UNSPEC; 1363} 1364 1365void rtnl_link_set_arptype(struct rtnl_link *link, unsigned int arptype) 1366{ 1367 link->l_arptype = arptype; 1368} 1369 1370unsigned int rtnl_link_get_arptype(struct rtnl_link *link) 1371{ 1372 return link->l_arptype; 1373} 1374 1375void rtnl_link_set_ifindex(struct rtnl_link *link, int ifindex) 1376{ 1377 link->l_index = ifindex; 1378 link->ce_mask |= LINK_ATTR_IFINDEX; 1379} 1380 1381int rtnl_link_get_ifindex(struct rtnl_link *link) 1382{ 1383 if (link->ce_mask & LINK_ATTR_IFINDEX) 1384 return link->l_index; 1385 else 1386 return RTNL_LINK_NOT_FOUND; 1387} 1388 1389void rtnl_link_set_mtu(struct rtnl_link *link, unsigned int mtu) 1390{ 1391 link->l_mtu = mtu; 1392 link->ce_mask |= LINK_ATTR_MTU; 1393} 1394 1395unsigned int rtnl_link_get_mtu(struct rtnl_link *link) 1396{ 1397 if (link->ce_mask & LINK_ATTR_MTU) 1398 return link->l_mtu; 1399 else 1400 return 0; 1401} 1402 1403void rtnl_link_set_txqlen(struct rtnl_link *link, unsigned int txqlen) 1404{ 1405 link->l_txqlen = txqlen; 1406 link->ce_mask |= LINK_ATTR_TXQLEN; 1407} 1408 1409unsigned int rtnl_link_get_txqlen(struct rtnl_link *link) 1410{ 1411 if (link->ce_mask & LINK_ATTR_TXQLEN) 1412 return link->l_txqlen; 1413 else 1414 return UINT_MAX; 1415} 1416 1417void rtnl_link_set_weight(struct rtnl_link *link, unsigned int weight) 1418{ 1419 link->l_weight = weight; 1420 link->ce_mask |= LINK_ATTR_WEIGHT; 1421} 1422 1423unsigned int rtnl_link_get_weight(struct rtnl_link *link) 1424{ 1425 if (link->ce_mask & LINK_ATTR_WEIGHT) 1426 return link->l_weight; 1427 else 1428 return UINT_MAX; 1429} 1430 1431void rtnl_link_set_link(struct rtnl_link *link, int ifindex) 1432{ 1433 link->l_link = ifindex; 1434 link->ce_mask |= LINK_ATTR_LINK; 1435} 1436 1437int rtnl_link_get_link(struct rtnl_link *link) 1438{ 1439 if (link->ce_mask & LINK_ATTR_LINK) 1440 return link->l_link; 1441 else 1442 return RTNL_LINK_NOT_FOUND; 1443} 1444 1445void rtnl_link_set_master(struct rtnl_link *link, int ifindex) 1446{ 1447 link->l_master = ifindex; 1448 link->ce_mask |= LINK_ATTR_MASTER; 1449} 1450 1451int rtnl_link_get_master(struct rtnl_link *link) 1452{ 1453 if (link->ce_mask & LINK_ATTR_MASTER) 1454 return link->l_master; 1455 else 1456 return RTNL_LINK_NOT_FOUND; 1457} 1458 1459void rtnl_link_set_operstate(struct rtnl_link *link, uint8_t operstate) 1460{ 1461 link->l_operstate = operstate; 1462 link->ce_mask |= LINK_ATTR_OPERSTATE; 1463} 1464 1465uint8_t rtnl_link_get_operstate(struct rtnl_link *link) 1466{ 1467 if (link->ce_mask & LINK_ATTR_OPERSTATE) 1468 return link->l_operstate; 1469 else 1470 return IF_OPER_UNKNOWN; 1471} 1472 1473void rtnl_link_set_linkmode(struct rtnl_link *link, uint8_t linkmode) 1474{ 1475 link->l_linkmode = linkmode; 1476 link->ce_mask |= LINK_ATTR_LINKMODE; 1477} 1478 1479uint8_t rtnl_link_get_linkmode(struct rtnl_link *link) 1480{ 1481 if (link->ce_mask & LINK_ATTR_LINKMODE) 1482 return link->l_linkmode; 1483 else 1484 return IF_LINK_MODE_DEFAULT; 1485} 1486 1487uint64_t rtnl_link_get_stat(struct rtnl_link *link, int id) 1488{ 1489 if (id < 0 || id > RTNL_LINK_STATS_MAX) 1490 return 0; 1491 1492 return link->l_stats[id]; 1493} 1494 1495/** 1496 * Specify the info type of a link 1497 * @arg link link object 1498 * @arg type info type 1499 * 1500 * Looks up the info type and prepares the link to store info type 1501 * specific attributes. If an info type has been assigned already 1502 * it will be released with all changes lost. 1503 * 1504 * @return 0 on success or a negative errror code. 1505 */ 1506int rtnl_link_set_info_type(struct rtnl_link *link, const char *type) 1507{ 1508 struct rtnl_link_info_ops *io; 1509 int err; 1510 1511 if ((io = rtnl_link_info_ops_lookup(type)) == NULL) 1512 return nl_error(ENOENT, "No such link info type exists"); 1513 1514 if (link->l_info_ops) 1515 release_link_info(link); 1516 1517 if ((err = io->io_alloc(link)) < 0) 1518 return err; 1519 1520 link->l_info_ops = io; 1521 1522 return 0; 1523} 1524 1525/** 1526 * Return info type of a link 1527 * @arg link link object 1528 * 1529 * @note The returned pointer is only valid as long as the link exists 1530 * @return Info type name or NULL if unknown. 1531 */ 1532char *rtnl_link_get_info_type(struct rtnl_link *link) 1533{ 1534 if (link->l_info_ops) 1535 return link->l_info_ops->io_name; 1536 else 1537 return NULL; 1538} 1539 1540/** @} */ 1541 1542static struct nl_object_ops link_obj_ops = { 1543 .oo_name = "route/link", 1544 .oo_size = sizeof(struct rtnl_link), 1545 .oo_free_data = link_free_data, 1546 .oo_clone = link_clone, 1547 .oo_dump[NL_DUMP_BRIEF] = link_dump_brief, 1548 .oo_dump[NL_DUMP_FULL] = link_dump_full, 1549 .oo_dump[NL_DUMP_STATS] = link_dump_stats, 1550 .oo_dump[NL_DUMP_XML] = link_dump_xml, 1551 .oo_dump[NL_DUMP_ENV] = link_dump_env, 1552 .oo_compare = link_compare, 1553 .oo_attrs2str = link_attrs2str, 1554 .oo_id_attrs = LINK_ATTR_IFINDEX, 1555}; 1556 1557static struct nl_af_group link_groups[] = { 1558 { AF_UNSPEC, RTNLGRP_LINK }, 1559 { END_OF_GROUP_LIST }, 1560}; 1561 1562static struct nl_cache_ops rtnl_link_ops = { 1563 .co_name = "route/link", 1564 .co_hdrsize = sizeof(struct ifinfomsg), 1565 .co_msgtypes = { 1566 { RTM_NEWLINK, NL_ACT_NEW, "new" }, 1567 { RTM_DELLINK, NL_ACT_DEL, "del" }, 1568 { RTM_GETLINK, NL_ACT_GET, "get" }, 1569 END_OF_MSGTYPES_LIST, 1570 }, 1571 .co_protocol = NETLINK_ROUTE, 1572 .co_groups = link_groups, 1573 .co_request_update = link_request_update, 1574 .co_msg_parser = link_msg_parser, 1575 .co_obj_ops = &link_obj_ops, 1576}; 1577 1578static void __init link_init(void) 1579{ 1580 nl_cache_mngt_register(&rtnl_link_ops); 1581} 1582 1583static void __exit link_exit(void) 1584{ 1585 nl_cache_mngt_unregister(&rtnl_link_ops); 1586} 1587 1588/** @} */ 1589