Merge branch 'net-next' of git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2 into net-next

This commit is contained in:
Stephen Hemminger 2015-06-25 08:01:41 -04:00
commit 586b397851
175 changed files with 9627 additions and 1178 deletions

View File

@ -1,15 +1,15 @@
ROOTDIR=$(DESTDIR) PREFIX?=/usr
PREFIX=/usr LIBDIR?=$(PREFIX)/lib
LIBDIR=$(PREFIX)/lib SBINDIR?=/sbin
SBINDIR=/sbin CONFDIR?=/etc/iproute2
CONFDIR=/etc/iproute2 DATADIR?=$(PREFIX)/share
DATADIR=$(PREFIX)/share DOCDIR?=$(DATADIR)/doc/iproute2
DOCDIR=$(DATADIR)/doc/iproute2 MANDIR?=$(DATADIR)/man
MANDIR=$(DATADIR)/man ARPDDIR?=/var/lib/arpd
ARPDDIR=/var/lib/arpd KERNEL_INCLUDE?=/usr/include
# Path to db_185.h include # Path to db_185.h include
DBM_INCLUDE:=$(ROOTDIR)/usr/include DBM_INCLUDE:=$(DESTDIR)/usr/include
SHARED_LIBS = y SHARED_LIBS = y
@ -26,6 +26,9 @@ ADDLIB+=dnet_ntop.o dnet_pton.o
#options for ipx #options for ipx
ADDLIB+=ipx_ntop.o ipx_pton.o ADDLIB+=ipx_ntop.o ipx_pton.o
#options for mpls
ADDLIB+=mpls_ntop.o mpls_pton.o
CC = gcc CC = gcc
HOSTCC = gcc HOSTCC = gcc
DEFINES += -D_GNU_SOURCE DEFINES += -D_GNU_SOURCE
@ -33,10 +36,10 @@ CCOPTS = -O2
WFLAGS := -Wall -Wstrict-prototypes -Wmissing-prototypes WFLAGS := -Wall -Wstrict-prototypes -Wmissing-prototypes
WFLAGS += -Wmissing-declarations -Wold-style-definition -Wformat=2 WFLAGS += -Wmissing-declarations -Wold-style-definition -Wformat=2
CFLAGS = $(WFLAGS) $(CCOPTS) -I../include $(DEFINES) CFLAGS := $(WFLAGS) $(CCOPTS) -I../include $(DEFINES) $(CFLAGS)
YACCFLAGS = -d -t -v YACCFLAGS = -d -t -v
SUBDIRS=lib ip tc bridge misc netem genl man SUBDIRS=lib ip tc bridge misc netem genl tipc man
LIBNETLINK=../lib/libnetlink.a ../lib/libutil.a LIBNETLINK=../lib/libnetlink.a ../lib/libutil.a
LDLIBS += $(LIBNETLINK) LDLIBS += $(LIBNETLINK)

View File

@ -72,12 +72,16 @@ ip route add 10.11.12.0/24 dev eth1 via whatever realm 1
etc. The same thing can be made with rules. etc. The same thing can be made with rules.
I still did not test ipchains, but they should work too. I still did not test ipchains, but they should work too.
Setup and code example of BPF classifier and action can be found under
examples/bpf/, which should explain everything for getting started.
Setup of rsvp and u32 classifiers is more hairy. Setup of rsvp and u32 classifiers is more hairy.
If you read RSVP specs, you will understand how rsvp classifier If you read RSVP specs, you will understand how rsvp classifier
works easily. What's about u32... That's example: works easily. What's about u32... That's example:
#! /bin/sh #! /bin/sh
TC=/home/root/tc TC=/home/root/tc

View File

@ -131,12 +131,16 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
if (ifindex) { if (ifindex) {
char ifname[IF_NAMESIZE]; char ifname[IF_NAMESIZE];
if (if_indextoname(ifindex, ifname)) if (!tb[NDA_LINK_NETNSID] &&
if_indextoname(ifindex, ifname))
fprintf(fp, "via %s ", ifname); fprintf(fp, "via %s ", ifname);
else else
fprintf(fp, "via ifindex %u ", ifindex); fprintf(fp, "via ifindex %u ", ifindex);
} }
} }
if (tb[NDA_LINK_NETNSID])
fprintf(fp, "link-netnsid %d ",
rta_getattr_u32(tb[NDA_LINK_NETNSID]));
if (show_stats && tb[NDA_CACHEINFO]) { if (show_stats && tb[NDA_CACHEINFO]) {
struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]); struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]);
@ -155,7 +159,7 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
if (r->ndm_flags & NTF_ROUTER) if (r->ndm_flags & NTF_ROUTER)
fprintf(fp, "router "); fprintf(fp, "router ");
if (r->ndm_flags & NTF_EXT_LEARNED) if (r->ndm_flags & NTF_EXT_LEARNED)
fprintf(fp, "external "); fprintf(fp, "offload ");
fprintf(fp, "%s\n", state_n2a(r->ndm_state)); fprintf(fp, "%s\n", state_n2a(r->ndm_state));
return 0; return 0;
@ -316,7 +320,7 @@ static int fdb_modify(int cmd, int flags, int argc, char **argv)
if (d == NULL || addr == NULL) { if (d == NULL || addr == NULL) {
fprintf(stderr, "Device and address are required arguments.\n"); fprintf(stderr, "Device and address are required arguments.\n");
exit(-1); return -1;
} }
/* Assume self */ /* Assume self */
@ -331,7 +335,7 @@ static int fdb_modify(int cmd, int flags, int argc, char **argv)
abuf, abuf+1, abuf+2, abuf, abuf+1, abuf+2,
abuf+3, abuf+4, abuf+5) != 6) { abuf+3, abuf+4, abuf+5) != 6) {
fprintf(stderr, "Invalid mac address %s\n", addr); fprintf(stderr, "Invalid mac address %s\n", addr);
exit(-1); return -1;
} }
addattr_l(&req.n, sizeof(req), NDA_LLADDR, abuf, ETH_ALEN); addattr_l(&req.n, sizeof(req), NDA_LLADDR, abuf, ETH_ALEN);
@ -358,8 +362,8 @@ static int fdb_modify(int cmd, int flags, int argc, char **argv)
return -1; return -1;
} }
if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
exit(2); return -1;
return 0; return 0;
} }

View File

@ -227,6 +227,7 @@ static void usage(void)
fprintf(stderr, " [ learning_sync {on | off} ]\n"); fprintf(stderr, " [ learning_sync {on | off} ]\n");
fprintf(stderr, " [ flood {on | off} ]\n"); fprintf(stderr, " [ flood {on | off} ]\n");
fprintf(stderr, " [ hwmode {vepa | veb} ]\n"); fprintf(stderr, " [ hwmode {vepa | veb} ]\n");
fprintf(stderr, " [ self ] [ master ]\n");
fprintf(stderr, " bridge link show [dev DEV]\n"); fprintf(stderr, " bridge link show [dev DEV]\n");
exit(-1); exit(-1);
} }
@ -283,31 +284,31 @@ static int brlink_modify(int argc, char **argv)
} else if (strcmp(*argv, "guard") == 0) { } else if (strcmp(*argv, "guard") == 0) {
NEXT_ARG(); NEXT_ARG();
if (!on_off("guard", &bpdu_guard, *argv)) if (!on_off("guard", &bpdu_guard, *argv))
exit(-1); return -1;
} else if (strcmp(*argv, "hairpin") == 0) { } else if (strcmp(*argv, "hairpin") == 0) {
NEXT_ARG(); NEXT_ARG();
if (!on_off("hairping", &hairpin, *argv)) if (!on_off("hairping", &hairpin, *argv))
exit(-1); return -1;
} else if (strcmp(*argv, "fastleave") == 0) { } else if (strcmp(*argv, "fastleave") == 0) {
NEXT_ARG(); NEXT_ARG();
if (!on_off("fastleave", &fast_leave, *argv)) if (!on_off("fastleave", &fast_leave, *argv))
exit(-1); return -1;
} else if (strcmp(*argv, "root_block") == 0) { } else if (strcmp(*argv, "root_block") == 0) {
NEXT_ARG(); NEXT_ARG();
if (!on_off("root_block", &root_block, *argv)) if (!on_off("root_block", &root_block, *argv))
exit(-1); return -1;
} else if (strcmp(*argv, "learning") == 0) { } else if (strcmp(*argv, "learning") == 0) {
NEXT_ARG(); NEXT_ARG();
if (!on_off("learning", &learning, *argv)) if (!on_off("learning", &learning, *argv))
exit(-1); return -1;
} else if (strcmp(*argv, "learning_sync") == 0) { } else if (strcmp(*argv, "learning_sync") == 0) {
NEXT_ARG(); NEXT_ARG();
if (!on_off("learning_sync", &learning_sync, *argv)) if (!on_off("learning_sync", &learning_sync, *argv))
exit(-1); return -1;
} else if (strcmp(*argv, "flood") == 0) { } else if (strcmp(*argv, "flood") == 0) {
NEXT_ARG(); NEXT_ARG();
if (!on_off("flood", &flood, *argv)) if (!on_off("flood", &flood, *argv))
exit(-1); return -1;
} else if (strcmp(*argv, "cost") == 0) { } else if (strcmp(*argv, "cost") == 0) {
NEXT_ARG(); NEXT_ARG();
cost = atoi(*argv); cost = atoi(*argv);
@ -316,7 +317,19 @@ static int brlink_modify(int argc, char **argv)
priority = atoi(*argv); priority = atoi(*argv);
} else if (strcmp(*argv, "state") == 0) { } else if (strcmp(*argv, "state") == 0) {
NEXT_ARG(); NEXT_ARG();
state = atoi(*argv); char *endptr;
size_t nstates = sizeof(port_states) / sizeof(*port_states);
state = strtol(*argv, &endptr, 10);
if (!(**argv != '\0' && *endptr == '\0')) {
for (state = 0; state < nstates; state++)
if (strcmp(port_states[state], *argv) == 0)
break;
if (state == nstates) {
fprintf(stderr,
"Error: invalid STP port state\n");
return -1;
}
}
} else if (strcmp(*argv, "hwmode") == 0) { } else if (strcmp(*argv, "hwmode") == 0) {
NEXT_ARG(); NEXT_ARG();
flags = BRIDGE_FLAGS_SELF; flags = BRIDGE_FLAGS_SELF;
@ -328,10 +341,12 @@ static int brlink_modify(int argc, char **argv)
fprintf(stderr, fprintf(stderr,
"Mode argument must be \"vepa\" or " "Mode argument must be \"vepa\" or "
"\"veb\".\n"); "\"veb\".\n");
exit(-1); return -1;
} }
} else if (strcmp(*argv, "self") == 0) { } else if (strcmp(*argv, "self") == 0) {
flags = BRIDGE_FLAGS_SELF; flags |= BRIDGE_FLAGS_SELF;
} else if (strcmp(*argv, "master") == 0) {
flags |= BRIDGE_FLAGS_MASTER;
} else { } else {
usage(); usage();
} }
@ -339,14 +354,14 @@ static int brlink_modify(int argc, char **argv)
} }
if (d == NULL) { if (d == NULL) {
fprintf(stderr, "Device is a required argument.\n"); fprintf(stderr, "Device is a required argument.\n");
exit(-1); return -1;
} }
req.ifm.ifi_index = ll_name_to_index(d); req.ifm.ifi_index = ll_name_to_index(d);
if (req.ifm.ifi_index == 0) { if (req.ifm.ifi_index == 0) {
fprintf(stderr, "Cannot find bridge device \"%s\"\n", d); fprintf(stderr, "Cannot find bridge device \"%s\"\n", d);
exit(-1); return -1;
} }
/* Nested PROTINFO attribute. Contains: port flags, cost, priority and /* Nested PROTINFO attribute. Contains: port flags, cost, priority and
@ -400,8 +415,8 @@ static int brlink_modify(int argc, char **argv)
addattr_nest_end(&req.n, nest); addattr_nest_end(&req.n, nest);
} }
if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
exit(2); return -1;
return 0; return 0;
} }

View File

@ -145,12 +145,12 @@ static int mdb_show(int argc, char **argv)
if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETMDB) < 0) { if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETMDB) < 0) {
perror("Cannot send dump request"); perror("Cannot send dump request");
exit(1); return -1;
} }
if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) { if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) {
fprintf(stderr, "Dump terminated\n"); fprintf(stderr, "Dump terminated\n");
exit(1); return -1;
} }
return 0; return 0;
@ -198,7 +198,7 @@ static int mdb_modify(int cmd, int flags, int argc, char **argv)
if (d == NULL || grp == NULL || p == NULL) { if (d == NULL || grp == NULL || p == NULL) {
fprintf(stderr, "Device, group address and port name are required arguments.\n"); fprintf(stderr, "Device, group address and port name are required arguments.\n");
exit(-1); return -1;
} }
req.bpm.ifindex = ll_name_to_index(d); req.bpm.ifindex = ll_name_to_index(d);
@ -224,8 +224,8 @@ static int mdb_modify(int cmd, int flags, int argc, char **argv)
addattr_l(&req.n, sizeof(req), MDBA_SET_ENTRY, &entry, sizeof(entry)); addattr_l(&req.n, sizeof(req), MDBA_SET_ENTRY, &entry, sizeof(entry));
if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
exit(2); return -1;
return 0; return 0;
} }

View File

@ -36,6 +36,7 @@ static void usage(void)
} }
static int accept_msg(const struct sockaddr_nl *who, static int accept_msg(const struct sockaddr_nl *who,
struct rtnl_ctrl_data *ctrl,
struct nlmsghdr *n, void *arg) struct nlmsghdr *n, void *arg)
{ {
FILE *fp = arg; FILE *fp = arg;

View File

@ -80,7 +80,7 @@ static int vlan_modify(int cmd, int argc, char **argv)
if (d == NULL || vid == -1) { if (d == NULL || vid == -1) {
fprintf(stderr, "Device and VLAN ID are required arguments.\n"); fprintf(stderr, "Device and VLAN ID are required arguments.\n");
exit(-1); return -1;
} }
req.ifm.ifi_index = ll_name_to_index(d); req.ifm.ifi_index = ll_name_to_index(d);
@ -131,8 +131,8 @@ static int vlan_modify(int cmd, int argc, char **argv)
addattr_nest_end(&req.n, afspec); addattr_nest_end(&req.n, afspec);
if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
exit(2); return -1;
return 0; return 0;
} }

28
configure vendored
View File

@ -201,7 +201,7 @@ check_setns()
{ {
cat >$TMPDIR/setnstest.c <<EOF cat >$TMPDIR/setnstest.c <<EOF
#include <sched.h> #include <sched.h>
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
(void)setns(0,0); (void)setns(0,0);
return 0; return 0;
@ -249,6 +249,29 @@ EOF
rm -f $TMPDIR/ipsettest.c $TMPDIR/ipsettest rm -f $TMPDIR/ipsettest.c $TMPDIR/ipsettest
} }
check_elf()
{
cat >$TMPDIR/elftest.c <<EOF
#include <libelf.h>
#include <gelf.h>
int main(void)
{
Elf_Scn *scn;
GElf_Shdr shdr;
return elf_version(EV_CURRENT);
}
EOF
if $CC -I$INCLUDE -o $TMPDIR/elftest $TMPDIR/elftest.c -lelf >/dev/null 2>&1
then
echo "TC_CONFIG_ELF:=y" >>Config
echo "yes"
else
echo "no"
fi
rm -f $TMPDIR/elftest.c $TMPDIR/elftest
}
check_selinux() check_selinux()
# SELinux is a compile time option in the ss utility # SELinux is a compile time option in the ss utility
{ {
@ -287,5 +310,8 @@ check_setns
echo -n "SELinux support: " echo -n "SELinux support: "
check_selinux check_selinux
echo -n "ELF support: "
check_elf
echo -e "\nDocs" echo -e "\nDocs"
check_docs check_docs

View File

@ -1432,6 +1432,17 @@ database.
even if it does not match any interface prefix. One application of this even if it does not match any interface prefix. One application of this
option may be found in~\cite{IP-TUNNELS}. option may be found in~\cite{IP-TUNNELS}.
\item \verb|pref PREF|
--- the IPv6 route preference.
\verb|PREF| PREF is a string specifying the route preference as defined in
RFC4191 for Router Discovery messages. Namely:
\begin{itemize}
\item \verb|low| --- the route has a lowest priority.
\item \verb|medium| --- the route has a default priority.
\item \verb|high| --- the route has a highest priority.
\end{itemize}
\end{itemize} \end{itemize}

258
examples/bpf/bpf_agent.c Normal file
View File

@ -0,0 +1,258 @@
/*
* eBPF user space agent part
*
* Simple, _self-contained_ user space agent for the eBPF kernel
* ebpf_prog.c program, which gets all map fds passed from tc via unix
* domain socket in one transaction and can thus keep referencing
* them from user space in order to read out (or possibly modify)
* map data. Here, just as a minimal example to display counters.
*
* The agent only uses the bpf(2) syscall API to read or possibly
* write to eBPF maps, it doesn't need to be aware of the low-level
* bytecode parts and/or ELF parsing bits.
*
* ! For more details, see header comment in bpf_prog.c !
*
* gcc bpf_agent.c -o bpf_agent -Wall -O2
*
* For example, a more complex user space agent could run on each
* host, reading and writing into eBPF maps used by tc classifier
* and actions. It would thus allow for implementing a distributed
* tc architecture, for example, which would push down central
* policies into eBPF maps, and thus altering run-time behaviour.
*
* -- Happy eBPF hacking! ;)
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdint.h>
#include <assert.h>
#include <sys/un.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
/* Just some misc macros as min(), offsetof(), etc. */
#include "../../include/utils.h"
/* Common code from fd passing. */
#include "../../include/bpf_scm.h"
/* Common, shared definitions with ebpf_prog.c */
#include "bpf_shared.h"
/* Mini syscall wrapper */
#include "bpf_sys.h"
static void bpf_dump_drops(int fd)
{
int cpu, max;
max = sysconf(_SC_NPROCESSORS_ONLN);
printf(" `- number of drops:");
for (cpu = 0; cpu < max; cpu++) {
long drops;
assert(bpf_lookup_elem(fd, &cpu, &drops) == 0);
printf("\tcpu%d: %5ld", cpu, drops);
}
printf("\n");
}
static void bpf_dump_queue(int fd)
{
/* Just for the same of the example. */
int max_queue = 4, i;
printf(" | nic queues:");
for (i = 0; i < max_queue; i++) {
struct count_queue cq;
int ret;
memset(&cq, 0, sizeof(cq));
ret = bpf_lookup_elem(fd, &i, &cq);
assert(ret == 0 || (ret < 0 && errno == ENOENT));
printf("\tq%d:[pkts: %ld, mis: %ld]",
i, cq.total, cq.mismatch);
}
printf("\n");
}
static void bpf_dump_proto(int fd)
{
uint8_t protos[] = { IPPROTO_TCP, IPPROTO_UDP, IPPROTO_ICMP };
char *names[] = { "tcp", "udp", "icmp" };
int i;
printf(" ` protos:");
for (i = 0; i < ARRAY_SIZE(protos); i++) {
struct count_tuple ct;
int ret;
memset(&ct, 0, sizeof(ct));
ret = bpf_lookup_elem(fd, &protos[i], &ct);
assert(ret == 0 || (ret < 0 && errno == ENOENT));
printf("\t%s:[pkts: %ld, bytes: %ld]",
names[i], ct.packets, ct.bytes);
}
printf("\n");
}
static void bpf_dump_map_data(int *tfd)
{
int i;
for (i = 0; i < 30; i++) {
const int period = 5;
printf("data, period: %dsec\n", period);
bpf_dump_drops(tfd[BPF_MAP_ID_DROPS]);
bpf_dump_queue(tfd[BPF_MAP_ID_QUEUE]);
bpf_dump_proto(tfd[BPF_MAP_ID_PROTO]);
sleep(period);
}
}
static void bpf_info_loop(int *fds, struct bpf_map_aux *aux)
{
int i, tfd[BPF_MAP_ID_MAX];
printf("ver: %d\nobj: %s\ndev: %lu\nino: %lu\nmaps: %u\n",
aux->uds_ver, aux->obj_name, aux->obj_st.st_dev,
aux->obj_st.st_ino, aux->num_ent);
for (i = 0; i < aux->num_ent; i++) {
printf("map%d:\n", i);
printf(" `- fd: %u\n", fds[i]);
printf(" | serial: %u\n", aux->ent[i].id);
printf(" | type: %u\n", aux->ent[i].type);
printf(" | max elem: %u\n", aux->ent[i].max_elem);
printf(" | size key: %u\n", aux->ent[i].size_key);
printf(" ` size val: %u\n", aux->ent[i].size_value);
tfd[aux->ent[i].id] = fds[i];
}
bpf_dump_map_data(tfd);
}
static void bpf_map_get_from_env(int *tfd)
{
char key[64], *val;
int i;
for (i = 0; i < BPF_MAP_ID_MAX; i++) {
memset(key, 0, sizeof(key));
snprintf(key, sizeof(key), "BPF_MAP%d", i);
val = secure_getenv(key);
assert(val != NULL);
tfd[i] = atoi(val);
}
}
static int bpf_map_set_recv(int fd, int *fds, struct bpf_map_aux *aux,
unsigned int entries)
{
struct bpf_map_set_msg msg;
int *cmsg_buf, min_fd, i;
char *amsg_buf, *mmsg_buf;
cmsg_buf = bpf_map_set_init(&msg, NULL, 0);
amsg_buf = (char *)msg.aux.ent;
mmsg_buf = (char *)&msg.aux;
for (i = 0; i < entries; i += min_fd) {
struct cmsghdr *cmsg;
int ret;
min_fd = min(BPF_SCM_MAX_FDS * 1U, entries - i);
bpf_map_set_init_single(&msg, min_fd);
ret = recvmsg(fd, &msg.hdr, 0);
if (ret <= 0)
return ret ? : -1;
cmsg = CMSG_FIRSTHDR(&msg.hdr);
if (!cmsg || cmsg->cmsg_type != SCM_RIGHTS)
return -EINVAL;
if (msg.hdr.msg_flags & MSG_CTRUNC)
return -EIO;
min_fd = (cmsg->cmsg_len - sizeof(*cmsg)) / sizeof(fd);
if (min_fd > entries || min_fd <= 0)
return -1;
memcpy(&fds[i], cmsg_buf, sizeof(fds[0]) * min_fd);
memcpy(&aux->ent[i], amsg_buf, sizeof(aux->ent[0]) * min_fd);
memcpy(aux, mmsg_buf, offsetof(struct bpf_map_aux, ent));
if (i + min_fd == aux->num_ent)
break;
}
return 0;
}
int main(int argc, char **argv)
{
int fds[BPF_SCM_MAX_FDS];
struct bpf_map_aux aux;
struct sockaddr_un addr;
int fd, ret, i;
/* When arguments are being passed, we take it as a path
* to a Unix domain socket, otherwise we grab the fds
* from the environment to demonstrate both possibilities.
*/
if (argc == 1) {
int tfd[BPF_MAP_ID_MAX];
bpf_map_get_from_env(tfd);
bpf_dump_map_data(tfd);
return 0;
}
fd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (fd < 0) {
fprintf(stderr, "Cannot open socket: %s\n",
strerror(errno));
exit(1);
}
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, argv[argc - 1], sizeof(addr.sun_path));
ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
if (ret < 0) {
fprintf(stderr, "Cannot bind to socket: %s\n",
strerror(errno));
exit(1);
}
memset(fds, 0, sizeof(fds));
memset(&aux, 0, sizeof(aux));
ret = bpf_map_set_recv(fd, fds, &aux, BPF_SCM_MAX_FDS);
if (ret >= 0)
bpf_info_loop(fds, &aux);
for (i = 0; i < aux.num_ent; i++)
close(fds[i]);
close(fd);
return 0;
}

58
examples/bpf/bpf_funcs.h Normal file
View File

@ -0,0 +1,58 @@
#ifndef __BPF_FUNCS__
#define __BPF_FUNCS__
/* Misc macros. */
#ifndef __maybe_unused
# define __maybe_unused __attribute__ ((__unused__))
#endif
#ifndef __section
# define __section(NAME) __attribute__((section(NAME), used))
#endif
#ifndef offsetof
# define offsetof __builtin_offsetof
#endif
#ifndef htons
# define htons(x) __constant_htons((x))
#endif
#ifndef likely
# define likely(x) __builtin_expect(!!(x), 1)
#endif
#ifndef unlikely
# define unlikely(x) __builtin_expect(!!(x), 0)
#endif
/* The verifier will translate them to actual function calls. */
static void *(*bpf_map_lookup_elem)(void *map, void *key) __maybe_unused =
(void *) BPF_FUNC_map_lookup_elem;
static int (*bpf_map_update_elem)(void *map, void *key, void *value,
unsigned long long flags) __maybe_unused =
(void *) BPF_FUNC_map_update_elem;
static int (*bpf_map_delete_elem)(void *map, void *key) __maybe_unused =
(void *) BPF_FUNC_map_delete_elem;
static unsigned int (*get_smp_processor_id)(void) __maybe_unused =
(void *) BPF_FUNC_get_smp_processor_id;
static unsigned int (*get_prandom_u32)(void) __maybe_unused =
(void *) BPF_FUNC_get_prandom_u32;
/* LLVM built-in functions that an eBPF C program may use to emit
* BPF_LD_ABS and BPF_LD_IND instructions.
*/
unsigned long long load_byte(void *skb, unsigned long long off)
asm ("llvm.bpf.load.byte");
unsigned long long load_half(void *skb, unsigned long long off)
asm ("llvm.bpf.load.half");
unsigned long long load_word(void *skb, unsigned long long off)
asm ("llvm.bpf.load.word");
#endif /* __BPF_FUNCS__ */

496
examples/bpf/bpf_prog.c Normal file
View File

@ -0,0 +1,496 @@
/*
* eBPF kernel space program part
*
* Toy eBPF program for demonstration purposes, some parts derived from
* kernel tree's samples/bpf/sockex2_kern.c example.
*
* More background on eBPF, kernel tree: Documentation/networking/filter.txt
*
* Note, this file is rather large, and most classifier and actions are
* likely smaller to accomplish one specific use-case and are tailored
* for high performance. For performance reasons, you might also have the
* classifier and action already merged inside the classifier.
*
* In order to show various features it serves as a bigger programming
* example, which you should feel free to rip apart and experiment with.
*
* Compilation, configuration example:
*
* Note: as long as the BPF backend in LLVM is still experimental,
* you need to build LLVM with LLVM with --enable-experimental-targets=BPF
* Also, make sure your 4.1+ kernel is compiled with CONFIG_BPF_SYSCALL=y,
* and you have libelf.h and gelf.h headers and can link tc against -lelf.
*
* In case you need to sync kernel headers, go to your kernel source tree:
* # make headers_install INSTALL_HDR_PATH=/usr/
*
* $ export PATH=/home/<...>/llvm/Debug+Asserts/bin/:$PATH
* $ clang -O2 -emit-llvm -c bpf_prog.c -o - | llc -march=bpf -filetype=obj -o bpf.o
* $ objdump -h bpf.o
* [...]
* 3 classifier 000007f8 0000000000000000 0000000000000000 00000040 2**3
* CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
* 4 action-mark 00000088 0000000000000000 0000000000000000 00000838 2**3
* CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
* 5 action-rand 00000098 0000000000000000 0000000000000000 000008c0 2**3
* CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
* 6 maps 00000030 0000000000000000 0000000000000000 00000958 2**2
* CONTENTS, ALLOC, LOAD, DATA
* 7 license 00000004 0000000000000000 0000000000000000 00000988 2**0
* CONTENTS, ALLOC, LOAD, DATA
* [...]
* # echo 1 > /proc/sys/net/core/bpf_jit_enable
* $ gcc bpf_agent.c -o bpf_agent -Wall -O2
* # ./bpf_agent /tmp/bpf-uds (e.g. on a different terminal)
* # tc filter add dev em1 parent 1: bpf obj bpf.o exp /tmp/bpf-uds flowid 1:1 \
* action bpf obj bpf.o sec action-mark \
* action bpf obj bpf.o sec action-rand ok
* # tc filter show dev em1
* filter parent 1: protocol all pref 49152 bpf
* filter parent 1: protocol all pref 49152 bpf handle 0x1 flowid 1:1 bpf.o:[classifier]
* action order 1: bpf bpf.o:[action-mark] default-action pipe
* index 52 ref 1 bind 1
*
* action order 2: bpf bpf.o:[action-rand] default-action pipe
* index 53 ref 1 bind 1
*
* action order 3: gact action pass
* random type none pass val 0
* index 38 ref 1 bind 1
*
* The same program can also be installed on ingress side (as opposed to above
* egress configuration), e.g.:
*
* # tc qdisc add dev em1 handle ffff: ingress
* # tc filter add dev em1 parent ffff: bpf obj ...
*
* Notes on BPF agent:
*
* In the above example, the bpf_agent creates the unix domain socket
* natively. "tc exec" can also spawn a shell and hold the socktes there:
*
* # tc exec bpf imp /tmp/bpf-uds
* # tc filter add dev em1 parent 1: bpf obj bpf.o exp /tmp/bpf-uds flowid 1:1 \
* action bpf obj bpf.o sec action-mark \
* action bpf obj bpf.o sec action-rand ok
* sh-4.2# (shell spawned from tc exec)
* sh-4.2# bpf_agent
* [...]
*
* This will read out fds over environment and produce the same data dump
* as below. This has the advantage that the spawned shell owns the fds
* and thus if the agent is restarted, it can reattach to the same fds, also
* various programs can easily read/modify the data simultaneously from user
* space side.
*
* If the shell is unnecessary, the agent can also just be spawned directly
* via tc exec:
*
* # tc exec bpf imp /tmp/bpf-uds run bpf_agent
* # tc filter add dev em1 parent 1: bpf obj bpf.o exp /tmp/bpf-uds flowid 1:1 \
* action bpf obj bpf.o sec action-mark \
* action bpf obj bpf.o sec action-rand ok
*
* BPF agent example output:
*
* ver: 1
* obj: bpf.o
* dev: 64770
* ino: 6045133
* maps: 3
* map0:
* `- fd: 4
* | serial: 1
* | type: 1
* | max elem: 256
* | size key: 1
* ` size val: 16
* map1:
* `- fd: 5
* | serial: 2
* | type: 1
* | max elem: 1024
* | size key: 4
* ` size val: 16
* map2:
* `- fd: 6
* | serial: 3
* | type: 2
* | max elem: 64
* | size key: 4
* ` size val: 8
* data, period: 5sec
* `- number of drops: cpu0: 0 cpu1: 0 cpu2: 0 cpu3: 0
* | nic queues: q0:[pkts: 0, mis: 0] q1:[pkts: 0, mis: 0] q2:[pkts: 0, mis: 0] q3:[pkts: 0, mis: 0]
* ` protos: tcp:[pkts: 0, bytes: 0] udp:[pkts: 0, bytes: 0] icmp:[pkts: 0, bytes: 0]
* data, period: 5sec
* `- number of drops: cpu0: 5 cpu1: 0 cpu2: 0 cpu3: 1
* | nic queues: q0:[pkts: 0, mis: 0] q1:[pkts: 0, mis: 0] q2:[pkts: 24, mis: 14] q3:[pkts: 0, mis: 0]
* ` protos: tcp:[pkts: 13, bytes: 1989] udp:[pkts: 10, bytes: 710] icmp:[pkts: 0, bytes: 0]
* data, period: 5sec
* `- number of drops: cpu0: 5 cpu1: 0 cpu2: 3 cpu3: 3
* | nic queues: q0:[pkts: 0, mis: 0] q1:[pkts: 0, mis: 0] q2:[pkts: 39, mis: 21] q3:[pkts: 0, mis: 0]
* ` protos: tcp:[pkts: 20, bytes: 3549] udp:[pkts: 18, bytes: 1278] icmp:[pkts: 0, bytes: 0]
* [...]
*
* This now means, the below classifier and action pipeline has been loaded
* as eBPF bytecode into the kernel, the kernel has verified that the
* execution of the bytecode is "safe", and it has JITed the programs
* afterwards, so that upon invocation they're running on native speed. tc
* has transferred all map file descriptors to the bpf_agent via IPC and
* even after tc exits, the agent can read out or modify all map data.
*
* Note that the export to the uds is done only once in the classifier and
* not in the action. It's enough to export the (here) shared descriptors
* once.
*
* If you need to disassemble the generated JIT image (echo with 2), the
* kernel tree has under tools/net/ a small helper, you can invoke e.g.
* `bpf_jit_disasm -o`.
*
* Please find in the code below further comments.
*
* -- Happy eBPF hacking! ;)
*/
#include <stdint.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <asm/types.h>
#include <linux/in.h>
#include <linux/if.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/if_tunnel.h>
#include <linux/filter.h>
#include <linux/bpf.h>
/* Common, shared definitions with ebpf_agent.c. */
#include "bpf_shared.h"
/* Selection of BPF helper functions for our example. */
#include "bpf_funcs.h"
/* Could be defined here as well, or included from the header. */
#define TC_ACT_UNSPEC (-1)
#define TC_ACT_OK 0
#define TC_ACT_RECLASSIFY 1
#define TC_ACT_SHOT 2
#define TC_ACT_PIPE 3
#define TC_ACT_STOLEN 4
#define TC_ACT_QUEUED 5
#define TC_ACT_REPEAT 6
/* Other, misc stuff. */
#define IP_MF 0x2000
#define IP_OFFSET 0x1FFF
/* eBPF map definitions, all placed in section "maps". */
struct bpf_elf_map __section("maps") map_proto = {
.type = BPF_MAP_TYPE_HASH,
.id = BPF_MAP_ID_PROTO,
.size_key = sizeof(uint8_t),
.size_value = sizeof(struct count_tuple),
.max_elem = 256,
};
struct bpf_elf_map __section("maps") map_queue = {
.type = BPF_MAP_TYPE_HASH,
.id = BPF_MAP_ID_QUEUE,
.size_key = sizeof(uint32_t),
.size_value = sizeof(struct count_queue),
.max_elem = 1024,
};
struct bpf_elf_map __section("maps") map_drops = {
.type = BPF_MAP_TYPE_ARRAY,
.id = BPF_MAP_ID_DROPS,
.size_key = sizeof(uint32_t),
.size_value = sizeof(long),
.max_elem = 64,
};
/* Helper functions and definitions for the flow dissector used by the
* example classifier. This resembles the kernel's flow dissector to
* some extend and is just used as an example to show what's possible
* with eBPF.
*/
struct sockaddr;
struct vlan_hdr {
__be16 h_vlan_TCI;
__be16 h_vlan_encapsulated_proto;
};
struct flow_keys {
__u32 src;
__u32 dst;
union {
__u32 ports;
__u16 port16[2];
};
__s32 th_off;
__u8 ip_proto;
};
static inline int flow_ports_offset(__u8 ip_proto)
{
switch (ip_proto) {
case IPPROTO_TCP:
case IPPROTO_UDP:
case IPPROTO_DCCP:
case IPPROTO_ESP:
case IPPROTO_SCTP:
case IPPROTO_UDPLITE:
default:
return 0;
case IPPROTO_AH:
return 4;
}
}
static inline bool flow_is_frag(struct __sk_buff *skb, int nh_off)
{
return !!(load_half(skb, nh_off + offsetof(struct iphdr, frag_off)) &
(IP_MF | IP_OFFSET));
}
static inline int flow_parse_ipv4(struct __sk_buff *skb, int nh_off,
__u8 *ip_proto, struct flow_keys *flow)
{
__u8 ip_ver_len;
if (unlikely(flow_is_frag(skb, nh_off)))
*ip_proto = 0;
else
*ip_proto = load_byte(skb, nh_off + offsetof(struct iphdr,
protocol));
if (*ip_proto != IPPROTO_GRE) {
flow->src = load_word(skb, nh_off + offsetof(struct iphdr, saddr));
flow->dst = load_word(skb, nh_off + offsetof(struct iphdr, daddr));
}
ip_ver_len = load_byte(skb, nh_off + 0 /* offsetof(struct iphdr, ihl) */);
if (likely(ip_ver_len == 0x45))
nh_off += 20;
else
nh_off += (ip_ver_len & 0xF) << 2;
return nh_off;
}
static inline __u32 flow_addr_hash_ipv6(struct __sk_buff *skb, int off)
{
__u32 w0 = load_word(skb, off);
__u32 w1 = load_word(skb, off + sizeof(w0));
__u32 w2 = load_word(skb, off + sizeof(w0) * 2);
__u32 w3 = load_word(skb, off + sizeof(w0) * 3);
return w0 ^ w1 ^ w2 ^ w3;
}
static inline int flow_parse_ipv6(struct __sk_buff *skb, int nh_off,
__u8 *ip_proto, struct flow_keys *flow)
{
*ip_proto = load_byte(skb, nh_off + offsetof(struct ipv6hdr, nexthdr));
flow->src = flow_addr_hash_ipv6(skb, nh_off + offsetof(struct ipv6hdr, saddr));
flow->dst = flow_addr_hash_ipv6(skb, nh_off + offsetof(struct ipv6hdr, daddr));
return nh_off + sizeof(struct ipv6hdr);
}
static inline bool flow_dissector(struct __sk_buff *skb,
struct flow_keys *flow)
{
int poff, nh_off = BPF_LL_OFF + ETH_HLEN;
__be16 proto = skb->protocol;
__u8 ip_proto;
/* TODO: check for skb->vlan_tci, skb->vlan_proto first */
if (proto == htons(ETH_P_8021AD)) {
proto = load_half(skb, nh_off +
offsetof(struct vlan_hdr, h_vlan_encapsulated_proto));
nh_off += sizeof(struct vlan_hdr);
}
if (proto == htons(ETH_P_8021Q)) {
proto = load_half(skb, nh_off +
offsetof(struct vlan_hdr, h_vlan_encapsulated_proto));
nh_off += sizeof(struct vlan_hdr);
}
if (likely(proto == htons(ETH_P_IP)))
nh_off = flow_parse_ipv4(skb, nh_off, &ip_proto, flow);
else if (proto == htons(ETH_P_IPV6))
nh_off = flow_parse_ipv6(skb, nh_off, &ip_proto, flow);
else
return false;
switch (ip_proto) {
case IPPROTO_GRE: {
struct gre_hdr {
__be16 flags;
__be16 proto;
};
__u16 gre_flags = load_half(skb, nh_off +
offsetof(struct gre_hdr, flags));
__u16 gre_proto = load_half(skb, nh_off +
offsetof(struct gre_hdr, proto));
if (gre_flags & (GRE_VERSION | GRE_ROUTING))
break;
nh_off += 4;
if (gre_flags & GRE_CSUM)
nh_off += 4;
if (gre_flags & GRE_KEY)
nh_off += 4;
if (gre_flags & GRE_SEQ)
nh_off += 4;
if (gre_proto == ETH_P_8021Q) {
gre_proto = load_half(skb, nh_off +
offsetof(struct vlan_hdr,
h_vlan_encapsulated_proto));
nh_off += sizeof(struct vlan_hdr);
}
if (gre_proto == ETH_P_IP)
nh_off = flow_parse_ipv4(skb, nh_off, &ip_proto, flow);
else if (gre_proto == ETH_P_IPV6)
nh_off = flow_parse_ipv6(skb, nh_off, &ip_proto, flow);
else
return false;
break;
}
case IPPROTO_IPIP:
nh_off = flow_parse_ipv4(skb, nh_off, &ip_proto, flow);
break;
case IPPROTO_IPV6:
nh_off = flow_parse_ipv6(skb, nh_off, &ip_proto, flow);
default:
break;
}
nh_off += flow_ports_offset(ip_proto);
flow->ports = load_word(skb, nh_off);
flow->th_off = nh_off;
flow->ip_proto = ip_proto;
return true;
}
static inline void cls_update_proto_map(const struct __sk_buff *skb,
const struct flow_keys *flow)
{
uint8_t proto = flow->ip_proto;
struct count_tuple *ct, _ct;
ct = bpf_map_lookup_elem(&map_proto, &proto);
if (likely(ct)) {
__sync_fetch_and_add(&ct->packets, 1);
__sync_fetch_and_add(&ct->bytes, skb->len);
return;
}
/* No hit yet, we need to create a new entry. */
_ct.packets = 1;
_ct.bytes = skb->len;
bpf_map_update_elem(&map_proto, &proto, &_ct, BPF_ANY);
}
static inline void cls_update_queue_map(const struct __sk_buff *skb)
{
uint32_t queue = skb->queue_mapping;
struct count_queue *cq, _cq;
bool mismatch;
mismatch = skb->queue_mapping != get_smp_processor_id();
cq = bpf_map_lookup_elem(&map_queue, &queue);
if (likely(cq)) {
__sync_fetch_and_add(&cq->total, 1);
if (mismatch)
__sync_fetch_and_add(&cq->mismatch, 1);
return;
}
/* No hit yet, we need to create a new entry. */
_cq.total = 1;
_cq.mismatch = mismatch ? 1 : 0;
bpf_map_update_elem(&map_queue, &queue, &_cq, BPF_ANY);
}
/* eBPF program definitions, placed in various sections, which can
* have custom section names. If custom names are in use, it's
* required to point tc to the correct section, e.g.
*
* tc filter add [...] bpf obj cls.o sec cls-tos [...]
*
* in case the program resides in __section("cls-tos").
*
* Default section for cls_bpf is: "classifier", for act_bpf is:
* "action". Naturally, if for example multiple actions are present
* in the same file, they need to have distinct section names.
*
* It is however not required to have multiple programs sharing
* a file.
*/
__section("classifier") int cls_main(struct __sk_buff *skb)
{
struct flow_keys flow;
if (!flow_dissector(skb, &flow))
return 0; /* No match in cls_bpf. */
cls_update_proto_map(skb, &flow);
cls_update_queue_map(skb);
return flow.ip_proto;
}
static inline void act_update_drop_map(void)
{
uint32_t *count, cpu = get_smp_processor_id();
count = bpf_map_lookup_elem(&map_drops, &cpu);
if (count)
/* Only this cpu is accessing this element. */
(*count)++;
}
__section("action-mark") int act_mark_main(struct __sk_buff *skb)
{
/* You could also mangle skb data here with the helper function
* BPF_FUNC_skb_store_bytes, etc. Or, alternatively you could
* do that already in the classifier itself as a merged combination
* of classifier'n'action model.
*/
if (skb->mark == 0xcafe) {
act_update_drop_map();
return TC_ACT_SHOT;
}
/* Default configured tc opcode. */
return TC_ACT_UNSPEC;
}
__section("action-rand") int act_rand_main(struct __sk_buff *skb)
{
/* Sorry, we're near event horizon ... */
if ((get_prandom_u32() & 3) == 0) {
act_update_drop_map();
return TC_ACT_SHOT;
}
return TC_ACT_UNSPEC;
}
/* Last but not least, the file contains a license. Some future helper
* functions may only be available with a GPL license.
*/
char __license[] __section("license") = "GPL";

