From 2f58a5d0031edb0cc90454ccb0883d61120e63a8 Mon Sep 17 00:00:00 2001 From: Justin Pettit Date: Tue, 21 Oct 2008 17:16:28 -0700 Subject: [PATCH] Fix crash when SNAT support is built and traffic is in-band. In order to make netfilter happy, we have to create a fake routing table entry. Unfortunately, the kernel really doesn't like this when it actually needs to make use of it. This code now removes the link between the packet and the fake routing entry when the packet is being sent to a local port. --- datapath/datapath.c | 3 +++ datapath/nx_act_snat.c | 17 ++++++++++++++--- datapath/nx_act_snat.h | 1 + 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/datapath/datapath.c b/datapath/datapath.c index 8f01386a9..27152c865 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -631,6 +631,9 @@ int dp_output_port(struct datapath *dp, struct sk_buff *skb, int out_port, case OFPP_LOCAL: { struct net_device *dev = dp->netdev; +#ifdef SUPPORT_SNAT + snat_local_in(skb); +#endif return dev ? dp_dev_recv(dev, skb) : -ESRCH; } diff --git a/datapath/nx_act_snat.c b/datapath/nx_act_snat.c index 83d505fbd..dcef792e4 100644 --- a/datapath/nx_act_snat.c +++ b/datapath/nx_act_snat.c @@ -97,6 +97,17 @@ done: spin_unlock_irqrestore(&p->lock, flags); } +/* When the packet is bound for a local interface, strip off the fake + * routing table. + */ +void snat_local_in(struct sk_buff *skb) +{ + if (skb->dst == (struct dst_entry *)&__fake_rtable) { + dst_release(skb->dst); + skb->dst = NULL; + } +} + /* Check whether destination IP's address is in the IP->MAC mappings. * If it is, then overwrite the destination MAC with the value from the * cache. @@ -147,6 +158,9 @@ snat_pre_route_finish(struct sk_buff *skb) { struct net_bridge_port *p = skb->dev->br_port; + skb->dst = (struct dst_entry *)&__fake_rtable; + dst_hold(skb->dst); + /* If SNAT is configured for this input device, check the IP->MAC * mappings to see if we should update the destination MAC. */ if (p->snat) @@ -308,9 +322,6 @@ snat_pre_route(struct sk_buff *skb) if (pskb_trim_rcsum(skb, len)) goto ipv4_error; - skb->dst = (struct dst_entry *)&__fake_rtable; - dst_hold(skb->dst); - return NF_HOOK(PF_INET, NF_INET_PRE_ROUTING, skb, skb->dev, NULL, snat_pre_route_finish); diff --git a/datapath/nx_act_snat.h b/datapath/nx_act_snat.h index 1e549d8ad..cb68d60ad 100644 --- a/datapath/nx_act_snat.h +++ b/datapath/nx_act_snat.h @@ -28,6 +28,7 @@ struct snat_conf { #define MAC_TIMEOUT_DEFAULT 120 +void snat_local_in(struct sk_buff *skb); int snat_pre_route(struct sk_buff *skb); void snat_skb(struct datapath *dp, struct sk_buff *skb, int out_port); void snat_maint(struct net_bridge_port *p); -- 2.43.0