iplink: add support for protodown reason
This patch adds support for recently
added link IFLA_PROTO_DOWN_REASON attribute.
IFLA_PROTO_DOWN_REASON enumerates reasons
for the already existing IFLA_PROTO_DOWN link
attribute.
$ cat /etc/iproute2/protodown_reasons.d/r.conf
0 mlag
1 evpn
2 vrrp
3 psecurity
$ ip link set dev vx10 protodown on protodown_reason vrrp on
$ip link show dev vx10
14: vx10: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode
DEFAULT group default qlen 1000
link/ether f2:32:28:b8:35:ff brd ff:ff:ff:ff:ff:ff protodown on
protodown_reason <vrrp>
$ip -p -j link show dev vx10
[ {
<snip>
"proto_down": true,
"proto_down_reason": [ "vrrp" ]
} ]
$ip link set dev vx10 protodown_reason mlag on
$ip link show dev vx10
14: vx10: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode
DEFAULT group default qlen 1000
link/ether f2:32:28:b8:35:ff brd ff:ff:ff:ff:ff:ff protodown on
protodown_reason <mlag,vrrp>
$ip -p -j link show dev vx10
[ {
<snip>
"proto_down": true,
"protodown_reason": [ "mlag","vrrp" ]
} ]
$ip -p -j link show dev vx10
$ip link set dev vx10 protodown off protodown_reason vrrp off
Error: Cannot clear protodown, active reasons.
$ip link set dev vx10 protodown off protodown_reason mlag off
$
Note: for somereason the json and non-json key for protodown
are different (protodown and proto_down). I have kept the
same for protodown reason for consistency (protodown_reason and
proto_down_reason).
Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
Signed-off-by: David Ahern <dsahern@gmail.com>
This commit is contained in:
parent
af27494d2e
commit
6fd53b2a1c
|
|
@ -33,6 +33,9 @@ int ll_proto_a2n(unsigned short *id, const char *buf);
|
||||||
const char *nl_proto_n2a(int id, char *buf, int len);
|
const char *nl_proto_n2a(int id, char *buf, int len);
|
||||||
int nl_proto_a2n(__u32 *id, const char *arg);
|
int nl_proto_a2n(__u32 *id, const char *arg);
|
||||||
|
|
||||||
|
int protodown_reason_a2n(__u32 *id, const char *arg);
|
||||||
|
int protodown_reason_n2a(int id, char *buf, int len);
|
||||||
|
|
||||||
extern int numeric;
|
extern int numeric;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -874,6 +874,45 @@ static void print_link_event(FILE *f, __u32 event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void print_proto_down(FILE *f, struct rtattr *tb[])
|
||||||
|
{
|
||||||
|
struct rtattr *preason[IFLA_PROTO_DOWN_REASON_MAX+1];
|
||||||
|
|
||||||
|
if (tb[IFLA_PROTO_DOWN]) {
|
||||||
|
if (rta_getattr_u8(tb[IFLA_PROTO_DOWN]))
|
||||||
|
print_bool(PRINT_ANY,
|
||||||
|
"proto_down", " protodown on ", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tb[IFLA_PROTO_DOWN_REASON]) {
|
||||||
|
char buf[255];
|
||||||
|
__u32 reason;
|
||||||
|
int i, start = 1;
|
||||||
|
|
||||||
|
parse_rtattr_nested(preason, IFLA_PROTO_DOWN_REASON_MAX,
|
||||||
|
tb[IFLA_PROTO_DOWN_REASON]);
|
||||||
|
if (!tb[IFLA_PROTO_DOWN_REASON_VALUE])
|
||||||
|
return;
|
||||||
|
|
||||||
|
reason = rta_getattr_u8(preason[IFLA_PROTO_DOWN_REASON_VALUE]);
|
||||||
|
if (!reason)
|
||||||
|
return;
|
||||||
|
|
||||||
|
open_json_array(PRINT_ANY,
|
||||||
|
is_json_context() ? "proto_down_reason" : "protodown_reason <");
|
||||||
|
for (i = 0; reason; i++, reason >>= 1) {
|
||||||
|
if (reason & 0x1) {
|
||||||
|
if (protodown_reason_n2a(i, buf, sizeof(buf)))
|
||||||
|
break;
|
||||||
|
print_string(PRINT_ANY, NULL,
|
||||||
|
start ? "%s" : ",%s", buf);
|
||||||
|
start = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close_json_array(PRINT_ANY, ">");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int print_linkinfo(struct nlmsghdr *n, void *arg)
|
int print_linkinfo(struct nlmsghdr *n, void *arg)
|
||||||
{
|
{
|
||||||
FILE *fp = (FILE *)arg;
|
FILE *fp = (FILE *)arg;
|
||||||
|
|
@ -1066,11 +1105,8 @@ int print_linkinfo(struct nlmsghdr *n, void *arg)
|
||||||
print_int(PRINT_FP, NULL, " new-ifindex %d", id);
|
print_int(PRINT_FP, NULL, " new-ifindex %d", id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tb[IFLA_PROTO_DOWN]) {
|
if (tb[IFLA_PROTO_DOWN])
|
||||||
if (rta_getattr_u8(tb[IFLA_PROTO_DOWN]))
|
print_proto_down(fp, tb);
|
||||||
print_bool(PRINT_ANY,
|
|
||||||
"proto_down", " protodown on ", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (show_details) {
|
if (show_details) {
|
||||||
if (tb[IFLA_PROMISCUITY])
|
if (tb[IFLA_PROMISCUITY])
|
||||||
|
|
|
||||||
23
ip/iplink.c
23
ip/iplink.c
|
|
@ -105,6 +105,7 @@ void iplink_usage(void)
|
||||||
" [ nomaster ]\n"
|
" [ nomaster ]\n"
|
||||||
" [ addrgenmode { eui64 | none | stable_secret | random } ]\n"
|
" [ addrgenmode { eui64 | none | stable_secret | random } ]\n"
|
||||||
" [ protodown { on | off } ]\n"
|
" [ protodown { on | off } ]\n"
|
||||||
|
" [ protodown_reason PREASON { on | off } ]\n"
|
||||||
" [ gso_max_size BYTES ] | [ gso_max_segs PACKETS ]\n"
|
" [ gso_max_size BYTES ] | [ gso_max_segs PACKETS ]\n"
|
||||||
"\n"
|
"\n"
|
||||||
" ip link show [ DEVICE | group GROUP ] [up] [master DEV] [vrf NAME] [type TYPE]\n"
|
" ip link show [ DEVICE | group GROUP ] [up] [master DEV] [vrf NAME] [type TYPE]\n"
|
||||||
|
|
@ -903,6 +904,28 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type)
|
||||||
return on_off("protodown", *argv);
|
return on_off("protodown", *argv);
|
||||||
addattr8(&req->n, sizeof(*req), IFLA_PROTO_DOWN,
|
addattr8(&req->n, sizeof(*req), IFLA_PROTO_DOWN,
|
||||||
proto_down);
|
proto_down);
|
||||||
|
} else if (strcmp(*argv, "protodown_reason") == 0) {
|
||||||
|
struct rtattr *pr;
|
||||||
|
__u32 preason = 0, prvalue = 0, prmask = 0;
|
||||||
|
|
||||||
|
NEXT_ARG();
|
||||||
|
if (protodown_reason_a2n(&preason, *argv))
|
||||||
|
invarg("invalid protodown reason\n", *argv);
|
||||||
|
NEXT_ARG();
|
||||||
|
prmask = 1 << preason;
|
||||||
|
if (matches(*argv, "on") == 0)
|
||||||
|
prvalue |= prmask;
|
||||||
|
else if (matches(*argv, "off") == 0)
|
||||||
|
prvalue &= ~prmask;
|
||||||
|
else
|
||||||
|
return on_off("protodown_reason", *argv);
|
||||||
|
pr = addattr_nest(&req->n, sizeof(*req),
|
||||||
|
IFLA_PROTO_DOWN_REASON | NLA_F_NESTED);
|
||||||
|
addattr32(&req->n, sizeof(*req),
|
||||||
|
IFLA_PROTO_DOWN_REASON_MASK, prmask);
|
||||||
|
addattr32(&req->n, sizeof(*req),
|
||||||
|
IFLA_PROTO_DOWN_REASON_VALUE, prvalue);
|
||||||
|
addattr_nest_end(&req->n, pr);
|
||||||
} else if (strcmp(*argv, "gso_max_size") == 0) {
|
} else if (strcmp(*argv, "gso_max_size") == 0) {
|
||||||
unsigned int max_size;
|
unsigned int max_size;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -682,3 +682,95 @@ int nl_proto_a2n(__u32 *id, const char *arg)
|
||||||
*id = res;
|
*id = res;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define PROTODOWN_REASON_NUM_BITS 32
|
||||||
|
static char *protodown_reason_tab[PROTODOWN_REASON_NUM_BITS] = {
|
||||||
|
};
|
||||||
|
|
||||||
|
static int protodown_reason_init;
|
||||||
|
|
||||||
|
static void protodown_reason_initialize(void)
|
||||||
|
{
|
||||||
|
struct dirent *de;
|
||||||
|
DIR *d;
|
||||||
|
|
||||||
|
protodown_reason_init = 1;
|
||||||
|
|
||||||
|
d = opendir(CONFDIR "/protodown_reasons.d");
|
||||||
|
if (!d)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while ((de = readdir(d)) != NULL) {
|
||||||
|
char path[PATH_MAX];
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if (*de->d_name == '.')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* only consider filenames ending in '.conf' */
|
||||||
|
len = strlen(de->d_name);
|
||||||
|
if (len <= 5)
|
||||||
|
continue;
|
||||||
|
if (strcmp(de->d_name + len - 5, ".conf"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), CONFDIR "/protodown_reasons.d/%s",
|
||||||
|
de->d_name);
|
||||||
|
rtnl_tab_initialize(path, protodown_reason_tab,
|
||||||
|
PROTODOWN_REASON_NUM_BITS);
|
||||||
|
}
|
||||||
|
closedir(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
int protodown_reason_n2a(int id, char *buf, int len)
|
||||||
|
{
|
||||||
|
if (id < 0 || id >= PROTODOWN_REASON_NUM_BITS)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (numeric) {
|
||||||
|
snprintf(buf, len, "%d", id);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!protodown_reason_init)
|
||||||
|
protodown_reason_initialize();
|
||||||
|
|
||||||
|
if (protodown_reason_tab[id])
|
||||||
|
snprintf(buf, len, "%s", protodown_reason_tab[id]);
|
||||||
|
else
|
||||||
|
snprintf(buf, len, "%d", id);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int protodown_reason_a2n(__u32 *id, const char *arg)
|
||||||
|
{
|
||||||
|
static char *cache;
|
||||||
|
static unsigned long res;
|
||||||
|
char *end;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (cache && strcmp(cache, arg) == 0) {
|
||||||
|
*id = res;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!protodown_reason_init)
|
||||||
|
protodown_reason_initialize();
|
||||||
|
|
||||||
|
for (i = 0; i < PROTODOWN_REASON_NUM_BITS; i++) {
|
||||||
|
if (protodown_reason_tab[i] &&
|
||||||
|
strcmp(protodown_reason_tab[i], arg) == 0) {
|
||||||
|
cache = protodown_reason_tab[i];
|
||||||
|
res = i;
|
||||||
|
*id = res;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res = strtoul(arg, &end, 0);
|
||||||
|
if (!end || end == arg || *end || res >= PROTODOWN_REASON_NUM_BITS)
|
||||||
|
return -1;
|
||||||
|
*id = res;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,9 @@ ip-link \- network device configuration
|
||||||
.br
|
.br
|
||||||
.RB "[ " protodown " { " on " | " off " } ]"
|
.RB "[ " protodown " { " on " | " off " } ]"
|
||||||
.br
|
.br
|
||||||
|
.RB "[ " protodown_reason
|
||||||
|
.IR PREASON " { " on " | " off " } ]"
|
||||||
|
.br
|
||||||
.RB "[ " trailers " { " on " | " off " } ]"
|
.RB "[ " trailers " { " on " | " off " } ]"
|
||||||
.br
|
.br
|
||||||
.RB "[ " txqueuelen
|
.RB "[ " txqueuelen
|
||||||
|
|
@ -1924,6 +1927,13 @@ state on the device. Indicates that a protocol error has been detected
|
||||||
on the port. Switch drivers can react to this error by doing a phys
|
on the port. Switch drivers can react to this error by doing a phys
|
||||||
down on the switch port.
|
down on the switch port.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.BR "protodown_reason PREASON on " or " off"
|
||||||
|
set
|
||||||
|
.B PROTODOWN
|
||||||
|
reasons on the device. protodown reason bit names can be enumerated under
|
||||||
|
/etc/iproute2/protodown_reasons.d/. possible reasons bits 0-31
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BR "dynamic on " or " dynamic off"
|
.BR "dynamic on " or " dynamic off"
|
||||||
change the
|
change the
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue