]> granicus.if.org Git - libnl/commitdiff
Support link operstate and linkmode
authorThomas Graf <tgr@deb.localdomain>
Wed, 19 Dec 2007 21:03:44 +0000 (22:03 +0100)
committerThomas Graf <tgr@deb.localdomain>
Wed, 19 Dec 2007 21:03:44 +0000 (22:03 +0100)
include/linux/if.h
include/netlink-types.h
include/netlink/addr.h
include/netlink/route/link.h
lib/addr.c
lib/route/link.c

index 9128570309d01d7ce8f4e19942f719896dde0183..4c1bcfec7f795ba5f5f8ec7be53acc7ae258c94e 100644 (file)
@@ -19,6 +19,8 @@
 #ifndef _LINUX_IF_H
 #define _LINUX_IF_H
 
+#include <linux/types.h>               /* for "__kernel_caddr_t" et al */
+
 #define        IFNAMSIZ        16
 
 /* Standard interface flags (netdevice->flags). */
@@ -28,7 +30,7 @@
 #define        IFF_LOOPBACK    0x8             /* is a loopback net            */
 #define        IFF_POINTOPOINT 0x10            /* interface is has p-p link    */
 #define        IFF_NOTRAILERS  0x20            /* avoid use of trailers        */
-#define        IFF_RUNNING     0x40            /* interface running and carrier ok */
+#define        IFF_RUNNING     0x40            /* interface RFC2863 OPER_UP    */
 #define        IFF_NOARP       0x80            /* no ARP protocol              */
 #define        IFF_PROMISC     0x100           /* receive all packets          */
 #define        IFF_ALLMULTI    0x200           /* receive all multicast packets*/
 
 #define IFF_MULTICAST  0x1000          /* Supports multicast           */
 
-#define IFF_VOLATILE   (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_MASTER|IFF_SLAVE|IFF_RUNNING)
-
 #define IFF_PORTSEL    0x2000          /* can set media type           */
 #define IFF_AUTOMEDIA  0x4000          /* auto media select active     */
 #define IFF_DYNAMIC    0x8000          /* dialup device with changing addresses*/
+
 #define IFF_LOWER_UP   0x10000         /* driver signals L1 up         */
 #define IFF_DORMANT    0x20000         /* driver signals dormant       */
 
+#define IFF_ECHO       0x40000         /* echo sent packets            */
+
+#define IFF_VOLATILE   (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_ECHO|\
+               IFF_MASTER|IFF_SLAVE|IFF_RUNNING|IFF_LOWER_UP|IFF_DORMANT)
+
 /* Private (from user) interface flags (netdevice->priv_flags). */
 #define IFF_802_1Q_VLAN 0x1             /* 802.1Q VLAN device.          */
 #define IFF_EBRIDGE    0x2             /* Ethernet bridging device.    */
+#define IFF_SLAVE_INACTIVE     0x4     /* bonding slave not the curr. active */
+#define IFF_MASTER_8023AD      0x8     /* bonding master, 802.3ad.     */
+#define IFF_MASTER_ALB 0x10            /* bonding master, balance-alb. */
+#define IFF_BONDING    0x20            /* bonding master or slave      */
+#define IFF_SLAVE_NEEDARP 0x40         /* need ARPs for validation     */
+#define IFF_ISATAP     0x80            /* ISATAP interface (RFC4214)   */
 
 #define IF_GET_IFACE   0x0001          /* for querying only */
 #define IF_GET_PROTO   0x0002
 #define IF_PROTO_FR_ETH_PVC 0x200B
 #define IF_PROTO_RAW    0x200C          /* RAW Socket                   */
 
+/* RFC 2863 operational status */
+enum {
+       IF_OPER_UNKNOWN,
+       IF_OPER_NOTPRESENT,
+       IF_OPER_DOWN,
+       IF_OPER_LOWERLAYERDOWN,
+       IF_OPER_TESTING,
+       IF_OPER_DORMANT,
+       IF_OPER_UP,
+};
+
+/* link modes */
+enum {
+       IF_LINK_MODE_DEFAULT,
+       IF_LINK_MODE_DORMANT,   /* limit upward transition to dormant */
+};
 
 /*
  *     Device mapping structure. I'd just gone off and designed a 
@@ -99,4 +127,5 @@ struct ifmap
        /* 3 bytes spare */
 };
 
+
 #endif /* _LINUX_IF_H */
