br_forward.c 7.0 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13
/*
 *	Forwarding decision
 *	Linux ethernet bridge
 *
 *	Authors:
 *	Lennert Buytenhek		<buytenh@gnu.org>
 *
 *	This program is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU General Public License
 *	as published by the Free Software Foundation; either version
 *	2 of the License, or (at your option) any later version.
 */

14
#include <linux/err.h>
15
#include <linux/slab.h>
L
Linus Torvalds 已提交
16 17
#include <linux/kernel.h>
#include <linux/netdevice.h>
W
WANG Cong 已提交
18
#include <linux/netpoll.h>
L
Linus Torvalds 已提交
19
#include <linux/skbuff.h>
20
#include <linux/if_vlan.h>
L
Linus Torvalds 已提交
21 22 23
#include <linux/netfilter_bridge.h>
#include "br_private.h"

T
tanxiaojun 已提交
24
/* Don't forward packets to originating port or forwarding disabled */
25
static inline int should_deliver(const struct net_bridge_port *p,
L
Linus Torvalds 已提交
26 27
				 const struct sk_buff *skb)
{
28 29
	struct net_bridge_vlan_group *vg;

30
	vg = nbp_vlan_group_rcu(p);
31
	return ((p->flags & BR_HAIRPIN_MODE) || skb->dev != p->dev) &&
32 33
		br_allowed_egress(vg, skb) && p->state == BR_STATE_FORWARDING &&
		nbp_switchdev_allowed_egress(p, skb);
L
Linus Torvalds 已提交
34 35
}

36
int br_dev_queue_push_xmit(struct net *net, struct sock *sk, struct sk_buff *skb)
L
Linus Torvalds 已提交
37
{
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
	if (!is_skb_forwardable(skb->dev, skb))
		goto drop;

	skb_push(skb, ETH_HLEN);
	br_drop_fake_rtable(skb);

	if (skb->ip_summed == CHECKSUM_PARTIAL &&
	    (skb->protocol == htons(ETH_P_8021Q) ||
	     skb->protocol == htons(ETH_P_8021AD))) {
		int depth;

		if (!__vlan_get_protocol(skb, skb->protocol, &depth))
			goto drop;

		skb_set_network_header(skb, depth);
L
Linus Torvalds 已提交
53 54
	}

55 56 57 58 59 60
	dev_queue_xmit(skb);

	return 0;

drop:
	kfree_skb(skb);
L
Linus Torvalds 已提交
61 62
	return 0;
}
63
EXPORT_SYMBOL_GPL(br_dev_queue_push_xmit);
L
Linus Torvalds 已提交
64

65
int br_forward_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
L
Linus Torvalds 已提交
66
{
67 68
	return NF_HOOK(NFPROTO_BRIDGE, NF_BR_POST_ROUTING,
		       net, sk, skb, NULL, skb->dev,
69
		       br_dev_queue_push_xmit);
L
Linus Torvalds 已提交
70 71

}
72
EXPORT_SYMBOL_GPL(br_forward_finish);
L
Linus Torvalds 已提交
73

74 75
static void __br_forward(const struct net_bridge_port *to,
			 struct sk_buff *skb, bool local_orig)
