mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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 <fw@strlen.de> Acked-by: David S. Miller <davem@davemloft.net> Acked-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
		
							parent
							
								
									f12064d1b4
								
							
						
					
					
						commit
						971502d77f
					
				
					 5 changed files with 56 additions and 7 deletions
				
			
		| 
						 | 
					@ -119,4 +119,7 @@ nfqueue_hash(const struct sk_buff *skb, u16 queue, u16 queues_total, u8 family,
 | 
				
			||||||
	return queue;
 | 
						return queue;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int nf_queue(struct sk_buff *skb, struct nf_hook_state *state,
 | 
				
			||||||
 | 
						     const struct nf_hook_entries *entries, unsigned int index,
 | 
				
			||||||
 | 
						     unsigned int verdict);
 | 
				
			||||||
#endif /* _NF_QUEUE_H */
 | 
					#endif /* _NF_QUEUE_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,6 +16,7 @@
 | 
				
			||||||
#include <linux/netdevice.h>
 | 
					#include <linux/netdevice.h>
 | 
				
			||||||
#include <linux/etherdevice.h>
 | 
					#include <linux/etherdevice.h>
 | 
				
			||||||
#include <linux/netfilter_bridge.h>
 | 
					#include <linux/netfilter_bridge.h>
 | 
				
			||||||
 | 
					#include <net/netfilter/nf_queue.h>
 | 
				
			||||||
#include <linux/neighbour.h>
 | 
					#include <linux/neighbour.h>
 | 
				
			||||||
#include <net/arp.h>
 | 
					#include <net/arp.h>
 | 
				
			||||||
#include <linux/export.h>
 | 
					#include <linux/export.h>
 | 
				
			||||||
| 
						 | 
					@ -206,6 +207,55 @@ static int br_handle_local_finish(struct net *net, struct sock *sk, struct sk_bu
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int nf_hook_bridge_pre(struct sk_buff *skb, struct sk_buff **pskb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE
 | 
				
			||||||
 | 
						struct nf_hook_entries *e = NULL;
 | 
				
			||||||
 | 
						struct nf_hook_state state;
 | 
				
			||||||
 | 
						unsigned int verdict, i;
 | 
				
			||||||
 | 
						struct net *net;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						net = dev_net(skb->dev);
 | 
				
			||||||
 | 
					#ifdef HAVE_JUMP_LABEL
 | 
				
			||||||
 | 
						if (!static_key_false(&nf_hooks_needed[NFPROTO_BRIDGE][NF_BR_PRE_ROUTING]))
 | 
				
			||||||
 | 
							goto frame_finish;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						e = rcu_dereference(net->nf.hooks_bridge[NF_BR_PRE_ROUTING]);
 | 
				
			||||||
 | 
						if (!e)
 | 
				
			||||||
 | 
							goto frame_finish;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						nf_hook_state_init(&state, NF_BR_PRE_ROUTING,
 | 
				
			||||||
 | 
								   NFPROTO_BRIDGE, skb->dev, NULL, NULL,
 | 
				
			||||||
 | 
								   net, br_handle_frame_finish);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < e->num_hook_entries; i++) {
 | 
				
			||||||
 | 
							verdict = nf_hook_entry_hookfn(&e->hooks[i], skb, &state);
 | 
				
			||||||
 | 
							switch (verdict & NF_VERDICT_MASK) {
 | 
				
			||||||
 | 
							case NF_ACCEPT:
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case NF_DROP:
 | 
				
			||||||
 | 
								kfree_skb(skb);
 | 
				
			||||||
 | 
								return RX_HANDLER_CONSUMED;
 | 
				
			||||||
 | 
							case NF_QUEUE:
 | 
				
			||||||
 | 
								ret = nf_queue(skb, &state, e, i, verdict);
 | 
				
			||||||
 | 
								if (ret == 1)
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								return RX_HANDLER_CONSUMED;
 | 
				
			||||||
 | 
							default: /* STOLEN */
 | 
				
			||||||
 | 
								return RX_HANDLER_CONSUMED;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					frame_finish:
 | 
				
			||||||
 | 
						net = dev_net(skb->dev);
 | 
				
			||||||
 | 
						br_handle_frame_finish(net, NULL, skb);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						br_handle_frame_finish(dev_net(skb->dev), NULL, skb);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						return RX_HANDLER_CONSUMED;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Return NULL if skb is handled
 | 
					 * Return NULL if skb is handled
 | 
				
			||||||
 * note: already called with rcu_read_lock
 | 
					 * note: already called with rcu_read_lock
 | 
				
			||||||
| 
						 | 
					@ -304,10 +354,7 @@ rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
 | 
				
			||||||
		if (ether_addr_equal(p->br->dev->dev_addr, dest))
 | 
							if (ether_addr_equal(p->br->dev->dev_addr, dest))
 | 
				
			||||||
			skb->pkt_type = PACKET_HOST;
 | 
								skb->pkt_type = PACKET_HOST;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING,
 | 
							return nf_hook_bridge_pre(skb, pskb);
 | 
				
			||||||
			dev_net(skb->dev), NULL, skb, skb->dev, NULL,
 | 
					 | 
				
			||||||
			br_handle_frame_finish);
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
drop:
 | 
					drop:
 | 
				
			||||||
		kfree_skb(skb);
 | 
							kfree_skb(skb);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,6 +23,7 @@
 | 
				
			||||||
#include <linux/mm.h>
 | 
					#include <linux/mm.h>
 | 
				
			||||||
#include <linux/rcupdate.h>
 | 
					#include <linux/rcupdate.h>
 | 
				
			||||||
#include <net/net_namespace.h>
 | 
					#include <net/net_namespace.h>
 | 
				
			||||||
 | 
					#include <net/netfilter/nf_queue.h>
 | 
				
			||||||
#include <net/sock.h>
 | 
					#include <net/sock.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "nf_internals.h"
 | 
					#include "nf_internals.h"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,9 +7,6 @@
 | 
				
			||||||
#include <linux/netdevice.h>
 | 
					#include <linux/netdevice.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* nf_queue.c */
 | 
					/* nf_queue.c */
 | 
				
			||||||
int nf_queue(struct sk_buff *skb, struct nf_hook_state *state,
 | 
					 | 
				
			||||||
	     const struct nf_hook_entries *entries, unsigned int index,
 | 
					 | 
				
			||||||
	     unsigned int verdict);
 | 
					 | 
				
			||||||
void nf_queue_nf_hook_drop(struct net *net);
 | 
					void nf_queue_nf_hook_drop(struct net *net);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* nf_log.c */
 | 
					/* nf_log.c */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -240,6 +240,7 @@ int nf_queue(struct sk_buff *skb, struct nf_hook_state *state,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL_GPL(nf_queue);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static unsigned int nf_iterate(struct sk_buff *skb,
 | 
					static unsigned int nf_iterate(struct sk_buff *skb,
 | 
				
			||||||
			       struct nf_hook_state *state,
 | 
								       struct nf_hook_state *state,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue