br_forward.c 6.1 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"

24 25
static int deliver_clone(const struct net_bridge_port *prev,
			 struct sk_buff *skb,
26 27 28
			 void (*__packet_hook)(const struct net_bridge_port *p,
					       struct sk_buff *skb));

29
/* Don't forward packets to originating port or forwarding diasabled */
30
static inline int should_deliver(const struct net_bridge_port *p,
L
Linus Torvalds 已提交
31 32
				 const struct sk_buff *skb)
{
33 34
	return (((p->flags & BR_HAIRPIN_MODE) || skb->dev != p->dev) &&
		p->state == BR_STATE_FORWARDING);
L
Linus Torvalds 已提交
35 36
}

37 38 39 40 41
static inline unsigned packet_length(const struct sk_buff *skb)
{
	return skb->len - (skb->protocol == htons(ETH_P_8021Q) ? VLAN_HLEN : 0);
}

L
Linus Torvalds 已提交
42 43
int br_dev_queue_push_xmit(struct sk_buff *skb)
{
44 45 46
	/* ip_fragment doesn't copy the MAC header */
	if (nf_bridge_maybe_copy_header(skb) ||
	    (packet_length(skb) > skb->dev->mtu && !skb_is_gso(skb))) {
L
Linus Torvalds 已提交
47
		kfree_skb(skb);
48 49 50
	} else {
		skb_push(skb, ETH_HLEN);
		dev_queue_xmit(skb);
L
Linus Torvalds 已提交
51 52 53 54 55 56 57
	}

	return 0;
}

int br_forward_finish(struct sk_buff *skb)
{
58
	return NF_HOOK(NFPROTO_BRIDGE, NF_BR_POST_ROUTING, skb, NULL, skb->dev,
59
		       br_dev_queue_push_xmit);
L
Linus Torvalds 已提交
60 61 62 63 64 65

}

static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
{
	skb->dev = to->dev;
H
Herbert Xu 已提交
66 67 68 69 70 71 72 73 74 75 76

	if (unlikely(netpoll_tx_running(to->dev))) {
		if (packet_length(skb) > skb->dev->mtu && !skb_is_gso(skb))
			kfree_skb(skb);
		else {
			skb_push(skb, ETH_HLEN);
			br_netpoll_send_skb(to, skb);
		}
		return;
	}

77 78
	NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
		br_forward_finish);
L
Linus Torvalds 已提交
79 80 81 82 83 84
}

static void __br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
{
	struct net_device *indev;

H
Herbert Xu 已提交
85 86 87 88 89
	if (skb_warn_if_lro(skb)) {
		kfree_skb(skb);
		return;
	}

L
Linus Torvalds 已提交
90 91
	indev = skb->dev;
	skb->dev = to->dev;
92
	skb_forward_csum(skb);
L
Linus Torvalds 已提交
93

94 95
	NF_HOOK(NFPROTO_BRIDGE, NF_BR_FORWARD, skb, indev, skb->dev,
		br_forward_finish);
L
Linus Torvalds 已提交
96 97 98 99 100 101 102 103 104 105 106 107 108 109
}

/* called with rcu_read_lock */
void br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
{
	if (should_deliver(to, skb)) {
		__br_deliver(to, skb);
		return;
	}

	kfree_skb(skb);
}

/* called with rcu_read_lock */
110
void br_forward(const struct net_bridge_port *to, struct sk_buff *skb, struct sk_buff *skb0)
L
Linus Torvalds 已提交
111
{
H
Herbert Xu 已提交
112
	if (should_deliver(to, skb)) {
113 114 115 116
		if (skb0)
			deliver_clone(to, skb, __br_forward);
		else
			__br_forward(to, skb);
L
Linus Torvalds 已提交
117 118 119
		return;
	}

120 121
	if (!skb0)
		kfree_skb(skb);
L
Linus Torvalds 已提交
122 123
}

124 125
static int deliver_clone(const struct net_bridge_port *prev,
			 struct sk_buff *skb,
126 127 128
			 void (*__packet_hook)(const struct net_bridge_port *p,
					       struct sk_buff *skb))
{
129 130
	struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;

131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
	skb = skb_clone(skb, GFP_ATOMIC);
	if (!skb) {
		dev->stats.tx_dropped++;
		return -ENOMEM;
	}

