]> git.ipfire.org Git - thirdparty/iproute2.git/commitdiff
iplink: add support for protodown reason
authorRoopa Prabhu <roopa@cumulusnetworks.com>
Sat, 29 Aug 2020 03:42:56 +0000 (20:42 -0700)
committerDavid Ahern <dsahern@gmail.com>
Wed, 2 Sep 2020 01:52:13 +0000 (19:52 -0600)
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>
include/rt_names.h
ip/ipaddress.c
ip/iplink.c
lib/rt_names.c
man/man8/ip-link.8.in

index 7afce1705f77590c779e2046e6ddf9fd5b98c8e6..990ed7f22e6915e21573bad983253c4beaf4eb9e 100644 (file)
@@ -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);
 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;
 
 #endif
index ccf67d1dd55cfac916db45350b2b4cb180e643a0..7a68fa02db4da87f1900e436bddf6254db2daa6b 100644 (file)
@@ -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)
 {
        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);
        }
 
-       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])
+               print_proto_down(fp, tb);
 
        if (show_details) {
                if (tb[IFLA_PROMISCUITY])
index 5ec33a98b96e95f00ebd88dd511f0fd482fd5db7..d6b766de1fcf22c9ee11559bb44ee8496494b2af 100644 (file)
@@ -105,6 +105,7 @@ void iplink_usage(void)
                "               [ nomaster ]\n"
                "               [ addrgenmode { eui64 | none | stable_secret | random } ]\n"
                "               [ protodown { on | off } ]\n"
+               "               [ protodown_reason PREASON { on | off } ]\n"
                "               [ gso_max_size BYTES ] | [ gso_max_segs PACKETS ]\n"
                "\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);
                        addattr8(&req->n, sizeof(*req), IFLA_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) {
                        unsigned int max_size;
 
index c40d2e7722b16733032acc549d2612d7ac59bb44..ca0680a121502d44a5eee5ea331df9c96efd9cd8 100644 (file)
@@ -682,3 +682,95 @@ int nl_proto_a2n(__u32 *id, const char *arg)
        *id = res;
        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;
+}
index 367105b72f44eac1f449af45cdd1f87d0e8ef77b..4acb5d47a8546d691c671488b19dc6e117d592b0 100644 (file)
@@ -75,6 +75,9 @@ ip-link \- network device configuration
 .br
 .RB "[ " protodown " { " on " | " off " } ]"
 .br
+.RB "[ " protodown_reason
+.IR PREASON " { " on " | " off " } ]"
+.br
 .RB "[ " trailers " { " on " | " off " } ]"
 .br
 .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
 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
 .BR "dynamic on " or " dynamic off"
 change the