index 53af6baef27f88c7190f4b852991e70fe9225149..5a23450e6effd68f38d4a4a23503d0c31fb6993c 100644 (file)
@@ -173,6 +173,8 @@ struct rtnl_link
        struct rtnl_link_map l_map;
        uint64_t        l_stats[RTNL_LINK_STATS_MAX+1];
        uint32_t        l_flag_mask;
+       uint8_t         l_operstate;
+       uint8_t         l_linkmode;
 };
 
 struct rtnl_ncacheinfo
index df5c868aaf53e742721a5c5d3e2937f0c6133f0a..25fce7e25b5eaa630997498e50332b1768e7f1d1 100644 (file)
@@ -36,6 +36,7 @@ extern int            nl_addr_shared(struct nl_addr *);
 
 extern int             nl_addr_cmp(struct nl_addr *, struct nl_addr *);
 extern int             nl_addr_cmp_prefix(struct nl_addr *, struct nl_addr *);
+extern int             nl_addr_iszero(struct nl_addr *);
 extern int             nl_addr_valid(char *, int);
 extern int             nl_addr_guess_family(struct nl_addr *);
 extern int             nl_addr_fill_sockaddr(struct nl_addr *,
index 8bcae24f8f513806946f5d3eafaebacc060625a1..78f2b0be41b0c97ffe14b7c085554b19f3158a9c 100644 (file)
@@ -91,6 +91,12 @@ extern int                   rtnl_link_str2stat(const char *);
 extern char *                  rtnl_link_flags2str(int, char *, size_t);
 extern int                     rtnl_link_str2flags(const char *);
 
+extern char *                  rtnl_link_operstate2str(int, char *, size_t);
+extern int                     rtnl_link_str2operstate(const char *);
+
+extern char *                  rtnl_link_mode2str(int, char *, size_t);
+extern int                     rtnl_link_str2mode(const char *);
+
 /* Access Functions */
 extern void                    rtnl_link_set_qdisc(struct rtnl_link *,
                                                    const char *);
@@ -142,6 +148,14 @@ extern int                 rtnl_link_get_link(struct rtnl_link *);
 extern void                    rtnl_link_set_master(struct rtnl_link *, int);
 extern int                     rtnl_link_get_master(struct rtnl_link *);
 
+extern void                    rtnl_link_set_operstate(struct rtnl_link *,
+                                                       uint8_t);
+extern uint8_t                 rtnl_link_get_operstate(struct rtnl_link *);
+
+extern void                    rtnl_link_set_linkmode(struct rtnl_link *,
+                                                      uint8_t);
+extern uint8_t                 rtnl_link_get_linkmode(struct rtnl_link *);
+
 extern uint64_t                rtnl_link_get_stat(struct rtnl_link *, int);
 
 #ifdef __cplusplus
index 7fe3781b2953c6190b309b6f07cb9111d6ec7e32..68f77410d65fba76d20eed4a40df75b9f14e9847 100644 (file)
@@ -528,6 +528,21 @@ int nl_addr_cmp_prefix(struct nl_addr *a, struct nl_addr *b)
        return d;
 }
 
