]> git.ipfire.org Git - thirdparty/iproute2.git/commitdiff
ip: Support IP address protocol
authorPetr Machata <petrm@nvidia.com>
Mon, 27 Mar 2023 16:12:05 +0000 (18:12 +0200)
committerDavid Ahern <dsahern@kernel.org>
Thu, 30 Mar 2023 15:53:13 +0000 (09:53 -0600)
IPv4 and IPv6 addresses can be assigned a protocol value that indicates the
provenance of the IP address. The attribute is modeled after ip route
protocols, and essentially allows the administrator or userspace stack to
tag addresses in some way that makes sense to the actor in question.
Support for this feature was merged with commit 47f0bd503210 ("net: Add new
protocol attribute to IP addresses"), for kernel 5.18.

In this patch, add support for setting the protocol attribute at IP address
addition, replacement, and listing requests.

An example session with the feature in action:

# ip address add dev d 192.0.2.1/28 proto 0xab
# ip address show dev d
26: d: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 06:29:74:fd:1f:eb brd ff:ff:ff:ff:ff:ff
    inet 192.0.2.1/28 scope global proto 0xab d
       valid_lft forever preferred_lft forever

# ip address replace dev d 192.0.2.1/28 proto 0x11
# ip address show dev d
26: d: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 06:29:74:fd:1f:eb brd ff:ff:ff:ff:ff:ff
    inet 192.0.2.1/28 scope global proto 0x11 d
       valid_lft forever preferred_lft forever

A JSON dump. The protocol value is always provided as a string, even in
numeric mode, to provide a consistent interface.

# ip -j address show dev d | jq
[
  {
    "ifindex": 26,
    "ifname": "d",
    "flags": [
      "BROADCAST",
      "NOARP"
    ],
    "mtu": 1500,
    "qdisc": "noop",
    "operstate": "DOWN",
    "group": "default",
    "txqlen": 1000,
    "link_type": "ether",
    "address": "06:29:74:fd:1f:eb",
    "broadcast": "ff:ff:ff:ff:ff:ff",
    "addr_info": [
      {
        "family": "inet",
        "local": "192.0.2.1",
        "prefixlen": 28,
        "scope": "global",
        "protocol": "0x11",
        "label": "d",
        "valid_life_time": 4294967295,
        "preferred_life_time": 4294967295
      }
    ]
  }
]

Signed-off-by: Petr Machata <petrm@nvidia.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
include/rt_names.h
ip/ip_common.h
ip/ipaddress.c
lib/rt_names.c

index 6358650db404f600c2cd802b5f6d68298a4bddca..e96d80f30554cd9672e8304cad6896e2a9591445 100644 (file)
@@ -5,6 +5,7 @@
 #include <asm/types.h>
 
 const char *rtnl_rtprot_n2a(int id, char *buf, int len);
+const char *rtnl_addrprot_n2a(int id, char *buf, int len);
 const char *rtnl_rtscope_n2a(int id, char *buf, int len);
 const char *rtnl_rttable_n2a(__u32 id, char *buf, int len);
 const char *rtnl_rtrealm_n2a(int id, char *buf, int len);
@@ -13,6 +14,7 @@ const char *rtnl_dsfield_get_name(int id);
 const char *rtnl_group_n2a(int id, char *buf, int len);
 
 int rtnl_rtprot_a2n(__u32 *id, const char *arg);
+int rtnl_addrprot_a2n(__u32 *id, const char *arg);
 int rtnl_rtscope_a2n(__u32 *id, const char *arg);
 int rtnl_rttable_a2n(__u32 *id, const char *arg);
 int rtnl_rtrealm_a2n(__u32 *id, const char *arg);
index c4cb1bcb1e3a78ab504a1ef9d9c5980f2a176a09..4a20ec3cba62a0f70f1ef12ee7ce99064dace81b 100644 (file)
@@ -28,6 +28,8 @@ struct link_filter {
        char *kind;
        char *slave_kind;
        int target_nsid;
+       bool have_proto;
+       int proto;
 };
 
 const char *get_ip_lib_dir(void);
index 9ba8143803422fa6fac72f1959acb56a6bba7f4b..41055c43ec13f6801b832cf9f439f67f9705d32c 100644 (file)
@@ -57,11 +57,13 @@ static void usage(void)
                "       ip address [ show [ dev IFNAME ] [ scope SCOPE-ID ] [ master DEVICE ]\n"
                "                         [ nomaster ]\n"
                "                         [ type TYPE ] [ to PREFIX ] [ FLAG-LIST ]\n"
-               "                         [ label LABEL ] [up] [ vrf NAME ] ]\n"
+               "                         [ label LABEL ] [up] [ vrf NAME ]\n"
+               "                         [ proto ADDRPROTO ] ]\n"
                "       ip address {showdump|restore}\n"
                "IFADDR := PREFIX | ADDR peer PREFIX\n"
                "          [ broadcast ADDR ] [ anycast ADDR ]\n"
                "          [ label IFNAME ] [ scope SCOPE-ID ] [ metric METRIC ]\n"
+               "          [ proto ADDRPROTO ]\n"
                "SCOPE-ID := [ host | link | global | NUMBER ]\n"
                "FLAG-LIST := [ FLAG-LIST ] FLAG\n"
                "FLAG  := [ permanent | dynamic | secondary | primary |\n"
@@ -70,7 +72,9 @@ static void usage(void)
                "CONFFLAG-LIST := [ CONFFLAG-LIST ] CONFFLAG\n"
                "CONFFLAG  := [ home | nodad | mngtmpaddr | noprefixroute | autojoin ]\n"
                "LIFETIME := [ valid_lft LFT ] [ preferred_lft LFT ]\n"
-               "LFT := forever | SECONDS\n");
+               "LFT := forever | SECONDS\n"
+               "ADDRPROTO := [ NAME | NUMBER ]\n"
+               );
        iplink_types_usage();
 
        exit(-1);