L
Linus Torvalds 已提交
76
{
77
	struct net_bridge_vlan_group *vg;
78 79 80
	struct net_device *indev;
	struct net *net;
	int br_hook;
81

82
	vg = nbp_vlan_group_rcu(to);
83
	skb = br_handle_vlan(to->br, vg, skb);
84 85 86
	if (!skb)
		return;

87
	indev = skb->dev;
L
Linus Torvalds 已提交
88
	skb->dev = to->dev;
89 90
	if (!local_orig) {
		if (skb_warn_if_lro(skb)) {
H
Herbert Xu 已提交
91
			kfree_skb(skb);
92
			return;
H
Herbert Xu 已提交
93
		}
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
		br_hook = NF_BR_FORWARD;
		skb_forward_csum(skb);
		net = dev_net(indev);
	} else {
		if (unlikely(netpoll_tx_running(to->br->dev))) {
			if (!is_skb_forwardable(skb->dev, skb)) {
				kfree_skb(skb);
			} else {
				skb_push(skb, ETH_HLEN);
				br_netpoll_send_skb(to, skb);
			}
			return;
		}
		br_hook = NF_BR_LOCAL_OUT;
		net = dev_net(skb->dev);
		indev = NULL;
H
Herbert Xu 已提交
110 111
	}

112 113
	NF_HOOK(NFPROTO_BRIDGE, br_hook,
		net, NULL, skb, indev, skb->dev,
114
		br_forward_finish);
L
Linus Torvalds 已提交
115 116
}

117 118
static int deliver_clone(const struct net_bridge_port *prev,
			 struct sk_buff *skb, bool local_orig)
L
Linus Torvalds 已提交
119
{
120
	struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
L
Linus Torvalds 已提交
121

122 123 124 125
	skb = skb_clone(skb, GFP_ATOMIC);
	if (!skb) {
		dev->stats.tx_dropped++;
		return -ENOMEM;
L
Linus Torvalds 已提交
126 127
	}

128 129
	__br_forward(prev, skb, local_orig);
	return 0;
L
Linus Torvalds 已提交
130 131
}

132 133 134 135 136 137 138 139 140 141 142
/**
 * br_forward - forward a packet to a specific port
 * @to: destination port
 * @skb: packet being forwarded
 * @local_rcv: packet will be received locally after forwarding
 * @local_orig: packet is locally originated
 *
 * Should be called with rcu_read_lock.
 */
void br_forward(const struct net_bridge_port *to,
		struct sk_buff *skb, bool local_rcv, bool local_orig)
L
Linus Torvalds 已提交
143
{
144
	if (to && should_deliver(to, skb)) {
145
		if (local_rcv)
146
			deliver_clone(to, skb, local_orig);
147
		else
148
			__br_forward(to, skb, local_orig);
L
Linus Torvalds 已提交
149 150 151
		return;
	}

152
	if (!local_rcv)
153
		kfree_skb(skb);
L
Linus Torvalds 已提交
154
}
155
EXPORT_SYMBOL_GPL(br_forward);
156 157 158

static struct net_bridge_port *maybe_deliver(
	struct net_bridge_port *prev, struct net_bridge_port *p,
159
	struct sk_buff *skb, bool local_orig)
160 161 162 163 164 165 166 167 168
{
	int err;

	if (!should_deliver(p, skb))
		return prev;

	if (!prev)
		goto out;

169
	err = deliver_clone(prev, skb, local_orig);
170 171 172 173 174 175 176
	if (err)
		return ERR_PTR(err);

out:
	return p;
}

F
Felix Fietkau 已提交
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
static void maybe_deliver_addr(struct net_bridge_port *p, struct sk_buff *skb,
			       const unsigned char *addr, bool local_orig)
{
	struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
	const unsigned char *src = eth_hdr(skb)->h_source;

	if (!should_deliver(p, skb))
		return;

	/* Even with hairpin, no soliloquies - prevent breaking IPv6 DAD */
	if (skb->dev == p->dev && ether_addr_equal(src, addr))
		return;

	skb = skb_copy(skb, GFP_ATOMIC);
	if (!skb) {
		dev->stats.tx_dropped++;
		return;
	}

	if (!is_broadcast_ether_addr(addr))
		memcpy(eth_hdr(skb)->h_dest, addr, ETH_ALEN);

	__br_forward(p, skb, local_orig);
}

202 203
/* called under rcu_read_lock */
void br_flood(struct net_bridge *br, struct sk_buff *skb,
204
	      enum br_pkt_type pkt_type, bool local_rcv, bool local_orig)