+/**
+ * Returns true if the address consists of all zeros
+ * @arg addr           Address to look at.
+ */
+int nl_addr_iszero(struct nl_addr *addr)
+{
+       int i;
+
+       for (i = 0; i < addr->a_len; i++)
+               if (addr->a_addr[i])
+                       return 0;
+
+       return 1;
+}
+
 /**
  * Check if an address matches a certain family.
  * @arg addr           Address represented as character string.
index d3c204f5bf19974eae9def44e4fee97b206175e6..29539990e3f9387e9b1874785ec44f42f2fd3da5 100644 (file)
 #define LINK_ATTR_ARPTYPE 0x2000
 #define LINK_ATTR_STATS   0x4000
 #define LINK_ATTR_CHANGE  0x8000
+#define LINK_ATTR_OPERSTATE 0x10000
+#define LINK_ATTR_LINKMODE  0x20000
 
 static struct nl_cache_ops rtnl_link_ops;
 static struct nl_object_ops link_obj_ops;
@@ -192,6 +194,8 @@ static struct nla_policy link_policy[IFLA_MAX+1] = {
        [IFLA_LINK]     = { .type = NLA_U32 },
        [IFLA_WEIGHT]   = { .type = NLA_U32 },
        [IFLA_MASTER]   = { .type = NLA_U32 },
+       [IFLA_OPERSTATE]= { .type = NLA_U8 },
+       [IFLA_LINKMODE] = { .type = NLA_U8 },
        [IFLA_QDISC]    = { .type = NLA_STRING,
                            .maxlen = IFQDISCSIZ },
        [IFLA_STATS]    = { .minlen = sizeof(struct rtnl_link_stats) },
@@ -323,6 +327,16 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
                link->ce_mask |= LINK_ATTR_MASTER;
        }
 
+       if (tb[IFLA_OPERSTATE]) {
+               link->l_operstate = nla_get_u8(tb[IFLA_OPERSTATE]);
+               link->ce_mask |= LINK_ATTR_OPERSTATE;
+       }
+
+       if (tb[IFLA_LINKMODE]) {
+               link->l_linkmode = nla_get_u8(tb[IFLA_LINKMODE]);
+               link->ce_mask |= LINK_ATTR_LINKMODE;
+       }
+
        err = pp->pp_cb((struct nl_object *) link, pp);
        if (err < 0)
                goto errout;
@@ -356,9 +370,9 @@ static int link_dump_brief(struct nl_object *obj, struct nl_dump_params *p)
        }
 
        dp_dump(p, "%s ", nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
-       dp_dump(p, "%s ", link->l_addr ?  nl_addr2str(link->l_addr, buf,
-                                                    sizeof(buf)) : "none");
-       dp_dump(p, "mtu %u ", link->l_mtu);
+
+       if (link->l_addr && !nl_addr_iszero(link->l_addr))
+               dp_dump(p, "%s ", nl_addr2str(link->l_addr, buf, sizeof(buf)));
 
        if (link->ce_mask & LINK_ATTR_MASTER) {
                struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
@@ -385,7 +399,8 @@ static int link_dump_full(struct nl_object *obj, struct nl_dump_params *p)
        line = link_dump_brief(obj, p);
        dp_new_line(p, line++);
 
-       dp_dump(p, "    txqlen %u weight %u ", link->l_txqlen, link->l_weight);
+       dp_dump(p, "    mtu %u ", link->l_mtu);
+       dp_dump(p, "txqlen %u weight %u ", link->l_txqlen, link->l_weight);
 
        if (link->ce_mask & LINK_ATTR_QDISC)
                dp_dump(p, "qdisc %s ", link->l_qdisc);
@@ -396,11 +411,24 @@ static int link_dump_full(struct nl_object *obj, struct nl_dump_params *p)
        if (link->ce_mask & LINK_ATTR_IFINDEX)
                dp_dump(p, "index %u ", link->l_index);
 
+
+       dp_dump(p, "\n");
+       dp_new_line(p, line++);
+
+       dp_dump(p, "    ");
+
        if (link->ce_mask & LINK_ATTR_BRD)
-               dp_dump(p, "brd %s", nl_addr2str(link->l_bcast, buf,
+               dp_dump(p, "brd %s ", nl_addr2str(link->l_bcast, buf,
                                                   sizeof(buf)));
 
-       dp_dump(p, "\n");
+       if ((link->ce_mask & LINK_ATTR_OPERSTATE) &&
+           link->l_operstate != IF_OPER_UNKNOWN) {
+               rtnl_link_operstate2str(link->l_operstate, buf, sizeof(buf));
+               dp_dump(p, "state %s ", buf);
+       }
+
+       dp_dump(p, "mode %s\n",
+               rtnl_link_mode2str(link->l_linkmode, buf, sizeof(buf)));
 
        return line;
 }
@@ -667,6 +695,8 @@ static int link_compare(struct nl_object *_a, struct nl_object *_b,
        diff |= LINK_DIFF(WEIGHT,       a->l_weight != b->l_weight);
        diff |= LINK_DIFF(MASTER,       a->l_master != b->l_master);
        diff |= LINK_DIFF(FAMILY,       a->l_family != b->l_family);
+       diff |= LINK_DIFF(OPERSTATE,    a->l_operstate != b->l_operstate);
+       diff |= LINK_DIFF(LINKMODE,     a->l_linkmode != b->l_linkmode);
        diff |= LINK_DIFF(QDISC,        strcmp(a->l_qdisc, b->l_qdisc));
        diff |= LINK_DIFF(IFNAME,       strcmp(a->l_name, b->l_name));
        diff |= LINK_DIFF(ADDR,         nl_addr_cmp(a->l_addr, b->l_addr));
@@ -700,6 +730,8 @@ static struct trans_tbl link_attrs[] = {
        __ADD(LINK_ATTR_ARPTYPE, arptype)
        __ADD(LINK_ATTR_STATS, stats)
        __ADD(LINK_ATTR_CHANGE, change)
+       __ADD(LINK_ATTR_OPERSTATE, operstate)
+       __ADD(LINK_ATTR_LINKMODE, linkmode)
 };
 
 static char *link_attrs2str(int attrs, char *buf, size_t len)
@@ -877,6 +909,12 @@ struct nl_msg * rtnl_link_build_change_request(struct rtnl_link *old,
        if (tmpl->ce_mask & LINK_ATTR_IFNAME)
                NLA_PUT_STRING(msg, IFLA_IFNAME, tmpl->l_name);
 
+       if (tmpl->ce_mask & LINK_ATTR_OPERSTATE)
+               NLA_PUT_U8(msg, IFLA_OPERSTATE, tmpl->l_operstate);
+
+       if (tmpl->ce_mask & LINK_ATTR_LINKMODE)
+               NLA_PUT_U8(msg, IFLA_LINKMODE, tmpl->l_linkmode);
+
        return msg;
 
 nla_put_failure:
@@ -1055,6 +1093,57 @@ int rtnl_link_str2stat(const char *name)
 
 /** @} */
 