@@ -1568,6 +1572,9 @@ int print_addrinfo(struct nlmsghdr *n, void *arg)
 
        if (filter.family && filter.family != ifa->ifa_family)
                return 0;
+       if (filter.have_proto && rta_tb[IFA_PROTO] &&
+           filter.proto != rta_getattr_u8(rta_tb[IFA_PROTO]))
+               return 0;
 
        if (ifa_label_match_rta(ifa->ifa_index, rta_tb[IFA_LABEL]))
                return 0;
@@ -1675,6 +1682,14 @@ int print_addrinfo(struct nlmsghdr *n, void *arg)
 
        print_ifa_flags(fp, ifa, ifa_flags);
 
+       if (rta_tb[IFA_PROTO]) {
+               __u8 proto = rta_getattr_u8(rta_tb[IFA_PROTO]);
+
+               if (proto || is_json_context())
+                       print_string(PRINT_ANY, "protocol", "proto %s ",
+                                    rtnl_addrprot_n2a(proto, b1, sizeof(b1)));
+       }
+
        if (rta_tb[IFA_LABEL])
                print_string(PRINT_ANY,
                             "label",
@@ -2196,6 +2211,14 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
                        } else {
                                filter.kind = *argv;
                        }
+               } else if (strcmp(*argv, "proto") == 0) {
+                       __u8 proto;
+
+                       NEXT_ARG();
+                       if (get_u8(&proto, *argv, 0))
+                               invarg("\"proto\" value is invalid\n", *argv);
+                       filter.have_proto = true;
+                       filter.proto = proto;
                } else {
                        if (strcmp(*argv, "dev") == 0)
                                NEXT_ARG();
@@ -2520,6 +2543,13 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv)
                        } else {
                                ifa_flags |= flag_data->mask;
                        }
+               } else if (strcmp(*argv, "proto") == 0) {
+                       __u8 proto;
+
+                       NEXT_ARG();
+                       if (get_u8(&proto, *argv, 0))
+                               invarg("\"proto\" value is invalid\n", *argv);
+                       addattr8(&req.n, sizeof(req), IFA_PROTO, proto);
                } else {
                        if (strcmp(*argv, "local") == 0)
                                NEXT_ARG();
index 2432224acc0a988fd3282d66417b7774e4ca8070..51d11fd056b1dfd4eb22271f4103f1c0897981c4 100644 (file)
@@ -226,6 +226,68 @@ int rtnl_rtprot_a2n(__u32 *id, const char *arg)
 }
 
 
+static char *rtnl_addrprot_tab[256] = {
+       [IFAPROT_UNSPEC]    = "unspec",
+       [IFAPROT_KERNEL_LO] = "kernel_lo",
+       [IFAPROT_KERNEL_RA] = "kernel_ra",
+       [IFAPROT_KERNEL_LL] = "kernel_ll",
+};
+static bool rtnl_addrprot_tab_initialized;
+
+static void rtnl_addrprot_initialize(void)
+{
+       rtnl_tab_initialize(CONFDIR "/rt_addrprotos",
+                           rtnl_addrprot_tab,
+                           ARRAY_SIZE(rtnl_addrprot_tab));
+       rtnl_addrprot_tab_initialized = true;
+}
+
+const char *rtnl_addrprot_n2a(int id, char *buf, int len)
+{
+       if (id < 0 || id >= 256 || numeric)
+               goto numeric;
+       if (!rtnl_addrprot_tab_initialized)
+               rtnl_addrprot_initialize();
+       if (rtnl_addrprot_tab[id])
+               return rtnl_addrprot_tab[id];
+numeric:
+       snprintf(buf, len, "%#x", id);
+       return buf;
+}
+
+int rtnl_addrprot_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 (!rtnl_addrprot_tab_initialized)
+               rtnl_addrprot_initialize();
+
+       for (i = 0; i < 256; i++) {
+               if (rtnl_addrprot_tab[i] &&
+                   strcmp(rtnl_addrprot_tab[i], arg) == 0) {
+                       cache = rtnl_addrprot_tab[i];
+                       res = i;
+                       *id = res;
+                       return 0;
+               }
+       }
+
+       res = strtoul(arg, &end, 0);
+       if (!end || end == arg || *end || res > 255)
+               return -1;
+       *id = res;
+       return 0;
+}
+
+
 static char *rtnl_rtscope_tab[256] = {
        [RT_SCOPE_UNIVERSE]     = "global",
        [RT_SCOPE_NOWHERE]      = "nowhere",