br_forward.c 4.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>
L
Linus Torvalds 已提交
15 16 17
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
18
#include <linux/if_vlan.h>
L
Linus Torvalds 已提交
19 20 21
#include <linux/netfilter_bridge.h>
#include "br_private.h"

22
/* Don't forward packets to originating port or forwarding diasabled */
23
static inline int should_deliver(const struct net_bridge_port *p,
L
Linus Torvalds 已提交
24 25
				 const struct sk_buff *skb)
{
26 27
	return (((p->flags & BR_HAIRPIN_MODE) || skb->dev != p->dev) &&
		p->state == BR_STATE_FORWARDING);
L
Linus Torvalds 已提交
28 29
}

30 31 32 33 34
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 已提交
35 36
int br_dev_queue_push_xmit(struct sk_buff *skb)
{
37
	/* drop mtu oversized packets except gso */
H
Herbert Xu 已提交
38
	if (packet_length(skb) > skb->dev->mtu && !skb_is_gso(skb))
L
Linus Torvalds 已提交
39 40 41
		kfree_skb(skb);
	else {
		/* ip_refrag calls ip_fragment, doesn't copy the MAC header. */
42 43
		if (nf_bridge_maybe_copy_header(skb))
			kfree_skb(skb);
44
		else {
45
			skb_push(skb, ETH_HLEN);
L
Linus Torvalds 已提交
46

47 48
			dev_queue_xmit(skb);
		}
L
Linus Torvalds 已提交
49 50 51 52 53 54 55
	}

	return 0;
}

int br_forward_finish(struct sk_buff *skb)
{
56 57
	return NF_HOOK(PF_BRIDGE, NF_BR_POST_ROUTING, skb, NULL, skb->dev,
		       br_dev_queue_push_xmit);
L
Linus Torvalds 已提交
58 59 60 61 62 63 64 65 66 67 68 69 70 71

}

static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
{
	skb->dev = to->dev;
	NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
			br_forward_finish);
}

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

H
Herbert Xu 已提交
72 73 74 75 76
	if (skb_warn_if_lro(skb)) {
		kfree_skb(skb);
		return;
	}

L
Linus Torvalds 已提交
77 78
	indev = skb->dev;
	skb->dev = to->dev;
79
	skb_forward_csum(skb);
L
Linus Torvalds 已提交
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98

	NF_HOOK(PF_BRIDGE, NF_BR_FORWARD, skb, indev, skb->dev,
			br_forward_finish);
}

/* 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 */
void br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
{
H
Herbert Xu 已提交
99
	if (should_deliver(to, skb)) {
L
Linus Torvalds 已提交
100 101 102 103 104 105 106
		__br_forward(to, skb);
		return;
	}

	kfree_skb(skb);
}

107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
static int deliver_clone(struct net_bridge_port *prev, struct sk_buff *skb,
			 void (*__packet_hook)(const struct net_bridge_port *p,
					       struct sk_buff *skb))
{
	skb = skb_clone(skb, GFP_ATOMIC);
	if (!skb) {
		struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;

		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 已提交
145
/* called under bridge lock */
146
static void br_flood(struct net_bridge *br, struct sk_buff *skb,
147 148 149
		     struct sk_buff *skb0,
		     void (*__packet_hook)(const struct net_bridge_port *p,
					   struct sk_buff *skb))
L
Linus Torvalds 已提交
150 151 152 153 154 155 156
{
	struct net_bridge_port *p;
	struct net_bridge_port *prev;

	prev = NULL;

	list_for_each_entry_rcu(p, &br->port_list, list) {
157 158 159
		prev = maybe_deliver(prev, p, skb, __packet_hook);
		if (IS_ERR(prev))
			goto out;
L
Linus Torvalds 已提交
160 161
	}

162 163 164
	if (!prev)
		goto out;

165 166 167 168
	if (skb0)
		deliver_clone(prev, skb, __packet_hook);
	else
		__packet_hook(prev, skb);
169
	return;
L
Linus Torvalds 已提交
170

171 172 173
out:
	if (!skb0)
		kfree_skb(skb);
L
Linus Torvalds 已提交
174 175 176 177
}


/* called with rcu_read_lock */
178
void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb)
L
Linus Torvalds 已提交
179
{
180
	br_flood(br, skb, NULL, __br_deliver);
L
Linus Torvalds 已提交
181 182 183
}

/* called under bridge lock */
184 185
void br_flood_forward(struct net_bridge *br, struct sk_buff *skb,
		      struct sk_buff *skb2)
L
Linus Torvalds 已提交
186
{
187
	br_flood(br, skb, skb2, __br_forward);
L
Linus Torvalds 已提交
188
}