]> git.proxmox.com Git - mirror_iproute2.git/blobdiff - ip/ipaddress.c
ip: add IP_LIB_DIR environment variable
[mirror_iproute2.git] / ip / ipaddress.c
index b7e9132404b1619f2a41e8fed330ca477588de76..571346b15cc358db7315cbdde4ff3dc45eeafdfc 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/sockios.h>
 #include <linux/net_namespace.h>
 
-#include "utils.h"
 #include "rt_names.h"
 #include "utils.h"
 #include "ll_map.h"
@@ -745,7 +744,7 @@ static void __print_link_stats(FILE *fp, struct rtattr *tb[])
                close_json_object();
        } else {
                /* RX stats */
-               fprintf(fp, "    RX: bytes  packets  errors  dropped overrun mcast   %s%s",
+               fprintf(fp, "    RX: bytes  packets  errors  dropped missed  mcast   %s%s",
                        s->rx_compressed ? "compressed" : "", _SL_);
 
                fprintf(fp, "    ");
@@ -753,7 +752,7 @@ static void __print_link_stats(FILE *fp, struct rtattr *tb[])
                print_num(fp, 8, s->rx_packets);
                print_num(fp, 7, s->rx_errors);
                print_num(fp, 7, s->rx_dropped);
-               print_num(fp, 7, s->rx_over_errors);
+               print_num(fp, 7, s->rx_missed_errors);
                print_num(fp, 7, s->multicast);
                if (s->rx_compressed)
                        print_num(fp, 7, s->rx_compressed);
@@ -761,14 +760,14 @@ static void __print_link_stats(FILE *fp, struct rtattr *tb[])
                /* RX error stats */
                if (show_stats > 1) {
                        fprintf(fp, "%s", _SL_);
-                       fprintf(fp, "    RX errors: length   crc     frame   fifo    missed%s%s",
+                       fprintf(fp, "    RX errors: length   crc     frame   fifo    overrun%s%s",
                                s->rx_nohandler ? "   nohandler" : "", _SL_);
                        fprintf(fp, "               ");
                        print_num(fp, 8, s->rx_length_errors);
                        print_num(fp, 7, s->rx_crc_errors);
                        print_num(fp, 7, s->rx_frame_errors);
                        print_num(fp, 7, s->rx_fifo_errors);
-                       print_num(fp, 7, s->rx_missed_errors);
+                       print_num(fp, 7, s->rx_over_errors);
                        if (s->rx_nohandler)
                                print_num(fp, 7, s->rx_nohandler);
                }
@@ -875,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;
@@ -1011,6 +1049,24 @@ int print_linkinfo(struct nlmsghdr *n, void *arg)
                                                       ifi->ifi_type,
                                                       b1, sizeof(b1)));
                }
+               if (tb[IFLA_PERM_ADDRESS]) {
+                       unsigned int len = RTA_PAYLOAD(tb[IFLA_PERM_ADDRESS]);
+
+                       if (!tb[IFLA_ADDRESS] ||
+                           RTA_PAYLOAD(tb[IFLA_ADDRESS]) != len ||
+                           memcmp(RTA_DATA(tb[IFLA_PERM_ADDRESS]),
+                                  RTA_DATA(tb[IFLA_ADDRESS]), len)) {
+                               print_string(PRINT_FP, NULL, " permaddr ", NULL);
+                               print_color_string(PRINT_ANY,
+                                                  COLOR_MAC,
+                                                  "permaddr",
+                                                  "%s",
+                                                  ll_addr_n2a(RTA_DATA(tb[IFLA_PERM_ADDRESS]),
+                                                              RTA_PAYLOAD(tb[IFLA_PERM_ADDRESS]),
+                                                              ifi->ifi_type,
+                                                              b1, sizeof(b1)));
+                       }
+               }
        }
 
        if (tb[IFLA_LINK_NETNSID]) {
@@ -1049,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])
@@ -1215,52 +1268,65 @@ static unsigned int get_ifa_flags(struct ifaddrmsg *ifa,
                ifa->ifa_flags;
 }
 
