#include <linux/sockios.h>
#include <linux/net_namespace.h>
-#include "utils.h"
#include "rt_names.h"
#include "utils.h"
#include "ll_map.h"
vf_spoofchk->setting);
}
+ if (vf[IFLA_VF_IB_NODE_GUID]) {
+ struct ifla_vf_guid *guid = RTA_DATA(vf[IFLA_VF_IB_NODE_GUID]);
+ uint64_t node_guid = ntohll(guid->guid);
+
+ print_string(PRINT_ANY, "node guid", ", NODE_GUID %s",
+ ll_addr_n2a((const unsigned char *)&node_guid,
+ sizeof(node_guid), ARPHRD_INFINIBAND,
+ b1, sizeof(b1)));
+ }
+ if (vf[IFLA_VF_IB_PORT_GUID]) {
+ struct ifla_vf_guid *guid = RTA_DATA(vf[IFLA_VF_IB_PORT_GUID]);
+ uint64_t port_guid = ntohll(guid->guid);
+
+ print_string(PRINT_ANY, "port guid", ", PORT_GUID %s",
+ ll_addr_n2a((const unsigned char *)&port_guid,
+ sizeof(port_guid), ARPHRD_INFINIBAND,
+ b1, sizeof(b1)));
+ }
if (vf[IFLA_VF_LINK_STATE]) {
struct ifla_vf_link_state *vf_linkstate =
RTA_DATA(vf[IFLA_VF_LINK_STATE]);
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, " ");
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);
/* 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);
}
}
}
+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;
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]) {
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])
close_json_array(PRINT_JSON, NULL);
}
- print_string(PRINT_FP, NULL, "%s", _SL_);
+ print_string(PRINT_FP, NULL, "%s", "\n");
fflush(fp);
return 1;
}
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) {
static int get_filter(const char *arg)
{
bool inv = false;
- unsigned int i;
if (arg[0] == '-') {
inv = true;
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)
struct ifaddrmsg *ifa = NLMSG_DATA(n);
open_json_object(NULL);
- print_int(PRINT_ANY, "index", "if%d:\n", ifa->ifa_index);
+ print_int(PRINT_ANY, "index", "if%d:", ifa->ifa_index);
+ print_nl();
print_addrinfo(n, stdout);
close_json_object();
return 0;
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();