Skip to content
This repository has been archived by the owner on Aug 21, 2018. It is now read-only.

Commit

Permalink
net: add xdp redirect support
Browse files Browse the repository at this point in the history
This adds support for bpf_redirect helper function to the XDP
infrastructure. For now this only supports redirecting to the egress
path of a port.

In order to support drivers handling a xdp_buff natively this patches
uses a new ndo operation ndo_xdp_xmit() that consumes xdp_buff on the
specified device.

If the program specifies either (a) an unknown device or (b) a device
that does not support the operation a BPF warning is thrown and the
XDP_ABORTED error code is returned.

Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
  • Loading branch information
John Fastabend committed Dec 15, 2016
1 parent 19d0a5d commit e78f542
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 0 deletions.
3 changes: 3 additions & 0 deletions include/linux/bpf.h
Expand Up @@ -12,6 +12,7 @@
#include <linux/file.h>
#include <linux/percpu.h>
#include <linux/err.h>
#include <linux/filter.h>

struct perf_event;
struct bpf_map;
Expand Down Expand Up @@ -226,6 +227,8 @@ typedef unsigned long (*bpf_ctx_copy_t)(void *dst, const void *src,
u64 bpf_event_output(struct bpf_map *map, u64 flags, void *meta, u64 meta_size,
void *ctx, u64 ctx_size, bpf_ctx_copy_t ctx_copy);

int xdp_do_redirect(struct net_device *dev, struct xdp_buff *xdp);

#ifdef CONFIG_BPF_SYSCALL
DECLARE_PER_CPU(int, bpf_prog_active);

Expand Down
1 change: 1 addition & 0 deletions include/linux/filter.h
Expand Up @@ -603,6 +603,7 @@ struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off,
const struct bpf_insn *patch, u32 len);
void bpf_warn_invalid_xdp_action(u32 act);
void bpf_warn_invalid_xdp_buffer(void);
void bpf_warn_invalid_xdp_redirect(u32 ifindex);

#ifdef CONFIG_BPF_JIT
extern int bpf_jit_enable;
Expand Down
6 changes: 6 additions & 0 deletions include/linux/netdevice.h
Expand Up @@ -65,6 +65,7 @@ struct mpls_dev;
/* UDP Tunnel offloads */
struct udp_tunnel_info;
struct bpf_prog;
struct xdp_buff;

void netdev_set_default_ethtool_ops(struct net_device *dev,
const struct ethtool_ops *ops);
Expand Down Expand Up @@ -1133,6 +1134,9 @@ struct netdev_xdp {
* int (*ndo_xdp)(struct net_device *dev, struct netdev_xdp *xdp);
* This function is used to set or query state related to XDP on the
* netdevice. See definition of enum xdp_netdev_command for details.
* void (*ndo_xdp_xmit)(struct net_device *dev, struct xdp_buff *xdp);
* This function is used to submit a XDP packet for transmit on a
* netdevice.
*
*/
struct net_device_ops {
Expand Down Expand Up @@ -1324,6 +1328,8 @@ struct net_device_ops {
int needed_headroom);
int (*ndo_xdp)(struct net_device *dev,
struct netdev_xdp *xdp);
void (*ndo_xdp_xmit)(struct net_device *dev,
struct xdp_buff *xdp);
};

/**
Expand Down
1 change: 1 addition & 0 deletions include/uapi/linux/bpf.h
Expand Up @@ -595,6 +595,7 @@ enum xdp_action {
XDP_DROP,
XDP_PASS,
XDP_TX,
XDP_REDIRECT,
};

/* user accessible metadata for XDP packet hook
Expand Down
52 changes: 52 additions & 0 deletions net/core/filter.c
Expand Up @@ -2255,6 +2255,50 @@ static const struct bpf_func_proto bpf_xdp_adjust_head_proto = {
.arg2_type = ARG_ANYTHING,
};

static int __bpf_tx_xdp(struct net_device *dev, struct xdp_buff *xdp)
{
if (dev->netdev_ops->ndo_xdp_xmit) {
dev->netdev_ops->ndo_xdp_xmit(dev, xdp);
return 0;
}
bpf_warn_invalid_xdp_redirect(dev->ifindex);
return -EOPNOTSUPP;
}

int xdp_do_redirect(struct net_device *dev, struct xdp_buff *xdp)
{
struct redirect_info *ri = this_cpu_ptr(&redirect_info);

dev = dev_get_by_index_rcu(dev_net(dev), ri->ifindex);
ri->ifindex = 0;
if (unlikely(!dev)) {
bpf_warn_invalid_xdp_redirect(ri->ifindex);
return -EINVAL;
}

return __bpf_tx_xdp(dev, xdp);
}
EXPORT_SYMBOL_GPL(xdp_do_redirect);

BPF_CALL_2(bpf_xdp_redirect, u32, ifindex, u64, flags)
{
struct redirect_info *ri = this_cpu_ptr(&redirect_info);

if (unlikely(flags))
return XDP_ABORTED;

ri->ifindex = ifindex;
return XDP_REDIRECT;
}

static const struct bpf_func_proto bpf_xdp_redirect_proto = {
.func = bpf_xdp_redirect,
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_ANYTHING,
.arg2_type = ARG_ANYTHING,
};

bool bpf_helper_changes_pkt_data(void *func)
{
if (func == bpf_skb_vlan_push ||
Expand Down Expand Up @@ -2694,6 +2738,8 @@ xdp_func_proto(enum bpf_func_id func_id)
return &bpf_get_smp_processor_id_proto;
case BPF_FUNC_xdp_adjust_head:
return &bpf_xdp_adjust_head_proto;
case BPF_FUNC_redirect:
return &bpf_xdp_redirect_proto;
default:
return sk_filter_func_proto(func_id);
}
Expand Down Expand Up @@ -2978,6 +3024,12 @@ void bpf_warn_invalid_xdp_buffer(void)
}
EXPORT_SYMBOL_GPL(bpf_warn_invalid_xdp_buffer);

void bpf_warn_invalid_xdp_redirect(u32 ifindex)
{
WARN_ONCE(1, "Illegal XDP redirect to unsupported device ifindex(%i)\n", ifindex);
}
EXPORT_SYMBOL_GPL(bpf_warn_invalid_xdp_redirect);

static u32 sk_filter_convert_ctx_access(enum bpf_access_type type, int dst_reg,
int src_reg, int ctx_off,
struct bpf_insn *insn_buf,
Expand Down

0 comments on commit e78f542

Please sign in to comment.