195 lines
7.1 KiB
Diff
195 lines
7.1 KiB
Diff
From 9d59c86e575b5373d73f021f569ae520bc229ec5 Mon Sep 17 00:00:00 2001
|
|
From: "Ian K. Coolidge" <icoolidge@google.com>
|
|
Date: Wed, 27 May 2020 11:03:45 -0700
|
|
Subject: iproute2: ip addr: Organize flag properties structurally
|
|
|
|
This creates a nice systematic way to check that the various flags are
|
|
mutable from userspace and that the address family is valid.
|
|
|
|
Mutability properties are preserved to avoid introducing any behavioral
|
|
change in this CL. However, previously, immutable flags were ignored and
|
|
fell through to this confusing error:
|
|
|
|
Error: either "local" is duplicate, or "dadfailed" is a garbage.
|
|
|
|
But now, they just warn more explicitly:
|
|
|
|
Warning: dadfailed option is not mutable from userspace
|
|
Signed-off-by: David Ahern <dsahern@gmail.com>
|
|
|
|
Conflict:NA
|
|
Reference:https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit?id=9d59c86e575b5373d73f021f569ae520bc229ec5
|
|
|
|
---
|
|
ip/ipaddress.c | 112 ++++++++++++++++++++++++++++-----------------------------
|
|
1 file changed, 55 insertions(+), 57 deletions(-)
|
|
|
|
diff --git a/ip/ipaddress.c b/ip/ipaddress.c
|
|
index 80d27ce27..403f70109 100644
|
|
--- a/ip/ipaddress.c
|
|
+++ b/ip/ipaddress.c
|
|
@@ -1233,52 +1233,63 @@ 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 = true, .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 = true},
|
|
+ { .name = "autojoin", .mask = IFA_F_MCAUTOJOIN, .readonly = false, .v6only = true},
|
|
+ { .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) {
|
|
+ for (int 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) {
|
|
@@ -1297,7 +1308,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;
|
|
@@ -1313,18 +1323,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)
|
|
@@ -2330,25 +2338,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();
|
|
--
|
|
cgit 1.2.3-korg
|
|
|