History

bridge: broute: make broute a real ebtables table

This makes broute a normal ebtables table, hooking at PREROUTING. The broute hook is removed. It uses skb->cb to signal to bridge rx handler that the skb should be routed instead of being bridged. This change is backwards compatible with ebtables as no userspace visible parts are changed. This means we can also remove the !ops test in ebt_register_table, it was only there for broute table sake.

Florian Westphal committed 7 years ago

Commit 223fd0a1 parent 971502d5 files · +52 −42Browse files

Unified · Split

5 files
  1. include/linux/if_bridge.h +0 −3
  2. net/bridge/br_input.c +4 −14
  3. net/bridge/br_private.h +3 −0
  4. net/bridge/netfilter/ebtable_broute.c +44 −19
  5. net/bridge/netfilter/ebtables.c +1 −6
include/linux/if_bridge.h+0−3
@@ -56,9 +56,6 @@ struct br_ip_list { · 55 unmodified lines
5656
5757 extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *));
5858
59−typedef int br_should_route_hook_t(struct sk_buff *skb);
60−extern br_should_route_hook_t __rcu *br_should_route_hook;
61−
6259 #if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_BRIDGE_IGMP_SNOOPING)
6360 int br_multicast_list_adjacent(struct net_device *dev,
6461 struct list_head *br_ip_list);
net/bridge/br_input.c+4−14
@@ -24,10 +24,6 @@ · 23 unmodified lines
2424 #include "br_private.h"
2525 #include "br_private_tunnel.h"
2626
27−/* Hook for brouter */
28−br_should_route_hook_t __rcu *br_should_route_hook __read_mostly;
29−EXPORT_SYMBOL(br_should_route_hook);
30−
3127 static int
3228 br_netif_receive_skb(struct net *net, struct sock *sk, struct sk_buff *skb)
3329 {
@@ -234,6 +230,10 @@ static int nf_hook_bridge_pre(struct sk_buff *skb, struct sk_buff **pskb) · 200 unmodified lines
234230 verdict = nf_hook_entry_hookfn(&e->hooks[i], skb, &state);
235231 switch (verdict & NF_VERDICT_MASK) {
236232 case NF_ACCEPT:
233+ if (BR_INPUT_SKB_CB(skb)->br_netfilter_broute) {
234+ *pskb = skb;
235+ return RX_HANDLER_PASS;
236+ }
237237 break;
238238 case NF_DROP:
239239 kfree_skb(skb);
@@ -265,7 +265,6 @@ rx_handler_result_t br_handle_frame(struct sk_buff **pskb) · 25 unmodified lines
265265 struct net_bridge_port *p;
266266 struct sk_buff *skb = *pskb;
267267 const unsigned char *dest = eth_hdr(skb)->h_dest;
268− br_should_route_hook_t *rhook;
269268
270269 if (unlikely(skb->pkt_type == PACKET_LOOPBACK))
271270 return RX_HANDLER_PASS;
@@ -341,15 +340,6 @@ rx_handler_result_t br_handle_frame(struct sk_buff **pskb) · 69 unmodified lines
341340 forward:
342341 switch (p->state) {
343342 case BR_STATE_FORWARDING:
344− rhook = rcu_dereference(br_should_route_hook);
345− if (rhook) {
346− if ((*rhook)(skb)) {
347− *pskb = skb;
348− return RX_HANDLER_PASS;
349− }
350− dest = eth_hdr(skb)->h_dest;
351− }
352− /* fall through */
353343 case BR_STATE_LEARNING:
354344 if (ether_addr_equal(p->br->dev->dev_addr, dest))
355345 skb->pkt_type = PACKET_HOST;
net/bridge/br_private.h+3−0
@@ -433,6 +433,9 @@ struct br_input_skb_cb { · 432 unmodified lines
433433 #ifdef CONFIG_BRIDGE_VLAN_FILTERING
434434 u8 vlan_filtered:1;
435435 #endif
436+#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE
437+ u8 br_netfilter_broute:1;
438+#endif
436439
437440 #ifdef CONFIG_NET_SWITCHDEV
438441 int offload_fwd_mark;
net/bridge/netfilter/ebtable_broute.c+44−19
@@ -15,6 +15,8 @@ · 14 unmodified lines
1515 #include <linux/module.h>
1616 #include <linux/if_bridge.h>
1717
18+#include "../br_private.h"
19+
1820 /* EBT_ACCEPT means the frame will be bridged
1921 * EBT_DROP means the frame will be routed
2022 */
@@ -48,30 +50,63 @@ static const struct ebt_table broute_table = { · 27 unmodified lines
4850 .me = THIS_MODULE,
4951 };
5052
51−static int ebt_broute(struct sk_buff *skb)
53+static unsigned int ebt_broute(void *priv, struct sk_buff *skb,
54+ const struct nf_hook_state *s)
5255 {
56+ struct net_bridge_port *p = br_port_get_rcu(skb->dev);
5357 struct nf_hook_state state;
58+ unsigned char *dest;
5459 int ret;
5560
61+ if (!p || p->state != BR_STATE_FORWARDING)
62+ return NF_ACCEPT;
63+
5664 nf_hook_state_init(&state, NF_BR_BROUTING,
57− NFPROTO_BRIDGE, skb->dev, NULL, NULL,
58− dev_net(skb->dev), NULL);
65+ NFPROTO_BRIDGE, s->in, NULL, NULL,
66+ s->net, NULL);
5967
6068 ret = ebt_do_table(skb, &state, state.net->xt.broute_table);
61− if (ret == NF_DROP)
62− return 1; /* route it */
63− return 0; /* bridge it */
69+
70+ if (ret != NF_DROP)
71+ return ret;
72+
73+ /* DROP in ebtables -t broute means that the
74+ * skb should be routed, not bridged.
75+ * This is awkward, but can't be changed for compatibility
76+ * reasons.
77+ *
78+ * We map DROP to ACCEPT and set the ->br_netfilter_broute flag.
79+ */
80+ BR_INPUT_SKB_CB(skb)->br_netfilter_broute = 1;
81+
82+ /* undo PACKET_HOST mangling done in br_input in case the dst
83+ * address matches the logical bridge but not the port.
84+ */
85+ dest = eth_hdr(skb)->h_dest;
86+ if (skb->pkt_type == PACKET_HOST &&
87+ !ether_addr_equal(skb->dev->dev_addr, dest) &&
88+ ether_addr_equal(p->br->dev->dev_addr, dest))
89+ skb->pkt_type = PACKET_OTHERHOST;
90+
91+ return NF_ACCEPT;
6492 }
6593
94+static const struct nf_hook_ops ebt_ops_broute = {
95+ .hook = ebt_broute,
96+ .pf = NFPROTO_BRIDGE,
97+ .hooknum = NF_BR_PRE_ROUTING,
98+ .priority = NF_BR_PRI_FIRST,
99+};
100+
66101 static int __net_init broute_net_init(struct net *net)
67102 {
68− return ebt_register_table(net, &broute_table, NULL,
103+ return ebt_register_table(net, &broute_table, &ebt_ops_broute,
69104 &net->xt.broute_table);
70105 }
71106
72107 static void __net_exit broute_net_exit(struct net *net)
73108 {
74− ebt_unregister_table(net, net->xt.broute_table, NULL);
109+ ebt_unregister_table(net, net->xt.broute_table, &ebt_ops_broute);
75110 }
76111
77112 static struct pernet_operations broute_net_ops = {
@@ -81,21 +116,11 @@ static struct pernet_operations broute_net_ops = { · 3 unmodified lines
81116
82117 static int __init ebtable_broute_init(void)
83118 {
84− int ret;
85−
86− ret = register_pernet_subsys(&broute_net_ops);
87− if (ret < 0)
88− return ret;
89− /* see br_input.c */
90− RCU_INIT_POINTER(br_should_route_hook,
91− (br_should_route_hook_t *)ebt_broute);
92− return 0;
119+ return register_pernet_subsys(&broute_net_ops);
93120 }
94121
95122 static void __exit ebtable_broute_fini(void)
96123 {
97− RCU_INIT_POINTER(br_should_route_hook, NULL);
98− synchronize_net();
99124 unregister_pernet_subsys(&broute_net_ops);
100125 }
101126
net/bridge/netfilter/ebtables.c+1−6
@@ -1221,10 +1221,6 @@ int ebt_register_table(struct net *net, const struct ebt_table *input_table, · 1220 unmodified lines
12211221 mutex_unlock(&ebt_mutex);
12221222
12231223 WRITE_ONCE(*res, table);
1224−
1225− if (!ops)
1226− return 0;
1227−
12281224 ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks));
12291225 if (ret) {
12301226 __ebt_unregister_table(net, table);
@@ -1248,8 +1244,7 @@ out: · 17 unmodified lines
12481244 void ebt_unregister_table(struct net *net, struct ebt_table *table,
12491245 const struct nf_hook_ops *ops)
12501246 {
1251− if (ops)
1252− nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks));
1247+ nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks));
12531248 __ebt_unregister_table(net, table);
12541249 }
12551250

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t