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 8f01386..27152c8 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 83d505f..dcef792 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 1e549d8..cb68d60 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);