Commit 823d587e authored by Stephen Hemminger's avatar Stephen Hemminger

Merge branch 'net-next' of...

Merge branch 'net-next' of git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2 into net-next
parents 4dacfdcf 3a641f53
......@@ -16,4 +16,5 @@ extern int preferred_family;
extern int show_stats;
extern int show_details;
extern int timestamp;
extern int compress_vlans;
extern struct rtnl_handle rth;
......@@ -21,6 +21,7 @@ int resolve_hosts;
int oneline = 0;
int show_stats;
int show_details;
int compress_vlans;
int timestamp;
char * _SL_ = NULL;
......@@ -32,7 +33,8 @@ static void usage(void)
"Usage: bridge [ OPTIONS ] OBJECT { COMMAND | help }\n"
"where OBJECT := { link | fdb | mdb | vlan | monitor }\n"
" OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] |\n"
" -o[neline] | -t[imestamp] | -n[etns] name }\n");
" -o[neline] | -t[imestamp] | -n[etns] name |\n"
" -c[ompressvlans] }\n");
exit(-1);
}
......@@ -117,6 +119,8 @@ main(int argc, char **argv)
NEXT_ARG();
if (netns_switch(argv[1]))
exit(-1);
} else if (matches(opt, "-compressvlans") == 0) {
++compress_vlans;
} else {
fprintf(stderr, "Option \"%s\" is unknown, try \"bridge help\".\n", opt);
exit(-1);
......
......@@ -32,6 +32,7 @@ static int vlan_modify(int cmd, int argc, char **argv)
} req;
char *d = NULL;
short vid = -1;
short vid_end = -1;
struct rtattr *afspec;
struct bridge_vlan_info vinfo;
unsigned short flags = 0;
......@@ -49,8 +50,18 @@ static int vlan_modify(int cmd, int argc, char **argv)
NEXT_ARG();
d = *argv;
} else if (strcmp(*argv, "vid") == 0) {
char *p;
NEXT_ARG();
vid = atoi(*argv);
p = strchr(*argv, '-');
if (p) {
*p = '\0';
p++;
vid = atoi(*argv);
vid_end = atoi(p);
vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_BEGIN;
} else {
vid = atoi(*argv);
}
} else if (strcmp(*argv, "self") == 0) {
flags |= BRIDGE_FLAGS_SELF;
} else if (strcmp(*argv, "master") == 0) {
......@@ -83,15 +94,40 @@ static int vlan_modify(int cmd, int argc, char **argv)
return -1;
}
vinfo.vid = vid;
if (vinfo.flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
if (vid_end == -1 || vid_end >= 4096 || vid >= vid_end) {
fprintf(stderr, "Invalid VLAN range \"%hu-%hu\"\n",
vid, vid_end);
return -1;
}
if (vinfo.flags & BRIDGE_VLAN_INFO_PVID) {
fprintf(stderr,
"pvid cannot be configured for a vlan range\n");
return -1;
}
}
afspec = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC);
if (flags)
addattr16(&req.n, sizeof(req), IFLA_BRIDGE_FLAGS, flags);
addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo,
sizeof(vinfo));
vinfo.vid = vid;
if (vid_end != -1) {
/* send vlan range start */
addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo,
sizeof(vinfo));
vinfo.flags &= ~BRIDGE_VLAN_INFO_RANGE_BEGIN;
/* Now send the vlan range end */
vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_END;
vinfo.vid = vid_end;
addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo,
sizeof(vinfo));
} else {
addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo,
sizeof(vinfo));
}
addattr_nest_end(&req.n, afspec);
......@@ -146,7 +182,12 @@ static int print_vlan(const struct sockaddr_nl *who,
continue;
vinfo = RTA_DATA(i);
fprintf(fp, "\t %hu", vinfo->vid);
if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END)
fprintf(fp, "-%hu", vinfo->vid);
else
fprintf(fp, "\t %hu", vinfo->vid);
if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN)
continue;
if (vinfo->flags & BRIDGE_VLAN_INFO_PVID)
fprintf(fp, " PVID");
if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED)
......@@ -182,7 +223,9 @@ static int vlan_show(int argc, char **argv)
}
if (rtnl_wilddump_req_filter(&rth, PF_BRIDGE, RTM_GETLINK,
RTEXT_FILTER_BRVLAN) < 0) {
(compress_vlans ?
RTEXT_FILTER_BRVLAN_COMPRESSED :
RTEXT_FILTER_BRVLAN)) < 0) {
perror("Cannont send dump request");
exit(1);
}
......
static const char SNAPSHOT[] = "141224";
static const char SNAPSHOT[] = "150210";
/*
* Copyright (c) 2015 Jiri Pirko <jiri@resnulli.us>
*
* 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.
*/
#ifndef __LINUX_TC_BPF_H
#define __LINUX_TC_BPF_H
#include <linux/pkt_cls.h>
#define TCA_ACT_BPF 13
struct tc_act_bpf {
tc_gen;
};
enum {
TCA_ACT_BPF_UNSPEC,
TCA_ACT_BPF_TM,
TCA_ACT_BPF_PARMS,
TCA_ACT_BPF_OPS_LEN,
TCA_ACT_BPF_OPS,
__TCA_ACT_BPF_MAX,
};
#define TCA_ACT_BPF_MAX (__TCA_ACT_BPF_MAX - 1)
#endif
......@@ -3,6 +3,7 @@
#include <sched.h>
#include <sys/mount.h>
#include <sys/syscall.h>
#include <errno.h>
#define NETNS_RUN_DIR "/var/run/netns"
......@@ -30,7 +31,7 @@
#endif
#ifndef HAVE_SETNS
static int setns(int fd, int nstype)
static inline int setns(int fd, int nstype)
{
#ifdef __NR_setns
return syscall(__NR_setns, fd, nstype);
......@@ -43,5 +44,11 @@ static int setns(int fd, int nstype)
extern int netns_switch(char *netns);
extern int netns_get_fd(const char *netns);
extern int netns_foreach(int (*func)(char *nsname, void *arg), void *arg);
struct netns_func {
int (*func)(char *nsname, void *arg);
void *arg;
};
#endif /* __NAMESPACE_H__ */
......@@ -5,6 +5,7 @@
#include <asm/types.h>
#include <resolv.h>
#include <stdlib.h>
#include <stdbool.h>
#include "libnetlink.h"
#include "ll_map.h"
......@@ -23,6 +24,7 @@ extern int timestamp_short;
extern char * _SL_;
extern int max_flush_loops;
extern int batch_mode;
extern bool do_all;
#ifndef IPPROTO_ESP
#define IPPROTO_ESP 50
......@@ -162,4 +164,7 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
char **name, char **type, char **link, char **dev,
int *group, int *index);
extern int do_each_netns(int (*func)(char *nsname, void *arg), void *arg,
bool show_label);
#endif /* __UTILS_H__ */
......@@ -36,6 +36,7 @@ char * _SL_ = NULL;
int force = 0;
int max_flush_loops = 10;
int batch_mode = 0;
bool do_all = false;
struct rtnl_handle rth = { .fd = -1 };
......@@ -55,7 +56,7 @@ static void usage(void)
" -4 | -6 | -I | -D | -B | -0 |\n"
" -l[oops] { maximum-addr-flush-attempts } |\n"
" -o[neline] | -t[imestamp] | -ts[hort] | -b[atch] [filename] |\n"
" -rc[vbuf] [size] | -n[etns] name }\n");
" -rc[vbuf] [size] | -n[etns] name | -a[ll] }\n");
exit(-1);
}
......@@ -270,6 +271,8 @@ int main(int argc, char **argv)
NEXT_ARG();
if (netns_switch(argv[1]))
exit(-1);
} else if (matches(opt, "-all") == 0) {
do_all = true;
} else {
fprintf(stderr, "Option \"%s\" is unknown, try \"ip -help\".\n", opt);
exit(-1);
......
......@@ -970,7 +970,8 @@ struct nlmsg_chain
struct nlmsg_list *tail;
};
static int print_selected_addrinfo(int ifindex, struct nlmsg_list *ainfo, FILE *fp)
static int print_selected_addrinfo(struct ifinfomsg *ifi,
struct nlmsg_list *ainfo, FILE *fp)
{
for ( ;ainfo ; ainfo = ainfo->next) {
struct nlmsghdr *n = &ainfo->h;
......@@ -982,10 +983,13 @@ static int print_selected_addrinfo(int ifindex, struct nlmsg_list *ainfo, FILE *
if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifa)))
return -1;
if (ifa->ifa_index != ifindex ||
if (ifa->ifa_index != ifi->ifi_index ||
(filter.family && filter.family != ifa->ifa_family))
continue;
if (filter.up && !(ifi->ifi_flags&IFF_UP))
continue;
print_addrinfo(NULL, n, fp);
}
return 0;
......@@ -1446,7 +1450,7 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
if (no_link || (res = print_linkinfo(NULL, &l->h, stdout)) >= 0) {
struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
if (filter.family != AF_PACKET)
print_selected_addrinfo(ifi->ifi_index,
print_selected_addrinfo(ifi,
ainfo.head, stdout);
if (res > 0 && !do_link && show_stats)
print_link_stats(stdout, &l->h);
......
......@@ -37,6 +37,7 @@ static void print_usage(FILE *f)
"\t[ one-shot { on | off } ]\n"
"\t[ berr-reporting { on | off } ]\n"
"\t[ fd { on | off } ]\n"
"\t[ fd-non-iso { on | off } ]\n"
"\t[ presume-ack { on | off } ]\n"
"\n"
"\t[ restart-ms TIME-MS ]\n"
......@@ -100,6 +101,7 @@ static void print_ctrlmode(FILE *f, __u32 cm)
_PF(CAN_CTRLMODE_ONE_SHOT, "ONE-SHOT");
_PF(CAN_CTRLMODE_BERR_REPORTING, "BERR-REPORTING");
_PF(CAN_CTRLMODE_FD, "FD");
_PF(CAN_CTRLMODE_FD_NON_ISO, "FD-NON-ISO");
_PF(CAN_CTRLMODE_PRESUME_ACK, "PRESUME-ACK");
#undef _PF
if (cm)
......@@ -203,6 +205,10 @@ static int can_parse_opt(struct link_util *lu, int argc, char **argv,
NEXT_ARG();
set_ctrlmode("fd", *argv, &cm,
CAN_CTRLMODE_FD);
} else if (matches(*argv, "fd-non-iso") == 0) {
NEXT_ARG();
set_ctrlmode("fd-non-iso", *argv, &cm,
CAN_CTRLMODE_FD_NON_ISO);
} else if (matches(*argv, "presume-ack") == 0) {
NEXT_ARG();
set_ctrlmode("presume-ack", *argv, &cm,
......
......@@ -30,6 +30,7 @@ static void print_explain(FILE *f)
fprintf(f, " [ [no]l2miss ] [ [no]l3miss ]\n");
fprintf(f, " [ ageing SECONDS ] [ maxaddress NUMBER ]\n");
fprintf(f, " [ [no]udpcsum ] [ [no]udp6zerocsumtx ] [ [no]udp6zerocsumrx ]\n");
fprintf(f, " [ gbp ]\n");
fprintf(f, "\n");
fprintf(f, "Where: VNI := 0-16777215\n");
fprintf(f, " ADDR := { IP_ADDRESS | any }\n");
......@@ -68,6 +69,7 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
__u8 udpcsum = 0;
__u8 udp6zerocsumtx = 0;
__u8 udp6zerocsumrx = 0;
__u8 gbp = 0;
int dst_port_set = 0;
struct ifla_vxlan_port_range range = { 0, 0 };
......@@ -197,6 +199,8 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
udp6zerocsumrx = 1;
} else if (!matches(*argv, "noudp6zerocsumrx")) {
udp6zerocsumrx = 0;
} else if (!matches(*argv, "gbp")) {
gbp = 1;
} else if (matches(*argv, "help") == 0) {
explain();
return -1;
......@@ -268,6 +272,10 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
if (dstport)
addattr16(n, 1024, IFLA_VXLAN_PORT, htons(dstport));
if (gbp)
addattr_l(n, 1024, IFLA_VXLAN_GBP, NULL, 0);
return 0;
}
......@@ -398,6 +406,9 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
if (tb[IFLA_VXLAN_UDP_ZERO_CSUM6_RX] &&
rta_getattr_u8(tb[IFLA_VXLAN_UDP_ZERO_CSUM6_RX]))
fputs("udp6zerocsumrx ", f);
if (tb[IFLA_VXLAN_GBP])
fputs("gbp ", f);
}
static void vxlan_print_help(struct link_util *lu, int argc, char **argv,
......
......@@ -23,10 +23,10 @@ static int usage(void)
{
fprintf(stderr, "Usage: ip netns list\n");
fprintf(stderr, " ip netns add NAME\n");
fprintf(stderr, " ip netns delete NAME\n");
fprintf(stderr, " ip [-all] netns delete [NAME]\n");
fprintf(stderr, " ip netns identify [PID]\n");
fprintf(stderr, " ip netns pids NAME\n");
fprintf(stderr, " ip netns exec NAME cmd ...\n");
fprintf(stderr, " ip [-all] netns exec [NAME] cmd ...\n");
fprintf(stderr, " ip netns monitor\n");
exit(-1);
}
......@@ -51,29 +51,10 @@ static int netns_list(int argc, char **argv)
return 0;
}
static int netns_exec(int argc, char **argv)
static int cmd_exec(const char *cmd, char **argv, bool do_fork)
{
/* Setup the proper environment for apps that are not netns
* aware, and execute a program in that environment.
*/
const char *cmd;
if (argc < 1) {
fprintf(stderr, "No netns name specified\n");
return -1;
}
if (argc < 2) {
fprintf(stderr, "No command specified\n");
return -1;
}
cmd = argv[1];
if (netns_switch(argv[0]))
return -1;
fflush(stdout);
if (batch_mode) {
if (do_fork) {
int status;
pid_t pid;
......@@ -91,23 +72,56 @@ static int netns_exec(int argc, char **argv)
}
if (WIFEXITED(status)) {
/* ip must return the status of the child,
* but do_cmd() will add a minus to this,
* so let's add another one here to cancel it.
*/
return -WEXITSTATUS(status);
return WEXITSTATUS(status);
}
exit(1);
}
}
if (execvp(cmd, argv + 1) < 0)
if (execvp(cmd, argv) < 0)
fprintf(stderr, "exec of \"%s\" failed: %s\n",
cmd, strerror(errno));
cmd, strerror(errno));
_exit(1);
}
static int on_netns_exec(char *nsname, void *arg)
{
char **argv = arg;
cmd_exec(argv[1], argv + 1, true);
return 0;
}
static int netns_exec(int argc, char **argv)
{
/* Setup the proper environment for apps that are not netns
* aware, and execute a program in that environment.
*/
const char *cmd;
if (argc < 1 && !do_all) {
fprintf(stderr, "No netns name specified\n");
return -1;
}
if ((argc < 2 && !do_all) || (argc < 1 && do_all)) {
fprintf(stderr, "No command specified\n");
return -1;
}
if (do_all)
return do_each_netns(on_netns_exec, --argv, 1);
if (netns_switch(argv[0]))
return -1;
/* ip must return the status of the child,
* but do_cmd() will add a minus to this,
* so let's add another one here to cancel it.
*/
cmd = argv[1];
return -cmd_exec(cmd, argv + 1, !!batch_mode);
}
static int is_pid(const char *str)
{
int ch;
......@@ -245,18 +259,11 @@ static int netns_identify(int argc, char **argv)
}
static int netns_delete(int argc, char **argv)
static int on_netns_del(char *nsname, void *arg)
{
const char *name;
char netns_path[MAXPATHLEN];
if (argc < 1) {
fprintf(stderr, "No netns name specified\n");
return -1;
}
name = argv[0];
snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, nsname);
umount2(netns_path, MNT_DETACH);
if (unlink(netns_path) < 0) {
fprintf(stderr, "Cannot remove namespace file \"%s\": %s\n",
......@@ -266,6 +273,19 @@ static int netns_delete(int argc, char **argv)
return 0;
}
static int netns_delete(int argc, char **argv)
{
if (argc < 1 && !do_all) {
fprintf(stderr, "No netns name specified\n");
return -1;
}
if (do_all)
return netns_foreach(on_netns_del, NULL);
return on_netns_del(argv[0], NULL);
}
static int create_netns_dir(void)
{
/* Create the base netns directory if it doesn't exist */
......
......@@ -31,7 +31,7 @@ static void print_usage(FILE *f)
fprintf(f, " [ ttl TTL ] [ tos TOS ] [ [no]pmtudisc ] [ dev PHYS_DEV ]\n");
fprintf(f, " [ noencap ] [ encap { fou | gue | none } ]\n");
fprintf(f, " [ encap-sport PORT ] [ encap-dport PORT ]\n");
fprintf(f, " [ [no]encap-csum ] [ [no]encap-csum6 ]\n");
fprintf(f, " [ [no]encap-csum ] [ [no]encap-csum6 ] [ [no]encap-remcsum ]\n");
fprintf(f, "\n");
fprintf(f, "Where: NAME := STRING\n");
fprintf(f, " ADDR := { IP_ADDRESS | any }\n");
......@@ -287,6 +287,10 @@ get_failed:
encapflags |= TUNNEL_ENCAP_FLAG_CSUM6;
} else if (strcmp(*argv, "noencap-udp6-csum") == 0) {
encapflags |= ~TUNNEL_ENCAP_FLAG_CSUM6;
} else if (strcmp(*argv, "encap-remcsum") == 0) {
encapflags |= TUNNEL_ENCAP_FLAG_REMCSUM;
} else if (strcmp(*argv, "noencap-remcsum") == 0) {
encapflags |= ~TUNNEL_ENCAP_FLAG_REMCSUM;
} else
usage();
argc--; argv++;
......@@ -445,6 +449,11 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
fputs("encap-csum6 ", f);
else
fputs("noencap-csum6 ", f);
if (flags & TUNNEL_ENCAP_FLAG_REMCSUM)
fputs("encap-remcsum ", f);
else
fputs("noencap-remcsum ", f);
}
}
......
......@@ -31,7 +31,7 @@ static void print_usage(FILE *f, int sit)
fprintf(f, " [ 6rd-prefix ADDR ] [ 6rd-relay_prefix ADDR ] [ 6rd-reset ]\n");
fprintf(f, " [ noencap ] [ encap { fou | gue | none } ]\n");
fprintf(f, " [ encap-sport PORT ] [ encap-dport PORT ]\n");
fprintf(f, " [ [no]encap-csum ] [ [no]encap-csum6 ]\n");
fprintf(f, " [ [no]encap-csum ] [ [no]encap-csum6 ] [ [no]encap-remcsum ]\n");
if (sit) {
fprintf(f, " [ mode { ip6ip | ipip | any } ]\n");
fprintf(f, " [ isatap ]\n");
......@@ -256,6 +256,10 @@ get_failed:
encapflags |= TUNNEL_ENCAP_FLAG_CSUM6;
} else if (strcmp(*argv, "noencap-udp6-csum") == 0) {
encapflags &= ~TUNNEL_ENCAP_FLAG_CSUM6;
} else if (strcmp(*argv, "encap-remcsum") == 0) {
encapflags |= TUNNEL_ENCAP_FLAG_REMCSUM;
} else if (strcmp(*argv, "noencap-remcsum") == 0) {
encapflags &= ~TUNNEL_ENCAP_FLAG_REMCSUM;
} else if (strcmp(*argv, "6rd-prefix") == 0) {
inet_prefix prefix;
NEXT_ARG();
......@@ -438,6 +442,11 @@ static void iptunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[
fputs("encap-csum6 ", f);
else
fputs("noencap-csum6 ", f);
if (flags & TUNNEL_ENCAP_FLAG_REMCSUM)
fputs("encap-remcsum ", f);
else
fputs("noencap-remcsum ", f);
}
}
......
......@@ -99,3 +99,25 @@ int netns_get_fd(const char *name)
}
return open(path, O_RDONLY);
}
int netns_foreach(int (*func)(char *nsname, void *arg), void *arg)
{
DIR *dir;
struct dirent *entry;
dir = opendir(NETNS_RUN_DIR);
if (!dir)
return -1;
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0)
continue;
if (strcmp(entry->d_name, "..") == 0)
continue;
if (func(entry->d_name, arg))
break;
}
closedir(dir);
return 0;
}
......@@ -31,6 +31,7 @@
#include "utils.h"
#include "namespace.h"
int timestamp_short = 0;
......@@ -878,3 +879,30 @@ void print_nlmsg_timestamp(FILE *fp, const struct nlmsghdr *n)
tstr[strlen(tstr)-1] = 0;
fprintf(fp, "Timestamp: %s %lu us\n", tstr, usecs);
}
static int on_netns(char *nsname, void *arg)
{
struct netns_func *f = arg;
if (netns_switch(nsname))
return -1;
return f->func(nsname, f->arg);
}
static int on_netns_label(char *nsname, void *arg)
{
printf("\nnetns: %s\n", nsname);
return on_netns(nsname, arg);
}
int do_each_netns(int (*func)(char *nsname, void *arg), void *arg,
bool show_label)
{
struct netns_func nsf = { .func = func, .arg = arg };
if (show_label)
return netns_foreach(on_netns_label, &nsf);
return netns_foreach(on_netns, &nsf);
}
......@@ -221,13 +221,13 @@ Link types:
- Virtual tunnel interface GRE over IPv4
.sp
.BR gretap
- Virtual L2 tuunel interface GRE over IPv4
- Virtual L2 tunnel interface GRE over IPv4
.sp
.BR ip6gre
- Virtual tuunel interface GRE over IPv6
- Virtual tunnel interface GRE over IPv6
.sp
.BR ip6gretap
- Virtual L2 tuunel interface GRE over IPv6
- Virtual L2 tunnel interface GRE over IPv6
.in -8
.TP
......@@ -276,6 +276,8 @@ the following additional arguments are supported:
.BI ageing " SECONDS "
.R " ] [ "
.BI maxaddress " NUMBER "
.R " ] [ "
.B gbp
.R " ]"
.in +8
......@@ -348,6 +350,106 @@ are entered into the VXLAN device forwarding database.
.BI maxaddress " NUMBER"
- specifies the maximum number of FDB entries.
.sp
.B gbp
- enables the Group Policy extension (VXLAN-GBP).
.in +4
Allows to transport group policy context across VXLAN network peers.
If enabled, includes the mark of a packet in the VXLAN header for outgoing
packets and fills the packet mark based on the information found in the
VXLAN header for incomming packets.
Format of upper 16 bits of packet mark (flags);
.in +2
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
.br
|-|-|-|-|-|-|-|-|-|D|-|-|A|-|-|-|
.br
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
.B D :=
Don't Learn bit. When set, this bit indicates that the egress
VTEP MUST NOT learn the source address of the encapsulated frame.
.B A :=
Indicates that the group policy has already been applied to
this packet. Policies MUST NOT be applied by devices when the A bit is set.
.in -2
Format of lower 16 bits of packet mark (policy ID):
.in +2
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
.br
| Group Policy ID |
.br
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
.in -2
Example:
iptables -A OUTPUT [...] -j MARK --set-mark 0x800FF
.in -4
.in -8
.TP
GRE, IPIP, SIT Type Support
For a link of types
.I GRE/IPIP/SIT
the following additional arguments are supported:
.BI "ip link add " DEVICE
.BR type " { gre | ipip | sit } "
.BI " remote " ADDR " local " ADDR
.R " [ "
.BR encap " { fou | gue | none } "
.R " ] [ "
.BI "encap-sport { " PORT " | auto } "
.R " ] [ "
.BI "encap-dport " PORT
.R " ] [ "
.I " [no]encap-csum "
.R " ] [ "
.I " [no]encap-remcsum "
.R " ]"
.in +8
.sp
.BI remote " ADDR "
- specifies the remote address of the tunnel.
.sp
.BI local " ADDR "
- specifies the fixed local address for tunneled packets.
It must be an address on another interface on this host.
.sp
.BR encap " { fou | gue | none } "
- specifies type of secondary UDP encapsulation. "fou" indicates
Foo-Over-UDP, "gue" indicates Generic UDP Encapsulation.
.sp
.BI "encap-sport { " PORT " | auto } "
- specifies the source port in UDP encapsulation.
.IR PORT
indicates the port by number, "auto"
indicates that the port number should be chosen automatically
(the kernel picks a flow based on the flow hash of the
encapsulated packet).
.sp
.I [no]encap-csum
- specifies if UDP checksums are enabled in the secondary
encapsulation.
.sp
.I [no]encap-remcsum
- specifies if Remote Checksum Offload is enabled. This is only
applicable for Generic UDP Encapsulation.
.in -8
.TP
......@@ -386,7 +488,7 @@ the following additional arguments are supported:
.sp
.BI local " ADDR "
- specifies the fixed local IPv6 address for tunneled packets.
It must be and address on another interface on this host.
It must be an address on another interface on this host.
.sp
.BI [i|o]seq
......@@ -762,6 +864,15 @@ Removes vlan device.
ip link help gre
.RS 4
Display help for the gre link type.
.RE
.PP
ip link add name tun1 type ipip remote 192.168.1.1
local 192.168.1.2 ttl 225 encap gue encap-sport auto
encap-dport 5555 encap-csum encap-remcsum
.RS 4
Creates an IPIP that is encapsulated with Generic UDP Encapsulation,
and the outer UDP checksum and remote checksum offload are enabled.
.RE
.SH SEE ALSO
......
......@@ -16,9 +16,13 @@ ip-netns \- process network namespace management
.BR "ip netns" " { " list " } "
.ti -8
.BR "ip netns" " { " add " | " delete " } "
.B ip netns add
.I NETNSNAME
.ti -8
.B ip [-all] netns del
.RI "[ " NETNSNAME " ]"
.ti -8
.BR "ip netns identify"
.RI "[ " PID " ]"
......@@ -28,8 +32,8 @@ ip-netns \- process network namespace management
.I NETNSNAME
.ti -8
.BR "ip netns exec "
.I NETNSNAME command ...
.BR "ip [-all] netns exec "
.RI "[ " NETNSNAME " ] " command ...
.ti -8
.BR "ip netns monitor"
......@@ -76,7 +80,7 @@ If NAME is available in /var/run/netns/ this command creates a new
network namespace and assigns NAME.
.TP
.B ip netns delete NAME - delete the name of a network namespace
.B ip [-all] netns delete [ NAME ] - delete the name of a network namespace(s)
.sp
If NAME is present in /var/run/netns it is umounted and the mount
point is removed. If this is the last user of the network namespace the
......@@ -84,6 +88,10 @@ network namespace will be freed, otherwise the network namespace
persists until it has no more users. ip netns delete may fail if
the mount point is in use in another mount namespace.
If
.B -all
option was specified then all the network namespace names will be removed.
.TP
.B ip netns identify [PID] - Report network namespaces names for process
.sp
......@@ -98,7 +106,7 @@ This command walks through proc and finds all of the process who have
the named network namespace as their primary network namespace.
.TP
.B ip netns exec NAME cmd ... - Run cmd in the named network namespace
.B ip [-all] netns exec [ NAME ] cmd ... - Run cmd in the named network namespace
.sp
This command allows applications that are network namespace unaware
to be run in something other than the default network namespace with
......@@ -107,6 +115,16 @@ in the customary global locations. A network namespace and bind mounts
are used to move files from their network namespace specific location
to their default locations without affecting other processes.
If
.B -all
option was specified then
.B cmd
will be executed synchronously on the each named network namespace even if
.B cmd
fails on some of them. Network namespace name is printed on each
.B cmd
executing.
.TP
.B ip netns monitor - Report as network namespace names are added and deleted
.sp
......
......@@ -32,7 +32,8 @@ ip \- show / manipulate routing, devices, policy routing and tunnels
\fB\-f\fR[\fIamily\fR] {
.BR inet " | " inet6 " | " ipx " | " dnet " | " link " } | "
\fB\-o\fR[\fIneline\fR] |
\fB\-n\fR[\fIetns\fR] name }
\fB\-n\fR[\fIetns\fR] name |
\fB\-a\fR[\fIll\fR] }
.SH OPTIONS
......@@ -155,6 +156,10 @@ to
.RI "-n[etns] " NETNS " [ " OPTIONS " ] " OBJECT " { " COMMAND " | "
.BR help " }"
.TP
.BR "\-a" , " \-all"
executes specified command over all objects, it depends if command supports this option.
.SH IP - COMMAND SYNTAX
.SS
......
......@@ -84,6 +84,9 @@ context of the creating process, however the context shown will reflect
any policy role, type and/or range transition rules applied,
and is therefore a useful reference.
.TP
.B \-N NSNAME, \-\-net=NSNAME
Switch to the specified network namespace name.
.TP
.B \-b, \-\-bpf
Show socket BPF filters (only administrators are allowed to get these information).
.TP
......
......@@ -10,6 +10,10 @@ ifeq ($(HAVE_SELINUX),y)
CFLAGS += $(shell pkg-config --cflags libselinux) -DHAVE_SELINUX
endif
ifeq ($(IP_CONFIG_SETNS),y)
CFLAGS += -DHAVE_SETNS
endif
all: $(TARGETS)
ss: $(SSOBJ)
......
This diff is collapsed.
TCOBJ= tc.o tc_qdisc.o tc_class.o tc_filter.o tc_util.o \
tc_monitor.o m_police.o m_estimator.o m_action.o \
tc_monitor.o tc_bpf.o m_police.o m_estimator.o m_action.o \
m_ematch.o emp_ematch.yacc.o emp_ematch.lex.o
include ../Config
......@@ -46,6 +46,7 @@ TCMODULES += m_skbedit.o
TCMODULES += m_csum.o
TCMODULES += m_simple.o
TCMODULES += m_vlan.o
TCMODULES += m_bpf.o
TCMODULES += p_ip.o
TCMODULES += p_icmp.o
TCMODULES += p_tcp.o
......
......@@ -26,6 +26,7 @@
#include "utils.h"
#include "tc_util.h"
#include "tc_bpf.h"
static void explain(void)
{
......@@ -44,130 +45,6 @@ static void explain(void)
fprintf(stderr, "NOTE: CLASSID is parsed as hexadecimal input.\n");
}
static int bpf_parse_string(char *arg, bool from_file, __u16 *bpf_len,
char **bpf_string, bool *need_release,
const char separator)
{
char sp;
if (from_file) {
size_t tmp_len, op_len = sizeof("65535 255 255 4294967295,");
char *tmp_string;
FILE *fp;
tmp_len = sizeof("4096,") + BPF_MAXINSNS * op_len;
tmp_string = malloc(tmp_len);
if (tmp_string == NULL)
return -ENOMEM;
memset(tmp_string, 0, tmp_len);
fp = fopen(arg, "r");
if (fp == NULL) {
perror("Cannot fopen");
free(tmp_string);
return -ENOENT;
}
if (!fgets(tmp_string, tmp_len, fp)) {
free(tmp_string);
fclose(fp);
return -EIO;
}
fclose(fp);
*need_release = true;
*bpf_string = tmp_string;
} else {
*need_release = false;
*bpf_string = arg;
}
if (sscanf(*bpf_string, "%hu%c", bpf_len, &sp) != 2 ||
sp != separator) {
if (*need_release)
free(*bpf_string);
return -EINVAL;
}
return 0;
}
static int bpf_parse_ops(int argc, char **argv, struct nlmsghdr *n,
bool from_file)
{
char *bpf_string, *token, separator = ',';
struct sock_filter bpf_ops[BPF_MAXINSNS];
int ret = 0, i = 0;
bool need_release;
__u16 bpf_len = 0;
if (argc < 1)
return -EINVAL;
if (bpf_parse_string(argv[0], from_file, &bpf_len, &bpf_string,
&need_release, separator))
return -EINVAL;
if (bpf_len == 0 || bpf_len > BPF_MAXINSNS) {
ret = -EINVAL;
goto out;
}
token = bpf_string;
while ((token = strchr(token, separator)) && (++token)[0]) {
if (i >= bpf_len) {
fprintf(stderr, "Real program length exceeds encoded "
"length parameter!\n");
ret = -EINVAL;
goto out;
}
if (sscanf(token, "%hu %hhu %hhu %u,",
&bpf_ops[i].code, &bpf_ops[i].jt,
&bpf_ops[i].jf, &bpf_ops[i].k) != 4) {
fprintf(stderr, "Error at instruction %d!\n", i);
ret = -EINVAL;
goto out;
}
i++;
}
if (i != bpf_len) {
fprintf(stderr, "Parsed program length is less than encoded"
"length parameter!\n");
ret = -EINVAL;
goto out;
}
addattr_l(n, MAX_MSG, TCA_BPF_OPS_LEN, &bpf_len, sizeof(bpf_len));
addattr_l(n, MAX_MSG, TCA_BPF_OPS, &bpf_ops,
bpf_len * sizeof(struct sock_filter));
out:
if (need_release)
free(bpf_string);
return ret;
}
static void bpf_print_ops(FILE *f, struct rtattr *bpf_ops, __u16 len)
{
struct sock_filter *ops = (struct sock_filter *) RTA_DATA(bpf_ops);
int i;
if (len == 0)
return;
fprintf(f, "bytecode \'%u,", len);
for (i = 0; i < len - 1; i++)
fprintf(f, "%hu %hhu %hhu %u,", ops[i].code, ops[i].jt,
ops[i].jf, ops[i].k);
fprintf(f, "%hu %hhu %hhu %u\'\n", ops[i].code, ops[i].jt,
ops[i].jf, ops[i].k);
}
static int bpf_parse_opt(struct filter_util *qu, char *handle,
int argc, char **argv, struct nlmsghdr *n)
{
......@@ -195,6 +72,10 @@ static int bpf_parse_opt(struct filter_util *qu, char *handle,
while (argc > 0) {
if (matches(*argv, "run") == 0) {
bool from_file;
struct sock_filter bpf_ops[BPF_MAXINSNS];
__u16 bpf_len;
int ret;
NEXT_ARG();
if (strcmp(*argv, "bytecode-file") == 0) {
from_file = true;
......@@ -206,10 +87,15 @@ static int bpf_parse_opt(struct filter_util *qu, char *handle,
return -1;
}
NEXT_ARG();
if (bpf_parse_ops(argc, argv, n, from_file)) {
ret = bpf_parse_ops(argc, argv, bpf_ops, from_file);
if (ret < 0) {
fprintf(stderr, "Illegal \"bytecode\"\n");
return -1;
}
bpf_len = ret;
addattr16(n, MAX_MSG, TCA_BPF_OPS_LEN, bpf_len);
addattr_l(n, MAX_MSG, TCA_BPF_OPS, &bpf_ops,
bpf_len * sizeof(struct sock_filter));
} else if (matches(*argv, "classid") == 0 ||
strcmp(*argv, "flowid") == 0) {
unsigned handle;
......
/*
* m_bpf.c BFP based action module
*
* 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: Jiri Pirko <jiri@resnulli.us>
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdbool.h>
#include <linux/tc_act/tc_bpf.h>
#include "utils.h"
#include "rt_names.h"
#include "tc_util.h"
#include "tc_bpf.h"
static void explain(void)
{
fprintf(stderr, "Usage: ... bpf ...\n");
fprintf(stderr, "\n");
fprintf(stderr, " [inline]: run bytecode BPF_BYTECODE\n");
fprintf(stderr, " [from file]: run bytecode-file FILE\n");
fprintf(stderr, "\n");
fprintf(stderr, "Where BPF_BYTECODE := \'s,c t f k,c t f k,c t f k,...\'\n");
fprintf(stderr, " c,t,f,k and s are decimals; s denotes number of 4-tuples\n");
fprintf(stderr, "Where FILE points to a file containing the BPF_BYTECODE string\n");
fprintf(stderr, "\nACTION_SPEC := ... look at individual actions\n");
fprintf(stderr, "NOTE: CLASSID is parsed as hexadecimal input.\n");
}
static void usage(void)
{
explain();
exit(-1);
}
static int parse_bpf(struct action_util *a, int *argc_p, char ***argv_p,
int tca_id, struct nlmsghdr *n)
{
int argc = *argc_p;
char **argv = *argv_p;
struct rtattr *tail;
struct tc_act_bpf parm = { 0 };
struct sock_filter bpf_ops[BPF_MAXINSNS];
__u16 bpf_len = 0;
if (matches(*argv, "bpf") != 0)
return -1;
NEXT_ARG();
while (argc > 0) {
if (matches(*argv, "run") == 0) {
bool from_file;
int ret;
NEXT_ARG();
if (strcmp(*argv, "bytecode-file") == 0) {
from_file = true;
} else if (strcmp(*argv, "bytecode") == 0) {
from_file = false;
} else {
fprintf(stderr, "unexpected \"%s\"\n", *argv);
explain();
return -1;
}
NEXT_ARG();
ret = bpf_parse_ops(argc, argv, bpf_ops, from_file);
if (ret < 0) {
fprintf(stderr, "Illegal \"bytecode\"\n");
return -1;
}
bpf_len = ret;
} else if (matches(*argv, "help") == 0) {
usage();
} else {
break;
}
argc--;
argv++;
}
parm.action = TC_ACT_PIPE;
if (argc) {
if (matches(*argv, "reclassify") == 0) {
parm.action = TC_ACT_RECLASSIFY;
NEXT_ARG();
} else if (matches(*argv, "pipe") == 0) {
parm.action = TC_ACT_PIPE;
NEXT_ARG();
} else if (matches(*argv, "drop") == 0 ||
matches(*argv, "shot") == 0) {
parm.action = TC_ACT_SHOT;
NEXT_ARG();
} else if (matches(*argv, "continue") == 0) {
parm.action = TC_ACT_UNSPEC;
NEXT_ARG();
} else if (matches(*argv, "pass") == 0) {
parm.action = TC_ACT_OK;
NEXT_ARG();
}
}
if (argc) {
if (matches(*argv, "index") == 0) {
NEXT_ARG();
if (get_u32(&parm.index, *argv, 10)) {
fprintf(stderr, "bpf: Illegal \"index\"\n");
return -1;
}
argc--;
argv++;
}
}
if (!bpf_len) {
fprintf(stderr, "bpf: Bytecode needs to be passed\n");
explain();
return -1;
}
tail = NLMSG_TAIL(n);
addattr_l(n, MAX_MSG, tca_id, NULL, 0);
addattr_l(n, MAX_MSG, TCA_ACT_BPF_PARMS, &parm, sizeof(parm));
addattr16(n, MAX_MSG, TCA_ACT_BPF_OPS_LEN, bpf_len);
addattr_l(n, MAX_MSG, TCA_ACT_BPF_OPS, &bpf_ops,
bpf_len * sizeof(struct sock_filter));
tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
*argc_p = argc;
*argv_p = argv;
return 0;
}
static int print_bpf(struct action_util *au, FILE *f, struct rtattr *arg)
{
struct rtattr *tb[TCA_ACT_BPF_MAX + 1];
struct tc_act_bpf *parm;
if (arg == NULL)
return -1;
parse_rtattr_nested(tb, TCA_ACT_BPF_MAX, arg);
if (!tb[TCA_ACT_BPF_PARMS]) {
fprintf(f, "[NULL bpf parameters]");
return -1;
}
parm = RTA_DATA(tb[TCA_ACT_BPF_PARMS]);
fprintf(f, " bpf ");
if (tb[TCA_ACT_BPF_OPS] && tb[TCA_ACT_BPF_OPS_LEN])
bpf_print_ops(f, tb[TCA_ACT_BPF_OPS],
rta_getattr_u16(tb[TCA_ACT_BPF_OPS_LEN]));
fprintf(f, "\n\tindex %d ref %d bind %d", parm->index, parm->refcnt,
parm->bindcnt);
if (show_stats) {
if (tb[TCA_ACT_BPF_TM]) {
struct tcf_t *tm = RTA_DATA(tb[TCA_ACT_BPF_TM]);
print_tm(f, tm);
}
}
fprintf(f, "\n ");
return 0;
}
struct action_util bpf_action_util = {
.id = "bpf",
.parse_aopt = parse_bpf,
.print_aopt = print_bpf,
};
/*
* tc_bpf.c BPF common code
*
* This program is free software; you can distribute 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: Daniel Borkmann <dborkman@redhat.com>
* Jiri Pirko <jiri@resnulli.us>
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdbool.h>
#include <errno.h>
#include <linux/filter.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include "utils.h"
#include "tc_util.h"
#include "tc_bpf.h"
int bpf_parse_string(char *arg, bool from_file, __u16 *bpf_len,
char **bpf_string, bool *need_release,
const char separator)
{
char sp;
if (from_file) {
size_t tmp_len, op_len = sizeof("65535 255 255 4294967295,");
char *tmp_string;
FILE *fp;
tmp_len = sizeof("4096,") + BPF_MAXINSNS * op_len;
tmp_string = malloc(tmp_len);
if (tmp_string == NULL)
return -ENOMEM;
memset(tmp_string, 0, tmp_len);
fp = fopen(arg, "r");
if (fp == NULL) {
perror("Cannot fopen");
free(tmp_string);
return -ENOENT;
}
if (!fgets(tmp_string, tmp_len, fp)) {
free(tmp_string);
fclose(fp);
return -EIO;
}
fclose(fp);
*need_release = true;
*bpf_string = tmp_string;
} else {
*need_release = false;
*bpf_string = arg;
}
if (sscanf(*bpf_string, "%hu%c", bpf_len, &sp) != 2 ||
sp != separator) {
if (*need_release)
free(*bpf_string);
return -EINVAL;
}
return 0;
}
int bpf_parse_ops(int argc, char **argv, struct sock_filter *bpf_ops,
bool from_file)
{
char *bpf_string, *token, separator = ',';
int ret = 0, i = 0;
bool need_release;
__u16 bpf_len = 0;
if (argc < 1)
return -EINVAL;
if (bpf_parse_string(argv[0], from_file, &bpf_len, &bpf_string,
&need_release, separator))
return -EINVAL;
if (bpf_len == 0 || bpf_len > BPF_MAXINSNS) {
ret = -EINVAL;
goto out;
}
token = bpf_string;
while ((token = strchr(token, separator)) && (++token)[0]) {
if (i >= bpf_len) {
fprintf(stderr, "Real program length exceeds encoded "
"length parameter!\n");
ret = -EINVAL;
goto out;
}
if (sscanf(token, "%hu %hhu %hhu %u,",
&bpf_ops[i].code, &bpf_ops[i].jt,
&bpf_ops[i].jf, &bpf_ops[i].k) != 4) {
fprintf(stderr, "Error at instruction %d!\n", i);
ret = -EINVAL;
goto out;
}
i++;
}
if (i != bpf_len) {
fprintf(stderr, "Parsed program length is less than encoded"
"length parameter!\n");
ret = -EINVAL;
goto out;
}
ret = bpf_len;
out:
if (need_release)
free(bpf_string);
return ret;
}
void bpf_print_ops(FILE *f, struct rtattr *bpf_ops, __u16 len)
{
struct sock_filter *ops = (struct sock_filter *) RTA_DATA(bpf_ops);
int i;
if (len == 0)
return;
fprintf(f, "bytecode \'%u,", len);
for (i = 0; i < len - 1; i++)
fprintf(f, "%hu %hhu %hhu %u,", ops[i].code, ops[i].jt,
ops[i].jf, ops[i].k);
fprintf(f, "%hu %hhu %hhu %u\'\n", ops[i].code, ops[i].jt,
ops[i].jf, ops[i].k);
}
/*
* tc_bpf.h BPF common code
*
* This program is free software; you can distribute 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: Daniel Borkmann <dborkman@redhat.com>
* Jiri Pirko <jiri@resnulli.us>
*/
#ifndef _TC_BPF_H_
#define _TC_BPF_H_ 1
#include <stdio.h>
#include <linux/filter.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
int bpf_parse_string(char *arg, bool from_file, __u16 *bpf_len,
char **bpf_string, bool *need_release,
const char separator);
int bpf_parse_ops(int argc, char **argv, struct sock_filter *bpf_ops,
bool from_file);
void bpf_print_ops(FILE *f, struct rtattr *bpf_ops, __u16 len);
#endif
......@@ -31,12 +31,13 @@ listtests:
alltests: $(TESTS)
clean:
@echo "Removing $(RESULTS_DIR) dir ..."
@rm -rf $(RESULTS_DIR)
distclean: clean
echo "Entering iproute2" && cd iproute2 && $(MAKE) distclean && cd ..;
$(TESTS):
$(TESTS): clean
@mkdir -p $(RESULTS_DIR)
@for d in $(TESTS_DIR); do \
......
......@@ -62,8 +62,9 @@ ts_ip()
TMP_OUT=`mktemp /tmp/tc_testsuite.XXXXXX` || exit
$IP $@ 2> $TMP_ERR > $TMP_OUT
RET=$?
if [ -s $TMP_ERR ]; then
if [ -s $TMP_ERR ] || [ "$RET" != "0" ]; then
ts_err "${SCRIPT}: ${DESC} failed:"
ts_err "command: $IP $@"
ts_err "stderr output:"
......@@ -91,3 +92,8 @@ ts_qdisc_available()
return 1;
fi
}
rand_dev()
{
echo "dev-$(tr -dc "[:alpha:]" < /dev/urandom | head -c 6)"
}
#!/bin/sh
source lib/generic.sh
ts_log "[Testing add/del virtual links]"
NEW_DEV="$(rand_dev)"
ts_ip "$0" "Add $NEW_DEV dummy interface" link add dev $NEW_DEV type dummy
ts_ip "$0" "Show $NEW_DEV dummy interface" link show dev $NEW_DEV
ts_ip "$0" "Del $NEW_DEV dummy interface" link del dev $NEW_DEV
#!/bin/sh
source lib/generic.sh
NL_FILE="tests/ip/link/dev_wo_vf_rate.nl"
ts_ip "$0" "Show VF devices w/o VF rate info" -d monitor file $NL_FILE
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment