diff options
author | Bart De Schuymer <bdschuym@pandora.be> | 2010-04-15 06:26:39 -0400 |
---|---|---|
committer | Patrick McHardy <kaber@trash.net> | 2010-04-15 06:26:39 -0400 |
commit | e179e6322ac334e21a3c6d669d95bc967e5d0a80 (patch) | |
tree | eee21d4e85ffeed02c6a25a8b224845cb9ed0fd2 /include | |
parent | ea2d9b41bd418894d1ee25de1642c3325d71c397 (diff) |
netfilter: bridge-netfilter: Fix MAC header handling with IP DNAT
- fix IP DNAT on vlan- or pppoe-encapsulated traffic: The functions
neigh_hh_output() or dst->neighbour->output() overwrite the complete
Ethernet header, although we only need the destination MAC address.
For encapsulated packets, they ended up overwriting the encapsulating
header. The new code copies the Ethernet source MAC address and
protocol number before calling dst->neighbour->output(). The Ethernet
source MAC and protocol number are copied back in place in
br_nf_pre_routing_finish_bridge_slow(). This also makes the IP DNAT
more transparent because in the old scheme the source MAC of the
bridge was copied into the source address in the Ethernet header. We
also let skb->protocol equal ETH_P_IP resp. ETH_P_IPV6 during the
execution of the PF_INET resp. PF_INET6 hooks.
- Speed up IP DNAT by calling neigh_hh_bridge() instead of
neigh_hh_output(): if dst->hh is available, we already know the MAC
address so we can just copy it.
Signed-off-by: Bart De Schuymer <bdschuym@pandora.be>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'include')
-rw-r--r-- | include/linux/netfilter_bridge.h | 5 | ||||
-rw-r--r-- | include/net/neighbour.h | 14 |
2 files changed, 18 insertions, 1 deletions
diff --git a/include/linux/netfilter_bridge.h b/include/linux/netfilter_bridge.h index ffab6c423a57..ea0e44b90432 100644 --- a/include/linux/netfilter_bridge.h +++ b/include/linux/netfilter_bridge.h | |||
@@ -43,7 +43,8 @@ enum nf_br_hook_priorities { | |||
43 | #define BRNF_BRIDGED_DNAT 0x02 | 43 | #define BRNF_BRIDGED_DNAT 0x02 |
44 | #define BRNF_BRIDGED 0x04 | 44 | #define BRNF_BRIDGED 0x04 |
45 | #define BRNF_NF_BRIDGE_PREROUTING 0x08 | 45 | #define BRNF_NF_BRIDGE_PREROUTING 0x08 |
46 | 46 | #define BRNF_8021Q 0x10 | |
47 | #define BRNF_PPPoE 0x20 | ||
47 | 48 | ||
48 | /* Only used in br_forward.c */ | 49 | /* Only used in br_forward.c */ |
49 | extern int nf_bridge_copy_header(struct sk_buff *skb); | 50 | extern int nf_bridge_copy_header(struct sk_buff *skb); |
@@ -75,6 +76,8 @@ static inline int br_nf_pre_routing_finish_bridge_slow(struct sk_buff *skb) | |||
75 | 76 | ||
76 | skb_pull(skb, ETH_HLEN); | 77 | skb_pull(skb, ETH_HLEN); |
77 | nf_bridge->mask ^= BRNF_BRIDGED_DNAT; | 78 | nf_bridge->mask ^= BRNF_BRIDGED_DNAT; |
79 | skb_copy_to_linear_data_offset(skb, -(ETH_HLEN-ETH_ALEN), | ||
80 | skb->nf_bridge->data, ETH_HLEN-ETH_ALEN); | ||
78 | skb->dev = nf_bridge->physindev; | 81 | skb->dev = nf_bridge->physindev; |
79 | return br_handle_frame_finish(skb); | 82 | return br_handle_frame_finish(skb); |
80 | } | 83 | } |
diff --git a/include/net/neighbour.h b/include/net/neighbour.h index da1d58be31b7..eb21340a573b 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h | |||
@@ -299,6 +299,20 @@ static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb) | |||
299 | return 0; | 299 | return 0; |
300 | } | 300 | } |
301 | 301 | ||
302 | #ifdef CONFIG_BRIDGE_NETFILTER | ||
303 | static inline int neigh_hh_bridge(struct hh_cache *hh, struct sk_buff *skb) | ||
304 | { | ||
305 | unsigned seq, hh_alen; | ||
306 | |||
307 | do { | ||
308 | seq = read_seqbegin(&hh->hh_lock); | ||
309 | hh_alen = HH_DATA_ALIGN(ETH_HLEN); | ||
310 | memcpy(skb->data - hh_alen, hh->hh_data, ETH_ALEN + hh_alen - ETH_HLEN); | ||
311 | } while (read_seqretry(&hh->hh_lock, seq)); | ||
312 | return 0; | ||
313 | } | ||
314 | #endif | ||
315 | |||
302 | static inline int neigh_hh_output(struct hh_cache *hh, struct sk_buff *skb) | 316 | static inline int neigh_hh_output(struct hh_cache *hh, struct sk_buff *skb) |
303 | { | 317 | { |
304 | unsigned seq; | 318 | unsigned seq; |