Skip to content

Commit 971502d

Browse files
Florian Westphalummakynes
authored andcommitted
bridge: netfilter: unroll NF_HOOK helper in bridge input path
Replace NF_HOOK() based invocation of the netfilter hooks with a private copy of nf_hook_slow(). This copy has one difference: it can return the rx handler value expected by the stack, i.e. RX_HANDLER_CONSUMED or RX_HANDLER_PASS. This is needed by the next patch to invoke the ebtables "broute" table via the standard netfilter hooks rather than the custom "br_should_route_hook" indirection that is used now. When the skb is to be "brouted", we must return RX_HANDLER_PASS from the bridge rx input handler, but there is no way to indicate this via NF_HOOK(), unless perhaps by some hack such as exposing bridge_cb in the netfilter core or a percpu flag. text data bss dec filename 3369 56 0 3425 net/bridge/br_input.o.before 3458 40 0 3498 net/bridge/br_input.o.after This allows removal of the "br_should_route_hook" in the next patch. Signed-off-by: Florian Westphal <[email protected]> Acked-by: David S. Miller <[email protected]> Acked-by: Nikolay Aleksandrov <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent f12064d commit 971502d

File tree

5 files changed

+56
-7
lines changed

5 files changed

+56
-7
lines changed

include/net/netfilter/nf_queue.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,4 +119,7 @@ nfqueue_hash(const struct sk_buff *skb, u16 queue, u16 queues_total, u8 family,
119119
return queue;
120120
}
121121

122+
int nf_queue(struct sk_buff *skb, struct nf_hook_state *state,
123+
const struct nf_hook_entries *entries, unsigned int index,
124+
unsigned int verdict);
122125
#endif /* _NF_QUEUE_H */

net/bridge/br_input.c

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <linux/netdevice.h>
1717
#include <linux/etherdevice.h>
1818
#include <linux/netfilter_bridge.h>
19+
#include <net/netfilter/nf_queue.h>
1920
#include <linux/neighbour.h>
2021
#include <net/arp.h>
2122
#include <linux/export.h>
@@ -206,6 +207,55 @@ static int br_handle_local_finish(struct net *net, struct sock *sk, struct sk_bu
206207
return 0;
207208
}
208209

210+
static int nf_hook_bridge_pre(struct sk_buff *skb, struct sk_buff **pskb)
211+
{
212+
#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE
213+
struct nf_hook_entries *e = NULL;
214+
struct nf_hook_state state;
215+
unsigned int verdict, i;
216+
struct net *net;
217+
int ret;
218+
219+
net = dev_net(skb->dev);
220+
#ifdef HAVE_JUMP_LABEL
221+
if (!static_key_false(&nf_hooks_needed[NFPROTO_BRIDGE][NF_BR_PRE_ROUTING]))
222+
goto frame_finish;
223+
#endif
224+
225+
e = rcu_dereference(net->nf.hooks_bridge[NF_BR_PRE_ROUTING]);
226+
if (!e)
227+
goto frame_finish;
228+
229+
nf_hook_state_init(&state, NF_BR_PRE_ROUTING,
230+
NFPROTO_BRIDGE, skb->dev, NULL, NULL,
231+
net, br_handle_frame_finish);
232+
233+
for (i = 0; i < e->num_hook_entries; i++) {
234+
verdict = nf_hook_entry_hookfn(&e->hooks[i], skb, &state);
235+
switch (verdict & NF_VERDICT_MASK) {
236+
case NF_ACCEPT:
237+
break;
238+
case NF_DROP:
239+
kfree_skb(skb);
240+
return RX_HANDLER_CONSUMED;
241+
case NF_QUEUE:
242+
ret = nf_queue(skb, &state, e, i, verdict);
243+
if (ret == 1)
244+
continue;
245+
return RX_HANDLER_CONSUMED;
246+
default: /* STOLEN */
247+
return RX_HANDLER_CONSUMED;
248+
}
249+
}
250+
frame_finish:
251+
net = dev_net(skb->dev);
252+
br_handle_frame_finish(net, NULL, skb);
253+
#else
254+
br_handle_frame_finish(dev_net(skb->dev), NULL, skb);
255+
#endif
256+
return RX_HANDLER_CONSUMED;
257+
}
258+
209259
/*
210260
* Return NULL if skb is handled
211261
* note: already called with rcu_read_lock
@@ -304,10 +354,7 @@ rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
304354
if (ether_addr_equal(p->br->dev->dev_addr, dest))
305355
skb->pkt_type = PACKET_HOST;
306356

307-
NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING,
308-
dev_net(skb->dev), NULL, skb, skb->dev, NULL,
309-
br_handle_frame_finish);
310-
break;
357+
return nf_hook_bridge_pre(skb, pskb);
311358
default:
312359
drop:
313360
kfree_skb(skb);

net/netfilter/core.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <linux/mm.h>
2424
#include <linux/rcupdate.h>
2525
#include <net/net_namespace.h>
26+
#include <net/netfilter/nf_queue.h>
2627
#include <net/sock.h>
2728

2829
#include "nf_internals.h"

net/netfilter/nf_internals.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@
77
#include <linux/netdevice.h>
88

99
/* nf_queue.c */
10-
int nf_queue(struct sk_buff *skb, struct nf_hook_state *state,
11-
const struct nf_hook_entries *entries, unsigned int index,
12-
unsigned int verdict);
1310
void nf_queue_nf_hook_drop(struct net *net);
1411

1512
/* nf_log.c */

net/netfilter/nf_queue.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ int nf_queue(struct sk_buff *skb, struct nf_hook_state *state,
240240

241241
return 0;
242242
}
243+
EXPORT_SYMBOL_GPL(nf_queue);
243244

244245
static unsigned int nf_iterate(struct sk_buff *skb,
245246
struct nf_hook_state *state,

0 commit comments

Comments
 (0)