Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net

Several cases of bug fixes in 'net' overlapping other changes in
'net-next-.

Signed-off-by: David S. Miller <[email protected]>
This commit is contained in:
David S. Miller 2016-11-15 10:54:36 -05:00
commit bb598c1b8c
580 changed files with 7286 additions and 4003 deletions

View file

@ -26,6 +26,7 @@ hostprogs-y += xdp2
hostprogs-y += test_current_task_under_cgroup
hostprogs-y += trace_event
hostprogs-y += sampleip
hostprogs-y += tc_l2_redirect
sock_example-objs := sock_example.o libbpf.o
fds_example-objs := bpf_load.o libbpf.o fds_example.o
@ -53,6 +54,7 @@ test_current_task_under_cgroup-objs := bpf_load.o libbpf.o \
test_current_task_under_cgroup_user.o
trace_event-objs := bpf_load.o libbpf.o trace_event_user.o
sampleip-objs := bpf_load.o libbpf.o sampleip_user.o
tc_l2_redirect-objs := bpf_load.o libbpf.o tc_l2_redirect_user.o
# Tell kbuild to always build the programs
always := $(hostprogs-y)
@ -69,6 +71,7 @@ always += test_probe_write_user_kern.o
always += trace_output_kern.o
always += tcbpf1_kern.o
always += tcbpf2_kern.o
always += tc_l2_redirect_kern.o
always += lathist_kern.o
always += offwaketime_kern.o
always += spintest_kern.o
@ -108,6 +111,7 @@ HOSTLOADLIBES_xdp2 += -lelf
HOSTLOADLIBES_test_current_task_under_cgroup += -lelf
HOSTLOADLIBES_trace_event += -lelf
HOSTLOADLIBES_sampleip += -lelf
HOSTLOADLIBES_tc_l2_redirect += -l elf
# Allows pointing LLC/CLANG to a LLVM backend with bpf support, redefine on cmdline:
# make samples/bpf/ LLC=~/git/llvm/build/bin/llc CLANG=~/git/llvm/build/bin/clang

173
samples/bpf/tc_l2_redirect.sh Executable file
View file

