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-2010 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, 0);
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/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 #define LINK_ATTR_IFALIAS   0x80000
00180 #define LINK_ATTR_NUM_VF   0x100000
00181 
00182 static struct nl_cache_ops rtnl_link_ops;
00183 static struct nl_object_ops link_obj_ops;
00184 /** @endcond */
00185 
00186 static struct rtnl_link_af_ops *af_lookup_and_alloc(struct rtnl_link *link,
00187                                                     int family)
00188 {
00189         struct rtnl_link_af_ops *af_ops;
00190         void *data;
00191 
00192         af_ops = rtnl_link_af_ops_lookup(family);
00193         if (!af_ops)
00194                 return NULL;
00195 
00196         if (!(data = rtnl_link_af_alloc(link, af_ops)))
00197                 return NULL;
00198 
00199         return af_ops;
00200 }
00201 
00202 static int af_free(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
00203                     void *data, void *arg)
00204 {
00205         if (ops->ao_free)
00206                 ops->ao_free(link, data);
00207 
00208         rtnl_link_af_ops_put(ops);
00209 
00210         return 0;
00211 }
00212 
00213 static int af_clone(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
00214                     void *data, void *arg)
00215 {
00216         struct rtnl_link *dst = arg;
00217 
00218         if (ops->ao_clone &&
00219             !(dst->l_af_data[ops->ao_family] = ops->ao_clone(link, data)))
00220                 return -NLE_NOMEM;
00221 
00222         return 0;
00223 }
00224 
00225 static int af_fill(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
00226                    void *data, void *arg)
00227 {
00228         struct nl_msg *msg = arg;
00229         struct nlattr *af_attr;
00230         int err;
00231 
00232         if (!ops->ao_fill_af)
00233                 return 0;
00234 
00235         if (!(af_attr = nla_nest_start(msg, ops->ao_family)))
00236                 return -NLE_MSGSIZE;
00237 
00238         if ((err = ops->ao_fill_af(link, arg, data)) < 0)
00239                 return err;
00240 
00241         nla_nest_end(msg, af_attr);
00242 
00243         return 0;
00244 }
00245 
00246 static int af_dump_line(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
00247                          void *data, void *arg)
00248 {
00249         struct nl_dump_params *p = arg;
00250 
00251         if (ops->ao_dump[NL_DUMP_LINE])
00252                 ops->ao_dump[NL_DUMP_LINE](link, p, data);
00253 
00254         return 0;
00255 }
00256 
00257 static int af_dump_details(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
00258                            void *data, void *arg)
00259 {
00260         struct nl_dump_params *p = arg;
00261 
00262         if (ops->ao_dump[NL_DUMP_DETAILS])
00263                 ops->ao_dump[NL_DUMP_DETAILS](link, p, data);
00264 
00265         return 0;
00266 }
00267 
00268 static int af_dump_stats(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
00269                          void *data, void *arg)
00270 {
00271         struct nl_dump_params *p = arg;
00272 
00273         if (ops->ao_dump[NL_DUMP_STATS])
00274                 ops->ao_dump[NL_DUMP_STATS](link, p, data);
00275 
00276         return 0;
00277 }
00278 
00279 static int do_foreach_af(struct rtnl_link *link,
00280                          int (*cb)(struct rtnl_link *,
00281                                    struct rtnl_link_af_ops *, void *, void *),
00282                          void *arg)
00283 {
00284         int i, err;
00285 
00286         for (i = 0; i < AF_MAX; i++) {
00287                 if (link->l_af_data[i]) {
00288                         struct rtnl_link_af_ops *ops;
00289 
00290                         if (!(ops = rtnl_link_af_ops_lookup(i)))
00291                                 BUG();
00292 
00293                         if ((err = cb(link, ops, link->l_af_data[i], arg)) < 0)
00294                                 return err;
00295                 }
00296         }
00297 
00298         return 0;
00299 }
00300 
00301 static void release_link_info(struct rtnl_link *link)
00302 {
00303         struct rtnl_link_info_ops *io = link->l_info_ops;
00304 
00305         if (io != NULL) {
00306                 io->io_free(link);
00307                 rtnl_link_info_ops_put(io);
00308                 link->l_info_ops = NULL;
00309         }
00310 }
00311 
00312 static void link_free_data(struct nl_object *c)
00313 {
00314         struct rtnl_link *link = nl_object_priv(c);
00315 
00316         if (link) {
00317                 struct rtnl_link_info_ops *io;
00318 
00319                 if ((io = link->l_info_ops) != NULL)
00320                         release_link_info(link);
00321 
00322                 nl_addr_put(link->l_addr);
00323                 nl_addr_put(link->l_bcast);
00324 
00325                 free(link->l_ifalias);
00326 
00327                 do_foreach_af(link, af_free, NULL);
00328         }
00329 }
00330 
00331 static int link_clone(struct nl_object *_dst, struct nl_object *_src)
00332 {
00333         struct rtnl_link *dst = nl_object_priv(_dst);
00334         struct rtnl_link *src = nl_object_priv(_src);
00335         int err;
00336 
00337         if (src->l_addr)
00338                 if (!(dst->l_addr = nl_addr_clone(src->l_addr)))
00339                         return -NLE_NOMEM;
00340 
00341         if (src->l_bcast)
00342                 if (!(dst->l_bcast = nl_addr_clone(src->l_bcast)))
00343                         return -NLE_NOMEM;
00344 
00345         if (src->l_ifalias)
00346                 if (!(dst->l_ifalias = strdup(src->l_ifalias)))
00347                         return -NLE_NOMEM;
00348 
00349         if (src->l_info_ops && src->l_info_ops->io_clone) {
00350                 err = src->l_info_ops->io_clone(dst, src);
00351                 if (err < 0)
00352                         return err;
00353         }
00354 
00355         if ((err = do_foreach_af(src, af_clone, dst)) < 0)
00356                 return err;
00357 
00358         return 0;
00359 }
00360 
00361 static struct nla_policy link_policy[IFLA_MAX+1] = {
00362         [IFLA_IFNAME]   = { .type = NLA_STRING,
00363                             .maxlen = IFNAMSIZ },
00364         [IFLA_MTU]      = { .type = NLA_U32 },
00365         [IFLA_TXQLEN]   = { .type = NLA_U32 },
00366         [IFLA_LINK]     = { .type = NLA_U32 },
00367         [IFLA_WEIGHT]   = { .type = NLA_U32 },
00368         [IFLA_MASTER]   = { .type = NLA_U32 },
00369         [IFLA_OPERSTATE]= { .type = NLA_U8 },
00370         [IFLA_LINKMODE] = { .type = NLA_U8 },
00371         [IFLA_LINKINFO] = { .type = NLA_NESTED },
00372         [IFLA_QDISC]    = { .type = NLA_STRING,
00373                             .maxlen = IFQDISCSIZ },
00374         [IFLA_STATS]    = { .minlen = sizeof(struct rtnl_link_stats) },
00375         [IFLA_STATS64]  = { .minlen = sizeof(struct rtnl_link_stats64) },
00376         [IFLA_MAP]      = { .minlen = sizeof(struct rtnl_link_ifmap) },
00377         [IFLA_IFALIAS]  = { .type = NLA_STRING, .maxlen = IFALIASZ },
00378         [IFLA_NUM_VF]   = { .type = NLA_U32 },
00379         [IFLA_AF_SPEC]  = { .type = NLA_NESTED },
00380 };
00381 
00382 static struct nla_policy link_info_policy[IFLA_INFO_MAX+1] = {
00383         [IFLA_INFO_KIND]        = { .type = NLA_STRING },
00384         [IFLA_INFO_DATA]        = { .type = NLA_NESTED },
00385         [IFLA_INFO_XSTATS]      = { .type = NLA_NESTED },
00386 };
00387 
00388 static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
00389                            struct nlmsghdr *n, struct nl_parser_param *pp)
00390 {
00391         struct rtnl_link *link;
00392         struct ifinfomsg *ifi;
00393         struct nlattr *tb[IFLA_MAX+1];
00394         struct rtnl_link_af_ops *af_ops = NULL;
00395         int err, family;
00396 
00397         link = rtnl_link_alloc();
00398         if (link == NULL) {
00399                 err = -NLE_NOMEM;
00400                 goto errout;
00401         }
00402                 
00403         link->ce_msgtype = n->nlmsg_type;
00404 
00405         if (!nlmsg_valid_hdr(n, sizeof(*ifi)))
00406                 return -NLE_MSG_TOOSHORT;
00407 
00408         ifi = nlmsg_data(n);
00409         link->l_family = family = ifi->ifi_family;
00410         link->l_arptype = ifi->ifi_type;
00411         link->l_index = ifi->ifi_index;
00412         link->l_flags = ifi->ifi_flags;
00413         link->l_change = ifi->ifi_change;
00414         link->ce_mask = (LINK_ATTR_IFNAME | LINK_ATTR_FAMILY |
00415                           LINK_ATTR_ARPTYPE| LINK_ATTR_IFINDEX |
00416                           LINK_ATTR_FLAGS | LINK_ATTR_CHANGE);
00417 
00418         if ((af_ops = af_lookup_and_alloc(link, family))) {
00419                 if (af_ops->ao_protinfo_policy) {
00420                         memcpy(&link_policy[IFLA_PROTINFO],
00421                                af_ops->ao_protinfo_policy,
00422                                sizeof(struct nla_policy));
00423                 }
00424         }
00425 
00426         err = nlmsg_parse(n, sizeof(*ifi), tb, IFLA_MAX, link_policy);
00427         if (err < 0)
00428                 goto errout;
00429 
00430         if (tb[IFLA_IFNAME] == NULL) {
00431                 err = -NLE_MISSING_ATTR;
00432                 goto errout;
00433         }
00434 
00435         nla_strlcpy(link->l_name, tb[IFLA_IFNAME], IFNAMSIZ);
00436 
00437 
00438         if (tb[IFLA_STATS]) {
00439                 struct rtnl_link_stats *st = nla_data(tb[IFLA_STATS]);
00440 
00441                 link->l_stats[RTNL_LINK_RX_PACKETS]     = st->rx_packets;
00442                 link->l_stats[RTNL_LINK_TX_PACKETS]     = st->tx_packets;
00443                 link->l_stats[RTNL_LINK_RX_BYTES]       = st->rx_bytes;
00444                 link->l_stats[RTNL_LINK_TX_BYTES]       = st->tx_bytes;
00445                 link->l_stats[RTNL_LINK_RX_ERRORS]      = st->rx_errors;
00446                 link->l_stats[RTNL_LINK_TX_ERRORS]      = st->tx_errors;
00447                 link->l_stats[RTNL_LINK_RX_DROPPED]     = st->rx_dropped;
00448                 link->l_stats[RTNL_LINK_TX_DROPPED]     = st->tx_dropped;
00449                 link->l_stats[RTNL_LINK_MULTICAST]      = st->multicast;
00450                 link->l_stats[RTNL_LINK_COLLISIONS]     = st->collisions;
00451 
00452                 link->l_stats[RTNL_LINK_RX_LEN_ERR]     = st->rx_length_errors;
00453                 link->l_stats[RTNL_LINK_RX_OVER_ERR]    = st->rx_over_errors;
00454                 link->l_stats[RTNL_LINK_RX_CRC_ERR]     = st->rx_crc_errors;
00455                 link->l_stats[RTNL_LINK_RX_FRAME_ERR]   = st->rx_frame_errors;
00456                 link->l_stats[RTNL_LINK_RX_FIFO_ERR]    = st->rx_fifo_errors;
00457                 link->l_stats[RTNL_LINK_RX_MISSED_ERR]  = st->rx_missed_errors;
00458 
00459                 link->l_stats[RTNL_LINK_TX_ABORT_ERR]   = st->tx_aborted_errors;
00460                 link->l_stats[RTNL_LINK_TX_CARRIER_ERR] = st->tx_carrier_errors;
00461                 link->l_stats[RTNL_LINK_TX_FIFO_ERR]    = st->tx_fifo_errors;
00462                 link->l_stats[RTNL_LINK_TX_HBEAT_ERR]   = st->tx_heartbeat_errors;
00463                 link->l_stats[RTNL_LINK_TX_WIN_ERR]     = st->tx_window_errors;
00464 
00465                 link->l_stats[RTNL_LINK_RX_COMPRESSED]  = st->rx_compressed;
00466                 link->l_stats[RTNL_LINK_TX_COMPRESSED]  = st->tx_compressed;
00467 
00468                 link->ce_mask |= LINK_ATTR_STATS;
00469         }
00470 
00471         if (tb[IFLA_STATS64]) {
00472                 struct rtnl_link_stats64 *st = nla_data(tb[IFLA_STATS64]);
00473                 
00474                 link->l_stats[RTNL_LINK_RX_PACKETS]     = st->rx_packets;
00475                 link->l_stats[RTNL_LINK_TX_PACKETS]     = st->tx_packets;
00476                 link->l_stats[RTNL_LINK_RX_BYTES]       = st->rx_bytes;
00477                 link->l_stats[RTNL_LINK_TX_BYTES]       = st->tx_bytes;
00478                 link->l_stats[RTNL_LINK_RX_ERRORS]      = st->rx_errors;
00479                 link->l_stats[RTNL_LINK_TX_ERRORS]      = st->tx_errors;
00480                 link->l_stats[RTNL_LINK_RX_DROPPED]     = st->rx_dropped;
00481                 link->l_stats[RTNL_LINK_TX_DROPPED]     = st->tx_dropped;
00482                 link->l_stats[RTNL_LINK_MULTICAST]      = st->multicast;
00483                 link->l_stats[RTNL_LINK_COLLISIONS]     = st->collisions;
00484 
00485                 link->l_stats[RTNL_LINK_RX_LEN_ERR]     = st->rx_length_errors;
00486                 link->l_stats[RTNL_LINK_RX_OVER_ERR]    = st->rx_over_errors;
00487                 link->l_stats[RTNL_LINK_RX_CRC_ERR]     = st->rx_crc_errors;
00488                 link->l_stats[RTNL_LINK_RX_FRAME_ERR]   = st->rx_frame_errors;
00489                 link->l_stats[RTNL_LINK_RX_FIFO_ERR]    = st->rx_fifo_errors;
00490                 link->l_stats[RTNL_LINK_RX_MISSED_ERR]  = st->rx_missed_errors;
00491 
00492                 link->l_stats[RTNL_LINK_TX_ABORT_ERR]   = st->tx_aborted_errors;
00493                 link->l_stats[RTNL_LINK_TX_CARRIER_ERR] = st->tx_carrier_errors;
00494                 link->l_stats[RTNL_LINK_TX_FIFO_ERR]    = st->tx_fifo_errors;
00495                 link->l_stats[RTNL_LINK_TX_HBEAT_ERR]   = st->tx_heartbeat_errors;
00496                 link->l_stats[RTNL_LINK_TX_WIN_ERR]     = st->tx_window_errors;
00497 
00498                 link->l_stats[RTNL_LINK_RX_COMPRESSED]  = st->rx_compressed;
00499                 link->l_stats[RTNL_LINK_TX_COMPRESSED]  = st->tx_compressed;
00500 
00501                 link->ce_mask |= LINK_ATTR_STATS;
00502         }
00503 
00504         if (tb[IFLA_TXQLEN]) {
00505                 link->l_txqlen = nla_get_u32(tb[IFLA_TXQLEN]);
00506                 link->ce_mask |= LINK_ATTR_TXQLEN;
00507         }
00508 
00509         if (tb[IFLA_MTU]) {
00510                 link->l_mtu = nla_get_u32(tb[IFLA_MTU]);
00511                 link->ce_mask |= LINK_ATTR_MTU;
00512         }
00513 
00514         if (tb[IFLA_ADDRESS]) {
00515                 link->l_addr = nl_addr_alloc_attr(tb[IFLA_ADDRESS], AF_UNSPEC);
00516                 if (link->l_addr == NULL) {
00517                         err = -NLE_NOMEM;
00518                         goto errout;
00519                 }
00520                 nl_addr_set_family(link->l_addr,
00521                                    nl_addr_guess_family(link->l_addr));
00522                 link->ce_mask |= LINK_ATTR_ADDR;
00523         }
00524 
00525         if (tb[IFLA_BROADCAST]) {
00526                 link->l_bcast = nl_addr_alloc_attr(tb[IFLA_BROADCAST],
00527                                                    AF_UNSPEC);
00528                 if (link->l_bcast == NULL) {
00529                         err = -NLE_NOMEM;
00530                         goto errout;
00531                 }
00532                 nl_addr_set_family(link->l_bcast,
00533                                    nl_addr_guess_family(link->l_bcast));
00534                 link->ce_mask |= LINK_ATTR_BRD;
00535         }
00536 
00537         if (tb[IFLA_LINK]) {
00538                 link->l_link = nla_get_u32(tb[IFLA_LINK]);
00539                 link->ce_mask |= LINK_ATTR_LINK;
00540         }
00541 
00542         if (tb[IFLA_WEIGHT]) {
00543                 link->l_weight = nla_get_u32(tb[IFLA_WEIGHT]);
00544                 link->ce_mask |= LINK_ATTR_WEIGHT;
00545         }
00546 
00547         if (tb[IFLA_QDISC]) {
00548                 nla_strlcpy(link->l_qdisc, tb[IFLA_QDISC], IFQDISCSIZ);
00549                 link->ce_mask |= LINK_ATTR_QDISC;
00550         }
00551 
00552         if (tb[IFLA_MAP]) {
00553                 nla_memcpy(&link->l_map, tb[IFLA_MAP], 
00554                            sizeof(struct rtnl_link_ifmap));
00555                 link->ce_mask |= LINK_ATTR_MAP;
00556         }
00557 
00558         if (tb[IFLA_MASTER]) {
00559                 link->l_master = nla_get_u32(tb[IFLA_MASTER]);
00560                 link->ce_mask |= LINK_ATTR_MASTER;
00561         }
00562 
00563         if (tb[IFLA_OPERSTATE]) {
00564                 link->l_operstate = nla_get_u8(tb[IFLA_OPERSTATE]);
00565                 link->ce_mask |= LINK_ATTR_OPERSTATE;
00566         }
00567 
00568         if (tb[IFLA_LINKMODE]) {
00569                 link->l_linkmode = nla_get_u8(tb[IFLA_LINKMODE]);
00570                 link->ce_mask |= LINK_ATTR_LINKMODE;
00571         }
00572 
00573         if (tb[IFLA_IFALIAS]) {
00574                 link->l_ifalias = nla_strdup(tb[IFLA_IFALIAS]);
00575                 if (link->l_ifalias == NULL) {
00576                         err = -NLE_NOMEM;
00577                         goto errout;
00578                 }
00579                 link->ce_mask |= LINK_ATTR_IFALIAS;
00580         }
00581 
00582         if (tb[IFLA_NUM_VF]) {
00583                 link->l_num_vf = nla_get_u32(tb[IFLA_NUM_VF]);
00584                 link->ce_mask |= LINK_ATTR_NUM_VF;
00585         }
00586 
00587         if (tb[IFLA_LINKINFO]) {
00588                 struct nlattr *li[IFLA_INFO_MAX+1];
00589 
00590                 err = nla_parse_nested(li, IFLA_INFO_MAX, tb[IFLA_LINKINFO],
00591                                        link_info_policy);
00592                 if (err < 0)
00593                         goto errout;
00594 
00595                 if (li[IFLA_INFO_KIND] &&
00596                     (li[IFLA_INFO_DATA] || li[IFLA_INFO_XSTATS])) {
00597                         struct rtnl_link_info_ops *ops;
00598                         char *kind;
00599 
00600                         kind = nla_get_string(li[IFLA_INFO_KIND]);
00601                         ops = rtnl_link_info_ops_lookup(kind);
00602                         if (ops != NULL) {
00603                                 link->l_info_ops = ops;
00604                                 err = ops->io_parse(link, li[IFLA_INFO_DATA],
00605                                                     li[IFLA_INFO_XSTATS]);
00606                                 if (err < 0)
00607                                         goto errout;
00608                         } else {
00609                                 /* XXX: Warn about unparsed info? */
00610                         }
00611                 }
00612         }
00613 
00614         if (tb[IFLA_PROTINFO] && af_ops && af_ops->ao_parse_protinfo) {
00615                 err = af_ops->ao_parse_protinfo(link, tb[IFLA_PROTINFO],
00616                                                 link->l_af_data[link->l_family]);
00617                 if (err < 0)
00618                         goto errout;
00619         }
00620 
00621         if (tb[IFLA_AF_SPEC]) {
00622                 struct nlattr *af_attr;
00623                 int remaining;
00624 
00625                 nla_for_each_nested(af_attr, tb[IFLA_AF_SPEC], remaining) {
00626                         af_ops = af_lookup_and_alloc(link, nla_type(af_attr));
00627                         if (af_ops && af_ops->ao_parse_af) {
00628                                 char *af_data = link->l_af_data[nla_type(af_attr)];
00629 
00630                                 err = af_ops->ao_parse_af(link, af_attr, af_data);
00631 
00632                                 rtnl_link_af_ops_put(af_ops);
00633 
00634                                 if (err < 0)
00635                                         goto errout;
00636                         }
00637 
00638                 }
00639         }
00640 
00641         err = pp->pp_cb((struct nl_object *) link, pp);
00642 errout:
00643         rtnl_link_af_ops_put(af_ops);
00644         rtnl_link_put(link);
00645         return err;
00646 }
00647 
00648 static int link_request_update(struct nl_cache *cache, struct nl_sock *sk)
00649 {
00650         int family = cache->c_iarg1;
00651 
00652         return nl_rtgen_request(sk, RTM_GETLINK, family, NLM_F_DUMP);
00653 }
00654 
00655 static void link_dump_line(struct nl_object *obj, struct nl_dump_params *p)
00656 {
00657         char buf[128];
00658         struct nl_cache *cache = dp_cache(obj);
00659         struct rtnl_link *link = (struct rtnl_link *) obj;
00660 
00661         nl_dump_line(p, "%s %s ", link->l_name,
00662                      nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
00663 
00664         if (link->l_addr && !nl_addr_iszero(link->l_addr))
00665                 nl_dump(p, "%s ", nl_addr2str(link->l_addr, buf, sizeof(buf)));
00666 
00667         if (link->ce_mask & LINK_ATTR_MASTER) {
00668                 struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
00669                 nl_dump(p, "master %s ", master ? master->l_name : "inv");
00670                 if (master)
00671                         rtnl_link_put(master);
00672         }
00673 
00674         rtnl_link_flags2str(link->l_flags, buf, sizeof(buf));
00675         if (buf[0])
00676                 nl_dump(p, "<%s> ", buf);
00677 
00678         if (link->ce_mask & LINK_ATTR_LINK) {
00679                 struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
00680                 nl_dump(p, "slave-of %s ", ll ? ll->l_name : "NONE");
00681                 if (ll)
00682                         rtnl_link_put(ll);
00683         }
00684 
00685         if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_LINE])
00686                 link->l_info_ops->io_dump[NL_DUMP_LINE](link, p);
00687 
00688         do_foreach_af(link, af_dump_line, p);
00689 
00690         nl_dump(p, "\n");
00691 }
00692 
00693 static void link_dump_details(struct nl_object *obj, struct nl_dump_params *p)
00694 {
00695         struct rtnl_link *link = (struct rtnl_link *) obj;
00696         char buf[64];
00697 
00698         link_dump_line(obj, p);
00699 
00700         nl_dump_line(p, "    mtu %u ", link->l_mtu);
00701         nl_dump(p, "txqlen %u weight %u ", link->l_txqlen, link->l_weight);
00702 
00703         if (link->ce_mask & LINK_ATTR_QDISC)
00704                 nl_dump(p, "qdisc %s ", link->l_qdisc);
00705 
00706         if (link->ce_mask & LINK_ATTR_MAP && link->l_map.lm_irq)
00707                 nl_dump(p, "irq %u ", link->l_map.lm_irq);
00708 
00709         if (link->ce_mask & LINK_ATTR_IFINDEX)
00710                 nl_dump(p, "index %u ", link->l_index);
00711 
00712 
00713         nl_dump(p, "\n");
00714 
00715         if (link->ce_mask & LINK_ATTR_IFALIAS)
00716                 nl_dump_line(p, "    alias %s\n", link->l_ifalias);
00717 
00718         nl_dump_line(p, "    ");
00719 
00720         if (link->ce_mask & LINK_ATTR_BRD)
00721                 nl_dump(p, "brd %s ", nl_addr2str(link->l_bcast, buf,
00722                                                    sizeof(buf)));
00723 
00724         if ((link->ce_mask & LINK_ATTR_OPERSTATE) &&
00725             link->l_operstate != IF_OPER_UNKNOWN) {
00726                 rtnl_link_operstate2str(link->l_operstate, buf, sizeof(buf));
00727                 nl_dump(p, "state %s ", buf);
00728         }
00729 
00730         if (link->ce_mask & LINK_ATTR_NUM_VF)
00731                 nl_dump(p, "num-vf %u ", link->l_num_vf);
00732 
00733         nl_dump(p, "mode %s\n",
00734                 rtnl_link_mode2str(link->l_linkmode, buf, sizeof(buf)));
00735 
00736         if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_DETAILS])
00737                 link->l_info_ops->io_dump[NL_DUMP_DETAILS](link, p);
00738 
00739         do_foreach_af(link, af_dump_details, p);
00740 }
00741 
00742 static void link_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
00743 {
00744         struct rtnl_link *link = (struct rtnl_link *) obj;
00745         char *unit, fmt[64];
00746         float res;
00747         
00748         link_dump_details(obj, p);
00749 
00750         nl_dump_line(p, "    Stats:    bytes    packets     errors "
00751                         "   dropped   fifo-err compressed\n");
00752 
00753         res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_RX_BYTES], &unit);
00754 
00755         strcpy(fmt, "     RX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n");
00756         fmt[9] = *unit == 'B' ? '9' : '7';
00757         
00758         nl_dump_line(p, fmt, res, unit,
00759                 link->l_stats[RTNL_LINK_RX_PACKETS],
00760                 link->l_stats[RTNL_LINK_RX_ERRORS],
00761                 link->l_stats[RTNL_LINK_RX_DROPPED],
00762                 link->l_stats[RTNL_LINK_RX_FIFO_ERR],
00763                 link->l_stats[RTNL_LINK_RX_COMPRESSED]);
00764 
00765         res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_TX_BYTES], &unit);
00766 
00767         strcpy(fmt, "     TX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n");
00768         fmt[9] = *unit == 'B' ? '9' : '7';
00769         
00770         nl_dump_line(p, fmt, res, unit,
00771                 link->l_stats[RTNL_LINK_TX_PACKETS],
00772                 link->l_stats[RTNL_LINK_TX_ERRORS],
00773                 link->l_stats[RTNL_LINK_TX_DROPPED],
00774                 link->l_stats[RTNL_LINK_TX_FIFO_ERR],
00775                 link->l_stats[RTNL_LINK_TX_COMPRESSED]);
00776 
00777         nl_dump_line(p, "    Errors:  length       over        crc "
00778                         "     frame     missed  multicast\n");
00779 
00780         nl_dump_line(p, "     RX  %10" PRIu64 " %10" PRIu64 " %10"
00781                                 PRIu64 " %10" PRIu64 " %10" PRIu64 " %10"
00782                                 PRIu64 "\n",
00783                 link->l_stats[RTNL_LINK_RX_LEN_ERR],
00784                 link->l_stats[RTNL_LINK_RX_OVER_ERR],
00785                 link->l_stats[RTNL_LINK_RX_CRC_ERR],
00786                 link->l_stats[RTNL_LINK_RX_FRAME_ERR],
00787                 link->l_stats[RTNL_LINK_RX_MISSED_ERR],
00788                 link->l_stats[RTNL_LINK_MULTICAST]);
00789 
00790         nl_dump_line(p, "            aborted    carrier  heartbeat "
00791                         "    window  collision\n");
00792         
00793         nl_dump_line(p, "     TX  %10" PRIu64 " %10" PRIu64 " %10"
00794                         PRIu64 " %10" PRIu64 " %10" PRIu64 "\n",
00795                 link->l_stats[RTNL_LINK_TX_ABORT_ERR],
00796                 link->l_stats[RTNL_LINK_TX_CARRIER_ERR],
00797                 link->l_stats[RTNL_LINK_TX_HBEAT_ERR],
00798                 link->l_stats[RTNL_LINK_TX_WIN_ERR],
00799                 link->l_stats[RTNL_LINK_COLLISIONS]);
00800 
00801         if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_STATS])
00802                 link->l_info_ops->io_dump[NL_DUMP_STATS](link, p);
00803 
00804         do_foreach_af(link, af_dump_stats, p);
00805 }
00806 
00807 #if 0
00808 static int link_handle_event(struct nl_object *a, struct rtnl_link_event_cb *cb)
00809 {
00810         struct rtnl_link *l = (struct rtnl_link *) a;
00811         struct nl_cache *c = dp_cache(a);
00812         int nevents = 0;
00813 
00814         if (l->l_change == ~0U) {
00815                 if (l->ce_msgtype == RTM_NEWLINK)
00816                         cb->le_register(l);
00817                 else
00818                         cb->le_unregister(l);
00819 
00820                 return 1;
00821         }
00822 
00823         if (l->l_change & IFF_SLAVE) {
00824                 if (l->l_flags & IFF_SLAVE) {
00825                         struct rtnl_link *m = rtnl_link_get(c, l->l_master);
00826                         cb->le_new_bonding(l, m);
00827                         if (m)
00828                                 rtnl_link_put(m);
00829                 } else
00830                         cb->le_cancel_bonding(l);
00831         }
00832 
00833 #if 0
00834         if (l->l_change & IFF_UP && l->l_change & IFF_RUNNING)
00835                 dp_dump_line(p, line++, "link %s changed state to %s.\n",
00836                         l->l_name, l->l_flags & IFF_UP ? "up" : "down");
00837 
00838         if (l->l_change & IFF_PROMISC) {
00839                 dp_new_line(p, line++);
00840                 dp_dump(p, "link %s %s promiscuous mode.\n",
00841                     l->l_name, l->l_flags & IFF_PROMISC ? "entered" : "left");
00842         }
00843 
00844         if (line == 0)
00845                 dp_dump_line(p, line++, "link %s sent unknown event.\n",
00846                              l->l_name);
00847 #endif
00848 
00849         return nevents;
00850 }
00851 #endif
00852 
00853 static int link_compare(struct nl_object *_a, struct nl_object *_b,
00854                         uint32_t attrs, int flags)
00855 {
00856         struct rtnl_link *a = (struct rtnl_link *) _a;
00857         struct rtnl_link *b = (struct rtnl_link *) _b;
00858         int diff = 0;
00859 
00860 #define LINK_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, LINK_ATTR_##ATTR, a, b, EXPR)
00861 
00862         diff |= LINK_DIFF(IFINDEX,      a->l_index != b->l_index);
00863         diff |= LINK_DIFF(MTU,          a->l_mtu != b->l_mtu);
00864         diff |= LINK_DIFF(LINK,         a->l_link != b->l_link);
00865         diff |= LINK_DIFF(TXQLEN,       a->l_txqlen != b->l_txqlen);
00866         diff |= LINK_DIFF(WEIGHT,       a->l_weight != b->l_weight);
00867         diff |= LINK_DIFF(MASTER,       a->l_master != b->l_master);
00868         diff |= LINK_DIFF(FAMILY,       a->l_family != b->l_family);
00869         diff |= LINK_DIFF(OPERSTATE,    a->l_operstate != b->l_operstate);
00870         diff |= LINK_DIFF(LINKMODE,     a->l_linkmode != b->l_linkmode);
00871         diff |= LINK_DIFF(QDISC,        strcmp(a->l_qdisc, b->l_qdisc));
00872         diff |= LINK_DIFF(IFNAME,       strcmp(a->l_name, b->l_name));
00873         diff |= LINK_DIFF(ADDR,         nl_addr_cmp(a->l_addr, b->l_addr));
00874         diff |= LINK_DIFF(BRD,          nl_addr_cmp(a->l_bcast, b->l_bcast));
00875         diff |= LINK_DIFF(IFALIAS,      strcmp(a->l_ifalias, b->l_ifalias));
00876         diff |= LINK_DIFF(NUM_VF,       a->l_num_vf != b->l_num_vf);
00877 
00878         if (flags & LOOSE_COMPARISON)
00879                 diff |= LINK_DIFF(FLAGS,
00880                                   (a->l_flags ^ b->l_flags) & b->l_flag_mask);
00881         else
00882                 diff |= LINK_DIFF(FLAGS, a->l_flags != b->l_flags);
00883 
00884 #undef LINK_DIFF
00885 
00886         return diff;
00887 }
00888 
00889 static const struct trans_tbl link_attrs[] = {
00890         __ADD(LINK_ATTR_MTU, mtu)
00891         __ADD(LINK_ATTR_LINK, link)
00892         __ADD(LINK_ATTR_TXQLEN, txqlen)
00893         __ADD(LINK_ATTR_WEIGHT, weight)
00894         __ADD(LINK_ATTR_MASTER, master)
00895         __ADD(LINK_ATTR_QDISC, qdisc)
00896         __ADD(LINK_ATTR_MAP, map)
00897         __ADD(LINK_ATTR_ADDR, address)
00898         __ADD(LINK_ATTR_BRD, broadcast)
00899         __ADD(LINK_ATTR_FLAGS, flags)
00900         __ADD(LINK_ATTR_IFNAME, name)
00901         __ADD(LINK_ATTR_IFINDEX, ifindex)
00902         __ADD(LINK_ATTR_FAMILY, family)
00903         __ADD(LINK_ATTR_ARPTYPE, arptype)
00904         __ADD(LINK_ATTR_STATS, stats)
00905         __ADD(LINK_ATTR_CHANGE, change)
00906         __ADD(LINK_ATTR_OPERSTATE, operstate)
00907         __ADD(LINK_ATTR_LINKMODE, linkmode)
00908         __ADD(LINK_ATTR_IFALIAS, ifalias)
00909         __ADD(LINK_ATTR_NUM_VF, num_vf)
00910 };
00911 
00912 static char *link_attrs2str(int attrs, char *buf, size_t len)
00913 {
00914         return __flags2str(attrs, buf, len, link_attrs,
00915                            ARRAY_SIZE(link_attrs));
00916 }
00917 
00918 /**
00919  * @name Allocation/Freeing
00920  * @{
00921  */
00922 
00923 struct rtnl_link *rtnl_link_alloc(void)
00924 {
00925         return (struct rtnl_link *) nl_object_alloc(&link_obj_ops);
00926 }
00927 
00928 void rtnl_link_put(struct rtnl_link *link)
00929 {
00930         nl_object_put((struct nl_object *) link);
00931 }
00932 
00933 /** @} */
00934 
00935 /**
00936  * @name Cache Management
00937  * @{
00938  */
00939 
00940 
00941 /**
00942  * Allocate link cache and fill in all configured links.
00943  * @arg sk              Netlink socket.
00944  * @arg family          Link address family or AF_UNSPEC
00945  * @arg result          Pointer to store resulting cache.
00946  *
00947  * Allocates a new link cache, initializes it properly and updates it
00948  * to include all links currently configured in the kernel.
00949  *
00950  * @return 0 on success or a negative error code.
00951  */
00952 int rtnl_link_alloc_cache(struct nl_sock *sk, int family, struct nl_cache **result)
00953 {
00954         struct nl_cache * cache;
00955         int err;
00956         
00957         cache = nl_cache_alloc(&rtnl_link_ops);
00958         if (!cache)
00959                 return -NLE_NOMEM;
00960 
00961         cache->c_iarg1 = family;
00962         
00963         if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
00964                 nl_cache_free(cache);
00965                 return err;
00966         }
00967 
00968         *result = cache;
00969         return 0;
00970 }
00971 
00972 /**
00973  * Look up link by interface index in the provided cache
00974  * @arg cache           link cache
00975  * @arg ifindex         link interface index
00976  *
00977  * The caller owns a reference on the returned object and
00978  * must give the object back via rtnl_link_put().
00979  *
00980  * @return pointer to link inside the cache or NULL if no match was found.
00981  */
00982 struct rtnl_link *rtnl_link_get(struct nl_cache *cache, int ifindex)
00983 {
00984         struct rtnl_link *link;
00985 
00986         if (cache->c_ops != &rtnl_link_ops)
00987                 return NULL;
00988 
00989         nl_list_for_each_entry(link, &cache->c_items, ce_list) {
00990                 if (link->l_index == ifindex) {
00991                         nl_object_get((struct nl_object *) link);
00992                         return link;
00993                 }
00994         }
00995 
00996         return NULL;
00997 }
00998 
00999 /**
01000  * Look up link by link name in the provided cache
01001  * @arg cache           link cache
01002  * @arg name            link name
01003  *
01004  * The caller owns a reference on the returned object and
01005  * must give the object back via rtnl_link_put().
01006  *
01007  * @return pointer to link inside the cache or NULL if no match was found.
01008  */
01009 struct rtnl_link *rtnl_link_get_by_name(struct nl_cache *cache,
01010                                          const char *name)
01011 {
01012         struct rtnl_link *link;
01013 
01014         if (cache->c_ops != &rtnl_link_ops)
01015                 return NULL;
01016 
01017         nl_list_for_each_entry(link, &cache->c_items, ce_list) {
01018                 if (!strcmp(name, link->l_name)) {
01019                         nl_object_get((struct nl_object *) link);
01020                         return link;
01021                 }
01022         }
01023 
01024         return NULL;
01025 }
01026 
01027 /** @} */
01028 
01029 /**
01030  * @name Link Modifications
01031  * @{
01032  */
01033 
01034 /**
01035  * Builds a netlink change request message to change link attributes
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 requesting a change of link attributes.
01041  * The netlink message header isn't fully equipped with all relevant
01042  * fields and must be sent out via nl_send_auto_complete() or
01043  * supplemented as needed.
01044  * \a old must point to a link currently configured in the kernel
01045  * and \a tmpl must contain the attributes to be changed set via
01046  * \c rtnl_link_set_* functions.
01047  *
01048  * @return New netlink message
01049  * @note Not all attributes can be changed, see
01050  *       \ref link_changeable "Changeable Attributes" for more details.
01051  */
01052 int rtnl_link_build_change_request(struct rtnl_link *old,
01053                                    struct rtnl_link *tmpl, int flags,
01054                                    struct nl_msg **result)
01055 {
01056         struct nl_msg *msg;
01057         struct nlattr *af_spec;
01058         struct ifinfomsg ifi = {
01059                 .ifi_family = old->l_family,
01060                 .ifi_index = old->l_index,
01061         };
01062 
01063         if (tmpl->ce_mask & LINK_ATTR_FLAGS) {
01064                 ifi.ifi_flags = old->l_flags & ~tmpl->l_flag_mask;
01065                 ifi.ifi_flags |= tmpl->l_flags;
01066         }
01067 
01068         msg = nlmsg_alloc_simple(RTM_SETLINK, flags);
01069         if (!msg)
01070                 return -NLE_NOMEM;
01071 
01072         if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
01073                 goto nla_put_failure;
01074 
01075         if (tmpl->ce_mask & LINK_ATTR_ADDR)
01076                 NLA_PUT_ADDR(msg, IFLA_ADDRESS, tmpl->l_addr);
01077 
01078         if (tmpl->ce_mask & LINK_ATTR_BRD)
01079                 NLA_PUT_ADDR(msg, IFLA_BROADCAST, tmpl->l_bcast);
01080 
01081         if (tmpl->ce_mask & LINK_ATTR_MTU)
01082                 NLA_PUT_U32(msg, IFLA_MTU, tmpl->l_mtu);
01083 
01084         if (tmpl->ce_mask & LINK_ATTR_TXQLEN)
01085                 NLA_PUT_U32(msg, IFLA_TXQLEN, tmpl->l_txqlen);
01086 
01087         if (tmpl->ce_mask & LINK_ATTR_WEIGHT)
01088                 NLA_PUT_U32(msg, IFLA_WEIGHT, tmpl->l_weight);
01089 
01090         if (tmpl->ce_mask & LINK_ATTR_IFNAME)
01091                 NLA_PUT_STRING(msg, IFLA_IFNAME, tmpl->l_name);
01092 
01093         if (tmpl->ce_mask & LINK_ATTR_OPERSTATE)
01094                 NLA_PUT_U8(msg, IFLA_OPERSTATE, tmpl->l_operstate);
01095 
01096         if (tmpl->ce_mask & LINK_ATTR_LINKMODE)
01097                 NLA_PUT_U8(msg, IFLA_LINKMODE, tmpl->l_linkmode);
01098 
01099         if (tmpl->ce_mask & LINK_ATTR_IFALIAS)
01100                 NLA_PUT_STRING(msg, IFLA_IFALIAS, tmpl->l_ifalias);
01101 
01102         if ((tmpl->ce_mask & LINK_ATTR_LINKINFO) && tmpl->l_info_ops &&
01103             tmpl->l_info_ops->io_put_attrs) {
01104                 struct nlattr *info;
01105 
01106                 if (!(info = nla_nest_start(msg, IFLA_LINKINFO)))
01107                         goto nla_put_failure;
01108 
01109                 NLA_PUT_STRING(msg, IFLA_INFO_KIND, tmpl->l_info_ops->io_name);
01110 
01111                 if (tmpl->l_info_ops->io_put_attrs(msg, tmpl) < 0)
01112                         goto nla_put_failure;
01113 
01114                 nla_nest_end(msg, info);
01115         }
01116 
01117         if (!(af_spec = nla_nest_start(msg, IFLA_AF_SPEC)))
01118                 goto nla_put_failure;
01119 
01120         if (do_foreach_af(tmpl, af_fill, msg) < 0)
01121                 goto nla_put_failure;
01122 
01123         nla_nest_end(msg, af_spec);
01124 
01125         *result = msg;
01126         return 0;
01127 
01128 nla_put_failure:
01129         nlmsg_free(msg);
01130         return -NLE_MSGSIZE;
01131 }
01132 
01133 /**
01134  * Change link attributes
01135  * @arg sk              Netlink socket.
01136  * @arg old             link to be changed
01137  * @arg tmpl            template with requested changes
01138  * @arg flags           additional netlink message flags
01139  *
01140  * Builds a new netlink message by calling rtnl_link_build_change_request(),
01141  * sends the request to the kernel and waits for the next ACK to be
01142  * received, i.e. blocks until the request has been processed.
01143  *
01144  * @return 0 on success or a negative error code
01145  * @note Not all attributes can be changed, see
01146  *       \ref link_changeable "Changeable Attributes" for more details.
01147  */
01148 int rtnl_link_change(struct nl_sock *sk, struct rtnl_link *old,
01149                      struct rtnl_link *tmpl, int flags)
01150 {
01151         struct nl_msg *msg;
01152         int err;
01153         
01154         if ((err = rtnl_link_build_change_request(old, tmpl, flags, &msg)) < 0)
01155                 return err;
01156         
01157         err = nl_send_auto_complete(sk, msg);
01158         nlmsg_free(msg);
01159         if (err < 0)
01160                 return err;
01161 
01162         return wait_for_ack(sk);
01163 }
01164 
01165 /** @} */
01166 
01167 /**
01168  * @name Name <-> Index Translations
01169  * @{
01170  */
01171 
01172 /**
01173  * Translate an interface index to the corresponding link name
01174  * @arg cache           link cache
01175  * @arg ifindex         link interface index
01176  * @arg dst             destination buffer
01177  * @arg len             length of destination buffer
01178  *
01179  * Translates the specified interface index to the corresponding
01180  * link name and stores the name in the destination buffer.
01181  *
01182  * @return link name or NULL if no match was found.
01183  */
01184 char * rtnl_link_i2name(struct nl_cache *cache, int ifindex, char *dst,
01185                         size_t len)
01186 {
01187         struct rtnl_link *link = rtnl_link_get(cache, ifindex);
01188 
01189         if (link) {
01190                 strncpy(dst, link->l_name, len - 1);
01191                 rtnl_link_put(link);
01192                 return dst;
01193         }
01194 
01195         return NULL;
01196 }
01197 
01198 /**
01199  * Translate a link name to the corresponding interface index
01200  * @arg cache           link cache
01201  * @arg name            link name
01202  *
01203  * @return interface index or 0 if no match was found.
01204  */
01205 int rtnl_link_name2i(struct nl_cache *cache, const char *name)
01206 {
01207         int ifindex = 0;
01208         struct rtnl_link *link;
01209         
01210         link = rtnl_link_get_by_name(cache, name);
01211         if (link) {
01212                 ifindex = link->l_index;
01213                 rtnl_link_put(link);
01214         }
01215 
01216         return ifindex;
01217 }
01218 
01219 /** @} */
01220 
01221 /**
01222  * @name Link Flags Translations
01223  * @{
01224  */
01225 
01226 static const struct trans_tbl link_flags[] = {
01227         __ADD(IFF_LOOPBACK, loopback)
01228         __ADD(IFF_BROADCAST, broadcast)
01229         __ADD(IFF_POINTOPOINT, pointopoint)
01230         __ADD(IFF_MULTICAST, multicast)
01231         __ADD(IFF_NOARP, noarp)
01232         __ADD(IFF_ALLMULTI, allmulti)
01233         __ADD(IFF_PROMISC, promisc)
01234         __ADD(IFF_MASTER, master)
01235         __ADD(IFF_SLAVE, slave)
01236         __ADD(IFF_DEBUG, debug)
01237         __ADD(IFF_DYNAMIC, dynamic)
01238         __ADD(IFF_AUTOMEDIA, automedia)
01239         __ADD(IFF_PORTSEL, portsel)
01240         __ADD(IFF_NOTRAILERS, notrailers)
01241         __ADD(IFF_UP, up)
01242         __ADD(IFF_RUNNING, running)
01243         __ADD(IFF_LOWER_UP, lowerup)
01244         __ADD(IFF_DORMANT, dormant)
01245         __ADD(IFF_ECHO, echo)
01246 };
01247 
01248 char * rtnl_link_flags2str(int flags, char *buf, size_t len)
01249 {
01250         return __flags2str(flags, buf, len, link_flags,
01251                            ARRAY_SIZE(link_flags));
01252 }
01253 
01254 int rtnl_link_str2flags(const char *name)
01255 {
01256         return __str2flags(name, link_flags, ARRAY_SIZE(link_flags));
01257 }
01258 
01259 /** @} */
01260 
01261 /**
01262  * @name Link Statistics Translations
01263  * @{
01264  */
01265 
01266 static const struct trans_tbl link_stats[] = {
01267         __ADD(RTNL_LINK_RX_PACKETS, rx_packets)
01268         __ADD(RTNL_LINK_TX_PACKETS, tx_packets)
01269         __ADD(RTNL_LINK_RX_BYTES, rx_bytes)
01270         __ADD(RTNL_LINK_TX_BYTES, tx_bytes)
01271         __ADD(RTNL_LINK_RX_ERRORS, rx_errors)
01272         __ADD(RTNL_LINK_TX_ERRORS, tx_errors)
01273         __ADD(RTNL_LINK_RX_DROPPED, rx_dropped)
01274         __ADD(RTNL_LINK_TX_DROPPED, tx_dropped)
01275         __ADD(RTNL_LINK_RX_COMPRESSED, rx_compressed)
01276         __ADD(RTNL_LINK_TX_COMPRESSED, tx_compressed)
01277         __ADD(RTNL_LINK_RX_FIFO_ERR, rx_fifo_err)
01278         __ADD(RTNL_LINK_TX_FIFO_ERR, tx_fifo_err)
01279         __ADD(RTNL_LINK_RX_LEN_ERR, rx_len_err)
01280         __ADD(RTNL_LINK_RX_OVER_ERR, rx_over_err)
01281         __ADD(RTNL_LINK_RX_CRC_ERR, rx_crc_err)
01282         __ADD(RTNL_LINK_RX_FRAME_ERR, rx_frame_err)
01283         __ADD(RTNL_LINK_RX_MISSED_ERR, rx_missed_err)
01284         __ADD(RTNL_LINK_TX_ABORT_ERR, tx_abort_err)
01285         __ADD(RTNL_LINK_TX_CARRIER_ERR, tx_carrier_err)
01286         __ADD(RTNL_LINK_TX_HBEAT_ERR, tx_hbeat_err)
01287         __ADD(RTNL_LINK_TX_WIN_ERR, tx_win_err)
01288         __ADD(RTNL_LINK_COLLISIONS, collisions)
01289         __ADD(RTNL_LINK_MULTICAST, multicast)
01290         __ADD(RTNL_LINK_IP6_INPKTS, Ip6InReceives)
01291         __ADD(RTNL_LINK_IP6_INHDRERRORS, Ip6InHdrErrors)
01292         __ADD(RTNL_LINK_IP6_INTOOBIGERRORS, Ip6InTooBigErrors)
01293         __ADD(RTNL_LINK_IP6_INNOROUTES, Ip6InNoRoutes)
01294         __ADD(RTNL_LINK_IP6_INADDRERRORS, Ip6InAddrErrors)
01295         __ADD(RTNL_LINK_IP6_INUNKNOWNPROTOS, Ip6InUnknownProtos)
01296         __ADD(RTNL_LINK_IP6_INTRUNCATEDPKTS, Ip6InTruncatedPkts)
01297         __ADD(RTNL_LINK_IP6_INDISCARDS, Ip6InDiscards)
01298         __ADD(RTNL_LINK_IP6_INDELIVERS, Ip6InDelivers)
01299         __ADD(RTNL_LINK_IP6_OUTFORWDATAGRAMS, Ip6OutForwDatagrams)
01300         __ADD(RTNL_LINK_IP6_OUTPKTS, Ip6OutRequests)
01301         __ADD(RTNL_LINK_IP6_OUTDISCARDS, Ip6OutDiscards)
01302         __ADD(RTNL_LINK_IP6_OUTNOROUTES, Ip6OutNoRoutes)
01303         __ADD(RTNL_LINK_IP6_REASMTIMEOUT, Ip6ReasmTimeout)
01304         __ADD(RTNL_LINK_IP6_REASMREQDS, Ip6ReasmReqds)
01305         __ADD(RTNL_LINK_IP6_REASMOKS, Ip6ReasmOKs)
01306         __ADD(RTNL_LINK_IP6_REASMFAILS, Ip6ReasmFails)
01307         __ADD(RTNL_LINK_IP6_FRAGOKS, Ip6FragOKs)
01308         __ADD(RTNL_LINK_IP6_FRAGFAILS, Ip6FragFails)
01309         __ADD(RTNL_LINK_IP6_FRAGCREATES, Ip6FragCreates)
01310         __ADD(RTNL_LINK_IP6_INMCASTPKTS, Ip6InMcastPkts)
01311         __ADD(RTNL_LINK_IP6_OUTMCASTPKTS, Ip6OutMcastPkts)
01312         __ADD(RTNL_LINK_IP6_INBCASTPKTS, Ip6InBcastPkts)
01313         __ADD(RTNL_LINK_IP6_OUTBCASTPKTS, Ip6OutBcastPkts)
01314         __ADD(RTNL_LINK_IP6_INOCTETS, Ip6InOctets)
01315         __ADD(RTNL_LINK_IP6_OUTOCTETS, Ip6OutOctets)
01316         __ADD(RTNL_LINK_IP6_INMCASTOCTETS, Ip6InMcastOctets)
01317         __ADD(RTNL_LINK_IP6_OUTMCASTOCTETS, Ip6OutMcastOctets)
01318         __ADD(RTNL_LINK_IP6_INBCASTOCTETS, Ip6InBcastOctets)
01319         __ADD(RTNL_LINK_IP6_OUTBCASTOCTETS, Ip6OutBcastOctets)
01320         __ADD(RTNL_LINK_ICMP6_INMSGS, ICMP6_InMsgs)
01321         __ADD(RTNL_LINK_ICMP6_INERRORS, ICMP6_InErrors)
01322         __ADD(RTNL_LINK_ICMP6_OUTMSGS, ICMP6_OutMsgs)
01323         __ADD(RTNL_LINK_ICMP6_OUTERRORS, ICMP6_OutErrors)
01324 };
01325 
01326 char *rtnl_link_stat2str(int st, char *buf, size_t len)
01327 {
01328         return __type2str(st, buf, len, link_stats, ARRAY_SIZE(link_stats));
01329 }
01330 
01331 int rtnl_link_str2stat(const char *name)
01332 {
01333         return __str2type(name, link_stats, ARRAY_SIZE(link_stats));
01334 }
01335 
01336 /** @} */
01337 
01338 /**
01339  * @name Link Operstate Translations
01340  * @{
01341  */
01342 
01343 static const struct trans_tbl link_operstates[] = {
01344         __ADD(IF_OPER_UNKNOWN, unknown)
01345         __ADD(IF_OPER_NOTPRESENT, notpresent)
01346         __ADD(IF_OPER_DOWN, down)
01347         __ADD(IF_OPER_LOWERLAYERDOWN, lowerlayerdown)
01348         __ADD(IF_OPER_TESTING, testing)
01349         __ADD(IF_OPER_DORMANT, dormant)
01350         __ADD(IF_OPER_UP, up)
01351 };
01352 
01353 char *rtnl_link_operstate2str(int st, char *buf, size_t len)
01354 {
01355         return __type2str(st, buf, len, link_operstates,
01356                           ARRAY_SIZE(link_operstates));
01357 }
01358 
01359 int rtnl_link_str2operstate(const char *name)
01360 {
01361         return __str2type(name, link_operstates,
01362                           ARRAY_SIZE(link_operstates));
01363 }
01364 
01365 /** @} */
01366 
01367 /**
01368  * @name Link Mode Translations
01369  * @{
01370  */
01371 
01372 static const struct trans_tbl link_modes[] = {
01373         __ADD(IF_LINK_MODE_DEFAULT, default)
01374         __ADD(IF_LINK_MODE_DORMANT, dormant)
01375 };
01376 
01377 char *rtnl_link_mode2str(int st, char *buf, size_t len)
01378 {
01379         return __type2str(st, buf, len, link_modes, ARRAY_SIZE(link_modes));
01380 }
01381 
01382 int rtnl_link_str2mode(const char *name)
01383 {
01384         return __str2type(name, link_modes, ARRAY_SIZE(link_modes));
01385 }
01386 
01387 /** @} */
01388 
01389 /**
01390  * @name Attributes
01391  * @{
01392  */
01393 
01394 void rtnl_link_set_qdisc(struct rtnl_link *link, const char *qdisc)
01395 {
01396         strncpy(link->l_qdisc, qdisc, sizeof(link->l_qdisc) - 1);
01397         link->ce_mask |= LINK_ATTR_QDISC;
01398 }
01399 
01400 char *rtnl_link_get_qdisc(struct rtnl_link *link)
01401 {
01402         if (link->ce_mask & LINK_ATTR_QDISC)
01403                 return link->l_qdisc;
01404         else
01405                 return NULL;
01406 }
01407 
01408 void rtnl_link_set_name(struct rtnl_link *link, const char *name)
01409 {
01410         strncpy(link->l_name, name, sizeof(link->l_name) - 1);
01411         link->ce_mask |= LINK_ATTR_IFNAME;
01412 }
01413 
01414 char *rtnl_link_get_name(struct rtnl_link *link)
01415 {
01416         if (link->ce_mask & LINK_ATTR_IFNAME)
01417                 return link->l_name;
01418         else
01419                 return NULL;
01420 }
01421 
01422 static inline void __assign_addr(struct rtnl_link *link, struct nl_addr **pos,
01423                                  struct nl_addr *new, int flag)
01424 {
01425         if (*pos)
01426                 nl_addr_put(*pos);
01427 
01428         nl_addr_get(new);
01429         *pos = new;
01430 
01431         link->ce_mask |= flag;
01432 }
01433 
01434 void rtnl_link_set_addr(struct rtnl_link *link, struct nl_addr *addr)
01435 {
01436         __assign_addr(link, &link->l_addr, addr, LINK_ATTR_ADDR);
01437 }
01438 
01439 struct nl_addr *rtnl_link_get_addr(struct rtnl_link *link)
01440 {
01441         if (link->ce_mask & LINK_ATTR_ADDR)
01442                 return link->l_addr;
01443         else
01444                 return NULL;
01445 }
01446 
01447 void rtnl_link_set_broadcast(struct rtnl_link *link, struct nl_addr *brd)
01448 {
01449         __assign_addr(link, &link->l_bcast, brd, LINK_ATTR_BRD);
01450 }
01451 
01452 struct nl_addr *rtnl_link_get_broadcast(struct rtnl_link *link)
01453 {
01454         if (link->ce_mask & LINK_ATTR_BRD)
01455                 return link->l_bcast;
01456         else
01457                 return NULL;
01458 }
01459 
01460 void rtnl_link_set_flags(struct rtnl_link *link, unsigned int flags)
01461 {
01462         link->l_flag_mask |= flags;
01463         link->l_flags |= flags;
01464         link->ce_mask |= LINK_ATTR_FLAGS;
01465 }
01466 
01467 void rtnl_link_unset_flags(struct rtnl_link *link, unsigned int flags)
01468 {
01469         link->l_flag_mask |= flags;
01470         link->l_flags &= ~flags;
01471         link->ce_mask |= LINK_ATTR_FLAGS;
01472 }
01473 
01474 unsigned int rtnl_link_get_flags(struct rtnl_link *link)
01475 {
01476         return link->l_flags;
01477 }
01478 
01479 void rtnl_link_set_family(struct rtnl_link *link, int family)
01480 {
01481         link->l_family = family;
01482         link->ce_mask |= LINK_ATTR_FAMILY;
01483 }
01484 
01485 int rtnl_link_get_family(struct rtnl_link *link)
01486 {
01487         if (link->ce_mask & LINK_ATTR_FAMILY)
01488                 return link->l_family;
01489         else
01490                 return AF_UNSPEC;
01491 }
01492 
01493 void rtnl_link_set_arptype(struct rtnl_link *link, unsigned int arptype)
01494 {
01495         link->l_arptype = arptype;
01496 }
01497 
01498 unsigned int rtnl_link_get_arptype(struct rtnl_link *link)
01499 {
01500         return link->l_arptype;
01501 }
01502 
01503 void rtnl_link_set_ifindex(struct rtnl_link *link, int ifindex)
01504 {
01505         link->l_index = ifindex;
01506         link->ce_mask |= LINK_ATTR_IFINDEX;
01507 }
01508 
01509 int rtnl_link_get_ifindex(struct rtnl_link *link)
01510 {
01511         return link->l_index;
01512 }
01513 
01514 void rtnl_link_set_mtu(struct rtnl_link *link, unsigned int mtu)
01515 {
01516         link->l_mtu = mtu;
01517         link->ce_mask |= LINK_ATTR_MTU;
01518 }
01519 
01520 unsigned int rtnl_link_get_mtu(struct rtnl_link *link)
01521 {
01522         if (link->ce_mask & LINK_ATTR_MTU)
01523                 return link->l_mtu;
01524         else
01525                 return 0;
01526 }
01527 
01528 void rtnl_link_set_txqlen(struct rtnl_link *link, unsigned int txqlen)
01529 {
01530         link->l_txqlen = txqlen;
01531         link->ce_mask |= LINK_ATTR_TXQLEN;
01532 }
01533 
01534 unsigned int rtnl_link_get_txqlen(struct rtnl_link *link)
01535 {
01536         if (link->ce_mask & LINK_ATTR_TXQLEN)
01537                 return link->l_txqlen;
01538         else
01539                 return UINT_MAX;
01540 }
01541 
01542 void rtnl_link_set_weight(struct rtnl_link *link, unsigned int weight)
01543 {
01544         link->l_weight = weight;
01545         link->ce_mask |= LINK_ATTR_WEIGHT;
01546 }
01547 
01548 unsigned int rtnl_link_get_weight(struct rtnl_link *link)
01549 {
01550         if (link->ce_mask & LINK_ATTR_WEIGHT)
01551                 return link->l_weight;
01552         else
01553                 return UINT_MAX;
01554 }
01555 
01556 void rtnl_link_set_link(struct rtnl_link *link, int ifindex)
01557 {
01558         link->l_link = ifindex;
01559         link->ce_mask |= LINK_ATTR_LINK;
01560 }
01561 
01562 int rtnl_link_get_link(struct rtnl_link *link)
01563 {
01564         return link->l_link;
01565 }
01566 
01567 void rtnl_link_set_master(struct rtnl_link *link, int ifindex)
01568 {
01569         link->l_master = ifindex;
01570         link->ce_mask |= LINK_ATTR_MASTER;
01571 }
01572 
01573 int rtnl_link_get_master(struct rtnl_link *link)
01574 {
01575         return link->l_master;
01576 }
01577 
01578 void rtnl_link_set_operstate(struct rtnl_link *link, uint8_t operstate)
01579 {
01580         link->l_operstate = operstate;
01581         link->ce_mask |= LINK_ATTR_OPERSTATE;
01582 }
01583 
01584 uint8_t rtnl_link_get_operstate(struct rtnl_link *link)
01585 {
01586         if (link->ce_mask & LINK_ATTR_OPERSTATE)
01587                 return link->l_operstate;
01588         else
01589                 return IF_OPER_UNKNOWN;
01590 }
01591 
01592 void rtnl_link_set_linkmode(struct rtnl_link *link, uint8_t linkmode)
01593 {
01594         link->l_linkmode = linkmode;
01595         link->ce_mask |= LINK_ATTR_LINKMODE;
01596 }
01597 
01598 uint8_t rtnl_link_get_linkmode(struct rtnl_link *link)
01599 {
01600         if (link->ce_mask & LINK_ATTR_LINKMODE)
01601                 return link->l_linkmode;
01602         else
01603                 return IF_LINK_MODE_DEFAULT;
01604 }
01605 
01606 /**
01607  * Return alias name of link (SNMP IfAlias)
01608  * @arg link            Link object
01609  *
01610  * @return Alias name or NULL if not set.
01611  */
01612 const char *rtnl_link_get_ifalias(struct rtnl_link *link)
01613 {
01614         return link->l_ifalias;
01615 }
01616 
01617 /**
01618  * Set alias name of link (SNMP IfAlias)
01619  * @arg link            Link object
01620  * @arg alias           Alias name or NULL to unset
01621  *
01622  * Sets the alias name of the link to the specified name. The alias
01623  * name can be unset by specyfing NULL as the alias. The name will
01624  * be strdup()ed, so no need to provide a persistent character string.
01625  */
01626 void rtnl_link_set_ifalias(struct rtnl_link *link, const char *alias)
01627 {
01628         free(link->l_ifalias);
01629         link->ce_mask &= ~LINK_ATTR_IFALIAS;
01630 
01631         if (alias) {
01632                 link->l_ifalias = strdup(alias);
01633                 link->ce_mask |= LINK_ATTR_IFALIAS;
01634         }
01635 }
01636 
01637 /**
01638  * Retrieve number of PCI VFs of link
01639  * @arg link            Link object
01640  * @arg num_vf          Pointer to store number of VFs
01641  *
01642  * @return 0 if value is available or -NLE_OPNOTSUPP if not.
01643  */
01644 int rtnl_link_get_num_vf(struct rtnl_link *link, uint32_t *num_vf)
01645 {
01646         if (link->ce_mask & LINK_ATTR_NUM_VF) {
01647                 *num_vf = link->l_num_vf;
01648                 return 0;
01649         } else
01650                 return -NLE_OPNOTSUPP;
01651 }
01652 
01653 uint64_t rtnl_link_get_stat(struct rtnl_link *link, int id)
01654 {
01655         if (id < 0 || id > RTNL_LINK_STATS_MAX)
01656                 return 0;
01657 
01658         return link->l_stats[id];
01659 }
01660 
01661 /**
01662  * Set value of a link statistics counter
01663  * @arg link            Link object
01664  * @arg id              Counter ID
01665  * @arg value           New value
01666  *
01667  * @return 0 on success or a negative error code
01668  */
01669 int rtnl_link_set_stat(struct rtnl_link *link, const unsigned int id,
01670                        const uint64_t value)
01671 {
01672         if (id > RTNL_LINK_STATS_MAX)
01673                 return -NLE_INVAL;
01674 
01675         link->l_stats[id] = value;
01676 
01677         return 0;
01678 }
01679 
01680 /**
01681  * Specify the info type of a link
01682  * @arg link    link object
01683  * @arg type    info type
01684  *
01685  * Looks up the info type and prepares the link to store info type
01686  * specific attributes. If an info type has been assigned already
01687  * it will be released with all changes lost.
01688  *
01689  * @return 0 on success or a negative errror code.
01690  */
01691 int rtnl_link_set_info_type(struct rtnl_link *link, const char *type)
01692 {
01693         struct rtnl_link_info_ops *io;
01694         int err;
01695 
01696         if ((io = rtnl_link_info_ops_lookup(type)) == NULL)
01697                 return -NLE_OPNOTSUPP;
01698 
01699         if (link->l_info_ops)
01700                 release_link_info(link);
01701 
01702         if ((err = io->io_alloc(link)) < 0)
01703                 return err;
01704 
01705         link->l_info_ops = io;
01706 
01707         return 0;
01708 }
01709 
01710 /**
01711  * Return info type of a link
01712  * @arg link    link object
01713  *
01714  * @note The returned pointer is only valid as long as the link exists
01715  * @return Info type name or NULL if unknown.
01716  */
01717 char *rtnl_link_get_info_type(struct rtnl_link *link)
01718 {
01719         if (link->l_info_ops)
01720                 return link->l_info_ops->io_name;
01721         else
01722                 return NULL;
01723 }
01724 
01725 /** @} */
01726 
01727 static struct nl_object_ops link_obj_ops = {
01728         .oo_name                = "route/link",
01729         .oo_size                = sizeof(struct rtnl_link),
01730         .oo_free_data           = link_free_data,
01731         .oo_clone               = link_clone,
01732         .oo_dump = {
01733             [NL_DUMP_LINE]      = link_dump_line,
01734             [NL_DUMP_DETAILS]   = link_dump_details,
01735             [NL_DUMP_STATS]     = link_dump_stats,
01736         },
01737         .oo_compare             = link_compare,
01738         .oo_attrs2str           = link_attrs2str,
01739         .oo_id_attrs            = LINK_ATTR_IFINDEX,
01740 };
01741 
01742 static struct nl_af_group link_groups[] = {
01743         { AF_UNSPEC,    RTNLGRP_LINK },
01744         { END_OF_GROUP_LIST },
01745 };
01746 
01747 static struct nl_cache_ops rtnl_link_ops = {
01748         .co_name                = "route/link",
01749         .co_hdrsize             = sizeof(struct ifinfomsg),
01750         .co_msgtypes            = {
01751                                         { RTM_NEWLINK, NL_ACT_NEW, "new" },
01752                                         { RTM_DELLINK, NL_ACT_DEL, "del" },
01753                                         { RTM_GETLINK, NL_ACT_GET, "get" },
01754                                         { RTM_SETLINK, NL_ACT_CHANGE, "set" },
01755                                         END_OF_MSGTYPES_LIST,
01756                                   },
01757         .co_protocol            = NETLINK_ROUTE,
01758         .co_groups              = link_groups,
01759         .co_request_update      = link_request_update,
01760         .co_msg_parser          = link_msg_parser,
01761         .co_obj_ops             = &link_obj_ops,
01762 };
01763 
01764 static void __init link_init(void)
01765 {
01766         nl_cache_mngt_register(&rtnl_link_ops);
01767 }
01768 
01769 static void __exit link_exit(void)
01770 {
01771         nl_cache_mngt_unregister(&rtnl_link_ops);
01772 }
01773 
01774 /** @} */