26
examples/bpf/bpf_shared.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef __BPF_SHARED__
#define __BPF_SHARED__
#include <stdint.h>
#include "../../include/bpf_elf.h"
enum {
BPF_MAP_ID_PROTO,
BPF_MAP_ID_QUEUE,
BPF_MAP_ID_DROPS,
__BPF_MAP_ID_MAX,
#define BPF_MAP_ID_MAX __BPF_MAP_ID_MAX
};
struct count_tuple {
long packets; /* type long for __sync_fetch_and_add() */
long bytes;
};
struct count_queue {
long total;
long mismatch;
};
#endif /* __BPF_SHARED__ */

23
examples/bpf/bpf_sys.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef __BPF_SYS__
#define __BPF_SYS__
#include <sys/syscall.h>
#include <linux/bpf.h>
static inline __u64 bpf_ptr_to_u64(const void *ptr)
{
return (__u64) (unsigned long) ptr;
}
static inline int bpf_lookup_elem(int fd, void *key, void *value)
{
union bpf_attr attr = {
.map_fd = fd,
.key = bpf_ptr_to_u64(key),
.value = bpf_ptr_to_u64(value),
};
return syscall(__NR_bpf, BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr));
}
#endif /* __BPF_SYS__ */

View File

@ -578,14 +578,14 @@ cbq_show () {
### Check configuration and load DEVICES, DEVFIELDS and CLASSLIST from $1 ### Check configuration and load DEVICES, DEVFIELDS and CLASSLIST from $1
cbq_init () { cbq_init () {
### Get a list of configured classes ### Get a list of configured classes
CLASSLIST=`find $1 \( -type f -or -type l \) -name 'cbq-*' \ CLASSLIST=`find $1 -maxdepth 1 \( -type f -or -type l \) -name 'cbq-*' \
-not -name '*~' -maxdepth 1 -printf "%f\n"| sort` -not -name '*~' -printf "%f\n"| sort`
[ -z "$CLASSLIST" ] && [ -z "$CLASSLIST" ] &&
cbq_failure "no configuration files found in $1!" cbq_failure "no configuration files found in $1!"
### Gather all DEVICE fields from $1/cbq-* ### Gather all DEVICE fields from $1/cbq-*
DEVFIELDS=`find $1 \( -type f -or -type l \) -name 'cbq-*' \ DEVFIELDS=`find $1 -maxdepth 1 \( -type f -or -type l \) -name 'cbq-*' \
-not -name '*~' -maxdepth 1| xargs sed -n 's/#.*//; \ -not -name '*~' | xargs sed -n 's/#.*//; \
s/[[:space:]]//g; /^DEVICE=[^,]*,[^,]*\(,[^,]*\)\?/ \ s/[[:space:]]//g; /^DEVICE=[^,]*,[^,]*\(,[^,]*\)\?/ \
{ s/.*=//; p; }'| sort -u` { s/.*=//; p; }'| sort -u`
[ -z "$DEVFIELDS" ] && [ -z "$DEVFIELDS" ] &&

View File

@ -67,7 +67,7 @@ int genl_ctrl_resolve_family(const char *family)
addattr_l(nlh, 128, CTRL_ATTR_FAMILY_NAME, family, strlen(family) + 1); addattr_l(nlh, 128, CTRL_ATTR_FAMILY_NAME, family, strlen(family) + 1);
if (rtnl_talk(&rth, nlh, 0, 0, nlh) < 0) { if (rtnl_talk(&rth, nlh, nlh, sizeof(req)) < 0) {
fprintf(stderr, "Error talking to the kernel\n"); fprintf(stderr, "Error talking to the kernel\n");
goto errout; goto errout;
} }
@ -177,8 +177,9 @@ static int print_ctrl_grp(FILE *fp, struct rtattr *arg, __u32 ctrl_ver)
/* /*
* The controller sends one nlmsg per family * The controller sends one nlmsg per family
*/ */
static int print_ctrl(const struct sockaddr_nl *who, struct nlmsghdr *n, static int print_ctrl(const struct sockaddr_nl *who,
void *arg) struct rtnl_ctrl_data *ctrl,
struct nlmsghdr *n, void *arg)
{ {
struct rtattr *tb[CTRL_ATTR_MAX + 1]; struct rtattr *tb[CTRL_ATTR_MAX + 1];
struct genlmsghdr *ghdr = NLMSG_DATA(n); struct genlmsghdr *ghdr = NLMSG_DATA(n);
@ -281,6 +282,12 @@ static int print_ctrl(const struct sockaddr_nl *who, struct nlmsghdr *n,
return 0; return 0;
} }
static int print_ctrl2(const struct sockaddr_nl *who,
struct nlmsghdr *n, void *arg)
{
return print_ctrl(who, NULL, n, arg);
}
static int ctrl_list(int cmd, int argc, char **argv) static int ctrl_list(int cmd, int argc, char **argv)
{ {
struct rtnl_handle rth; struct rtnl_handle rth;
@ -334,12 +341,12 @@ static int ctrl_list(int cmd, int argc, char **argv)
goto ctrl_done; goto ctrl_done;
} }
if (rtnl_talk(&rth, nlh, 0, 0, nlh) < 0) { if (rtnl_talk(&rth, nlh, nlh, sizeof(req)) < 0) {
fprintf(stderr, "Error talking to the kernel\n"); fprintf(stderr, "Error talking to the kernel\n");
goto ctrl_done; goto ctrl_done;
} }
if (print_ctrl(NULL, nlh, (void *) stdout) < 0) { if (print_ctrl2(NULL, nlh, (void *) stdout) < 0) {
fprintf(stderr, "Dump terminated\n"); fprintf(stderr, "Dump terminated\n");
goto ctrl_done; goto ctrl_done;
} }
@ -355,7 +362,7 @@ static int ctrl_list(int cmd, int argc, char **argv)
goto ctrl_done; goto ctrl_done;
} }
rtnl_dump_filter(&rth, print_ctrl, stdout); rtnl_dump_filter(&rth, print_ctrl2, stdout);
} }
@ -408,5 +415,5 @@ static int parse_ctrl(struct genl_util *a, int argc, char **argv)
struct genl_util ctrl_genl_util = { struct genl_util ctrl_genl_util = {
.name = "ctrl", .name = "ctrl",
.parse_genlopt = parse_ctrl, .parse_genlopt = parse_ctrl,
.print_genlopt = print_ctrl, .print_genlopt = print_ctrl2,
}; };

View File

@ -1 +1 @@
static const char SNAPSHOT[] = "150210"; static const char SNAPSHOT[] = "150413";

33
include/bpf_elf.h Normal file
View File

@ -0,0 +1,33 @@
#ifndef __BPF_ELF__
#define __BPF_ELF__
#include <asm/types.h>
/* Note:
*
* Below ELF section names and bpf_elf_map structure definition
* are not (!) kernel ABI. It's rather a "contract" between the
* application and the BPF loader in tc. For compatibility, the
* section names should stay as-is. Introduction of aliases, if
* needed, are a possibility, though.
*/
/* ELF section names, etc */
#define ELF_SECTION_LICENSE "license"
#define ELF_SECTION_MAPS "maps"
#define ELF_SECTION_CLASSIFIER "classifier"
#define ELF_SECTION_ACTION "action"
#define ELF_MAX_MAPS 64
#define ELF_MAX_LICENSE_LEN 128
/* ELF map definition */
struct bpf_elf_map {
__u32 type;
__u32 size_key;
__u32 size_value;
__u32 max_elem;
__u32 id;
};
#endif /* __BPF_ELF__ */

75
include/bpf_scm.h Normal file
View File

@ -0,0 +1,75 @@
#ifndef __BPF_SCM__
#define __BPF_SCM__
#include <sys/types.h>
#include <sys/socket.h>
#include "utils.h"
#include "bpf_elf.h"
#define BPF_SCM_AUX_VER 1
#define BPF_SCM_MAX_FDS ELF_MAX_MAPS
#define BPF_SCM_MSG_SIZE 1024
struct bpf_elf_st {
dev_t st_dev;
ino_t st_ino;
};
struct bpf_map_aux {
unsigned short uds_ver;
unsigned short num_ent;
char obj_name[64];
struct bpf_elf_st obj_st;
struct bpf_elf_map ent[BPF_SCM_MAX_FDS];
};
struct bpf_map_set_msg {
struct msghdr hdr;
struct iovec iov;
char msg_buf[BPF_SCM_MSG_SIZE];
struct bpf_map_aux aux;
};
static inline int *bpf_map_set_init(struct bpf_map_set_msg *msg,
struct sockaddr_un *addr,
unsigned int addr_len)
{
const unsigned int cmsg_ctl_len = sizeof(int) * BPF_SCM_MAX_FDS;
struct cmsghdr *cmsg;
msg->iov.iov_base = &msg->aux;
msg->iov.iov_len = sizeof(msg->aux);
msg->hdr.msg_iov = &msg->iov;
msg->hdr.msg_iovlen = 1;
msg->hdr.msg_name = (struct sockaddr *)addr;
msg->hdr.msg_namelen = addr_len;
BUILD_BUG_ON(sizeof(msg->msg_buf) < cmsg_ctl_len);
msg->hdr.msg_control = &msg->msg_buf;
msg->hdr.msg_controllen = cmsg_ctl_len;
cmsg = CMSG_FIRSTHDR(&msg->hdr);
cmsg->cmsg_len = msg->hdr.msg_controllen;
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
return (int *)CMSG_DATA(cmsg);
}
static inline void bpf_map_set_init_single(struct bpf_map_set_msg *msg,
int num)
{
struct cmsghdr *cmsg;
msg->hdr.msg_controllen = CMSG_LEN(sizeof(int) * num);
msg->iov.iov_len = offsetof(struct bpf_map_aux, ent) +
sizeof(struct bpf_elf_map) * num;
cmsg = CMSG_FIRSTHDR(&msg->hdr);
cmsg->cmsg_len = msg->hdr.msg_controllen;
}
#endif /* __BPF_SCM__ */

16
include/color.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef __COLOR_H__
#define __COLOR_H__ 1
enum color_attr {
COLOR_IFNAME,
COLOR_MAC,
COLOR_INET,
COLOR_INET6,
COLOR_OPERSTATE_UP,
COLOR_OPERSTATE_DOWN
};
void enable_color(void);
int color_fprintf(FILE *fp, enum color_attr attr, const char *fmt, ...);
#endif

View File

@ -20,6 +20,8 @@ struct rtnl_handle
__u32 dump; __u32 dump;
int proto; int proto;
FILE *dump_fp; FILE *dump_fp;
#define RTNL_HANDLE_F_LISTEN_ALL_NSID 0x01
int flags;
}; };
extern int rcvbuf; extern int rcvbuf;
@ -41,9 +43,17 @@ extern int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req,
int len) int len)
__attribute__((warn_unused_result)); __attribute__((warn_unused_result));
struct rtnl_ctrl_data {
int nsid;
};
typedef int (*rtnl_filter_t)(const struct sockaddr_nl *, typedef int (*rtnl_filter_t)(const struct sockaddr_nl *,
struct nlmsghdr *n, void *); struct nlmsghdr *n, void *);
typedef int (*rtnl_listen_filter_t)(const struct sockaddr_nl *,
struct rtnl_ctrl_data *,
struct nlmsghdr *n, void *);
struct rtnl_dump_filter_arg struct rtnl_dump_filter_arg
{ {
rtnl_filter_t filter; rtnl_filter_t filter;
@ -54,8 +64,8 @@ extern int rtnl_dump_filter_l(struct rtnl_handle *rth,
const struct rtnl_dump_filter_arg *arg); const struct rtnl_dump_filter_arg *arg);
extern int rtnl_dump_filter(struct rtnl_handle *rth, rtnl_filter_t filter, extern int rtnl_dump_filter(struct rtnl_handle *rth, rtnl_filter_t filter,
void *arg); void *arg);
extern int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, extern int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
unsigned groups, struct nlmsghdr *answer) struct nlmsghdr *answer, size_t len)
__attribute__((warn_unused_result)); __attribute__((warn_unused_result));
extern int rtnl_send(struct rtnl_handle *rth, const void *buf, int) extern int rtnl_send(struct rtnl_handle *rth, const void *buf, int)
__attribute__((warn_unused_result)); __attribute__((warn_unused_result));
@ -118,9 +128,10 @@ static inline const char *rta_getattr_str(const struct rtattr *rta)
return (const char *)RTA_DATA(rta); return (const char *)RTA_DATA(rta);
} }
extern int rtnl_listen(struct rtnl_handle *, rtnl_filter_t handler, extern int rtnl_listen_all_nsid(struct rtnl_handle *);
extern int rtnl_listen(struct rtnl_handle *, rtnl_listen_filter_t handler,
void *jarg); void *jarg);
extern int rtnl_from_file(FILE *, rtnl_filter_t handler, extern int rtnl_from_file(FILE *, rtnl_listen_filter_t handler,
void *jarg); void *jarg);
#define NLMSG_TAIL(nmsg) \ #define NLMSG_TAIL(nmsg) \
@ -158,6 +169,14 @@ extern int rtnl_from_file(FILE *, rtnl_filter_t handler,
#define NDTA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndtmsg)) #define NDTA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndtmsg))
#endif #endif
#ifndef NETNS_RTA
#define NETNS_RTA(r) \
((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))))
#endif
#ifndef NETNS_PAYLOAD
#define NETNS_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct rtgenmsg))
#endif
/* User defined nlmsg_type which is used mostly for logging netlink /* User defined nlmsg_type which is used mostly for logging netlink
* messages from dump file */ * messages from dump file */
#define NLMSG_TSTAMP 15 #define NLMSG_TSTAMP 15

241
include/linux/bpf.h Normal file
View File

@ -0,0 +1,241 @@
/* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*/
#ifndef __LINUX_BPF_H__
#define __LINUX_BPF_H__
#include <linux/types.h>
#include <linux/bpf_common.h>
/* Extended instruction set based on top of classic BPF */
/* instruction classes */
#define BPF_ALU64 0x07 /* alu mode in double word width */
/* ld/ldx fields */
#define BPF_DW 0x18 /* double word */
#define BPF_XADD 0xc0 /* exclusive add */
/* alu/jmp fields */
#define BPF_MOV 0xb0 /* mov reg to reg */
#define BPF_ARSH 0xc0 /* sign extending arithmetic shift right */
/* change endianness of a register */
#define BPF_END 0xd0 /* flags for endianness conversion: */
#define BPF_TO_LE 0x00 /* convert to little-endian */
#define BPF_TO_BE 0x08 /* convert to big-endian */
#define BPF_FROM_LE BPF_TO_LE
#define BPF_FROM_BE BPF_TO_BE
#define BPF_JNE 0x50 /* jump != */
#define BPF_JSGT 0x60 /* SGT is signed '>', GT in x86 */
#define BPF_JSGE 0x70 /* SGE is signed '>=', GE in x86 */
#define BPF_CALL 0x80 /* function call */
#define BPF_EXIT 0x90 /* function return */
/* Register numbers */
enum {
BPF_REG_0 = 0,
BPF_REG_1,
BPF_REG_2,
BPF_REG_3,
BPF_REG_4,
BPF_REG_5,
BPF_REG_6,
BPF_REG_7,
BPF_REG_8,
BPF_REG_9,
BPF_REG_10,
__MAX_BPF_REG,
};
/* BPF has 10 general purpose 64-bit registers and stack frame. */
#define MAX_BPF_REG __MAX_BPF_REG
struct bpf_insn {
__u8 code; /* opcode */
__u8 dst_reg:4; /* dest register */
__u8 src_reg:4; /* source register */
__s16 off; /* signed offset */
__s32 imm; /* signed immediate constant */
};
/* BPF syscall commands */
enum bpf_cmd {
/* create a map with given type and attributes
* fd = bpf(BPF_MAP_CREATE, union bpf_attr *, u32 size)
* returns fd or negative error
* map is deleted when fd is closed
*/
BPF_MAP_CREATE,
/* lookup key in a given map
* err = bpf(BPF_MAP_LOOKUP_ELEM, union bpf_attr *attr, u32 size)
* Using attr->map_fd, attr->key, attr->value
* returns zero and stores found elem into value
* or negative error
*/
BPF_MAP_LOOKUP_ELEM,
/* create or update key/value pair in a given map
* err = bpf(BPF_MAP_UPDATE_ELEM, union bpf_attr *attr, u32 size)
* Using attr->map_fd, attr->key, attr->value, attr->flags
* returns zero or negative error
*/
BPF_MAP_UPDATE_ELEM,
/* find and delete elem by key in a given map
* err = bpf(BPF_MAP_DELETE_ELEM, union bpf_attr *attr, u32 size)
* Using attr->map_fd, attr->key
* returns zero or negative error
*/
BPF_MAP_DELETE_ELEM,
/* lookup key in a given map and return next key
* err = bpf(BPF_MAP_GET_NEXT_KEY, union bpf_attr *attr, u32 size)
* Using attr->map_fd, attr->key, attr->next_key
* returns zero and stores next key or negative error
*/
BPF_MAP_GET_NEXT_KEY,
/* verify and load eBPF program
* prog_fd = bpf(BPF_PROG_LOAD, union bpf_attr *attr, u32 size)
* Using attr->prog_type, attr->insns, attr->license
* returns fd or negative error
*/
BPF_PROG_LOAD,
};
enum bpf_map_type {
BPF_MAP_TYPE_UNSPEC,
BPF_MAP_TYPE_HASH,
BPF_MAP_TYPE_ARRAY,
BPF_MAP_TYPE_PROG_ARRAY,
};
enum bpf_prog_type {
BPF_PROG_TYPE_UNSPEC,
BPF_PROG_TYPE_SOCKET_FILTER,
BPF_PROG_TYPE_KPROBE,
BPF_PROG_TYPE_SCHED_CLS,
BPF_PROG_TYPE_SCHED_ACT,
};
#define BPF_PSEUDO_MAP_FD 1
/* flags for BPF_MAP_UPDATE_ELEM command */
#define BPF_ANY 0 /* create new element or update existing */
#define BPF_NOEXIST 1 /* create new element if it didn't exist */
#define BPF_EXIST 2 /* update existing element */
union bpf_attr {
struct { /* anonymous struct used by BPF_MAP_CREATE command */
__u32 map_type; /* one of enum bpf_map_type */
__u32 key_size; /* size of key in bytes */
__u32 value_size; /* size of value in bytes */
__u32 max_entries; /* max number of entries in a map */
};
struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */
__u32 map_fd;
__aligned_u64 key;
union {
__aligned_u64 value;
__aligned_u64 next_key;
};
__u64 flags;
};
struct { /* anonymous struct used by BPF_PROG_LOAD command */
__u32 prog_type; /* one of enum bpf_prog_type */
__u32 insn_cnt;
__aligned_u64 insns;
__aligned_u64 license;
__u32 log_level; /* verbosity level of verifier */
__u32 log_size; /* size of user buffer */
__aligned_u64 log_buf; /* user supplied buffer */
__u32 kern_version; /* checked when prog_type=kprobe */
};
} __attribute__((aligned(8)));
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
* function eBPF program intends to call
*/
enum bpf_func_id {
BPF_FUNC_unspec,
BPF_FUNC_map_lookup_elem, /* void *map_lookup_elem(&map, &key) */
BPF_FUNC_map_update_elem, /* int map_update_elem(&map, &key, &value, flags) */
BPF_FUNC_map_delete_elem, /* int map_delete_elem(&map, &key) */
BPF_FUNC_probe_read, /* int bpf_probe_read(void *dst, int size, void *src) */
BPF_FUNC_ktime_get_ns, /* u64 bpf_ktime_get_ns(void) */
BPF_FUNC_trace_printk, /* int bpf_trace_printk(const char *fmt, int fmt_size, ...) */
BPF_FUNC_get_prandom_u32, /* u32 prandom_u32(void) */
BPF_FUNC_get_smp_processor_id, /* u32 raw_smp_processor_id(void) */
/**
* skb_store_bytes(skb, offset, from, len, flags) - store bytes into packet
* @skb: pointer to skb
* @offset: offset within packet from skb->mac_header
* @from: pointer where to copy bytes from
* @len: number of bytes to store into packet
* @flags: bit 0 - if true, recompute skb->csum
* other bits - reserved
* Return: 0 on success
*/
BPF_FUNC_skb_store_bytes,
/**
* l3_csum_replace(skb, offset, from, to, flags) - recompute IP checksum
* @skb: pointer to skb
* @offset: offset within packet where IP checksum is located
* @from: old value of header field
* @to: new value of header field
* @flags: bits 0-3 - size of header field
* other bits - reserved
* Return: 0 on success
*/
BPF_FUNC_l3_csum_replace,
/**
* l4_csum_replace(skb, offset, from, to, flags) - recompute TCP/UDP checksum
* @skb: pointer to skb
* @offset: offset within packet where TCP/UDP checksum is located
* @from: old value of header field
* @to: new value of header field
* @flags: bits 0-3 - size of header field
* bit 4 - is pseudo header
* other bits - reserved
* Return: 0 on success
*/
BPF_FUNC_l4_csum_replace,
/**
* bpf_tail_call(ctx, prog_array_map, index) - jump into another BPF program
* @ctx: context pointer passed to next program
* @prog_array_map: pointer to map which type is BPF_MAP_TYPE_PROG_ARRAY
* @index: index inside array that selects specific program to run
* Return: 0 on success
*/
BPF_FUNC_tail_call,
__BPF_FUNC_MAX_ID,
};
/* user accessible mirror of in-kernel sk_buff.
* new fields can only be added to the end of this structure
*/
struct __sk_buff {
__u32 len;
__u32 pkt_type;
__u32 mark;
__u32 queue_mapping;
__u32 protocol;
__u32 vlan_present;
__u32 vlan_tci;
__u32 vlan_proto;
__u32 priority;
};
#endif /* __LINUX_BPF_H__ */

View File

@ -95,11 +95,17 @@ typedef __u32 can_err_mask_t;
* @can_dlc: frame payload length in byte (0 .. 8) aka data length code * @can_dlc: frame payload length in byte (0 .. 8) aka data length code
* N.B. the DLC field from ISO 11898-1 Chapter 8.4.2.3 has a 1:1 * N.B. the DLC field from ISO 11898-1 Chapter 8.4.2.3 has a 1:1
* mapping of the 'data length code' to the real payload length * mapping of the 'data length code' to the real payload length
* @__pad: padding
* @__res0: reserved / padding
* @__res1: reserved / padding
* @data: CAN frame payload (up to 8 byte) * @data: CAN frame payload (up to 8 byte)
*/ */
struct can_frame { struct can_frame {
canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */ canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */
__u8 can_dlc; /* frame payload length in byte (0 .. CAN_MAX_DLEN) */ __u8 can_dlc; /* frame payload length in byte (0 .. CAN_MAX_DLEN) */
__u8 __pad; /* padding */
__u8 __res0; /* reserved / padding */
__u8 __res1; /* reserved / padding */
__u8 data[CAN_MAX_DLEN] __attribute__((aligned(8))); __u8 data[CAN_MAX_DLEN] __attribute__((aligned(8)));
}; };

View File

@ -77,9 +77,13 @@ struct sock_fprog { /* Required for SO_ATTACH_FILTER. */
#define SKF_AD_VLAN_TAG_PRESENT 48 #define SKF_AD_VLAN_TAG_PRESENT 48
#define SKF_AD_PAY_OFFSET 52 #define SKF_AD_PAY_OFFSET 52
#define SKF_AD_RANDOM 56 #define SKF_AD_RANDOM 56
#define SKF_AD_MAX 60 #define SKF_AD_VLAN_TPID 60
#define SKF_NET_OFF (-0x100000) #define SKF_AD_MAX 64
#define SKF_LL_OFF (-0x200000)
#define SKF_NET_OFF (-0x100000)
#define SKF_LL_OFF (-0x200000)
#define BPF_NET_OFF SKF_NET_OFF
#define BPF_LL_OFF SKF_LL_OFF
#endif /* __LINUX_FILTER_H__ */ #endif /* __LINUX_FILTER_H__ */

View File

@ -14,6 +14,7 @@ enum {
FOU_ATTR_AF, /* u8 */ FOU_ATTR_AF, /* u8 */
FOU_ATTR_IPPROTO, /* u8 */ FOU_ATTR_IPPROTO, /* u8 */
FOU_ATTR_TYPE, /* u8 */ FOU_ATTR_TYPE, /* u8 */
FOU_ATTR_REMCSUM_NOPARTIAL, /* flag */
__FOU_ATTR_MAX, __FOU_ATTR_MAX,
}; };
@ -24,6 +25,7 @@ enum {
FOU_CMD_UNSPEC, FOU_CMD_UNSPEC,
FOU_CMD_ADD, FOU_CMD_ADD,
FOU_CMD_DEL, FOU_CMD_DEL,
FOU_CMD_GET,
__FOU_CMD_MAX, __FOU_CMD_MAX,
}; };

View File

@ -50,6 +50,8 @@ enum {
#define IFA_F_PERMANENT 0x80 #define IFA_F_PERMANENT 0x80
#define IFA_F_MANAGETEMPADDR 0x100 #define IFA_F_MANAGETEMPADDR 0x100
#define IFA_F_NOPREFIXROUTE 0x200 #define IFA_F_NOPREFIXROUTE 0x200
#define IFA_F_MCAUTOJOIN 0x400
#define IFA_F_STABLE_PRIVACY 0x800
struct ifa_cacheinfo { struct ifa_cacheinfo {
__u32 ifa_prefered; __u32 ifa_prefered;

View File

@ -147,6 +147,7 @@ enum {
IFLA_CARRIER_CHANGES, IFLA_CARRIER_CHANGES,
IFLA_PHYS_SWITCH_ID, IFLA_PHYS_SWITCH_ID,
IFLA_LINK_NETNSID, IFLA_LINK_NETNSID,
IFLA_PHYS_PORT_NAME,
__IFLA_MAX __IFLA_MAX
}; };
@ -213,6 +214,7 @@ enum {
enum in6_addr_gen_mode { enum in6_addr_gen_mode {
IN6_ADDR_GEN_MODE_EUI64, IN6_ADDR_GEN_MODE_EUI64,
IN6_ADDR_GEN_MODE_NONE, IN6_ADDR_GEN_MODE_NONE,
IN6_ADDR_GEN_MODE_STABLE_PRIVACY,
}; };
/* Bridge section */ /* Bridge section */
@ -222,6 +224,9 @@ enum {
IFLA_BR_FORWARD_DELAY, IFLA_BR_FORWARD_DELAY,
IFLA_BR_HELLO_TIME, IFLA_BR_HELLO_TIME,
IFLA_BR_MAX_AGE, IFLA_BR_MAX_AGE,
IFLA_BR_AGEING_TIME,
IFLA_BR_STP_STATE,
IFLA_BR_PRIORITY,
__IFLA_BR_MAX, __IFLA_BR_MAX,
}; };
@ -245,6 +250,7 @@ enum {
IFLA_BRPORT_UNICAST_FLOOD, /* flood unicast traffic */ IFLA_BRPORT_UNICAST_FLOOD, /* flood unicast traffic */
IFLA_BRPORT_PROXYARP, /* proxy ARP */ IFLA_BRPORT_PROXYARP, /* proxy ARP */
IFLA_BRPORT_LEARNING_SYNC, /* mac learning sync from device */ IFLA_BRPORT_LEARNING_SYNC, /* mac learning sync from device */
IFLA_BRPORT_PROXYARP_WIFI, /* proxy ARP for Wi-Fi */
__IFLA_BRPORT_MAX __IFLA_BRPORT_MAX
}; };
#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
@ -372,6 +378,7 @@ enum {
IFLA_VXLAN_REMCSUM_TX, IFLA_VXLAN_REMCSUM_TX,
IFLA_VXLAN_REMCSUM_RX, IFLA_VXLAN_REMCSUM_RX,
IFLA_VXLAN_GBP, IFLA_VXLAN_GBP,
IFLA_VXLAN_REMCSUM_NOPARTIAL,
__IFLA_VXLAN_MAX __IFLA_VXLAN_MAX
}; };
#define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1) #define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1)
@ -381,6 +388,15 @@ struct ifla_vxlan_port_range {
__be16 high; __be16 high;
}; };
/* GENEVE section */
enum {
IFLA_GENEVE_UNSPEC,
IFLA_GENEVE_ID,
IFLA_GENEVE_REMOTE,
__IFLA_GENEVE_MAX
};
#define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1)
/* Bonding section */ /* Bonding section */
enum { enum {
@ -408,6 +424,9 @@ enum {
IFLA_BOND_AD_LACP_RATE, IFLA_BOND_AD_LACP_RATE,
IFLA_BOND_AD_SELECT, IFLA_BOND_AD_SELECT,
IFLA_BOND_AD_INFO, IFLA_BOND_AD_INFO,
IFLA_BOND_AD_ACTOR_SYS_PRIO,
IFLA_BOND_AD_USER_PORT_KEY,
IFLA_BOND_AD_ACTOR_SYSTEM,
__IFLA_BOND_MAX, __IFLA_BOND_MAX,
}; };
@ -456,6 +475,9 @@ enum {
IFLA_VF_SPOOFCHK, /* Spoof Checking on/off switch */ IFLA_VF_SPOOFCHK, /* Spoof Checking on/off switch */
IFLA_VF_LINK_STATE, /* link state enable/disable/auto switch */ IFLA_VF_LINK_STATE, /* link state enable/disable/auto switch */
IFLA_VF_RATE, /* Min and Max TX Bandwidth Allocation */ IFLA_VF_RATE, /* Min and Max TX Bandwidth Allocation */
IFLA_VF_RSS_QUERY_EN, /* RSS Redirection Table and Hash Key query
* on/off switch
*/
__IFLA_VF_MAX, __IFLA_VF_MAX,
}; };
@ -500,6 +522,11 @@ struct ifla_vf_link_state {
__u32 link_state; __u32 link_state;
}; };
struct ifla_vf_rss_query_en {
__u32 vf;
__u32 setting;
};
/* VF ports management section /* VF ports management section
* *
* Nested layout of set/get msg is: * Nested layout of set/get msg is:

View File

@ -143,4 +143,8 @@ struct tcp_dctcp_info {
__u32 dctcp_ab_tot; __u32 dctcp_ab_tot;
}; };
union tcp_cc_info {
struct tcpvegas_info vegas;
struct tcp_dctcp_info dctcp;
};
#endif /* _INET_DIAG_H_ */ #endif /* _INET_DIAG_H_ */