	__packet_hook(prev, skb);
	return 0;
}

static struct net_bridge_port *maybe_deliver(
	struct net_bridge_port *prev, struct net_bridge_port *p,
	struct sk_buff *skb,
	void (*__packet_hook)(const struct net_bridge_port *p,
			      struct sk_buff *skb))
{
	int err;

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

	if (!prev)
		goto out;

	err = deliver_clone(prev, skb, __packet_hook);
	if (err)
		return ERR_PTR(err);

out:
	return p;
}

L
Linus Torvalds 已提交
163
/* called under bridge lock */
164
static void br_flood(struct net_bridge *br, struct sk_buff *skb,
165 166 167
		     struct sk_buff *skb0,
		     void (*__packet_hook)(const struct net_bridge_port *p,
					   struct sk_buff *skb))
L
Linus Torvalds 已提交
168 169 170 171 172 173 174
{
	struct net_bridge_port *p;
	struct net_bridge_port *prev;

	prev = NULL;

	list_for_each_entry_rcu(p, &br->port_list, list) {
175 176 177
		prev = maybe_deliver(prev, p, skb, __packet_hook);
		if (IS_ERR(prev))
			goto out;
L
Linus Torvalds 已提交
178 179
	}

180 181 182
	if (!prev)
		goto out;

183 184 185 186
	if (skb0)
		deliver_clone(prev, skb, __packet_hook);
	else
		__packet_hook(prev, skb);
187
	return;
L
Linus Torvalds 已提交
188

189 190 191
out:
	if (!skb0)
		kfree_skb(skb);
L
Linus Torvalds 已提交
192 193 194 195
}


/* called with rcu_read_lock */
196
void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb)
L
Linus Torvalds 已提交
197
{
198
	br_flood(br, skb, NULL, __br_deliver);
L
Linus Torvalds 已提交
199 200 201
}

/* called under bridge lock */
202 203
void br_flood_forward(struct net_bridge *br, struct sk_buff *skb,
		      struct sk_buff *skb2)
L
Linus Torvalds 已提交
204
{
205
	br_flood(br, skb, skb2, __br_forward);
L
Linus Torvalds 已提交
206
}
207 208 209 210 211 212 213 214 215 216 217

#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
/* called with rcu_read_lock */
static void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
			       struct sk_buff *skb, struct sk_buff *skb0,
			       void (*__packet_hook)(
					const struct net_bridge_port *p,
					struct sk_buff *skb))
{
	struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
	struct net_bridge *br = netdev_priv(dev);
218
	struct net_bridge_port *prev = NULL;
219 220 221
	struct net_bridge_port_group *p;
	struct hlist_node *rp;

222
	rp = rcu_dereference(hlist_first_rcu(&br->router_list));
223
	p = mdst ? rcu_dereference(mdst->ports) : NULL;
224
	while (p || rp) {
225 226
		struct net_bridge_port *port, *lport, *rport;

227 228 229 230 231 232 233 234 235 236 237 238
		lport = p ? p->port : NULL;
		rport = rp ? hlist_entry(rp, struct net_bridge_port, rlist) :
			     NULL;

		port = (unsigned long)lport > (unsigned long)rport ?
		       lport : rport;

		prev = maybe_deliver(prev, port, skb, __packet_hook);
		if (IS_ERR(prev))
			goto out;

		if ((unsigned long)lport >= (unsigned long)port)
239
			p = rcu_dereference(p->next);
240
		if ((unsigned long)rport >= (unsigned long)port)
241
			rp = rcu_dereference(hlist_next_rcu(rp));
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
	}

	if (!prev)
		goto out;

	if (skb0)
		deliver_clone(prev, skb, __packet_hook);
	else
		__packet_hook(prev, skb);
	return;

out:
	if (!skb0)
		kfree_skb(skb);
}

/* called with rcu_read_lock */
void br_multicast_deliver(struct net_bridge_mdb_entry *mdst,
			  struct sk_buff *skb)
{
	br_multicast_flood(mdst, skb, NULL, __br_deliver);
}

/* called with rcu_read_lock */
void br_multicast_forward(struct net_bridge_mdb_entry *mdst,
			  struct sk_buff *skb, struct sk_buff *skb2)
{
	br_multicast_flood(mdst, skb, skb2, __br_forward);
}
#endif