+/**
+ * @name Link Operstate Translations
+ * @{
+ */
+
+static struct trans_tbl link_operstates[] = {
+       __ADD(IF_OPER_UNKNOWN, unknown)
+       __ADD(IF_OPER_NOTPRESENT, notpresent)
+       __ADD(IF_OPER_DOWN, down)
+       __ADD(IF_OPER_LOWERLAYERDOWN, lowerlayerdown)
+       __ADD(IF_OPER_TESTING, testing)
+       __ADD(IF_OPER_DORMANT, dormant)
+       __ADD(IF_OPER_UP, up)
+};
+
+char *rtnl_link_operstate2str(int st, char *buf, size_t len)
+{
+       return __type2str(st, buf, len, link_operstates,
+                         ARRAY_SIZE(link_operstates));
+}
+
+int rtnl_link_str2operstate(const char *name)
+{
+       return __str2type(name, link_operstates,
+                         ARRAY_SIZE(link_operstates));
+}
+
+/** @} */
+
+/**
+ * @name Link Mode Translations
+ * @{
+ */
+
+static struct trans_tbl link_modes[] = {
+       __ADD(IF_LINK_MODE_DEFAULT, default)
+       __ADD(IF_LINK_MODE_DORMANT, dormant)
+};
+
+char *rtnl_link_mode2str(int st, char *buf, size_t len)
+{
+       return __type2str(st, buf, len, link_modes, ARRAY_SIZE(link_modes));
+}
+
+int rtnl_link_str2mode(const char *name)
+{
+       return __str2type(name, link_modes, ARRAY_SIZE(link_modes));
+}
+
+/** @} */
+
 /**
  * @name Attributes
  * @{
@@ -1253,6 +1342,34 @@ int rtnl_link_get_master(struct rtnl_link *link)
                return RTNL_LINK_NOT_FOUND;
 }
 
+void rtnl_link_set_operstate(struct rtnl_link *link, uint8_t operstate)
+{
+       link->l_operstate = operstate;
+       link->ce_mask |= LINK_ATTR_OPERSTATE;
+}
+
+uint8_t rtnl_link_get_operstate(struct rtnl_link *link)
+{
+       if (link->ce_mask & LINK_ATTR_OPERSTATE)
+               return link->l_operstate;
+       else
+               return IF_OPER_UNKNOWN;
+}
+
+void rtnl_link_set_linkmode(struct rtnl_link *link, uint8_t linkmode)
+{
+       link->l_linkmode = linkmode;
+       link->ce_mask |= LINK_ATTR_LINKMODE;
+}
+
+uint8_t rtnl_link_get_linkmode(struct rtnl_link *link)
+{
+       if (link->ce_mask & LINK_ATTR_LINKMODE)
+               return link->l_linkmode;
+       else
+               return IF_LINK_MODE_DEFAULT;
+}
+
 uint64_t rtnl_link_get_stat(struct rtnl_link *link, int id)
 {
        if (id < 0 || id > RTNL_LINK_STATS_MAX)