44
include/linux/mpls.h Normal file
View File

@ -0,0 +1,44 @@
#ifndef _MPLS_H
#define _MPLS_H
#include <linux/types.h>
#include <asm/byteorder.h>
/* Reference: RFC 5462, RFC 3032
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Label | TC |S| TTL |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* Label: Label Value, 20 bits
* TC: Traffic Class field, 3 bits
* S: Bottom of Stack, 1 bit
* TTL: Time to Live, 8 bits
*/
struct mpls_label {
__be32 entry;
};
#define MPLS_LS_LABEL_MASK 0xFFFFF000
#define MPLS_LS_LABEL_SHIFT 12
#define MPLS_LS_TC_MASK 0x00000E00
#define MPLS_LS_TC_SHIFT 9
#define MPLS_LS_S_MASK 0x00000100
#define MPLS_LS_S_SHIFT 8
#define MPLS_LS_TTL_MASK 0x000000FF
#define MPLS_LS_TTL_SHIFT 0
/* Reserved labels */
#define MPLS_LABEL_IPV4NULL 0 /* RFC3032 */
#define MPLS_LABEL_RTALERT 1 /* RFC3032 */
#define MPLS_LABEL_IPV6NULL 2 /* RFC3032 */
#define MPLS_LABEL_IMPLNULL 3 /* RFC3032 */
#define MPLS_LABEL_ENTROPY 7 /* RFC6790 */
#define MPLS_LABEL_GAL 13 /* RFC5586 */
#define MPLS_LABEL_OAMALERT 14 /* RFC3429 */
#define MPLS_LABEL_EXTENSION 15 /* RFC7274 */
#endif /* _MPLS_H */

View File

@ -126,6 +126,7 @@ enum {
NDTPA_PROXY_QLEN, /* u32 */ NDTPA_PROXY_QLEN, /* u32 */
NDTPA_LOCKTIME, /* u64, msecs */ NDTPA_LOCKTIME, /* u64, msecs */
NDTPA_QUEUE_LENBYTES, /* u32 */ NDTPA_QUEUE_LENBYTES, /* u32 */
NDTPA_MCAST_REPROBES, /* u32 */
__NDTPA_MAX __NDTPA_MAX
}; };
#define NDTPA_MAX (__NDTPA_MAX - 1) #define NDTPA_MAX (__NDTPA_MAX - 1)

View File

@ -0,0 +1,23 @@
/* Copyright (c) 2015 6WIND S.A.
* Author: Nicolas Dichtel <nicolas.dichtel@6wind.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*/
#ifndef _LINUX_NET_NAMESPACE_H_
#define _LINUX_NET_NAMESPACE_H_
/* Attributes of RTM_NEWNSID/RTM_GETNSID messages */
enum {
NETNSA_NONE,
#define NETNSA_NSID_NOT_ASSIGNED -1
NETNSA_NSID,
NETNSA_PID,
NETNSA_FD,
__NETNSA_MAX,
};
#define NETNSA_MAX (__NETNSA_MAX - 1)
#endif /* _LINUX_NET_NAMESPACE_H_ */

View File

@ -49,11 +49,17 @@ enum nf_inet_hooks {
NF_INET_NUMHOOKS NF_INET_NUMHOOKS
}; };
enum nf_dev_hooks {
NF_NETDEV_INGRESS,
NF_NETDEV_NUMHOOKS
};
enum { enum {
NFPROTO_UNSPEC = 0, NFPROTO_UNSPEC = 0,
NFPROTO_INET = 1, NFPROTO_INET = 1,
NFPROTO_IPV4 = 2, NFPROTO_IPV4 = 2,
NFPROTO_ARP = 3, NFPROTO_ARP = 3,
NFPROTO_NETDEV = 5,
NFPROTO_BRIDGE = 7, NFPROTO_BRIDGE = 7,
NFPROTO_IPV6 = 10, NFPROTO_IPV6 = 10,
NFPROTO_DECNET = 12, NFPROTO_DECNET = 12,

View File

@ -108,6 +108,7 @@ struct nlmsgerr {
#define NETLINK_NO_ENOBUFS 5 #define NETLINK_NO_ENOBUFS 5
#define NETLINK_RX_RING 6 #define NETLINK_RX_RING 6
#define NETLINK_TX_RING 7 #define NETLINK_TX_RING 7
#define NETLINK_LISTEN_ALL_NSID 8
struct nl_pktinfo { struct nl_pktinfo {
__u32 group; __u32 group;

View File

@ -4,75 +4,6 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/pkt_sched.h> #include <linux/pkt_sched.h>
/* I think i could have done better macros ; for now this is stolen from
* some arch/mips code - jhs
*/
#define _TC_MAKE32(x) ((x))
#define _TC_MAKEMASK1(n) (_TC_MAKE32(1) << _TC_MAKE32(n))
#define _TC_MAKEMASK(v,n) (_TC_MAKE32((_TC_MAKE32(1)<<(v))-1) << _TC_MAKE32(n))
#define _TC_MAKEVALUE(v,n) (_TC_MAKE32(v) << _TC_MAKE32(n))
#define _TC_GETVALUE(v,n,m) ((_TC_MAKE32(v) & _TC_MAKE32(m)) >> _TC_MAKE32(n))
/* verdict bit breakdown
*
bit 0: when set -> this packet has been munged already
bit 1: when set -> It is ok to munge this packet
bit 2,3,4,5: Reclassify counter - sort of reverse TTL - if exceeded
assume loop
bit 6,7: Where this packet was last seen
0: Above the transmit example at the socket level
1: on the Ingress
2: on the Egress
bit 8: when set --> Request not to classify on ingress.
bits 9,10,11: redirect counter - redirect TTL. Loop avoidance
*
* */
#define TC_MUNGED _TC_MAKEMASK1(0)
#define SET_TC_MUNGED(v) ( TC_MUNGED | (v & ~TC_MUNGED))
#define CLR_TC_MUNGED(v) ( v & ~TC_MUNGED)
#define TC_OK2MUNGE _TC_MAKEMASK1(1)
#define SET_TC_OK2MUNGE(v) ( TC_OK2MUNGE | (v & ~TC_OK2MUNGE))
#define CLR_TC_OK2MUNGE(v) ( v & ~TC_OK2MUNGE)
#define S_TC_VERD _TC_MAKE32(2)
#define M_TC_VERD _TC_MAKEMASK(4,S_TC_VERD)
#define G_TC_VERD(x) _TC_GETVALUE(x,S_TC_VERD,M_TC_VERD)
#define V_TC_VERD(x) _TC_MAKEVALUE(x,S_TC_VERD)
#define SET_TC_VERD(v,n) ((V_TC_VERD(n)) | (v & ~M_TC_VERD))
#define S_TC_FROM _TC_MAKE32(6)
#define M_TC_FROM _TC_MAKEMASK(2,S_TC_FROM)
#define G_TC_FROM(x) _TC_GETVALUE(x,S_TC_FROM,M_TC_FROM)
#define V_TC_FROM(x) _TC_MAKEVALUE(x,S_TC_FROM)
#define SET_TC_FROM(v,n) ((V_TC_FROM(n)) | (v & ~M_TC_FROM))
#define AT_STACK 0x0
#define AT_INGRESS 0x1
#define AT_EGRESS 0x2
#define TC_NCLS _TC_MAKEMASK1(8)
#define SET_TC_NCLS(v) ( TC_NCLS | (v & ~TC_NCLS))
#define CLR_TC_NCLS(v) ( v & ~TC_NCLS)
#define S_TC_RTTL _TC_MAKE32(9)
#define M_TC_RTTL _TC_MAKEMASK(3,S_TC_RTTL)
#define G_TC_RTTL(x) _TC_GETVALUE(x,S_TC_RTTL,M_TC_RTTL)
#define V_TC_RTTL(x) _TC_MAKEVALUE(x,S_TC_RTTL)
#define SET_TC_RTTL(v,n) ((V_TC_RTTL(n)) | (v & ~M_TC_RTTL))
#define S_TC_AT _TC_MAKE32(12)
#define M_TC_AT _TC_MAKEMASK(2,S_TC_AT)
#define G_TC_AT(x) _TC_GETVALUE(x,S_TC_AT,M_TC_AT)
#define V_TC_AT(x) _TC_MAKEVALUE(x,S_TC_AT)
#define SET_TC_AT(v,n) ((V_TC_AT(n)) | (v & ~M_TC_AT))
/* Action attributes */ /* Action attributes */
enum { enum {
@ -93,8 +24,6 @@ enum {
#define TCA_ACT_NOUNBIND 0 #define TCA_ACT_NOUNBIND 0
#define TCA_ACT_REPLACE 1 #define TCA_ACT_REPLACE 1
#define TCA_ACT_NOREPLACE 0 #define TCA_ACT_NOREPLACE 0
#define MAX_REC_LOOP 4
#define MAX_RED_LOOP 4
#define TC_ACT_UNSPEC (-1) #define TC_ACT_UNSPEC (-1)
#define TC_ACT_OK 0 #define TC_ACT_OK 0
@ -397,11 +326,43 @@ enum {
TCA_BPF_CLASSID, TCA_BPF_CLASSID,
TCA_BPF_OPS_LEN, TCA_BPF_OPS_LEN,
TCA_BPF_OPS, TCA_BPF_OPS,
TCA_BPF_FD,
TCA_BPF_NAME,
__TCA_BPF_MAX, __TCA_BPF_MAX,
}; };
#define TCA_BPF_MAX (__TCA_BPF_MAX - 1) #define TCA_BPF_MAX (__TCA_BPF_MAX - 1)
/* Flower classifier */
enum {
TCA_FLOWER_UNSPEC,
TCA_FLOWER_CLASSID,
TCA_FLOWER_INDEV,
TCA_FLOWER_ACT,
TCA_FLOWER_KEY_ETH_DST, /* ETH_ALEN */
TCA_FLOWER_KEY_ETH_DST_MASK, /* ETH_ALEN */
TCA_FLOWER_KEY_ETH_SRC, /* ETH_ALEN */
TCA_FLOWER_KEY_ETH_SRC_MASK, /* ETH_ALEN */
TCA_FLOWER_KEY_ETH_TYPE, /* be16 */
TCA_FLOWER_KEY_IP_PROTO, /* u8 */
TCA_FLOWER_KEY_IPV4_SRC, /* be32 */
TCA_FLOWER_KEY_IPV4_SRC_MASK, /* be32 */
TCA_FLOWER_KEY_IPV4_DST, /* be32 */
TCA_FLOWER_KEY_IPV4_DST_MASK, /* be32 */
TCA_FLOWER_KEY_IPV6_SRC, /* struct in6_addr */
TCA_FLOWER_KEY_IPV6_SRC_MASK, /* struct in6_addr */
TCA_FLOWER_KEY_IPV6_DST, /* struct in6_addr */
TCA_FLOWER_KEY_IPV6_DST_MASK, /* struct in6_addr */
TCA_FLOWER_KEY_TCP_SRC, /* be16 */
TCA_FLOWER_KEY_TCP_DST, /* be16 */
TCA_FLOWER_KEY_UDP_SRC, /* be16 */
TCA_FLOWER_KEY_UDP_DST, /* be16 */
__TCA_FLOWER_MAX,
};
#define TCA_FLOWER_MAX (__TCA_FLOWER_MAX - 1)
/* Extended Matches */ /* Extended Matches */
struct tcf_ematch_tree_hdr { struct tcf_ematch_tree_hdr {

View File

@ -268,7 +268,8 @@ enum {
TCA_GRED_STAB, TCA_GRED_STAB,
TCA_GRED_DPS, TCA_GRED_DPS,
TCA_GRED_MAX_P, TCA_GRED_MAX_P,
__TCA_GRED_MAX, TCA_GRED_LIMIT,
__TCA_GRED_MAX,
}; };
#define TCA_GRED_MAX (__TCA_GRED_MAX - 1) #define TCA_GRED_MAX (__TCA_GRED_MAX - 1)
@ -679,6 +680,7 @@ enum {
TCA_CODEL_LIMIT, TCA_CODEL_LIMIT,
TCA_CODEL_INTERVAL, TCA_CODEL_INTERVAL,
TCA_CODEL_ECN, TCA_CODEL_ECN,
TCA_CODEL_CE_THRESHOLD,
__TCA_CODEL_MAX __TCA_CODEL_MAX
}; };
@ -695,6 +697,7 @@ struct tc_codel_xstats {
__u32 drop_overlimit; /* number of time max qdisc packet limit was hit */ __u32 drop_overlimit; /* number of time max qdisc packet limit was hit */
__u32 ecn_mark; /* number of packets we ECN marked instead of dropped */ __u32 ecn_mark; /* number of packets we ECN marked instead of dropped */
__u32 dropping; /* are we in dropping state ? */ __u32 dropping; /* are we in dropping state ? */
__u32 ce_mark; /* number of CE marked packets because of ce_threshold */
}; };
/* FQ_CODEL */ /* FQ_CODEL */
@ -707,6 +710,7 @@ enum {
TCA_FQ_CODEL_ECN, TCA_FQ_CODEL_ECN,
TCA_FQ_CODEL_FLOWS, TCA_FQ_CODEL_FLOWS,
TCA_FQ_CODEL_QUANTUM, TCA_FQ_CODEL_QUANTUM,
TCA_FQ_CODEL_CE_THRESHOLD,
__TCA_FQ_CODEL_MAX __TCA_FQ_CODEL_MAX
}; };
@ -730,6 +734,7 @@ struct tc_fq_codel_qd_stats {
*/ */
__u32 new_flows_len; /* count of flows in new list */ __u32 new_flows_len; /* count of flows in new list */
__u32 old_flows_len; /* count of flows in old list */ __u32 old_flows_len; /* count of flows in old list */
__u32 ce_mark; /* packets above ce_threshold */
}; };
struct tc_fq_codel_cl_stats { struct tc_fq_codel_cl_stats {
@ -774,6 +779,8 @@ enum {
TCA_FQ_FLOW_REFILL_DELAY, /* flow credit refill delay in usec */ TCA_FQ_FLOW_REFILL_DELAY, /* flow credit refill delay in usec */
TCA_FQ_ORPHAN_MASK, /* mask applied to orphaned skb hashes */
__TCA_FQ_MAX __TCA_FQ_MAX
}; };

View File

@ -134,6 +134,8 @@ enum {
RTM_NEWNSID = 88, RTM_NEWNSID = 88,
#define RTM_NEWNSID RTM_NEWNSID #define RTM_NEWNSID RTM_NEWNSID
RTM_DELNSID = 89,
#define RTM_DELNSID RTM_DELNSID
RTM_GETNSID = 90, RTM_GETNSID = 90,
#define RTM_GETNSID RTM_GETNSID #define RTM_GETNSID RTM_GETNSID
@ -303,6 +305,9 @@ enum rtattr_type_t {
RTA_TABLE, RTA_TABLE,
RTA_MARK, RTA_MARK,
RTA_MFC_STATS, RTA_MFC_STATS,
RTA_VIA,
RTA_NEWDST,
RTA_PREF,
__RTA_MAX __RTA_MAX
}; };
@ -332,6 +337,7 @@ struct rtnexthop {
#define RTNH_F_DEAD 1 /* Nexthop is dead (used by multipath) */ #define RTNH_F_DEAD 1 /* Nexthop is dead (used by multipath) */
#define RTNH_F_PERVASIVE 2 /* Do recursive gateway lookup */ #define RTNH_F_PERVASIVE 2 /* Do recursive gateway lookup */
#define RTNH_F_ONLINK 4 /* Gateway is forced on link */ #define RTNH_F_ONLINK 4 /* Gateway is forced on link */
#define RTNH_F_OFFLOAD 8 /* offloaded route */
/* Macros to handle hexthops */ /* Macros to handle hexthops */
@ -344,6 +350,12 @@ struct rtnexthop {
#define RTNH_SPACE(len) RTNH_ALIGN(RTNH_LENGTH(len)) #define RTNH_SPACE(len) RTNH_ALIGN(RTNH_LENGTH(len))
#define RTNH_DATA(rtnh) ((struct rtattr*)(((char*)(rtnh)) + RTNH_LENGTH(0))) #define RTNH_DATA(rtnh) ((struct rtattr*)(((char*)(rtnh)) + RTNH_LENGTH(0)))
/* RTA_VIA */
struct rtvia {
__kernel_sa_family_t rtvia_family;
__u8 rtvia_addr[0];
};
/* RTM_CACHEINFO */ /* RTM_CACHEINFO */
struct rta_cacheinfo { struct rta_cacheinfo {
@ -621,6 +633,10 @@ enum rtnetlink_groups {
#define RTNLGRP_IPV6_NETCONF RTNLGRP_IPV6_NETCONF #define RTNLGRP_IPV6_NETCONF RTNLGRP_IPV6_NETCONF
RTNLGRP_MDB, RTNLGRP_MDB,
#define RTNLGRP_MDB RTNLGRP_MDB #define RTNLGRP_MDB RTNLGRP_MDB
RTNLGRP_MPLS_ROUTE,
#define RTNLGRP_MPLS_ROUTE RTNLGRP_MPLS_ROUTE
RTNLGRP_NSID,
#define RTNLGRP_NSID RTNLGRP_NSID
__RTNLGRP_MAX __RTNLGRP_MAX
}; };
#define RTNLGRP_MAX (__RTNLGRP_MAX - 1) #define RTNLGRP_MAX (__RTNLGRP_MAX - 1)

View File

@ -24,6 +24,8 @@ enum {
TCA_ACT_BPF_PARMS, TCA_ACT_BPF_PARMS,
TCA_ACT_BPF_OPS_LEN, TCA_ACT_BPF_OPS_LEN,
TCA_ACT_BPF_OPS, TCA_ACT_BPF_OPS,
TCA_ACT_BPF_FD,
TCA_ACT_BPF_NAME,
__TCA_ACT_BPF_MAX, __TCA_ACT_BPF_MAX,
}; };
#define TCA_ACT_BPF_MAX (__TCA_ACT_BPF_MAX - 1) #define TCA_ACT_BPF_MAX (__TCA_ACT_BPF_MAX - 1)

View File

@ -0,0 +1,22 @@
#ifndef __UAPI_TC_CONNMARK_H
#define __UAPI_TC_CONNMARK_H
#include <linux/types.h>
#include <linux/pkt_cls.h>
#define TCA_ACT_CONNMARK 14
struct tc_connmark {
tc_gen;
__u16 zone;
};
enum {
TCA_CONNMARK_UNSPEC,
TCA_CONNMARK_PARMS,
TCA_CONNMARK_TM,
__TCA_CONNMARK_MAX
};
#define TCA_CONNMARK_MAX (__TCA_CONNMARK_MAX - 1)
#endif

View File

@ -112,6 +112,9 @@ enum {
#define TCP_FASTOPEN 23 /* Enable FastOpen on listeners */ #define TCP_FASTOPEN 23 /* Enable FastOpen on listeners */
#define TCP_TIMESTAMP 24 #define TCP_TIMESTAMP 24
#define TCP_NOTSENT_LOWAT 25 /* limit number of unsent bytes in write queue */ #define TCP_NOTSENT_LOWAT 25 /* limit number of unsent bytes in write queue */
#define TCP_CC_INFO 26 /* Get Congestion Control (optional) info */
#define TCP_SAVE_SYN 27 /* Record SYN headers for new connections */
#define TCP_SAVED_SYN 28 /* Get SYN headers recorded for connection */
struct tcp_repair_opt { struct tcp_repair_opt {
__u32 opt_code; __u32 opt_code;
@ -189,6 +192,10 @@ struct tcp_info {
__u64 tcpi_pacing_rate; __u64 tcpi_pacing_rate;
__u64 tcpi_max_pacing_rate; __u64 tcpi_max_pacing_rate;
__u64 tcpi_bytes_acked; /* RFC4898 tcpEStatsAppHCThruOctetsAcked */
__u64 tcpi_bytes_received; /* RFC4898 tcpEStatsAppHCThruOctetsReceived */
__u32 tcpi_segs_out; /* RFC4898 tcpEStatsPerfSegsOut */
__u32 tcpi_segs_in; /* RFC4898 tcpEStatsPerfSegsIn */
}; };
/* for TCP_MD5SIG socket option */ /* for TCP_MD5SIG socket option */

View File

@ -0,0 +1,253 @@
/*
* Copyright (c) 2014, Ericsson AB
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _LINUX_TIPC_NETLINK_H_
#define _LINUX_TIPC_NETLINK_H_
#define TIPC_GENL_V2_NAME "TIPCv2"
#define TIPC_GENL_V2_VERSION 0x1
/* Netlink commands */
enum {
TIPC_NL_UNSPEC,
TIPC_NL_LEGACY,
TIPC_NL_BEARER_DISABLE,
TIPC_NL_BEARER_ENABLE,
TIPC_NL_BEARER_GET,
TIPC_NL_BEARER_SET,
TIPC_NL_SOCK_GET,
TIPC_NL_PUBL_GET,
TIPC_NL_LINK_GET,
TIPC_NL_LINK_SET,
TIPC_NL_LINK_RESET_STATS,
TIPC_NL_MEDIA_GET,
TIPC_NL_MEDIA_SET,
TIPC_NL_NODE_GET,
TIPC_NL_NET_GET,
TIPC_NL_NET_SET,
TIPC_NL_NAME_TABLE_GET,
__TIPC_NL_CMD_MAX,
TIPC_NL_CMD_MAX = __TIPC_NL_CMD_MAX - 1
};
/* Top level netlink attributes */
enum {
TIPC_NLA_UNSPEC,
TIPC_NLA_BEARER, /* nest */
TIPC_NLA_SOCK, /* nest */
TIPC_NLA_PUBL, /* nest */
TIPC_NLA_LINK, /* nest */
TIPC_NLA_MEDIA, /* nest */
TIPC_NLA_NODE, /* nest */
TIPC_NLA_NET, /* nest */
TIPC_NLA_NAME_TABLE, /* nest */
__TIPC_NLA_MAX,
TIPC_NLA_MAX = __TIPC_NLA_MAX - 1
};
/* Bearer info */
enum {
TIPC_NLA_BEARER_UNSPEC,
TIPC_NLA_BEARER_NAME, /* string */
TIPC_NLA_BEARER_PROP, /* nest */
TIPC_NLA_BEARER_DOMAIN, /* u32 */
TIPC_NLA_BEARER_UDP_OPTS, /* nest */
__TIPC_NLA_BEARER_MAX,
TIPC_NLA_BEARER_MAX = __TIPC_NLA_BEARER_MAX - 1
};
enum {
TIPC_NLA_UDP_UNSPEC,
TIPC_NLA_UDP_LOCAL, /* sockaddr_storage */
TIPC_NLA_UDP_REMOTE, /* sockaddr_storage */
__TIPC_NLA_UDP_MAX,
TIPC_NLA_UDP_MAX = __TIPC_NLA_UDP_MAX - 1
};
/* Socket info */
enum {
TIPC_NLA_SOCK_UNSPEC,
TIPC_NLA_SOCK_ADDR, /* u32 */
TIPC_NLA_SOCK_REF, /* u32 */
TIPC_NLA_SOCK_CON, /* nest */
TIPC_NLA_SOCK_HAS_PUBL, /* flag */
__TIPC_NLA_SOCK_MAX,
TIPC_NLA_SOCK_MAX = __TIPC_NLA_SOCK_MAX - 1
};
/* Link info */
enum {
TIPC_NLA_LINK_UNSPEC,
TIPC_NLA_LINK_NAME, /* string */
TIPC_NLA_LINK_DEST, /* u32 */
TIPC_NLA_LINK_MTU, /* u32 */
TIPC_NLA_LINK_BROADCAST, /* flag */
TIPC_NLA_LINK_UP, /* flag */
TIPC_NLA_LINK_ACTIVE, /* flag */
TIPC_NLA_LINK_PROP, /* nest */
TIPC_NLA_LINK_STATS, /* nest */
TIPC_NLA_LINK_RX, /* u32 */
TIPC_NLA_LINK_TX, /* u32 */
__TIPC_NLA_LINK_MAX,
TIPC_NLA_LINK_MAX = __TIPC_NLA_LINK_MAX - 1
};
/* Media info */
enum {
TIPC_NLA_MEDIA_UNSPEC,
TIPC_NLA_MEDIA_NAME, /* string */
TIPC_NLA_MEDIA_PROP, /* nest */
__TIPC_NLA_MEDIA_MAX,
TIPC_NLA_MEDIA_MAX = __TIPC_NLA_MEDIA_MAX - 1
};
/* Node info */
enum {
TIPC_NLA_NODE_UNSPEC,
TIPC_NLA_NODE_ADDR, /* u32 */
TIPC_NLA_NODE_UP, /* flag */
__TIPC_NLA_NODE_MAX,
TIPC_NLA_NODE_MAX = __TIPC_NLA_NODE_MAX - 1
};
/* Net info */
enum {
TIPC_NLA_NET_UNSPEC,
TIPC_NLA_NET_ID, /* u32 */
TIPC_NLA_NET_ADDR, /* u32 */
__TIPC_NLA_NET_MAX,
TIPC_NLA_NET_MAX = __TIPC_NLA_NET_MAX - 1
};
/* Name table info */
enum {
TIPC_NLA_NAME_TABLE_UNSPEC,
TIPC_NLA_NAME_TABLE_PUBL, /* nest */
__TIPC_NLA_NAME_TABLE_MAX,
TIPC_NLA_NAME_TABLE_MAX = __TIPC_NLA_NAME_TABLE_MAX - 1
};
/* Publication info */
enum {
TIPC_NLA_PUBL_UNSPEC,
TIPC_NLA_PUBL_TYPE, /* u32 */
TIPC_NLA_PUBL_LOWER, /* u32 */
TIPC_NLA_PUBL_UPPER, /* u32 */
TIPC_NLA_PUBL_SCOPE, /* u32 */
TIPC_NLA_PUBL_NODE, /* u32 */
TIPC_NLA_PUBL_REF, /* u32 */
TIPC_NLA_PUBL_KEY, /* u32 */
__TIPC_NLA_PUBL_MAX,
TIPC_NLA_PUBL_MAX = __TIPC_NLA_PUBL_MAX - 1
};
/* Nest, connection info */
enum {
TIPC_NLA_CON_UNSPEC,
TIPC_NLA_CON_FLAG, /* flag */
TIPC_NLA_CON_NODE, /* u32 */
TIPC_NLA_CON_SOCK, /* u32 */
TIPC_NLA_CON_TYPE, /* u32 */
TIPC_NLA_CON_INST, /* u32 */
__TIPC_NLA_CON_MAX,
TIPC_NLA_CON_MAX = __TIPC_NLA_CON_MAX - 1
};
/* Nest, link propreties. Valid for link, media and bearer */
enum {
TIPC_NLA_PROP_UNSPEC,
TIPC_NLA_PROP_PRIO, /* u32 */
TIPC_NLA_PROP_TOL, /* u32 */
TIPC_NLA_PROP_WIN, /* u32 */
__TIPC_NLA_PROP_MAX,
TIPC_NLA_PROP_MAX = __TIPC_NLA_PROP_MAX - 1
};
/* Nest, statistics info */
enum {
TIPC_NLA_STATS_UNSPEC,
TIPC_NLA_STATS_RX_INFO, /* u32 */
TIPC_NLA_STATS_RX_FRAGMENTS, /* u32 */
TIPC_NLA_STATS_RX_FRAGMENTED, /* u32 */
TIPC_NLA_STATS_RX_BUNDLES, /* u32 */
TIPC_NLA_STATS_RX_BUNDLED, /* u32 */
TIPC_NLA_STATS_TX_INFO, /* u32 */
TIPC_NLA_STATS_TX_FRAGMENTS, /* u32 */
TIPC_NLA_STATS_TX_FRAGMENTED, /* u32 */
TIPC_NLA_STATS_TX_BUNDLES, /* u32 */
TIPC_NLA_STATS_TX_BUNDLED, /* u32 */
TIPC_NLA_STATS_MSG_PROF_TOT, /* u32 */
TIPC_NLA_STATS_MSG_LEN_CNT, /* u32 */
TIPC_NLA_STATS_MSG_LEN_TOT, /* u32 */
TIPC_NLA_STATS_MSG_LEN_P0, /* u32 */
TIPC_NLA_STATS_MSG_LEN_P1, /* u32 */
TIPC_NLA_STATS_MSG_LEN_P2, /* u32 */
TIPC_NLA_STATS_MSG_LEN_P3, /* u32 */
TIPC_NLA_STATS_MSG_LEN_P4, /* u32 */
TIPC_NLA_STATS_MSG_LEN_P5, /* u32 */
TIPC_NLA_STATS_MSG_LEN_P6, /* u32 */
TIPC_NLA_STATS_RX_STATES, /* u32 */
TIPC_NLA_STATS_RX_PROBES, /* u32 */
TIPC_NLA_STATS_RX_NACKS, /* u32 */
TIPC_NLA_STATS_RX_DEFERRED, /* u32 */
TIPC_NLA_STATS_TX_STATES, /* u32 */
TIPC_NLA_STATS_TX_PROBES, /* u32 */
TIPC_NLA_STATS_TX_NACKS, /* u32 */
TIPC_NLA_STATS_TX_ACKS, /* u32 */
TIPC_NLA_STATS_RETRANSMITTED, /* u32 */
TIPC_NLA_STATS_DUPLICATES, /* u32 */
TIPC_NLA_STATS_LINK_CONGS, /* u32 */
TIPC_NLA_STATS_MAX_QUEUE, /* u32 */
TIPC_NLA_STATS_AVG_QUEUE, /* u32 */
__TIPC_NLA_STATS_MAX,
TIPC_NLA_STATS_MAX = __TIPC_NLA_STATS_MAX - 1
};
#endif

View File

@ -1,6 +1,7 @@
#ifndef _LINUX_XFRM_H #ifndef _LINUX_XFRM_H
#define _LINUX_XFRM_H #define _LINUX_XFRM_H
#include <linux/in6.h>
#include <linux/types.h> #include <linux/types.h>
/* All of the structures in this file may not change size as they are /* All of the structures in this file may not change size as they are
@ -13,6 +14,7 @@
typedef union { typedef union {
__be32 a4; __be32 a4;
__be32 a6[4]; __be32 a6[4];
struct in6_addr in6;
} xfrm_address_t; } xfrm_address_t;
/* Ident of a specific xfrm_state. It is used on input to lookup /* Ident of a specific xfrm_state. It is used on input to lookup

View File

@ -10,5 +10,6 @@ extern const char *ll_index_to_name(unsigned idx);
extern const char *ll_idx_n2a(unsigned idx, char *buf); extern const char *ll_idx_n2a(unsigned idx, char *buf);
extern int ll_index_to_type(unsigned idx); extern int ll_index_to_type(unsigned idx);
extern int ll_index_to_flags(unsigned idx); extern int ll_index_to_flags(unsigned idx);
extern unsigned namehash(const char *str);
#endif /* __LL_MAP_H__ */ #endif /* __LL_MAP_H__ */

26
include/names.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef DB_NAMES_H_
#define DB_NAMES_H_ 1
#define IDNAME_MAX 256
struct db_entry {
struct db_entry *next;
unsigned int id;
char *name;
};
struct db_names {
unsigned int size;
struct db_entry *cached;
struct db_entry **hash;
int max;
};
struct db_names *db_names_alloc(void);
int db_names_load(struct db_names *db, const char *path);
void db_names_free(struct db_names *db);
char *id_to_name(struct db_names *db, int id, char *name);
int name_to_id(struct db_names *db, int *id, const char *name);
#endif

View File

@ -3,6 +3,7 @@
#include <sched.h> #include <sched.h>
#include <sys/mount.h> #include <sys/mount.h>
#include <unistd.h>
#include <sys/syscall.h> #include <sys/syscall.h>
#include <errno.h> #include <errno.h>

View File

@ -22,7 +22,7 @@ int inet_proto_a2n(const char *buf);
const char * ll_type_n2a(int type, char *buf, int len); const char * ll_type_n2a(int type, char *buf, int len);
const char *ll_addr_n2a(unsigned char *addr, int alen, const char *ll_addr_n2a(const unsigned char *addr, int alen,
int type, char *buf, int blen); int type, char *buf, int blen);
int ll_addr_a2n(char *lladdr, int len, const char *arg); int ll_addr_a2n(char *lladdr, int len, const char *arg);

View File

@ -50,10 +50,11 @@ extern void incomplete_command(void) __attribute__((noreturn));
typedef struct typedef struct
{ {
__u8 family; __u16 flags;
__u8 bytelen; __u16 bytelen;
__s16 bitlen; __s16 bitlen;
__u32 flags; /* These next two fields match rtvia */
__u16 family;
__u32 data[8]; __u32 data[8];
} inet_prefix; } inet_prefix;
@ -77,6 +78,13 @@ struct ipx_addr {
u_int8_t ipx_node[IPX_NODE_LEN]; u_int8_t ipx_node[IPX_NODE_LEN];
}; };
#ifndef AF_MPLS
# define AF_MPLS 28
#endif
/* Maximum number of labels the mpls helpers support */
#define MPLS_MAX_LABELS 8
extern __u32 get_addr32(const char *name); extern __u32 get_addr32(const char *name);
extern int get_addr_1(inet_prefix *dst, const char *arg, int family); extern int get_addr_1(inet_prefix *dst, const char *arg, int family);
extern int get_prefix_1(inet_prefix *dst, char *arg, int family); extern int get_prefix_1(inet_prefix *dst, char *arg, int family);
@ -101,11 +109,17 @@ extern int get_s8(__s8 *val, const char *arg, int base);
extern char* hexstring_n2a(const __u8 *str, int len, char *buf, int blen); extern char* hexstring_n2a(const __u8 *str, int len, char *buf, int blen);
extern __u8* hexstring_a2n(const char *str, __u8 *buf, int blen); extern __u8* hexstring_a2n(const char *str, __u8 *buf, int blen);
extern int af_bit_len(int af);
extern int af_byte_len(int af);
extern const char *format_host(int af, int len, const void *addr, extern const char *format_host(int af, int len, const void *addr,
char *buf, int buflen); char *buf, int buflen);
extern const char *rt_addr_n2a(int af, const void *addr, extern const char *rt_addr_n2a(int af, int len, const void *addr,
char *buf, int buflen); char *buf, int buflen);
extern int read_family(const char *name);
extern const char *family_name(int family);
void missarg(const char *) __attribute__((noreturn)); void missarg(const char *) __attribute__((noreturn));
void invarg(const char *, const char *) __attribute__((noreturn)); void invarg(const char *, const char *) __attribute__((noreturn));
void duparg(const char *, const char *) __attribute__((noreturn)); void duparg(const char *, const char *) __attribute__((noreturn));
@ -119,6 +133,9 @@ int dnet_pton(int af, const char *src, void *addr);
const char *ipx_ntop(int af, const void *addr, char *str, size_t len); const char *ipx_ntop(int af, const void *addr, char *str, size_t len);
int ipx_pton(int af, const char *src, void *addr); int ipx_pton(int af, const char *src, void *addr);
const char *mpls_ntop(int af, const void *addr, char *str, size_t len);
int mpls_pton(int af, const char *src, void *addr);
extern int __iproute2_hz_internal; extern int __iproute2_hz_internal;
extern int __get_hz(void); extern int __get_hz(void);
@ -154,6 +171,25 @@ void print_nlmsg_timestamp(FILE *fp, const struct nlmsghdr *n);
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#define BUILD_BUG_ON(cond) ((void)sizeof(char[1 - 2 * !!(cond)]))
#ifndef offsetof
# define offsetof(type, member) ((size_t) &((type *)0)->member)
#endif
#ifndef min
# define min(x, y) ({ \
typeof(x) _min1 = (x); \
typeof(y) _min2 = (y); \
(void) (&_min1 == &_min2); \
_min1 < _min2 ? _min1 : _min2; })
#endif
#ifndef __check_format_string
# define __check_format_string(pos_str, pos_args) \
__attribute__ ((format (printf, (pos_str), (pos_args))))
#endif
extern int cmdlineno; extern int cmdlineno;
extern ssize_t getcmdline(char **line, size_t *len, FILE *in); extern ssize_t getcmdline(char **line, size_t *len, FILE *in);
extern int makeargs(char *line, char *argv[], int maxargs); extern int makeargs(char *line, char *argv[], int maxargs);
@ -167,4 +203,6 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
extern int do_each_netns(int (*func)(char *nsname, void *arg), void *arg, extern int do_each_netns(int (*func)(char *nsname, void *arg), void *arg,
bool show_label); bool show_label);
char *int_to_str(int val, char *buf);
#endif /* __UTILS_H__ */ #endif /* __UTILS_H__ */

View File

@ -6,7 +6,8 @@ IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o ipnetns.o \
iplink_macvlan.o iplink_macvtap.o ipl2tp.o link_vti.o link_vti6.o \ iplink_macvlan.o iplink_macvtap.o ipl2tp.o link_vti.o link_vti6.o \
iplink_vxlan.o tcp_metrics.o iplink_ipoib.o ipnetconf.o link_ip6tnl.o \ iplink_vxlan.o tcp_metrics.o iplink_ipoib.o ipnetconf.o link_ip6tnl.o \
link_iptnl.o link_gre6.o iplink_bond.o iplink_bond_slave.o iplink_hsr.o \ link_iptnl.o link_gre6.o iplink_bond.o iplink_bond_slave.o iplink_hsr.o \
iplink_bridge.o iplink_bridge_slave.o ipfou.o iplink_ipvlan.o iplink_bridge.o iplink_bridge_slave.o ipfou.o iplink_ipvlan.o \
iplink_geneve.o
RTMONOBJ=rtmon.o RTMONOBJ=rtmon.o

25
ip/ip.c
View File

@ -23,6 +23,7 @@
#include "utils.h" #include "utils.h"
#include "ip_common.h" #include "ip_common.h"
#include "namespace.h" #include "namespace.h"
#include "color.h"
int preferred_family = AF_UNSPEC; int preferred_family = AF_UNSPEC;
int human_readable = 0; int human_readable = 0;
@ -52,11 +53,11 @@ static void usage(void)
" netns | l2tp | fou | tcp_metrics | token | netconf }\n" " netns | l2tp | fou | tcp_metrics | token | netconf }\n"
" OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n" " OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n"
" -h[uman-readable] | -iec |\n" " -h[uman-readable] | -iec |\n"
" -f[amily] { inet | inet6 | ipx | dnet | bridge | link } |\n" " -f[amily] { inet | inet6 | ipx | dnet | mpls | bridge | link } |\n"
" -4 | -6 | -I | -D | -B | -0 |\n" " -4 | -6 | -I | -D | -B | -0 |\n"
" -l[oops] { maximum-addr-flush-attempts } |\n" " -l[oops] { maximum-addr-flush-attempts } |\n"
" -o[neline] | -t[imestamp] | -ts[hort] | -b[atch] [filename] |\n" " -o[neline] | -t[imestamp] | -ts[hort] | -b[atch] [filename] |\n"
" -rc[vbuf] [size] | -n[etns] name | -a[ll] }\n"); " -rc[vbuf] [size] | -n[etns] name | -a[ll] | -c[olor]}\n");
exit(-1); exit(-1);
} }
@ -190,21 +191,11 @@ int main(int argc, char **argv)
argv++; argv++;
if (argc <= 1) if (argc <= 1)
usage(); usage();
if (strcmp(argv[1], "inet") == 0) if (strcmp(argv[1], "help") == 0)
preferred_family = AF_INET;
else if (strcmp(argv[1], "inet6") == 0)
preferred_family = AF_INET6;
else if (strcmp(argv[1], "dnet") == 0)
preferred_family = AF_DECnet;
else if (strcmp(argv[1], "link") == 0)
preferred_family = AF_PACKET;
else if (strcmp(argv[1], "ipx") == 0)
preferred_family = AF_IPX;
else if (strcmp(argv[1], "bridge") == 0)
preferred_family = AF_BRIDGE;
else if (strcmp(argv[1], "help") == 0)
usage(); usage();
else else
preferred_family = read_family(argv[1]);
if (preferred_family == AF_UNSPEC)
invarg("invalid protocol family", argv[1]); invarg("invalid protocol family", argv[1]);
} else if (strcmp(opt, "-4") == 0) { } else if (strcmp(opt, "-4") == 0) {
preferred_family = AF_INET; preferred_family = AF_INET;
@ -216,6 +207,8 @@ int main(int argc, char **argv)
preferred_family = AF_IPX; preferred_family = AF_IPX;
} else if (strcmp(opt, "-D") == 0) { } else if (strcmp(opt, "-D") == 0) {
preferred_family = AF_DECnet; preferred_family = AF_DECnet;
} else if (strcmp(opt, "-M") == 0) {
preferred_family = AF_MPLS;
} else if (strcmp(opt, "-B") == 0) { } else if (strcmp(opt, "-B") == 0) {
preferred_family = AF_BRIDGE; preferred_family = AF_BRIDGE;
} else if (matches(opt, "-human") == 0 || } else if (matches(opt, "-human") == 0 ||
@ -265,6 +258,8 @@ int main(int argc, char **argv)
exit(-1); exit(-1);
} }
rcvbuf = size; rcvbuf = size;
} else if (matches(opt, "-color") == 0) {
enable_color();
} else if (matches(opt, "-help") == 0) { } else if (matches(opt, "-help") == 0) {
usage(); usage();
} else if (matches(opt, "-netns") == 0) { } else if (matches(opt, "-netns") == 0) {

View File

@ -33,7 +33,11 @@ extern int print_prefix(const struct sockaddr_nl *who,
extern int print_rule(const struct sockaddr_nl *who, extern int print_rule(const struct sockaddr_nl *who,
struct nlmsghdr *n, void *arg); struct nlmsghdr *n, void *arg);
extern int print_netconf(const struct sockaddr_nl *who, extern int print_netconf(const struct sockaddr_nl *who,
struct rtnl_ctrl_data *ctrl,
struct nlmsghdr *n, void *arg); struct nlmsghdr *n, void *arg);
extern void netns_map_init(void);
extern int print_nsid(const struct sockaddr_nl *who,
struct nlmsghdr *n, void *arg);
extern int do_ipaddr(int argc, char **argv); extern int do_ipaddr(int argc, char **argv);
extern int do_ipaddrlabel(int argc, char **argv); extern int do_ipaddrlabel(int argc, char **argv);
extern int do_iproute(int argc, char **argv); extern int do_iproute(int argc, char **argv);

View File

@ -28,11 +28,13 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/sockios.h> #include <linux/sockios.h>
#include <linux/net_namespace.h>
#include "rt_names.h" #include "rt_names.h"
#include "utils.h" #include "utils.h"
#include "ll_map.h" #include "ll_map.h"
#include "ip_common.h" #include "ip_common.h"
#include "color.h"
enum { enum {
IPADD_LIST, IPADD_LIST,
@ -84,7 +86,7 @@ static void usage(void)
fprintf(stderr, " [-]tentative | [-]deprecated | [-]dadfailed | temporary |\n"); fprintf(stderr, " [-]tentative | [-]deprecated | [-]dadfailed | temporary |\n");
fprintf(stderr, " CONFFLAG-LIST ]\n"); fprintf(stderr, " CONFFLAG-LIST ]\n");
fprintf(stderr, "CONFFLAG-LIST := [ CONFFLAG-LIST ] CONFFLAG\n"); fprintf(stderr, "CONFFLAG-LIST := [ CONFFLAG-LIST ] CONFFLAG\n");
fprintf(stderr, "CONFFLAG := [ home | nodad | mngtmpaddr | noprefixroute ]\n"); fprintf(stderr, "CONFFLAG := [ home | nodad | mngtmpaddr | noprefixroute | autojoin ]\n");
fprintf(stderr, "LIFETIME := [ valid_lft LFT ] [ preferred_lft LFT ]\n"); fprintf(stderr, "LIFETIME := [ valid_lft LFT ] [ preferred_lft LFT ]\n");
fprintf(stderr, "LFT := forever | SECONDS\n"); fprintf(stderr, "LFT := forever | SECONDS\n");
@ -135,8 +137,15 @@ static void print_operstate(FILE *f, __u8 state)
{ {
if (state >= sizeof(oper_states)/sizeof(oper_states[0])) if (state >= sizeof(oper_states)/sizeof(oper_states[0]))
fprintf(f, "state %#x ", state); fprintf(f, "state %#x ", state);
else else {
fprintf(f, "state %s ", oper_states[state]); fprintf(f, "state ");
if (strcmp(oper_states[state], "UP") == 0)
color_fprintf(f, COLOR_OPERSTATE_UP, "%s ", oper_states[state]);
else if (strcmp(oper_states[state], "DOWN") == 0)
color_fprintf(f, COLOR_OPERSTATE_DOWN, "%s ", oper_states[state]);
else
fprintf(f, "%s ", oper_states[state]);
}
} }
int get_operstate(const char *name) int get_operstate(const char *name)
@ -605,7 +614,8 @@ int print_linkinfo(const struct sockaddr_nl *who,
if (n->nlmsg_type == RTM_DELLINK) if (n->nlmsg_type == RTM_DELLINK)
fprintf(fp, "Deleted "); fprintf(fp, "Deleted ");
fprintf(fp, "%d: %s", ifi->ifi_index, fprintf(fp, "%d: ", ifi->ifi_index);
color_fprintf(fp, COLOR_IFNAME, "%s",
tb[IFLA_IFNAME] ? rta_getattr_str(tb[IFLA_IFNAME]) : "<nil>"); tb[IFLA_IFNAME] ? rta_getattr_str(tb[IFLA_IFNAME]) : "<nil>");
if (tb[IFLA_LINK]) { if (tb[IFLA_LINK]) {
@ -614,9 +624,13 @@ int print_linkinfo(const struct sockaddr_nl *who,
if (iflink == 0) if (iflink == 0)
fprintf(fp, "@NONE: "); fprintf(fp, "@NONE: ");
else { else {
fprintf(fp, "@%s: ", ll_idx_n2a(iflink, b1)); if (tb[IFLA_LINK_NETNSID])
m_flag = ll_index_to_flags(iflink); fprintf(fp, "@if%d: ", iflink);
m_flag = !(m_flag & IFF_UP); else {
fprintf(fp, "@%s: ", ll_idx_n2a(iflink, b1));
m_flag = ll_index_to_flags(iflink);
m_flag = !(m_flag & IFF_UP);
}
} }
} else { } else {
fprintf(fp, ": "); fprintf(fp, ": ");
@ -661,10 +675,11 @@ int print_linkinfo(const struct sockaddr_nl *who,
fprintf(fp, " link/%s ", ll_type_n2a(ifi->ifi_type, b1, sizeof(b1))); fprintf(fp, " link/%s ", ll_type_n2a(ifi->ifi_type, b1, sizeof(b1)));
if (tb[IFLA_ADDRESS]) { if (tb[IFLA_ADDRESS]) {
fprintf(fp, "%s", ll_addr_n2a(RTA_DATA(tb[IFLA_ADDRESS]), color_fprintf(fp, COLOR_MAC, "%s",
RTA_PAYLOAD(tb[IFLA_ADDRESS]), ll_addr_n2a(RTA_DATA(tb[IFLA_ADDRESS]),
ifi->ifi_type, RTA_PAYLOAD(tb[IFLA_ADDRESS]),
b1, sizeof(b1))); ifi->ifi_type,
b1, sizeof(b1)));
} }
if (tb[IFLA_BROADCAST]) { if (tb[IFLA_BROADCAST]) {
if (ifi->ifi_flags&IFF_POINTOPOINT) if (ifi->ifi_flags&IFF_POINTOPOINT)
@ -678,6 +693,15 @@ int print_linkinfo(const struct sockaddr_nl *who,
} }
} }
if (tb[IFLA_LINK_NETNSID]) {
int id = *(int*)RTA_DATA(tb[IFLA_LINK_NETNSID]);
if (id >= 0)
fprintf(fp, " link-netnsid %d", id);
else
fprintf(fp, " link-netnsid unknown");
}
if (tb[IFLA_PROMISCUITY] && show_details) if (tb[IFLA_PROMISCUITY] && show_details)
fprintf(fp, " promiscuity %u ", fprintf(fp, " promiscuity %u ",
*(int*)RTA_DATA(tb[IFLA_PROMISCUITY])); *(int*)RTA_DATA(tb[IFLA_PROMISCUITY]));
@ -835,10 +859,21 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
fprintf(fp, " family %d ", ifa->ifa_family); fprintf(fp, " family %d ", ifa->ifa_family);
if (rta_tb[IFA_LOCAL]) { if (rta_tb[IFA_LOCAL]) {
fprintf(fp, "%s", format_host(ifa->ifa_family, if (ifa->ifa_family == AF_INET)
RTA_PAYLOAD(rta_tb[IFA_LOCAL]), color_fprintf(fp, COLOR_INET, "%s", format_host(ifa->ifa_family,
RTA_DATA(rta_tb[IFA_LOCAL]), RTA_PAYLOAD(rta_tb[IFA_LOCAL]),
abuf, sizeof(abuf))); RTA_DATA(rta_tb[IFA_LOCAL]),
abuf, sizeof(abuf)));
else if (ifa->ifa_family == AF_INET6)
color_fprintf(fp, COLOR_INET6, "%s", format_host(ifa->ifa_family,
RTA_PAYLOAD(rta_tb[IFA_LOCAL]),
RTA_DATA(rta_tb[IFA_LOCAL]),
abuf, sizeof(abuf)));
else
fprintf(fp, "%s", format_host(ifa->ifa_family,
RTA_PAYLOAD(rta_tb[IFA_LOCAL]),
RTA_DATA(rta_tb[IFA_LOCAL]),
abuf, sizeof(abuf)));
if (rta_tb[IFA_ADDRESS] == NULL || if (rta_tb[IFA_ADDRESS] == NULL ||
memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_LOCAL]), memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_LOCAL]),
@ -901,6 +936,10 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
ifa_flags &= ~IFA_F_NOPREFIXROUTE; ifa_flags &= ~IFA_F_NOPREFIXROUTE;
fprintf(fp, "noprefixroute "); fprintf(fp, "noprefixroute ");
} }
if (ifa_flags & IFA_F_MCAUTOJOIN) {
ifa_flags &= ~IFA_F_MCAUTOJOIN;
fprintf(fp, "autojoin ");
}
if (!(ifa_flags & IFA_F_PERMANENT)) { if (!(ifa_flags & IFA_F_PERMANENT)) {
fprintf(fp, "dynamic "); fprintf(fp, "dynamic ");
} else } else
@ -1072,7 +1111,9 @@ static int save_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n,
return ret == n->nlmsg_len ? 0 : ret; return ret == n->nlmsg_len ? 0 : ret;
} }
static int show_handler(const struct sockaddr_nl *nl, struct nlmsghdr *n, void *arg) static int show_handler(const struct sockaddr_nl *nl,
struct rtnl_ctrl_data *ctrl,
struct nlmsghdr *n, void *arg)
{ {
struct ifaddrmsg *ifa = NLMSG_DATA(n); struct ifaddrmsg *ifa = NLMSG_DATA(n);
@ -1089,7 +1130,9 @@ static int ipaddr_showdump(void)
exit(rtnl_from_file(stdin, &show_handler, NULL)); exit(rtnl_from_file(stdin, &show_handler, NULL));
} }
static int restore_handler(const struct sockaddr_nl *nl, struct nlmsghdr *n, void *arg) static int restore_handler(const struct sockaddr_nl *nl,
struct rtnl_ctrl_data *ctrl,
struct nlmsghdr *n, void *arg)
{ {
int ret; int ret;
@ -1097,7 +1140,7 @@ static int restore_handler(const struct sockaddr_nl *nl, struct nlmsghdr *n, voi
ll_init_map(&rth); ll_init_map(&rth);
ret = rtnl_talk(&rth, n, 0, 0, n); ret = rtnl_talk(&rth, n, n, sizeof(*n));
if ((ret < 0) && (errno == EEXIST)) if ((ret < 0) && (errno == EEXIST))
ret = 0; ret = 0;
@ -1340,6 +1383,9 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
} else if (strcmp(*argv, "noprefixroute") == 0) { } else if (strcmp(*argv, "noprefixroute") == 0) {
filter.flags |= IFA_F_NOPREFIXROUTE; filter.flags |= IFA_F_NOPREFIXROUTE;
filter.flagmask |= IFA_F_NOPREFIXROUTE; filter.flagmask |= IFA_F_NOPREFIXROUTE;
} else if (strcmp(*argv, "autojoin") == 0) {
filter.flags |= IFA_F_MCAUTOJOIN;
filter.flagmask |= IFA_F_MCAUTOJOIN;
} else if (strcmp(*argv, "dadfailed") == 0) { } else if (strcmp(*argv, "dadfailed") == 0) {
filter.flags |= IFA_F_DADFAILED; filter.flags |= IFA_F_DADFAILED;
filter.flagmask |= IFA_F_DADFAILED; filter.flagmask |= IFA_F_DADFAILED;
@ -1544,6 +1590,16 @@ static int default_scope(inet_prefix *lcl)
return 0; return 0;
} }
static bool ipaddr_is_multicast(inet_prefix *a)
{
if (a->family == AF_INET)
return IN_MULTICAST(ntohl(a->data[0]));
else if (a->family == AF_INET6)
return IN6_IS_ADDR_MULTICAST(a->data);
else
return false;
}
static int ipaddr_modify(int cmd, int flags, int argc, char **argv) static int ipaddr_modify(int cmd, int flags, int argc, char **argv)
{ {
struct { struct {
@ -1651,6 +1707,8 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv)
ifa_flags |= IFA_F_MANAGETEMPADDR; ifa_flags |= IFA_F_MANAGETEMPADDR;
} else if (strcmp(*argv, "noprefixroute") == 0) { } else if (strcmp(*argv, "noprefixroute") == 0) {
ifa_flags |= IFA_F_NOPREFIXROUTE; ifa_flags |= IFA_F_NOPREFIXROUTE;
} else if (strcmp(*argv, "autojoin") == 0) {
ifa_flags |= IFA_F_MCAUTOJOIN;
} else { } else {
if (strcmp(*argv, "local") == 0) { if (strcmp(*argv, "local") == 0) {
NEXT_ARG(); NEXT_ARG();
@ -1741,7 +1799,12 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv)
sizeof(cinfo)); sizeof(cinfo));
} }
if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) if ((ifa_flags & IFA_F_MCAUTOJOIN) && !ipaddr_is_multicast(&lcl)) {
fprintf(stderr, "autojoin needs multicast address\n");
return -1;
}
if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
return -2; return -2;
return 0; return 0;

View File

@ -182,8 +182,8 @@ static int ipaddrlabel_modify(int cmd, int argc, char **argv)
if (req.ifal.ifal_family == AF_UNSPEC) if (req.ifal.ifal_family == AF_UNSPEC)
req.ifal.ifal_family = AF_INET6; req.ifal.ifal_family = AF_INET6;
if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
return 2; return -2;
return 0; return 0;
} }
@ -209,7 +209,7 @@ static int flush_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, vo
if (rtnl_open(&rth2, 0) < 0) if (rtnl_open(&rth2, 0) < 0)
return -1; return -1;
if (rtnl_talk(&rth2, n, 0, 0, NULL) < 0) if (rtnl_talk(&rth2, n, NULL, 0) < 0)
return -2; return -2;
rtnl_close(&rth2); rtnl_close(&rth2);
@ -232,12 +232,12 @@ static int ipaddrlabel_flush(int argc, char **argv)
if (rtnl_wilddump_request(&rth, af, RTM_GETADDRLABEL) < 0) { if (rtnl_wilddump_request(&rth, af, RTM_GETADDRLABEL) < 0) {
perror("Cannot send dump request"); perror("Cannot send dump request");
return 1; return -1;
} }
if (rtnl_dump_filter(&rth, flush_addrlabel, NULL) < 0) { if (rtnl_dump_filter(&rth, flush_addrlabel, NULL) < 0) {
fprintf(stderr, "Flush terminated\n"); fprintf(stderr, "Flush terminated\n");
return 1; return -1;
} }
return 0; return 0;
@ -248,6 +248,7 @@ int do_ipaddrlabel(int argc, char **argv)
if (argc < 1) { if (argc < 1) {
return ipaddrlabel_list(0, NULL); return ipaddrlabel_list(0, NULL);
} else if (matches(argv[0], "list") == 0 || } else if (matches(argv[0], "list") == 0 ||
matches(argv[0], "lst") == 0 ||
matches(argv[0], "show") == 0) { matches(argv[0], "show") == 0) {
return ipaddrlabel_list(argc-1, argv+1); return ipaddrlabel_list(argc-1, argv+1);
} else if (matches(argv[0], "add") == 0) { } else if (matches(argv[0], "add") == 0) {

View File

@ -112,7 +112,7 @@ static int do_add(int argc, char **argv)
fou_parse_opt(argc, argv, &req.n, true); fou_parse_opt(argc, argv, &req.n, true);
if (rtnl_talk(&genl_rth, &req.n, 0, 0, NULL) < 0) if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0)
return -2; return -2;
return 0; return 0;
@ -124,7 +124,7 @@ static int do_del(int argc, char **argv)
fou_parse_opt(argc, argv, &req.n, false); fou_parse_opt(argc, argv, &req.n, false);
if (rtnl_talk(&genl_rth, &req.n, 0, 0, NULL) < 0) if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0)
return -2; return -2;
return 0; return 0;

View File

@ -119,7 +119,7 @@ static int create_tunnel(struct l2tp_parm *p)
addattr16(&req.n, 1024, L2TP_ATTR_UDP_DPORT, p->peer_udp_port); addattr16(&req.n, 1024, L2TP_ATTR_UDP_DPORT, p->peer_udp_port);
} }
if (rtnl_talk(&genl_rth, &req.n, 0, 0, NULL) < 0) if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0)
return -2; return -2;
return 0; return 0;
@ -132,7 +132,7 @@ static int delete_tunnel(struct l2tp_parm *p)
addattr32(&req.n, 128, L2TP_ATTR_CONN_ID, p->tunnel_id); addattr32(&req.n, 128, L2TP_ATTR_CONN_ID, p->tunnel_id);
if (rtnl_talk(&genl_rth, &req.n, 0, 0, NULL) < 0) if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0)
return -2; return -2;
return 0; return 0;
@ -166,7 +166,7 @@ static int create_session(struct l2tp_parm *p)
if (p->ifname && p->ifname[0]) if (p->ifname && p->ifname[0])
addattrstrz(&req.n, 1024, L2TP_ATTR_IFNAME, p->ifname); addattrstrz(&req.n, 1024, L2TP_ATTR_IFNAME, p->ifname);
if (rtnl_talk(&genl_rth, &req.n, 0, 0, NULL) < 0) if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0)
return -2; return -2;
return 0; return 0;
@ -179,7 +179,7 @@ static int delete_session(struct l2tp_parm *p)
addattr32(&req.n, 1024, L2TP_ATTR_CONN_ID, p->tunnel_id); addattr32(&req.n, 1024, L2TP_ATTR_CONN_ID, p->tunnel_id);
addattr32(&req.n, 1024, L2TP_ATTR_SESSION_ID, p->session_id); addattr32(&req.n, 1024, L2TP_ATTR_SESSION_ID, p->session_id);
if (rtnl_talk(&genl_rth, &req.n, 0, 0, NULL) < 0) if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0)
return -2; return -2;
return 0; return 0;

