iproute2/lib/rt_names.c

894 lines
18 KiB
C
Raw Normal View History

/* SPDX-License-Identifier: GPL-2.0-or-later */
2004-04-16 04:56:59 +08:00
/*
* rt_names.c rtnetlink names DB.
*
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <dirent.h>
#include <limits.h>
#include <errno.h>
#include <asm/types.h>
#include <linux/rtnetlink.h>
#include "rt_names.h"
#include "utils.h"
#define NAME_MAX_LEN 512
int numeric;
struct rtnl_hash_entry {
struct rtnl_hash_entry *next;
const char *name;
unsigned int id;
};
static int fread_id_name(FILE *fp, int *id, char *namebuf)
{
char buf[NAME_MAX_LEN];
while (fgets(buf, sizeof(buf), fp)) {
char *p = buf;
while (*p == ' ' || *p == '\t')
p++;
if (*p == '#' || *p == '\n' || *p == 0)
continue;
if (sscanf(p, "0x%x %s\n", id, namebuf) != 2 &&
sscanf(p, "0x%x %s #", id, namebuf) != 2 &&
sscanf(p, "%d %s\n", id, namebuf) != 2 &&
sscanf(p, "%d %s #", id, namebuf) != 2) {
strcpy(namebuf, p);
return -1;
}
return 1;
}
return 0;
}
static int
rtnl_hash_initialize(const char *file, struct rtnl_hash_entry **hash, int size)
{
struct rtnl_hash_entry *entry;
FILE *fp;
int id;
char namebuf[NAME_MAX_LEN] = {0};
int ret;
fp = fopen(file, "r");
if (!fp)
return -errno;
while ((ret = fread_id_name(fp, &id, &namebuf[0]))) {
if (ret == -1) {
fprintf(stderr, "Database %s is corrupted at %s\n",
file, namebuf);
fclose(fp);
return -EINVAL;
}
if (id < 0)
continue;
entry = malloc(sizeof(*entry));
if (entry == NULL) {
fprintf(stderr, "malloc error: for entry\n");
break;
}
entry->id = id;
entry->name = strdup(namebuf);
entry->next = hash[id & (size - 1)];
hash[id & (size - 1)] = entry;
}
fclose(fp);
return 0;
}
static int rtnl_tab_initialize(const char *file, char **tab, int size)
2004-04-16 04:56:59 +08:00
{
FILE *fp;
int id;
char namebuf[NAME_MAX_LEN] = {0};
int ret;
2004-04-16 04:56:59 +08:00
fp = fopen(file, "r");
if (!fp)
return -errno;
2004-04-16 04:56:59 +08:00
while ((ret = fread_id_name(fp, &id, &namebuf[0]))) {
if (ret == -1) {
2004-04-16 04:56:59 +08:00
fprintf(stderr, "Database %s is corrupted at %s\n",
file, namebuf);
fclose(fp);
return -EINVAL;
2004-04-16 04:56:59 +08:00
}
if (id < 0 || id > size)
2004-04-16 04:56:59 +08:00
continue;
tab[id] = strdup(namebuf);
}
fclose(fp);
return 0;
2004-04-16 04:56:59 +08:00
}
static char *rtnl_rtprot_tab[256] = {
[RTPROT_UNSPEC] = "unspec",
[RTPROT_REDIRECT] = "redirect",
[RTPROT_KERNEL] = "kernel",
[RTPROT_BOOT] = "boot",
[RTPROT_STATIC] = "static",
[RTPROT_GATED] = "gated",
[RTPROT_RA] = "ra",
[RTPROT_MRT] = "mrt",
[RTPROT_ZEBRA] = "zebra",
[RTPROT_BIRD] = "bird",
[RTPROT_BABEL] = "babel",
[RTPROT_DNROUTED] = "dnrouted",
[RTPROT_XORP] = "xorp",
[RTPROT_NTK] = "ntk",
[RTPROT_DHCP] = "dhcp",
[RTPROT_KEEPALIVED] = "keepalived",
[RTPROT_BGP] = "bgp",
[RTPROT_ISIS] = "isis",
[RTPROT_OSPF] = "ospf",
[RTPROT_RIP] = "rip",
[RTPROT_EIGRP] = "eigrp",
2004-04-16 04:56:59 +08:00
};
struct tabhash {
enum { TAB, HASH } type;
union tab_or_hash {
char **tab;
struct rtnl_hash_entry **hash;
} data;
};
2004-04-16 04:56:59 +08:00
static void
rtnl_tabhash_readdir(const char *dirpath_base, const char *dirpath_overload,
const struct tabhash tabhash, const int size)
2004-04-16 04:56:59 +08:00
{
struct dirent *de;
DIR *d;
d = opendir(dirpath_base);
while (d && (de = readdir(d)) != NULL) {
char path[PATH_MAX];
size_t len;
struct stat sb;
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;
if (dirpath_overload) {
/* only consider filenames not present in
the overloading directory, e.g. /etc */
snprintf(path, sizeof(path), "%s/%s", dirpath_overload, de->d_name);
if (lstat(path, &sb) == 0)
continue;
}
/* load the conf file in the base directory, e.g., /usr */
snprintf(path, sizeof(path), "%s/%s", dirpath_base, de->d_name);
if (tabhash.type == TAB)
rtnl_tab_initialize(path, tabhash.data.tab, size);
else
rtnl_hash_initialize(path, tabhash.data.hash, size);
}
if (d)
closedir(d);
}
static void
rtnl_tabhash_initialize_dir(const char *ddir, const struct tabhash tabhash, const int size)
{
char dirpath_usr[PATH_MAX], dirpath_etc[PATH_MAX];
snprintf(dirpath_usr, sizeof(dirpath_usr), "%s/%s", CONF_USR_DIR, ddir);
snprintf(dirpath_etc, sizeof(dirpath_etc), "%s/%s", CONF_ETC_DIR, ddir);
/* load /usr/lib/iproute2/foo.d/X conf files, unless /etc/iproute2/foo.d/X exists */
rtnl_tabhash_readdir(dirpath_usr, dirpath_etc, tabhash, size);
/* load /etc/iproute2/foo.d/X conf files */
rtnl_tabhash_readdir(dirpath_etc, NULL, tabhash, size);
}
static void
rtnl_tab_initialize_dir(const char *ddir, char **tab, const int size)
{
struct tabhash tab_data = {.type = TAB, .data.tab = tab};
rtnl_tabhash_initialize_dir(ddir, tab_data, size);
}
static void
rtnl_hash_initialize_dir(const char *ddir, struct rtnl_hash_entry **hash,
const int size) {
struct tabhash hash_data = {.type = HASH, .data.hash = hash};
rtnl_tabhash_initialize_dir(ddir, hash_data, size);
}
static int rtnl_rtprot_init;
static void rtnl_rtprot_initialize(void)
{
int ret;
rtnl_rtprot_init = 1;
ret = rtnl_tab_initialize(CONF_ETC_DIR "/rt_protos",
rtnl_rtprot_tab, 256);
if (ret == -ENOENT)
rtnl_tab_initialize(CONF_USR_DIR "/rt_protos",
rtnl_rtprot_tab, 256);
rtnl_tab_initialize_dir("rt_protos.d", rtnl_rtprot_tab, 256);
2004-04-16 04:56:59 +08:00
}
const char *rtnl_rtprot_n2a(int id, char *buf, int len)
2004-04-16 04:56:59 +08:00
{
if (id < 0 || id >= 256 || numeric) {
snprintf(buf, len, "%u", id);
2004-04-16 04:56:59 +08:00
return buf;
}
if (!rtnl_rtprot_tab[id]) {
if (!rtnl_rtprot_init)
rtnl_rtprot_initialize();
}
if (rtnl_rtprot_tab[id])
return rtnl_rtprot_tab[id];
snprintf(buf, len, "%u", id);
2004-04-16 04:56:59 +08:00
return buf;
}
int rtnl_rtprot_a2n(__u32 *id, const char *arg)
2004-04-16 04:56:59 +08:00
{
static char *cache;
2004-04-16 04:56:59 +08:00
static unsigned long res;
char *end;
int i;
if (cache && strcmp(cache, arg) == 0) {
*id = res;
return 0;
}
if (!rtnl_rtprot_init)
rtnl_rtprot_initialize();
for (i = 0; i < 256; i++) {
2004-04-16 04:56:59 +08:00
if (rtnl_rtprot_tab[i] &&
strcmp(rtnl_rtprot_tab[i], arg) == 0) {
cache = rtnl_rtprot_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;
}
ip: Support IP address protocol 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>
2023-03-28 00:12:05 +08:00
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)
{
int ret;
ip: Support IP address protocol 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>
2023-03-28 00:12:05 +08:00
rtnl_addrprot_tab_initialized = true;
ret = rtnl_tab_initialize(CONF_ETC_DIR "/rt_addrprotos",
rtnl_addrprot_tab,
ARRAY_SIZE(rtnl_addrprot_tab));
if (ret == -ENOENT)
ret = rtnl_tab_initialize(CONF_USR_DIR "/rt_addrprotos",
rtnl_addrprot_tab,
ARRAY_SIZE(rtnl_addrprot_tab));
ip: Support IP address protocol 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>
2023-03-28 00:12:05 +08:00
}
const char *rtnl_addrprot_n2a(__u8 id, char *buf, int len)
ip: Support IP address protocol 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>
2023-03-28 00:12:05 +08:00
{
if (numeric)
ip: Support IP address protocol 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>
2023-03-28 00:12:05 +08:00
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(__u8 *id, const char *arg)
ip: Support IP address protocol 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>
2023-03-28 00:12:05 +08:00
{
unsigned long res;
ip: Support IP address protocol 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>
2023-03-28 00:12:05 +08:00
char *end;
int i;
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) {
*id = i;
ip: Support IP address protocol 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>
2023-03-28 00:12:05 +08:00
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",
[RT_SCOPE_HOST] = "host",
[RT_SCOPE_LINK] = "link",
[RT_SCOPE_SITE] = "site",
2004-04-16 04:56:59 +08:00
};
static int rtnl_rtscope_init;
static void rtnl_rtscope_initialize(void)
{
int ret;
2004-04-16 04:56:59 +08:00
rtnl_rtscope_init = 1;
ret = rtnl_tab_initialize(CONF_ETC_DIR "/rt_scopes",
rtnl_rtscope_tab, 256);
if (ret == -ENOENT)
rtnl_tab_initialize(CONF_USR_DIR "/rt_scopes",
rtnl_rtscope_tab, 256);
2004-04-16 04:56:59 +08:00
}
const char *rtnl_rtscope_n2a(int id, char *buf, int len)
2004-04-16 04:56:59 +08:00
{
if (id < 0 || id >= 256 || numeric) {
2004-04-16 04:56:59 +08:00
snprintf(buf, len, "%d", id);
return buf;
}
2004-04-16 04:56:59 +08:00
if (!rtnl_rtscope_tab[id]) {
if (!rtnl_rtscope_init)
rtnl_rtscope_initialize();
}
2004-04-16 04:56:59 +08:00
if (rtnl_rtscope_tab[id])
return rtnl_rtscope_tab[id];
2004-04-16 04:56:59 +08:00
snprintf(buf, len, "%d", id);
return buf;
}
int rtnl_rtscope_a2n(__u32 *id, const char *arg)
2004-04-16 04:56:59 +08:00
{
static const char *cache;
2004-04-16 04:56:59 +08:00
static unsigned long res;
char *end;
int i;
if (cache && strcmp(cache, arg) == 0) {
*id = res;
return 0;
}
if (!rtnl_rtscope_init)
rtnl_rtscope_initialize();
for (i = 0; i < 256; i++) {
2004-04-16 04:56:59 +08:00
if (rtnl_rtscope_tab[i] &&
strcmp(rtnl_rtscope_tab[i], arg) == 0) {
cache = rtnl_rtscope_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_rtrealm_tab[256] = {
2004-04-16 04:56:59 +08:00
"unknown",
};
static int rtnl_rtrealm_init;
static void rtnl_rtrealm_initialize(void)
{
int ret;
2004-04-16 04:56:59 +08:00
rtnl_rtrealm_init = 1;
ret = rtnl_tab_initialize(CONF_ETC_DIR "/rt_realms",
rtnl_rtrealm_tab, 256);
if (ret == -ENOENT)
rtnl_tab_initialize(CONF_USR_DIR "/rt_realms",
rtnl_rtrealm_tab, 256);
2004-04-16 04:56:59 +08:00
}
const char *rtnl_rtrealm_n2a(int id, char *buf, int len)
2004-04-16 04:56:59 +08:00
{
if (id < 0 || id >= 256 || numeric) {
2004-04-16 04:56:59 +08:00
snprintf(buf, len, "%d", id);
return buf;
}
if (!rtnl_rtrealm_tab[id]) {
if (!rtnl_rtrealm_init)
rtnl_rtrealm_initialize();
}
if (rtnl_rtrealm_tab[id])
return rtnl_rtrealm_tab[id];
snprintf(buf, len, "%d", id);
return buf;
}
int rtnl_rtrealm_a2n(__u32 *id, const char *arg)
2004-04-16 04:56:59 +08:00
{
static char *cache;
2004-04-16 04:56:59 +08:00
static unsigned long res;
char *end;
int i;
if (cache && strcmp(cache, arg) == 0) {
*id = res;
return 0;
}
if (!rtnl_rtrealm_init)
rtnl_rtrealm_initialize();
for (i = 0; i < 256; i++) {
2004-04-16 04:56:59 +08:00
if (rtnl_rtrealm_tab[i] &&
strcmp(rtnl_rtrealm_tab[i], arg) == 0) {
cache = rtnl_rtrealm_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 struct rtnl_hash_entry dflt_table_entry = { .name = "default" };
static struct rtnl_hash_entry main_table_entry = { .name = "main" };
static struct rtnl_hash_entry local_table_entry = { .name = "local" };
2004-04-16 04:56:59 +08:00
static struct rtnl_hash_entry *rtnl_rttable_hash[256] = {
[RT_TABLE_DEFAULT] = &dflt_table_entry,
[RT_TABLE_MAIN] = &main_table_entry,
[RT_TABLE_LOCAL] = &local_table_entry,
2004-04-16 04:56:59 +08:00
};
static int rtnl_rttable_init;
static void rtnl_rttable_initialize(void)
{
int i;
int ret;
2004-04-16 04:56:59 +08:00
rtnl_rttable_init = 1;
for (i = 0; i < 256; i++) {
if (rtnl_rttable_hash[i])
rtnl_rttable_hash[i]->id = i;
}
ret = rtnl_hash_initialize(CONF_ETC_DIR "/rt_tables",
rtnl_rttable_hash, 256);
if (ret == -ENOENT)
rtnl_hash_initialize(CONF_USR_DIR "/rt_tables",
rtnl_rttable_hash, 256);
rtnl_hash_initialize_dir("rt_tables.d", rtnl_rttable_hash, 256);
2004-04-16 04:56:59 +08:00
}
const char *rtnl_rttable_n2a(__u32 id, char *buf, int len)
2004-04-16 04:56:59 +08:00
{
struct rtnl_hash_entry *entry;
if (!rtnl_rttable_init)
rtnl_rttable_initialize();
entry = rtnl_rttable_hash[id & 255];
while (entry && entry->id != id)
entry = entry->next;
if (!numeric && entry)
return entry->name;
snprintf(buf, len, "%u", id);
2004-04-16 04:56:59 +08:00
return buf;
}
int rtnl_rttable_a2n(__u32 *id, const char *arg)
2004-04-16 04:56:59 +08:00
{
static const char *cache;
2004-04-16 04:56:59 +08:00
static unsigned long res;
struct rtnl_hash_entry *entry;
2004-04-16 04:56:59 +08:00
char *end;
unsigned long i;
2004-04-16 04:56:59 +08:00
if (cache && strcmp(cache, arg) == 0) {
*id = res;
return 0;
}
if (!rtnl_rttable_init)
rtnl_rttable_initialize();
for (i = 0; i < 256; i++) {
entry = rtnl_rttable_hash[i];
while (entry && strcmp(entry->name, arg))
entry = entry->next;
if (entry) {
cache = entry->name;
res = entry->id;
2004-04-16 04:56:59 +08:00
*id = res;
return 0;
}
}
i = strtoul(arg, &end, 0);
if (!end || end == arg || *end || i > RT_TABLE_MAX)
2004-04-16 04:56:59 +08:00
return -1;
*id = i;
return 0;
}
static char *rtnl_rtdsfield_tab[256] = {
2004-04-16 04:56:59 +08:00
"0",
};
static int rtnl_rtdsfield_init;
static void rtnl_rtdsfield_initialize(void)
{
int ret;
2004-04-16 04:56:59 +08:00
rtnl_rtdsfield_init = 1;
ret = rtnl_tab_initialize(CONF_ETC_DIR "/rt_dsfield",
rtnl_rtdsfield_tab, 256);
if (ret == -ENOENT)
rtnl_tab_initialize(CONF_USR_DIR "/rt_dsfield",
rtnl_rtdsfield_tab, 256);
2004-04-16 04:56:59 +08:00
}
const char *rtnl_dsfield_n2a(int id, char *buf, int len)
2004-04-16 04:56:59 +08:00
{
const char *name;
if (id < 0 || id >= 256) {
2004-04-16 04:56:59 +08:00
snprintf(buf, len, "%d", id);
return buf;
}
if (!numeric) {
name = rtnl_dsfield_get_name(id);
if (name != NULL)
return name;
}
snprintf(buf, len, "0x%02x", id);
return buf;
}
const char *rtnl_dsfield_get_name(int id)
{
if (id < 0 || id >= 256)
return NULL;
2004-04-16 04:56:59 +08:00
if (!rtnl_rtdsfield_tab[id]) {
if (!rtnl_rtdsfield_init)
rtnl_rtdsfield_initialize();
}
return rtnl_rtdsfield_tab[id];
2004-04-16 04:56:59 +08:00
}
int rtnl_dsfield_a2n(__u32 *id, const char *arg)
2004-04-16 04:56:59 +08:00
{
static char *cache;
2004-04-16 04:56:59 +08:00
static unsigned long res;
char *end;
int i;
if (cache && strcmp(cache, arg) == 0) {
*id = res;
return 0;
}
if (!rtnl_rtdsfield_init)
rtnl_rtdsfield_initialize();
for (i = 0; i < 256; i++) {
2004-04-16 04:56:59 +08:00
if (rtnl_rtdsfield_tab[i] &&
strcmp(rtnl_rtdsfield_tab[i], arg) == 0) {
cache = rtnl_rtdsfield_tab[i];
res = i;
*id = res;
return 0;
}
}
res = strtoul(arg, &end, 16);
if (!end || end == arg || *end || res > 255)
return -1;
*id = res;
return 0;
}
static struct rtnl_hash_entry dflt_group_entry = {
.id = 0, .name = "default"
};
static struct rtnl_hash_entry *rtnl_group_hash[256] = {
[0] = &dflt_group_entry,
};
static int rtnl_group_init;
static void rtnl_group_initialize(void)
{
int ret;
rtnl_group_init = 1;
ret = rtnl_hash_initialize(CONF_ETC_DIR "/group",
rtnl_group_hash, 256);
if (ret == -ENOENT)
rtnl_hash_initialize(CONF_USR_DIR "/group",
rtnl_group_hash, 256);
}
int rtnl_group_a2n(int *id, const char *arg)
{
static const char *cache;
static unsigned long res;
struct rtnl_hash_entry *entry;
char *end;
int i;
if (cache && strcmp(cache, arg) == 0) {
*id = res;
return 0;
}
if (!rtnl_group_init)
rtnl_group_initialize();
for (i = 0; i < 256; i++) {
entry = rtnl_group_hash[i];
while (entry && strcmp(entry->name, arg))
entry = entry->next;
if (entry) {
cache = entry->name;
res = entry->id;
*id = res;
return 0;
}
}
i = strtol(arg, &end, 0);
if (!end || end == arg || *end || i < 0)
return -1;
*id = i;
return 0;
}
const char *rtnl_group_n2a(int id, char *buf, int len)
{
struct rtnl_hash_entry *entry;
int i;
if (!rtnl_group_init)
rtnl_group_initialize();
for (i = 0; !numeric && i < 256; i++) {
entry = rtnl_group_hash[i];
while (entry) {
if (entry->id == id)
return entry->name;
entry = entry->next;
}
}
snprintf(buf, len, "%d", id);
return buf;
}
static char *nl_proto_tab[256] = {
[NETLINK_ROUTE] = "rtnl",
[NETLINK_UNUSED] = "unused",
[NETLINK_USERSOCK] = "usersock",
[NETLINK_FIREWALL] = "fw",
[NETLINK_SOCK_DIAG] = "tcpdiag",
[NETLINK_NFLOG] = "nflog",
[NETLINK_XFRM] = "xfrm",
[NETLINK_SELINUX] = "selinux",
[NETLINK_ISCSI] = "iscsi",
[NETLINK_AUDIT] = "audit",
[NETLINK_FIB_LOOKUP] = "fiblookup",
[NETLINK_CONNECTOR] = "connector",
[NETLINK_NETFILTER] = "nft",
[NETLINK_IP6_FW] = "ip6fw",
[NETLINK_DNRTMSG] = "dec-rt",
[NETLINK_KOBJECT_UEVENT] = "uevent",
[NETLINK_GENERIC] = "genl",
[NETLINK_SCSITRANSPORT] = "scsi-trans",
[NETLINK_ECRYPTFS] = "ecryptfs",
[NETLINK_RDMA] = "rdma",
[NETLINK_CRYPTO] = "crypto",
};
static int nl_proto_init;
static void nl_proto_initialize(void)
{
int ret;
nl_proto_init = 1;
ret = rtnl_tab_initialize(CONF_ETC_DIR "/nl_protos",
nl_proto_tab, 256);
if (ret == -ENOENT)
rtnl_tab_initialize(CONF_USR_DIR "/nl_protos",
nl_proto_tab, 256);
}
const char *nl_proto_n2a(int id, char *buf, int len)
{
if (id < 0 || id >= 256 || numeric) {
snprintf(buf, len, "%d", id);
return buf;
}
if (!nl_proto_init)
nl_proto_initialize();
if (nl_proto_tab[id])
return nl_proto_tab[id];
snprintf(buf, len, "%u", id);
return buf;
}
int nl_proto_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 (!nl_proto_init)
nl_proto_initialize();
for (i = 0; i < 256; i++) {
if (nl_proto_tab[i] &&
strcmp(nl_proto_tab[i], arg) == 0) {
cache = nl_proto_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;
}
iplink: add support for protodown reason 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>
2020-08-29 11:42:56 +08:00
#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)
{
protodown_reason_init = 1;
rtnl_tab_initialize_dir("protodown_reasons.d", protodown_reason_tab,
PROTODOWN_REASON_NUM_BITS);
iplink: add support for protodown reason 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>
2020-08-29 11:42:56 +08:00
}
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;
}