Skip to content

Commit 223fd0a

Browse files
Florian Westphalummakynes
authored andcommitted
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. 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 971502d commit 223fd0a

File tree

5 files changed

+52
-42
lines changed

5 files changed

+52
-42
lines changed

include/linux/if_bridge.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,6 @@ struct br_ip_list {
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

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,6 @@
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)
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)
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)
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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,9 @@ struct br_input_skb_cb {
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

Lines changed: 44 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
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 = {
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 = {
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

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1221,10 +1221,6 @@ int ebt_register_table(struct net *net, const struct ebt_table *input_table,
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 @@ int ebt_register_table(struct net *net, const struct ebt_table *input_table,
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

0 commit comments

Comments
 (0)