View File

@ -53,9 +53,9 @@ void iplink_usage(void)
fprintf(stderr, " [ numtxqueues QUEUE_COUNT ]\n"); fprintf(stderr, " [ numtxqueues QUEUE_COUNT ]\n");
fprintf(stderr, " [ numrxqueues QUEUE_COUNT ]\n"); fprintf(stderr, " [ numrxqueues QUEUE_COUNT ]\n");
fprintf(stderr, " type TYPE [ ARGS ]\n"); fprintf(stderr, " type TYPE [ ARGS ]\n");
fprintf(stderr, " ip link delete DEV type TYPE [ ARGS ]\n"); fprintf(stderr, " ip link delete { DEVICE | dev DEVICE | group DEVGROUP } type TYPE [ ARGS ]\n");
fprintf(stderr, "\n"); fprintf(stderr, "\n");
fprintf(stderr, " ip link set { dev DEVICE | group DEVGROUP } [ { up | down } ]\n"); fprintf(stderr, " ip link set { DEVICE | dev DEVICE | group DEVGROUP } [ { up | down } ]\n");
} else } else
fprintf(stderr, "Usage: ip link set DEVICE [ { up | down } ]\n"); fprintf(stderr, "Usage: ip link set DEVICE [ { up | down } ]\n");
@ -72,6 +72,7 @@ void iplink_usage(void)
fprintf(stderr, " [ mtu MTU ]\n"); fprintf(stderr, " [ mtu MTU ]\n");
fprintf(stderr, " [ netns PID ]\n"); fprintf(stderr, " [ netns PID ]\n");
fprintf(stderr, " [ netns NAME ]\n"); fprintf(stderr, " [ netns NAME ]\n");
fprintf(stderr, " [ link-netnsid ID ]\n");
fprintf(stderr, " [ alias NAME ]\n"); fprintf(stderr, " [ alias NAME ]\n");
fprintf(stderr, " [ vf NUM [ mac LLADDR ]\n"); fprintf(stderr, " [ vf NUM [ mac LLADDR ]\n");
fprintf(stderr, " [ vlan VLANID [ qos VLAN-QOS ] ]\n"); fprintf(stderr, " [ vlan VLANID [ qos VLAN-QOS ] ]\n");
@ -79,6 +80,7 @@ void iplink_usage(void)
fprintf(stderr, " [ rate TXRATE ] ] \n"); fprintf(stderr, " [ rate TXRATE ] ] \n");
fprintf(stderr, " [ spoofchk { on | off} ] ] \n"); fprintf(stderr, " [ spoofchk { on | off} ] ] \n");
fprintf(stderr, " [ query_rss { on | off} ] ] \n");
fprintf(stderr, " [ state { auto | enable | disable} ] ]\n"); fprintf(stderr, " [ state { auto | enable | disable} ] ]\n");
fprintf(stderr, " [ master DEVICE ]\n"); fprintf(stderr, " [ master DEVICE ]\n");
fprintf(stderr, " [ nomaster ]\n"); fprintf(stderr, " [ nomaster ]\n");
@ -91,7 +93,7 @@ void iplink_usage(void)
fprintf(stderr, "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | macvtap |\n"); fprintf(stderr, "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | macvtap |\n");
fprintf(stderr, " bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan |\n"); fprintf(stderr, " bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan |\n");
fprintf(stderr, " gre | gretap | ip6gre | ip6gretap | vti | nlmon |\n"); fprintf(stderr, " gre | gretap | ip6gre | ip6gretap | vti | nlmon |\n");
fprintf(stderr, " bond_slave | ipvlan }\n"); fprintf(stderr, " bond_slave | ipvlan | geneve }\n");
} }
exit(-1); exit(-1);
} }
@ -178,6 +180,7 @@ static int get_addr_gen_mode(const char *mode)
static int have_rtnl_newlink = -1; static int have_rtnl_newlink = -1;
static int accept_msg(const struct sockaddr_nl *who, static int accept_msg(const struct sockaddr_nl *who,
struct rtnl_ctrl_data *ctrl,
struct nlmsghdr *n, void *arg) struct nlmsghdr *n, void *arg)
{ {
struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n); struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
@ -330,6 +333,18 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
ivs.vf = vf; ivs.vf = vf;
addattr_l(&req->n, sizeof(*req), IFLA_VF_SPOOFCHK, &ivs, sizeof(ivs)); addattr_l(&req->n, sizeof(*req), IFLA_VF_SPOOFCHK, &ivs, sizeof(ivs));
} else if (matches(*argv, "query_rss") == 0) {
struct ifla_vf_rss_query_en ivs;
NEXT_ARG();
if (matches(*argv, "on") == 0)
ivs.setting = 1;
else if (matches(*argv, "off") == 0)
ivs.setting = 0;
else
invarg("Invalid \"query_rss\" value\n", *argv);
ivs.vf = vf;
addattr_l(&req->n, sizeof(*req), IFLA_VF_RSS_QUERY_EN, &ivs, sizeof(ivs));
} else if (matches(*argv, "state") == 0) { } else if (matches(*argv, "state") == 0) {
struct ifla_vf_link_state ivl; struct ifla_vf_link_state ivl;
NEXT_ARG(); NEXT_ARG();
@ -386,6 +401,7 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
int numtxqueues = -1; int numtxqueues = -1;
int numrxqueues = -1; int numrxqueues = -1;
int dev_index = 0; int dev_index = 0;
int link_netnsid = -1;
*group = -1; *group = -1;
ret = argc; ret = argc;
@ -588,6 +604,14 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
addattr8(&req->n, sizeof(*req), IFLA_INET6_ADDR_GEN_MODE, mode); addattr8(&req->n, sizeof(*req), IFLA_INET6_ADDR_GEN_MODE, mode);
addattr_nest_end(&req->n, afs6); addattr_nest_end(&req->n, afs6);
addattr_nest_end(&req->n, afs); addattr_nest_end(&req->n, afs);
} else if (matches(*argv, "link-netnsid") == 0) {
NEXT_ARG();
if (link_netnsid != -1)
duparg("link-netnsid", *argv);
if (get_integer(&link_netnsid, *argv, 0))
invarg("Invalid \"link-netnsid\" value\n", *argv);
addattr32(&req->n, sizeof(*req), IFLA_LINK_NETNSID,
link_netnsid);
} else { } else {
if (strcmp(*argv, "dev") == 0) { if (strcmp(*argv, "dev") == 0) {
NEXT_ARG(); NEXT_ARG();
@ -651,7 +675,7 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
req.i.ifi_index = 0; req.i.ifi_index = 0;
addattr32(&req.n, sizeof(req), IFLA_GROUP, group); addattr32(&req.n, sizeof(req), IFLA_GROUP, group);
if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
exit(2); exit(2);
return 0; return 0;
} }
@ -750,7 +774,7 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
return -1; return -1;
} }
if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
exit(2); exit(2);
return 0; return 0;
@ -760,7 +784,10 @@ int iplink_get(unsigned int flags, char *name, __u32 filt_mask)
{ {
int len; int len;
struct iplink_req req; struct iplink_req req;
char answer[16384]; struct {
struct nlmsghdr n;
char buf[16384];
} answer;
memset(&req, 0, sizeof(req)); memset(&req, 0, sizeof(req));
@ -780,10 +807,10 @@ int iplink_get(unsigned int flags, char *name, __u32 filt_mask)
} }
addattr32(&req.n, sizeof(req), IFLA_EXT_MASK, filt_mask); addattr32(&req.n, sizeof(req), IFLA_EXT_MASK, filt_mask);
if (rtnl_talk(&rth, &req.n, 0, 0, (struct nlmsghdr *)answer) < 0) if (rtnl_talk(&rth, &req.n, &answer.n, sizeof(answer)) < 0)
return -2; return -2;
print_linkinfo(NULL, (struct nlmsghdr *)answer, stdout); print_linkinfo(NULL, &answer.n, stdout);
return 0; return 0;
} }

View File

