• Main Page
  • Modules
  • Data Structures
  • Files
  • File List

/home/bifh1/cs2009q3-i386/work/libnl-1.1/lib/route/link.c

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

Generated on Mon Mar 14 2011 11:27:04 for libnl by  doxygen 1.7.1