libnl 3.2.7
/builddir/build/BUILD/libnl-3.2.7/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-2011 Thomas Graf <tgraf@suug.ch>
00010  */
00011 
00012 /**
00013  * @ingroup rtnl
00014  * @defgroup link Links (Interfaces)
00015  *
00016  * @details
00017  * @route_doc{route_link, Link Documentation}
00018  * @{
00019  */
00020 
00021 #include <netlink-local.h>
00022 #include <netlink/netlink.h>
00023 #include <netlink/attr.h>
00024 #include <netlink/utils.h>
00025 #include <netlink/object.h>
00026 #include <netlink/route/rtnl.h>
00027 #include <netlink/route/link.h>
00028 #include <netlink/route/link/api.h>
00029 
00030 /** @cond SKIP */
00031 #define LINK_ATTR_MTU     0x0001
00032 #define LINK_ATTR_LINK    0x0002
00033 #define LINK_ATTR_TXQLEN  0x0004
00034 #define LINK_ATTR_WEIGHT  0x0008
00035 #define LINK_ATTR_MASTER  0x0010
00036 #define LINK_ATTR_QDISC   0x0020
00037 #define LINK_ATTR_MAP     0x0040
00038 #define LINK_ATTR_ADDR    0x0080
00039 #define LINK_ATTR_BRD     0x0100
00040 #define LINK_ATTR_FLAGS   0x0200
00041 #define LINK_ATTR_IFNAME  0x0400
00042 #define LINK_ATTR_IFINDEX 0x0800
00043 #define LINK_ATTR_FAMILY  0x1000
00044 #define LINK_ATTR_ARPTYPE 0x2000
00045 #define LINK_ATTR_STATS   0x4000
00046 #define LINK_ATTR_CHANGE  0x8000
00047 #define LINK_ATTR_OPERSTATE 0x10000
00048 #define LINK_ATTR_LINKMODE  0x20000
00049 #define LINK_ATTR_LINKINFO  0x40000
00050 #define LINK_ATTR_IFALIAS   0x80000
00051 #define LINK_ATTR_NUM_VF   0x100000
00052 
00053 static struct nl_cache_ops rtnl_link_ops;
00054 static struct nl_object_ops link_obj_ops;
00055 /** @endcond */
00056 
00057 static struct rtnl_link_af_ops *af_lookup_and_alloc(struct rtnl_link *link,
00058                                                     int family)
00059 {
00060         struct rtnl_link_af_ops *af_ops;
00061         void *data;
00062 
00063         af_ops = rtnl_link_af_ops_lookup(family);
00064         if (!af_ops)
00065                 return NULL;
00066 
00067         if (!(data = rtnl_link_af_alloc(link, af_ops)))
00068                 return NULL;
00069 
00070         return af_ops;
00071 }
00072 
00073 static int af_free(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
00074                     void *data, void *arg)
00075 {
00076         if (ops->ao_free)
00077                 ops->ao_free(link, data);
00078 
00079         rtnl_link_af_ops_put(ops);
00080 
00081         return 0;
00082 }
00083 
00084 static int af_clone(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
00085                     void *data, void *arg)
00086 {
00087         struct rtnl_link *dst = arg;
00088 
00089         if (ops->ao_clone &&
00090             !(dst->l_af_data[ops->ao_family] = ops->ao_clone(dst, data)))
00091                 return -NLE_NOMEM;
00092 
00093         return 0;
00094 }
00095 
00096 static int af_fill(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
00097                    void *data, void *arg)
00098 {
00099         struct nl_msg *msg = arg;
00100         struct nlattr *af_attr;
00101         int err;
00102 
00103         if (!ops->ao_fill_af)
00104                 return 0;
00105 
00106         if (!(af_attr = nla_nest_start(msg, ops->ao_family)))
00107                 return -NLE_MSGSIZE;
00108 
00109         if ((err = ops->ao_fill_af(link, arg, data)) < 0)
00110                 return err;
00111 
00112         nla_nest_end(msg, af_attr);
00113 
00114         return 0;
00115 }
00116 
00117 static int af_dump_line(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
00118                          void *data, void *arg)
00119 {
00120         struct nl_dump_params *p = arg;
00121 
00122         if (ops->ao_dump[NL_DUMP_LINE])
00123                 ops->ao_dump[NL_DUMP_LINE](link, p, data);
00124 
00125         return 0;
00126 }
00127 
00128 static int af_dump_details(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
00129                            void *data, void *arg)
00130 {
00131         struct nl_dump_params *p = arg;
00132 
00133         if (ops->ao_dump[NL_DUMP_DETAILS])
00134                 ops->ao_dump[NL_DUMP_DETAILS](link, p, data);
00135 
00136         return 0;
00137 }
00138 
00139 static int af_dump_stats(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
00140                          void *data, void *arg)
00141 {
00142         struct nl_dump_params *p = arg;
00143 
00144         if (ops->ao_dump[NL_DUMP_STATS])
00145                 ops->ao_dump[NL_DUMP_STATS](link, p, data);
00146 
00147         return 0;
00148 }
00149 
00150 static int do_foreach_af(struct rtnl_link *link,
00151                          int (*cb)(struct rtnl_link *,
00152                                    struct rtnl_link_af_ops *, void *, void *),
00153                          void *arg)
00154 {
00155         int i, err;
00156 
00157         for (i = 0; i < AF_MAX; i++) {
00158                 if (link->l_af_data[i]) {
00159                         struct rtnl_link_af_ops *ops;
00160 
00161                         if (!(ops = rtnl_link_af_ops_lookup(i)))
00162                                 BUG();
00163 
00164                         if ((err = cb(link, ops, link->l_af_data[i], arg)) < 0)
00165                                 return err;
00166                 }
00167         }
00168 
00169         return 0;
00170 }
00171 
00172 static void release_link_info(struct rtnl_link *link)
00173 {
00174         struct rtnl_link_info_ops *io = link->l_info_ops;
00175 
00176         if (io != NULL) {
00177                 if (io->io_free)
00178                         io->io_free(link);
00179                 rtnl_link_info_ops_put(io);
00180                 link->l_info_ops = NULL;
00181         }
00182 }
00183 
00184 static void link_free_data(struct nl_object *c)
00185 {
00186         struct rtnl_link *link = nl_object_priv(c);
00187 
00188         if (link) {
00189                 struct rtnl_link_info_ops *io;
00190 
00191                 if ((io = link->l_info_ops) != NULL)
00192                         release_link_info(link);
00193 
00194                 nl_addr_put(link->l_addr);
00195                 nl_addr_put(link->l_bcast);
00196 
00197                 free(link->l_ifalias);
00198                 free(link->l_info_kind);
00199 
00200                 do_foreach_af(link, af_free, NULL);
00201         }
00202 }
00203 
00204 static int link_clone(struct nl_object *_dst, struct nl_object *_src)
00205 {
00206         struct rtnl_link *dst = nl_object_priv(_dst);
00207         struct rtnl_link *src = nl_object_priv(_src);
00208         int err;
00209 
00210         if (src->l_addr)
00211                 if (!(dst->l_addr = nl_addr_clone(src->l_addr)))
00212                         return -NLE_NOMEM;
00213 
00214         if (src->l_bcast)
00215                 if (!(dst->l_bcast = nl_addr_clone(src->l_bcast)))
00216                         return -NLE_NOMEM;
00217 
00218         if (src->l_ifalias)
00219                 if (!(dst->l_ifalias = strdup(src->l_ifalias)))
00220                         return -NLE_NOMEM;
00221 
00222         if (src->l_info_kind)
00223                 if (!(dst->l_info_kind = strdup(src->l_info_kind)))
00224                         return -NLE_NOMEM;
00225 
00226         if (src->l_info_ops && src->l_info_ops->io_clone) {
00227                 err = src->l_info_ops->io_clone(dst, src);
00228                 if (err < 0)
00229                         return err;
00230         }
00231 
00232         if ((err = do_foreach_af(src, af_clone, dst)) < 0)
00233                 return err;
00234 
00235         return 0;
00236 }
00237 
00238 static struct nla_policy link_policy[IFLA_MAX+1] = {
00239         [IFLA_IFNAME]   = { .type = NLA_STRING,
00240                             .maxlen = IFNAMSIZ },
00241         [IFLA_MTU]      = { .type = NLA_U32 },
00242         [IFLA_TXQLEN]   = { .type = NLA_U32 },
00243         [IFLA_LINK]     = { .type = NLA_U32 },
00244         [IFLA_WEIGHT]   = { .type = NLA_U32 },
00245         [IFLA_MASTER]   = { .type = NLA_U32 },
00246         [IFLA_OPERSTATE]= { .type = NLA_U8 },
00247         [IFLA_LINKMODE] = { .type = NLA_U8 },
00248         [IFLA_LINKINFO] = { .type = NLA_NESTED },
00249         [IFLA_QDISC]    = { .type = NLA_STRING,
00250                             .maxlen = IFQDISCSIZ },
00251         [IFLA_STATS]    = { .minlen = sizeof(struct rtnl_link_stats) },
00252         [IFLA_STATS64]  = { .minlen = sizeof(struct rtnl_link_stats64) },
00253         [IFLA_MAP]      = { .minlen = sizeof(struct rtnl_link_ifmap) },
00254         [IFLA_IFALIAS]  = { .type = NLA_STRING, .maxlen = IFALIASZ },
00255         [IFLA_NUM_VF]   = { .type = NLA_U32 },
00256         [IFLA_AF_SPEC]  = { .type = NLA_NESTED },
00257 };
00258 
00259 static struct nla_policy link_info_policy[IFLA_INFO_MAX+1] = {
00260         [IFLA_INFO_KIND]        = { .type = NLA_STRING },
00261         [IFLA_INFO_DATA]        = { .type = NLA_NESTED },
00262         [IFLA_INFO_XSTATS]      = { .type = NLA_NESTED },
00263 };
00264 
00265 static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
00266                            struct nlmsghdr *n, struct nl_parser_param *pp)
00267 {
00268         struct rtnl_link *link;
00269         struct ifinfomsg *ifi;
00270         struct nlattr *tb[IFLA_MAX+1];
00271         struct rtnl_link_af_ops *af_ops = NULL;
00272         int err, family;
00273 
00274         link = rtnl_link_alloc();
00275         if (link == NULL) {
00276                 err = -NLE_NOMEM;
00277                 goto errout;
00278         }
00279                 
00280         link->ce_msgtype = n->nlmsg_type;
00281 
00282         if (!nlmsg_valid_hdr(n, sizeof(*ifi)))
00283                 return -NLE_MSG_TOOSHORT;
00284 
00285         ifi = nlmsg_data(n);
00286         link->l_family = 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 ((af_ops = af_lookup_and_alloc(link, family))) {
00296                 if (af_ops->ao_protinfo_policy) {
00297                         memcpy(&link_policy[IFLA_PROTINFO],
00298                                af_ops->ao_protinfo_policy,
00299                                sizeof(struct nla_policy));
00300                 }
00301         }
00302 
00303         err = nlmsg_parse(n, sizeof(*ifi), tb, IFLA_MAX, link_policy);
00304         if (err < 0)
00305                 goto errout;
00306 
00307         if (tb[IFLA_IFNAME] == NULL) {
00308                 err = -NLE_MISSING_ATTR;
00309                 goto errout;
00310         }
00311 
00312         nla_strlcpy(link->l_name, tb[IFLA_IFNAME], IFNAMSIZ);
00313 
00314 
00315         if (tb[IFLA_STATS]) {
00316                 struct rtnl_link_stats *st = nla_data(tb[IFLA_STATS]);
00317 
00318                 link->l_stats[RTNL_LINK_RX_PACKETS]     = st->rx_packets;
00319                 link->l_stats[RTNL_LINK_TX_PACKETS]     = st->tx_packets;
00320                 link->l_stats[RTNL_LINK_RX_BYTES]       = st->rx_bytes;
00321                 link->l_stats[RTNL_LINK_TX_BYTES]       = st->tx_bytes;
00322                 link->l_stats[RTNL_LINK_RX_ERRORS]      = st->rx_errors;
00323                 link->l_stats[RTNL_LINK_TX_ERRORS]      = st->tx_errors;
00324                 link->l_stats[RTNL_LINK_RX_DROPPED]     = st->rx_dropped;
00325                 link->l_stats[RTNL_LINK_TX_DROPPED]     = st->tx_dropped;
00326                 link->l_stats[RTNL_LINK_MULTICAST]      = st->multicast;
00327                 link->l_stats[RTNL_LINK_COLLISIONS]     = st->collisions;
00328 
00329                 link->l_stats[RTNL_LINK_RX_LEN_ERR]     = st->rx_length_errors;
00330                 link->l_stats[RTNL_LINK_RX_OVER_ERR]    = st->rx_over_errors;
00331                 link->l_stats[RTNL_LINK_RX_CRC_ERR]     = st->rx_crc_errors;
00332                 link->l_stats[RTNL_LINK_RX_FRAME_ERR]   = st->rx_frame_errors;
00333                 link->l_stats[RTNL_LINK_RX_FIFO_ERR]    = st->rx_fifo_errors;
00334                 link->l_stats[RTNL_LINK_RX_MISSED_ERR]  = st->rx_missed_errors;
00335 
00336                 link->l_stats[RTNL_LINK_TX_ABORT_ERR]   = st->tx_aborted_errors;
00337                 link->l_stats[RTNL_LINK_TX_CARRIER_ERR] = st->tx_carrier_errors;
00338                 link->l_stats[RTNL_LINK_TX_FIFO_ERR]    = st->tx_fifo_errors;
00339                 link->l_stats[RTNL_LINK_TX_HBEAT_ERR]   = st->tx_heartbeat_errors;
00340                 link->l_stats[RTNL_LINK_TX_WIN_ERR]     = st->tx_window_errors;
00341 
00342                 link->l_stats[RTNL_LINK_RX_COMPRESSED]  = st->rx_compressed;
00343                 link->l_stats[RTNL_LINK_TX_COMPRESSED]  = st->tx_compressed;
00344 
00345                 link->ce_mask |= LINK_ATTR_STATS;
00346         }
00347 
00348         if (tb[IFLA_STATS64]) {
00349                 /*
00350                  * This structure contains 64bit parameters, and per the
00351                  * documentation in lib/attr.c, must not be accessed
00352                  * directly (because of alignment to 4 instead of 8).
00353                  * Therefore, copy the data to the stack and access it from
00354                  * there, where it will be aligned to 8.
00355                  */
00356                 struct rtnl_link_stats64 st;
00357 
00358                 nla_memcpy(&st, tb[IFLA_STATS64], 
00359                            sizeof(struct rtnl_link_stats64));
00360                 
00361                 link->l_stats[RTNL_LINK_RX_PACKETS]     = st.rx_packets;
00362                 link->l_stats[RTNL_LINK_TX_PACKETS]     = st.tx_packets;
00363                 link->l_stats[RTNL_LINK_RX_BYTES]       = st.rx_bytes;
00364                 link->l_stats[RTNL_LINK_TX_BYTES]       = st.tx_bytes;
00365                 link->l_stats[RTNL_LINK_RX_ERRORS]      = st.rx_errors;
00366                 link->l_stats[RTNL_LINK_TX_ERRORS]      = st.tx_errors;
00367                 link->l_stats[RTNL_LINK_RX_DROPPED]     = st.rx_dropped;
00368                 link->l_stats[RTNL_LINK_TX_DROPPED]     = st.tx_dropped;
00369                 link->l_stats[RTNL_LINK_MULTICAST]      = st.multicast;
00370                 link->l_stats[RTNL_LINK_COLLISIONS]     = st.collisions;
00371 
00372                 link->l_stats[RTNL_LINK_RX_LEN_ERR]     = st.rx_length_errors;
00373                 link->l_stats[RTNL_LINK_RX_OVER_ERR]    = st.rx_over_errors;
00374                 link->l_stats[RTNL_LINK_RX_CRC_ERR]     = st.rx_crc_errors;
00375                 link->l_stats[RTNL_LINK_RX_FRAME_ERR]   = st.rx_frame_errors;
00376                 link->l_stats[RTNL_LINK_RX_FIFO_ERR]    = st.rx_fifo_errors;
00377                 link->l_stats[RTNL_LINK_RX_MISSED_ERR]  = st.rx_missed_errors;
00378 
00379                 link->l_stats[RTNL_LINK_TX_ABORT_ERR]   = st.tx_aborted_errors;
00380                 link->l_stats[RTNL_LINK_TX_CARRIER_ERR] = st.tx_carrier_errors;
00381                 link->l_stats[RTNL_LINK_TX_FIFO_ERR]    = st.tx_fifo_errors;
00382                 link->l_stats[RTNL_LINK_TX_HBEAT_ERR]   = st.tx_heartbeat_errors;
00383                 link->l_stats[RTNL_LINK_TX_WIN_ERR]     = st.tx_window_errors;
00384 
00385                 link->l_stats[RTNL_LINK_RX_COMPRESSED]  = st.rx_compressed;
00386                 link->l_stats[RTNL_LINK_TX_COMPRESSED]  = st.tx_compressed;
00387 
00388                 link->ce_mask |= LINK_ATTR_STATS;
00389         }
00390 
00391         if (tb[IFLA_TXQLEN]) {
00392                 link->l_txqlen = nla_get_u32(tb[IFLA_TXQLEN]);
00393                 link->ce_mask |= LINK_ATTR_TXQLEN;
00394         }
00395 
00396         if (tb[IFLA_MTU]) {
00397                 link->l_mtu = nla_get_u32(tb[IFLA_MTU]);
00398                 link->ce_mask |= LINK_ATTR_MTU;
00399         }
00400 
00401         if (tb[IFLA_ADDRESS]) {
00402                 link->l_addr = nl_addr_alloc_attr(tb[IFLA_ADDRESS], AF_UNSPEC);
00403                 if (link->l_addr == NULL) {
00404                         err = -NLE_NOMEM;
00405                         goto errout;
00406                 }
00407                 nl_addr_set_family(link->l_addr,
00408                                    nl_addr_guess_family(link->l_addr));
00409                 link->ce_mask |= LINK_ATTR_ADDR;
00410         }
00411 
00412         if (tb[IFLA_BROADCAST]) {
00413                 link->l_bcast = nl_addr_alloc_attr(tb[IFLA_BROADCAST],
00414                                                    AF_UNSPEC);
00415                 if (link->l_bcast == NULL) {
00416                         err = -NLE_NOMEM;
00417                         goto errout;
00418                 }
00419                 nl_addr_set_family(link->l_bcast,
00420                                    nl_addr_guess_family(link->l_bcast));
00421                 link->ce_mask |= LINK_ATTR_BRD;
00422         }
00423 
00424         if (tb[IFLA_LINK]) {
00425                 link->l_link = nla_get_u32(tb[IFLA_LINK]);
00426                 link->ce_mask |= LINK_ATTR_LINK;
00427         }
00428 
00429         if (tb[IFLA_WEIGHT]) {
00430                 link->l_weight = nla_get_u32(tb[IFLA_WEIGHT]);
00431                 link->ce_mask |= LINK_ATTR_WEIGHT;
00432         }
00433 
00434         if (tb[IFLA_QDISC]) {
00435                 nla_strlcpy(link->l_qdisc, tb[IFLA_QDISC], IFQDISCSIZ);
00436                 link->ce_mask |= LINK_ATTR_QDISC;
00437         }
00438 
00439         if (tb[IFLA_MAP]) {
00440                 nla_memcpy(&link->l_map, tb[IFLA_MAP], 
00441                            sizeof(struct rtnl_link_ifmap));
00442                 link->ce_mask |= LINK_ATTR_MAP;
00443         }
00444 
00445         if (tb[IFLA_MASTER]) {
00446                 link->l_master = nla_get_u32(tb[IFLA_MASTER]);
00447                 link->ce_mask |= LINK_ATTR_MASTER;
00448         }
00449 
00450         if (tb[IFLA_OPERSTATE]) {
00451                 link->l_operstate = nla_get_u8(tb[IFLA_OPERSTATE]);
00452                 link->ce_mask |= LINK_ATTR_OPERSTATE;
00453         }
00454 
00455         if (tb[IFLA_LINKMODE]) {
00456                 link->l_linkmode = nla_get_u8(tb[IFLA_LINKMODE]);
00457                 link->ce_mask |= LINK_ATTR_LINKMODE;
00458         }
00459 
00460         if (tb[IFLA_IFALIAS]) {
00461                 link->l_ifalias = nla_strdup(tb[IFLA_IFALIAS]);
00462                 if (link->l_ifalias == NULL) {
00463                         err = -NLE_NOMEM;
00464                         goto errout;
00465                 }
00466                 link->ce_mask |= LINK_ATTR_IFALIAS;
00467         }
00468 
00469         if (tb[IFLA_NUM_VF]) {
00470                 link->l_num_vf = nla_get_u32(tb[IFLA_NUM_VF]);
00471                 link->ce_mask |= LINK_ATTR_NUM_VF;
00472         }
00473 
00474         if (tb[IFLA_LINKINFO]) {
00475                 struct nlattr *li[IFLA_INFO_MAX+1];
00476 
00477                 err = nla_parse_nested(li, IFLA_INFO_MAX, tb[IFLA_LINKINFO],
00478                                        link_info_policy);
00479                 if (err < 0)
00480                         goto errout;
00481 
00482                 if (li[IFLA_INFO_KIND]) {
00483                         struct rtnl_link_info_ops *ops;
00484                         char *kind;
00485 
00486                         kind = nla_strdup(li[IFLA_INFO_KIND]);
00487                         if (kind == NULL) {
00488                                 err = -NLE_NOMEM;
00489                                 goto errout;
00490                         }
00491                         link->l_info_kind = kind;
00492                         link->ce_mask |= LINK_ATTR_LINKINFO;
00493 
00494                         ops = rtnl_link_info_ops_lookup(kind);
00495                         link->l_info_ops = ops;
00496 
00497                         if (ops) {
00498                                 if (ops->io_parse &&
00499                                     (li[IFLA_INFO_DATA] || li[IFLA_INFO_XSTATS])) {
00500                                         err = ops->io_parse(link, li[IFLA_INFO_DATA],
00501                                                             li[IFLA_INFO_XSTATS]);
00502                                         if (err < 0)
00503                                                 goto errout;
00504                                 } else {
00505                                         /* XXX: Warn about unparsed info? */
00506                                 }
00507                         }
00508                 }
00509         }
00510 
00511         if (tb[IFLA_PROTINFO] && af_ops && af_ops->ao_parse_protinfo) {
00512                 err = af_ops->ao_parse_protinfo(link, tb[IFLA_PROTINFO],
00513                                                 link->l_af_data[link->l_family]);
00514                 if (err < 0)
00515                         goto errout;
00516         }
00517 
00518         if (tb[IFLA_AF_SPEC]) {
00519                 struct nlattr *af_attr;
00520                 int remaining;
00521 
00522                 nla_for_each_nested(af_attr, tb[IFLA_AF_SPEC], remaining) {
00523                         af_ops = af_lookup_and_alloc(link, nla_type(af_attr));
00524                         if (af_ops && af_ops->ao_parse_af) {
00525                                 char *af_data = link->l_af_data[nla_type(af_attr)];
00526 
00527                                 err = af_ops->ao_parse_af(link, af_attr, af_data);
00528 
00529                                 rtnl_link_af_ops_put(af_ops);
00530 
00531                                 if (err < 0)
00532                                         goto errout;
00533                         }
00534 
00535                 }
00536         }
00537 
00538         err = pp->pp_cb((struct nl_object *) link, pp);
00539 errout:
00540         rtnl_link_af_ops_put(af_ops);
00541         rtnl_link_put(link);
00542         return err;
00543 }
00544 
00545 static int link_event_filter(struct nl_cache *cache, struct nl_object *obj)
00546 {
00547         struct rtnl_link *link = (struct rtnl_link *) obj;
00548 
00549         /*
00550          * Ignore bridging messages when keeping the cache manager up to date.
00551          */
00552         if (link->l_family == AF_BRIDGE)
00553                 return NL_SKIP;
00554 
00555         return NL_OK;
00556 }
00557 
00558 static int link_request_update(struct nl_cache *cache, struct nl_sock *sk)
00559 {
00560         int family = cache->c_iarg1;
00561 
00562         return nl_rtgen_request(sk, RTM_GETLINK, family, NLM_F_DUMP);
00563 }
00564 
00565 static void link_dump_line(struct nl_object *obj, struct nl_dump_params *p)
00566 {
00567         char buf[128];
00568         struct nl_cache *cache = dp_cache(obj);
00569         struct rtnl_link *link = (struct rtnl_link *) obj;
00570 
00571         nl_dump_line(p, "%s %s ", link->l_name,
00572                      nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
00573 
00574         if (link->l_addr && !nl_addr_iszero(link->l_addr))
00575                 nl_dump(p, "%s ", nl_addr2str(link->l_addr, buf, sizeof(buf)));
00576 
00577         if (link->ce_mask & LINK_ATTR_MASTER) {
00578                 struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
00579                 nl_dump(p, "master %s ", master ? master->l_name : "inv");
00580                 if (master)
00581                         rtnl_link_put(master);
00582         }
00583 
00584         rtnl_link_flags2str(link->l_flags, buf, sizeof(buf));
00585         if (buf[0])
00586                 nl_dump(p, "<%s> ", buf);
00587 
00588         if (link->ce_mask & LINK_ATTR_LINK) {
00589                 struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
00590                 nl_dump(p, "slave-of %s ", ll ? ll->l_name : "NONE");
00591                 if (ll)
00592                         rtnl_link_put(ll);
00593         }
00594 
00595         if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_LINE])
00596                 link->l_info_ops->io_dump[NL_DUMP_LINE](link, p);
00597 
00598         do_foreach_af(link, af_dump_line, p);
00599 
00600         nl_dump(p, "\n");
00601 }
00602 
00603 static void link_dump_details(struct nl_object *obj, struct nl_dump_params *p)
00604 {
00605         struct rtnl_link *link = (struct rtnl_link *) obj;
00606         char buf[64];
00607 
00608         link_dump_line(obj, p);
00609 
00610         nl_dump_line(p, "    mtu %u ", link->l_mtu);
00611         nl_dump(p, "txqlen %u weight %u ", link->l_txqlen, link->l_weight);
00612 
00613         if (link->ce_mask & LINK_ATTR_QDISC)
00614                 nl_dump(p, "qdisc %s ", link->l_qdisc);
00615 
00616         if (link->ce_mask & LINK_ATTR_MAP && link->l_map.lm_irq)
00617                 nl_dump(p, "irq %u ", link->l_map.lm_irq);
00618 
00619         if (link->ce_mask & LINK_ATTR_IFINDEX)
00620                 nl_dump(p, "index %u ", link->l_index);
00621 
00622 
00623         nl_dump(p, "\n");
00624 
00625         if (link->ce_mask & LINK_ATTR_IFALIAS)
00626                 nl_dump_line(p, "    alias %s\n", link->l_ifalias);
00627 
00628         nl_dump_line(p, "    ");
00629 
00630         if (link->ce_mask & LINK_ATTR_BRD)
00631                 nl_dump(p, "brd %s ", nl_addr2str(link->l_bcast, buf,
00632                                                    sizeof(buf)));
00633 
00634         if ((link->ce_mask & LINK_ATTR_OPERSTATE) &&
00635             link->l_operstate != IF_OPER_UNKNOWN) {
00636                 rtnl_link_operstate2str(link->l_operstate, buf, sizeof(buf));
00637                 nl_dump(p, "state %s ", buf);
00638         }
00639 
00640         if (link->ce_mask & LINK_ATTR_NUM_VF)
00641                 nl_dump(p, "num-vf %u ", link->l_num_vf);
00642 
00643         nl_dump(p, "mode %s\n",
00644                 rtnl_link_mode2str(link->l_linkmode, buf, sizeof(buf)));
00645 
00646         if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_DETAILS])
00647                 link->l_info_ops->io_dump[NL_DUMP_DETAILS](link, p);
00648 
00649         do_foreach_af(link, af_dump_details, p);
00650 }
00651 
00652 static void link_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
00653 {
00654         struct rtnl_link *link = (struct rtnl_link *) obj;
00655         char *unit, fmt[64];
00656         float res;
00657         
00658         link_dump_details(obj, p);
00659 
00660         nl_dump_line(p, "    Stats:    bytes    packets     errors "
00661                         "   dropped   fifo-err compressed\n");
00662 
00663         res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_RX_BYTES], &unit);
00664 
00665         strcpy(fmt, "     RX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n");
00666         fmt[9] = *unit == 'B' ? '9' : '7';
00667         
00668         nl_dump_line(p, fmt, res, unit,
00669                 link->l_stats[RTNL_LINK_RX_PACKETS],
00670                 link->l_stats[RTNL_LINK_RX_ERRORS],
00671                 link->l_stats[RTNL_LINK_RX_DROPPED],
00672                 link->l_stats[RTNL_LINK_RX_FIFO_ERR],
00673                 link->l_stats[RTNL_LINK_RX_COMPRESSED]);
00674 
00675         res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_TX_BYTES], &unit);
00676 
00677         strcpy(fmt, "     TX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n");
00678         fmt[9] = *unit == 'B' ? '9' : '7';
00679         
00680         nl_dump_line(p, fmt, res, unit,
00681                 link->l_stats[RTNL_LINK_TX_PACKETS],
00682                 link->l_stats[RTNL_LINK_TX_ERRORS],
00683                 link->l_stats[RTNL_LINK_TX_DROPPED],
00684                 link->l_stats[RTNL_LINK_TX_FIFO_ERR],
00685                 link->l_stats[RTNL_LINK_TX_COMPRESSED]);
00686 
00687         nl_dump_line(p, "    Errors:  length       over        crc "
00688                         "     frame     missed  multicast\n");
00689 
00690         nl_dump_line(p, "     RX  %10" PRIu64 " %10" PRIu64 " %10"
00691                                 PRIu64 " %10" PRIu64 " %10" PRIu64 " %10"
00692                                 PRIu64 "\n",
00693                 link->l_stats[RTNL_LINK_RX_LEN_ERR],
00694                 link->l_stats[RTNL_LINK_RX_OVER_ERR],
00695                 link->l_stats[RTNL_LINK_RX_CRC_ERR],
00696                 link->l_stats[RTNL_LINK_RX_FRAME_ERR],
00697                 link->l_stats[RTNL_LINK_RX_MISSED_ERR],
00698                 link->l_stats[RTNL_LINK_MULTICAST]);
00699 
00700         nl_dump_line(p, "            aborted    carrier  heartbeat "
00701                         "    window  collision\n");
00702         
00703         nl_dump_line(p, "     TX  %10" PRIu64 " %10" PRIu64 " %10"
00704                         PRIu64 " %10" PRIu64 " %10" PRIu64 "\n",
00705                 link->l_stats[RTNL_LINK_TX_ABORT_ERR],
00706                 link->l_stats[RTNL_LINK_TX_CARRIER_ERR],
00707                 link->l_stats[RTNL_LINK_TX_HBEAT_ERR],
00708                 link->l_stats[RTNL_LINK_TX_WIN_ERR],
00709                 link->l_stats[RTNL_LINK_COLLISIONS]);
00710 
00711         if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_STATS])
00712                 link->l_info_ops->io_dump[NL_DUMP_STATS](link, p);
00713 
00714         do_foreach_af(link, af_dump_stats, p);
00715 }
00716 
00717 #if 0
00718 static int link_handle_event(struct nl_object *a, struct rtnl_link_event_cb *cb)
00719 {
00720         struct rtnl_link *l = (struct rtnl_link *) a;
00721         struct nl_cache *c = dp_cache(a);
00722         int nevents = 0;
00723 
00724         if (l->l_change == ~0U) {
00725                 if (l->ce_msgtype == RTM_NEWLINK)
00726                         cb->le_register(l);
00727                 else
00728                         cb->le_unregister(l);
00729 
00730                 return 1;
00731         }
00732 
00733         if (l->l_change & IFF_SLAVE) {
00734                 if (l->l_flags & IFF_SLAVE) {
00735                         struct rtnl_link *m = rtnl_link_get(c, l->l_master);
00736                         cb->le_new_bonding(l, m);
00737                         if (m)
00738                                 rtnl_link_put(m);
00739                 } else
00740                         cb->le_cancel_bonding(l);
00741         }
00742 
00743 #if 0
00744         if (l->l_change & IFF_UP && l->l_change & IFF_RUNNING)
00745                 dp_dump_line(p, line++, "link %s changed state to %s.\n",
00746                         l->l_name, l->l_flags & IFF_UP ? "up" : "down");
00747 
00748         if (l->l_change & IFF_PROMISC) {
00749                 dp_new_line(p, line++);
00750                 dp_dump(p, "link %s %s promiscuous mode.\n",
00751                     l->l_name, l->l_flags & IFF_PROMISC ? "entered" : "left");
00752         }
00753 
00754         if (line == 0)
00755                 dp_dump_line(p, line++, "link %s sent unknown event.\n",
00756                              l->l_name);
00757 #endif
00758 
00759         return nevents;
00760 }
00761 #endif
00762 
00763 static int link_compare(struct nl_object *_a, struct nl_object *_b,
00764                         uint32_t attrs, int flags)
00765 {
00766         struct rtnl_link *a = (struct rtnl_link *) _a;
00767         struct rtnl_link *b = (struct rtnl_link *) _b;
00768         int diff = 0;
00769 
00770 #define LINK_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, LINK_ATTR_##ATTR, a, b, EXPR)
00771 
00772         diff |= LINK_DIFF(IFINDEX,      a->l_index != b->l_index);
00773         diff |= LINK_DIFF(MTU,          a->l_mtu != b->l_mtu);
00774         diff |= LINK_DIFF(LINK,         a->l_link != b->l_link);
00775         diff |= LINK_DIFF(TXQLEN,       a->l_txqlen != b->l_txqlen);
00776         diff |= LINK_DIFF(WEIGHT,       a->l_weight != b->l_weight);
00777         diff |= LINK_DIFF(MASTER,       a->l_master != b->l_master);
00778         diff |= LINK_DIFF(FAMILY,       a->l_family != b->l_family);
00779         diff |= LINK_DIFF(OPERSTATE,    a->l_operstate != b->l_operstate);
00780         diff |= LINK_DIFF(LINKMODE,     a->l_linkmode != b->l_linkmode);
00781         diff |= LINK_DIFF(QDISC,        strcmp(a->l_qdisc, b->l_qdisc));
00782         diff |= LINK_DIFF(IFNAME,       strcmp(a->l_name, b->l_name));
00783         diff |= LINK_DIFF(ADDR,         nl_addr_cmp(a->l_addr, b->l_addr));
00784         diff |= LINK_DIFF(BRD,          nl_addr_cmp(a->l_bcast, b->l_bcast));
00785         diff |= LINK_DIFF(IFALIAS,      strcmp(a->l_ifalias, b->l_ifalias));
00786         diff |= LINK_DIFF(NUM_VF,       a->l_num_vf != b->l_num_vf);
00787 
00788         if (flags & LOOSE_COMPARISON)
00789                 diff |= LINK_DIFF(FLAGS,
00790                                   (a->l_flags ^ b->l_flags) & b->l_flag_mask);
00791         else
00792                 diff |= LINK_DIFF(FLAGS, a->l_flags != b->l_flags);
00793 
00794 #undef LINK_DIFF
00795 
00796         return diff;
00797 }
00798 
00799 static const struct trans_tbl link_attrs[] = {
00800         __ADD(LINK_ATTR_MTU, mtu)
00801         __ADD(LINK_ATTR_LINK, link)
00802         __ADD(LINK_ATTR_TXQLEN, txqlen)
00803         __ADD(LINK_ATTR_WEIGHT, weight)
00804         __ADD(LINK_ATTR_MASTER, master)
00805         __ADD(LINK_ATTR_QDISC, qdisc)
00806         __ADD(LINK_ATTR_MAP, map)
00807         __ADD(LINK_ATTR_ADDR, address)
00808         __ADD(LINK_ATTR_BRD, broadcast)
00809         __ADD(LINK_ATTR_FLAGS, flags)
00810         __ADD(LINK_ATTR_IFNAME, name)
00811         __ADD(LINK_ATTR_IFINDEX, ifindex)
00812         __ADD(LINK_ATTR_FAMILY, family)
00813         __ADD(LINK_ATTR_ARPTYPE, arptype)
00814         __ADD(LINK_ATTR_STATS, stats)
00815         __ADD(LINK_ATTR_CHANGE, change)
00816         __ADD(LINK_ATTR_OPERSTATE, operstate)
00817         __ADD(LINK_ATTR_LINKMODE, linkmode)
00818         __ADD(LINK_ATTR_IFALIAS, ifalias)
00819         __ADD(LINK_ATTR_NUM_VF, num_vf)
00820 };
00821 
00822 static char *link_attrs2str(int attrs, char *buf, size_t len)
00823 {
00824         return __flags2str(attrs, buf, len, link_attrs,
00825                            ARRAY_SIZE(link_attrs));
00826 }
00827 
00828 /**
00829  * @name Get / List
00830  * @{
00831  */
00832 
00833 
00834 /**
00835  * Allocate link cache and fill in all configured links.
00836  * @arg sk              Netlink socket.
00837  * @arg family          Link address family or AF_UNSPEC
00838  * @arg result          Pointer to store resulting cache.
00839  *
00840  * Allocates and initializes a new link cache. A netlink message is sent to
00841  * the kernel requesting a full dump of all configured links. The returned
00842  * messages are parsed and filled into the cache. If the operation succeeds
00843  * the resulting cache will a link object for each link configured in the
00844  * kernel.
00845  *
00846  * If \c family is set to an address family other than \c AF_UNSPEC the
00847  * contents of the cache can be limited to a specific address family.
00848  * Currently the following address families are supported:
00849  * - AF_BRIDGE
00850  * - AF_INET6
00851  *
00852  * @route_doc{link_list, Get List of Links}
00853  * @see rtnl_link_get()
00854  * @see rtnl_link_get_by_name()
00855  * @return 0 on success or a negative error code.
00856  */
00857 int rtnl_link_alloc_cache(struct nl_sock *sk, int family, struct nl_cache **result)
00858 {
00859         struct nl_cache * cache;
00860         int err;
00861         
00862         cache = nl_cache_alloc(&rtnl_link_ops);
00863         if (!cache)
00864                 return -NLE_NOMEM;
00865 
00866         cache->c_iarg1 = family;
00867         
00868         if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
00869                 nl_cache_free(cache);
00870                 return err;
00871         }
00872 
00873         *result = cache;
00874         return 0;
00875 }
00876 
00877 /**
00878  * Lookup link in cache by interface index
00879  * @arg cache           Link cache
00880  * @arg ifindex         Interface index
00881  *
00882  * Searches through the provided cache looking for a link with matching
00883  * interface index.
00884  *
00885  * @attention The reference counter of the returned link object will be
00886  *            incremented. Use rtnl_link_put() to release the reference.
00887  *
00888  * @route_doc{link_list, Get List of Links}
00889  * @see rtnl_link_get_by_name()
00890  * @return Link object or NULL if no match was found.
00891  */
00892 struct rtnl_link *rtnl_link_get(struct nl_cache *cache, int ifindex)
00893 {
00894         struct rtnl_link *link;
00895 
00896         if (cache->c_ops != &rtnl_link_ops)
00897                 return NULL;
00898 
00899         nl_list_for_each_entry(link, &cache->c_items, ce_list) {
00900                 if (link->l_index == ifindex) {
00901                         nl_object_get((struct nl_object *) link);
00902                         return link;
00903                 }
00904         }
00905 
00906         return NULL;
00907 }
00908 
00909 /**
00910  * Lookup link in cache by link name
00911  * @arg cache           Link cache
00912  * @arg name            Name of link
00913  *
00914  * Searches through the provided cache looking for a link with matching
00915  * link name
00916  *
00917  * @attention The reference counter of the returned link object will be
00918  *            incremented. Use rtnl_link_put() to release the reference.
00919  *
00920  * @route_doc{link_list, Get List of Links}
00921  * @see rtnl_link_get()
00922  * @return Link object or NULL if no match was found.
00923  */
00924 struct rtnl_link *rtnl_link_get_by_name(struct nl_cache *cache,
00925                                          const char *name)
00926 {
00927         struct rtnl_link *link;
00928 
00929         if (cache->c_ops != &rtnl_link_ops)
00930                 return NULL;
00931 
00932         nl_list_for_each_entry(link, &cache->c_items, ce_list) {
00933                 if (!strcmp(name, link->l_name)) {
00934                         nl_object_get((struct nl_object *) link);
00935                         return link;
00936                 }
00937         }
00938 
00939         return NULL;
00940 }
00941 
00942 /**
00943  * Construct RTM_GETLINK netlink message
00944  * @arg ifindex         Interface index
00945  * @arg name            Name of link
00946  * @arg result          Pointer to store resulting netlink message
00947  *
00948  * The behaviour of this function is identical to rtnl_link_get_kernel()
00949  * with the exception that it will not send the message but return it in
00950  * the provided return pointer instead.
00951  *
00952  * @see rtnl_link_get_kernel()
00953  *
00954  * @return 0 on success or a negative error code.
00955  */
00956 int rtnl_link_build_get_request(int ifindex, const char *name,
00957                                 struct nl_msg **result)
00958 {
00959         struct ifinfomsg ifi;
00960         struct nl_msg *msg;
00961 
00962         if (ifindex <= 0 && !name) {
00963                 APPBUG("ifindex or name must be specified");
00964                 return -NLE_MISSING_ATTR;
00965         }
00966 
00967         memset(&ifi, 0, sizeof(ifi));
00968 
00969         if (!(msg = nlmsg_alloc_simple(RTM_GETLINK, 0)))
00970                 return -NLE_NOMEM;
00971 
00972         if (ifindex > 0)
00973                 ifi.ifi_index = ifindex;
00974 
00975         if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
00976                 goto nla_put_failure;
00977 
00978         if (name)
00979                 NLA_PUT_STRING(msg, IFLA_IFNAME, name);
00980 
00981         *result = msg;
00982         return 0;
00983 
00984 nla_put_failure:
00985         nlmsg_free(msg);
00986         return -NLE_MSGSIZE;
00987 }
00988 
00989 /**
00990  * Get a link object directly from kernel
00991  * @arg sk              Netlink socket
00992  * @arg ifindex         Interface index
00993  * @arg name            Name of link
00994  * @arg result          Pointer to store resulting link object
00995  *
00996  * This function builds a \c RTM_GETLINK netlink message to request
00997  * a specific link directly from the kernel. The returned answer is
00998  * parsed into a struct rtnl_link object and returned via the result
00999  * pointer or -NLE_OBJ_NOTFOUND is returned if no matching link was
01000  * found.
01001  *
01002  * @route_doc{link_direct_lookup, Lookup Single Link (Direct Lookup)}
01003  * @return 0 on success or a negative error code.
01004  */
01005 int rtnl_link_get_kernel(struct nl_sock *sk, int ifindex, const char *name,
01006                          struct rtnl_link **result)
01007 {
01008         struct nl_msg *msg = NULL;
01009         struct nl_object *obj;
01010         int err;
01011 
01012         if ((err = rtnl_link_build_get_request(ifindex, name, &msg)) < 0)
01013                 return err;
01014 
01015         err = nl_send_auto(sk, msg);
01016         nlmsg_free(msg);
01017         if (err < 0)
01018                 return err;
01019 
01020         if ((err = nl_pickup(sk, link_msg_parser, &obj)) < 0)
01021                 return err;
01022 
01023         /* We have used link_msg_parser(), object is definitely a link */
01024         *result = (struct rtnl_link *) obj;
01025 
01026         /* If an object has been returned, we also need to wait for the ACK */
01027          if (err == 0 && obj)
01028                  nl_wait_for_ack(sk);
01029 
01030         return 0;
01031 }
01032 
01033 /**
01034  * Translate interface index to corresponding link name
01035  * @arg cache           Link cache
01036  * @arg ifindex         Interface index
01037  * @arg dst             String to store name
01038  * @arg len             Length of destination string
01039  *
01040  * Translates the specified interface index to the corresponding
01041  * link name and stores the name in the destination string.
01042  *
01043  * @route_doc{link_translate_ifindex, Translating interface index to link name}
01044  * @see rtnl_link_name2i()
01045  * @return Name of link or NULL if no match was found.
01046  */
01047 char * rtnl_link_i2name(struct nl_cache *cache, int ifindex, char *dst,
01048                         size_t len)
01049 {
01050         struct rtnl_link *link = rtnl_link_get(cache, ifindex);
01051 
01052         if (link) {
01053                 strncpy(dst, link->l_name, len - 1);
01054                 rtnl_link_put(link);
01055                 return dst;
01056         }
01057 
01058         return NULL;
01059 }
01060 
01061 /**
01062  * Translate link name to corresponding interface index
01063  * @arg cache           Link cache
01064  * @arg name            Name of link
01065  *
01066  * @route_doc{link_translate_ifindex, Translating interface index to link name}
01067  * @see rtnl_link_i2name()
01068  * @return Interface index or 0 if no match was found.
01069  */
01070 int rtnl_link_name2i(struct nl_cache *cache, const char *name)
01071 {
01072         int ifindex = 0;
01073         struct rtnl_link *link;
01074         
01075         link = rtnl_link_get_by_name(cache, name);
01076         if (link) {
01077                 ifindex = link->l_index;
01078                 rtnl_link_put(link);
01079         }
01080 
01081         return ifindex;
01082 }
01083 
01084 /** @} */
01085 
01086 static int build_link_msg(int cmd, struct ifinfomsg *hdr,
01087                           struct rtnl_link *link, int flags, struct nl_msg **result)
01088 {
01089         struct nl_msg *msg;
01090         struct nlattr *af_spec;
01091 
01092         msg = nlmsg_alloc_simple(cmd, flags);
01093         if (!msg)
01094                 return -NLE_NOMEM;
01095 
01096         if (nlmsg_append(msg, hdr, sizeof(*hdr), NLMSG_ALIGNTO) < 0)
01097                 goto nla_put_failure;
01098 
01099         if (link->ce_mask & LINK_ATTR_ADDR)
01100                 NLA_PUT_ADDR(msg, IFLA_ADDRESS, link->l_addr);
01101 
01102         if (link->ce_mask & LINK_ATTR_BRD)
01103                 NLA_PUT_ADDR(msg, IFLA_BROADCAST, link->l_bcast);
01104 
01105         if (link->ce_mask & LINK_ATTR_MTU)
01106                 NLA_PUT_U32(msg, IFLA_MTU, link->l_mtu);
01107 
01108         if (link->ce_mask & LINK_ATTR_TXQLEN)
01109                 NLA_PUT_U32(msg, IFLA_TXQLEN, link->l_txqlen);
01110 
01111         if (link->ce_mask & LINK_ATTR_WEIGHT)
01112                 NLA_PUT_U32(msg, IFLA_WEIGHT, link->l_weight);
01113 
01114         if (link->ce_mask & LINK_ATTR_IFNAME)
01115                 NLA_PUT_STRING(msg, IFLA_IFNAME, link->l_name);
01116 
01117         if (link->ce_mask & LINK_ATTR_OPERSTATE)
01118                 NLA_PUT_U8(msg, IFLA_OPERSTATE, link->l_operstate);
01119 
01120         if (link->ce_mask & LINK_ATTR_LINKMODE)
01121                 NLA_PUT_U8(msg, IFLA_LINKMODE, link->l_linkmode);
01122 
01123         if (link->ce_mask & LINK_ATTR_IFALIAS)
01124                 NLA_PUT_STRING(msg, IFLA_IFALIAS, link->l_ifalias);
01125 
01126         if (link->ce_mask & LINK_ATTR_LINK)
01127                 NLA_PUT_U32(msg, IFLA_LINK, link->l_link);
01128 
01129         if (link->ce_mask & LINK_ATTR_MASTER)
01130                 NLA_PUT_U32(msg, IFLA_MASTER, link->l_master);
01131 
01132         if (link->ce_mask & LINK_ATTR_LINKINFO) {
01133                 struct nlattr *info;
01134 
01135                 if (!(info = nla_nest_start(msg, IFLA_LINKINFO)))
01136                         goto nla_put_failure;
01137 
01138                 NLA_PUT_STRING(msg, IFLA_INFO_KIND, link->l_info_kind);
01139 
01140                 if (link->l_info_ops) {
01141                         if (link->l_info_ops->io_put_attrs &&
01142                             link->l_info_ops->io_put_attrs(msg, link) < 0)
01143                                 goto nla_put_failure;
01144                 }
01145 
01146                 nla_nest_end(msg, info);
01147         }
01148 
01149         if (!(af_spec = nla_nest_start(msg, IFLA_AF_SPEC)))
01150                 goto nla_put_failure;
01151 
01152         if (do_foreach_af(link, af_fill, msg) < 0)
01153                 goto nla_put_failure;
01154 
01155         nla_nest_end(msg, af_spec);
01156 
01157         *result = msg;
01158         return 0;
01159 
01160 nla_put_failure:
01161         nlmsg_free(msg);
01162         return -NLE_MSGSIZE;
01163 }
01164 
01165 /**
01166  * @name Add / Modify
01167  * @{
01168  */
01169 
01170 /**
01171  * Build a netlink message requesting the addition of new virtual link
01172  * @arg link            new link to add
01173  * @arg flags           additional netlink message flags
01174  * @arg result          pointer to store resulting netlink message
01175  *
01176  * The behaviour of this function is identical to rtnl_link_add() with
01177  * the exception that it will not send the message but return it in the
01178  * provided return pointer instead.
01179  *
01180  * @see rtnl_link_add()
01181  *
01182  * @note This operation is not supported on all kernel versions.
01183  *
01184  * @return 0 on success or a negative error code.
01185  */
01186 int rtnl_link_build_add_request(struct rtnl_link *link, int flags,
01187                                 struct nl_msg **result)
01188 {
01189         struct ifinfomsg ifi = {
01190                 .ifi_family = link->l_family,
01191                 .ifi_index = link->l_index,
01192                 .ifi_flags = link->l_flags,
01193         };
01194 
01195         return build_link_msg(RTM_NEWLINK, &ifi, link, flags, result);
01196 }
01197 
01198 /**
01199  * Add virtual link
01200  * @arg sk              netlink socket.
01201  * @arg link            new link to add
01202  * @arg flags           additional netlink message flags
01203  *
01204  * Builds a \c RTM_NEWLINK netlink message requesting the addition of
01205  * a new virtual link.
01206  *
01207  * After sending, the function will wait for the ACK or an eventual
01208  * error message to be received and will therefore block until the
01209  * operation has been completed.
01210  *
01211  * @copydoc auto_ack_warning
01212  *
01213  * @return 0 on success or a negative error code.
01214  */
01215 int rtnl_link_add(struct nl_sock *sk, struct rtnl_link *link, int flags)
01216 {
01217         struct nl_msg *msg;
01218         int err;
01219         
01220         err = rtnl_link_build_add_request(link, flags, &msg);
01221         if (err < 0)
01222                 return err;
01223 
01224         return nl_send_sync(sk, msg);
01225 }
01226 
01227 /**
01228  * Build a netlink message requesting the modification of link
01229  * @arg orig            original link to change
01230  * @arg changes         link containing the changes to be made
01231  * @arg flags           additional netlink message flags
01232  * @arg result          pointer to store resulting netlink message
01233  *
01234  * The behaviour of this function is identical to rtnl_link_change() with
01235  * the exception that it will not send the message but return it in the
01236  * provided return pointer instead.
01237  *
01238  * @see rtnl_link_change()
01239  *
01240  * @note The resulting message will have message type set to RTM_NEWLINK
01241  *       which may not work with older kernels. You may have to modify it
01242  *       to RTM_SETLINK (does not allow changing link info attributes) to
01243  *       have the change request work with older kernels.
01244  *
01245  * @return 0 on success or a negative error code.
01246  */
01247 int rtnl_link_build_change_request(struct rtnl_link *orig,
01248                                    struct rtnl_link *changes, int flags,
01249                                    struct nl_msg **result)
01250 {
01251         struct ifinfomsg ifi = {
01252                 .ifi_family = orig->l_family,
01253                 .ifi_index = orig->l_index,
01254         };
01255         int err;
01256 
01257         if (changes->ce_mask & LINK_ATTR_FLAGS) {
01258                 ifi.ifi_flags = orig->l_flags & ~changes->l_flag_mask;
01259                 ifi.ifi_flags |= changes->l_flags;
01260         }
01261 
01262         if (changes->l_family && changes->l_family != orig->l_family) {
01263                 APPBUG("link change: family is immutable");
01264                 return -NLE_IMMUTABLE;
01265         }
01266 
01267         /* Avoid unnecessary name change requests */
01268         if (orig->ce_mask & LINK_ATTR_IFINDEX &&
01269             orig->ce_mask & LINK_ATTR_IFNAME &&
01270             changes->ce_mask & LINK_ATTR_IFNAME &&
01271             !strcmp(orig->l_name, changes->l_name))
01272                 changes->ce_mask &= ~LINK_ATTR_IFNAME;
01273 
01274         if ((err = build_link_msg(RTM_NEWLINK, &ifi, changes, flags, result)) < 0)
01275                 goto errout;
01276 
01277         return 0;
01278 
01279 errout:
01280         return err;
01281 }
01282 
01283 /**
01284  * Change link
01285  * @arg sk              netlink socket.
01286  * @arg orig            original link to be changed
01287  * @arg changes         link containing the changes to be made
01288  * @arg flags           additional netlink message flags
01289  *
01290  * Builds a \c RTM_NEWLINK netlink message requesting the change of
01291  * a network link. If -EOPNOTSUPP is returned by the kernel, the
01292  * message type will be changed to \c RTM_SETLINK and the message is
01293  * resent to work around older kernel versions.
01294  *
01295  * The link to be changed is looked up based on the interface index
01296  * supplied in the \p orig link. Optionaly the link name is used but
01297  * only if no interface index is provided, otherwise providing an
01298  * link name will result in the link name being changed.
01299  *
01300  * If no matching link exists, the function will return
01301  * -NLE_OBJ_NOTFOUND.
01302  *
01303  * After sending, the function will wait for the ACK or an eventual
01304  * error message to be received and will therefore block until the
01305  * operation has been completed.
01306  *
01307  * @copydoc auto_ack_warning
01308  *
01309  * @note The link name can only be changed if the link has been put
01310  *       in opertional down state. (~IF_UP)
01311  *
01312  * @return 0 on success or a negative error code.
01313  */
01314 int rtnl_link_change(struct nl_sock *sk, struct rtnl_link *orig,
01315                      struct rtnl_link *changes, int flags)
01316 {
01317         struct nl_msg *msg;
01318         int err;
01319         
01320         err = rtnl_link_build_change_request(orig, changes, flags, &msg);
01321         if (err < 0)
01322                 return err;
01323 
01324 retry:
01325         err = nl_send_auto_complete(sk, msg);
01326         if (err < 0)
01327                 goto errout;
01328 
01329         err = wait_for_ack(sk);
01330         if (err == -NLE_OPNOTSUPP && msg->nm_nlh->nlmsg_type == RTM_NEWLINK) {
01331                 msg->nm_nlh->nlmsg_type = RTM_SETLINK;
01332                 goto retry;
01333         }
01334 
01335 errout:
01336         nlmsg_free(msg);
01337         return err;
01338 }
01339 
01340 /** @} */
01341 
01342 /**
01343  * @name Delete
01344  * @{
01345  */
01346 
01347 /**
01348  * Build a netlink message requesting the deletion of a link
01349  * @arg link            Link to delete
01350  * @arg result          Pointer to store resulting netlink message
01351  *
01352  * The behaviour of this function is identical to rtnl_link_delete() with
01353  * the exception that it will not send the message but return it in the
01354  * provided return pointer instead.
01355  *
01356  * @see rtnl_link_delete()
01357  *
01358  * @return 0 on success or a negative error code.
01359  */
01360 int rtnl_link_build_delete_request(const struct rtnl_link *link,
01361                                    struct nl_msg **result)
01362 {
01363         struct nl_msg *msg;
01364         struct ifinfomsg ifi = {
01365                 .ifi_index = link->l_index,
01366         };
01367 
01368         if (!(link->ce_mask & (LINK_ATTR_IFINDEX | LINK_ATTR_IFNAME))) {
01369                 APPBUG("ifindex or name must be specified");
01370                 return -NLE_MISSING_ATTR;
01371         }
01372 
01373         if (!(msg = nlmsg_alloc_simple(RTM_DELLINK, 0)))
01374                 return -NLE_NOMEM;
01375 
01376         if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
01377                 goto nla_put_failure;
01378 
01379         if (link->ce_mask & LINK_ATTR_IFNAME)
01380                 NLA_PUT_STRING(msg, IFLA_IFNAME, link->l_name);
01381 
01382         *result = msg;
01383         return 0;
01384 
01385 nla_put_failure:
01386         nlmsg_free(msg);
01387         return -NLE_MSGSIZE;
01388 }
01389 
01390 /**
01391  * Delete link
01392  * @arg sk              Netlink socket
01393  * @arg link            Link to delete
01394  *
01395  * Builds a \c RTM_DELLINK netlink message requesting the deletion of
01396  * a network link which has been previously added to the kernel and
01397  * sends the message to the kernel.
01398  *
01399  * If no matching link exists, the function will return
01400  * -NLE_OBJ_NOTFOUND.
01401  *
01402  * After sending, the function will wait for the ACK or an eventual
01403  * error message to be received and will therefore block until the
01404  * operation has been completed.
01405  *
01406  * @copydoc auto_ack_warning
01407  *
01408  * @note Only virtual links such as dummy interface or vlan interfaces
01409  *       can be deleted. It is not possible to delete physical interfaces
01410  *       such as ethernet interfaces or the loopback device.
01411  *
01412  * @return 0 on success or a negative error code.
01413  */
01414 int rtnl_link_delete(struct nl_sock *sk, const struct rtnl_link *link)
01415 {
01416         struct nl_msg *msg;
01417         int err;
01418         
01419         if ((err = rtnl_link_build_delete_request(link, &msg)) < 0)
01420                 return err;
01421 
01422         return nl_send_sync(sk, msg);
01423 }
01424 
01425 /** @} */
01426 
01427 /**
01428  * @name Link Object
01429  * @{
01430  */
01431 
01432 /**
01433  * Allocate link object
01434  *
01435  * @see rtnl_link_put()
01436  * @return New link object or NULL if allocation failed
01437  */
01438 struct rtnl_link *rtnl_link_alloc(void)
01439 {
01440         return (struct rtnl_link *) nl_object_alloc(&link_obj_ops);
01441 }
01442 
01443 /**
01444  * Return a link object reference
01445  *
01446  * @copydetails nl_object_put()
01447  */
01448 void rtnl_link_put(struct rtnl_link *link)
01449 {
01450         nl_object_put((struct nl_object *) link);
01451 }
01452 
01453 /**
01454  * Set name of link object
01455  * @arg link            Link object
01456  * @arg name            New name
01457  *
01458  * @note To change the name of a link in the kernel, set the interface
01459  *       index to the link you wish to change, modify the link name using
01460  *       this function and pass the link object to rtnl_link_change() or
01461  *       rtnl_link_add().
01462  *
01463  * @route_doc{link_attr_name, Link Name}
01464  * @see rtnl_link_get_name()
01465  * @see rtnl_link_set_ifindex()
01466  */
01467 void rtnl_link_set_name(struct rtnl_link *link, const char *name)
01468 {
01469         strncpy(link->l_name, name, sizeof(link->l_name) - 1);
01470         link->ce_mask |= LINK_ATTR_IFNAME;
01471 }
01472 
01473 /**
01474  * Return name of link object
01475  * @arg link            Link object
01476  *
01477  * @route_doc{link_attr_name, Link Name}
01478  * @see rtnl_link_set_name()
01479  * @return Link name or NULL if name is not specified
01480  */
01481 char *rtnl_link_get_name(struct rtnl_link *link)
01482 {
01483         return link->ce_mask & LINK_ATTR_IFNAME ? link->l_name : NULL;
01484 }
01485 
01486 static inline void __assign_addr(struct rtnl_link *link, struct nl_addr **pos,
01487                                  struct nl_addr *new, int flag)
01488 {
01489         if (*pos)
01490                 nl_addr_put(*pos);
01491 
01492         nl_addr_get(new);
01493         *pos = new;
01494 
01495         link->ce_mask |= flag;
01496 }
01497 
01498 /**
01499  * Set link layer address of link object
01500  * @arg link            Link object
01501  * @arg addr            New link layer address
01502  *
01503  * The function increments the reference counter of the address object
01504  * and overwrites any existing link layer address previously assigned.
01505  *
01506  * @route_doc{link_attr_address, Link layer address}
01507  * @see rtnl_link_get_addr()
01508  */
01509 void rtnl_link_set_addr(struct rtnl_link *link, struct nl_addr *addr)
01510 {
01511         __assign_addr(link, &link->l_addr, addr, LINK_ATTR_ADDR);
01512 }
01513 
01514 /**
01515  * Return link layer address of link object
01516  * @arg link            Link object
01517  *
01518  * @copydoc pointer_lifetime_warning
01519  * @route_doc{link_attr_address, Link Layer Address}
01520  * @see rtnl_link_set_addr()
01521  * @return Link layer address or NULL if not set.
01522  */
01523 struct nl_addr *rtnl_link_get_addr(struct rtnl_link *link)
01524 {
01525         return link->ce_mask & LINK_ATTR_ADDR ? link->l_addr : NULL;
01526 }
01527 
01528 /**
01529  * Set link layer broadcast address of link object
01530  * @arg link            Link object
01531  * @arg addr            New broadcast address
01532  *
01533  * The function increments the reference counter of the address object
01534  * and overwrites any existing link layer broadcast address previously
01535  * assigned.
01536  *
01537  * @route_doc{link_attr_broadcast, Link Layer Broadcast Address}
01538  * @see rtnl_link_get_broadcast()
01539  */
01540 void rtnl_link_set_broadcast(struct rtnl_link *link, struct nl_addr *addr)
01541 {
01542         __assign_addr(link, &link->l_bcast, addr, LINK_ATTR_BRD);
01543 }
01544 
01545 /**
01546  * Return link layer broadcast address of link object
01547  * @arg link            Link object
01548  *
01549  * @copydoc pointer_lifetime_warning
01550  * @route_doc{link_attr_address, Link Layer Address}
01551  * @see rtnl_link_set_broadcast()
01552  * @return Link layer address or NULL if not set.
01553  */
01554 struct nl_addr *rtnl_link_get_broadcast(struct rtnl_link *link)
01555 {
01556         return link->ce_mask & LINK_ATTR_BRD ? link->l_bcast : NULL;
01557 }
01558 
01559 /**
01560  * Set flags of link object
01561  * @arg link            Link object
01562  * @arg flags           Flags
01563  *
01564  * @see rtnl_link_get_flags()
01565  * @see rtnl_link_unset_flags()
01566  */
01567 void rtnl_link_set_flags(struct rtnl_link *link, unsigned int flags)
01568 {
01569         link->l_flag_mask |= flags;
01570         link->l_flags |= flags;
01571         link->ce_mask |= LINK_ATTR_FLAGS;
01572 }
01573 
01574 /**
01575  * Unset flags of link object
01576  * @arg link            Link object
01577  * @arg flags           Flags
01578  *
01579  * @see rtnl_link_set_flags()
01580  * @see rtnl_link_get_flags()
01581  */
01582 void rtnl_link_unset_flags(struct rtnl_link *link, unsigned int flags)
01583 {
01584         link->l_flag_mask |= flags;
01585         link->l_flags &= ~flags;
01586         link->ce_mask |= LINK_ATTR_FLAGS;
01587 }
01588 
01589 /**
01590  * Return flags of link object
01591  * @arg link            Link object
01592  *
01593  * @route_doc{link_attr_flags, Link Flags}
01594  * @see rtnl_link_set_flags()
01595  * @see rtnl_link_unset_flags()
01596  * @return Link flags or 0 if none have been set.
01597  */
01598 unsigned int rtnl_link_get_flags(struct rtnl_link *link)
01599 {
01600         return link->l_flags;
01601 }
01602 
01603 /**
01604  * Set address family of link object
01605  *
01606  * @see rtnl_link_get_family()
01607  */
01608 void rtnl_link_set_family(struct rtnl_link *link, int family)
01609 {
01610         link->l_family = family;
01611         link->ce_mask |= LINK_ATTR_FAMILY;
01612 }
01613 
01614 /**
01615  * Return address family of link object
01616  * @arg link            Link object
01617  *
01618  * @see rtnl_link_set_family()
01619  * @return Address family or \c AF_UNSPEC if not specified.
01620  */
01621 int rtnl_link_get_family(struct rtnl_link *link)
01622 {
01623         return link->ce_mask & LINK_ATTR_FAMILY ? link->l_family : AF_UNSPEC;
01624 }
01625 
01626 /**
01627  * Set hardware type of link object
01628  * @arg link            Link object
01629  * @arg arptype         New hardware type \c (ARPHRD_*)
01630  *
01631  * @route_doc{link_attr_arptype, Hardware Type}
01632  * @copydoc read_only_attribute
01633  * @see rtnl_link_get_arptype()
01634  */
01635 void rtnl_link_set_arptype(struct rtnl_link *link, unsigned int arptype)
01636 {
01637         link->l_arptype = arptype;
01638         link->ce_mask |= LINK_ATTR_ARPTYPE;
01639 }
01640 
01641 /**
01642  * Get hardware type of link object
01643  * @arg link            Link object
01644  *
01645  * @route_doc{link_attr_arptype, Hardware Type}
01646  * @see rtnl_link_set_arptype()
01647  * @return Hardware type \c (ARPHRD_ETHER *) or \c ARPHRD_VOID
01648  */
01649 unsigned int rtnl_link_get_arptype(struct rtnl_link *link)
01650 {
01651         if (link->ce_mask & LINK_ATTR_ARPTYPE)
01652                 return link->l_arptype;
01653         else
01654                 return ARPHRD_VOID;
01655 }
01656 
01657 /**
01658  * Set interface index of link object
01659  * @arg link            Link object
01660  * @arg ifindex         Interface index
01661  *
01662  * @route_doc{link_attr_ifindex, Interface Index}
01663  * @see rtnl_link_get_ifindex()
01664  */
01665 void rtnl_link_set_ifindex(struct rtnl_link *link, int ifindex)
01666 {
01667         link->l_index = ifindex;
01668         link->ce_mask |= LINK_ATTR_IFINDEX;
01669 }
01670 
01671 
01672 /**
01673  * Return interface index of link object
01674  * @arg link            Link object
01675  *
01676  * @route_doc{link_attr_ifindex, Interface Index}
01677  * @see rtnl_link_set_ifindex()
01678  * @return Interface index or 0 if not set.
01679  */
01680 int rtnl_link_get_ifindex(struct rtnl_link *link)
01681 {
01682         return link->l_index;
01683 }
01684 
01685 /**
01686  * Set Maximum Transmission Unit of link object
01687  * @arg link            Link object
01688  * @arg mtu             New MTU value in number of bytes
01689  *
01690  * @route_doc{link_attr_mtu, Maximum Transmission Unit}
01691  * @see rtnl_link_get_mtu()
01692  */
01693 void rtnl_link_set_mtu(struct rtnl_link *link, unsigned int mtu)
01694 {
01695         link->l_mtu = mtu;
01696         link->ce_mask |= LINK_ATTR_MTU;
01697 }
01698 
01699 /**
01700  * Return maximum transmission unit of link object
01701  * @arg link            Link object
01702  *
01703  * @route_doc{link_attr_mtu, Maximum Transmission Unit}
01704  * @see rtnl_link_set_mtu()
01705  * @return MTU in bytes or 0 if not set
01706  */
01707 unsigned int rtnl_link_get_mtu(struct rtnl_link *link)
01708 {
01709         return link->l_mtu;
01710 }
01711 
01712 /**
01713  * Set transmission queue length
01714  * @arg link            Link object
01715  * @arg txqlen          New queue length
01716  *
01717  * The unit is dependant on the link type. The most common units is number
01718  * of packets.
01719  *
01720  * @route_doc{link_attr_txqlen, Transmission Queue Length}
01721  */
01722 void rtnl_link_set_txqlen(struct rtnl_link *link, unsigned int txqlen)
01723 {
01724         link->l_txqlen = txqlen;
01725         link->ce_mask |= LINK_ATTR_TXQLEN;
01726 }
01727 
01728 /**
01729  * Return transmission queue length
01730  * @arg link            Link object
01731  *
01732  * The unit is dependant on the link type. The most common units is number
01733  * of packets.
01734  *
01735  * @route_doc{link_attr_txqlen, Transmission Queue Length}
01736  * @return queue length or 0 if not specified.
01737  */
01738 unsigned int rtnl_link_get_txqlen(struct rtnl_link *link)
01739 {
01740         return link->ce_mask & LINK_ATTR_TXQLEN ? link->l_txqlen : 0;
01741 }
01742 
01743 void rtnl_link_set_link(struct rtnl_link *link, int ifindex)
01744 {
01745         link->l_link = ifindex;
01746         link->ce_mask |= LINK_ATTR_LINK;
01747 }
01748 
01749 int rtnl_link_get_link(struct rtnl_link *link)
01750 {
01751         return link->l_link;
01752 }
01753 
01754 /**
01755  * Set master link of link object
01756  * @arg link            Link object
01757  * @arg ifindex         Interface index of master link
01758  *
01759  * @see rtnl_link_get_master()
01760  */
01761 void rtnl_link_set_master(struct rtnl_link *link, int ifindex)
01762 {
01763         link->l_master = ifindex;
01764         link->ce_mask |= LINK_ATTR_MASTER;
01765 }
01766 
01767 /**
01768  * Return master link of link object
01769  * @arg link            Link object
01770  *
01771  * @see rtnl_link_set_master()
01772  * @return Interface index of master link or 0 if not specified
01773  */
01774 int rtnl_link_get_master(struct rtnl_link *link)
01775 {
01776         return link->l_master;
01777 }
01778 
01779 /**
01780  * Set operational status of link object
01781  * @arg link            Link object
01782  * @arg status          New opertional status
01783  *
01784  * @route_doc{link_attr_operstate, Operational Status}}
01785  * @see rtnl_link_get_operstate()
01786  */
01787 void rtnl_link_set_operstate(struct rtnl_link *link, uint8_t status)
01788 {
01789         link->l_operstate = status;
01790         link->ce_mask |= LINK_ATTR_OPERSTATE;
01791 }
01792 
01793 /**
01794  * Return operational status of link object
01795  * @arg link            Link object
01796  *
01797  * @route_doc{link_attr_operstate, Operational Status}
01798  * @see rtnl_link_set_operstate()
01799  * @return Opertional state or \c IF_OPER_UNKNOWN
01800  */
01801 uint8_t rtnl_link_get_operstate(struct rtnl_link *link)
01802 {
01803         return link->l_operstate;
01804 }
01805 
01806 /**
01807  * Set link mode of link object
01808  * @arg link            Link object
01809  * @arg mode            New link mode
01810  *
01811  * @route_doc{link_attr_mode, Mode}
01812  * @see rtnl_link_get_linkmode()
01813  */
01814 void rtnl_link_set_linkmode(struct rtnl_link *link, uint8_t mode)
01815 {
01816         link->l_linkmode = mode;
01817         link->ce_mask |= LINK_ATTR_LINKMODE;
01818 }
01819 
01820 /**
01821  * Return link mode of link object
01822  * @arg link            Link object
01823  *
01824  * @route_doc{link_attr_mode, Mode}
01825  * @see rtnl_link_get_linkmode()
01826  * @return Link mode or \c IF_LINK_MODE_DEFAULT
01827  */
01828 uint8_t rtnl_link_get_linkmode(struct rtnl_link *link)
01829 {
01830         return link->l_linkmode;
01831 }
01832 
01833 /**
01834  * Return alias name of link object (SNMP IfAlias)
01835  * @arg link            Link object
01836  *
01837  * @route_doc{link_attr_alias, Alias}
01838  * @see rtnl_link_set_ifalias()
01839  * @return Alias name or NULL if not set.
01840  */
01841 const char *rtnl_link_get_ifalias(struct rtnl_link *link)
01842 {
01843         return link->l_ifalias;
01844 }
01845 
01846 /**
01847  * Set alias name of link object (SNMP IfAlias)
01848  * @arg link            Link object
01849  * @arg alias           Alias name or NULL to unset
01850  *
01851  * Sets the alias name of the link to the specified name. The alias
01852  * name can be unset by specyfing NULL as the alias. The name will
01853  * be strdup()ed, so no need to provide a persistent character string.
01854  *
01855  * @route_doc{link_attr_alias, Alias}
01856  * @see rtnl_link_get_ifalias()
01857  */
01858 void rtnl_link_set_ifalias(struct rtnl_link *link, const char *alias)
01859 {
01860         free(link->l_ifalias);
01861         link->ce_mask &= ~LINK_ATTR_IFALIAS;
01862 
01863         if (alias) {
01864                 link->l_ifalias = strdup(alias);
01865                 link->ce_mask |= LINK_ATTR_IFALIAS;
01866         }
01867 }
01868 
01869 /**
01870  * Set queueing discipline name of link object
01871  * @arg link            Link object
01872  * @arg name            Name of queueing discipline
01873  *
01874  * @copydoc read_only_attribute
01875  *
01876  * For more information on how to modify the qdisc of a link, see section
01877  * @ref_route{route_tc, Traffic Control}.
01878  *
01879  * @route_doc{link_attr_qdisc, Queueing Discipline Name}
01880  * @see rtnl_link_get_qdisc()
01881  */
01882 void rtnl_link_set_qdisc(struct rtnl_link *link, const char *name)
01883 {
01884         strncpy(link->l_qdisc, name, sizeof(link->l_qdisc) - 1);
01885         link->ce_mask |= LINK_ATTR_QDISC;
01886 }
01887 
01888 /**
01889  * Return name of queueing discipline of link object
01890  * @arg link            Link object
01891  *
01892  * @route_doc{link_attr_qdisc, Queueing Discipline Name}
01893  * @see rtnl_link_set_qdisc()
01894  * @return Name of qdisc or NULL if not specified.
01895  */
01896 char *rtnl_link_get_qdisc(struct rtnl_link *link)
01897 {
01898         return link->ce_mask & LINK_ATTR_QDISC ? link->l_qdisc : NULL;
01899 }
01900 
01901 
01902 /**
01903  * Return number of PCI virtual functions of link object
01904  * @arg link            Link object
01905  * @arg num_vf          Pointer to store number of VFs
01906  *
01907  * @return 0 on success or -NLE_OPNOTSUPP if not available
01908  */
01909 int rtnl_link_get_num_vf(struct rtnl_link *link, uint32_t *num_vf)
01910 {
01911         if (link->ce_mask & LINK_ATTR_NUM_VF) {
01912                 *num_vf = link->l_num_vf;
01913                 return 0;
01914         } else
01915                 return -NLE_OPNOTSUPP;
01916 }
01917 
01918 /**
01919  * Return value of link statistics counter
01920  * @arg link            Link object
01921  * @arg id              Identifier of statistical counter
01922  *
01923  * @return Value of counter or 0 if not specified.
01924  */
01925 uint64_t rtnl_link_get_stat(struct rtnl_link *link, rtnl_link_stat_id_t id)
01926 {
01927         if (id > RTNL_LINK_STATS_MAX)
01928                 return 0;
01929 
01930         return link->l_stats[id];
01931 }
01932 
01933 /**
01934  * Set value of link statistics counter
01935  * @arg link            Link object
01936  * @arg id              Identifier of statistical counter
01937  * @arg value           New value
01938  *
01939  * \note Changing the value of a statistical counter will not change the
01940  *       value in the kernel.
01941  *
01942  * @return 0 on success or a negative error code
01943  */
01944 int rtnl_link_set_stat(struct rtnl_link *link, rtnl_link_stat_id_t id,
01945                        const uint64_t value)
01946 {
01947         if (id > RTNL_LINK_STATS_MAX)
01948                 return -NLE_INVAL;
01949 
01950         link->l_stats[id] = value;
01951 
01952         return 0;
01953 }
01954 
01955 /**
01956  * Set type of link object
01957  * @arg link            Link object
01958  * @arg type            Name of link type
01959  *
01960  * Looks up the link type module and prepares the link to store type
01961  * specific attributes. If a type has been assigned already it will
01962  * be released with all link type specific attributes lost.
01963  *
01964  * @route_doc{link_modules, Link Modules}
01965  * @return 0 on success or a negative errror code.
01966  */
01967 int rtnl_link_set_type(struct rtnl_link *link, const char *type)
01968 {
01969         struct rtnl_link_info_ops *io;
01970         int err;
01971         char *kind;
01972 
01973         free(link->l_info_kind);
01974         link->ce_mask &= ~LINK_ATTR_LINKINFO;
01975         if (link->l_info_ops)
01976                 release_link_info(link);
01977 
01978         if (!type)
01979                 return 0;
01980 
01981         kind = strdup(type);
01982         if (!kind)
01983                 return -NLE_NOMEM;
01984 
01985         io = rtnl_link_info_ops_lookup(type);
01986         if (io) {
01987                 if (io->io_alloc && (err = io->io_alloc(link)) < 0)
01988                         goto errout;
01989 
01990                 link->l_info_ops = io;
01991         }
01992 
01993         link->l_info_kind = kind;
01994         link->ce_mask |= LINK_ATTR_LINKINFO;
01995 
01996         return 0;
01997 
01998 errout:
01999         free(kind);
02000         return err;
02001 }
02002 
02003 /**
02004  * Return type of link
02005  * @arg link            Link object
02006  *
02007  * @route_doc{link_modules, Link Modules}
02008  * @return Name of link type or NULL if not specified.
02009  */
02010 char *rtnl_link_get_type(struct rtnl_link *link)
02011 {
02012         return link->l_info_kind;
02013 }
02014 
02015 /** @} */
02016 
02017 /**
02018  * @name Master/Slave
02019  * @{
02020  */
02021 
02022 /**
02023  * Enslave slave link to master link
02024  * @arg sock            netlink socket
02025  * @arg master          ifindex of master link
02026  * @arg slave           ifindex of slave link
02027  *
02028  * This function is identical to rtnl_link_enslave() except that
02029  * it takes interface indices instead of rtnl_link objects.
02030  *
02031  * @see rtnl_link_enslave()
02032  *
02033  * @return 0 on success or a negative error code.
02034  */
02035 int rtnl_link_enslave_ifindex(struct nl_sock *sock, int master, int slave)
02036 {
02037         struct rtnl_link *link;
02038         int err;
02039 
02040         if (!(link = rtnl_link_alloc()))
02041                 return -NLE_NOMEM;
02042 
02043         rtnl_link_set_ifindex(link, slave);
02044         rtnl_link_set_master(link, master);
02045         
02046         if ((err = rtnl_link_change(sock, link, link, 0)) < 0)
02047                 goto errout;
02048 
02049         rtnl_link_put(link);
02050 
02051         /*
02052          * Due to the kernel not signaling whether this opertion is
02053          * supported or not, we will retrieve the attribute to see  if the
02054          * request was successful. If the master assigned remains unchanged
02055          * we will return NLE_OPNOTSUPP to allow performing backwards
02056          * compatibility of some sort.
02057          */
02058         if ((err = rtnl_link_get_kernel(sock, slave, NULL, &link)) < 0)
02059                 return err;
02060 
02061         if (rtnl_link_get_master(link) != master)
02062                 err = -NLE_OPNOTSUPP;
02063 
02064 errout:
02065         rtnl_link_put(link);
02066 
02067         return err;
02068 }
02069 
02070 /**
02071  * Enslave slave link to master link
02072  * @arg sock            netlink socket
02073  * @arg master          master link
02074  * @arg slave           slave link
02075  *
02076  * Constructs a RTM_NEWLINK or RTM_SETLINK message adding the slave to
02077  * the master and sends the request via the specified netlink socket.
02078  *
02079  * @note The feature of enslaving/releasing via netlink has only been added
02080  *       recently to the kernel (Feb 2011). Also, the kernel does not signal
02081  *       if the operation is not supported. Therefore this function will
02082  *       verify if the master assignment has changed and will return
02083  *       -NLE_OPNOTSUPP if it did not.
02084  *
02085  * @see rtnl_link_enslave_ifindex()
02086  * @see rtnl_link_release()
02087  *
02088  * @return 0 on success or a negative error code.
02089  */
02090 int rtnl_link_enslave(struct nl_sock *sock, struct rtnl_link *master,
02091                       struct rtnl_link *slave)
02092 {
02093         return rtnl_link_enslave_ifindex(sock, rtnl_link_get_ifindex(master),
02094                                          rtnl_link_get_ifindex(slave));
02095 }
02096 
02097 /**
02098  * Release slave link from its master
02099  * @arg sock            netlink socket
02100  * @arg slave           slave link
02101  *
02102  * This function is identical to rtnl_link_release() except that
02103  * it takes an interface index instead of a rtnl_link object.
02104  *
02105  * @see rtnl_link_release()
02106  *
02107  * @return 0 on success or a negative error code.
02108  */
02109 int rtnl_link_release_ifindex(struct nl_sock *sock, int slave)
02110 {
02111         return rtnl_link_enslave_ifindex(sock, 0, slave);
02112 }
02113 
02114 /**
02115  * Release slave link from its master
02116  * @arg sock            netlink socket
02117  * @arg slave           slave link
02118  *
02119  * Constructs a RTM_NEWLINK or RTM_SETLINK message releasing the slave from
02120  * its master and sends the request via the specified netlink socket.
02121  *
02122  * @note The feature of enslaving/releasing via netlink has only been added
02123  *       recently to the kernel (Feb 2011). Also, the kernel does not signal
02124  *       if the operation is not supported. Therefore this function will
02125  *       verify if the master assignment has changed and will return
02126  *       -NLE_OPNOTSUPP if it did not.
02127  *
02128  * @see rtnl_link_release_ifindex()
02129  * @see rtnl_link_enslave()
02130  *
02131  * @return 0 on success or a negative error code.
02132  */
02133 int rtnl_link_release(struct nl_sock *sock, struct rtnl_link *slave)
02134 {
02135         return rtnl_link_release_ifindex(sock, rtnl_link_get_ifindex(slave));
02136 }
02137 
02138 /** @} */
02139 
02140 /**
02141  * @name Utilities
02142  * @{
02143  */
02144 
02145 static const struct trans_tbl link_flags[] = {
02146         __ADD(IFF_LOOPBACK, loopback)
02147         __ADD(IFF_BROADCAST, broadcast)
02148         __ADD(IFF_POINTOPOINT, pointopoint)
02149         __ADD(IFF_MULTICAST, multicast)
02150         __ADD(IFF_NOARP, noarp)
02151         __ADD(IFF_ALLMULTI, allmulti)
02152         __ADD(IFF_PROMISC, promisc)
02153         __ADD(IFF_MASTER, master)
02154         __ADD(IFF_SLAVE, slave)
02155         __ADD(IFF_DEBUG, debug)
02156         __ADD(IFF_DYNAMIC, dynamic)
02157         __ADD(IFF_AUTOMEDIA, automedia)
02158         __ADD(IFF_PORTSEL, portsel)
02159         __ADD(IFF_NOTRAILERS, notrailers)
02160         __ADD(IFF_UP, up)
02161         __ADD(IFF_RUNNING, running)
02162         __ADD(IFF_LOWER_UP, lowerup)
02163         __ADD(IFF_DORMANT, dormant)
02164         __ADD(IFF_ECHO, echo)
02165 };
02166 
02167 char *rtnl_link_flags2str(int flags, char *buf, size_t len)
02168 {
02169         return __flags2str(flags, buf, len, link_flags,
02170                            ARRAY_SIZE(link_flags));
02171 }
02172 
02173 int rtnl_link_str2flags(const char *name)
02174 {
02175         return __str2flags(name, link_flags, ARRAY_SIZE(link_flags));
02176 }
02177 
02178 static const struct trans_tbl link_stats[] = {
02179         __ADD(RTNL_LINK_RX_PACKETS, rx_packets)
02180         __ADD(RTNL_LINK_TX_PACKETS, tx_packets)
02181         __ADD(RTNL_LINK_RX_BYTES, rx_bytes)
02182         __ADD(RTNL_LINK_TX_BYTES, tx_bytes)
02183         __ADD(RTNL_LINK_RX_ERRORS, rx_errors)
02184         __ADD(RTNL_LINK_TX_ERRORS, tx_errors)
02185         __ADD(RTNL_LINK_RX_DROPPED, rx_dropped)
02186         __ADD(RTNL_LINK_TX_DROPPED, tx_dropped)
02187         __ADD(RTNL_LINK_RX_COMPRESSED, rx_compressed)
02188         __ADD(RTNL_LINK_TX_COMPRESSED, tx_compressed)
02189         __ADD(RTNL_LINK_RX_FIFO_ERR, rx_fifo_err)
02190         __ADD(RTNL_LINK_TX_FIFO_ERR, tx_fifo_err)
02191         __ADD(RTNL_LINK_RX_LEN_ERR, rx_len_err)
02192         __ADD(RTNL_LINK_RX_OVER_ERR, rx_over_err)
02193         __ADD(RTNL_LINK_RX_CRC_ERR, rx_crc_err)
02194         __ADD(RTNL_LINK_RX_FRAME_ERR, rx_frame_err)
02195         __ADD(RTNL_LINK_RX_MISSED_ERR, rx_missed_err)
02196         __ADD(RTNL_LINK_TX_ABORT_ERR, tx_abort_err)
02197         __ADD(RTNL_LINK_TX_CARRIER_ERR, tx_carrier_err)
02198         __ADD(RTNL_LINK_TX_HBEAT_ERR, tx_hbeat_err)
02199         __ADD(RTNL_LINK_TX_WIN_ERR, tx_win_err)
02200         __ADD(RTNL_LINK_COLLISIONS, collisions)
02201         __ADD(RTNL_LINK_MULTICAST, multicast)
02202         __ADD(RTNL_LINK_IP6_INPKTS, Ip6InReceives)
02203         __ADD(RTNL_LINK_IP6_INHDRERRORS, Ip6InHdrErrors)
02204         __ADD(RTNL_LINK_IP6_INTOOBIGERRORS, Ip6InTooBigErrors)
02205         __ADD(RTNL_LINK_IP6_INNOROUTES, Ip6InNoRoutes)
02206         __ADD(RTNL_LINK_IP6_INADDRERRORS, Ip6InAddrErrors)
02207         __ADD(RTNL_LINK_IP6_INUNKNOWNPROTOS, Ip6InUnknownProtos)
02208         __ADD(RTNL_LINK_IP6_INTRUNCATEDPKTS, Ip6InTruncatedPkts)
02209         __ADD(RTNL_LINK_IP6_INDISCARDS, Ip6InDiscards)
02210         __ADD(RTNL_LINK_IP6_INDELIVERS, Ip6InDelivers)
02211         __ADD(RTNL_LINK_IP6_OUTFORWDATAGRAMS, Ip6OutForwDatagrams)
02212         __ADD(RTNL_LINK_IP6_OUTPKTS, Ip6OutRequests)
02213         __ADD(RTNL_LINK_IP6_OUTDISCARDS, Ip6OutDiscards)
02214         __ADD(RTNL_LINK_IP6_OUTNOROUTES, Ip6OutNoRoutes)
02215         __ADD(RTNL_LINK_IP6_REASMTIMEOUT, Ip6ReasmTimeout)
02216         __ADD(RTNL_LINK_IP6_REASMREQDS, Ip6ReasmReqds)
02217         __ADD(RTNL_LINK_IP6_REASMOKS, Ip6ReasmOKs)
02218         __ADD(RTNL_LINK_IP6_REASMFAILS, Ip6ReasmFails)
02219         __ADD(RTNL_LINK_IP6_FRAGOKS, Ip6FragOKs)
02220         __ADD(RTNL_LINK_IP6_FRAGFAILS, Ip6FragFails)
02221         __ADD(RTNL_LINK_IP6_FRAGCREATES, Ip6FragCreates)
02222         __ADD(RTNL_LINK_IP6_INMCASTPKTS, Ip6InMcastPkts)
02223         __ADD(RTNL_LINK_IP6_OUTMCASTPKTS, Ip6OutMcastPkts)
02224         __ADD(RTNL_LINK_IP6_INBCASTPKTS, Ip6InBcastPkts)
02225         __ADD(RTNL_LINK_IP6_OUTBCASTPKTS, Ip6OutBcastPkts)
02226         __ADD(RTNL_LINK_IP6_INOCTETS, Ip6InOctets)
02227         __ADD(RTNL_LINK_IP6_OUTOCTETS, Ip6OutOctets)
02228         __ADD(RTNL_LINK_IP6_INMCASTOCTETS, Ip6InMcastOctets)
02229         __ADD(RTNL_LINK_IP6_OUTMCASTOCTETS, Ip6OutMcastOctets)
02230         __ADD(RTNL_LINK_IP6_INBCASTOCTETS, Ip6InBcastOctets)
02231         __ADD(RTNL_LINK_IP6_OUTBCASTOCTETS, Ip6OutBcastOctets)
02232         __ADD(RTNL_LINK_ICMP6_INMSGS, ICMP6_InMsgs)
02233         __ADD(RTNL_LINK_ICMP6_INERRORS, ICMP6_InErrors)
02234         __ADD(RTNL_LINK_ICMP6_OUTMSGS, ICMP6_OutMsgs)
02235         __ADD(RTNL_LINK_ICMP6_OUTERRORS, ICMP6_OutErrors)
02236 };
02237 
02238 char *rtnl_link_stat2str(int st, char *buf, size_t len)
02239 {
02240         return __type2str(st, buf, len, link_stats, ARRAY_SIZE(link_stats));
02241 }
02242 
02243 int rtnl_link_str2stat(const char *name)
02244 {
02245         return __str2type(name, link_stats, ARRAY_SIZE(link_stats));
02246 }
02247 
02248 static const struct trans_tbl link_operstates[] = {
02249         __ADD(IF_OPER_UNKNOWN, unknown)
02250         __ADD(IF_OPER_NOTPRESENT, notpresent)
02251         __ADD(IF_OPER_DOWN, down)
02252         __ADD(IF_OPER_LOWERLAYERDOWN, lowerlayerdown)
02253         __ADD(IF_OPER_TESTING, testing)
02254         __ADD(IF_OPER_DORMANT, dormant)
02255         __ADD(IF_OPER_UP, up)
02256 };
02257 
02258 char *rtnl_link_operstate2str(uint8_t st, char *buf, size_t len)
02259 {
02260         return __type2str(st, buf, len, link_operstates,
02261                           ARRAY_SIZE(link_operstates));
02262 }
02263 
02264 int rtnl_link_str2operstate(const char *name)
02265 {
02266         return __str2type(name, link_operstates,
02267                           ARRAY_SIZE(link_operstates));
02268 }
02269 
02270 static const struct trans_tbl link_modes[] = {
02271         __ADD(IF_LINK_MODE_DEFAULT, default)
02272         __ADD(IF_LINK_MODE_DORMANT, dormant)
02273 };
02274 
02275 char *rtnl_link_mode2str(uint8_t st, char *buf, size_t len)
02276 {
02277         return __type2str(st, buf, len, link_modes, ARRAY_SIZE(link_modes));
02278 }
02279 
02280 int rtnl_link_str2mode(const char *name)
02281 {
02282         return __str2type(name, link_modes, ARRAY_SIZE(link_modes));
02283 }
02284 
02285 /** @} */
02286 
02287 /**
02288  * @name Deprecated Functions
02289  */
02290 
02291 /**
02292  * @deprecated Use of this function is deprecated, use rtnl_link_set_type()
02293  */
02294 int rtnl_link_set_info_type(struct rtnl_link *link, const char *type)
02295 {
02296         return rtnl_link_set_type(link, type);
02297 }
02298 
02299 /**
02300  * @deprecated Use of this function is deprecated, use rtnl_link_get_type()
02301  */
02302 char *rtnl_link_get_info_type(struct rtnl_link *link)
02303 {
02304         return rtnl_link_get_type(link);
02305 }
02306 
02307 /**
02308  * @deprecated The weight attribute is unused and obsoleted in all recent kernels
02309  */
02310 void rtnl_link_set_weight(struct rtnl_link *link, unsigned int weight)
02311 {
02312         link->l_weight = weight;
02313         link->ce_mask |= LINK_ATTR_WEIGHT;
02314 }
02315 
02316 /**
02317  * @deprecated The weight attribute is unused and obsoleted in all recent kernels
02318  */
02319 unsigned int rtnl_link_get_weight(struct rtnl_link *link)
02320 {
02321         return link->l_weight;
02322 }
02323 
02324 /** @} */
02325 
02326 static struct nl_object_ops link_obj_ops = {
02327         .oo_name                = "route/link",
02328         .oo_size                = sizeof(struct rtnl_link),
02329         .oo_free_data           = link_free_data,
02330         .oo_clone               = link_clone,
02331         .oo_dump = {
02332             [NL_DUMP_LINE]      = link_dump_line,
02333             [NL_DUMP_DETAILS]   = link_dump_details,
02334             [NL_DUMP_STATS]     = link_dump_stats,
02335         },
02336         .oo_compare             = link_compare,
02337         .oo_attrs2str           = link_attrs2str,
02338         .oo_id_attrs            = LINK_ATTR_IFINDEX,
02339 };
02340 
02341 static struct nl_af_group link_groups[] = {
02342         { AF_UNSPEC,    RTNLGRP_LINK },
02343         { END_OF_GROUP_LIST },
02344 };
02345 
02346 static struct nl_cache_ops rtnl_link_ops = {
02347         .co_name                = "route/link",
02348         .co_hdrsize             = sizeof(struct ifinfomsg),
02349         .co_msgtypes            = {
02350                                         { RTM_NEWLINK, NL_ACT_NEW, "new" },
02351                                         { RTM_DELLINK, NL_ACT_DEL, "del" },
02352                                         { RTM_GETLINK, NL_ACT_GET, "get" },
02353                                         { RTM_SETLINK, NL_ACT_CHANGE, "set" },
02354                                         END_OF_MSGTYPES_LIST,
02355                                   },
02356         .co_protocol            = NETLINK_ROUTE,
02357         .co_groups              = link_groups,
02358         .co_request_update      = link_request_update,
02359         .co_msg_parser          = link_msg_parser,
02360         .co_event_filter        = link_event_filter,
02361         .co_obj_ops             = &link_obj_ops,
02362 };
02363 
02364 static void __init link_init(void)
02365 {
02366         nl_cache_mngt_register(&rtnl_link_ops);
02367 }
02368 
02369 static void __exit link_exit(void)
02370 {
02371         nl_cache_mngt_unregister(&rtnl_link_ops);
02372 }
02373 
02374 /** @} */