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
56 56
57extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *));57extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *));
58 58
59typedef int br_should_route_hook_t(struct sk_buff *skb);
60extern br_should_route_hook_t __rcu *br_should_route_hook;
61
62#if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_BRIDGE_IGMP_SNOOPING)59#if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_BRIDGE_IGMP_SNOOPING)
63int br_multicast_list_adjacent(struct net_device *dev,60int br_multicast_list_adjacent(struct net_device *dev,
64 struct list_head *br_ip_list);61 struct list_head *br_ip_list);
net/bridge/br_input.c+4−14
@@ -24,10 +24,6 @@ · 23 unmodified lines
24#include "br_private.h"24#include "br_private.h"
25#include "br_private_tunnel.h"25#include "br_private_tunnel.h"
26 26
27/* Hook for brouter */
28br_should_route_hook_t __rcu *br_should_route_hook __read_mostly;
29EXPORT_SYMBOL(br_should_route_hook);
30
31static int27static int
32br_netif_receive_skb(struct net *net, struct sock *sk, struct sk_buff *skb)28br_netif_receive_skb(struct net *net, struct sock *sk, struct sk_buff *skb)
33{29{
@@ -234,6 +230,10 @@ static int nf_hook_bridge_pre(struct sk_buff *skb, struct sk_buff **pskb) · 200 unmodified lines
234 verdict = nf_hook_entry_hookfn(&e->hooks[i], skb, &state);230 verdict = nf_hook_entry_hookfn(&e->hooks[i], skb, &state);
235 switch (verdict & NF_VERDICT_MASK) {231 switch (verdict & NF_VERDICT_MASK) {
236 case NF_ACCEPT:232 case NF_ACCEPT:
233 if (BR_INPUT_SKB_CB(skb)->br_netfilter_broute) {
234 *pskb = skb;
235 return RX_HANDLER_PASS;
236 }
237 break;237 break;
238 case NF_DROP:238 case NF_DROP:
239 kfree_skb(skb);239 kfree_skb(skb);
@@ -265,7 +265,6 @@ rx_handler_result_t br_handle_frame(struct sk_buff **pskb) · 25 unmodified lines
265 struct net_bridge_port *p;265 struct net_bridge_port *p;
266 struct sk_buff *skb = *pskb;266 struct sk_buff *skb = *pskb;
267 const unsigned char *dest = eth_hdr(skb)->h_dest;267 const unsigned char *dest = eth_hdr(skb)->h_dest;
268 br_should_route_hook_t *rhook;
269 268
270 if (unlikely(skb->pkt_type == PACKET_LOOPBACK))269 if (unlikely(skb->pkt_type == PACKET_LOOPBACK))
271 return RX_HANDLER_PASS;270 return RX_HANDLER_PASS;
@@ -341,15 +340,6 @@ rx_handler_result_t br_handle_frame(struct sk_buff **pskb) · 69 unmodified lines
341forward:340forward:
342 switch (p->state) {341 switch (p->state) {
343 case BR_STATE_FORWARDING:342 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 */
353 case BR_STATE_LEARNING:343 case BR_STATE_LEARNING:
354 if (ether_addr_equal(p->br->dev->dev_addr, dest))344 if (ether_addr_equal(p->br->dev->dev_addr, dest))
355 skb->pkt_type = PACKET_HOST;345 skb->pkt_type = PACKET_HOST;
net/bridge/br_private.h+3−0
@@ -433,6 +433,9 @@ struct br_input_skb_cb { · 432 unmodified lines
433#ifdef CONFIG_BRIDGE_VLAN_FILTERING433#ifdef CONFIG_BRIDGE_VLAN_FILTERING
434 u8 vlan_filtered:1;434 u8 vlan_filtered:1;
435#endif435#endif
436#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE
437 u8 br_netfilter_broute:1;
438#endif
436 439
437#ifdef CONFIG_NET_SWITCHDEV440#ifdef CONFIG_NET_SWITCHDEV
438 int offload_fwd_mark;441 int offload_fwd_mark;
net/bridge/netfilter/ebtable_broute.c+44−19
@@ -15,6 +15,8 @@ · 14 unmodified lines
15#include <linux/module.h>15#include <linux/module.h>
16#include <linux/if_bridge.h>16#include <linux/if_bridge.h>
17 17
18#include "../br_private.h"
19
18/* EBT_ACCEPT means the frame will be bridged20/* EBT_ACCEPT means the frame will be bridged
19 * EBT_DROP means the frame will be routed21 * EBT_DROP means the frame will be routed
20 */22 */
@@ -48,30 +50,63 @@ static const struct ebt_table broute_table = { · 27 unmodified lines
48 .me = THIS_MODULE,50 .me = THIS_MODULE,
49};51};
50 52
51static int ebt_broute(struct sk_buff *skb)53static unsigned int ebt_broute(void *priv, struct sk_buff *skb,
54 const struct nf_hook_state *s)
52{55{
56 struct net_bridge_port *p = br_port_get_rcu(skb->dev);
53 struct nf_hook_state state;57 struct nf_hook_state state;
58 unsigned char *dest;
54 int ret;59 int ret;
55 60
61 if (!p || p->state != BR_STATE_FORWARDING)
62 return NF_ACCEPT;
63
56 nf_hook_state_init(&state, NF_BR_BROUTING,64 nf_hook_state_init(&state, NF_BR_BROUTING,
57 NFPROTO_BRIDGE, skb->dev, NULL, NULL,65 NFPROTO_BRIDGE, s->in, NULL, NULL,
58 dev_net(skb->dev), NULL);66 s->net, NULL);
59 67
60 ret = ebt_do_table(skb, &state, state.net->xt.broute_table);68 ret = ebt_do_table(skb, &state, state.net->xt.broute_table);
61 if (ret == NF_DROP)69
62 return 1; /* route it */70 if (ret != NF_DROP)
63 return 0; /* bridge it */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;
64}92}
65 93
94static 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
66static int __net_init broute_net_init(struct net *net)101static int __net_init broute_net_init(struct net *net)
67{102{
68 return ebt_register_table(net, &broute_table, NULL,103 return ebt_register_table(net, &broute_table, &ebt_ops_broute,
69 &net->xt.broute_table);104 &net->xt.broute_table);
70}105}
71 106
72static void __net_exit broute_net_exit(struct net *net)107static void __net_exit broute_net_exit(struct net *net)
73{108{
74 ebt_unregister_table(net, net->xt.broute_table, NULL);109 ebt_unregister_table(net, net->xt.broute_table, &ebt_ops_broute);
75}110}
76 111
77static struct pernet_operations broute_net_ops = {112static struct pernet_operations broute_net_ops = {
@@ -81,21 +116,11 @@ static struct pernet_operations broute_net_ops = { · 3 unmodified lines
81 116
82static int __init ebtable_broute_init(void)117static int __init ebtable_broute_init(void)
83{118{
84 int ret;119 return register_pernet_subsys(&broute_net_ops);
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;
93}120}
94 121
95static void __exit ebtable_broute_fini(void)122static void __exit ebtable_broute_fini(void)
96{123{
97 RCU_INIT_POINTER(br_should_route_hook, NULL);
98 synchronize_net();
99 unregister_pernet_subsys(&broute_net_ops);124 unregister_pernet_subsys(&broute_net_ops);
100}125}
101 126
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
1221 mutex_unlock(&ebt_mutex);1221 mutex_unlock(&ebt_mutex);
1222 1222
1223 WRITE_ONCE(*res, table);1223 WRITE_ONCE(*res, table);
1224
1225 if (!ops)
1226 return 0;
1227
1228 ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks));1224 ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks));
1229 if (ret) {1225 if (ret) {
1230 __ebt_unregister_table(net, table);1226 __ebt_unregister_table(net, table);
@@ -1248,8 +1244,7 @@ out: · 17 unmodified lines
1248void ebt_unregister_table(struct net *net, struct ebt_table *table,1244void ebt_unregister_table(struct net *net, struct ebt_table *table,
1249 const struct nf_hook_ops *ops)1245 const struct nf_hook_ops *ops)
1250{1246{
1251 if (ops)1247 nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks));
1252 nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks));
1253 __ebt_unregister_table(net, table);1248 __ebt_unregister_table(net, table);
1254}1249}
1255 1250

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