Fix crash when SNAT support is built and traffic is in-band.
authorJustin Pettit <jpettit@nicira.com>
Wed, 22 Oct 2008 00:16:28 +0000 (17:16 -0700)
committerJustin Pettit <jpettit@nicira.com>
Wed, 22 Oct 2008 00:16:46 +0000 (17:16 -0700)
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
datapath/nx_act_snat.c
datapath/nx_act_snat.h

index 8f01386a95b6be890aa00965154c1e7effb950c5..27152c8656a518ba69908f2b50c4b2c63c05807c 100644 (file)
@@ -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;
        }
 
index 83d505fbde0c59893df1df38ef564f1332dc023f..dcef792e417eb40be9805a1b955e8b437d5f21ac 100644 (file)
@@ -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);
 
index 1e549d8ad0d22c942da403da508477c22c36c194..cb68d60adbdfc3a950a9b3a3c68480f0b6815dad 100644 (file)
@@ -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);