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