libnl 2.0

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