datapath: Use ipv4_dst_hoplimit() instead of direct access.
[openvswitch] / datapath / datapath.c
index 74f276b556c269e4c2a98a4dd24282bc3f3d4ba7..8a55001254e8e9488553a634068cc4763e3a615c 100644 (file)
@@ -51,6 +51,7 @@
 #include "flow.h"
 #include "loop_counter.h"
 #include "table.h"
+#include "vlan.h"
 #include "vport-internal_dev.h"
 
 int (*dp_ioctl_hook)(struct net_device *dev, struct ifreq *rq, int cmd);
@@ -358,7 +359,6 @@ static void copy_and_csum_skb(struct sk_buff *skb, void *to)
 
        get_skb_csum_pointers(skb, &csum_start, &csum_offset);
        csum_start -= skb_headroom(skb);
-       BUG_ON(csum_start >= skb_headlen(skb));
 
        skb_copy_bits(skb, 0, to, csum_start);
 
@@ -440,7 +440,11 @@ int dp_upcall(struct datapath *dp, struct sk_buff *skb, const struct dp_upcall_i
                }
        }
 
-       return queue_control_packets(dp, skb, upcall_info);
+       err = queue_control_packets(dp, skb, upcall_info);
+       if (err)
+               goto err;
+
+       return 0;
 
 err_kfree_skb:
        kfree_skb(skb);
@@ -483,6 +487,13 @@ static int queue_control_packets(struct datapath *dp, struct sk_buff *skb,
                nskb = skb->next;
                skb->next = NULL;
 
+               err = vlan_deaccel_tag(skb);
+               if (unlikely(err))
+                       goto err_kfree_skbs;
+
+               if (nla_attr_size(skb->len) > USHRT_MAX)
+                       goto err_kfree_skbs;
+
                len = sizeof(struct odp_header);
                len += nla_total_size(skb->len);
                len += nla_total_size(FLOW_BUFSIZE);
@@ -700,6 +711,9 @@ static int odp_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
        else
                packet->protocol = htons(ETH_P_802_2);
 
+       /* Initialize OVS_CB (it came from Netlink so might not be zeroed). */
+       memset(OVS_CB(packet), 0, sizeof(struct ovs_skb_cb));
+
        err = flow_extract(packet, -1, &key, &is_frag);
        if (err)
                goto exit;
@@ -773,6 +787,8 @@ int dp_min_mtu(const struct datapath *dp)
                        continue;
 
                dev_mtu = vport_get_mtu(p);
+               if (!dev_mtu)
+                       continue;
                if (!mtu || dev_mtu < mtu)
                        mtu = dev_mtu;
        }
@@ -1288,7 +1304,7 @@ static int odp_dp_cmd_validate(struct nlattr *a[ODP_DP_ATTR_MAX + 1])
                        return -EINVAL;
        }
 
-       return VERIFY_NUL_STRING(a[ODP_DP_ATTR_NAME], IFNAMSIZ - 1);
+       return CHECK_NUL_STRING(a[ODP_DP_ATTR_NAME], IFNAMSIZ - 1);
 }
 
 /* Called with genl_mutex and optionally with RTNL lock also. */
@@ -1440,12 +1456,20 @@ static int odp_dp_cmd_del(struct sk_buff *skb, struct genl_info *info)
        list_del(&dp->list_node);
        dp_detach_port(get_vport_protected(dp, ODPP_LOCAL));
 
+       /* rtnl_unlock() will wait until all the references to devices that
+        * are pending unregistration have been dropped.  We do it here to
+        * ensure that any internal devices (which contain DP pointers) are
+        * fully destroyed before freeing the datapath.
+        */
+       rtnl_unlock();
+
        call_rcu(&dp->rcu, destroy_dp_rcu);
        module_put(THIS_MODULE);
 
        genl_notify(reply, genl_info_net(info), info->snd_pid,
                    dp_datapath_multicast_group.id, info->nlhdr, GFP_KERNEL);
-       err = 0;
+
+       return 0;
 
 exit_unlock:
        rtnl_unlock();
@@ -1582,6 +1606,7 @@ static int odp_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb,
        struct odp_header *odp_header;
        struct nlattr *nla;
        int ifindex, iflink;
+       int mtu;
        int err;
 
        odp_header = genlmsg_put(skb, pid, seq, &dp_vport_genl_family,
@@ -1603,7 +1628,9 @@ static int odp_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb,
 
        NLA_PUT(skb, ODP_VPORT_ATTR_ADDRESS, ETH_ALEN, vport_get_addr(vport));
 
-       NLA_PUT_U32(skb, ODP_VPORT_ATTR_MTU, vport_get_mtu(vport));
+       mtu = vport_get_mtu(vport);
+       if (mtu)
+               NLA_PUT_U32(skb, ODP_VPORT_ATTR_MTU, mtu);
 
        err = vport_get_options(vport, skb);
        if (err == -EMSGSIZE)
@@ -1647,7 +1674,7 @@ static struct sk_buff *odp_vport_cmd_build_info(struct vport *vport, u32 pid,
 
 static int odp_vport_cmd_validate(struct nlattr *a[ODP_VPORT_ATTR_MAX + 1])
 {
-       return VERIFY_NUL_STRING(a[ODP_VPORT_ATTR_NAME], IFNAMSIZ - 1);
+       return CHECK_NUL_STRING(a[ODP_VPORT_ATTR_NAME], IFNAMSIZ - 1);
 }
 
 /* Called with RTNL lock or RCU read lock. */