libnl 1.1
lib/route/link.c
00001 /*
00002  * lib/route/link.c     Links (Interfaces)
00003  *
00004  *      This library is free software; you can redistribute it and/or
00005  *      modify it under the terms of the GNU Lesser General Public
00006  *      License as published by the Free Software Foundation version 2.1
00007  *      of the License.
00008  *
00009  * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
00010  */
00011 
00012 /**
00013  * @ingroup rtnl
00014  * @defgroup link Links (Interfaces)
00015  * @brief
00016  *
00017  * @par Link Identification
00018  * A link can be identified by either its interface index or by its
00019  * name. The kernel favours the interface index but falls back to the
00020  * interface name if the interface index is lesser-than 0 for kernels
00021  * >= 2.6.11. Therefore you can request changes without mapping a
00022  * interface name to the corresponding index first.
00023  *
00024  * @par Changeable Attributes
00025  * @anchor link_changeable
00026  *  - Link layer address
00027  *  - Link layer broadcast address
00028  *  - device mapping (ifmap) (>= 2.6.9)
00029  *  - MTU (>= 2.6.9)
00030  *  - Transmission queue length (>= 2.6.9)
00031  *  - Weight (>= 2.6.9)
00032  *  - Link name (only via access through interface index) (>= 2.6.9)
00033  *  - Flags (>= 2.6.9)
00034  *    - IFF_DEBUG
00035  *    - IFF_NOTRAILERS
00036  *    - IFF_NOARP
00037  *    - IFF_DYNAMIC
00038  *    - IFF_MULTICAST
00039  *    - IFF_PORTSEL
00040  *    - IFF_AUTOMEDIA
00041  *    - IFF_UP
00042  *    - IFF_PROMISC
00043  *    - IFF_ALLMULTI
00044  *
00045  * @par Link Flags (linux/if.h)
00046  * @anchor link_flags
00047  * @code
00048  *   IFF_UP            Status of link (up|down)
00049  *   IFF_BROADCAST     Indicates this link allows broadcasting
00050  *   IFF_MULTICAST     Indicates this link allows multicasting
00051  *   IFF_ALLMULTI      Indicates this link is doing multicast routing
00052  *   IFF_DEBUG         Tell the driver to do debugging (currently unused)
00053  *   IFF_LOOPBACK      This is the loopback link
00054  *   IFF_POINTOPOINT   Point-to-point link
00055  *   IFF_NOARP         Link is unable to perform ARP
00056  *   IFF_PROMISC       Status of promiscious mode flag
00057  *   IFF_MASTER        Used by teql
00058  *   IFF_SLAVE         Used by teql
00059  *   IFF_PORTSEL       Indicates this link allows port selection
00060  *   IFF_AUTOMEDIA     Indicates this link selects port automatically
00061  *   IFF_DYNAMIC       Indicates the address of this link is dynamic
00062  *   IFF_RUNNING       Link is running and carrier is ok.
00063  *   IFF_NOTRAILERS    Unused, BSD compat.
00064  * @endcode
00065  *
00066  * @par Notes on IFF_PROMISC and IFF_ALLMULTI flags
00067  * Although you can query the status of IFF_PROMISC and IFF_ALLMULTI
00068  * they do not represent the actual state in the kernel but rather
00069  * whether the flag has been enabled/disabled by userspace. The link
00070  * may be in promiscious mode even if IFF_PROMISC is not set in a link
00071  * dump request response because promiscity might be needed by the driver
00072  * for a period of time.
00073  *
00074  * @note The unit of the transmission queue length depends on the
00075  *       link type, a common unit is \a packets.
00076  *
00077  * @par 1) Retrieving information about available links
00078  * @code
00079  * // The first step is to retrieve a list of all available interfaces within
00080  * // the kernel and put them into a cache.
00081  * struct nl_cache *cache = rtnl_link_alloc_cache(nl_handle);
00082  *
00083  * // In a second step, a specific link may be looked up by either interface
00084  * // index or interface name.
00085  * struct rtnl_link *link = rtnl_link_get_by_name(cache, "lo");
00086  *
00087  * // rtnl_link_get_by_name() is the short version for translating the
00088  * // interface name to an interface index first like this:
00089  * int ifindex = rtnl_link_name2i(cache, "lo");
00090  * struct rtnl_link *link = rtnl_link_get(cache, ifindex);
00091  *
00092  * // After successful usage, the object must be given back to the cache
00093  * rtnl_link_put(link);
00094  * @endcode
00095  *
00096  * @par 2) Changing link attributes
00097  * @code
00098  * // In order to change any attributes of an existing link, we must allocate
00099  * // a new link to hold the change requests:
00100  * struct rtnl_link *request = rtnl_link_alloc();
00101  *
00102  * // Now we can go on and specify the attributes we want to change:
00103  * rtnl_link_set_weight(request, 300);
00104  * rtnl_link_set_mtu(request, 1360);
00105  *
00106  * // We can also shut an interface down administratively
00107  * rtnl_link_unset_flags(request, rtnl_link_str2flags("up"));
00108  *
00109  * // Actually, we should know which link to change, so let's look it up
00110  * struct rtnl_link *old = rtnl_link_get(cache, "eth0");
00111  *
00112  * // Two ways exist to commit this change request, the first one is to
00113  * // build the required netlink message and send it out in one single
00114  * // step:
00115  * rtnl_link_change(nl_handle, old, request);
00116  *
00117  * // An alternative way is to build the netlink message and send it
00118  * // out yourself using nl_send_auto_complete()
00119  * struct nl_msg *msg = rtnl_link_build_change_request(old, request);
00120  * nl_send_auto_complete(nl_handle, nlmsg_hdr(msg));
00121  * nlmsg_free(msg);
00122  *
00123  * // Don't forget to give back the link object ;->
00124  * rtnl_link_put(old);
00125  * @endcode
00126  *
00127  * @par 3) Link Type Specific Attributes
00128  * @code
00129  * // Some link types offer additional parameters and statistics specific
00130  * // to their type. F.e. a VLAN link can be configured like this:
00131  * //
00132  * // Allocate a new link and set the info type to "vlan". This is required
00133  * // to prepare the link to hold vlan specific attributes.
00134  * struct rtnl_link *request = rtnl_link_alloc();
00135  * rtnl_link_set_info_type(request, "vlan");
00136  *
00137  * // Now vlan specific attributes can be set:
00138  * rtnl_link_vlan_set_id(request, 10);
00139  * rtnl_link_vlan_set_ingress_map(request, 2, 8);
00140  *
00141  * // Of course the attributes can also be read, check the info type
00142  * // to make sure you are using the right access functions:
00143  * char *type = rtnl_link_get_info_type(link);
00144  * if (!strcmp(type, "vlan"))
00145  *      int id = rtnl_link_vlan_get_id(link);
00146  * @endcode
00147  * @{
00148  */
00149 
00150 #include <netlink-local.h>
00151 #include <netlink/netlink.h>
00152 #include <netlink/attr.h>
00153 #include <netlink/utils.h>
00154 #include <netlink/object.h>
00155 #include <netlink/route/rtnl.h>
00156 #include <netlink/route/link.h>
00157 #include <netlink/route/link/info-api.h>
00158 
00159 /** @cond SKIP */
00160 #define LINK_ATTR_MTU     0x0001
00161 #define LINK_ATTR_LINK    0x0002
00162 #define LINK_ATTR_TXQLEN  0x0004
00163 #define LINK_ATTR_WEIGHT  0x0008
00164 #define LINK_ATTR_MASTER  0x0010
00165 #define LINK_ATTR_QDISC   0x0020
00166 #define LINK_ATTR_MAP     0x0040
00167 #define LINK_ATTR_ADDR    0x0080
00168 #define LINK_ATTR_BRD     0x0100
00169 #define LINK_ATTR_FLAGS   0x0200
00170 #define LINK_ATTR_IFNAME  0x0400
00171 #define LINK_ATTR_IFINDEX 0x0800
00172 #define LINK_ATTR_FAMILY  0x1000
00173 #define LINK_ATTR_ARPTYPE 0x2000
00174 #define LINK_ATTR_STATS   0x4000
00175 #define LINK_ATTR_CHANGE  0x8000
00176 #define LINK_ATTR_OPERSTATE 0x10000
00177 #define LINK_ATTR_LINKMODE  0x20000
00178 #define LINK_ATTR_LINKINFO  0x40000
00179 
00180 static struct nl_cache_ops rtnl_link_ops;
00181 static struct nl_object_ops link_obj_ops;
00182 /** @endcond */
00183 
00184 static void release_link_info(struct rtnl_link *link)
00185 {
00186         struct rtnl_link_info_ops *io = link->l_info_ops;
00187 
00188         if (io != NULL) {
00189                 io->io_refcnt--;
00190                 io->io_free(link);
00191                 link->l_info_ops = NULL;
00192         }
00193 }
00194 
00195 static void link_free_data(struct nl_object *c)
00196 {
00197         struct rtnl_link *link = nl_object_priv(c);
00198 
00199         if (link) {
00200                 struct rtnl_link_info_ops *io;
00201 
00202                 if ((io = link->l_info_ops) != NULL)
00203                         release_link_info(link);
00204 
00205                 nl_addr_put(link->l_addr);
00206                 nl_addr_put(link->l_bcast);
00207         }
00208 }
00209 
00210 static int link_clone(struct nl_object *_dst, struct nl_object *_src)
00211 {
00212         struct rtnl_link *dst = nl_object_priv(_dst);
00213         struct rtnl_link *src = nl_object_priv(_src);
00214         int err;
00215 
00216         if (src->l_addr)
00217                 if (!(dst->l_addr = nl_addr_clone(src->l_addr)))
00218                         goto errout;
00219 
00220         if (src->l_bcast)
00221                 if (!(dst->l_bcast = nl_addr_clone(src->l_bcast)))
00222                         goto errout;
00223 
00224         if (src->l_info_ops && src->l_info_ops->io_clone) {
00225                 err = src->l_info_ops->io_clone(dst, src);
00226                 if (err < 0)
00227                         goto errout;
00228         }
00229 
00230         return 0;
00231 errout:
00232         return nl_get_errno();
00233 }
00234 
00235 static struct nla_policy link_policy[IFLA_MAX+1] = {
00236         [IFLA_IFNAME]   = { .type = NLA_STRING,
00237                             .maxlen = IFNAMSIZ },
00238         [IFLA_MTU]      = { .type = NLA_U32 },
00239         [IFLA_TXQLEN]   = { .type = NLA_U32 },
00240         [IFLA_LINK]     = { .type = NLA_U32 },
00241         [IFLA_WEIGHT]   = { .type = NLA_U32 },
00242         [IFLA_MASTER]   = { .type = NLA_U32 },
00243         [IFLA_OPERSTATE]= { .type = NLA_U8 },
00244         [IFLA_LINKMODE] = { .type = NLA_U8 },
00245         [IFLA_LINKINFO] = { .type = NLA_NESTED },
00246         [IFLA_QDISC]    = { .type = NLA_STRING,
00247                             .maxlen = IFQDISCSIZ },
00248         [IFLA_STATS]    = { .minlen = sizeof(struct rtnl_link_stats) },
00249         [IFLA_MAP]      = { .minlen = sizeof(struct rtnl_link_ifmap) },
00250 };
00251 
00252 static struct nla_policy link_info_policy[IFLA_INFO_MAX+1] = {
00253         [IFLA_INFO_KIND]        = { .type = NLA_STRING },
00254         [IFLA_INFO_DATA]        = { .type = NLA_NESTED },
00255         [IFLA_INFO_XSTATS]      = { .type = NLA_NESTED },
00256 };
00257 
00258 static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
00259                            struct nlmsghdr *n, struct nl_parser_param *pp)
00260 {
00261         struct rtnl_link *link;
00262         struct ifinfomsg *ifi;
00263         struct nlattr *tb[IFLA_MAX+1];
00264         int err;
00265 
00266         link = rtnl_link_alloc();
00267         if (link == NULL) {
00268                 err = nl_errno(ENOMEM);
00269                 goto errout;
00270         }
00271                 
00272         link->ce_msgtype = n->nlmsg_type;
00273 
00274         err = nlmsg_parse(n, sizeof(*ifi), tb, IFLA_MAX, link_policy);
00275         if (err < 0)
00276                 goto errout;
00277 
00278         if (tb[IFLA_IFNAME] == NULL) {
00279                 err = nl_error(EINVAL, "Missing link name TLV");
00280                 goto errout;
00281         }
00282 
00283         nla_strlcpy(link->l_name, tb[IFLA_IFNAME], IFNAMSIZ);
00284 
00285         ifi = nlmsg_data(n);
00286         link->l_family = ifi->ifi_family;
00287         link->l_arptype = ifi->ifi_type;
00288         link->l_index = ifi->ifi_index;
00289         link->l_flags = ifi->ifi_flags;
00290         link->l_change = ifi->ifi_change;
00291         link->ce_mask = (LINK_ATTR_IFNAME | LINK_ATTR_FAMILY |
00292                           LINK_ATTR_ARPTYPE| LINK_ATTR_IFINDEX |
00293                           LINK_ATTR_FLAGS | LINK_ATTR_CHANGE);
00294 
00295         if (tb[IFLA_STATS]) {
00296                 struct rtnl_link_stats *st = nla_data(tb[IFLA_STATS]);
00297                 
00298                 link->l_stats[RTNL_LINK_RX_PACKETS]     = st->rx_packets;
00299                 link->l_stats[RTNL_LINK_RX_BYTES]       = st->rx_bytes;
00300                 link->l_stats[RTNL_LINK_RX_ERRORS]      = st->rx_errors;
00301                 link->l_stats[RTNL_LINK_RX_DROPPED]     = st->rx_dropped;
00302                 link->l_stats[RTNL_LINK_RX_COMPRESSED]  = st->rx_compressed;
00303                 link->l_stats[RTNL_LINK_RX_FIFO_ERR]    = st->rx_fifo_errors;
00304                 link->l_stats[RTNL_LINK_TX_PACKETS]     = st->tx_packets;
00305                 link->l_stats[RTNL_LINK_TX_BYTES]       = st->tx_bytes;
00306                 link->l_stats[RTNL_LINK_TX_ERRORS]      = st->tx_errors;
00307                 link->l_stats[RTNL_LINK_TX_DROPPED]     = st->tx_dropped;
00308                 link->l_stats[RTNL_LINK_TX_COMPRESSED]  = st->tx_compressed;
00309                 link->l_stats[RTNL_LINK_TX_FIFO_ERR]    = st->tx_fifo_errors;
00310                 link->l_stats[RTNL_LINK_RX_LEN_ERR]     = st->rx_length_errors;
00311                 link->l_stats[RTNL_LINK_RX_OVER_ERR]    = st->rx_over_errors;
00312                 link->l_stats[RTNL_LINK_RX_CRC_ERR]     = st->rx_crc_errors;
00313                 link->l_stats[RTNL_LINK_RX_FRAME_ERR]   = st->rx_frame_errors;
00314                 link->l_stats[RTNL_LINK_RX_MISSED_ERR]  = st->rx_missed_errors;
00315                 link->l_stats[RTNL_LINK_TX_ABORT_ERR]   = st->tx_aborted_errors;
00316                 link->l_stats[RTNL_LINK_TX_CARRIER_ERR] = st->tx_carrier_errors;
00317                 link->l_stats[RTNL_LINK_TX_HBEAT_ERR]   = st->tx_heartbeat_errors;
00318                 link->l_stats[RTNL_LINK_TX_WIN_ERR]     = st->tx_window_errors;
00319                 link->l_stats[RTNL_LINK_MULTICAST]      = st->multicast;
00320 
00321                 link->ce_mask |= LINK_ATTR_STATS;
00322         }
00323 
00324         if (tb[IFLA_TXQLEN]) {
00325                 link->l_txqlen = nla_get_u32(tb[IFLA_TXQLEN]);
00326                 link->ce_mask |= LINK_ATTR_TXQLEN;
00327         }
00328 
00329         if (tb[IFLA_MTU]) {
00330                 link->l_mtu = nla_get_u32(tb[IFLA_MTU]);
00331                 link->ce_mask |= LINK_ATTR_MTU;
00332         }
00333 
00334         if (tb[IFLA_ADDRESS]) {
00335                 link->l_addr = nla_get_addr(tb[IFLA_ADDRESS], AF_UNSPEC);
00336                 if (link->l_addr == NULL)
00337                         goto errout;
00338                 nl_addr_set_family(link->l_addr,
00339                                    nl_addr_guess_family(link->l_addr));
00340                 link->ce_mask |= LINK_ATTR_ADDR;
00341         }
00342 
00343         if (tb[IFLA_BROADCAST]) {
00344                 link->l_bcast = nla_get_addr(tb[IFLA_BROADCAST], AF_UNSPEC);
00345                 if (link->l_bcast == NULL)
00346                         goto errout;
00347                 nl_addr_set_family(link->l_bcast,
00348                                    nl_addr_guess_family(link->l_bcast));
00349                 link->ce_mask |= LINK_ATTR_BRD;
00350         }
00351 
00352         if (tb[IFLA_LINK]) {
00353                 link->l_link = nla_get_u32(tb[IFLA_LINK]);
00354                 link->ce_mask |= LINK_ATTR_LINK;
00355         }
00356 
00357         if (tb[IFLA_WEIGHT]) {
00358                 link->l_weight = nla_get_u32(tb[IFLA_WEIGHT]);
00359                 link->ce_mask |= LINK_ATTR_WEIGHT;
00360         }
00361 
00362         if (tb[IFLA_QDISC]) {
00363                 nla_strlcpy(link->l_qdisc, tb[IFLA_QDISC], IFQDISCSIZ);
00364                 link->ce_mask |= LINK_ATTR_QDISC;
00365         }
00366 
00367         if (tb[IFLA_MAP]) {
00368                 nla_memcpy(&link->l_map, tb[IFLA_MAP], 
00369                            sizeof(struct rtnl_link_ifmap));
00370                 link->ce_mask |= LINK_ATTR_MAP;
00371         }
00372 
00373         if (tb[IFLA_MASTER]) {
00374                 link->l_master = nla_get_u32(tb[IFLA_MASTER]);
00375                 link->ce_mask |= LINK_ATTR_MASTER;
00376         }
00377 
00378         if (tb[IFLA_OPERSTATE]) {
00379                 link->l_operstate = nla_get_u8(tb[IFLA_OPERSTATE]);
00380                 link->ce_mask |= LINK_ATTR_OPERSTATE;
00381         }
00382 
00383         if (tb[IFLA_LINKMODE]) {
00384                 link->l_linkmode = nla_get_u8(tb[IFLA_LINKMODE]);
00385                 link->ce_mask |= LINK_ATTR_LINKMODE;
00386         }
00387 
00388         if (tb[IFLA_LINKINFO]) {
00389                 struct nlattr *li[IFLA_INFO_MAX+1];
00390 
00391                 err = nla_parse_nested(li, IFLA_INFO_MAX, tb[IFLA_LINKINFO],
00392                                        link_info_policy);
00393                 if (err < 0)
00394                         goto errout;
00395 
00396                 if (li[IFLA_INFO_KIND] &&
00397                     (li[IFLA_INFO_DATA] || li[IFLA_INFO_XSTATS])) {
00398                         struct rtnl_link_info_ops *ops;
00399                         char *kind;
00400 
00401                         kind = nla_get_string(li[IFLA_INFO_KIND]);
00402                         ops = rtnl_link_info_ops_lookup(kind);
00403                         if (ops != NULL) {
00404                                 ops->io_refcnt++;
00405                                 link->l_info_ops = ops;
00406                                 err = ops->io_parse(link, li[IFLA_INFO_DATA],
00407                                                     li[IFLA_INFO_XSTATS]);
00408                                 if (err < 0)
00409                                         goto errout;
00410                         } else {
00411                                 /* XXX: Warn about unparsed info? */
00412                         }
00413                 }
00414         }
00415 
00416         err = pp->pp_cb((struct nl_object *) link, pp);
00417         if (err < 0)
00418                 goto errout;
00419 
00420         err = P_ACCEPT;
00421 
00422 errout:
00423         rtnl_link_put(link);
00424         return err;
00425 }
00426 
00427 static int link_request_update(struct nl_cache *c, struct nl_handle *h)
00428 {
00429         return nl_rtgen_request(h, RTM_GETLINK, AF_UNSPEC, NLM_F_DUMP);
00430 }
00431 
00432 static int link_dump_brief(struct nl_object *obj, struct nl_dump_params *p)
00433 {
00434         char buf[128];
00435         struct nl_cache *cache = dp_cache(obj);
00436         struct rtnl_link *link = (struct rtnl_link *) obj;
00437         int line = 1;
00438 
00439         dp_dump(p, "%s %s ", link->l_name,
00440                              nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
00441 
00442         if (link->l_addr && !nl_addr_iszero(link->l_addr))
00443                 dp_dump(p, "%s ", nl_addr2str(link->l_addr, buf, sizeof(buf)));
00444 
00445         if (link->ce_mask & LINK_ATTR_MASTER) {
00446                 struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
00447                 dp_dump(p, "master %s ", master ? master->l_name : "inv");
00448                 if (master)
00449                         rtnl_link_put(master);
00450         }
00451 
00452         rtnl_link_flags2str(link->l_flags, buf, sizeof(buf));
00453         if (buf[0])
00454                 dp_dump(p, "<%s> ", buf);
00455 
00456         if (link->ce_mask & LINK_ATTR_LINK) {
00457                 struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
00458                 dp_dump(p, "slave-of %s ", ll ? ll->l_name : "NONE");
00459                 if (ll)
00460                         rtnl_link_put(ll);
00461         }
00462 
00463         if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_BRIEF])
00464                 line = link->l_info_ops->io_dump[NL_DUMP_BRIEF](link, p, line);
00465 
00466         dp_dump(p, "\n");
00467 
00468         return line;
00469 }
00470 
00471 static int link_dump_full(struct nl_object *obj, struct nl_dump_params *p)
00472 {
00473         struct rtnl_link *link = (struct rtnl_link *) obj;
00474         char buf[64];
00475         int line;
00476 
00477         line = link_dump_brief(obj, p);
00478         dp_new_line(p, line++);
00479 
00480         dp_dump(p, "    mtu %u ", link->l_mtu);
00481         dp_dump(p, "txqlen %u weight %u ", link->l_txqlen, link->l_weight);
00482 
00483         if (link->ce_mask & LINK_ATTR_QDISC)
00484                 dp_dump(p, "qdisc %s ", link->l_qdisc);
00485 
00486         if (link->ce_mask & LINK_ATTR_MAP && link->l_map.lm_irq)
00487                 dp_dump(p, "irq %u ", link->l_map.lm_irq);
00488 
00489         if (link->ce_mask & LINK_ATTR_IFINDEX)
00490                 dp_dump(p, "index %u ", link->l_index);
00491 
00492 
00493         dp_dump(p, "\n");
00494         dp_new_line(p, line++);
00495 
00496         dp_dump(p, "    ");
00497 
00498         if (link->ce_mask & LINK_ATTR_BRD)
00499                 dp_dump(p, "brd %s ", nl_addr2str(link->l_bcast, buf,
00500                                                    sizeof(buf)));
00501 
00502         if ((link->ce_mask & LINK_ATTR_OPERSTATE) &&
00503             link->l_operstate != IF_OPER_UNKNOWN) {
00504                 rtnl_link_operstate2str(link->l_operstate, buf, sizeof(buf));
00505                 dp_dump(p, "state %s ", buf);
00506         }
00507 
00508         dp_dump(p, "mode %s\n",
00509                 rtnl_link_mode2str(link->l_linkmode, buf, sizeof(buf)));
00510 
00511         if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_FULL])
00512                 line = link->l_info_ops->io_dump[NL_DUMP_FULL](link, p, line);
00513 
00514         return line;
00515 }
00516 
00517 static int link_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
00518 {
00519         struct rtnl_link *link = (struct rtnl_link *) obj;
00520         char *unit, fmt[64];
00521         float res;
00522         int line;
00523         
00524         line = link_dump_full(obj, p);
00525 
00526         dp_dump_line(p, line++, "    Stats:    bytes    packets     errors "
00527                                 "   dropped   fifo-err compressed\n");
00528 
00529         res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_RX_BYTES], &unit);
00530 
00531         strcpy(fmt, "    RX  %X.2f %s %10llu %10llu %10llu %10llu %10llu\n");
00532         fmt[9] = *unit == 'B' ? '9' : '7';
00533         
00534         dp_dump_line(p, line++, fmt,
00535                 res, unit,
00536                 link->l_stats[RTNL_LINK_RX_PACKETS],
00537                 link->l_stats[RTNL_LINK_RX_ERRORS],
00538                 link->l_stats[RTNL_LINK_RX_DROPPED],
00539                 link->l_stats[RTNL_LINK_RX_FIFO_ERR],
00540                 link->l_stats[RTNL_LINK_RX_COMPRESSED]);
00541 
00542         res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_TX_BYTES], &unit);
00543 
00544         strcpy(fmt, "    TX  %X.2f %s %10llu %10llu %10llu %10llu %10llu\n");
00545         fmt[9] = *unit == 'B' ? '9' : '7';
00546         
00547         dp_dump_line(p, line++, fmt,
00548                 res, unit,
00549                 link->l_stats[RTNL_LINK_TX_PACKETS],
00550                 link->l_stats[RTNL_LINK_TX_ERRORS],
00551                 link->l_stats[RTNL_LINK_TX_DROPPED],
00552                 link->l_stats[RTNL_LINK_TX_FIFO_ERR],
00553                 link->l_stats[RTNL_LINK_TX_COMPRESSED]);
00554 
00555         dp_dump_line(p, line++, "    Errors:  length       over        crc "
00556                                 "     frame     missed  multicast\n");
00557 
00558         dp_dump_line(p, line++, "    RX   %10" PRIu64 " %10" PRIu64 " %10"
00559                                 PRIu64 " %10" PRIu64 " %10" PRIu64 " %10"
00560                                 PRIu64 "\n",
00561                 link->l_stats[RTNL_LINK_RX_LEN_ERR],
00562                 link->l_stats[RTNL_LINK_RX_OVER_ERR],
00563                 link->l_stats[RTNL_LINK_RX_CRC_ERR],
00564                 link->l_stats[RTNL_LINK_RX_FRAME_ERR],
00565                 link->l_stats[RTNL_LINK_RX_MISSED_ERR],
00566                 link->l_stats[RTNL_LINK_MULTICAST]);
00567 
00568         dp_dump_line(p, line++, "    Errors: aborted    carrier  heartbeat "
00569                                 "    window  collision\n");
00570         
00571         dp_dump_line(p, line++, "    TX   %10" PRIu64 " %10" PRIu64 " %10"
00572                                 PRIu64 " %10" PRIu64 " %10" PRIu64 "\n",
00573                 link->l_stats[RTNL_LINK_TX_ABORT_ERR],
00574                 link->l_stats[RTNL_LINK_TX_CARRIER_ERR],
00575                 link->l_stats[RTNL_LINK_TX_HBEAT_ERR],
00576                 link->l_stats[RTNL_LINK_TX_WIN_ERR],
00577                 link->l_stats[RTNL_LINK_TX_COLLISIONS]);
00578 
00579         if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_STATS])
00580                 line = link->l_info_ops->io_dump[NL_DUMP_STATS](link, p, line);
00581 
00582         return line;
00583 }
00584 
00585 static int link_dump_xml(struct nl_object *obj, struct nl_dump_params *p)
00586 {
00587         struct rtnl_link *link = (struct rtnl_link *) obj;
00588         struct nl_cache *cache = dp_cache(obj);
00589         char buf[128];
00590         int i, line = 0;
00591 
00592         dp_dump_line(p, line++, "<link name=\"%s\" index=\"%u\">\n",
00593                      link->l_name, link->l_index);
00594         dp_dump_line(p, line++, "  <family>%s</family>\n",
00595                      nl_af2str(link->l_family, buf, sizeof(buf)));
00596         dp_dump_line(p, line++, "  <arptype>%s</arptype>\n",
00597                      nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
00598         dp_dump_line(p, line++, "  <address>%s</address>\n",
00599                      nl_addr2str(link->l_addr, buf, sizeof(buf)));
00600         dp_dump_line(p, line++, "  <mtu>%u</mtu>\n", link->l_mtu);
00601         dp_dump_line(p, line++, "  <txqlen>%u</txqlen>\n", link->l_txqlen);
00602         dp_dump_line(p, line++, "  <weight>%u</weight>\n", link->l_weight);
00603 
00604         rtnl_link_flags2str(link->l_flags, buf, sizeof(buf));
00605         if (buf[0])
00606                 dp_dump_line(p, line++, "  <flags>%s</flags>\n", buf);
00607 
00608         if (link->ce_mask & LINK_ATTR_QDISC)
00609                 dp_dump_line(p, line++, "  <qdisc>%s</qdisc>\n", link->l_qdisc);
00610 
00611         if (link->ce_mask & LINK_ATTR_LINK) {
00612                 struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
00613                 dp_dump_line(p, line++, "  <link>%s</link>\n",
00614                              ll ? ll->l_name : "none");
00615                 if (ll)
00616                         rtnl_link_put(ll);
00617         }
00618 
00619         if (link->ce_mask & LINK_ATTR_MASTER) {
00620                 struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
00621                 dp_dump_line(p, line++, "  <master>%s</master>\n",
00622                              master ? master->l_name : "none");
00623                 if (master)
00624                         rtnl_link_put(master);
00625         }
00626 
00627         if (link->ce_mask & LINK_ATTR_BRD)
00628                 dp_dump_line(p, line++, "  <broadcast>%s</broadcast>\n",
00629                              nl_addr2str(link->l_bcast, buf, sizeof(buf)));
00630 
00631         if (link->ce_mask & LINK_ATTR_STATS) {
00632                 dp_dump_line(p, line++, "  <stats>\n");
00633                 for (i = 0; i <= RTNL_LINK_STATS_MAX; i++) {
00634                         rtnl_link_stat2str(i, buf, sizeof(buf));
00635                         dp_dump_line(p, line++,
00636                                      "    <%s>%" PRIu64 "</%s>\n",
00637                                      buf, link->l_stats[i], buf);
00638                 }
00639                 dp_dump_line(p, line++, "  </stats>\n");
00640         }
00641 
00642         if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_XML]) {
00643                 dp_dump_line(p, line++, "  <info>\n");
00644                 line = link->l_info_ops->io_dump[NL_DUMP_XML](link, p, line);
00645                 dp_dump_line(p, line++, "  </info>\n");
00646         }
00647 
00648         dp_dump_line(p, line++, "</link>\n");
00649 
00650 #if 0
00651         uint32_t        l_change;       /**< Change mask */
00652         struct rtnl_lifmap l_map;       /**< Interface device mapping */
00653 #endif
00654 
00655         return line;
00656 }
00657 
00658 static int link_dump_env(struct nl_object *obj, struct nl_dump_params *p)
00659 {
00660         struct rtnl_link *link = (struct rtnl_link *) obj;
00661         struct nl_cache *cache = dp_cache(obj);
00662         char buf[128];
00663         int i, line = 0;
00664 
00665         dp_dump_line(p, line++, "LINK_NAME=%s\n", link->l_name);
00666         dp_dump_line(p, line++, "LINK_IFINDEX=%u\n", link->l_index);
00667         dp_dump_line(p, line++, "LINK_FAMILY=%s\n",
00668                      nl_af2str(link->l_family, buf, sizeof(buf)));
00669         dp_dump_line(p, line++, "LINK_TYPE=%s\n",
00670                      nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
00671         if (link->ce_mask & LINK_ATTR_ADDR)
00672                 dp_dump_line(p, line++, "LINK_ADDRESS=%s\n",
00673                              nl_addr2str(link->l_addr, buf, sizeof(buf)));
00674         dp_dump_line(p, line++, "LINK_MTU=%u\n", link->l_mtu);
00675         dp_dump_line(p, line++, "LINK_TXQUEUELEN=%u\n", link->l_txqlen);
00676         dp_dump_line(p, line++, "LINK_WEIGHT=%u\n", link->l_weight);
00677 
00678         rtnl_link_flags2str(link->l_flags & ~IFF_RUNNING, buf, sizeof(buf));
00679         if (buf[0])
00680                 dp_dump_line(p, line++, "LINK_FLAGS=%s\n", buf);
00681 
00682         if (link->ce_mask & LINK_ATTR_QDISC)
00683                 dp_dump_line(p, line++, "LINK_QDISC=%s\n", link->l_qdisc);
00684 
00685         if (link->ce_mask & LINK_ATTR_LINK) {
00686                 struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
00687 
00688                 dp_dump_line(p, line++, "LINK_LINK_IFINDEX=%d\n", link->l_link);
00689                 if (ll) {
00690                         dp_dump_line(p, line++, "LINK_LINK_IFNAME=%s\n",
00691                                      ll->l_name);
00692                         rtnl_link_put(ll);
00693                 }
00694         }
00695 
00696         if (link->ce_mask & LINK_ATTR_MASTER) {
00697                 struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
00698                 dp_dump_line(p, line++, "LINK_MASTER=%s\n",
00699                              master ? master->l_name : "none");
00700                 if (master)
00701                         rtnl_link_put(master);
00702         }
00703 
00704         if (link->ce_mask & LINK_ATTR_BRD)
00705                 dp_dump_line(p, line++, "LINK_BROADCAST=%s\n",
00706                              nl_addr2str(link->l_bcast, buf, sizeof(buf)));
00707 
00708         if (link->ce_mask & LINK_ATTR_STATS) {
00709                 for (i = 0; i <= RTNL_LINK_STATS_MAX; i++) {
00710                         char *c = buf;
00711 
00712                         sprintf(buf, "LINK_");
00713                         rtnl_link_stat2str(i, buf + 5, sizeof(buf) - 5);
00714                         while (*c) {
00715                                 *c = toupper(*c);
00716                                 c++;
00717                         }
00718                         dp_dump_line(p, line++,
00719                                      "%s=%" PRIu64 "\n", buf, link->l_stats[i]);
00720                 }
00721         }
00722 
00723         if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_ENV])
00724                 line = link->l_info_ops->io_dump[NL_DUMP_ENV](link, p, line);
00725 
00726         return line;
00727 }
00728 
00729 #if 0
00730 static int link_handle_event(struct nl_object *a, struct rtnl_link_event_cb *cb)
00731 {
00732         struct rtnl_link *l = (struct rtnl_link *) a;
00733         struct nl_cache *c = dp_cache(a);
00734         int nevents = 0;
00735 
00736         if (l->l_change == ~0U) {
00737                 if (l->ce_msgtype == RTM_NEWLINK)
00738                         cb->le_register(l);
00739                 else
00740                         cb->le_unregister(l);
00741 
00742                 return 1;
00743         }
00744 
00745         if (l->l_change & IFF_SLAVE) {
00746                 if (l->l_flags & IFF_SLAVE) {
00747                         struct rtnl_link *m = rtnl_link_get(c, l->l_master);
00748                         cb->le_new_bonding(l, m);
00749                         if (m)
00750                                 rtnl_link_put(m);
00751                 } else
00752                         cb->le_cancel_bonding(l);
00753         }
00754 
00755 #if 0
00756         if (l->l_change & IFF_UP && l->l_change & IFF_RUNNING)
00757                 dp_dump_line(p, line++, "link %s changed state to %s.\n",
00758                         l->l_name, l->l_flags & IFF_UP ? "up" : "down");
00759 
00760         if (l->l_change & IFF_PROMISC) {
00761                 dp_new_line(p, line++);
00762                 dp_dump(p, "link %s %s promiscuous mode.\n",
00763                     l->l_name, l->l_flags & IFF_PROMISC ? "entered" : "left");
00764         }
00765 
00766         if (line == 0)
00767                 dp_dump_line(p, line++, "link %s sent unknown event.\n",
00768                              l->l_name);
00769 #endif
00770 
00771         return nevents;
00772 }
00773 #endif
00774 
00775 static int link_compare(struct nl_object *_a, struct nl_object *_b,
00776                         uint32_t attrs, int flags)
00777 {
00778         struct rtnl_link *a = (struct rtnl_link *) _a;
00779         struct rtnl_link *b = (struct rtnl_link *) _b;
00780         int diff = 0;
00781 
00782 #define LINK_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, LINK_ATTR_##ATTR, a, b, EXPR)
00783 
00784         diff |= LINK_DIFF(IFINDEX,      a->l_index != b->l_index);
00785         diff |= LINK_DIFF(MTU,          a->l_mtu != b->l_mtu);
00786         diff |= LINK_DIFF(LINK,         a->l_link != b->l_link);
00787         diff |= LINK_DIFF(TXQLEN,       a->l_txqlen != b->l_txqlen);
00788         diff |= LINK_DIFF(WEIGHT,       a->l_weight != b->l_weight);
00789         diff |= LINK_DIFF(MASTER,       a->l_master != b->l_master);
00790         diff |= LINK_DIFF(FAMILY,       a->l_family != b->l_family);
00791         diff |= LINK_DIFF(OPERSTATE,    a->l_operstate != b->l_operstate);
00792         diff |= LINK_DIFF(LINKMODE,     a->l_linkmode != b->l_linkmode);
00793         diff |= LINK_DIFF(QDISC,        strcmp(a->l_qdisc, b->l_qdisc));
00794         diff |= LINK_DIFF(IFNAME,       strcmp(a->l_name, b->l_name));
00795         diff |= LINK_DIFF(ADDR,         nl_addr_cmp(a->l_addr, b->l_addr));
00796         diff |= LINK_DIFF(BRD,          nl_addr_cmp(a->l_bcast, b->l_bcast));
00797 
00798         if (flags & LOOSE_FLAG_COMPARISON)
00799                 diff |= LINK_DIFF(FLAGS,
00800                                   (a->l_flags ^ b->l_flags) & b->l_flag_mask);
00801         else
00802                 diff |= LINK_DIFF(FLAGS, a->l_flags != b->l_flags);
00803 
00804 #undef LINK_DIFF
00805 
00806         return diff;
00807 }
00808 
00809 static struct trans_tbl link_attrs[] = {
00810         __ADD(LINK_ATTR_MTU, mtu)
00811         __ADD(LINK_ATTR_LINK, link)
00812         __ADD(LINK_ATTR_TXQLEN, txqlen)
00813         __ADD(LINK_ATTR_WEIGHT, weight)
00814         __ADD(LINK_ATTR_MASTER, master)
00815         __ADD(LINK_ATTR_QDISC, qdisc)
00816         __ADD(LINK_ATTR_MAP, map)
00817         __ADD(LINK_ATTR_ADDR, address)
00818         __ADD(LINK_ATTR_BRD, broadcast)
00819         __ADD(LINK_ATTR_FLAGS, flags)
00820         __ADD(LINK_ATTR_IFNAME, name)
00821         __ADD(LINK_ATTR_IFINDEX, ifindex)
00822         __ADD(LINK_ATTR_FAMILY, family)
00823         __ADD(LINK_ATTR_ARPTYPE, arptype)
00824         __ADD(LINK_ATTR_STATS, stats)
00825         __ADD(LINK_ATTR_CHANGE, change)
00826         __ADD(LINK_ATTR_OPERSTATE, operstate)
00827         __ADD(LINK_ATTR_LINKMODE, linkmode)
00828 };
00829 
00830 static char *link_attrs2str(int attrs, char *buf, size_t len)
00831 {
00832         return __flags2str(attrs, buf, len, link_attrs,
00833                            ARRAY_SIZE(link_attrs));
00834 }
00835 
00836 /**
00837  * @name Allocation/Freeing
00838  * @{
00839  */
00840 
00841 struct rtnl_link *rtnl_link_alloc(void)
00842 {
00843         return (struct rtnl_link *) nl_object_alloc(&link_obj_ops);
00844 }
00845 
00846 void rtnl_link_put(struct rtnl_link *link)
00847 {
00848         nl_object_put((struct nl_object *) link);
00849 }
00850 
00851 /** @} */
00852 
00853 /**
00854  * @name Cache Management
00855  * @{
00856  */
00857 
00858 
00859 /**
00860  * Allocate link cache and fill in all configured links.
00861  * @arg handle          Netlink handle.
00862  *
00863  * Allocates a new link cache, initializes it properly and updates it
00864  * to include all links currently configured in the kernel.
00865  *
00866  * @note Free the memory after usage.
00867  * @return Newly allocated cache or NULL if an error occured.
00868  */
00869 struct nl_cache *rtnl_link_alloc_cache(struct nl_handle *handle)
00870 {
00871         struct nl_cache * cache;
00872         
00873         cache = nl_cache_alloc(&rtnl_link_ops);
00874         if (cache == NULL)
00875                 return NULL;
00876         
00877         if (handle && nl_cache_refill(handle, cache) < 0) {
00878                 nl_cache_free(cache);
00879                 return NULL;
00880         }
00881 
00882         return cache;
00883 }
00884 
00885 /**
00886  * Look up link by interface index in the provided cache
00887  * @arg cache           link cache
00888  * @arg ifindex         link interface index
00889  *
00890  * The caller owns a reference on the returned object and
00891  * must give the object back via rtnl_link_put().
00892  *
00893  * @return pointer to link inside the cache or NULL if no match was found.
00894  */
00895 struct rtnl_link *rtnl_link_get(struct nl_cache *cache, int ifindex)
00896 {
00897         struct rtnl_link *link;
00898 
00899         if (cache->c_ops != &rtnl_link_ops)
00900                 return NULL;
00901 
00902         nl_list_for_each_entry(link, &cache->c_items, ce_list) {
00903                 if (link->l_index == ifindex) {
00904                         nl_object_get((struct nl_object *) link);
00905                         return link;
00906                 }
00907         }
00908 
00909         return NULL;
00910 }
00911 
00912 /**
00913  * Look up link by link name in the provided cache
00914  * @arg cache           link cache
00915  * @arg name            link name
00916  *
00917  * The caller owns a reference on the returned object and
00918  * must give the object back via rtnl_link_put().
00919  *
00920  * @return pointer to link inside the cache or NULL if no match was found.
00921  */
00922 struct rtnl_link *rtnl_link_get_by_name(struct nl_cache *cache,
00923                                          const char *name)
00924 {
00925         struct rtnl_link *link;
00926 
00927         if (cache->c_ops != &rtnl_link_ops)
00928                 return NULL;
00929 
00930         nl_list_for_each_entry(link, &cache->c_items, ce_list) {
00931                 if (!strcmp(name, link->l_name)) {
00932                         nl_object_get((struct nl_object *) link);
00933                         return link;
00934                 }
00935         }
00936 
00937         return NULL;
00938 }
00939 
00940 /** @} */
00941 
00942 /**
00943  * @name Link Modifications
00944  * @{
00945  */
00946 
00947 /**
00948  * Builds a netlink change request message to change link attributes
00949  * @arg old             link to be changed
00950  * @arg tmpl            template with requested changes
00951  * @arg flags           additional netlink message flags
00952  *
00953  * Builds a new netlink message requesting a change of link attributes.
00954  * The netlink message header isn't fully equipped with all relevant
00955  * fields and must be sent out via nl_send_auto_complete() or
00956  * supplemented as needed.
00957  * \a old must point to a link currently configured in the kernel
00958  * and \a tmpl must contain the attributes to be changed set via
00959  * \c rtnl_link_set_* functions.
00960  *
00961  * @return New netlink message
00962  * @note Not all attributes can be changed, see
00963  *       \ref link_changeable "Changeable Attributes" for more details.
00964  */
00965 struct nl_msg * rtnl_link_build_change_request(struct rtnl_link *old,
00966                                                struct rtnl_link *tmpl,
00967                                                int flags)
00968 {
00969         struct nl_msg *msg;
00970         struct ifinfomsg ifi = {
00971                 .ifi_family = old->l_family,
00972                 .ifi_index = old->l_index,
00973         };
00974 
00975         if (tmpl->ce_mask & LINK_ATTR_FLAGS) {
00976                 ifi.ifi_flags = old->l_flags & ~tmpl->l_flag_mask;
00977                 ifi.ifi_flags |= tmpl->l_flags;
00978         }
00979 
00980         msg = nlmsg_alloc_simple(RTM_SETLINK, flags);
00981         if (!msg)
00982                 goto nla_put_failure;
00983 
00984         if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
00985                 goto nla_put_failure;
00986 
00987         if (tmpl->ce_mask & LINK_ATTR_ADDR)
00988                 NLA_PUT_ADDR(msg, IFLA_ADDRESS, tmpl->l_addr);
00989 
00990         if (tmpl->ce_mask & LINK_ATTR_BRD)
00991                 NLA_PUT_ADDR(msg, IFLA_BROADCAST, tmpl->l_bcast);
00992 
00993         if (tmpl->ce_mask & LINK_ATTR_MTU)
00994                 NLA_PUT_U32(msg, IFLA_MTU, tmpl->l_mtu);
00995 
00996         if (tmpl->ce_mask & LINK_ATTR_TXQLEN)
00997                 NLA_PUT_U32(msg, IFLA_TXQLEN, tmpl->l_txqlen);
00998 
00999         if (tmpl->ce_mask & LINK_ATTR_WEIGHT)
01000                 NLA_PUT_U32(msg, IFLA_WEIGHT, tmpl->l_weight);
01001 
01002         if (tmpl->ce_mask & LINK_ATTR_IFNAME)
01003                 NLA_PUT_STRING(msg, IFLA_IFNAME, tmpl->l_name);
01004 
01005         if (tmpl->ce_mask & LINK_ATTR_OPERSTATE)
01006                 NLA_PUT_U8(msg, IFLA_OPERSTATE, tmpl->l_operstate);
01007 
01008         if (tmpl->ce_mask & LINK_ATTR_LINKMODE)
01009                 NLA_PUT_U8(msg, IFLA_LINKMODE, tmpl->l_linkmode);
01010 
01011         if ((tmpl->ce_mask & LINK_ATTR_LINKINFO) && tmpl->l_info_ops &&
01012             tmpl->l_info_ops->io_put_attrs) {
01013                 struct nlattr *info;
01014 
01015                 if (!(info = nla_nest_start(msg, IFLA_LINKINFO)))
01016                         goto nla_put_failure;
01017 
01018                 NLA_PUT_STRING(msg, IFLA_INFO_KIND, tmpl->l_info_ops->io_name);
01019 
01020                 if (tmpl->l_info_ops->io_put_attrs(msg, tmpl) < 0)
01021                         goto nla_put_failure;
01022 
01023                 nla_nest_end(msg, info);
01024         }
01025 
01026         return msg;
01027 
01028 nla_put_failure:
01029         nlmsg_free(msg);
01030         return NULL;
01031 }
01032 
01033 /**
01034  * Change link attributes
01035  * @arg handle          netlink handle
01036  * @arg old             link to be changed
01037  * @arg tmpl            template with requested changes
01038  * @arg flags           additional netlink message flags
01039  *
01040  * Builds a new netlink message by calling rtnl_link_build_change_request(),
01041  * sends the request to the kernel and waits for the next ACK to be
01042  * received, i.e. blocks until the request has been processed.
01043  *
01044  * @return 0 on success or a negative error code
01045  * @note Not all attributes can be changed, see
01046  *       \ref link_changeable "Changeable Attributes" for more details.
01047  */
01048 int rtnl_link_change(struct nl_handle *handle, struct rtnl_link *old,
01049                      struct rtnl_link *tmpl, int flags)
01050 {
01051         int err;
01052         struct nl_msg *msg;
01053         
01054         msg = rtnl_link_build_change_request(old, tmpl, flags);
01055         if (!msg)
01056                 return nl_errno(ENOMEM);
01057         
01058         err = nl_send_auto_complete(handle, msg);
01059         if (err < 0)
01060                 return err;
01061 
01062         nlmsg_free(msg);
01063         return nl_wait_for_ack(handle);
01064 }
01065 
01066 /** @} */
01067 
01068 /**
01069  * @name Name <-> Index Translations
01070  * @{
01071  */
01072 
01073 /**
01074  * Translate an interface index to the corresponding link name
01075  * @arg cache           link cache
01076  * @arg ifindex         link interface index
01077  * @arg dst             destination buffer
01078  * @arg len             length of destination buffer
01079  *
01080  * Translates the specified interface index to the corresponding
01081  * link name and stores the name in the destination buffer.
01082  *
01083  * @return link name or NULL if no match was found.
01084  */
01085 char * rtnl_link_i2name(struct nl_cache *cache, int ifindex, char *dst,
01086                         size_t len)
01087 {
01088         struct rtnl_link *link = rtnl_link_get(cache, ifindex);
01089 
01090         if (link) {
01091                 strncpy(dst, link->l_name, len - 1);
01092                 rtnl_link_put(link);
01093                 return dst;
01094         }
01095 
01096         return NULL;
01097 }
01098 
01099 /**
01100  * Translate a link name to the corresponding interface index
01101  * @arg cache           link cache
01102  * @arg name            link name
01103  *
01104  * @return interface index or RTNL_LINK_NOT_FOUND if no match was found.
01105  */
01106 int rtnl_link_name2i(struct nl_cache *cache, const char *name)
01107 {
01108         int ifindex = RTNL_LINK_NOT_FOUND;
01109         struct rtnl_link *link;
01110         
01111         link = rtnl_link_get_by_name(cache, name);
01112         if (link) {
01113                 ifindex = link->l_index;
01114                 rtnl_link_put(link);
01115         }
01116 
01117         return ifindex;
01118 }
01119 
01120 /** @} */
01121 
01122 /**
01123  * @name Link Flags Translations
01124  * @{
01125  */
01126 
01127 static struct trans_tbl link_flags[] = {
01128         __ADD(IFF_LOOPBACK, loopback)
01129         __ADD(IFF_BROADCAST, broadcast)
01130         __ADD(IFF_POINTOPOINT, pointopoint)
01131         __ADD(IFF_MULTICAST, multicast)
01132         __ADD(IFF_NOARP, noarp)
01133         __ADD(IFF_ALLMULTI, allmulti)
01134         __ADD(IFF_PROMISC, promisc)
01135         __ADD(IFF_MASTER, master)
01136         __ADD(IFF_SLAVE, slave)
01137         __ADD(IFF_DEBUG, debug)
01138         __ADD(IFF_DYNAMIC, dynamic)
01139         __ADD(IFF_AUTOMEDIA, automedia)
01140         __ADD(IFF_PORTSEL, portsel)
01141         __ADD(IFF_NOTRAILERS, notrailers)
01142         __ADD(IFF_UP, up)
01143         __ADD(IFF_RUNNING, running)
01144         __ADD(IFF_LOWER_UP, lowerup)
01145         __ADD(IFF_DORMANT, dormant)
01146         __ADD(IFF_ECHO, echo)
01147 };
01148 
01149 char * rtnl_link_flags2str(int flags, char *buf, size_t len)
01150 {
01151         return __flags2str(flags, buf, len, link_flags,
01152                            ARRAY_SIZE(link_flags));
01153 }
01154 
01155 int rtnl_link_str2flags(const char *name)
01156 {
01157         return __str2flags(name, link_flags, ARRAY_SIZE(link_flags));
01158 }
01159 
01160 /** @} */
01161 
01162 /**
01163  * @name Link Statistics Translations
01164  * @{
01165  */
01166 
01167 static struct trans_tbl link_stats[] = {
01168         __ADD(RTNL_LINK_RX_PACKETS, rx_packets)
01169         __ADD(RTNL_LINK_TX_PACKETS, tx_packets)
01170         __ADD(RTNL_LINK_RX_BYTES, rx_bytes)
01171         __ADD(RTNL_LINK_TX_BYTES, tx_bytes)
01172         __ADD(RTNL_LINK_RX_ERRORS, rx_errors)
01173         __ADD(RTNL_LINK_TX_ERRORS, tx_errors)
01174         __ADD(RTNL_LINK_RX_DROPPED, rx_dropped)
01175         __ADD(RTNL_LINK_TX_DROPPED, tx_dropped)
01176         __ADD(RTNL_LINK_RX_COMPRESSED, rx_compressed)
01177         __ADD(RTNL_LINK_TX_COMPRESSED, tx_compressed)
01178         __ADD(RTNL_LINK_RX_FIFO_ERR, rx_fifo_err)
01179         __ADD(RTNL_LINK_TX_FIFO_ERR, tx_fifo_err)
01180         __ADD(RTNL_LINK_RX_LEN_ERR, rx_len_err)
01181         __ADD(RTNL_LINK_RX_OVER_ERR, rx_over_err)
01182         __ADD(RTNL_LINK_RX_CRC_ERR, rx_crc_err)
01183         __ADD(RTNL_LINK_RX_FRAME_ERR, rx_frame_err)
01184         __ADD(RTNL_LINK_RX_MISSED_ERR, rx_missed_err)
01185         __ADD(RTNL_LINK_TX_ABORT_ERR, tx_abort_err)
01186         __ADD(RTNL_LINK_TX_CARRIER_ERR, tx_carrier_err)
01187         __ADD(RTNL_LINK_TX_HBEAT_ERR, tx_hbeat_err)
01188         __ADD(RTNL_LINK_TX_WIN_ERR, tx_win_err)
01189         __ADD(RTNL_LINK_TX_COLLISIONS, tx_collision)
01190         __ADD(RTNL_LINK_MULTICAST, multicast)
01191 };
01192 
01193 char *rtnl_link_stat2str(int st, char *buf, size_t len)
01194 {
01195         return __type2str(st, buf, len, link_stats, ARRAY_SIZE(link_stats));
01196 }
01197 
01198 int rtnl_link_str2stat(const char *name)
01199 {
01200         return __str2type(name, link_stats, ARRAY_SIZE(link_stats));
01201 }
01202 
01203 /** @} */
01204 
01205 /**
01206  * @name Link Operstate Translations
01207  * @{
01208  */
01209 
01210 static struct trans_tbl link_operstates[] = {
01211         __ADD(IF_OPER_UNKNOWN, unknown)
01212         __ADD(IF_OPER_NOTPRESENT, notpresent)
01213         __ADD(IF_OPER_DOWN, down)
01214         __ADD(IF_OPER_LOWERLAYERDOWN, lowerlayerdown)
01215         __ADD(IF_OPER_TESTING, testing)
01216         __ADD(IF_OPER_DORMANT, dormant)
01217         __ADD(IF_OPER_UP, up)
01218 };
01219 
01220 char *rtnl_link_operstate2str(int st, char *buf, size_t len)
01221 {
01222         return __type2str(st, buf, len, link_operstates,
01223                           ARRAY_SIZE(link_operstates));
01224 }
01225 
01226 int rtnl_link_str2operstate(const char *name)
01227 {
01228         return __str2type(name, link_operstates,
01229                           ARRAY_SIZE(link_operstates));
01230 }
01231 
01232 /** @} */
01233 
01234 /**
01235  * @name Link Mode Translations
01236  * @{
01237  */
01238 
01239 static struct trans_tbl link_modes[] = {
01240         __ADD(IF_LINK_MODE_DEFAULT, default)
01241         __ADD(IF_LINK_MODE_DORMANT, dormant)
01242 };
01243 
01244 char *rtnl_link_mode2str(int st, char *buf, size_t len)
01245 {
01246         return __type2str(st, buf, len, link_modes, ARRAY_SIZE(link_modes));
01247 }
01248 
01249 int rtnl_link_str2mode(const char *name)
01250 {
01251         return __str2type(name, link_modes, ARRAY_SIZE(link_modes));
01252 }
01253 
01254 /** @} */
01255 
01256 /**
01257  * @name Attributes
01258  * @{
01259  */
01260 
01261 void rtnl_link_set_qdisc(struct rtnl_link *link, const char *qdisc)
01262 {
01263         strncpy(link->l_qdisc, qdisc, sizeof(link->l_qdisc) - 1);
01264         link->ce_mask |= LINK_ATTR_QDISC;
01265 }
01266 
01267 char *rtnl_link_get_qdisc(struct rtnl_link *link)
01268 {
01269         if (link->ce_mask & LINK_ATTR_QDISC)
01270                 return link->l_qdisc;
01271         else
01272                 return NULL;
01273 }
01274 
01275 void rtnl_link_set_name(struct rtnl_link *link, const char *name)
01276 {
01277         strncpy(link->l_name, name, sizeof(link->l_name) - 1);
01278         link->ce_mask |= LINK_ATTR_IFNAME;
01279 }
01280 
01281 char *rtnl_link_get_name(struct rtnl_link *link)
01282 {
01283         if (link->ce_mask & LINK_ATTR_IFNAME)
01284                 return link->l_name;
01285         else
01286                 return NULL;
01287 }
01288 
01289 static inline void __assign_addr(struct rtnl_link *link, struct nl_addr **pos,
01290                                  struct nl_addr *new, int flag)
01291 {
01292         if (*pos)
01293                 nl_addr_put(*pos);
01294 
01295         nl_addr_get(new);
01296         *pos = new;
01297 
01298         link->ce_mask |= flag;
01299 }
01300 
01301 void rtnl_link_set_addr(struct rtnl_link *link, struct nl_addr *addr)
01302 {
01303         __assign_addr(link, &link->l_addr, addr, LINK_ATTR_ADDR);
01304 }
01305 
01306 struct nl_addr *rtnl_link_get_addr(struct rtnl_link *link)
01307 {
01308         if (link->ce_mask & LINK_ATTR_ADDR)
01309                 return link->l_addr;
01310         else
01311                 return NULL;
01312 }
01313 
01314 void rtnl_link_set_broadcast(struct rtnl_link *link, struct nl_addr *brd)
01315 {
01316         __assign_addr(link, &link->l_bcast, brd, LINK_ATTR_BRD);
01317 }
01318 
01319 struct nl_addr *rtnl_link_get_broadcast(struct rtnl_link *link)
01320 {
01321         if (link->ce_mask & LINK_ATTR_BRD)
01322                 return link->l_bcast;
01323         else
01324                 return NULL;
01325 }
01326 
01327 void rtnl_link_set_flags(struct rtnl_link *link, unsigned int flags)
01328 {
01329         link->l_flag_mask |= flags;
01330         link->l_flags |= flags;
01331         link->ce_mask |= LINK_ATTR_FLAGS;
01332 }
01333 
01334 void rtnl_link_unset_flags(struct rtnl_link *link, unsigned int flags)
01335 {
01336         link->l_flag_mask |= flags;
01337         link->l_flags &= ~flags;
01338         link->ce_mask |= LINK_ATTR_FLAGS;
01339 }
01340 
01341 unsigned int rtnl_link_get_flags(struct rtnl_link *link)
01342 {
01343         return link->l_flags;
01344 }
01345 
01346 void rtnl_link_set_family(struct rtnl_link *link, int family)
01347 {
01348         link->l_family = family;
01349         link->ce_mask |= LINK_ATTR_FAMILY;
01350 }
01351 
01352 int rtnl_link_get_family(struct rtnl_link *link)
01353 {
01354         if (link->l_family & LINK_ATTR_FAMILY)
01355                 return link->l_family;
01356         else
01357                 return AF_UNSPEC;
01358 }
01359 
01360 void rtnl_link_set_arptype(struct rtnl_link *link, unsigned int arptype)
01361 {
01362         link->l_arptype = arptype;
01363 }
01364 
01365 unsigned int rtnl_link_get_arptype(struct rtnl_link *link)
01366 {
01367         return link->l_arptype;
01368 }
01369 
01370 void rtnl_link_set_ifindex(struct rtnl_link *link, int ifindex)
01371 {
01372         link->l_index = ifindex;
01373         link->ce_mask |= LINK_ATTR_IFINDEX;
01374 }
01375 
01376 int rtnl_link_get_ifindex(struct rtnl_link *link)
01377 {
01378         if (link->ce_mask & LINK_ATTR_IFINDEX)
01379                 return link->l_index;
01380         else
01381                 return RTNL_LINK_NOT_FOUND;
01382 }
01383 
01384 void rtnl_link_set_mtu(struct rtnl_link *link, unsigned int mtu)
01385 {
01386         link->l_mtu = mtu;
01387         link->ce_mask |= LINK_ATTR_MTU;
01388 }
01389 
01390 unsigned int rtnl_link_get_mtu(struct rtnl_link *link)
01391 {
01392         if (link->ce_mask & LINK_ATTR_MTU)
01393                 return link->l_mtu;
01394         else
01395                 return 0;
01396 }
01397 
01398 void rtnl_link_set_txqlen(struct rtnl_link *link, unsigned int txqlen)
01399 {
01400         link->l_txqlen = txqlen;
01401         link->ce_mask |= LINK_ATTR_TXQLEN;
01402 }
01403 
01404 unsigned int rtnl_link_get_txqlen(struct rtnl_link *link)
01405 {
01406         if (link->ce_mask & LINK_ATTR_TXQLEN)
01407                 return link->l_txqlen;
01408         else
01409                 return UINT_MAX;
01410 }
01411 
01412 void rtnl_link_set_weight(struct rtnl_link *link, unsigned int weight)
01413 {
01414         link->l_weight = weight;
01415         link->ce_mask |= LINK_ATTR_WEIGHT;
01416 }
01417 
01418 unsigned int rtnl_link_get_weight(struct rtnl_link *link)
01419 {
01420         if (link->ce_mask & LINK_ATTR_WEIGHT)
01421                 return link->l_weight;
01422         else
01423                 return UINT_MAX;
01424 }
01425 
01426 void rtnl_link_set_link(struct rtnl_link *link, int ifindex)
01427 {
01428         link->l_link = ifindex;
01429         link->ce_mask |= LINK_ATTR_LINK;
01430 }
01431 
01432 int rtnl_link_get_link(struct rtnl_link *link)
01433 {
01434         if (link->ce_mask & LINK_ATTR_LINK)
01435                 return link->l_link;
01436         else
01437                 return RTNL_LINK_NOT_FOUND;
01438 }
01439 
01440 void rtnl_link_set_master(struct rtnl_link *link, int ifindex)
01441 {
01442         link->l_master = ifindex;
01443         link->ce_mask |= LINK_ATTR_MASTER;
01444 }
01445 
01446 int rtnl_link_get_master(struct rtnl_link *link)
01447 {
01448         if (link->ce_mask & LINK_ATTR_MASTER)
01449                 return link->l_master;
01450         else
01451                 return RTNL_LINK_NOT_FOUND;
01452 }
01453 
01454 void rtnl_link_set_operstate(struct rtnl_link *link, uint8_t operstate)
01455 {
01456         link->l_operstate = operstate;
01457         link->ce_mask |= LINK_ATTR_OPERSTATE;
01458 }
01459 
01460 uint8_t rtnl_link_get_operstate(struct rtnl_link *link)
01461 {
01462         if (link->ce_mask & LINK_ATTR_OPERSTATE)
01463                 return link->l_operstate;
01464         else
01465                 return IF_OPER_UNKNOWN;
01466 }
01467 
01468 void rtnl_link_set_linkmode(struct rtnl_link *link, uint8_t linkmode)
01469 {
01470         link->l_linkmode = linkmode;
01471         link->ce_mask |= LINK_ATTR_LINKMODE;
01472 }
01473 
01474 uint8_t rtnl_link_get_linkmode(struct rtnl_link *link)
01475 {
01476         if (link->ce_mask & LINK_ATTR_LINKMODE)
01477                 return link->l_linkmode;
01478         else
01479                 return IF_LINK_MODE_DEFAULT;
01480 }
01481 
01482 uint64_t rtnl_link_get_stat(struct rtnl_link *link, int id)
01483 {
01484         if (id < 0 || id > RTNL_LINK_STATS_MAX)
01485                 return 0;
01486 
01487         return link->l_stats[id];
01488 }
01489 
01490 /**
01491  * Specify the info type of a link
01492  * @arg link    link object
01493  * @arg type    info type
01494  *
01495  * Looks up the info type and prepares the link to store info type
01496  * specific attributes. If an info type has been assigned already
01497  * it will be released with all changes lost.
01498  *
01499  * @return 0 on success or a negative errror code.
01500  */
01501 int rtnl_link_set_info_type(struct rtnl_link *link, const char *type)
01502 {
01503         struct rtnl_link_info_ops *io;
01504         int err;
01505 
01506         if ((io = rtnl_link_info_ops_lookup(type)) == NULL)
01507                 return nl_error(ENOENT, "No such link info type exists");
01508 
01509         if (link->l_info_ops)
01510                 release_link_info(link);
01511 
01512         if ((err = io->io_alloc(link)) < 0)
01513                 return err;
01514 
01515         link->l_info_ops = io;
01516 
01517         return 0;
01518 }
01519 
01520 /**
01521  * Return info type of a link
01522  * @arg link    link object
01523  *
01524  * @note The returned pointer is only valid as long as the link exists
01525  * @return Info type name or NULL if unknown.
01526  */
01527 char *rtnl_link_get_info_type(struct rtnl_link *link)
01528 {
01529         if (link->l_info_ops)
01530                 return link->l_info_ops->io_name;
01531         else
01532                 return NULL;
01533 }
01534 
01535 /** @} */
01536 
01537 static struct nl_object_ops link_obj_ops = {
01538         .oo_name                = "route/link",
01539         .oo_size                = sizeof(struct rtnl_link),
01540         .oo_free_data           = link_free_data,
01541         .oo_clone               = link_clone,
01542         .oo_dump[NL_DUMP_BRIEF] = link_dump_brief,
01543         .oo_dump[NL_DUMP_FULL]  = link_dump_full,
01544         .oo_dump[NL_DUMP_STATS] = link_dump_stats,
01545         .oo_dump[NL_DUMP_XML]   = link_dump_xml,
01546         .oo_dump[NL_DUMP_ENV]   = link_dump_env,
01547         .oo_compare             = link_compare,
01548         .oo_attrs2str           = link_attrs2str,
01549         .oo_id_attrs            = LINK_ATTR_IFINDEX,
01550 };
01551 
01552 static struct nl_af_group link_groups[] = {
01553         { AF_UNSPEC,    RTNLGRP_LINK },
01554         { END_OF_GROUP_LIST },
01555 };
01556 
01557 static struct nl_cache_ops rtnl_link_ops = {
01558         .co_name                = "route/link",
01559         .co_hdrsize             = sizeof(struct ifinfomsg),
01560         .co_msgtypes            = {
01561                                         { RTM_NEWLINK, NL_ACT_NEW, "new" },
01562                                         { RTM_DELLINK, NL_ACT_DEL, "del" },
01563                                         { RTM_GETLINK, NL_ACT_GET, "get" },
01564                                         END_OF_MSGTYPES_LIST,
01565                                   },
01566         .co_protocol            = NETLINK_ROUTE,
01567         .co_groups              = link_groups,
01568         .co_request_update      = link_request_update,
01569         .co_msg_parser          = link_msg_parser,
01570         .co_obj_ops             = &link_obj_ops,
01571 };
01572 
01573 static void __init link_init(void)
01574 {
01575         nl_cache_mngt_register(&rtnl_link_ops);
01576 }
01577 
01578 static void __exit link_exit(void)
01579 {
01580         nl_cache_mngt_unregister(&rtnl_link_ops);
01581 }
01582 
01583 /** @} */