mirror of
https://git.kernel.org/pub/scm/network/iproute2/iproute2.git
synced 2024-11-27 11:54:53 +08:00
e4956e7f1f
Add base support for creating/dumping netkit devices. Minimal example usage: # ip link add type netkit # ip -d a [...] 7: nk0@nk1: <BROADCAST,MULTICAST,NOARP,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000 link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff promiscuity 0 allmulti 0 minmtu 68 maxmtu 65535 netkit mode l3 type peer policy forward numtxqueues 1 numrxqueues 1 [...] 8: nk1@nk0: <BROADCAST,MULTICAST,NOARP,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000 link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff promiscuity 0 allmulti 0 minmtu 68 maxmtu 65535 netkit mode l3 type primary policy forward numtxqueues 1 numrxqueues 1 [...] Example usage with netns (for BPF examples, see BPF selftests linked below): # ip netns add blue # ip link add nk0 type netkit peer nk1 netns blue # ip link set up nk0 # ip addr add 10.0.0.1/24 dev nk0 # ip -n blue link set up nk1 # ip -n blue addr add 10.0.0.2/24 dev nk1 # ping -c1 10.0.0.2 PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data. 64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.021 ms Example usage with L2 mode and peer blackholing when no BPF is attached: # ip link add foo type netkit mode l2 forward peer blackhole bar # ip -d a [...] 13: bar@foo: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000 link/ether 5e:5b:81:17:02:27 brd ff:ff:ff:ff:ff:ff promiscuity 0 allmulti 0 minmtu 68 maxmtu 65535 netkit mode l2 type peer policy blackhole numtxqueues 1 numrxqueues 1 [...] 14: foo@bar: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000 link/ether de:01:a5:88:9e:99 brd ff:ff:ff:ff:ff:ff promiscuity 0 allmulti 0 minmtu 68 maxmtu 65535 netkit mode l2 type primary policy forward numtxqueues 1 numrxqueues 1 [...] Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org> Link: https://git.kernel.org/torvalds/c/35dfaad7188c Link: https://git.kernel.org/torvalds/c/05c31b4ab205 Link: https://git.kernel.org/torvalds/c/ace15f91e569 Signed-off-by: David Ahern <dsahern@kernel.org>
184 lines
4.4 KiB
C
184 lines
4.4 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
/*
|
|
* iplink_netkit.c netkit device management
|
|
*
|
|
* Authors: Daniel Borkmann <daniel@iogearbox.net>
|
|
*/
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/socket.h>
|
|
#include <linux/if_link.h>
|
|
|
|
#include "rt_names.h"
|
|
#include "utils.h"
|
|
#include "ip_common.h"
|
|
|
|
static const char * const netkit_mode_strings[] = {
|
|
[NETKIT_L2] = "l2",
|
|
[NETKIT_L3] = "l3",
|
|
};
|
|
|
|
static const char * const netkit_policy_strings[] = {
|
|
[NETKIT_PASS] = "forward",
|
|
[NETKIT_DROP] = "blackhole",
|
|
};
|
|
|
|
static void explain(struct link_util *lu, FILE *f)
|
|
{
|
|
fprintf(f,
|
|
"Usage: ... %s [ mode MODE ] [ POLICY ] [ peer [ POLICY <options> ] ]\n"
|
|
"\n"
|
|
"MODE: l3 | l2\n"
|
|
"POLICY: forward | blackhole\n"
|
|
"(first values are the defaults if nothing is specified)\n"
|
|
"\n"
|
|
"To get <options> type 'ip link add help'.\n",
|
|
lu->id);
|
|
}
|
|
|
|
static int netkit_parse_opt(struct link_util *lu, int argc, char **argv,
|
|
struct nlmsghdr *n)
|
|
{
|
|
__u32 ifi_flags, ifi_change, ifi_index;
|
|
struct ifinfomsg *ifm, *peer_ifm;
|
|
static bool seen_mode, seen_peer;
|
|
static struct rtattr *data;
|
|
int err;
|
|
|
|
ifm = NLMSG_DATA(n);
|
|
ifi_flags = ifm->ifi_flags;
|
|
ifi_change = ifm->ifi_change;
|
|
ifi_index = ifm->ifi_index;
|
|
ifm->ifi_flags = 0;
|
|
ifm->ifi_change = 0;
|
|
ifm->ifi_index = 0;
|
|
while (argc > 0) {
|
|
if (strcmp(*argv, "mode") == 0) {
|
|
__u32 mode = 0;
|
|
|
|
NEXT_ARG();
|
|
if (seen_mode)
|
|
duparg("mode", *argv);
|
|
seen_mode = true;
|
|
|
|
if (strcmp(*argv, "l3") == 0) {
|
|
mode = NETKIT_L3;
|
|
} else if (strcmp(*argv, "l2") == 0) {
|
|
mode = NETKIT_L2;
|
|
} else {
|
|
fprintf(stderr, "Error: argument of \"mode\" must be either \"l3\" or \"l2\"\n");
|
|
return -1;
|
|
}
|
|
addattr32(n, 1024, IFLA_NETKIT_MODE, mode);
|
|
} else if (strcmp(*argv, "forward") == 0 ||
|
|
strcmp(*argv, "blackhole") == 0) {
|
|
int attr_name = seen_peer ?
|
|
IFLA_NETKIT_PEER_POLICY :
|
|
IFLA_NETKIT_POLICY;
|
|
__u32 policy = 0;
|
|
|
|
if (strcmp(*argv, "forward") == 0) {
|
|
policy = NETKIT_PASS;
|
|
} else if (strcmp(*argv, "blackhole") == 0) {
|
|
policy = NETKIT_DROP;
|
|
} else {
|
|
fprintf(stderr, "Error: policy must be either \"forward\" or \"blackhole\"\n");
|
|
return -1;
|
|
}
|
|
addattr32(n, 1024, attr_name, policy);
|
|
} else if (strcmp(*argv, "peer") == 0) {
|
|
if (seen_peer)
|
|
duparg("peer", *(argv + 1));
|
|
seen_peer = true;
|
|
} else {
|
|
char *type = NULL;
|
|
|
|
if (seen_peer) {
|
|
data = addattr_nest(n, 1024, IFLA_NETKIT_PEER_INFO);
|
|
n->nlmsg_len += sizeof(struct ifinfomsg);
|
|
err = iplink_parse(argc, argv, (struct iplink_req *)n, &type);
|
|
if (err < 0)
|
|
return err;
|
|
if (type)
|
|
duparg("type", argv[err]);
|
|
goto out_ok;
|
|
}
|
|
fprintf(stderr, "%s: unknown option \"%s\"?\n",
|
|
lu->id, *argv);
|
|
explain(lu, stderr);
|
|
return -1;
|
|
}
|
|
argc--;
|
|
argv++;
|
|
}
|
|
out_ok:
|
|
if (data) {
|
|
peer_ifm = RTA_DATA(data);
|
|
peer_ifm->ifi_index = ifm->ifi_index;
|
|
peer_ifm->ifi_flags = ifm->ifi_flags;
|
|
peer_ifm->ifi_change = ifm->ifi_change;
|
|
addattr_nest_end(n, data);
|
|
}
|
|
ifm->ifi_flags = ifi_flags;
|
|
ifm->ifi_change = ifi_change;
|
|
ifm->ifi_index = ifi_index;
|
|
return 0;
|
|
}
|
|
|
|
static const char *netkit_print_policy(__u32 policy)
|
|
{
|
|
const char *inv = "UNKNOWN";
|
|
|
|
if (policy >= ARRAY_SIZE(netkit_policy_strings))
|
|
return inv;
|
|
return netkit_policy_strings[policy] ? : inv;
|
|
}
|
|
|
|
static const char *netkit_print_mode(__u32 mode)
|
|
{
|
|
const char *inv = "UNKNOWN";
|
|
|
|
if (mode >= ARRAY_SIZE(netkit_mode_strings))
|
|
return inv;
|
|
return netkit_mode_strings[mode] ? : inv;
|
|
}
|
|
|
|
static void netkit_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
|
|
{
|
|
if (!tb)
|
|
return;
|
|
if (tb[IFLA_NETKIT_MODE]) {
|
|
__u32 mode = rta_getattr_u32(tb[IFLA_NETKIT_MODE]);
|
|
|
|
print_string(PRINT_ANY, "mode", "mode %s ",
|
|
netkit_print_mode(mode));
|
|
}
|
|
if (tb[IFLA_NETKIT_PRIMARY]) {
|
|
__u8 primary = rta_getattr_u8(tb[IFLA_NETKIT_PRIMARY]);
|
|
|
|
print_string(PRINT_ANY, "type", "type %s ",
|
|
primary ? "primary" : "peer");
|
|
}
|
|
if (tb[IFLA_NETKIT_POLICY]) {
|
|
__u32 policy = rta_getattr_u32(tb[IFLA_NETKIT_POLICY]);
|
|
|
|
print_string(PRINT_ANY, "policy", "policy %s ",
|
|
netkit_print_policy(policy));
|
|
}
|
|
}
|
|
|
|
static void netkit_print_help(struct link_util *lu,
|
|
int argc, char **argv, FILE *f)
|
|
{
|
|
explain(lu, f);
|
|
}
|
|
|
|
struct link_util netkit_link_util = {
|
|
.id = "netkit",
|
|
.maxattr = IFLA_NETKIT_MAX,
|
|
.parse_opt = netkit_parse_opt,
|
|
.print_opt = netkit_print_opt,
|
|
.print_help = netkit_print_help,
|
|
};
|