-/* Mapping from argument to address flag mask */
-static const struct {
+/* Mapping from argument to address flag mask and attributes */
+static const struct ifa_flag_data_t {
        const char *name;
-       unsigned long value;
-} ifa_flag_names[] = {
-       { "secondary",          IFA_F_SECONDARY },
-       { "temporary",          IFA_F_SECONDARY },
-       { "nodad",              IFA_F_NODAD },
-       { "optimistic",         IFA_F_OPTIMISTIC },
-       { "dadfailed",          IFA_F_DADFAILED },
-       { "home",               IFA_F_HOMEADDRESS },
-       { "deprecated",         IFA_F_DEPRECATED },
-       { "tentative",          IFA_F_TENTATIVE },
-       { "permanent",          IFA_F_PERMANENT },
-       { "mngtmpaddr",         IFA_F_MANAGETEMPADDR },
-       { "noprefixroute",      IFA_F_NOPREFIXROUTE },
-       { "autojoin",           IFA_F_MCAUTOJOIN },
-       { "stable-privacy",     IFA_F_STABLE_PRIVACY },
+       unsigned long mask;
+       bool readonly;
+       bool v6only;
+} ifa_flag_data[] = {
+       { .name = "secondary",          .mask = IFA_F_SECONDARY,        .readonly = true,       .v6only = false},
+       { .name = "temporary",          .mask = IFA_F_SECONDARY,        .readonly = true,       .v6only = false},
+       { .name = "nodad",              .mask = IFA_F_NODAD,            .readonly = false,      .v6only = true},
+       { .name = "optimistic",         .mask = IFA_F_OPTIMISTIC,       .readonly = false,      .v6only = true},
+       { .name = "dadfailed",          .mask = IFA_F_DADFAILED,        .readonly = true,       .v6only = true},
+       { .name = "home",               .mask = IFA_F_HOMEADDRESS,      .readonly = false,      .v6only = true},
+       { .name = "deprecated",         .mask = IFA_F_DEPRECATED,       .readonly = true,       .v6only = true},
+       { .name = "tentative",          .mask = IFA_F_TENTATIVE,        .readonly = true,       .v6only = true},
+       { .name = "permanent",          .mask = IFA_F_PERMANENT,        .readonly = true,       .v6only = true},
+       { .name = "mngtmpaddr",         .mask = IFA_F_MANAGETEMPADDR,   .readonly = false,      .v6only = true},
+       { .name = "noprefixroute",      .mask = IFA_F_NOPREFIXROUTE,    .readonly = false,      .v6only = false},
+       { .name = "autojoin",           .mask = IFA_F_MCAUTOJOIN,       .readonly = false,      .v6only = false},
+       { .name = "stable-privacy",     .mask = IFA_F_STABLE_PRIVACY,   .readonly = true,       .v6only = true},
 };
 
+/* Returns a pointer to the data structure for a particular interface flag, or null if no flag could be found */
+static const struct ifa_flag_data_t* lookup_flag_data_by_name(const char* flag_name) {
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(ifa_flag_data); ++i) {
+               if (strcmp(flag_name, ifa_flag_data[i].name) == 0)
+                       return &ifa_flag_data[i];
+       }
+        return NULL;
+}
+
 static void print_ifa_flags(FILE *fp, const struct ifaddrmsg *ifa,
                            unsigned int flags)
 {
        unsigned int i;
 
-       for (i = 0; i < ARRAY_SIZE(ifa_flag_names); i++) {
-               unsigned long mask = ifa_flag_names[i].value;
+       for (i = 0; i < ARRAY_SIZE(ifa_flag_data); i++) {
+               const struct ifa_flag_data_t* flag_data = &ifa_flag_data[i];
 
-               if (mask == IFA_F_PERMANENT) {
-                       if (!(flags & mask))
+               if (flag_data->mask == IFA_F_PERMANENT) {
+                       if (!(flags & flag_data->mask))
                                print_bool(PRINT_ANY,
                                           "dynamic", "dynamic ", true);
-               } else if (flags & mask) {
-                       if (mask == IFA_F_SECONDARY &&
+               } else if (flags & flag_data->mask) {
+                       if (flag_data->mask == IFA_F_SECONDARY &&
                            ifa->ifa_family == AF_INET6) {
                                print_bool(PRINT_ANY,
                                           "temporary", "temporary ", true);
                        } else {
                                print_string(PRINT_FP, NULL,
-                                            "%s ", ifa_flag_names[i].name);
+                                            "%s ", flag_data->name);
                                print_bool(PRINT_JSON,
-                                          ifa_flag_names[i].name, NULL, true);
+                                          flag_data->name, NULL, true);
                        }
                }
 
-               flags &= ~mask;
+               flags &= ~flag_data->mask;
        }
 
        if (flags) {
@@ -1279,7 +1345,6 @@ static void print_ifa_flags(FILE *fp, const struct ifaddrmsg *ifa,
 static int get_filter(const char *arg)
 {
        bool inv = false;
-       unsigned int i;
 
        if (arg[0] == '-') {
                inv = true;
@@ -1295,18 +1360,16 @@ static int get_filter(const char *arg)
                arg = "secondary";
        }
 
-       for (i = 0; i < ARRAY_SIZE(ifa_flag_names); i++) {
-               if (strcmp(arg, ifa_flag_names[i].name))
-                       continue;
+       const struct ifa_flag_data_t* flag_data = lookup_flag_data_by_name(arg);
+       if (flag_data == NULL)
+               return -1;
 
-               if (inv)
-                       filter.flags &= ~ifa_flag_names[i].value;
-               else
-                       filter.flags |= ifa_flag_names[i].value;
-               filter.flagmask |= ifa_flag_names[i].value;
-               return 0;
-       }
-       return -1;
+       if (inv)
+               filter.flags &= ~flag_data->mask;
+       else
+               filter.flags |= flag_data->mask;
+       filter.flagmask |= flag_data->mask;
+       return 0;
 }
 
 static int ifa_label_match_rta(int ifindex, const struct rtattr *rta)
@@ -2312,25 +2375,15 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv)
                        preferred_lftp = *argv;
                        if (set_lifetime(&preferred_lft, *argv))
                                invarg("preferred_lft value", *argv);
-               } else if (strcmp(*argv, "home") == 0) {
-                       if (req.ifa.ifa_family == AF_INET6)
-                               ifa_flags |= IFA_F_HOMEADDRESS;
-                       else
-                               fprintf(stderr, "Warning: home option can be set only for IPv6 addresses\n");
-               } else if (strcmp(*argv, "nodad") == 0) {
-                       if (req.ifa.ifa_family == AF_INET6)
-                               ifa_flags |= IFA_F_NODAD;
-                       else
-                               fprintf(stderr, "Warning: nodad option can be set only for IPv6 addresses\n");
-               } else if (strcmp(*argv, "mngtmpaddr") == 0) {
-                       if (req.ifa.ifa_family == AF_INET6)
-                               ifa_flags |= IFA_F_MANAGETEMPADDR;
-                       else
-                               fprintf(stderr, "Warning: mngtmpaddr option can be set only for IPv6 addresses\n");
-               } else if (strcmp(*argv, "noprefixroute") == 0) {
-                       ifa_flags |= IFA_F_NOPREFIXROUTE;
-               } else if (strcmp(*argv, "autojoin") == 0) {
-                       ifa_flags |= IFA_F_MCAUTOJOIN;
+               } else if (lookup_flag_data_by_name(*argv)) {
+                       const struct ifa_flag_data_t* flag_data = lookup_flag_data_by_name(*argv);
+                       if (flag_data->readonly) {
+                               fprintf(stderr, "Warning: %s option is not mutable from userspace\n", flag_data->name);
+                       } else if (flag_data->v6only && req.ifa.ifa_family != AF_INET6) {
+                               fprintf(stderr, "Warning: %s option can be set only for IPv6 addresses\n", flag_data->name);
+                       } else {
+                               ifa_flags |= flag_data->mask;
+                       }
                } else {
                        if (strcmp(*argv, "local") == 0)
                                NEXT_ARG();