1 This patch allows the user to specify desired packet types (outgoing,
2 broadcast, unicast, etc.) on packet sockets via setsockopt.
3 This can reduce the load in situations where only a limited number
4 of packet types are necessary
6 Signed-off-by: Felix Fietkau <nbd@openwrt.org>
8 --- a/include/uapi/linux/if_packet.h
9 +++ b/include/uapi/linux/if_packet.h
10 @@ -29,6 +29,8 @@ struct sockaddr_ll {
11 /* These ones are invisible by user level */
12 #define PACKET_LOOPBACK 5 /* MC/BRD frame looped back */
13 #define PACKET_FASTROUTE 6 /* Fastrouted frame */
14 +#define PACKET_MASK_ANY 0xffffffff /* mask for packet type bits */
17 /* Packet socket options */
19 @@ -51,6 +53,7 @@ struct sockaddr_ll {
20 #define PACKET_TIMESTAMP 17
21 #define PACKET_FANOUT 18
22 #define PACKET_TX_HAS_OFF 19
23 +#define PACKET_RECV_TYPE 20
25 #define PACKET_FANOUT_HASH 0
26 #define PACKET_FANOUT_LB 1
27 --- a/net/packet/af_packet.c
28 +++ b/net/packet/af_packet.c
29 @@ -1273,6 +1273,7 @@ static int packet_rcv_spkt(struct sk_buf
32 struct sockaddr_pkt *spkt;
33 + struct packet_sock *po;
36 * When we registered the protocol we saved the socket in the data
37 @@ -1280,6 +1281,7 @@ static int packet_rcv_spkt(struct sk_buf
40 sk = pt->af_packet_priv;
44 * Yank back the headers [hope the device set this
45 @@ -1292,7 +1294,7 @@ static int packet_rcv_spkt(struct sk_buf
46 * so that this procedure is noop.
49 - if (skb->pkt_type == PACKET_LOOPBACK)
50 + if (!(po->pkt_type & (1 << skb->pkt_type)))
53 if (!net_eq(dev_net(dev), sock_net(sk)))
54 @@ -1498,12 +1500,12 @@ static int packet_rcv(struct sk_buff *sk
55 int skb_len = skb->len;
56 unsigned int snaplen, res;
58 - if (skb->pkt_type == PACKET_LOOPBACK)
61 sk = pt->af_packet_priv;
64 + if (!(po->pkt_type & (1 << skb->pkt_type)))
67 if (!net_eq(dev_net(dev), sock_net(sk)))
70 @@ -1622,12 +1624,12 @@ static int tpacket_rcv(struct sk_buff *s
72 struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
74 - if (skb->pkt_type == PACKET_LOOPBACK)
77 sk = pt->af_packet_priv;
80 + if (!(po->pkt_type & (1 << skb->pkt_type)))
83 if (!net_eq(dev_net(dev), sock_net(sk)))
86 @@ -2539,6 +2541,7 @@ static int packet_create(struct net *net
87 spin_lock_init(&po->bind_lock);
88 mutex_init(&po->pg_vec_lock);
89 po->prot_hook.func = packet_rcv;
90 + po->pkt_type = PACKET_MASK_ANY & ~(1 << PACKET_LOOPBACK);
92 if (sock->type == SOCK_PACKET)
93 po->prot_hook.func = packet_rcv_spkt;
94 @@ -3152,6 +3155,16 @@ packet_setsockopt(struct socket *sock, i
95 po->tp_tx_has_off = !!val;
98 + case PACKET_RECV_TYPE:
101 + if (optlen != sizeof(val))
103 + if (copy_from_user(&val, optval, sizeof(val)))
105 + po->pkt_type = val & ~PACKET_LOOPBACK;
111 @@ -3206,6 +3219,13 @@ static int packet_getsockopt(struct sock
112 case PACKET_VNET_HDR:
113 val = po->has_vnet_hdr;
115 + case PACKET_RECV_TYPE:
116 + if (len > sizeof(unsigned int))
117 + len = sizeof(unsigned int);
118 + val = po->pkt_type;
123 val = po->tp_version;
125 --- a/net/packet/internal.h
126 +++ b/net/packet/internal.h
127 @@ -112,6 +112,7 @@ struct packet_sock {
128 unsigned int tp_tx_has_off:1;
129 unsigned int tp_tstamp;
130 struct packet_type prot_hook ____cacheline_aligned_in_smp;
131 + unsigned int pkt_type;
134 static struct packet_sock *pkt_sk(struct sock *sk)