L
Linus Torvalds 已提交
205
{
206
	u8 igmp_type = br_multicast_igmp_type(skb);
207
	struct net_bridge_port *prev = NULL;
208
	struct net_bridge_port *p;
L
Linus Torvalds 已提交
209 210

	list_for_each_entry_rcu(p, &br->port_list, list) {
211
		/* Do not flood unicast traffic to ports that turn it off */
212
		if (pkt_type == BR_PKT_UNICAST && !(p->flags & BR_FLOOD))
213
			continue;
214 215 216
		if (pkt_type == BR_PKT_MULTICAST &&
		    !(p->flags & BR_MCAST_FLOOD))
			continue;
217 218 219 220

		/* Do not flood to ports that enable proxy ARP */
		if (p->flags & BR_PROXYARP)
			continue;
221 222 223
		if ((p->flags & BR_PROXYARP_WIFI) &&
		    BR_INPUT_SKB_CB(skb)->proxyarp_replied)
			continue;
224

225
		prev = maybe_deliver(prev, p, skb, local_orig);
226 227
		if (IS_ERR(prev))
			goto out;
228
		if (prev == p)
229
			br_multicast_count(p->br, p, skb, igmp_type,
230
					   BR_MCAST_DIR_TX);
L
Linus Torvalds 已提交
231 232
	}

233 234 235
	if (!prev)
		goto out;

236
	if (local_rcv)
237
		deliver_clone(prev, skb, local_orig);
238
	else
239
		__br_forward(prev, skb, local_orig);
240
	return;
L
Linus Torvalds 已提交
241

242
out:
243
	if (!local_rcv)
244
		kfree_skb(skb);
L
Linus Torvalds 已提交
245 246
}

247 248
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
/* called with rcu_read_lock */
249 250 251
void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
			struct sk_buff *skb,
			bool local_rcv, bool local_orig)
252 253
{
	struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
254
	u8 igmp_type = br_multicast_igmp_type(skb);
255
	struct net_bridge *br = netdev_priv(dev);
256
	struct net_bridge_port *prev = NULL;
257 258 259
	struct net_bridge_port_group *p;
	struct hlist_node *rp;

260
	rp = rcu_dereference(hlist_first_rcu(&br->router_list));
261
	p = mdst ? rcu_dereference(mdst->ports) : NULL;
262
	while (p || rp) {
263 264
		struct net_bridge_port *port, *lport, *rport;

265 266 267 268
		lport = p ? p->port : NULL;
		rport = rp ? hlist_entry(rp, struct net_bridge_port, rlist) :
			     NULL;

F
Felix Fietkau 已提交
269 270 271 272 273 274 275 276 277 278 279
		if ((unsigned long)lport > (unsigned long)rport) {
			port = lport;

			if (port->flags & BR_MULTICAST_TO_UNICAST) {
				maybe_deliver_addr(lport, skb, p->eth_addr,
						   local_orig);
				goto delivered;
			}
		} else {
			port = rport;
		}
280

281
		prev = maybe_deliver(prev, port, skb, local_orig);
F
Felix Fietkau 已提交
282
delivered:
283 284
		if (IS_ERR(prev))
			goto out;
285
		if (prev == port)
286
			br_multicast_count(port->br, port, skb, igmp_type,
287
					   BR_MCAST_DIR_TX);
288 289

		if ((unsigned long)lport >= (unsigned long)port)
290
			p = rcu_dereference(p->next);
291
		if ((unsigned long)rport >= (unsigned long)port)
292
			rp = rcu_dereference(hlist_next_rcu(rp));
293 294 295 296 297
	}

	if (!prev)
		goto out;

298
	if (local_rcv)
299
		deliver_clone(prev, skb, local_orig);
300
	else
301
		__br_forward(prev, skb, local_orig);
302 303 304
	return;

out:
305
	if (!local_rcv)
306 307 308
		kfree_skb(skb);
}
#endif