#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). */
#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
/* 3 bytes spare */
};
+
#endif /* _LINUX_IF_H */
#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;
[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) },
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;
}
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);
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);
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;
}
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));
__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)
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:
/** @} */
+/**
+ * @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
* @{
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)