From 3ad4665be2f192291238cbe78118a57ec42436c6 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Wed, 19 Dec 2007 22:03:44 +0100 Subject: [PATCH] Support link operstate and linkmode --- include/linux/if.h | 35 +++++++++- include/netlink-types.h | 2 + include/netlink/addr.h | 1 + include/netlink/route/link.h | 14 ++++ lib/addr.c | 15 ++++ lib/route/link.c | 129 +++++++++++++++++++++++++++++++++-- 6 files changed, 187 insertions(+), 9 deletions(-) diff --git a/include/linux/if.h b/include/linux/if.h index 9128570..4c1bcfe 100644 --- a/include/linux/if.h +++ b/include/linux/if.h @@ -19,6 +19,8 @@ #ifndef _LINUX_IF_H #define _LINUX_IF_H +#include /* 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*/ @@ -38,17 +40,27 @@ #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 @@ -77,6 +89,22 @@ #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 */ diff --git a/include/netlink-types.h b/include/netlink-types.h index 53af6ba..5a23450 100644 --- a/include/netlink-types.h +++ b/include/netlink-types.h @@ -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 diff --git a/include/netlink/addr.h b/include/netlink/addr.h index df5c868..25fce7e 100644 --- a/include/netlink/addr.h +++ b/include/netlink/addr.h @@ -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 *, diff --git a/include/netlink/route/link.h b/include/netlink/route/link.h index 8bcae24..78f2b0b 100644 --- a/include/netlink/route/link.h +++ b/include/netlink/route/link.h @@ -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 diff --git a/lib/addr.c b/lib/addr.c index 7fe3781..68f7741 100644 --- a/lib/addr.c +++ b/lib/addr.c @@ -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. diff --git a/lib/route/link.c b/lib/route/link.c index d3c204f..2953999 100644 --- a/lib/route/link.c +++ b/lib/route/link.c @@ -151,6 +151,8 @@ #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) -- 2.40.0