diff options
author | Willem de Bruijn <willemb@google.com> | 2015-08-14 22:31:35 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-08-17 17:22:48 -0400 |
commit | f2e520956a1ab636698f8160194c9b8ac0989aab (patch) | |
tree | f3ff84457be59fab5303f64b5e5ba93204c3f90b | |
parent | 47dceb8ecdc1c3ad1818dfea3d659a05b74c3fc2 (diff) |
packet: add extended BPF fanout mode
Add fanout mode PACKET_FANOUT_EBPF that accepts an en extended BPF
program to select a socket.
Update the internal eBPF program by passing to socket option
SOL_PACKET/PACKET_FANOUT_DATA a file descriptor returned by bpf().
Signed-off-by: Willem de Bruijn <willemb@google.com>
Acked-by: Alexei Starovoitov <ast@plumgrid.com>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/uapi/linux/if_packet.h | 1 | ||||
-rw-r--r-- | net/packet/af_packet.c | 31 |
2 files changed, 32 insertions, 0 deletions
diff --git a/include/uapi/linux/if_packet.h b/include/uapi/linux/if_packet.h index a4bb16fa822e..9e7edfd8141e 100644 --- a/include/uapi/linux/if_packet.h +++ b/include/uapi/linux/if_packet.h | |||
@@ -64,6 +64,7 @@ struct sockaddr_ll { | |||
64 | #define PACKET_FANOUT_RND 4 | 64 | #define PACKET_FANOUT_RND 4 |
65 | #define PACKET_FANOUT_QM 5 | 65 | #define PACKET_FANOUT_QM 5 |
66 | #define PACKET_FANOUT_CBPF 6 | 66 | #define PACKET_FANOUT_CBPF 6 |
67 | #define PACKET_FANOUT_EBPF 7 | ||
67 | #define PACKET_FANOUT_FLAG_ROLLOVER 0x1000 | 68 | #define PACKET_FANOUT_FLAG_ROLLOVER 0x1000 |
68 | #define PACKET_FANOUT_FLAG_DEFRAG 0x8000 | 69 | #define PACKET_FANOUT_FLAG_DEFRAG 0x8000 |
69 | 70 | ||
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 8869d07013e6..7b8e39a22387 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
@@ -1472,6 +1472,7 @@ static int packet_rcv_fanout(struct sk_buff *skb, struct net_device *dev, | |||
1472 | idx = fanout_demux_rollover(f, skb, 0, false, num); | 1472 | idx = fanout_demux_rollover(f, skb, 0, false, num); |
1473 | break; | 1473 | break; |
1474 | case PACKET_FANOUT_CBPF: | 1474 | case PACKET_FANOUT_CBPF: |
1475 | case PACKET_FANOUT_EBPF: | ||
1475 | idx = fanout_demux_bpf(f, skb, num); | 1476 | idx = fanout_demux_bpf(f, skb, num); |
1476 | break; | 1477 | break; |
1477 | } | 1478 | } |
@@ -1529,6 +1530,7 @@ static void fanout_init_data(struct packet_fanout *f) | |||
1529 | atomic_set(&f->rr_cur, 0); | 1530 | atomic_set(&f->rr_cur, 0); |
1530 | break; | 1531 | break; |
1531 | case PACKET_FANOUT_CBPF: | 1532 | case PACKET_FANOUT_CBPF: |
1533 | case PACKET_FANOUT_EBPF: | ||
1532 | RCU_INIT_POINTER(f->bpf_prog, NULL); | 1534 | RCU_INIT_POINTER(f->bpf_prog, NULL); |
1533 | break; | 1535 | break; |
1534 | } | 1536 | } |
@@ -1571,12 +1573,39 @@ static int fanout_set_data_cbpf(struct packet_sock *po, char __user *data, | |||
1571 | return 0; | 1573 | return 0; |
1572 | } | 1574 | } |
1573 | 1575 | ||
1576 | static int fanout_set_data_ebpf(struct packet_sock *po, char __user *data, | ||
1577 | unsigned int len) | ||
1578 | { | ||
1579 | struct bpf_prog *new; | ||
1580 | u32 fd; | ||
1581 | |||
1582 | if (sock_flag(&po->sk, SOCK_FILTER_LOCKED)) | ||
1583 | return -EPERM; | ||
1584 | if (len != sizeof(fd)) | ||
1585 | return -EINVAL; | ||
1586 | if (copy_from_user(&fd, data, len)) | ||
1587 | return -EFAULT; | ||
1588 | |||
1589 | new = bpf_prog_get(fd); | ||
1590 | if (IS_ERR(new)) | ||
1591 | return PTR_ERR(new); | ||
1592 | if (new->type != BPF_PROG_TYPE_SOCKET_FILTER) { | ||
1593 | bpf_prog_put(new); | ||
1594 | return -EINVAL; | ||
1595 | } | ||
1596 | |||
1597 | __fanout_set_data_bpf(po->fanout, new); | ||
1598 | return 0; | ||
1599 | } | ||
1600 | |||
1574 | static int fanout_set_data(struct packet_sock *po, char __user *data, | 1601 | static int fanout_set_data(struct packet_sock *po, char __user *data, |
1575 | unsigned int len) | 1602 | unsigned int len) |
1576 | { | 1603 | { |
1577 | switch (po->fanout->type) { | 1604 | switch (po->fanout->type) { |
1578 | case PACKET_FANOUT_CBPF: | 1605 | case PACKET_FANOUT_CBPF: |
1579 | return fanout_set_data_cbpf(po, data, len); | 1606 | return fanout_set_data_cbpf(po, data, len); |
1607 | case PACKET_FANOUT_EBPF: | ||
1608 | return fanout_set_data_ebpf(po, data, len); | ||
1580 | default: | 1609 | default: |
1581 | return -EINVAL; | 1610 | return -EINVAL; |
1582 | }; | 1611 | }; |
@@ -1586,6 +1615,7 @@ static void fanout_release_data(struct packet_fanout *f) | |||
1586 | { | 1615 | { |
1587 | switch (f->type) { | 1616 | switch (f->type) { |
1588 | case PACKET_FANOUT_CBPF: | 1617 | case PACKET_FANOUT_CBPF: |
1618 | case PACKET_FANOUT_EBPF: | ||
1589 | __fanout_set_data_bpf(f, NULL); | 1619 | __fanout_set_data_bpf(f, NULL); |
1590 | }; | 1620 | }; |
1591 | } | 1621 | } |
@@ -1608,6 +1638,7 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags) | |||
1608 | case PACKET_FANOUT_RND: | 1638 | case PACKET_FANOUT_RND: |
1609 | case PACKET_FANOUT_QM: | 1639 | case PACKET_FANOUT_QM: |
1610 | case PACKET_FANOUT_CBPF: | 1640 | case PACKET_FANOUT_CBPF: |
1641 | case PACKET_FANOUT_EBPF: | ||
1611 | break; | 1642 | break; |
1612 | default: | 1643 | default: |
1613 | return -EINVAL; | 1644 | return -EINVAL; |