@ -135,6 +135,9 @@ static void print_explain(FILE *f)
" [ packets_per_slave PACKETS_PER_SLAVE ]\n" " [ packets_per_slave PACKETS_PER_SLAVE ]\n"
" [ lacp_rate LACP_RATE ]\n" " [ lacp_rate LACP_RATE ]\n"
" [ ad_select AD_SELECT ]\n" " [ ad_select AD_SELECT ]\n"
" [ ad_user_port_key PORTKEY ]\n"
" [ ad_actor_sys_prio SYSPRIO ]\n"
" [ ad_actor_system LLADDR ]\n"
"\n" "\n"
"BONDMODE := balance-rr|active-backup|balance-xor|broadcast|802.3ad|balance-tlb|balance-alb\n" "BONDMODE := balance-rr|active-backup|balance-xor|broadcast|802.3ad|balance-tlb|balance-alb\n"
"ARP_VALIDATE := none|active|backup|all\n" "ARP_VALIDATE := none|active|backup|all\n"
@ -158,6 +161,7 @@ static int bond_parse_opt(struct link_util *lu, int argc, char **argv,
__u8 mode, use_carrier, primary_reselect, fail_over_mac; __u8 mode, use_carrier, primary_reselect, fail_over_mac;
__u8 xmit_hash_policy, num_peer_notif, all_slaves_active; __u8 xmit_hash_policy, num_peer_notif, all_slaves_active;
__u8 lacp_rate, ad_select; __u8 lacp_rate, ad_select;
__u16 ad_user_port_key, ad_actor_sys_prio;
__u32 miimon, updelay, downdelay, arp_interval, arp_validate; __u32 miimon, updelay, downdelay, arp_interval, arp_validate;
__u32 arp_all_targets, resend_igmp, min_links, lp_interval; __u32 arp_all_targets, resend_igmp, min_links, lp_interval;
__u32 packets_per_slave; __u32 packets_per_slave;
@ -344,6 +348,32 @@ static int bond_parse_opt(struct link_util *lu, int argc, char **argv,
} }
ad_select = get_index(ad_select_tbl, *argv); ad_select = get_index(ad_select_tbl, *argv);
addattr8(n, 1024, IFLA_BOND_AD_SELECT, ad_select); addattr8(n, 1024, IFLA_BOND_AD_SELECT, ad_select);
} else if (matches(*argv, "ad_user_port_key") == 0) {
NEXT_ARG();
if (get_u16(&ad_user_port_key, *argv, 0)) {
invarg("invalid ad_user_port_key", *argv);
return -1;
}
addattr16(n, 1024, IFLA_BOND_AD_USER_PORT_KEY,
ad_user_port_key);
} else if (matches(*argv, "ad_actor_sys_prio") == 0) {
NEXT_ARG();
if (get_u16(&ad_actor_sys_prio, *argv, 0)) {
invarg("invalid ad_actor_sys_prio", *argv);
return -1;
}
addattr16(n, 1024, IFLA_BOND_AD_ACTOR_SYS_PRIO,
ad_actor_sys_prio);
} else if (matches(*argv, "ad_actor_system") == 0) {
int len;
char abuf[32];
NEXT_ARG();
len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
if (len < 0)
return -1;
addattr_l(n, 1024, IFLA_BOND_AD_ACTOR_SYSTEM,
abuf, len);
} else if (matches(*argv, "help") == 0) { } else if (matches(*argv, "help") == 0) {
explain(); explain();
return -1; return -1;
@ -415,6 +445,7 @@ static void bond_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
if (iptb[i]) if (iptb[i])
fprintf(f, "%s", fprintf(f, "%s",
rt_addr_n2a(AF_INET, rt_addr_n2a(AF_INET,
RTA_PAYLOAD(iptb[i]),
RTA_DATA(iptb[i]), RTA_DATA(iptb[i]),
buf, buf,
INET_ADDRSTRLEN)); INET_ADDRSTRLEN));
@ -533,6 +564,25 @@ static void bond_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
ll_addr_n2a(p, ETH_ALEN, 0, b, sizeof(b))); ll_addr_n2a(p, ETH_ALEN, 0, b, sizeof(b)));
} }
} }
if (tb[IFLA_BOND_AD_ACTOR_SYS_PRIO]) {
fprintf(f, "ad_actor_sys_prio %u ",
rta_getattr_u16(tb[IFLA_BOND_AD_ACTOR_SYS_PRIO]));
}
if (tb[IFLA_BOND_AD_USER_PORT_KEY]) {
fprintf(f, "ad_user_port_key %u ",
rta_getattr_u16(tb[IFLA_BOND_AD_USER_PORT_KEY]));
}
if (tb[IFLA_BOND_AD_ACTOR_SYSTEM]) {
/* We assume the l2 address is an Ethernet MAC address */
SPRINT_BUF(b1);
fprintf(f, "ad_actor_system %s ",
ll_addr_n2a(RTA_DATA(tb[IFLA_BOND_AD_ACTOR_SYSTEM]),
RTA_PAYLOAD(tb[IFLA_BOND_AD_ACTOR_SYSTEM]),
1 /*ARPHDR_ETHER*/, b1, sizeof(b1)));
}
} }
static void bond_print_help(struct link_util *lu, int argc, char **argv, static void bond_print_help(struct link_util *lu, int argc, char **argv,

122
ip/iplink_geneve.c Normal file
View File

@ -0,0 +1,122 @@
/*
* iplink_geneve.c GENEVE device support
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Authors: John W. Linville <linville@tuxdriver.com>
*/
#include <stdio.h>
#include "utils.h"
#include "ip_common.h"
static void print_explain(FILE *f)
{
fprintf(f, "Usage: ... geneve id VNI remote ADDR\n");
fprintf(f, "\n");
fprintf(f, "Where: VNI := 0-16777215\n");
fprintf(f, " ADDR := IP_ADDRESS\n");
}
static void explain(void)
{
print_explain(stderr);
}
static int geneve_parse_opt(struct link_util *lu, int argc, char **argv,
struct nlmsghdr *n)
{
__u32 vni = 0;
int vni_set = 0;
__u32 daddr = 0;
struct in6_addr daddr6 = IN6ADDR_ANY_INIT;
while (argc > 0) {
if (!matches(*argv, "id") ||
!matches(*argv, "vni")) {
NEXT_ARG();
if (get_u32(&vni, *argv, 0) ||
vni >= 1u << 24)
invarg("invalid id", *argv);
vni_set = 1;
} else if (!matches(*argv, "remote")) {
NEXT_ARG();
if (!inet_get_addr(*argv, &daddr, &daddr6)) {
fprintf(stderr, "Invalid address \"%s\"\n", *argv);
return -1;
}
if (IN_MULTICAST(ntohl(daddr)))
invarg("invalid remote address", *argv);
} else if (matches(*argv, "help") == 0) {
explain();
return -1;
} else {
fprintf(stderr, "geneve: unknown command \"%s\"?\n", *argv);
explain();
return -1;
}
argc--, argv++;
}
if (!vni_set) {
fprintf(stderr, "geneve: missing virtual network identifier\n");
return -1;
}
if (!daddr) {
fprintf(stderr, "geneve: remove link partner not specified\n");
return -1;
}
if (memcmp(&daddr6, &in6addr_any, sizeof(daddr6)) != 0) {
fprintf(stderr, "geneve: remove link over IPv6 not supported\n");
return -1;
}
addattr32(n, 1024, IFLA_GENEVE_ID, vni);
if (daddr)
addattr_l(n, 1024, IFLA_GENEVE_REMOTE, &daddr, 4);
return 0;
}
static void geneve_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
{
__u32 vni;
char s1[1024];
if (!tb)
return;
if (!tb[IFLA_GENEVE_ID] ||
RTA_PAYLOAD(tb[IFLA_GENEVE_ID]) < sizeof(__u32))
return;
vni = rta_getattr_u32(tb[IFLA_GENEVE_ID]);
fprintf(f, "id %u ", vni);
if (tb[IFLA_GENEVE_REMOTE]) {
__be32 addr = rta_getattr_u32(tb[IFLA_GENEVE_REMOTE]);
if (addr)
fprintf(f, "remote %s ",
format_host(AF_INET, 4, &addr, s1, sizeof(s1)));
}
}
static void geneve_print_help(struct link_util *lu, int argc, char **argv,
FILE *f)
{
print_explain(f);
}
struct link_util geneve_link_util = {
.id = "geneve",
.maxattr = IFLA_GENEVE_MAX,
.parse_opt = geneve_parse_opt,
.print_opt = geneve_print_opt,
.print_help = geneve_print_help,
};

View File

@ -26,18 +26,36 @@
static void usage(void) __attribute__((noreturn)); static void usage(void) __attribute__((noreturn));
int prefix_banner; int prefix_banner;
int listen_all_nsid;
static void usage(void) static void usage(void)
{ {
fprintf(stderr, "Usage: ip monitor [ all | LISTofOBJECTS ] [ FILE ]" fprintf(stderr, "Usage: ip monitor [ all | LISTofOBJECTS ] [ FILE ] "
"[ label ] [dev DEVICE]\n"); "[ label ] [all-nsid] [dev DEVICE]\n");
fprintf(stderr, "LISTofOBJECTS := link | address | route | mroute | prefix |\n"); fprintf(stderr, "LISTofOBJECTS := link | address | route | mroute | prefix |\n");
fprintf(stderr, " neigh | netconf\n"); fprintf(stderr, " neigh | netconf | rule | nsid\n");
fprintf(stderr, "FILE := file FILENAME\n"); fprintf(stderr, "FILE := file FILENAME\n");
exit(-1); exit(-1);
} }
static void print_headers(FILE *fp, char *label, struct rtnl_ctrl_data *ctrl)
{
if (timestamp)
print_timestamp(fp);
if (listen_all_nsid) {
if (ctrl == NULL || ctrl->nsid < 0)
fprintf(fp, "[nsid current]");
else
fprintf(fp, "[nsid %d]", ctrl->nsid);
}
if (prefix_banner)
fprintf(fp, "%s", label);
}
static int accept_msg(const struct sockaddr_nl *who, static int accept_msg(const struct sockaddr_nl *who,
struct rtnl_ctrl_data *ctrl,
struct nlmsghdr *n, void *arg) struct nlmsghdr *n, void *arg)
{ {
FILE *fp = (FILE*)arg; FILE *fp = (FILE*)arg;
@ -54,42 +72,31 @@ static int accept_msg(const struct sockaddr_nl *who,
if (r->rtm_flags & RTM_F_CLONED) if (r->rtm_flags & RTM_F_CLONED)
return 0; return 0;
if (timestamp)
print_timestamp(fp);
if (r->rtm_family == RTNL_FAMILY_IPMR || if (r->rtm_family == RTNL_FAMILY_IPMR ||
r->rtm_family == RTNL_FAMILY_IP6MR) { r->rtm_family == RTNL_FAMILY_IP6MR) {
if (prefix_banner) print_headers(fp, "[MROUTE]", ctrl);
fprintf(fp, "[MROUTE]");
print_mroute(who, n, arg); print_mroute(who, n, arg);
return 0; return 0;
} else { } else {
if (prefix_banner) print_headers(fp, "[ROUTE]", ctrl);
fprintf(fp, "[ROUTE]");
print_route(who, n, arg); print_route(who, n, arg);
return 0; return 0;
} }
} }
if (timestamp)
print_timestamp(fp);
if (n->nlmsg_type == RTM_NEWLINK || n->nlmsg_type == RTM_DELLINK) { if (n->nlmsg_type == RTM_NEWLINK || n->nlmsg_type == RTM_DELLINK) {
ll_remember_index(who, n, NULL); ll_remember_index(who, n, NULL);
if (prefix_banner) print_headers(fp, "[LINK]", ctrl);
fprintf(fp, "[LINK]");
print_linkinfo(who, n, arg); print_linkinfo(who, n, arg);
return 0; return 0;
} }
if (n->nlmsg_type == RTM_NEWADDR || n->nlmsg_type == RTM_DELADDR) { if (n->nlmsg_type == RTM_NEWADDR || n->nlmsg_type == RTM_DELADDR) {
if (prefix_banner) print_headers(fp, "[ADDR]", ctrl);
fprintf(fp, "[ADDR]");
print_addrinfo(who, n, arg); print_addrinfo(who, n, arg);
return 0; return 0;
} }
if (n->nlmsg_type == RTM_NEWADDRLABEL || n->nlmsg_type == RTM_DELADDRLABEL) { if (n->nlmsg_type == RTM_NEWADDRLABEL || n->nlmsg_type == RTM_DELADDRLABEL) {
if (prefix_banner) print_headers(fp, "[ADDRLABEL]", ctrl);
fprintf(fp, "[ADDRLABEL]");
print_addrlabel(who, n, arg); print_addrlabel(who, n, arg);
return 0; return 0;
} }
@ -102,33 +109,34 @@ static int accept_msg(const struct sockaddr_nl *who,
return 0; return 0;
} }
if (prefix_banner) print_headers(fp, "[NEIGH]", ctrl);
fprintf(fp, "[NEIGH]");
print_neigh(who, n, arg); print_neigh(who, n, arg);
return 0; return 0;
} }
if (n->nlmsg_type == RTM_NEWPREFIX) { if (n->nlmsg_type == RTM_NEWPREFIX) {
if (prefix_banner) print_headers(fp, "[PREFIX]", ctrl);
fprintf(fp, "[PREFIX]");
print_prefix(who, n, arg); print_prefix(who, n, arg);
return 0; return 0;
} }
if (n->nlmsg_type == RTM_NEWRULE || n->nlmsg_type == RTM_DELRULE) { if (n->nlmsg_type == RTM_NEWRULE || n->nlmsg_type == RTM_DELRULE) {
if (prefix_banner) print_headers(fp, "[RULE]", ctrl);
fprintf(fp, "[RULE]");
print_rule(who, n, arg); print_rule(who, n, arg);
return 0; return 0;
} }
if (n->nlmsg_type == RTM_NEWNETCONF) { if (n->nlmsg_type == RTM_NEWNETCONF) {
if (prefix_banner) print_headers(fp, "[NETCONF]", ctrl);
fprintf(fp, "[NETCONF]"); print_netconf(who, ctrl, n, arg);
print_netconf(who, n, arg);
return 0; return 0;
} }
if (n->nlmsg_type == NLMSG_TSTAMP) { if (n->nlmsg_type == NLMSG_TSTAMP) {
print_nlmsg_timestamp(fp, n); print_nlmsg_timestamp(fp, n);
return 0; return 0;
} }
if (n->nlmsg_type == RTM_NEWNSID || n->nlmsg_type == RTM_DELNSID) {
print_headers(fp, "[NSID]", ctrl);
print_nsid(who, n, arg);
return 0;
}
if (n->nlmsg_type != NLMSG_ERROR && n->nlmsg_type != NLMSG_NOOP && if (n->nlmsg_type != NLMSG_ERROR && n->nlmsg_type != NLMSG_NOOP &&
n->nlmsg_type != NLMSG_DONE) { n->nlmsg_type != NLMSG_DONE) {
fprintf(fp, "Unknown message: type=0x%08x(%d) flags=0x%08x(%d)" fprintf(fp, "Unknown message: type=0x%08x(%d) flags=0x%08x(%d)"
@ -150,6 +158,8 @@ int do_ipmonitor(int argc, char **argv)
int lprefix=0; int lprefix=0;
int lneigh=0; int lneigh=0;
int lnetconf=0; int lnetconf=0;
int lrule=0;
int lnsid=0;
int ifindex=0; int ifindex=0;
groups |= nl_mgrp(RTNLGRP_LINK); groups |= nl_mgrp(RTNLGRP_LINK);
@ -157,12 +167,16 @@ int do_ipmonitor(int argc, char **argv)
groups |= nl_mgrp(RTNLGRP_IPV6_IFADDR); groups |= nl_mgrp(RTNLGRP_IPV6_IFADDR);
groups |= nl_mgrp(RTNLGRP_IPV4_ROUTE); groups |= nl_mgrp(RTNLGRP_IPV4_ROUTE);
groups |= nl_mgrp(RTNLGRP_IPV6_ROUTE); groups |= nl_mgrp(RTNLGRP_IPV6_ROUTE);
groups |= nl_mgrp(RTNLGRP_MPLS_ROUTE);
groups |= nl_mgrp(RTNLGRP_IPV4_MROUTE); groups |= nl_mgrp(RTNLGRP_IPV4_MROUTE);
groups |= nl_mgrp(RTNLGRP_IPV6_MROUTE); groups |= nl_mgrp(RTNLGRP_IPV6_MROUTE);
groups |= nl_mgrp(RTNLGRP_IPV6_PREFIX); groups |= nl_mgrp(RTNLGRP_IPV6_PREFIX);
groups |= nl_mgrp(RTNLGRP_NEIGH); groups |= nl_mgrp(RTNLGRP_NEIGH);
groups |= nl_mgrp(RTNLGRP_IPV4_NETCONF); groups |= nl_mgrp(RTNLGRP_IPV4_NETCONF);
groups |= nl_mgrp(RTNLGRP_IPV6_NETCONF); groups |= nl_mgrp(RTNLGRP_IPV6_NETCONF);
groups |= nl_mgrp(RTNLGRP_IPV4_RULE);
groups |= nl_mgrp(RTNLGRP_IPV6_RULE);
groups |= nl_mgrp(RTNLGRP_NSID);
rtnl_close(&rth); rtnl_close(&rth);
@ -172,6 +186,8 @@ int do_ipmonitor(int argc, char **argv)
file = *argv; file = *argv;
} else if (matches(*argv, "label") == 0) { } else if (matches(*argv, "label") == 0) {
prefix_banner = 1; prefix_banner = 1;
} else if (matches(*argv, "all-nsid") == 0) {
listen_all_nsid = 1;
} else if (matches(*argv, "link") == 0) { } else if (matches(*argv, "link") == 0) {
llink=1; llink=1;
groups = 0; groups = 0;
@ -193,6 +209,12 @@ int do_ipmonitor(int argc, char **argv)
} else if (matches(*argv, "netconf") == 0) { } else if (matches(*argv, "netconf") == 0) {
lnetconf = 1; lnetconf = 1;
groups = 0; groups = 0;
} else if (matches(*argv, "rule") == 0) {
lrule = 1;
groups = 0;
} else if (matches(*argv, "nsid") == 0) {
lnsid = 1;
groups = 0;
} else if (strcmp(*argv, "all") == 0) { } else if (strcmp(*argv, "all") == 0) {
prefix_banner=1; prefix_banner=1;
} else if (matches(*argv, "help") == 0) { } else if (matches(*argv, "help") == 0) {
@ -229,6 +251,8 @@ int do_ipmonitor(int argc, char **argv)
groups |= nl_mgrp(RTNLGRP_IPV4_ROUTE); groups |= nl_mgrp(RTNLGRP_IPV4_ROUTE);
if (!preferred_family || preferred_family == AF_INET6) if (!preferred_family || preferred_family == AF_INET6)
groups |= nl_mgrp(RTNLGRP_IPV6_ROUTE); groups |= nl_mgrp(RTNLGRP_IPV6_ROUTE);
if (!preferred_family || preferred_family == AF_MPLS)
groups |= nl_mgrp(RTNLGRP_MPLS_ROUTE);
} }
if (lmroute) { if (lmroute) {
if (!preferred_family || preferred_family == AF_INET) if (!preferred_family || preferred_family == AF_INET)
@ -249,6 +273,15 @@ int do_ipmonitor(int argc, char **argv)
if (!preferred_family || preferred_family == AF_INET6) if (!preferred_family || preferred_family == AF_INET6)
groups |= nl_mgrp(RTNLGRP_IPV6_NETCONF); groups |= nl_mgrp(RTNLGRP_IPV6_NETCONF);
} }
if (lrule) {
if (!preferred_family || preferred_family == AF_INET)
groups |= nl_mgrp(RTNLGRP_IPV4_RULE);
if (!preferred_family || preferred_family == AF_INET6)
groups |= nl_mgrp(RTNLGRP_IPV6_RULE);
}
if (lnsid) {
groups |= nl_mgrp(RTNLGRP_NSID);
}
if (file) { if (file) {
FILE *fp; FILE *fp;
fp = fopen(file, "r"); fp = fopen(file, "r");
@ -261,7 +294,11 @@ int do_ipmonitor(int argc, char **argv)
if (rtnl_open(&rth, groups) < 0) if (rtnl_open(&rth, groups) < 0)
exit(1); exit(1);
if (listen_all_nsid && rtnl_listen_all_nsid(&rth) < 0)
exit(1);
ll_init_map(&rth); ll_init_map(&rth);
netns_map_init();
if (rtnl_listen(&rth, accept_msg, stdout) < 0) if (rtnl_listen(&rth, accept_msg, stdout) < 0)
exit(2); exit(2);

View File

@ -67,8 +67,7 @@ int print_mroute(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
int family; int family;
if ((n->nlmsg_type != RTM_NEWROUTE && if ((n->nlmsg_type != RTM_NEWROUTE &&
n->nlmsg_type != RTM_DELROUTE) || n->nlmsg_type != RTM_DELROUTE)) {
!(n->nlmsg_flags & NLM_F_MULTI)) {
fprintf(stderr, "Not a multicast route: %08x %08x %08x\n", fprintf(stderr, "Not a multicast route: %08x %08x %08x\n",
n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
return 0; return 0;
@ -116,6 +115,7 @@ int print_mroute(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
if (tb[RTA_SRC]) if (tb[RTA_SRC])
len = snprintf(obuf, sizeof(obuf), len = snprintf(obuf, sizeof(obuf),
"(%s, ", rt_addr_n2a(family, "(%s, ", rt_addr_n2a(family,
RTA_PAYLOAD(tb[RTA_SRC]),
RTA_DATA(tb[RTA_SRC]), RTA_DATA(tb[RTA_SRC]),
abuf, sizeof(abuf))); abuf, sizeof(abuf)));
else else
@ -123,6 +123,7 @@ int print_mroute(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
if (tb[RTA_DST]) if (tb[RTA_DST])
snprintf(obuf + len, sizeof(obuf) - len, snprintf(obuf + len, sizeof(obuf) - len,
"%s)", rt_addr_n2a(family, "%s)", rt_addr_n2a(family,
RTA_PAYLOAD(tb[RTA_DST]),
RTA_DATA(tb[RTA_DST]), RTA_DATA(tb[RTA_DST]),
abuf, sizeof(abuf))); abuf, sizeof(abuf)));
else else

View File

@ -179,7 +179,7 @@ static int ipneigh_modify(int cmd, int flags, int argc, char **argv)
return -1; return -1;
} }
if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
exit(2); exit(2);
return 0; return 0;

View File

@ -40,7 +40,8 @@ static void usage(void)
#define NETCONF_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct netconfmsg)))) #define NETCONF_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct netconfmsg))))
int print_netconf(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) int print_netconf(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl,
struct nlmsghdr *n, void *arg)
{ {
FILE *fp = (FILE*)arg; FILE *fp = (FILE*)arg;
struct netconfmsg *ncm = NLMSG_DATA(n); struct netconfmsg *ncm = NLMSG_DATA(n);
@ -123,6 +124,12 @@ int print_netconf(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
return 0; return 0;
} }
static int print_netconf2(const struct sockaddr_nl *who,
struct nlmsghdr *n, void *arg)
{
return print_netconf(who, NULL, n, arg);
}
void ipnetconf_reset_filter(int ifindex) void ipnetconf_reset_filter(int ifindex)
{ {
memset(&filter, 0, sizeof(filter)); memset(&filter, 0, sizeof(filter));
@ -177,7 +184,7 @@ dump:
perror("Cannot send dump request"); perror("Cannot send dump request");
exit(1); exit(1);
} }
if (rtnl_dump_filter(&rth, print_netconf, stdout) < 0) { if (rtnl_dump_filter(&rth, print_netconf2, stdout) < 0) {
fprintf(stderr, "Dump terminated\n"); fprintf(stderr, "Dump terminated\n");
exit(1); exit(1);
} }

View File

@ -14,8 +14,12 @@
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
#include <ctype.h> #include <ctype.h>
#include <linux/limits.h>
#include <linux/net_namespace.h>
#include "utils.h" #include "utils.h"
#include "hlist.h"
#include "ip_common.h" #include "ip_common.h"
#include "namespace.h" #include "namespace.h"
@ -23,18 +27,310 @@ static int usage(void)
{ {
fprintf(stderr, "Usage: ip netns list\n"); fprintf(stderr, "Usage: ip netns list\n");
fprintf(stderr, " ip netns add NAME\n"); fprintf(stderr, " ip netns add NAME\n");
fprintf(stderr, " ip netns set NAME NETNSID\n");
fprintf(stderr, " ip [-all] netns delete [NAME]\n"); fprintf(stderr, " ip [-all] netns delete [NAME]\n");
fprintf(stderr, " ip netns identify [PID]\n"); fprintf(stderr, " ip netns identify [PID]\n");
fprintf(stderr, " ip netns pids NAME\n"); fprintf(stderr, " ip netns pids NAME\n");
fprintf(stderr, " ip [-all] netns exec [NAME] cmd ...\n"); fprintf(stderr, " ip [-all] netns exec [NAME] cmd ...\n");
fprintf(stderr, " ip netns monitor\n"); fprintf(stderr, " ip netns monitor\n");
fprintf(stderr, " ip netns list-id\n");
exit(-1); exit(-1);
} }
/* This socket is used to get nsid */
static struct rtnl_handle rtnsh = { .fd = -1 };
static int have_rtnl_getnsid = -1;
static int ipnetns_accept_msg(const struct sockaddr_nl *who,
struct rtnl_ctrl_data *ctrl,
struct nlmsghdr *n, void *arg)
{
struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
if (n->nlmsg_type == NLMSG_ERROR &&
(err->error == -EOPNOTSUPP || err->error == -EINVAL))
have_rtnl_getnsid = 0;
else
have_rtnl_getnsid = 1;
return -1;
}
static int ipnetns_have_nsid(void)
{
struct {
struct nlmsghdr n;
struct rtgenmsg g;
char buf[1024];
} req;
int fd;
if (have_rtnl_getnsid < 0) {
memset(&req, 0, sizeof(req));
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
req.n.nlmsg_flags = NLM_F_REQUEST;
req.n.nlmsg_type = RTM_GETNSID;
req.g.rtgen_family = AF_UNSPEC;
fd = open("/proc/self/ns/net", O_RDONLY);
if (fd < 0) {
perror("open(\"/proc/self/ns/net\")");
exit(1);
}
addattr32(&req.n, 1024, NETNSA_FD, fd);
if (rtnl_send(&rth, &req.n, req.n.nlmsg_len) < 0) {
perror("request send failed");
exit(1);
}
rtnl_listen(&rth, ipnetns_accept_msg, NULL);
close(fd);
}
return have_rtnl_getnsid;
}
static int get_netnsid_from_name(const char *name)
{
struct {
struct nlmsghdr n;
struct rtgenmsg g;
char buf[1024];
} req, answer;
struct rtattr *tb[NETNSA_MAX + 1];
struct rtgenmsg *rthdr;
int len, fd;
memset(&req, 0, sizeof(req));
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
req.n.nlmsg_flags = NLM_F_REQUEST;
req.n.nlmsg_type = RTM_GETNSID;
req.g.rtgen_family = AF_UNSPEC;
fd = netns_get_fd(name);
if (fd < 0)
return fd;
addattr32(&req.n, 1024, NETNSA_FD, fd);
if (rtnl_talk(&rtnsh, &req.n, &answer.n, sizeof(answer)) < 0) {
close(fd);
return -2;
}
close(fd);
/* Validate message and parse attributes */
if (answer.n.nlmsg_type == NLMSG_ERROR)
return -1;
rthdr = NLMSG_DATA(&answer.n);
len = answer.n.nlmsg_len - NLMSG_SPACE(sizeof(*rthdr));
if (len < 0)
return -1;
parse_rtattr(tb, NETNSA_MAX, NETNS_RTA(rthdr), len);
if (tb[NETNSA_NSID])
return rta_getattr_u32(tb[NETNSA_NSID]);
return -1;
}
struct nsid_cache {
struct hlist_node nsid_hash;
struct hlist_node name_hash;
int nsid;
char name[NAME_MAX];
};
#define NSIDMAP_SIZE 128
#define NSID_HASH_NSID(nsid) (nsid & (NSIDMAP_SIZE - 1))
#define NSID_HASH_NAME(name) (namehash(name) & (NSIDMAP_SIZE - 1))
static struct hlist_head nsid_head[NSIDMAP_SIZE];
static struct hlist_head name_head[NSIDMAP_SIZE];
static struct nsid_cache *netns_map_get_by_nsid(int nsid)
{
uint32_t h = NSID_HASH_NSID(nsid);
struct hlist_node *n;
hlist_for_each(n, &nsid_head[h]) {
struct nsid_cache *c = container_of(n, struct nsid_cache,
nsid_hash);
if (c->nsid == nsid)
return c;
}
return NULL;
}
static int netns_map_add(int nsid, char *name)
{
struct nsid_cache *c;
uint32_t h;
if (netns_map_get_by_nsid(nsid) != NULL)
return -EEXIST;
c = malloc(sizeof(*c));
if (c == NULL) {
perror("malloc");
return -ENOMEM;
}
c->nsid = nsid;
strcpy(c->name, name);
h = NSID_HASH_NSID(nsid);
hlist_add_head(&c->nsid_hash, &nsid_head[h]);
h = NSID_HASH_NAME(name);
hlist_add_head(&c->name_hash, &name_head[h]);
return 0;
}
static void netns_map_del(struct nsid_cache *c)
{
hlist_del(&c->name_hash);
hlist_del(&c->nsid_hash);
free(c);
}
void netns_map_init(void)
{
static int initialized;
struct dirent *entry;
DIR *dir;
int nsid;
if (initialized || !ipnetns_have_nsid())
return;
if (rtnl_open(&rtnsh, 0) < 0) {
fprintf(stderr, "Cannot open rtnetlink\n");
exit(1);
}
dir = opendir(NETNS_RUN_DIR);
if (!dir)
return;
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0)
continue;
if (strcmp(entry->d_name, "..") == 0)
continue;
nsid = get_netnsid_from_name(entry->d_name);
if (nsid >= 0)
netns_map_add(nsid, entry->d_name);
}
closedir(dir);
initialized = 1;
}
static int netns_get_name(int nsid, char *name)
{
struct dirent *entry;
DIR *dir;
int id;
dir = opendir(NETNS_RUN_DIR);
if (!dir)
return -ENOENT;
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0)
continue;
if (strcmp(entry->d_name, "..") == 0)
continue;
id = get_netnsid_from_name(entry->d_name);
if (nsid == id) {
strcpy(name, entry->d_name);
closedir(dir);
return 0;
}
}
closedir(dir);
return -ENOENT;
}
int print_nsid(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
{
struct rtgenmsg *rthdr = NLMSG_DATA(n);
struct rtattr *tb[NETNSA_MAX+1];
int len = n->nlmsg_len;
FILE *fp = (FILE *)arg;
struct nsid_cache *c;
char name[NAME_MAX];
int nsid;
if (n->nlmsg_type != RTM_NEWNSID && n->nlmsg_type != RTM_DELNSID)
return 0;
len -= NLMSG_SPACE(sizeof(*rthdr));
if (len < 0) {
fprintf(stderr, "BUG: wrong nlmsg len %d in %s\n", len,
__func__);
return -1;
}
parse_rtattr(tb, NETNSA_MAX, NETNS_RTA(rthdr), len);
if (tb[NETNSA_NSID] == NULL) {
fprintf(stderr, "BUG: NETNSA_NSID is missing %s\n", __func__);
return -1;
}
if (n->nlmsg_type == RTM_DELNSID)
fprintf(fp, "Deleted ");
nsid = rta_getattr_u32(tb[NETNSA_NSID]);
fprintf(fp, "nsid %u ", nsid);
c = netns_map_get_by_nsid(nsid);
if (c != NULL) {
fprintf(fp, "(iproute2 netns name: %s)", c->name);
netns_map_del(c);
}
/* During 'ip monitor nsid', no chance to have new nsid in cache. */
if (c == NULL && n->nlmsg_type == RTM_NEWNSID)
if (netns_get_name(nsid, name) == 0) {
fprintf(fp, "(iproute2 netns name: %s)", name);
netns_map_add(nsid, name);
}
fprintf(fp, "\n");
fflush(fp);
return 0;
}
static int netns_list_id(int argc, char **argv)
{
if (!ipnetns_have_nsid()) {
fprintf(stderr,
"RTM_GETNSID is not supported by the kernel.\n");
return -ENOTSUP;
}
if (rtnl_wilddump_request(&rth, AF_UNSPEC, RTM_GETNSID) < 0) {
perror("Cannot send dump request");
exit(1);
}
if (rtnl_dump_filter(&rth, print_nsid, stdout) < 0) {
fprintf(stderr, "Dump terminated\n");
exit(1);
}
return 0;
}
static int netns_list(int argc, char **argv) static int netns_list(int argc, char **argv)
{ {
struct dirent *entry; struct dirent *entry;
DIR *dir; DIR *dir;
int id;
dir = opendir(NETNS_RUN_DIR); dir = opendir(NETNS_RUN_DIR);
if (!dir) if (!dir)
@ -45,7 +341,13 @@ static int netns_list(int argc, char **argv)
continue; continue;
if (strcmp(entry->d_name, "..") == 0) if (strcmp(entry->d_name, "..") == 0)
continue; continue;
printf("%s\n", entry->d_name); printf("%s", entry->d_name);
if (ipnetns_have_nsid()) {
id = get_netnsid_from_name(entry->d_name);
if (id >= 0)
printf(" (id: %d)", id);
}
printf("\n");
} }
closedir(dir); closedir(dir);
return 0; return 0;
@ -375,6 +677,61 @@ out_delete:
return -1; return -1;
} }
static int set_netnsid_from_name(const char *name, int nsid)
{
struct {
struct nlmsghdr n;
struct rtgenmsg g;
char buf[1024];
} req;
int fd, err = 0;
memset(&req, 0, sizeof(req));
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
req.n.nlmsg_flags = NLM_F_REQUEST;
req.n.nlmsg_type = RTM_NEWNSID;
req.g.rtgen_family = AF_UNSPEC;
fd = netns_get_fd(name);
if (fd < 0)
return fd;
addattr32(&req.n, 1024, NETNSA_FD, fd);
addattr32(&req.n, 1024, NETNSA_NSID, nsid);
if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
err = -2;
close(fd);
return err;
}
static int netns_set(int argc, char **argv)
{
char netns_path[MAXPATHLEN];
const char *name;
int netns, nsid;
if (argc < 1) {
fprintf(stderr, "No netns name specified\n");
return -1;
}
if (argc < 2) {
fprintf(stderr, "No nsid specified\n");
return -1;
}
name = argv[0];
nsid = atoi(argv[1]);
snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
netns = open(netns_path, O_RDONLY | O_CLOEXEC);
if (netns < 0) {
fprintf(stderr, "Cannot open network namespace \"%s\": %s\n",
name, strerror(errno));
return -1;
}
return set_netnsid_from_name(name, nsid);
}
static int netns_monitor(int argc, char **argv) static int netns_monitor(int argc, char **argv)
{ {
@ -417,6 +774,8 @@ static int netns_monitor(int argc, char **argv)
int do_netns(int argc, char **argv) int do_netns(int argc, char **argv)
{ {
netns_map_init();
if (argc < 1) if (argc < 1)
return netns_list(0, NULL); return netns_list(0, NULL);
@ -424,12 +783,18 @@ int do_netns(int argc, char **argv)
(matches(*argv, "lst") == 0)) (matches(*argv, "lst") == 0))
return netns_list(argc-1, argv+1); return netns_list(argc-1, argv+1);
if ((matches(*argv, "list-id") == 0))
return netns_list_id(argc-1, argv+1);
if (matches(*argv, "help") == 0) if (matches(*argv, "help") == 0)
return usage(); return usage();
if (matches(*argv, "add") == 0) if (matches(*argv, "add") == 0)
return netns_add(argc-1, argv+1); return netns_add(argc-1, argv+1);
if (matches(*argv, "set") == 0)
return netns_set(argc-1, argv+1);
if (matches(*argv, "delete") == 0) if (matches(*argv, "delete") == 0)
return netns_delete(argc-1, argv+1); return netns_delete(argc-1, argv+1);

View File

@ -313,7 +313,7 @@ static int ipntable_modify(int cmd, int flags, int argc, char **argv)
RTA_PAYLOAD(parms_rta)); RTA_PAYLOAD(parms_rta));
} }
if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
exit(2); exit(2);
return 0; return 0;

View File

@ -80,7 +80,9 @@ int print_prefix(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
pfx = (struct in6_addr *)RTA_DATA(tb[PREFIX_ADDRESS]); pfx = (struct in6_addr *)RTA_DATA(tb[PREFIX_ADDRESS]);
memset(abuf, '\0', sizeof(abuf)); memset(abuf, '\0', sizeof(abuf));
fprintf(fp, "%s", rt_addr_n2a(family, pfx, fprintf(fp, "%s", rt_addr_n2a(family,
RTA_PAYLOAD(tb[PREFIX_ADDRESS]),
pfx,
abuf, sizeof(abuf))); abuf, sizeof(abuf)));
} }
fprintf(fp, "/%u ", prefix->prefix_len); fprintf(fp, "/%u ", prefix->prefix_len);

View File

@ -23,6 +23,7 @@
#include <netinet/ip.h> #include <netinet/ip.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <linux/in_route.h> #include <linux/in_route.h>
#include <linux/icmpv6.h>
#include <errno.h> #include <errno.h>
#include "rt_names.h" #include "rt_names.h"
@ -75,19 +76,22 @@ static void usage(void)
fprintf(stderr, " [ table TABLE_ID ] [ proto RTPROTO ]\n"); fprintf(stderr, " [ table TABLE_ID ] [ proto RTPROTO ]\n");
fprintf(stderr, " [ scope SCOPE ] [ metric METRIC ]\n"); fprintf(stderr, " [ scope SCOPE ] [ metric METRIC ]\n");
fprintf(stderr, "INFO_SPEC := NH OPTIONS FLAGS [ nexthop NH ]...\n"); fprintf(stderr, "INFO_SPEC := NH OPTIONS FLAGS [ nexthop NH ]...\n");
fprintf(stderr, "NH := [ via ADDRESS ] [ dev STRING ] [ weight NUMBER ] NHFLAGS\n"); fprintf(stderr, "NH := [ via [ FAMILY ] ADDRESS ] [ dev STRING ] [ weight NUMBER ] NHFLAGS\n");
fprintf(stderr, "OPTIONS := FLAGS [ mtu NUMBER ] [ advmss NUMBER ]\n"); fprintf(stderr, "FAMILY := [ inet | inet6 | ipx | dnet | mpls | bridge | link ]\n");
fprintf(stderr, "OPTIONS := FLAGS [ mtu NUMBER ] [ advmss NUMBER ] [ as [ to ] ADDRESS ]\n");
fprintf(stderr, " [ rtt TIME ] [ rttvar TIME ] [ reordering NUMBER ]\n"); fprintf(stderr, " [ rtt TIME ] [ rttvar TIME ] [ reordering NUMBER ]\n");
fprintf(stderr, " [ window NUMBER] [ cwnd NUMBER ] [ initcwnd NUMBER ]\n"); fprintf(stderr, " [ window NUMBER] [ cwnd NUMBER ] [ initcwnd NUMBER ]\n");
fprintf(stderr, " [ ssthresh NUMBER ] [ realms REALM ] [ src ADDRESS ]\n"); fprintf(stderr, " [ ssthresh NUMBER ] [ realms REALM ] [ src ADDRESS ]\n");
fprintf(stderr, " [ rto_min TIME ] [ hoplimit NUMBER ] [ initrwnd NUMBER ]\n"); fprintf(stderr, " [ rto_min TIME ] [ hoplimit NUMBER ] [ initrwnd NUMBER ]\n");
fprintf(stderr, " [ features FEATURES ] [ quickack BOOL ] [ congctl NAME ]\n"); fprintf(stderr, " [ features FEATURES ] [ quickack BOOL ] [ congctl NAME ]\n");
fprintf(stderr, " [ pref PREF ]\n");
fprintf(stderr, "TYPE := [ unicast | local | broadcast | multicast | throw |\n"); fprintf(stderr, "TYPE := [ unicast | local | broadcast | multicast | throw |\n");
fprintf(stderr, " unreachable | prohibit | blackhole | nat ]\n"); fprintf(stderr, " unreachable | prohibit | blackhole | nat ]\n");
fprintf(stderr, "TABLE_ID := [ local | main | default | all | NUMBER ]\n"); fprintf(stderr, "TABLE_ID := [ local | main | default | all | NUMBER ]\n");
fprintf(stderr, "SCOPE := [ host | link | global | NUMBER ]\n"); fprintf(stderr, "SCOPE := [ host | link | global | NUMBER ]\n");
fprintf(stderr, "NHFLAGS := [ onlink | pervasive ]\n"); fprintf(stderr, "NHFLAGS := [ onlink | pervasive ]\n");
fprintf(stderr, "RTPROTO := [ kernel | boot | static | NUMBER ]\n"); fprintf(stderr, "RTPROTO := [ kernel | boot | static | NUMBER ]\n");
fprintf(stderr, "PREF := [ low | medium | high ]\n");
fprintf(stderr, "TIME := NUMBER[s|ms]\n"); fprintf(stderr, "TIME := NUMBER[s|ms]\n");
fprintf(stderr, "BOOL := [1|0]\n"); fprintf(stderr, "BOOL := [1|0]\n");
fprintf(stderr, "FEATURES := ecn\n"); fprintf(stderr, "FEATURES := ecn\n");
@ -185,8 +189,15 @@ static int filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
(r->rtm_family != filter.msrc.family || (r->rtm_family != filter.msrc.family ||
(filter.msrc.bitlen >= 0 && filter.msrc.bitlen < r->rtm_src_len))) (filter.msrc.bitlen >= 0 && filter.msrc.bitlen < r->rtm_src_len)))
return 0; return 0;
if (filter.rvia.family && r->rtm_family != filter.rvia.family) if (filter.rvia.family) {
return 0; int family = r->rtm_family;
if (tb[RTA_VIA]) {
struct rtvia *via = RTA_DATA(tb[RTA_VIA]);
family = via->rtvia_family;
}
if (family != filter.rvia.family)
return 0;
}
if (filter.rprefsrc.family && r->rtm_family != filter.rprefsrc.family) if (filter.rprefsrc.family && r->rtm_family != filter.rprefsrc.family)
return 0; return 0;
@ -205,6 +216,12 @@ static int filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
via.family = r->rtm_family; via.family = r->rtm_family;
if (tb[RTA_GATEWAY]) if (tb[RTA_GATEWAY])
memcpy(&via.data, RTA_DATA(tb[RTA_GATEWAY]), host_len/8); memcpy(&via.data, RTA_DATA(tb[RTA_GATEWAY]), host_len/8);
if (tb[RTA_VIA]) {
size_t len = RTA_PAYLOAD(tb[RTA_VIA]) - 2;
struct rtvia *rtvia = RTA_DATA(tb[RTA_VIA]);
via.family = rtvia->rtvia_family;
memcpy(&via.data, rtvia->rtvia_addr, len);
}
} }
if (filter.rprefsrc.bitlen>0) { if (filter.rprefsrc.bitlen>0) {
memset(&prefsrc, 0, sizeof(prefsrc)); memset(&prefsrc, 0, sizeof(prefsrc));
@ -268,20 +285,6 @@ static int filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
return 1; return 1;
} }
static int calc_host_len(const struct rtmsg *r)
{
if (r->rtm_family == AF_INET6)
return 128;
else if (r->rtm_family == AF_INET)
return 32;
else if (r->rtm_family == AF_DECnet)
return 16;
else if (r->rtm_family == AF_IPX)
return 80;
else
return -1;
}
static void print_rtax_features(FILE *fp, unsigned int features) static void print_rtax_features(FILE *fp, unsigned int features)
{ {
unsigned int of = features; unsigned int of = features;
@ -302,7 +305,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
int len = n->nlmsg_len; int len = n->nlmsg_len;
struct rtattr * tb[RTA_MAX+1]; struct rtattr * tb[RTA_MAX+1];
char abuf[256]; char abuf[256];
int host_len = -1; int host_len;
__u32 table; __u32 table;
SPRINT_BUF(b1); SPRINT_BUF(b1);
static int hz; static int hz;
@ -320,7 +323,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
return -1; return -1;
} }
host_len = calc_host_len(r); host_len = af_bit_len(r->rtm_family);
parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
table = rtm_get_table(r, tb); table = rtm_get_table(r, tb);
@ -353,8 +356,9 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
if (tb[RTA_DST]) { if (tb[RTA_DST]) {
if (r->rtm_dst_len != host_len) { if (r->rtm_dst_len != host_len) {
fprintf(fp, "%s/%u ", rt_addr_n2a(r->rtm_family, fprintf(fp, "%s/%u ", rt_addr_n2a(r->rtm_family,
RTA_DATA(tb[RTA_DST]), RTA_PAYLOAD(tb[RTA_DST]),
abuf, sizeof(abuf)), RTA_DATA(tb[RTA_DST]),
abuf, sizeof(abuf)),
r->rtm_dst_len r->rtm_dst_len
); );
} else { } else {
@ -372,8 +376,9 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
if (tb[RTA_SRC]) { if (tb[RTA_SRC]) {
if (r->rtm_src_len != host_len) { if (r->rtm_src_len != host_len) {
fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family, fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family,
RTA_DATA(tb[RTA_SRC]), RTA_PAYLOAD(tb[RTA_SRC]),
abuf, sizeof(abuf)), RTA_DATA(tb[RTA_SRC]),
abuf, sizeof(abuf)),
r->rtm_src_len r->rtm_src_len
); );
} else { } else {
@ -386,6 +391,13 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
} else if (r->rtm_src_len) { } else if (r->rtm_src_len) {
fprintf(fp, "from 0/%u ", r->rtm_src_len); fprintf(fp, "from 0/%u ", r->rtm_src_len);
} }
if (tb[RTA_NEWDST]) {
fprintf(fp, "as to %s ", format_host(r->rtm_family,
RTA_PAYLOAD(tb[RTA_NEWDST]),
RTA_DATA(tb[RTA_NEWDST]),
abuf, sizeof(abuf))
);
}
if (r->rtm_tos && filter.tosmask != -1) { if (r->rtm_tos && filter.tosmask != -1) {
SPRINT_BUF(b1); SPRINT_BUF(b1);
fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1))); fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1)));
@ -398,6 +410,14 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
RTA_DATA(tb[RTA_GATEWAY]), RTA_DATA(tb[RTA_GATEWAY]),
abuf, sizeof(abuf))); abuf, sizeof(abuf)));
} }
if (tb[RTA_VIA]) {
size_t len = RTA_PAYLOAD(tb[RTA_VIA]) - 2;
struct rtvia *via = RTA_DATA(tb[RTA_VIA]);
fprintf(fp, "via %s %s ",
family_name(via->rtvia_family),
format_host(via->rtvia_family, len, via->rtvia_addr,
abuf, sizeof(abuf)));
}
if (tb[RTA_OIF] && filter.oifmask != -1) if (tb[RTA_OIF] && filter.oifmask != -1)
fprintf(fp, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF]))); fprintf(fp, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF])));
@ -415,6 +435,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
*/ */
fprintf(fp, " src %s ", fprintf(fp, " src %s ",
rt_addr_n2a(r->rtm_family, rt_addr_n2a(r->rtm_family,
RTA_PAYLOAD(tb[RTA_PREFSRC]),
RTA_DATA(tb[RTA_PREFSRC]), RTA_DATA(tb[RTA_PREFSRC]),
abuf, sizeof(abuf))); abuf, sizeof(abuf)));
} }
@ -426,6 +447,8 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
fprintf(fp, "onlink "); fprintf(fp, "onlink ");
if (r->rtm_flags & RTNH_F_PERVASIVE) if (r->rtm_flags & RTNH_F_PERVASIVE)
fprintf(fp, "pervasive "); fprintf(fp, "pervasive ");
if (r->rtm_flags & RTNH_F_OFFLOAD)
fprintf(fp, "offload ");
if (r->rtm_flags & RTM_F_NOTIFY) if (r->rtm_flags & RTM_F_NOTIFY)
fprintf(fp, "notify "); fprintf(fp, "notify ");
if (tb[RTA_MARK]) { if (tb[RTA_MARK]) {
@ -612,6 +635,14 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
RTA_DATA(tb[RTA_GATEWAY]), RTA_DATA(tb[RTA_GATEWAY]),
abuf, sizeof(abuf))); abuf, sizeof(abuf)));
} }
if (tb[RTA_VIA]) {
size_t len = RTA_PAYLOAD(tb[RTA_VIA]) - 2;
struct rtvia *via = RTA_DATA(tb[RTA_VIA]);
fprintf(fp, "via %s %s ",
family_name(via->rtvia_family),
format_host(via->rtvia_family, len, via->rtvia_addr,
abuf, sizeof(abuf)));
}
if (tb[RTA_FLOW]) { if (tb[RTA_FLOW]) {
__u32 to = rta_getattr_u32(tb[RTA_FLOW]); __u32 to = rta_getattr_u32(tb[RTA_FLOW]);
__u32 from = to>>16; __u32 from = to>>16;
@ -643,6 +674,24 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
nh = RTNH_NEXT(nh); nh = RTNH_NEXT(nh);
} }
} }
if (tb[RTA_PREF]) {
unsigned int pref = rta_getattr_u8(tb[RTA_PREF]);
fprintf(fp, " pref ");
switch (pref) {
case ICMPV6_ROUTER_PREF_LOW:
fprintf(fp, "low");
break;
case ICMPV6_ROUTER_PREF_MEDIUM:
fprintf(fp, "medium");
break;
case ICMPV6_ROUTER_PREF_HIGH:
fprintf(fp, "high");
break;
default:
fprintf(fp, "%u", pref);
}
}
fprintf(fp, "\n"); fprintf(fp, "\n");
fflush(fp); fflush(fp);
return 0; return 0;
@ -659,12 +708,23 @@ static int parse_one_nh(struct rtmsg *r, struct rtattr *rta,
while (++argv, --argc > 0) { while (++argv, --argc > 0) {
if (strcmp(*argv, "via") == 0) { if (strcmp(*argv, "via") == 0) {
inet_prefix addr; inet_prefix addr;
int family;
NEXT_ARG(); NEXT_ARG();
get_addr(&addr, *argv, r->rtm_family); family = read_family(*argv);
if (family == AF_UNSPEC)
family = r->rtm_family;
else
NEXT_ARG();
get_addr(&addr, *argv, family);
if (r->rtm_family == AF_UNSPEC) if (r->rtm_family == AF_UNSPEC)
r->rtm_family = addr.family; r->rtm_family = addr.family;
rta_addattr_l(rta, 4096, RTA_GATEWAY, &addr.data, addr.bytelen); if (addr.family == r->rtm_family) {
rtnh->rtnh_len += sizeof(struct rtattr) + addr.bytelen; rta_addattr_l(rta, 4096, RTA_GATEWAY, &addr.data, addr.bytelen);
rtnh->rtnh_len += sizeof(struct rtattr) + addr.bytelen;
} else {
rta_addattr_l(rta, 4096, RTA_VIA, &addr.family, addr.bytelen+2);
rtnh->rtnh_len += sizeof(struct rtattr) + addr.bytelen+2;
}
} else if (strcmp(*argv, "dev") == 0) { } else if (strcmp(*argv, "dev") == 0) {
NEXT_ARG(); NEXT_ARG();
if ((rtnh->rtnh_ifindex = ll_name_to_index(*argv)) == 0) { if ((rtnh->rtnh_ifindex = ll_name_to_index(*argv)) == 0) {
@ -770,14 +830,33 @@ static int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
if (req.r.rtm_family == AF_UNSPEC) if (req.r.rtm_family == AF_UNSPEC)
req.r.rtm_family = addr.family; req.r.rtm_family = addr.family;
addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &addr.data, addr.bytelen); addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &addr.data, addr.bytelen);
} else if (strcmp(*argv, "via") == 0) { } else if (strcmp(*argv, "as") == 0) {
inet_prefix addr; inet_prefix addr;
gw_ok = 1;
NEXT_ARG(); NEXT_ARG();
if (strcmp(*argv, "to") == 0) {
NEXT_ARG();
}
get_addr(&addr, *argv, req.r.rtm_family); get_addr(&addr, *argv, req.r.rtm_family);
if (req.r.rtm_family == AF_UNSPEC) if (req.r.rtm_family == AF_UNSPEC)
req.r.rtm_family = addr.family; req.r.rtm_family = addr.family;
addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &addr.data, addr.bytelen); addattr_l(&req.n, sizeof(req), RTA_NEWDST, &addr.data, addr.bytelen);
} else if (strcmp(*argv, "via") == 0) {
inet_prefix addr;
int family;
gw_ok = 1;
NEXT_ARG();
family = read_family(*argv);
if (family == AF_UNSPEC)
family = req.r.rtm_family;
else
NEXT_ARG();
get_addr(&addr, *argv, family);
if (req.r.rtm_family == AF_UNSPEC)
req.r.rtm_family = addr.family;
if (addr.family == req.r.rtm_family)
addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &addr.data, addr.bytelen);
else
addattr_l(&req.n, sizeof(req), RTA_VIA, &addr.family, addr.bytelen+2);
} else if (strcmp(*argv, "from") == 0) { } else if (strcmp(*argv, "from") == 0) {
inet_prefix addr; inet_prefix addr;
NEXT_ARG(); NEXT_ARG();
@ -796,7 +875,7 @@ static int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
req.r.rtm_tos = tos; req.r.rtm_tos = tos;
} else if (matches(*argv, "metric") == 0 || } else if (matches(*argv, "metric") == 0 ||
matches(*argv, "priority") == 0 || matches(*argv, "priority") == 0 ||
matches(*argv, "preference") == 0) { strcmp(*argv, "preference") == 0) {
__u32 metric; __u32 metric;
NEXT_ARG(); NEXT_ARG();
if (get_u32(&metric, *argv, 0)) if (get_u32(&metric, *argv, 0))
@ -993,6 +1072,18 @@ static int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
strcmp(*argv, "oif") == 0) { strcmp(*argv, "oif") == 0) {
NEXT_ARG(); NEXT_ARG();
d = *argv; d = *argv;
} else if (matches(*argv, "pref") == 0) {
__u8 pref;
NEXT_ARG();
if (strcmp(*argv, "low") == 0)
pref = ICMPV6_ROUTER_PREF_LOW;
else if (strcmp(*argv, "medium") == 0)
pref = ICMPV6_ROUTER_PREF_MEDIUM;
else if (strcmp(*argv, "high") == 0)
pref = ICMPV6_ROUTER_PREF_HIGH;
else if (get_u8(&pref, *argv, 0))
invarg("\"pref\" value is invalid\n", *argv);
addattr8(&req.n, sizeof(req), RTA_PREF, pref);
} else { } else {
int type; int type;
inet_prefix dst; inet_prefix dst;
@ -1072,8 +1163,8 @@ static int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
if (req.r.rtm_family == AF_UNSPEC) if (req.r.rtm_family == AF_UNSPEC)
req.r.rtm_family = AF_INET; req.r.rtm_family = AF_INET;
if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
exit(2); return -2;
return 0; return 0;
} }
@ -1134,9 +1225,9 @@ static int save_route(const struct sockaddr_nl *who, struct nlmsghdr *n,
int len = n->nlmsg_len; int len = n->nlmsg_len;
struct rtmsg *r = NLMSG_DATA(n); struct rtmsg *r = NLMSG_DATA(n);
struct rtattr *tb[RTA_MAX+1]; struct rtattr *tb[RTA_MAX+1];
int host_len = -1; int host_len;
host_len = calc_host_len(r); host_len = af_bit_len(r->rtm_family);
len -= NLMSG_LENGTH(sizeof(*r)); len -= NLMSG_LENGTH(sizeof(*r));
parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
@ -1262,8 +1353,14 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)
get_unsigned(&mark, *argv, 0); get_unsigned(&mark, *argv, 0);
filter.markmask = -1; filter.markmask = -1;
} else if (strcmp(*argv, "via") == 0) { } else if (strcmp(*argv, "via") == 0) {
int family;
NEXT_ARG(); NEXT_ARG();
get_prefix(&filter.rvia, *argv, do_ipv6); family = read_family(*argv);
if (family == AF_UNSPEC)
family = do_ipv6;
else
NEXT_ARG();
get_prefix(&filter.rvia, *argv, family);
} else if (strcmp(*argv, "src") == 0) { } else if (strcmp(*argv, "src") == 0) {
NEXT_ARG(); NEXT_ARG();
get_prefix(&filter.rprefsrc, *argv, do_ipv6); get_prefix(&filter.rprefsrc, *argv, do_ipv6);
@ -1529,7 +1626,7 @@ static int iproute_get(int argc, char **argv)
if (req.r.rtm_family == AF_UNSPEC) if (req.r.rtm_family == AF_UNSPEC)
req.r.rtm_family = AF_INET; req.r.rtm_family = AF_INET;
if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0) if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0)
exit(2); exit(2);
if (connected && !from_ok) { if (connected && !from_ok) {
@ -1565,12 +1662,14 @@ static int iproute_get(int argc, char **argv)
tb[RTA_OIF]->rta_type = 0; tb[RTA_OIF]->rta_type = 0;
if (tb[RTA_GATEWAY]) if (tb[RTA_GATEWAY])
tb[RTA_GATEWAY]->rta_type = 0; tb[RTA_GATEWAY]->rta_type = 0;
if (tb[RTA_VIA])
tb[RTA_VIA]->rta_type = 0;
if (!idev && tb[RTA_IIF]) if (!idev && tb[RTA_IIF])
tb[RTA_IIF]->rta_type = 0; tb[RTA_IIF]->rta_type = 0;
req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_flags = NLM_F_REQUEST;
req.n.nlmsg_type = RTM_GETROUTE; req.n.nlmsg_type = RTM_GETROUTE;
if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0) if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0)
exit(2); exit(2);
} }
@ -1582,8 +1681,9 @@ static int iproute_get(int argc, char **argv)
exit(0); exit(0);
} }
static int restore_handler(const struct sockaddr_nl *nl, struct nlmsghdr *n, static int restore_handler(const struct sockaddr_nl *nl,
void *arg) struct rtnl_ctrl_data *ctrl,
struct nlmsghdr *n, void *arg)
{ {
int ret; int ret;
@ -1591,7 +1691,7 @@ static int restore_handler(const struct sockaddr_nl *nl, struct nlmsghdr *n,
ll_init_map(&rth); ll_init_map(&rth);
ret = rtnl_talk(&rth, n, 0, 0, n); ret = rtnl_talk(&rth, n, n, sizeof(*n));
if ((ret < 0) && (errno == EEXIST)) if ((ret < 0) && (errno == EEXIST))
ret = 0; ret = 0;
@ -1625,7 +1725,9 @@ static int iproute_restore(void)
exit(rtnl_from_file(stdin, &restore_handler, NULL)); exit(rtnl_from_file(stdin, &restore_handler, NULL));
} }
static int show_handler(const struct sockaddr_nl *nl, struct nlmsghdr *n, void *arg) static int show_handler(const struct sockaddr_nl *nl,
struct rtnl_ctrl_data *ctrl,
struct nlmsghdr *n, void *arg)
{ {
print_route(nl, n, stdout); print_route(nl, n, stdout);
return 0; return 0;

View File

@ -66,14 +66,7 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
parse_rtattr(tb, FRA_MAX, RTM_RTA(r), len); parse_rtattr(tb, FRA_MAX, RTM_RTA(r), len);
if (r->rtm_family == AF_INET) host_len = af_bit_len(r->rtm_family);
host_len = 32;
else if (r->rtm_family == AF_INET6)
host_len = 128;
else if (r->rtm_family == AF_DECnet)
host_len = 16;
else if (r->rtm_family == AF_IPX)
host_len = 80;
if (n->nlmsg_type == RTM_DELRULE) if (n->nlmsg_type == RTM_DELRULE)
fprintf(fp, "Deleted "); fprintf(fp, "Deleted ");
@ -89,8 +82,9 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
if (tb[FRA_SRC]) { if (tb[FRA_SRC]) {
if (r->rtm_src_len != host_len) { if (r->rtm_src_len != host_len) {
fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family, fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family,
RTA_DATA(tb[FRA_SRC]), RTA_PAYLOAD(tb[FRA_SRC]),
abuf, sizeof(abuf)), RTA_DATA(tb[FRA_SRC]),
abuf, sizeof(abuf)),
r->rtm_src_len r->rtm_src_len
); );
} else { } else {
@ -109,8 +103,9 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
if (tb[FRA_DST]) { if (tb[FRA_DST]) {
if (r->rtm_dst_len != host_len) { if (r->rtm_dst_len != host_len) {
fprintf(fp, "to %s/%u ", rt_addr_n2a(r->rtm_family, fprintf(fp, "to %s/%u ", rt_addr_n2a(r->rtm_family,
RTA_DATA(tb[FRA_DST]), RTA_PAYLOAD(tb[FRA_DST]),
abuf, sizeof(abuf)), RTA_DATA(tb[FRA_DST]),
abuf, sizeof(abuf)),
r->rtm_dst_len r->rtm_dst_len
); );
} else { } else {
@ -385,8 +380,8 @@ static int iprule_modify(int cmd, int argc, char **argv)
if (!table_ok && cmd == RTM_NEWRULE) if (!table_ok && cmd == RTM_NEWRULE)
req.r.rtm_table = RT_TABLE_MAIN; req.r.rtm_table = RT_TABLE_MAIN;
if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
return 2; return -2;
return 0; return 0;
} }
@ -412,7 +407,7 @@ static int flush_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *a
if (rtnl_open(&rth2, 0) < 0) if (rtnl_open(&rth2, 0) < 0)
return -1; return -1;
if (rtnl_talk(&rth2, n, 0, 0, NULL) < 0) if (rtnl_talk(&rth2, n, NULL, 0) < 0)
return -2; return -2;
rtnl_close(&rth2); rtnl_close(&rth2);

View File

@ -182,7 +182,7 @@ static int iptoken_set(int argc, char **argv)
return -1; return -1;
} }
if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
return -2; return -2;
return 0; return 0;
@ -195,6 +195,7 @@ int do_iptoken(int argc, char **argv)
if (argc < 1) { if (argc < 1) {
return iptoken_list(0, NULL); return iptoken_list(0, NULL);
} else if (matches(argv[0], "list") == 0 || } else if (matches(argv[0], "list") == 0 ||
matches(argv[0], "lst") == 0 ||
matches(argv[0], "show") == 0) { matches(argv[0], "show") == 0) {
return iptoken_list(argc - 1, argv + 1); return iptoken_list(argc - 1, argv + 1);
} else if (matches(argv[0], "set") == 0 || } else if (matches(argv[0], "set") == 0 ||

View File

@ -342,8 +342,8 @@ static void print_tunnel(struct ip_tunnel_parm *p)
printf("%s: %s/ip remote %s local %s ", printf("%s: %s/ip remote %s local %s ",
p->name, p->name,
tnl_strproto(p->iph.protocol), tnl_strproto(p->iph.protocol),
p->iph.daddr ? format_host(AF_INET, 4, &p->iph.daddr, s1, sizeof(s1)) : "any", p->iph.daddr ? format_host(AF_INET, 4, &p->iph.daddr, s1, sizeof(s1)) : "any",
p->iph.saddr ? rt_addr_n2a(AF_INET, &p->iph.saddr, s2, sizeof(s2)) : "any"); p->iph.saddr ? rt_addr_n2a(AF_INET, 4, &p->iph.saddr, s2, sizeof(s2)) : "any");
if (p->iph.protocol == IPPROTO_IPV6 && (p->i_flags & SIT_ISATAP)) { if (p->iph.protocol == IPPROTO_IPV6 && (p->i_flags & SIT_ISATAP)) {
struct ip_tunnel_prl prl[16]; struct ip_tunnel_prl prl[16];

View File

@ -288,10 +288,10 @@ void xfrm_id_info_print(xfrm_address_t *saddr, struct xfrm_id *id,
fputs(title, fp); fputs(title, fp);
memset(abuf, '\0', sizeof(abuf)); memset(abuf, '\0', sizeof(abuf));
fprintf(fp, "src %s ", rt_addr_n2a(family, fprintf(fp, "src %s ", rt_addr_n2a(family, sizeof(*saddr),
saddr, abuf, sizeof(abuf))); saddr, abuf, sizeof(abuf)));
memset(abuf, '\0', sizeof(abuf)); memset(abuf, '\0', sizeof(abuf));
fprintf(fp, "dst %s", rt_addr_n2a(family, fprintf(fp, "dst %s", rt_addr_n2a(family, sizeof(id->daddr),
&id->daddr, abuf, sizeof(abuf))); &id->daddr, abuf, sizeof(abuf)));
fprintf(fp, "%s", _SL_); fprintf(fp, "%s", _SL_);
@ -455,11 +455,15 @@ void xfrm_selector_print(struct xfrm_selector *sel, __u16 family,
fputs(prefix, fp); fputs(prefix, fp);
memset(abuf, '\0', sizeof(abuf)); memset(abuf, '\0', sizeof(abuf));
fprintf(fp, "src %s/%u ", rt_addr_n2a(f, &sel->saddr, abuf, sizeof(abuf)), fprintf(fp, "src %s/%u ",
rt_addr_n2a(f, sizeof(sel->saddr), &sel->saddr,
abuf, sizeof(abuf)),
sel->prefixlen_s); sel->prefixlen_s);
memset(abuf, '\0', sizeof(abuf)); memset(abuf, '\0', sizeof(abuf));
fprintf(fp, "dst %s/%u ", rt_addr_n2a(f, &sel->daddr, abuf, sizeof(abuf)), fprintf(fp, "dst %s/%u ",
rt_addr_n2a(f, sizeof(sel->daddr), &sel->daddr,
abuf, sizeof(abuf)),
sel->prefixlen_d); sel->prefixlen_d);
if (sel->proto) if (sel->proto)
@ -689,7 +693,8 @@ void xfrm_xfrma_print(struct rtattr *tb[], __u16 family,
if (tb[XFRMA_MARK]) { if (tb[XFRMA_MARK]) {
struct rtattr *rta = tb[XFRMA_MARK]; struct rtattr *rta = tb[XFRMA_MARK];
struct xfrm_mark *m = (struct xfrm_mark *) RTA_DATA(rta); struct xfrm_mark *m = (struct xfrm_mark *) RTA_DATA(rta);
fprintf(fp, "\tmark %d/0x%x\n", m->v, m->m); fprintf(fp, "\tmark %#x/%#x", m->v, m->m);
fprintf(fp, "%s", _SL_);
} }
if (tb[XFRMA_ALG_AUTH] && !tb[XFRMA_ALG_AUTH_TRUNC]) { if (tb[XFRMA_ALG_AUTH] && !tb[XFRMA_ALG_AUTH_TRUNC]) {
@ -754,7 +759,8 @@ void xfrm_xfrma_print(struct rtattr *tb[], __u16 family,
memset(abuf, '\0', sizeof(abuf)); memset(abuf, '\0', sizeof(abuf));
fprintf(fp, "addr %s", fprintf(fp, "addr %s",
rt_addr_n2a(family, &e->encap_oa, abuf, sizeof(abuf))); rt_addr_n2a(family, sizeof(e->encap_oa), &e->encap_oa,
abuf, sizeof(abuf)));
fprintf(fp, "%s", _SL_); fprintf(fp, "%s", _SL_);
} }
@ -782,7 +788,7 @@ void xfrm_xfrma_print(struct rtattr *tb[], __u16 family,
memset(abuf, '\0', sizeof(abuf)); memset(abuf, '\0', sizeof(abuf));
fprintf(fp, "%s", fprintf(fp, "%s",
rt_addr_n2a(family, coa, rt_addr_n2a(family, sizeof(*coa), coa,
abuf, sizeof(abuf))); abuf, sizeof(abuf)));
fprintf(fp, "%s", _SL_); fprintf(fp, "%s", _SL_);
} }
@ -1338,6 +1344,7 @@ static int xfrm_selector_upspec_parse(struct xfrm_selector *sel,
case IPPROTO_UDP: case IPPROTO_UDP:
case IPPROTO_SCTP: case IPPROTO_SCTP:
case IPPROTO_DCCP: case IPPROTO_DCCP:
case IPPROTO_IP: /* to allow shared SA for different protocols */
break; break;
default: default:
fprintf(stderr, "\"sport\" and \"dport\" are invalid with PROTO value \"%s\"\n", strxf_proto(sel->proto)); fprintf(stderr, "\"sport\" and \"dport\" are invalid with PROTO value \"%s\"\n", strxf_proto(sel->proto));

View File

@ -53,7 +53,7 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
struct { struct {
struct nlmsghdr n; struct nlmsghdr n;
struct ifinfomsg i; struct ifinfomsg i;
char buf[1024]; char buf[16384];
} req; } req;
struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1); struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
struct rtattr *tb[IFLA_MAX + 1]; struct rtattr *tb[IFLA_MAX + 1];
@ -84,7 +84,7 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
req.i.ifi_family = preferred_family; req.i.ifi_family = preferred_family;
req.i.ifi_index = ifi->ifi_index; req.i.ifi_index = ifi->ifi_index;
if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0) { if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) {
get_failed: get_failed:
fprintf(stderr, fprintf(stderr,
"Failed to get existing tunnel info.\n"); "Failed to get existing tunnel info.\n");

View File

@ -91,7 +91,7 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
req.i.ifi_family = preferred_family; req.i.ifi_family = preferred_family;
req.i.ifi_index = ifi->ifi_index; req.i.ifi_index = ifi->ifi_index;
if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0) { if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) {
get_failed: get_failed:
fprintf(stderr, fprintf(stderr,
"Failed to get existing tunnel info.\n"); "Failed to get existing tunnel info.\n");

View File

@ -89,7 +89,7 @@ static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv,
req.i.ifi_family = preferred_family; req.i.ifi_family = preferred_family;
req.i.ifi_index = ifi->ifi_index; req.i.ifi_index = ifi->ifi_index;
if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0) { if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) {
get_failed: get_failed:
fprintf(stderr, fprintf(stderr,
"Failed to get existing tunnel info.\n"); "Failed to get existing tunnel info.\n");
@ -285,6 +285,7 @@ static void ip6tunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb
if (tb[IFLA_IPTUN_REMOTE]) { if (tb[IFLA_IPTUN_REMOTE]) {
fprintf(f, "remote %s ", fprintf(f, "remote %s ",
rt_addr_n2a(AF_INET6, rt_addr_n2a(AF_INET6,
RTA_PAYLOAD(tb[IFLA_IPTUN_REMOTE]),
RTA_DATA(tb[IFLA_IPTUN_REMOTE]), RTA_DATA(tb[IFLA_IPTUN_REMOTE]),
s1, sizeof(s1))); s1, sizeof(s1)));
} }
@ -292,6 +293,7 @@ static void ip6tunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb
if (tb[IFLA_IPTUN_LOCAL]) { if (tb[IFLA_IPTUN_LOCAL]) {
fprintf(f, "local %s ", fprintf(f, "local %s ",
rt_addr_n2a(AF_INET6, rt_addr_n2a(AF_INET6,
RTA_PAYLOAD(tb[IFLA_IPTUN_LOCAL]),
RTA_DATA(tb[IFLA_IPTUN_LOCAL]), RTA_DATA(tb[IFLA_IPTUN_LOCAL]),
s1, sizeof(s1))); s1, sizeof(s1)));
} }

View File

@ -91,7 +91,7 @@ static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv,
req.i.ifi_family = preferred_family; req.i.ifi_family = preferred_family;
req.i.ifi_index = ifi->ifi_index; req.i.ifi_index = ifi->ifi_index;
if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0) { if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) {
get_failed: get_failed:
fprintf(stderr, fprintf(stderr,
"Failed to get existing tunnel info.\n"); "Failed to get existing tunnel info.\n");

View File

@ -71,7 +71,7 @@ static int vti_parse_opt(struct link_util *lu, int argc, char **argv,
req.i.ifi_family = preferred_family; req.i.ifi_family = preferred_family;
req.i.ifi_index = ifi->ifi_index; req.i.ifi_index = ifi->ifi_index;
if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0) { if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) {
get_failed: get_failed:
fprintf(stderr, fprintf(stderr,
"Failed to get existing tunnel info.\n"); "Failed to get existing tunnel info.\n");

View File

@ -67,7 +67,7 @@ static int vti6_parse_opt(struct link_util *lu, int argc, char **argv,
req.i.ifi_family = preferred_family; req.i.ifi_family = preferred_family;
req.i.ifi_index = ifi->ifi_index; req.i.ifi_index = ifi->ifi_index;
if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0) { if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) {
get_failed: get_failed:
fprintf(stderr, fprintf(stderr,
"Failed to get existing tunnel info.\n"); "Failed to get existing tunnel info.\n");

View File

@ -45,8 +45,8 @@ static void write_stamp(FILE *fp)
fwrite((void*)n1, 1, NLMSG_ALIGN(n1->nlmsg_len), fp); fwrite((void*)n1, 1, NLMSG_ALIGN(n1->nlmsg_len), fp);
} }
static int dump_msg(const struct sockaddr_nl *who, struct nlmsghdr *n, static int dump_msg(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl,
void *arg) struct nlmsghdr *n, void *arg)
{ {
FILE *fp = (FILE*)arg; FILE *fp = (FILE*)arg;
if (!init_phase) if (!init_phase)
@ -56,6 +56,12 @@ static int dump_msg(const struct sockaddr_nl *who, struct nlmsghdr *n,
return 0; return 0;
} }
static int dump_msg2(const struct sockaddr_nl *who,
struct nlmsghdr *n, void *arg)
{
return dump_msg(who, NULL, n, arg);
}
static void usage(void) static void usage(void)
{ {
fprintf(stderr, "Usage: rtmon file FILE [ all | LISTofOBJECTS]\n"); fprintf(stderr, "Usage: rtmon file FILE [ all | LISTofOBJECTS]\n");
@ -163,7 +169,7 @@ main(int argc, char **argv)
write_stamp(fp); write_stamp(fp);
if (rtnl_dump_filter(&rth, dump_msg, fp) < 0) { if (rtnl_dump_filter(&rth, dump_msg2, fp) < 0) {
fprintf(stderr, "Dump terminated\n"); fprintf(stderr, "Dump terminated\n");
return 1; return 1;
} }

View File

@ -467,10 +467,10 @@ static int tcpm_do_cmd(int cmd, int argc, char **argv)
} }
if (ack) { if (ack) {
if (rtnl_talk(&grth, &req.n, 0, 0, NULL) < 0) if (rtnl_talk(&grth, &req.n, NULL, 0) < 0)
return -2; return -2;
} else if (atype >= 0) { } else if (atype >= 0) {
if (rtnl_talk(&grth, &req.n, 0, 0, &req.n) < 0) if (rtnl_talk(&grth, &req.n, &req.n, sizeof(req)) < 0)
return -2; return -2;
if (process_msg(NULL, &req.n, stdout) < 0) { if (process_msg(NULL, &req.n, stdout) < 0) {
fprintf(stderr, "Dump terminated\n"); fprintf(stderr, "Dump terminated\n");

View File

@ -27,16 +27,20 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <netinet/in.h>
#include <linux/xfrm.h> #include <linux/xfrm.h>
#include "utils.h" #include "utils.h"
#include "xfrm.h" #include "xfrm.h"
#include "ip_common.h" #include "ip_common.h"
static void usage(void) __attribute__((noreturn)); static void usage(void) __attribute__((noreturn));
int listen_all_nsid;
static void usage(void) static void usage(void)
{ {
fprintf(stderr, "Usage: ip xfrm monitor [ all | LISTofXFRM-OBJECTS ]\n"); fprintf(stderr, "Usage: ip xfrm monitor [all-nsid] [ all | OBJECTS | help ]\n");
fprintf(stderr, "OBJECTS := { acquire | expire | SA | aevent | policy | report }\n");
exit(-1); exit(-1);
} }
@ -226,7 +230,8 @@ static void xfrm_usersa_print(const struct xfrm_usersa_id *sa_id, __u32 reqid, F
buf[0] = 0; buf[0] = 0;
fprintf(fp, "dst %s ", fprintf(fp, "dst %s ",
rt_addr_n2a(sa_id->family, &sa_id->daddr, buf, sizeof(buf))); rt_addr_n2a(sa_id->family, sizeof(sa_id->daddr), &sa_id->daddr,
buf, sizeof(buf)));
fprintf(fp, " reqid 0x%x", reqid); fprintf(fp, " reqid 0x%x", reqid);
@ -245,7 +250,8 @@ static int xfrm_ae_print(const struct sockaddr_nl *who,
xfrm_ae_flags_print(id->flags, arg); xfrm_ae_flags_print(id->flags, arg);
fprintf(fp,"\n\t"); fprintf(fp,"\n\t");
memset(abuf, '\0', sizeof(abuf)); memset(abuf, '\0', sizeof(abuf));
fprintf(fp, "src %s ", rt_addr_n2a(id->sa_id.family, &id->saddr, fprintf(fp, "src %s ", rt_addr_n2a(id->sa_id.family,
sizeof(id->saddr), &id->saddr,
abuf, sizeof(abuf))); abuf, sizeof(abuf)));
xfrm_usersa_print(&id->sa_id, id->reqid, fp); xfrm_usersa_print(&id->sa_id, id->reqid, fp);
@ -261,7 +267,7 @@ static void xfrm_print_addr(FILE *fp, int family, xfrm_address_t *a)
char buf[256]; char buf[256];
buf[0] = 0; buf[0] = 0;
fprintf(fp, "%s", rt_addr_n2a(family, a, buf, sizeof(buf))); fprintf(fp, "%s", rt_addr_n2a(family, sizeof(*a), a, buf, sizeof(buf)));
} }
static int xfrm_mapping_print(const struct sockaddr_nl *who, static int xfrm_mapping_print(const struct sockaddr_nl *who,
@ -285,6 +291,7 @@ static int xfrm_mapping_print(const struct sockaddr_nl *who,
} }
static int xfrm_accept_msg(const struct sockaddr_nl *who, static int xfrm_accept_msg(const struct sockaddr_nl *who,
struct rtnl_ctrl_data *ctrl,
struct nlmsghdr *n, void *arg) struct nlmsghdr *n, void *arg)
{ {
FILE *fp = (FILE*)arg; FILE *fp = (FILE*)arg;
@ -292,6 +299,13 @@ static int xfrm_accept_msg(const struct sockaddr_nl *who,
if (timestamp) if (timestamp)
print_timestamp(fp); print_timestamp(fp);
if (listen_all_nsid) {
if (ctrl == NULL || ctrl->nsid < 0)
fprintf(fp, "[nsid current]");
else
fprintf(fp, "[nsid %d]", ctrl->nsid);
}
switch (n->nlmsg_type) { switch (n->nlmsg_type) {
case XFRM_MSG_NEWSA: case XFRM_MSG_NEWSA:
case XFRM_MSG_DELSA: case XFRM_MSG_DELSA:
@ -354,6 +368,8 @@ int do_xfrm_monitor(int argc, char **argv)
if (matches(*argv, "file") == 0) { if (matches(*argv, "file") == 0) {
NEXT_ARG(); NEXT_ARG();
file = *argv; file = *argv;
} else if (matches(*argv, "all-nsid") == 0) {
listen_all_nsid = 1;
} else if (matches(*argv, "acquire") == 0) { } else if (matches(*argv, "acquire") == 0) {
lacquire=1; lacquire=1;
groups = 0; groups = 0;
@ -374,7 +390,7 @@ int do_xfrm_monitor(int argc, char **argv)
groups = 0; groups = 0;
} else if (matches(*argv, "help") == 0) { } else if (matches(*argv, "help") == 0) {
usage(); usage();
} else { } else if (strcmp(*argv, "all")) {
fprintf(stderr, "Argument \"%s\" is unknown, try \"ip xfrm monitor help\".\n", *argv); fprintf(stderr, "Argument \"%s\" is unknown, try \"ip xfrm monitor help\".\n", *argv);
exit(-1); exit(-1);
} }
@ -406,6 +422,8 @@ int do_xfrm_monitor(int argc, char **argv)
if (rtnl_open_byproto(&rth, groups, NETLINK_XFRM) < 0) if (rtnl_open_byproto(&rth, groups, NETLINK_XFRM) < 0)
exit(1); exit(1);
if (listen_all_nsid && rtnl_listen_all_nsid(&rth) < 0)
exit(1);
if (rtnl_listen(&rth, xfrm_accept_msg, (void*)stdout) < 0) if (rtnl_listen(&rth, xfrm_accept_msg, (void*)stdout) < 0)
exit(2); exit(2);

View File

@ -63,7 +63,8 @@ static void usage(void)
fprintf(stderr, " [ index INDEX ] [ ptype PTYPE ] [ action ACTION ] [ priority PRIORITY ]\n"); fprintf(stderr, " [ index INDEX ] [ ptype PTYPE ] [ action ACTION ] [ priority PRIORITY ]\n");
fprintf(stderr, " [ flag FLAG-LIST ]\n"); fprintf(stderr, " [ flag FLAG-LIST ]\n");
fprintf(stderr, "Usage: ip xfrm policy flush [ ptype PTYPE ]\n"); fprintf(stderr, "Usage: ip xfrm policy flush [ ptype PTYPE ]\n");
fprintf(stderr, "Usage: ip xfrm count\n"); fprintf(stderr, "Usage: ip xfrm policy count\n");
fprintf(stderr, "Usage: ip xfrm policy set [ hthresh4 LBITS RBITS ] [ hthresh6 LBITS RBITS ]\n");
fprintf(stderr, "SELECTOR := [ src ADDR[/PLEN] ] [ dst ADDR[/PLEN] ] [ dev DEV ] [ UPSPEC ]\n"); fprintf(stderr, "SELECTOR := [ src ADDR[/PLEN] ] [ dst ADDR[/PLEN] ] [ dev DEV ] [ UPSPEC ]\n");
fprintf(stderr, "UPSPEC := proto { { "); fprintf(stderr, "UPSPEC := proto { { ");
fprintf(stderr, "%s | ", strxf_proto(IPPROTO_TCP)); fprintf(stderr, "%s | ", strxf_proto(IPPROTO_TCP));
@ -392,7 +393,7 @@ static int xfrm_policy_modify(int cmd, unsigned flags, int argc, char **argv)
if (req.xpinfo.sel.family == AF_UNSPEC) if (req.xpinfo.sel.family == AF_UNSPEC)
req.xpinfo.sel.family = AF_INET; req.xpinfo.sel.family = AF_INET;
if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
exit(2); exit(2);
rtnl_close(&rth); rtnl_close(&rth);
@ -554,7 +555,7 @@ int xfrm_policy_print(const struct sockaddr_nl *who, struct nlmsghdr *n,
} }
static int xfrm_policy_get_or_delete(int argc, char **argv, int delete, static int xfrm_policy_get_or_delete(int argc, char **argv, int delete,
void *res_nlbuf) void *res_nlbuf, size_t res_size)
{ {
struct rtnl_handle rth; struct rtnl_handle rth;
struct { struct {
@ -669,7 +670,7 @@ static int xfrm_policy_get_or_delete(int argc, char **argv, int delete,
(void *)&ctx, ctx.sctx.len); (void *)&ctx, ctx.sctx.len);
} }
if (rtnl_talk(&rth, &req.n, 0, 0, res_nlbuf) < 0) if (rtnl_talk(&rth, &req.n, res_nlbuf, res_size) < 0)
exit(2); exit(2);
rtnl_close(&rth); rtnl_close(&rth);
@ -679,7 +680,7 @@ static int xfrm_policy_get_or_delete(int argc, char **argv, int delete,
static int xfrm_policy_delete(int argc, char **argv) static int xfrm_policy_delete(int argc, char **argv)
{ {
return xfrm_policy_get_or_delete(argc, argv, 1, NULL); return xfrm_policy_get_or_delete(argc, argv, 1, NULL, 0);
} }
static int xfrm_policy_get(int argc, char **argv) static int xfrm_policy_get(int argc, char **argv)
@ -689,7 +690,7 @@ static int xfrm_policy_get(int argc, char **argv)
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
xfrm_policy_get_or_delete(argc, argv, 0, n); xfrm_policy_get_or_delete(argc, argv, 0, n, sizeof(buf));
if (xfrm_policy_print(NULL, n, (void*)stdout) < 0) { if (xfrm_policy_print(NULL, n, (void*)stdout) < 0) {
fprintf(stderr, "An error :-)\n"); fprintf(stderr, "An error :-)\n");
@ -847,13 +848,23 @@ static int xfrm_policy_list_or_deleteall(int argc, char **argv, int deleteall)
xb.rth = &rth; xb.rth = &rth;
for (i = 0; ; i++) { for (i = 0; ; i++) {
struct {
struct nlmsghdr n;
char buf[NLMSG_BUF_SIZE];
} req = {
.n.nlmsg_len = NLMSG_HDRLEN,
.n.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
.n.nlmsg_type = XFRM_MSG_GETPOLICY,
.n.nlmsg_seq = rth.dump = ++rth.seq,
};
xb.offset = 0; xb.offset = 0;
xb.nlmsg_count = 0; xb.nlmsg_count = 0;
if (show_stats > 1) if (show_stats > 1)
fprintf(stderr, "Delete-all round = %d\n", i); fprintf(stderr, "Delete-all round = %d\n", i);
if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETPOLICY) < 0) { if (rtnl_send(&rth, (void *)&req, req.n.nlmsg_len) < 0) {
perror("Cannot send dump request"); perror("Cannot send dump request");
exit(1); exit(1);
} }
@ -879,7 +890,17 @@ static int xfrm_policy_list_or_deleteall(int argc, char **argv, int deleteall)
xb.nlmsg_count = 0; xb.nlmsg_count = 0;
} }
} else { } else {
if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETPOLICY) < 0) { struct {
struct nlmsghdr n;
char buf[NLMSG_BUF_SIZE];
} req = {
.n.nlmsg_len = NLMSG_HDRLEN,
.n.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
.n.nlmsg_type = XFRM_MSG_GETPOLICY,
.n.nlmsg_seq = rth.dump = ++rth.seq,
};
if (rtnl_send(&rth, (void *)&req, req.n.nlmsg_len) < 0) {
perror("Cannot send dump request"); perror("Cannot send dump request");
exit(1); exit(1);
} }
@ -934,7 +955,7 @@ static int print_spdinfo( struct nlmsghdr *n, void *arg)
fprintf(fp,")"); fprintf(fp,")");
} }
fprintf(fp,"\n"); fprintf(fp, "%s", _SL_);
} }
if (show_stats > 1) { if (show_stats > 1) {
struct xfrmu_spdhinfo *sh; struct xfrmu_spdhinfo *sh;
@ -948,13 +969,109 @@ static int print_spdinfo( struct nlmsghdr *n, void *arg)
fprintf(fp,"\t SPD buckets:"); fprintf(fp,"\t SPD buckets:");
fprintf(fp," count %d", sh->spdhcnt); fprintf(fp," count %d", sh->spdhcnt);
fprintf(fp," Max %d", sh->spdhmcnt); fprintf(fp," Max %d", sh->spdhmcnt);
fprintf(fp, "%s", _SL_);
}
if (tb[XFRMA_SPD_IPV4_HTHRESH]) {
struct xfrmu_spdhthresh *th;
if (RTA_PAYLOAD(tb[XFRMA_SPD_IPV4_HTHRESH]) < sizeof(*th)) {
fprintf(stderr, "SPDinfo: Wrong len %d\n", len);
return -1;
}
th = RTA_DATA(tb[XFRMA_SPD_IPV4_HTHRESH]);
fprintf(fp,"\t SPD IPv4 thresholds:");
fprintf(fp," local %d", th->lbits);
fprintf(fp," remote %d", th->rbits);
fprintf(fp, "%s", _SL_);
}
if (tb[XFRMA_SPD_IPV6_HTHRESH]) {
struct xfrmu_spdhthresh *th;
if (RTA_PAYLOAD(tb[XFRMA_SPD_IPV6_HTHRESH]) < sizeof(*th)) {
fprintf(stderr, "SPDinfo: Wrong len %d\n", len);
return -1;
}
th = RTA_DATA(tb[XFRMA_SPD_IPV6_HTHRESH]);
fprintf(fp,"\t SPD IPv6 thresholds:");
fprintf(fp," local %d", th->lbits);
fprintf(fp," remote %d", th->rbits);
fprintf(fp, "%s", _SL_);
} }
} }
fprintf(fp,"\n");
if (oneline)
fprintf(fp, "\n");
return 0; return 0;
} }
static int xfrm_spd_setinfo(int argc, char **argv)
{
struct rtnl_handle rth;
struct {
struct nlmsghdr n;
__u32 flags;
char buf[RTA_BUF_SIZE];
} req;
char *thr4 = NULL;
char *thr6 = NULL;
memset(&req, 0, sizeof(req));
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(__u32));
req.n.nlmsg_flags = NLM_F_REQUEST;
req.n.nlmsg_type = XFRM_MSG_NEWSPDINFO;
req.flags = 0XFFFFFFFF;
while (argc > 0) {
if (strcmp(*argv, "hthresh4") == 0) {
struct xfrmu_spdhthresh thr;
if (thr4)
duparg("hthresh4", *argv);
thr4 = *argv;
NEXT_ARG();
if (get_u8(&thr.lbits, *argv, 0) || thr.lbits > 32)
invarg("hthresh4 LBITS value is invalid", *argv);
NEXT_ARG();
if (get_u8(&thr.rbits, *argv, 0) || thr.rbits > 32)
invarg("hthresh4 RBITS value is invalid", *argv);
addattr_l(&req.n, sizeof(req), XFRMA_SPD_IPV4_HTHRESH,
(void *)&thr, sizeof(thr));
} else if (strcmp(*argv, "hthresh6") == 0) {
struct xfrmu_spdhthresh thr;
if (thr6)
duparg("hthresh6", *argv);
thr6 = *argv;
NEXT_ARG();
if (get_u8(&thr.lbits, *argv, 0) || thr.lbits > 128)
invarg("hthresh6 LBITS value is invalid", *argv);
NEXT_ARG();
if (get_u8(&thr.rbits, *argv, 0) || thr.rbits > 128)
invarg("hthresh6 RBITS value is invalid", *argv);
addattr_l(&req.n, sizeof(req), XFRMA_SPD_IPV6_HTHRESH,
(void *)&thr, sizeof(thr));
} else {
invarg("unknown", *argv);
}
argc--; argv++;
}
if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
exit(1);
if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
exit(2);
rtnl_close(&rth);
return 0;
}
static int xfrm_spd_getinfo(int argc, char **argv) static int xfrm_spd_getinfo(int argc, char **argv)
{ {
struct rtnl_handle rth; struct rtnl_handle rth;
@ -974,7 +1091,7 @@ static int xfrm_spd_getinfo(int argc, char **argv)
if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
exit(1); exit(1);
if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0) if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0)
exit(2); exit(2);
print_spdinfo(&req.n, (void*)stdout); print_spdinfo(&req.n, (void*)stdout);
@ -1026,7 +1143,7 @@ static int xfrm_policy_flush(int argc, char **argv)
if (show_stats > 1) if (show_stats > 1)
fprintf(stderr, "Flush policy\n"); fprintf(stderr, "Flush policy\n");
if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
exit(2); exit(2);
rtnl_close(&rth); rtnl_close(&rth);
@ -1058,6 +1175,8 @@ int do_xfrm_policy(int argc, char **argv)
return xfrm_policy_flush(argc-1, argv+1); return xfrm_policy_flush(argc-1, argv+1);
if (matches(*argv, "count") == 0) if (matches(*argv, "count") == 0)
return xfrm_spd_getinfo(argc, argv); return xfrm_spd_getinfo(argc, argv);
if (matches(*argv, "set") == 0)
return xfrm_spd_setinfo(argc-1, argv+1);
if (matches(*argv, "help") == 0) if (matches(*argv, "help") == 0)
usage(); usage();
fprintf(stderr, "Command \"%s\" is unknown, try \"ip xfrm policy help\".\n", *argv); fprintf(stderr, "Command \"%s\" is unknown, try \"ip xfrm policy help\".\n", *argv);

View File

@ -688,7 +688,7 @@ static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
if (req.xsinfo.family == AF_UNSPEC) if (req.xsinfo.family == AF_UNSPEC)
req.xsinfo.family = AF_INET; req.xsinfo.family = AF_INET;
if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
exit(2); exit(2);
rtnl_close(&rth); rtnl_close(&rth);
@ -825,7 +825,7 @@ static int xfrm_state_allocspi(int argc, char **argv)
req.xspi.info.family = AF_INET; req.xspi.info.family = AF_INET;
if (rtnl_talk(&rth, &req.n, 0, 0, res_n) < 0) if (rtnl_talk(&rth, &req.n, res_n, sizeof(res_buf)) < 0)
exit(2); exit(2);
if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) { if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) {
@ -1015,7 +1015,7 @@ static int xfrm_state_get_or_delete(int argc, char **argv, int delete)
req.xsid.family = AF_INET; req.xsid.family = AF_INET;
if (delete) { if (delete) {
if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
exit(2); exit(2);
} else { } else {
char buf[NLMSG_BUF_SIZE]; char buf[NLMSG_BUF_SIZE];
@ -1023,7 +1023,7 @@ static int xfrm_state_get_or_delete(int argc, char **argv, int delete)
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
if (rtnl_talk(&rth, &req.n, 0, 0, res_n) < 0) if (rtnl_talk(&rth, &req.n, res_n, sizeof(req)) < 0)
exit(2); exit(2);
if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) { if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) {
@ -1148,13 +1148,23 @@ static int xfrm_state_list_or_deleteall(int argc, char **argv, int deleteall)
xb.rth = &rth; xb.rth = &rth;
for (i = 0; ; i++) { for (i = 0; ; i++) {
struct {
struct nlmsghdr n;
char buf[NLMSG_BUF_SIZE];
} req = {
.n.nlmsg_len = NLMSG_HDRLEN,
.n.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
.n.nlmsg_type = XFRM_MSG_GETSA,
.n.nlmsg_seq = rth.dump = ++rth.seq,
};
xb.offset = 0; xb.offset = 0;
xb.nlmsg_count = 0; xb.nlmsg_count = 0;
if (show_stats > 1) if (show_stats > 1)
fprintf(stderr, "Delete-all round = %d\n", i); fprintf(stderr, "Delete-all round = %d\n", i);
if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETSA) < 0) { if (rtnl_send(&rth, (void *)&req, req.n.nlmsg_len) < 0) {
perror("Cannot send dump request"); perror("Cannot send dump request");
exit(1); exit(1);
} }
@ -1287,7 +1297,7 @@ static int xfrm_sad_getinfo(int argc, char **argv)
if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
exit(1); exit(1);
if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0) if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0)
exit(2); exit(2);
print_sadinfo(&req.n, (void*)stdout); print_sadinfo(&req.n, (void*)stdout);
@ -1341,7 +1351,7 @@ static int xfrm_state_flush(int argc, char **argv)
fprintf(stderr, "Flush state with XFRM-PROTO value \"%s\"\n", fprintf(stderr, "Flush state with XFRM-PROTO value \"%s\"\n",
strxf_xfrmproto(req.xsf.proto)); strxf_xfrmproto(req.xsf.proto));
if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
exit(2); exit(2);
rtnl_close(&rth); rtnl_close(&rth);

View File

@ -6,7 +6,8 @@ endif
CFLAGS += -fPIC CFLAGS += -fPIC
UTILOBJ=utils.o rt_names.o ll_types.o ll_proto.o ll_addr.o inet_proto.o namespace.o UTILOBJ=utils.o rt_names.o ll_types.o ll_proto.o ll_addr.o inet_proto.o namespace.o \
names.o color.o
NLOBJ=libgenl.o ll_map.o libnetlink.o NLOBJ=libgenl.o ll_map.o libnetlink.o

64
lib/color.c Normal file
View File

@ -0,0 +1,64 @@
#include <stdio.h>
#include <stdarg.h>
#include "color.h"
enum color {
C_RED,
C_GREEN,
C_YELLOW,
C_BLUE,
C_MAGENTA,
C_CYAN,
C_WHITE,
C_CLEAR
};
static const char * const color_codes[] = {
"\e[31m",
"\e[32m",
"\e[33m",
"\e[34m",
"\e[35m",
"\e[36m",
"\e[37m",
"\e[0m",
NULL,
};
static enum color attr_colors[] = {
C_CYAN,
C_YELLOW,
C_MAGENTA,
C_BLUE,
C_GREEN,
C_RED
};
static int color_is_enabled;
void enable_color(void)
{
color_is_enabled = 1;
}
int color_fprintf(FILE *fp, enum color_attr attr, const char *fmt, ...)
{
int ret = 0;
va_list args;
va_start(args, fmt);
if (!color_is_enabled) {
ret = vfprintf(fp, fmt, args);
goto end;
}
ret += fprintf(fp, "%s", color_codes[attr_colors[attr]]);
ret += vfprintf(fp, fmt, args);
ret += fprintf(fp, "%s", color_codes[C_CLEAR]);
end:
va_end(args);
return ret;
}

View File

@ -53,7 +53,7 @@ int genl_resolve_family(struct rtnl_handle *grth, const char *family)
addattr_l(&req.n, sizeof(req), CTRL_ATTR_FAMILY_NAME, addattr_l(&req.n, sizeof(req), CTRL_ATTR_FAMILY_NAME,
family, strlen(family) + 1); family, strlen(family) + 1);
if (rtnl_talk(grth, &req.n, 0, 0, &req.n) < 0) { if (rtnl_talk(grth, &req.n, &req.n, sizeof(req)) < 0) {
fprintf(stderr, "Error talking to the kernel\n"); fprintf(stderr, "Error talking to the kernel\n");
return -2; return -2;
} }

View File

@ -25,6 +25,14 @@
#include "libnetlink.h" #include "libnetlink.h"
#ifndef SOL_NETLINK
#define SOL_NETLINK 270
#endif
#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
int rcvbuf = 1024 * 1024; int rcvbuf = 1024 * 1024;
void rtnl_close(struct rtnl_handle *rth) void rtnl_close(struct rtnl_handle *rth)
@ -300,8 +308,8 @@ int rtnl_dump_filter(struct rtnl_handle *rth,
return rtnl_dump_filter_l(rth, a); return rtnl_dump_filter_l(rth, a);
} }
int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
unsigned groups, struct nlmsghdr *answer) struct nlmsghdr *answer, size_t len)
{ {
int status; int status;
unsigned seq; unsigned seq;
@ -317,12 +325,10 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
.msg_iov = &iov, .msg_iov = &iov,
.msg_iovlen = 1, .msg_iovlen = 1,
}; };
char buf[16384]; char buf[32768];
memset(&nladdr, 0, sizeof(nladdr)); memset(&nladdr, 0, sizeof(nladdr));
nladdr.nl_family = AF_NETLINK; nladdr.nl_family = AF_NETLINK;
nladdr.nl_pid = peer;
nladdr.nl_groups = groups;
n->nlmsg_seq = seq = ++rtnl->seq; n->nlmsg_seq = seq = ++rtnl->seq;
@ -330,7 +336,6 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
n->nlmsg_flags |= NLM_F_ACK; n->nlmsg_flags |= NLM_F_ACK;
status = sendmsg(rtnl->fd, &msg, 0); status = sendmsg(rtnl->fd, &msg, 0);
if (status < 0) { if (status < 0) {
perror("Cannot talk to rtnetlink"); perror("Cannot talk to rtnetlink");
return -1; return -1;
@ -339,7 +344,6 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
memset(buf,0,sizeof(buf)); memset(buf,0,sizeof(buf));
iov.iov_base = buf; iov.iov_base = buf;
while (1) { while (1) {
iov.iov_len = sizeof(buf); iov.iov_len = sizeof(buf);
status = recvmsg(rtnl->fd, &msg, 0); status = recvmsg(rtnl->fd, &msg, 0);
@ -372,7 +376,7 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
exit(1); exit(1);
} }
if (nladdr.nl_pid != peer || if (nladdr.nl_pid != 0 ||
h->nlmsg_pid != rtnl->local.nl_pid || h->nlmsg_pid != rtnl->local.nl_pid ||
h->nlmsg_seq != seq) { h->nlmsg_seq != seq) {
/* Don't forget to skip that message. */ /* Don't forget to skip that message. */
@ -385,20 +389,22 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
if (l < sizeof(struct nlmsgerr)) { if (l < sizeof(struct nlmsgerr)) {
fprintf(stderr, "ERROR truncated\n"); fprintf(stderr, "ERROR truncated\n");
} else { } else if (!err->error) {
if (!err->error) { if (answer)
if (answer) memcpy(answer, h,
memcpy(answer, h, h->nlmsg_len); MIN(len, h->nlmsg_len));
return 0; return 0;
}
fprintf(stderr, "RTNETLINK answers: %s\n", strerror(-err->error));
errno = -err->error;
} }
fprintf(stderr, "RTNETLINK answers: %s\n",
strerror(-err->error));
errno = -err->error;
return -1; return -1;
} }
if (answer) { if (answer) {
memcpy(answer, h, h->nlmsg_len); memcpy(answer, h,
MIN(len, h->nlmsg_len));
return 0; return 0;
} }
@ -407,10 +413,12 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
status -= NLMSG_ALIGN(len); status -= NLMSG_ALIGN(len);
h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
} }
if (msg.msg_flags & MSG_TRUNC) { if (msg.msg_flags & MSG_TRUNC) {
fprintf(stderr, "Message truncated\n"); fprintf(stderr, "Message truncated\n");
continue; continue;
} }
if (status) { if (status) {
fprintf(stderr, "!!!Remnant of size %d\n", status); fprintf(stderr, "!!!Remnant of size %d\n", status);
exit(1); exit(1);
@ -418,8 +426,21 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
} }
} }
int rtnl_listen_all_nsid(struct rtnl_handle *rth)
{
unsigned int on = 1;
if (setsockopt(rth->fd, SOL_NETLINK, NETLINK_LISTEN_ALL_NSID, &on,
sizeof(on)) < 0) {
perror("NETLINK_LISTEN_ALL_NSID");
return -1;
}
rth->flags |= RTNL_HANDLE_F_LISTEN_ALL_NSID;
return 0;
}
int rtnl_listen(struct rtnl_handle *rtnl, int rtnl_listen(struct rtnl_handle *rtnl,
rtnl_filter_t handler, rtnl_listen_filter_t handler,
void *jarg) void *jarg)
{ {
int status; int status;
@ -433,6 +454,12 @@ int rtnl_listen(struct rtnl_handle *rtnl,
.msg_iovlen = 1, .msg_iovlen = 1,
}; };
char buf[16384]; char buf[16384];
char cmsgbuf[BUFSIZ];
if (rtnl->flags & RTNL_HANDLE_F_LISTEN_ALL_NSID) {
msg.msg_control = &cmsgbuf;
msg.msg_controllen = sizeof(cmsgbuf);
}
memset(&nladdr, 0, sizeof(nladdr)); memset(&nladdr, 0, sizeof(nladdr));
nladdr.nl_family = AF_NETLINK; nladdr.nl_family = AF_NETLINK;
@ -441,6 +468,9 @@ int rtnl_listen(struct rtnl_handle *rtnl,
iov.iov_base = buf; iov.iov_base = buf;
while (1) { while (1) {
struct rtnl_ctrl_data ctrl;
struct cmsghdr *cmsg;
iov.iov_len = sizeof(buf); iov.iov_len = sizeof(buf);
status = recvmsg(rtnl->fd, &msg, 0); status = recvmsg(rtnl->fd, &msg, 0);
@ -461,6 +491,21 @@ int rtnl_listen(struct rtnl_handle *rtnl,
fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen); fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen);
exit(1); exit(1);
} }
if (rtnl->flags & RTNL_HANDLE_F_LISTEN_ALL_NSID) {
memset(&ctrl, 0, sizeof(ctrl));
ctrl.nsid = -1;
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
cmsg = CMSG_NXTHDR(&msg, cmsg))
if (cmsg->cmsg_level == SOL_NETLINK &&
cmsg->cmsg_type == NETLINK_LISTEN_ALL_NSID &&
cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
int *data = (int *)CMSG_DATA(cmsg);
ctrl.nsid = *data;
}
}
for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) { for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
int err; int err;
int len = h->nlmsg_len; int len = h->nlmsg_len;
@ -475,7 +520,7 @@ int rtnl_listen(struct rtnl_handle *rtnl,
exit(1); exit(1);
} }
err = handler(&nladdr, h, jarg); err = handler(&nladdr, &ctrl, h, jarg);
if (err < 0) if (err < 0)
return err; return err;
@ -493,7 +538,7 @@ int rtnl_listen(struct rtnl_handle *rtnl,
} }
} }
int rtnl_from_file(FILE *rtnl, rtnl_filter_t handler, int rtnl_from_file(FILE *rtnl, rtnl_listen_filter_t handler,
void *jarg) void *jarg)
{ {
int status; int status;
@ -541,7 +586,7 @@ int rtnl_from_file(FILE *rtnl, rtnl_filter_t handler,
return -1; return -1;
} }
err = handler(&nladdr, h, jarg); err = handler(&nladdr, NULL, h, jarg);
if (err < 0) if (err < 0)
return err; return err;
} }

View File

@ -29,7 +29,7 @@
#include "utils.h" #include "utils.h"
const char *ll_addr_n2a(unsigned char *addr, int alen, int type, char *buf, int blen) const char *ll_addr_n2a(const unsigned char *addr, int alen, int type, char *buf, int blen)
{ {
int i; int i;
int l; int l;

View File

@ -52,7 +52,7 @@ static struct ll_cache *ll_get_by_index(unsigned index)
return NULL; return NULL;
} }
static unsigned namehash(const char *str) unsigned namehash(const char *str)
{ {
unsigned hash = 5381; unsigned hash = 5381;

48
lib/mpls_ntop.c Normal file
View File

@ -0,0 +1,48 @@
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <linux/mpls.h>
#include "utils.h"
static const char *mpls_ntop1(const struct mpls_label *addr, char *buf, size_t buflen)
{
size_t destlen = buflen;
char *dest = buf;
int count;
for (count = 0; count < MPLS_MAX_LABELS; count++) {
uint32_t entry = ntohl(addr[count].entry);
uint32_t label = (entry & MPLS_LS_LABEL_MASK) >> MPLS_LS_LABEL_SHIFT;
int len = snprintf(dest, destlen, "%u", label);
/* Is this the end? */
if (entry & MPLS_LS_S_MASK)
return buf;
dest += len;
destlen -= len;
if (destlen) {
*dest = '/';
dest++;
destlen--;
}
}
errno = -E2BIG;
return NULL;
}
const char *mpls_ntop(int af, const void *addr, char *buf, size_t buflen)
{
switch(af) {
case AF_MPLS:
errno = 0;
return mpls_ntop1((struct mpls_label *)addr, buf, buflen);
default:
errno = EAFNOSUPPORT;
}
return NULL;
}

58
lib/mpls_pton.c Normal file
View File

@ -0,0 +1,58 @@
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <linux/mpls.h>
#include "utils.h"
static int mpls_pton1(const char *name, struct mpls_label *addr)
{
char *endp;
unsigned count;
for (count = 0; count < MPLS_MAX_LABELS; count++) {
unsigned long label;
label = strtoul(name, &endp, 0);
/* Fail when the label value is out or range */
if (label >= (1 << 20))
return 0;
if (endp == name) /* no digits */
return 0;
addr->entry = htonl(label << MPLS_LS_LABEL_SHIFT);
if (*endp == '\0') {
addr->entry |= htonl(1 << MPLS_LS_S_SHIFT);
return 1;
}
/* Bad character in the address */
if (*endp != '/')
return 0;
name = endp + 1;
addr += 1;
}
/* The address was too long */
return 0;
}
int mpls_pton(int af, const char *src, void *addr)
{
int err;
switch(af) {
case AF_MPLS:
errno = 0;
err = mpls_pton1(src, (struct mpls_label *)addr);
break;
default:
errno = EAFNOSUPPORT;
err = -1;
}
return err;
}

183
lib/names.c Normal file
View File

@ -0,0 +1,183 @@
/*
* names.c db names
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include "names.h"
#include "utils.h"
#define MAX_ENTRIES 256
#define NAME_MAX_LEN 512
static int read_id_name(FILE *fp, int *id, char *name)
{
char buf[NAME_MAX_LEN];
int min, maj;
while (fgets(buf, sizeof(buf), fp)) {
char *p = buf;
while (*p == ' ' || *p == '\t')
p++;
if (*p == '#' || *p == '\n' || *p == 0)
continue;
if (sscanf(p, "%x:%x %s\n", &maj, &min, name) == 3) {
*id = (maj << 16) | min;
} else if (sscanf(p, "%x:%x %s #", &maj, &min, name) == 3) {
*id = (maj << 16) | min;
} else if (sscanf(p, "0x%x %s\n", id, name) != 2 &&
sscanf(p, "0x%x %s #", id, name) != 2 &&
sscanf(p, "%d %s\n", id, name) != 2 &&
sscanf(p, "%d %s #", id, name) != 2) {
strcpy(name, p);
return -1;
}
return 1;
}
return 0;
}
struct db_names *db_names_alloc(void)
{
struct db_names *db;
db = malloc(sizeof(*db));
if (!db)
return NULL;
memset(db, 0, sizeof(*db));
db->size = MAX_ENTRIES;
db->hash = malloc(sizeof(struct db_entry *) * db->size);
memset(db->hash, 0, sizeof(struct db_entry *) * db->size);
return db;
}
int db_names_load(struct db_names *db, const char *path)
{
struct db_entry *entry;
FILE *fp;
int id;
char namebuf[NAME_MAX_LEN] = {0};
int ret = -1;
fp = fopen(path, "r");
if (!fp)
return -ENOENT;
while ((ret = read_id_name(fp, &id, &namebuf[0]))) {
if (ret == -1) {
fprintf(stderr, "Database %s is corrupted at %s\n",
path, namebuf);
goto Exit;
}
ret = -1;
if (id < 0)
continue;
entry = malloc(sizeof(*entry));
if (!entry)
goto Exit;
entry->name = strdup(namebuf);
if (!entry->name) {
free(entry);
goto Exit;
}
entry->id = id;
entry->next = db->hash[id & (db->size - 1)];
db->hash[id & (db->size - 1)] = entry;
}
ret = 0;
Exit:
fclose(fp);
return ret;
}
void db_names_free(struct db_names *db)
{
int i;
if (!db)
return;
for (i = 0; i < db->size; i++) {
struct db_entry *entry = db->hash[i];
while (entry) {
struct db_entry *next = entry->next;
free(entry->name);
free(entry);
entry = next;
}
}
free(db->hash);
free(db);
}
char *id_to_name(struct db_names *db, int id, char *name)
{
struct db_entry *entry;
if (!db)
return NULL;
entry = db->hash[id & (db->size - 1)];
while (entry && entry->id != id)
entry = entry->next;
if (entry) {
strncpy(name, entry->name, IDNAME_MAX);
return name;
}
snprintf(name, IDNAME_MAX, "%d", id);
return NULL;
}
int name_to_id(struct db_names *db, int *id, const char *name)
{
struct db_entry *entry;
int i;
if (!db)
return -1;
if (db->cached && strcmp(db->cached->name, name) == 0) {
*id = db->cached->id;
return 0;
}
for (i = 0; i < db->size; i++) {
entry = db->hash[i];
while (entry && strcmp(entry->name, name))
entry = entry->next;
if (entry) {
db->cached = entry;
*id = entry->id;
return 0;
}
}
return -1;
}

View File

@ -25,11 +25,13 @@
#include <asm/types.h> #include <asm/types.h>
#include <linux/pkt_sched.h> #include <linux/pkt_sched.h>
#include <linux/param.h> #include <linux/param.h>
#include <linux/if_arp.h>
#include <linux/mpls.h>
#include <time.h> #include <time.h>
#include <sys/time.h> #include <sys/time.h>
#include <errno.h> #include <errno.h>
#include "rt_names.h"
#include "utils.h" #include "utils.h"
#include "namespace.h" #include "namespace.h"
@ -389,7 +391,7 @@ int get_addr_1(inet_prefix *addr, const char *name, int family)
if (strcmp(name, "default") == 0 || if (strcmp(name, "default") == 0 ||
strcmp(name, "all") == 0 || strcmp(name, "all") == 0 ||
strcmp(name, "any") == 0) { strcmp(name, "any") == 0) {
if (family == AF_DECnet) if ((family == AF_DECnet) || (family == AF_MPLS))
return -1; return -1;
addr->family = family; addr->family = family;
addr->bytelen = (family == AF_INET6 ? 16 : 4); addr->bytelen = (family == AF_INET6 ? 16 : 4);
@ -397,6 +399,18 @@ int get_addr_1(inet_prefix *addr, const char *name, int family)
return 0; return 0;
} }
if (family == AF_PACKET) {
int len;
len = ll_addr_a2n((char *)&addr->data, sizeof(addr->data), name);
if (len < 0)
return -1;
addr->family = AF_PACKET;
addr->bytelen = len;
addr->bitlen = len * 8;
return 0;
}
if (strchr(name, ':')) { if (strchr(name, ':')) {
addr->family = AF_INET6; addr->family = AF_INET6;
if (family != AF_UNSPEC && family != AF_INET6) if (family != AF_UNSPEC && family != AF_INET6)
@ -419,6 +433,23 @@ int get_addr_1(inet_prefix *addr, const char *name, int family)
return 0; return 0;
} }
if (family == AF_MPLS) {
int i;
addr->family = AF_MPLS;
if (mpls_pton(AF_MPLS, name, addr->data) <= 0)
return -1;
addr->bytelen = 4;
addr->bitlen = 20;
/* How many bytes do I need? */
for (i = 0; i < 8; i++) {
if (ntohl(addr->data[i]) & MPLS_LS_S_MASK) {
addr->bytelen = (i + 1)*4;
break;
}
}
return 0;
}
addr->family = AF_INET; addr->family = AF_INET;
if (family != AF_UNSPEC && family != AF_INET) if (family != AF_UNSPEC && family != AF_INET)
return -1; return -1;
@ -431,6 +462,29 @@ int get_addr_1(inet_prefix *addr, const char *name, int family)
return 0; return 0;
} }
int af_bit_len(int af)
{
switch (af) {
case AF_INET6:
return 128;
case AF_INET:
return 32;
case AF_DECnet:
return 16;
case AF_IPX:
return 80;
case AF_MPLS:
return 20;
}
return 0;
}
int af_byte_len(int af)
{
return af_bit_len(af) / 8;
}
int get_prefix_1(inet_prefix *dst, char *arg, int family) int get_prefix_1(inet_prefix *dst, char *arg, int family)
{ {
int err; int err;
@ -442,7 +496,7 @@ int get_prefix_1(inet_prefix *dst, char *arg, int family)
if (strcmp(arg, "default") == 0 || if (strcmp(arg, "default") == 0 ||
strcmp(arg, "any") == 0 || strcmp(arg, "any") == 0 ||
strcmp(arg, "all") == 0) { strcmp(arg, "all") == 0) {
if (family == AF_DECnet) if ((family == AF_DECnet) || (family == AF_MPLS))
return -1; return -1;
dst->family = family; dst->family = family;
dst->bytelen = 0; dst->bytelen = 0;
@ -456,17 +510,8 @@ int get_prefix_1(inet_prefix *dst, char *arg, int family)
err = get_addr_1(dst, arg, family); err = get_addr_1(dst, arg, family);
if (err == 0) { if (err == 0) {
switch(dst->family) { dst->bitlen = af_bit_len(dst->family);
case AF_INET6:
dst->bitlen = 128;
break;
case AF_DECnet:
dst->bitlen = 16;
break;
default:
case AF_INET:
dst->bitlen = 32;
}
if (slash) { if (slash) {
if (get_netmask(&plen, slash+1, 0) if (get_netmask(&plen, slash+1, 0)
|| plen > dst->bitlen) { || plen > dst->bitlen) {
@ -485,10 +530,6 @@ done:
int get_addr(inet_prefix *dst, const char *arg, int family) int get_addr(inet_prefix *dst, const char *arg, int family)
{ {
if (family == AF_PACKET) {
fprintf(stderr, "Error: \"%s\" may be inet address, but it is not allowed in this context.\n", arg);
exit(1);
}
if (get_addr_1(dst, arg, family)) { if (get_addr_1(dst, arg, family)) {
fprintf(stderr, "Error: an inet address is expected rather than \"%s\".\n", arg); fprintf(stderr, "Error: an inet address is expected rather than \"%s\".\n", arg);
exit(1); exit(1);
@ -624,12 +665,14 @@ int __get_user_hz(void)
return sysconf(_SC_CLK_TCK); return sysconf(_SC_CLK_TCK);
} }
const char *rt_addr_n2a(int af, const void *addr, char *buf, int buflen) const char *rt_addr_n2a(int af, int len, const void *addr, char *buf, int buflen)
{ {
switch (af) { switch (af) {
case AF_INET: case AF_INET:
case AF_INET6: case AF_INET6:
return inet_ntop(af, addr, buf, buflen); return inet_ntop(af, addr, buf, buflen);
case AF_MPLS:
return mpls_ntop(af, addr, buf, buflen);
case AF_IPX: case AF_IPX:
return ipx_ntop(af, addr, buf, buflen); return ipx_ntop(af, addr, buf, buflen);
case AF_DECnet: case AF_DECnet:
@ -638,11 +681,52 @@ const char *rt_addr_n2a(int af, const void *addr, char *buf, int buflen)
memcpy(dna.a_addr, addr, 2); memcpy(dna.a_addr, addr, 2);
return dnet_ntop(af, &dna, buf, buflen); return dnet_ntop(af, &dna, buf, buflen);
} }
case AF_PACKET:
return ll_addr_n2a(addr, len, ARPHRD_VOID, buf, buflen);
default: default:
return "???"; return "???";
} }
} }
int read_family(const char *name)
{
int family = AF_UNSPEC;
if (strcmp(name, "inet") == 0)
family = AF_INET;
else if (strcmp(name, "inet6") == 0)
family = AF_INET6;
else if (strcmp(name, "dnet") == 0)
family = AF_DECnet;
else if (strcmp(name, "link") == 0)
family = AF_PACKET;
else if (strcmp(name, "ipx") == 0)
family = AF_IPX;
else if (strcmp(name, "mpls") == 0)
family = AF_MPLS;
else if (strcmp(name, "bridge") == 0)
family = AF_BRIDGE;
return family;
}
const char *family_name(int family)
{
if (family == AF_INET)
return "inet";
if (family == AF_INET6)
return "inet6";
if (family == AF_DECnet)
return "dnet";
if (family == AF_PACKET)
return "link";
if (family == AF_IPX)
return "ipx";
if (family == AF_MPLS)
return "mpls";
if (family == AF_BRIDGE)
return "bridge";
return "???";
}
#ifdef RESOLVE_HOSTNAMES #ifdef RESOLVE_HOSTNAMES
struct namerec struct namerec
{ {
@ -697,7 +781,6 @@ static const char *resolve_address(const void *addr, int len, int af)
} }
#endif #endif
const char *format_host(int af, int len, const void *addr, const char *format_host(int af, int len, const void *addr,
char *buf, int buflen) char *buf, int buflen)
{ {
@ -705,33 +788,14 @@ const char *format_host(int af, int len, const void *addr,
if (resolve_hosts) { if (resolve_hosts) {
const char *n; const char *n;
if (len <= 0) { len = len <= 0 ? af_byte_len(af) : len;
switch (af) {
case AF_INET:
len = 4;
break;
case AF_INET6:
len = 16;
break;
case AF_IPX:
len = 10;
break;
#ifdef AF_DECnet
/* I see no reasons why gethostbyname
may not work for DECnet */
case AF_DECnet:
len = 2;
break;
#endif
default: ;
}
}
if (len > 0 && if (len > 0 &&
(n = resolve_address(addr, len, af)) != NULL) (n = resolve_address(addr, len, af)) != NULL)
return n; return n;
} }
#endif #endif
return rt_addr_n2a(af, addr, buf, buflen); return rt_addr_n2a(af, len, addr, buf, buflen);
} }
@ -906,3 +970,9 @@ int do_each_netns(int (*func)(char *nsname, void *arg), void *arg,
return netns_foreach(on_netns, &nsf); return netns_foreach(on_netns, &nsf);
} }
char *int_to_str(int val, char *buf)
{
sprintf(buf, "%d", val);
return buf;
}

View File

@ -33,7 +33,8 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
void *jarg) void *jarg)
.sp .sp
int rtnl_listen(struct rtnl_handle *rtnl, int rtnl_listen(struct rtnl_handle *rtnl,
int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *), int (*handler)(struct sockaddr_nl *, struct rtnl_ctrl_data *,
struct nlmsghdr *n, void *),
void *jarg) void *jarg)
.sp .sp
int rtnl_from_file(FILE *rtnl, int rtnl_from_file(FILE *rtnl,
@ -108,8 +109,8 @@ rtnl_listen
Receive netlink data after a request and pass it to Receive netlink data after a request and pass it to
.I handler. .I handler.
.B handler .B handler
is a callback that gets the message source address, the message itself, is a callback that gets the message source address, anscillary data, the message
and the itself, and the
.B jarg .B jarg
cookie as arguments. It will get called for all received messages. cookie as arguments. It will get called for all received messages.
Only one message bundle is received. If there is a message Only one message bundle is received. If there is a message

View File

@ -6,7 +6,7 @@ MAN8PAGES = $(TARGETS) ip.8 arpd.8 lnstat.8 routel.8 rtacct.8 rtmon.8 ss.8 \
tc-mqprio.8 tc-netem.8 tc-pfifo.8 tc-pfifo_fast.8 tc-prio.8 tc-red.8 \ tc-mqprio.8 tc-netem.8 tc-pfifo.8 tc-pfifo_fast.8 tc-prio.8 tc-red.8 \
tc-sfb.8 tc-sfq.8 tc-stab.8 tc-tbf.8 \ tc-sfb.8 tc-sfq.8 tc-stab.8 tc-tbf.8 \
bridge.8 rtstat.8 ctstat.8 nstat.8 routef.8 \ bridge.8 rtstat.8 ctstat.8 nstat.8 routef.8 \
ip-addrlabel.8 ip-l2tp.8 \ ip-addrlabel.8 ip-fou.8 ip-gue.8 ip-l2tp.8 \
ip-maddress.8 ip-monitor.8 ip-mroute.8 ip-neighbour.8 \ ip-maddress.8 ip-monitor.8 ip-mroute.8 ip-neighbour.8 \
ip-netns.8 ip-ntable.8 ip-rule.8 ip-tunnel.8 ip-xfrm.8 \ ip-netns.8 ip-ntable.8 ip-rule.8 ip-tunnel.8 ip-xfrm.8 \
ip-tcp_metrics.8 ip-netconf.8 ip-token.8 ip-tcp_metrics.8 ip-netconf.8 ip-token.8

View File

@ -35,7 +35,7 @@ Suppress sending broadcast queries by the kernel. This option only makes sense t
Specifies the timeout of the negative cache. When resolution fails, arpd suppresses further attempts to resolve for this period. This option only makes sense together with option '-k'. This timeout should not be too much longer than the boot time of a typical host not supporting gratuitous ARP. Default value is 60 seconds. Specifies the timeout of the negative cache. When resolution fails, arpd suppresses further attempts to resolve for this period. This option only makes sense together with option '-k'. This timeout should not be too much longer than the boot time of a typical host not supporting gratuitous ARP. Default value is 60 seconds.
.TP .TP
-p <TIME> -p <TIME>
The time to wait in seconds between polling attempts to the kernel ARP table. TIME may be a floating point number. The default value is 30. The time to wait in seconds between polling attempts to the kernel ARP table. TIME may be a floating point number. The default value is 30.
.TP .TP
-R <RATE> -R <RATE>
Maximal steady rate of broadcasts sent by arpd in packets per second. Default value is 1. Maximal steady rate of broadcasts sent by arpd in packets per second. Default value is 1.

View File

@ -40,7 +40,8 @@ bridge \- show / manipulate bridge addresses and devices
.BR learning " { " on " | " off " } ] [ " .BR learning " { " on " | " off " } ] [ "
.BR learning_sync " { " on " | " off " } ] [ " .BR learning_sync " { " on " | " off " } ] [ "
.BR flood " { " on " | " off " } ] [ " .BR flood " { " on " | " off " } ] [ "
.BR hwmode " { " vepa " | " veb " } ] " .BR hwmode " { " vepa " | " veb " } ] [ "
.BR self " ] [ " master " ] "
.ti -8 .ti -8
.BR "bridge link" " [ " show " ] [ " .BR "bridge link" " [ " show " ] [ "
@ -53,7 +54,7 @@ bridge \- show / manipulate bridge addresses and devices
.B dev .B dev
.IR DEV " { " .IR DEV " { "
.BR local " | " temp " } { " .BR local " | " temp " } { "
.BR self " } { " embedded " } { " router " } [ " .BR self " } { " router " } [ "
.B dst .B dst
.IR IPADDR " ] [ " .IR IPADDR " ] [ "
.B vni .B vni
@ -110,7 +111,7 @@ utility and exit.
.TP .TP
.BR "\-s" , " \-stats", " \-statistics" .BR "\-s" , " \-stats", " \-statistics"
output more information. If this option output more information. If this option
is given multiple times, the amount of information increases. is given multiple times, the amount of information increases.
As a rule, the information is statistics or some time values. As a rule, the information is statistics or some time values.
@ -168,9 +169,9 @@ and
(or (or
.B list .B list
) objects, but some objects do not allow all of these operations ) objects, but some objects do not allow all of these operations
or have some additional commands. The or have some additional commands. The
.B help .B help
command is available for all objects. It prints command is available for all objects. It prints
out a list of available commands and argument syntax conventions. out a list of available commands and argument syntax conventions.
.sp .sp
If no command is given, some default command is assumed. If no command is given, some default command is assumed.
@ -200,68 +201,70 @@ the STP path cost of the specified port.
.TP .TP
.BI priority " PRIO " .BI priority " PRIO "
the STP port priority. The priority value is an unsigned 8-bit quantity the STP port priority. The priority value is an unsigned 8-bit quantity
(number between 0 and 255). This metric is used in the designated port an (number between 0 and 255). This metric is used in the designated port an
droot port selectio algorithms. droot port selectio algorithms.
.TP .TP
.BI state " STATE " .BI state " STATE "
the operation state of the port. This is primarily used by user space STP/RSTP the operation state of the port. This is primarily used by user space STP/RSTP
implementation. The following is a list of valid values: implementation. One may enter a lowercased port state name, or one of the
numbers below. Negative inputs are ignored, and unrecognized names return an
error.
.B 0 .B 0
- port is DISABLED. Make this port completely inactive. - port is DISABLED. Make this port completely inactive.
.sp .sp
.B 1 .B 1
- STP LISTENING state. Only valid if STP is enabled on the brige. In this - STP LISTENING state. Only valid if STP is enabled on the brige. In this
state the port for list for STP BPDUs and drop all other traffic. state the port for list for STP BPDUs and drop all other traffic.
.sp .sp
.B 2 .B 2
- STP LEARNING state. Only valid if STP is enabled on the bridge. In this - STP LEARNING state. Only valid if STP is enabled on the bridge. In this
state the port will accept traffic only for the purpose of updating MAC state the port will accept traffic only for the purpose of updating MAC
adress tables. adress tables.
.sp .sp
.B 3 .B 3
- STP FORWARDING state. Port is fully active. - STP FORWARDING state. Port is fully active.
.sp .sp
.B 4 .B 4
- STP BLOCKING state. Only valid if STP is enabled on the bridge. This state - STP BLOCKING state. Only valid if STP is enabled on the bridge. This state
is used during the STP election process. In this state, port will only process is used during the STP election process. In this state, port will only process
STP BPDUs. STP BPDUs.
.sp .sp
.TP .TP
.BR "guard on " or " guard off " .BR "guard on " or " guard off "
Controls whether STP BPUDs will be processed by the bridge port. By default, Controls whether STP BPUDs will be processed by the bridge port. By default,
the flag is turned off allowed BPDU processing. Turning this flag on will the flag is turned off allowed BPDU processing. Turning this flag on will
cause the port to stop processing STP BPDUs. cause the port to stop processing STP BPDUs.
.TP .TP
.BR "hairpin on " or " hairpin off " .BR "hairpin on " or " hairpin off "
Controls whether traffic may be send back out of the port on which it was Controls whether traffic may be send back out of the port on which it was
received. By default, this flag is turned off and the bridge will not forward received. By default, this flag is turned off and the bridge will not forward
traffic back out of the receiving port. traffic back out of the receiving port.
.TP .TP
.BR "fastleave on " or " fastleave off " .BR "fastleave on " or " fastleave off "
This flag allows the bridge to immediately stop multicast traffic on a port This flag allows the bridge to immediately stop multicast traffic on a port
that receives IGMP Leave message. It is only used with IGMP snooping is that receives IGMP Leave message. It is only used with IGMP snooping is
enabled on the bridge. By default the flag is off. enabled on the bridge. By default the flag is off.
.TP .TP
.BR "root_block on " or " root_block off " .BR "root_block on " or " root_block off "
Controls whether a given port is allowed to become root port or not. Only used Controls whether a given port is allowed to become root port or not. Only used
when STP is enabled on the bridge. By default the flag is off. when STP is enabled on the bridge. By default the flag is off.
.TP .TP
.BR "learning on " or " learning off " .BR "learning on " or " learning off "
Controls whether a given port will learn MAC addresses from received traffic or Controls whether a given port will learn MAC addresses from received traffic or
not. If learning if off, the bridge will end up flooding any traffic for which not. If learning if off, the bridge will end up flooding any traffic for which
it has no FDB entry. By default this flag is on. it has no FDB entry. By default this flag is on.
.TP .TP
.BR "learning_sync on " or " learning_sync off " .BR "learning_sync on " or " learning_sync off "
@ -270,12 +273,12 @@ bridge FDB.
.TP .TP
.BR "flooding on " or " flooding off " .BR "flooding on " or " flooding off "
Controls whether a given port will flood unicast traffic for which there is no FDB entry. By default this flag is on. Controls whether a given port will flood unicast traffic for which there is no FDB entry. By default this flag is on.
.TP .TP
.BI hwmode .BI hwmode
Some network interface cards support HW bridge functionality and they may be Some network interface cards support HW bridge functionality and they may be
configured in different modes. Currently support modes are: configured in different modes. Currently support modes are:
.B vepa .B vepa
- Data sent between HW ports is sent on the wire to the external - Data sent between HW ports is sent on the wire to the external
@ -284,6 +287,15 @@ switch.
.B veb .B veb
- bridging happens in hardware. - bridging happens in hardware.
.TP
.BI self
link setting is configured on specified physical device
.TP
.BI master
link setting is configured on the software bridge (default)
.SS bridge link show - list bridge port configuration. .SS bridge link show - list bridge port configuration.
This command displays the current bridge port configuration and flags. This command displays the current bridge port configuration and flags.
@ -314,10 +326,6 @@ the interface to which this address is associated.
- the address is associated with a software fdb (default) - the address is associated with a software fdb (default)
.sp .sp
.B embedded
- the address is associated with an offloaded fdb
.sp
.B router .B router
- the destination address is associated with a router. - the destination address is associated with a router.
Valid if the referenced device is a VXLAN type device and has Valid if the referenced device is a VXLAN type device and has
@ -381,7 +389,7 @@ This command displays the current forwarding table.
.PP .PP
With the With the
.B -statistics .B -statistics
option, the command becomes verbose. It prints out the last updated option, the command becomes verbose. It prints out the last updated
and last used time for each entry. and last used time for each entry.
.SH bridge mdb - multicast group database management .SH bridge mdb - multicast group database management
@ -444,7 +452,7 @@ bridge interfaces.
.PP .PP
With the With the
.B -details .B -details
option, the command becomes verbose. It prints out the ports known to have option, the command becomes verbose. It prints out the ports known to have
a connected router. a connected router.
.SH bridge vlan - VLAN filter list .SH bridge vlan - VLAN filter list
@ -479,7 +487,7 @@ the vlan specified is to be treated as untagged on egress.
.TP .TP
.BI self .BI self
the vlan is configured on the specified physical device. Required if the the vlan is configured on the specified physical device. Required if the
device is the bridge device. device is the bridge device.
.TP .TP
@ -505,7 +513,7 @@ This command displays the current VLAN filter table.
The The
.B bridge .B bridge
utility can monitor the state of devices and addresses utility can monitor the state of devices and addresses
continuously. This option has a slightly different format. continuously. This option has a slightly different format.
Namely, the Namely, the
.B monitor .B monitor
command is the first in the command line and then the object list follows: command is the first in the command line and then the object list follows:
@ -527,7 +535,7 @@ described in previous sections.
.P .P
If a file name is given, it does not listen on RTNETLINK, If a file name is given, it does not listen on RTNETLINK,
but opens the file containing RTNETLINK messages saved in binary format but opens the file containing RTNETLINK messages saved in binary format
and dumps them. Such a history file can be generated with the and dumps them. Such a history file can be generated with the
.SH NOTES .SH NOTES

View File

@ -80,7 +80,7 @@ the name of the device to add the address to.
.BI local " ADDRESS " (default) .BI local " ADDRESS " (default)
the address of the interface. The format of the address depends the address of the interface. The format of the address depends
on the protocol. It is a dotted quad for IP and a sequence of on the protocol. It is a dotted quad for IP and a sequence of
hexadecimal halfwords separated by colons for IPv6. The hexadecimal halfwords separated by colons for IPv6. The
.I ADDRESS .I ADDRESS
may be followed by a slash and a decimal number which encodes may be followed by a slash and a decimal number which encodes
the network prefix length. the network prefix length.
@ -91,8 +91,8 @@ the address of the remote endpoint for pointopoint interfaces.
Again, the Again, the
.I ADDRESS .I ADDRESS
may be followed by a slash and a decimal number, encoding the network may be followed by a slash and a decimal number, encoding the network
prefix length. If a peer address is specified, the local address prefix length. If a peer address is specified, the local address
cannot have a prefix length. The network prefix is associated cannot have a prefix length. The network prefix is associated
with the peer rather than with the local address. with the peer rather than with the local address.
.TP .TP
@ -103,7 +103,7 @@ It is possible to use the special symbols
.B '+' .B '+'
and and
.B '-' .B '-'
instead of the broadcast address. In this case, the broadcast address instead of the broadcast address. In this case, the broadcast address
is derived by setting/resetting the host bits of the interface prefix. is derived by setting/resetting the host bits of the interface prefix.
.TP .TP
@ -139,7 +139,7 @@ valid inside this site.
.B Arguments: .B Arguments:
coincide with the arguments of coincide with the arguments of
.B ip addr add. .B ip addr add.
The device name is a required argument. The rest are optional. The device name is a required argument. The rest are optional.
If no arguments are given, the first address is deleted. If no arguments are given, the first address is deleted.
.SS ip address show - look at protocol addresses .SS ip address show - look at protocol addresses
@ -221,14 +221,14 @@ The difference is that it does not run when no arguments are given.
.B Warning: .B Warning:
This command (and other This command (and other
.B flush .B flush
commands described below) is pretty dangerous. If you make a mistake, commands described below) is pretty dangerous. If you make a mistake,
it will not forgive it, but will cruelly purge all the addresses. it will not forgive it, but will cruelly purge all the addresses.
.PP .PP
With the With the
.B -statistics .B -statistics
option, the command becomes verbose. It prints out the number of deleted option, the command becomes verbose. It prints out the number of deleted
addresses and the number of rounds made to flush the address list. If addresses and the number of rounds made to flush the address list. If
this option is given twice, this option is given twice,
.B ip address flush .B ip address flush
also dumps all the deleted addresses in the format described in the also dumps all the deleted addresses in the format described in the

View File

@ -35,7 +35,7 @@ ip-addrlabel \- protocol address label management
.SH "DESCRIPTION" .SH "DESCRIPTION"
IPv6 address labels are used for address selection; IPv6 address labels are used for address selection;
they are described in RFC 3484. Precedence is managed by userspace, they are described in RFC 3484. Precedence is managed by userspace,
and only the label itself is stored in the kernel. and only the label itself is stored in the kernel.
.SS ip addrlabel add - add an address label .SS ip addrlabel add - add an address label

View File

@ -356,16 +356,16 @@ the recipient expects to receive ethernet frames exactly as
transmitted. In such cases, it is important that frames leaving the transmitted. In such cases, it is important that frames leaving the
tunnel are reassembled back into a single frame before being tunnel are reassembled back into a single frame before being
forwarded on. To do so, enable netfilter connection tracking forwarded on. To do so, enable netfilter connection tracking
(conntrack) or manually load the Linux netfilter degrag modules at (conntrack) or manually load the Linux netfilter defrag modules at
each tunnel endpoint. each tunnel endpoint.
.PP .PP
.nf .nf
site-A:# modprobe nf_degrag_ipv4 site-A:# modprobe nf_defrag_ipv4
site-B:# modprobe nf_degrag_ipv4 site-B:# modprobe nf_defrag_ipv4
.fi .fi
.PP .PP
If L2TP is being used over IPv6, use the IPv6 degrag module. If L2TP is being used over IPv6, use the IPv6 defrag module.
.SH INTEROPERABILITY .SH INTEROPERABILITY
.PP .PP
Unmanaged (static) L2TPv3 tunnels are supported by some network Unmanaged (static) L2TPv3 tunnels are supported by some network

View File

@ -72,10 +72,17 @@ ip-link \- network device configuration
.BR gre " |" .BR gre " |"
.BR gretap " |" .BR gretap " |"
.BR ip6gre " |" .BR ip6gre " |"
.BR ip6gretap " ]" .BR ip6gretap " |"
.BR vti " |"
.BR nlmon " |"
.BR ipvlan " |"
.BR lowpan " ]"
.ti -8 .ti -8
.BI "ip link delete " DEVICE .BR "ip link delete " {
.IR DEVICE " | "
.BI "group " GROUP
}
.BI type " TYPE" .BI type " TYPE"
.RI "[ " ARGS " ]" .RI "[ " ARGS " ]"
@ -228,6 +235,18 @@ Link types:
.sp .sp
.BR ip6gretap .BR ip6gretap
- Virtual L2 tunnel interface GRE over IPv6 - Virtual L2 tunnel interface GRE over IPv6
.sp
.BR vti
- Virtual tunnel interface
.sp
.BR nlmon
- Netlink monitoring device
.sp
.BR ipvlan
- Interface for L3 (IPv6/IPv4) based VLANs
.sp
.BR lowpan
- Interface for 6LoWPAN (IPv6) over IEEE 802.15.4 / Bluetooth
.in -8 .in -8
.TP .TP
@ -300,7 +319,7 @@ parameter.
.BI remote " IPADDR" .BI remote " IPADDR"
- specifies the unicast destination IP address to use in outgoing packets - specifies the unicast destination IP address to use in outgoing packets
when the destination link layer address is not known in the VXLAN device when the destination link layer address is not known in the VXLAN device
forwarding database. This parameter cannot be specified with the forwarding database. This parameter cannot be specified with the
.B group .B group
parameter. parameter.
@ -521,7 +540,7 @@ flag calculates checksums for outgoing packets.
The The
.B icsum .B icsum
flag requires that all input packets have the correct flag requires that all input packets have the correct
checksum. The checksum. The
.B csum .B csum
flag is equivalent to the combination flag is equivalent to the combination
.BR "icsum ocsum" . .BR "icsum ocsum" .
@ -532,7 +551,7 @@ flag is equivalent to the combination
.sp .sp
.BI encaplimit " ELIM" .BI encaplimit " ELIM"
- specifies a fixed encapsulation limit. Default is 4. - specifies a fixed encapsulation limit. Default is 4.
.sp .sp
.BI flowlabel " FLOWLABEL" .BI flowlabel " FLOWLABEL"
@ -576,15 +595,19 @@ the following additional arguments are supported:
- specifies the mode (datagram or connected) to use. - specifies the mode (datagram or connected) to use.
.SS ip link delete - delete virtual link .SS ip link delete - delete virtual link
.I DEVICE
specifies the virtual device to act operate on.
.I TYPE
specifies the type of the device.
.TP .TP
.BI dev " DEVICE " .BI dev " DEVICE "
specifies the physical device to act operate on. specifies the virtual device to act operate on.
.TP
.BI group " GROUP "
specifies the group of virtual links to delete. Group 0 is not allowed to be
deleted since it is the default group.
.TP
.BI type " TYPE "
specifies the type of the device.
.SS ip link set - change device attributes .SS ip link set - change device attributes
@ -599,7 +622,7 @@ device.
.BI group " GROUP " .BI group " GROUP "
.I GROUP .I GROUP
has a dual role: If both group and dev are present, then move the device to the has a dual role: If both group and dev are present, then move the device to the
specified group. If only a group is specified, then the command operates on specified group. If only a group is specified, then the command operates on
all devices in that group. all devices in that group.
.TP .TP
@ -625,11 +648,13 @@ flag on the device.
.BR "dynamic on " or " dynamic off" .BR "dynamic on " or " dynamic off"
change the change the
.B DYNAMIC .B DYNAMIC
flag on the device. flag on the device. Indicates that address can change when interface goes down (currently
.B NOT
used by the Linux).
.TP .TP
.BI name " NAME" .BI name " NAME"
change the name of the device. This operation is not change the name of the device. This operation is not
recommended if the device is running or has some addresses recommended if the device is running or has some addresses
already configured. already configured.
@ -660,25 +685,34 @@ the interface is
.IR "POINTOPOINT" . .IR "POINTOPOINT" .
.TP .TP
.BI netns " PID" .BI netns " NETNSNAME " \fR| " PID"
move the device to the network namespace associated with the process
.IR "PID".
.TP
.BI netns " NETNSNAME"
move the device to the network namespace associated with name move the device to the network namespace associated with name
.IR "NETNSNAME". .IR "NETNSNAME " or
.RI process " PID".
Some devices are not allowed to change network namespace: loopback, bridge,
ppp, wireless. These are network namespace local devices. In such case
.B ip
tool will return "Invalid argument" error. It is possible to find out if device is local
to a single network namespace by checking
.B netns-local
flag in the output of the
.BR ethtool ":"
.in +8
.B ethtool -k
.I DEVICE
.in -8
To change network namespace for wireless devices the
.B iw
tool can be used. But it allows to change network namespace only for physical devices and by process
.IR PID .
.TP .TP
.BI alias " NAME" .BI alias " NAME"
give the device a symbolic name for easy reference. give the device a symbolic name for easy reference.
.TP
.BI group " GROUP"
specify the group the device belongs to.
The available groups are listed in file
.BR "@SYSCONFDIR@/group" .
.TP .TP
.BI vf " NUM" .BI vf " NUM"
specify a Virtual Function device to be configured. The associated PF device specify a Virtual Function device to be configured. The associated PF device
@ -765,7 +799,7 @@ If multiple parameter changes are requested,
aborts immediately after any of the changes have failed. aborts immediately after any of the changes have failed.
This is the only case when This is the only case when
.B ip .B ip
can move the system to an unpredictable state. The solution can move the system to an unpredictable state. The solution
is to avoid changing several parameters with one is to avoid changing several parameters with one
.B ip link set .B ip link set
call. call.
@ -824,6 +858,12 @@ print human readable rates in IEC units (ie. 1K = 1024).
.I "TYPE" .I "TYPE"
specifies which help of link type to dislpay. specifies which help of link type to dislpay.
.SS
.I GROUP
may be a number or a string from the file
.B @SYSCONFDIR@/group
which can be manually filled.
.SH "EXAMPLES" .SH "EXAMPLES"
.PP .PP
ip link show ip link show
@ -873,11 +913,18 @@ encap-dport 5555 encap-csum encap-remcsum
Creates an IPIP that is encapsulated with Generic UDP Encapsulation, Creates an IPIP that is encapsulated with Generic UDP Encapsulation,
and the outer UDP checksum and remote checksum offload are enabled. and the outer UDP checksum and remote checksum offload are enabled.
.RE
.PP
ip link add link wpan0 lowpan0 type lowpan
.RS 4
Creates a 6LoWPAN interface named lowpan0 on the underlying
IEEE 802.15.4 device wpan0.
.RE .RE
.SH SEE ALSO .SH SEE ALSO
.br .br
.BR ip (8) .BR ip (8),
.BR ip-netns (8)
.SH AUTHOR .SH AUTHOR
Original Manpage by Michail Litvak <mci@owl.openwall.com> Original Manpage by Michail Litvak <mci@owl.openwall.com>

View File

@ -39,7 +39,7 @@ the device name.
These commands attach/detach a static link-layer multicast address These commands attach/detach a static link-layer multicast address
to listen on the interface. to listen on the interface.
Note that it is impossible to join protocol multicast groups Note that it is impossible to join protocol multicast groups
statically. This command only manages link-layer addresses. statically. This command only manages link-layer addresses.
.RS .RS
.TP .TP

View File

@ -12,6 +12,10 @@ ip-monitor, rtmon \- state monitoring
.IR OBJECT-LIST " ] [" .IR OBJECT-LIST " ] ["
.BI file " FILENAME " .BI file " FILENAME "
] [ ] [
.BI label
] [
.BI all-nsid
] [
.BI dev " DEVICE " .BI dev " DEVICE "
] ]
.sp .sp
@ -33,7 +37,7 @@ Prints short timestamp before the event message on the same line in format:
The The
.B ip .B ip
utility can monitor the state of devices, addresses utility can monitor the state of devices, addresses
and routes continuously. This option has a slightly different format. and routes continuously. This option has a slightly different format.
Namely, the Namely, the
.B monitor .B monitor
command is the first in the command line and then the object list follows: command is the first in the command line and then the object list follows:
@ -42,6 +46,10 @@ command is the first in the command line and then the object list follows:
.IR OBJECT-LIST " ] [" .IR OBJECT-LIST " ] ["
.BI file " FILENAME " .BI file " FILENAME "
] [ ] [
.BI label
] [
.BI all-nsid
] [
.BI dev " DEVICE " .BI dev " DEVICE "
] ]
@ -49,7 +57,7 @@ command is the first in the command line and then the object list follows:
is the list of object types that we want to monitor. is the list of object types that we want to monitor.
It may contain It may contain
.BR link ", " address ", " route ", " mroute ", " prefix ", " .BR link ", " address ", " route ", " mroute ", " prefix ", "
.BR neigh " and " netconf "." .BR neigh ", " netconf ", " rule " and " nsid "."
If no If no
.B file .B file
argument is given, argument is given,
@ -57,6 +65,32 @@ argument is given,
opens RTNETLINK, listens on it and dumps state changes in the format opens RTNETLINK, listens on it and dumps state changes in the format
described in previous sections. described in previous sections.
.P
If the
.BI label
option is set, a prefix is displayed before each message to
show the family of the message. For example:
.sp
.in +2
[NEIGH]10.16.0.112 dev eth0 lladdr 00:04:23:df:2f:d0 REACHABLE
[LINK]3: eth1: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast state DOWN group default
link/ether 52:54:00:12:34:57 brd ff:ff:ff:ff:ff:ff
.in -2
.sp
.P
If the
.BI all-nsid
option is set, the program listens to all network namespaces that have a
nsid assigned into the network namespace were the program is running.
A prefix is displayed to show the network namespace where the message
originates. Example:
.sp
.in +2
[nsid 0]10.16.0.112 dev eth0 lladdr 00:04:23:df:2f:d0 REACHABLE
.in -2
.sp
.P .P
If the If the
.BI file .BI file
@ -65,7 +99,7 @@ but opens the given file, and dumps its contents. The file
should contain RTNETLINK messages saved in binary format. should contain RTNETLINK messages saved in binary format.
Such a file can be generated with the Such a file can be generated with the
.B rtmon .B rtmon
utility. This utility has a command line syntax similar to utility. This utility has a command line syntax similar to
.BR "ip monitor" . .BR "ip monitor" .
Ideally, Ideally,
.B rtmon .B rtmon
@ -97,3 +131,5 @@ option is given, the program prints only events related to this device.
.SH AUTHOR .SH AUTHOR
Original Manpage by Michail Litvak <mci@owl.openwall.com> Original Manpage by Michail Litvak <mci@owl.openwall.com>
.br
Manpage revised by Nicolas Dichtel <nicolas.dichtel@6wind.com>

View File

@ -28,7 +28,7 @@ or
Due to the limitations of the current interface to the multicast routing Due to the limitations of the current interface to the multicast routing
engine, it is impossible to change engine, it is impossible to change
.B mroute .B mroute
objects administratively, so we can only display them. This limitation objects administratively, so we can only display them. This limitation
will be removed in the future. will be removed in the future.
.SS ip mroute show - list mroute cache entries .SS ip mroute show - list mroute cache entries

Some files were not shown because too many files have changed in this diff Show More