@ -0,0 +1,173 @@
#!/bin/bash
[[ -z $TC ]] && TC='tc'
[[ -z $IP ]] && IP='ip'
REDIRECT_USER='./tc_l2_redirect'
REDIRECT_BPF='./tc_l2_redirect_kern.o'
RP_FILTER=$(< /proc/sys/net/ipv4/conf/all/rp_filter)
IPV6_FORWARDING=$(< /proc/sys/net/ipv6/conf/all/forwarding)
function config_common {
local tun_type=$1
$IP netns add ns1
$IP netns add ns2
$IP link add ve1 type veth peer name vens1
$IP link add ve2 type veth peer name vens2
$IP link set dev ve1 up
$IP link set dev ve2 up
$IP link set dev ve1 mtu 1500
$IP link set dev ve2 mtu 1500
$IP link set dev vens1 netns ns1
$IP link set dev vens2 netns ns2
$IP -n ns1 link set dev lo up
$IP -n ns1 link set dev vens1 up
$IP -n ns1 addr add 10.1.1.101/24 dev vens1
$IP -n ns1 addr add 2401:db01::65/64 dev vens1 nodad
$IP -n ns1 route add default via 10.1.1.1 dev vens1
$IP -n ns1 route add default via 2401:db01::1 dev vens1
$IP -n ns2 link set dev lo up
$IP -n ns2 link set dev vens2 up
$IP -n ns2 addr add 10.2.1.102/24 dev vens2
$IP -n ns2 addr add 2401:db02::66/64 dev vens2 nodad
$IP -n ns2 addr add 10.10.1.102 dev lo
$IP -n ns2 addr add 2401:face::66/64 dev lo nodad
$IP -n ns2 link add ipt2 type ipip local 10.2.1.102 remote 10.2.1.1
$IP -n ns2 link add ip6t2 type ip6tnl mode any local 2401:db02::66 remote 2401:db02::1
$IP -n ns2 link set dev ipt2 up
$IP -n ns2 link set dev ip6t2 up
$IP netns exec ns2 $TC qdisc add dev vens2 clsact
$IP netns exec ns2 $TC filter add dev vens2 ingress bpf da obj $REDIRECT_BPF sec drop_non_tun_vip
if [[ $tun_type == "ipip" ]]; then
$IP -n ns2 route add 10.1.1.0/24 dev ipt2
$IP netns exec ns2 sysctl -q -w net.ipv4.conf.all.rp_filter=0
$IP netns exec ns2 sysctl -q -w net.ipv4.conf.ipt2.rp_filter=0
else
$IP -n ns2 route add 10.1.1.0/24 dev ip6t2
$IP -n ns2 route add 2401:db01::/64 dev ip6t2
$IP netns exec ns2 sysctl -q -w net.ipv4.conf.all.rp_filter=0
$IP netns exec ns2 sysctl -q -w net.ipv4.conf.ip6t2.rp_filter=0
fi
$IP addr add 10.1.1.1/24 dev ve1
$IP addr add 2401:db01::1/64 dev ve1 nodad
$IP addr add 10.2.1.1/24 dev ve2
$IP addr add 2401:db02::1/64 dev ve2 nodad
$TC qdisc add dev ve2 clsact
$TC filter add dev ve2 ingress bpf da obj $REDIRECT_BPF sec l2_to_iptun_ingress_forward
sysctl -q -w net.ipv4.conf.all.rp_filter=0
sysctl -q -w net.ipv6.conf.all.forwarding=1
}
function cleanup {
set +e
[[ -z $DEBUG ]] || set +x
$IP netns delete ns1 >& /dev/null
$IP netns delete ns2 >& /dev/null
$IP link del ve1 >& /dev/null
$IP link del ve2 >& /dev/null
$IP link del ipt >& /dev/null
$IP link del ip6t >& /dev/null
sysctl -q -w net.ipv4.conf.all.rp_filter=$RP_FILTER
sysctl -q -w net.ipv6.conf.all.forwarding=$IPV6_FORWARDING
rm -f /sys/fs/bpf/tc/globals/tun_iface
[[ -z $DEBUG ]] || set -x
set -e
}
function l2_to_ipip {
echo -n "l2_to_ipip $1: "
local dir=$1
config_common ipip
$IP link add ipt type ipip external
$IP link set dev ipt up
sysctl -q -w net.ipv4.conf.ipt.rp_filter=0
sysctl -q -w net.ipv4.conf.ipt.forwarding=1
if [[ $dir == "egress" ]]; then
$IP route add 10.10.1.0/24 via 10.2.1.102 dev ve2
$TC filter add dev ve2 egress bpf da obj $REDIRECT_BPF sec l2_to_iptun_ingress_redirect
sysctl -q -w net.ipv4.conf.ve1.forwarding=1
else
$TC qdisc add dev ve1 clsact
$TC filter add dev ve1 ingress bpf da obj $REDIRECT_BPF sec l2_to_iptun_ingress_redirect
fi
$REDIRECT_USER -U /sys/fs/bpf/tc/globals/tun_iface -i $(< /sys/class/net/ipt/ifindex)
$IP netns exec ns1 ping -c1 10.10.1.102 >& /dev/null
if [[ $dir == "egress" ]]; then
# test direct egress to ve2 (i.e. not forwarding from
# ve1 to ve2).
ping -c1 10.10.1.102 >& /dev/null
fi
cleanup
echo "OK"
}
function l2_to_ip6tnl {
echo -n "l2_to_ip6tnl $1: "
local dir=$1
config_common ip6tnl
$IP link add ip6t type ip6tnl mode any external
$IP link set dev ip6t up
sysctl -q -w net.ipv4.conf.ip6t.rp_filter=0
sysctl -q -w net.ipv4.conf.ip6t.forwarding=1
if [[ $dir == "egress" ]]; then
$IP route add 10.10.1.0/24 via 10.2.1.102 dev ve2
$IP route add 2401:face::/64 via 2401:db02::66 dev ve2
$TC filter add dev ve2 egress bpf da obj $REDIRECT_BPF sec l2_to_ip6tun_ingress_redirect
sysctl -q -w net.ipv4.conf.ve1.forwarding=1
else
$TC qdisc add dev ve1 clsact
$TC filter add dev ve1 ingress bpf da obj $REDIRECT_BPF sec l2_to_ip6tun_ingress_redirect
fi
$REDIRECT_USER -U /sys/fs/bpf/tc/globals/tun_iface -i $(< /sys/class/net/ip6t/ifindex)
$IP netns exec ns1 ping -c1 10.10.1.102 >& /dev/null
$IP netns exec ns1 ping -6 -c1 2401:face::66 >& /dev/null
if [[ $dir == "egress" ]]; then
# test direct egress to ve2 (i.e. not forwarding from
# ve1 to ve2).
ping -c1 10.10.1.102 >& /dev/null
ping -6 -c1 2401:face::66 >& /dev/null
fi
cleanup
echo "OK"
}
cleanup
test_names="l2_to_ipip l2_to_ip6tnl"
test_dirs="ingress egress"
if [[ $# -ge 2 ]]; then
test_names=$1
test_dirs=$2
elif [[ $# -ge 1 ]]; then
test_names=$1
fi
for t in $test_names; do
for d in $test_dirs; do
$t $d
done
done

View file

@ -0,0 +1,236 @@
/* Copyright (c) 2016 Facebook
*
* 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.
*/
#include <uapi/linux/bpf.h>
#include <uapi/linux/if_ether.h>
#include <uapi/linux/if_packet.h>
#include <uapi/linux/ip.h>
#include <uapi/linux/ipv6.h>
#include <uapi/linux/in.h>
#include <uapi/linux/tcp.h>
#include <uapi/linux/filter.h>
#include <uapi/linux/pkt_cls.h>
#include <net/ipv6.h>
#include "bpf_helpers.h"
#define _htonl __builtin_bswap32
#define PIN_GLOBAL_NS 2
struct bpf_elf_map {
__u32 type;
__u32 size_key;
__u32 size_value;
__u32 max_elem;
__u32 flags;
__u32 id;
__u32 pinning;
};
/* copy of 'struct ethhdr' without __packed */
struct eth_hdr {
unsigned char h_dest[ETH_ALEN];
unsigned char h_source[ETH_ALEN];
unsigned short h_proto;
};
struct bpf_elf_map SEC("maps") tun_iface = {
.type = BPF_MAP_TYPE_ARRAY,
.size_key = sizeof(int),
.size_value = sizeof(int),
.pinning = PIN_GLOBAL_NS,
.max_elem = 1,
};
static __always_inline bool is_vip_addr(__be16 eth_proto, __be32 daddr)
{
if (eth_proto == htons(ETH_P_IP))
return (_htonl(0xffffff00) & daddr) == _htonl(0x0a0a0100);
else if (eth_proto == htons(ETH_P_IPV6))
return (daddr == _htonl(0x2401face));
return false;
}
SEC("l2_to_iptun_ingress_forward")
int _l2_to_iptun_ingress_forward(struct __sk_buff *skb)
{
struct bpf_tunnel_key tkey = {};
void *data = (void *)(long)skb->data;
struct eth_hdr *eth = data;
void *data_end = (void *)(long)skb->data_end;
int key = 0, *ifindex;
int ret;
if (data + sizeof(*eth) > data_end)
return TC_ACT_OK;
ifindex = bpf_map_lookup_elem(&tun_iface, &key);
if (!ifindex)
return TC_ACT_OK;
if (eth->h_proto == htons(ETH_P_IP)) {
char fmt4[] = "ingress forward to ifindex:%d daddr4:%x\n";
struct iphdr *iph = data + sizeof(*eth);
if (data + sizeof(*eth) + sizeof(*iph) > data_end)
return TC_ACT_OK;
if (iph->protocol != IPPROTO_IPIP)
return TC_ACT_OK;
bpf_trace_printk(fmt4, sizeof(fmt4), *ifindex,
_htonl(iph->daddr));
return bpf_redirect(*ifindex, BPF_F_INGRESS);
} else if (eth->h_proto == htons(ETH_P_IPV6)) {
char fmt6[] = "ingress forward to ifindex:%d daddr6:%x::%x\n";
struct ipv6hdr *ip6h = data + sizeof(*eth);
if (data + sizeof(*eth) + sizeof(*ip6h) > data_end)
return TC_ACT_OK;
if (ip6h->nexthdr != IPPROTO_IPIP &&
ip6h->nexthdr != IPPROTO_IPV6)
return TC_ACT_OK;
bpf_trace_printk(fmt6, sizeof(fmt6), *ifindex,
_htonl(ip6h->daddr.s6_addr32[0]),
_htonl(ip6h->daddr.s6_addr32[3]));
return bpf_redirect(*ifindex, BPF_F_INGRESS);
}
return TC_ACT_OK;
}
SEC("l2_to_iptun_ingress_redirect")
int _l2_to_iptun_ingress_redirect(struct __sk_buff *skb)
{
struct bpf_tunnel_key tkey = {};
void *data = (void *)(long)skb->data;
struct eth_hdr *eth = data;
void *data_end = (void *)(long)skb->data_end;
int key = 0, *ifindex;
int ret;
if (data + sizeof(*eth) > data_end)
return TC_ACT_OK;
ifindex = bpf_map_lookup_elem(&tun_iface, &key);
if (!ifindex)
return TC_ACT_OK;
if (eth->h_proto == htons(ETH_P_IP)) {
char fmt4[] = "e/ingress redirect daddr4:%x to ifindex:%d\n";
struct iphdr *iph = data + sizeof(*eth);
__be32 daddr = iph->daddr;
if (data + sizeof(*eth) + sizeof(*iph) > data_end)
return TC_ACT_OK;
if (!is_vip_addr(eth->h_proto, daddr))
return TC_ACT_OK;
bpf_trace_printk(fmt4, sizeof(fmt4), _htonl(daddr), *ifindex);
} else {
return TC_ACT_OK;
}
tkey.tunnel_id = 10000;
tkey.tunnel_ttl = 64;
tkey.remote_ipv4 = 0x0a020166; /* 10.2.1.102 */
bpf_skb_set_tunnel_key(skb, &tkey, sizeof(tkey), 0);
return bpf_redirect(*ifindex, 0);
}
SEC("l2_to_ip6tun_ingress_redirect")
int _l2_to_ip6tun_ingress_redirect(struct __sk_buff *skb)
{
struct bpf_tunnel_key tkey = {};
void *data = (void *)(long)skb->data;
struct eth_hdr *eth = data;
void *data_end = (void *)(long)skb->data_end;
int key = 0, *ifindex;
if (data + sizeof(*eth) > data_end)
return TC_ACT_OK;
ifindex = bpf_map_lookup_elem(&tun_iface, &key);
if (!ifindex)
return TC_ACT_OK;
if (eth->h_proto == htons(ETH_P_IP)) {
char fmt4[] = "e/ingress redirect daddr4:%x to ifindex:%d\n";
struct iphdr *iph = data + sizeof(*eth);
if (data + sizeof(*eth) + sizeof(*iph) > data_end)
return TC_ACT_OK;
if (!is_vip_addr(eth->h_proto, iph->daddr))
return TC_ACT_OK;
bpf_trace_printk(fmt4, sizeof(fmt4), _htonl(iph->daddr),
*ifindex);
} else if (eth->h_proto == htons(ETH_P_IPV6)) {
char fmt6[] = "e/ingress redirect daddr6:%x to ifindex:%d\n";
struct ipv6hdr *ip6h = data + sizeof(*eth);
if (data + sizeof(*eth) + sizeof(*ip6h) > data_end)
return TC_ACT_OK;
if (!is_vip_addr(eth->h_proto, ip6h->daddr.s6_addr32[0]))
return TC_ACT_OK;
bpf_trace_printk(fmt6, sizeof(fmt6),
_htonl(ip6h->daddr.s6_addr32[0]), *ifindex);
} else {
return TC_ACT_OK;
}
tkey.tunnel_id = 10000;
tkey.tunnel_ttl = 64;
/* 2401:db02:0:0:0:0:0:66 */
tkey.remote_ipv6[0] = _htonl(0x2401db02);
tkey.remote_ipv6[1] = 0;
tkey.remote_ipv6[2] = 0;
tkey.remote_ipv6[3] = _htonl(0x00000066);
bpf_skb_set_tunnel_key(skb, &tkey, sizeof(tkey), BPF_F_TUNINFO_IPV6);
return bpf_redirect(*ifindex, 0);
}
SEC("drop_non_tun_vip")
int _drop_non_tun_vip(struct __sk_buff *skb)
{
struct bpf_tunnel_key tkey = {};
void *data = (void *)(long)skb->data;
struct eth_hdr *eth = data;
void *data_end = (void *)(long)skb->data_end;
if (data + sizeof(*eth) > data_end)
return TC_ACT_OK;
if (eth->h_proto == htons(ETH_P_IP)) {
struct iphdr *iph = data + sizeof(*eth);
if (data + sizeof(*eth) + sizeof(*iph) > data_end)
return TC_ACT_OK;
if (is_vip_addr(eth->h_proto, iph->daddr))
return TC_ACT_SHOT;
} else if (eth->h_proto == htons(ETH_P_IPV6)) {
struct ipv6hdr *ip6h = data + sizeof(*eth);
if (data + sizeof(*eth) + sizeof(*ip6h) > data_end)
return TC_ACT_OK;
if (is_vip_addr(eth->h_proto, ip6h->daddr.s6_addr32[0]))
return TC_ACT_SHOT;
}
return TC_ACT_OK;
}
char _license[] SEC("license") = "GPL";

View file

@ -0,0 +1,73 @@
/* Copyright (c) 2016 Facebook
*
* 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.
*/
#include <linux/unistd.h>
#include <linux/bpf.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include "libbpf.h"
static void usage(void)
{
printf("Usage: tc_l2_ipip_redirect [...]\n");
printf(" -U <file> Update an already pinned BPF array\n");
printf(" -i <ifindex> Interface index\n");
printf(" -h Display this help\n");
}
int main(int argc, char **argv)
{
const char *pinned_file = NULL;
int ifindex = -1;
int array_key = 0;
int array_fd = -1;
int ret = -1;
int opt;
while ((opt = getopt(argc, argv, "F:U:i:")) != -1) {
switch (opt) {
/* General args */
case 'U':
pinned_file = optarg;
break;
case 'i':
ifindex = atoi(optarg);
break;
default:
usage();
goto out;
}
}
if (ifindex < 0 || !pinned_file) {
usage();
goto out;
}
array_fd = bpf_obj_get(pinned_file);
if (array_fd < 0) {
fprintf(stderr, "bpf_obj_get(%s): %s(%d)\n",
pinned_file, strerror(errno), errno);
goto out;
}
/* bpf_tunnel_key.remote_ipv4 expects host byte orders */
ret = bpf_update_elem(array_fd, &array_key, &ifindex, 0);
if (ret) {
perror("bpf_update_elem");
goto out;
}
out:
if (array_fd != -1)
close(array_fd);
return ret;
}