datapath: Always use generic stats for devices (vports)
[sliver-openvswitch.git] / datapath / vport-gre.c
index be8fb53..5beae42 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Nicira Networks.
+ * Copyright (c) 2010, 2011 Nicira Networks.
  * Distributed under the terms of the GNU GPL version 2.
  *
  * Significant portions of this file may be copied from parts of the Linux
@@ -34,22 +34,31 @@ struct gre_base_hdr {
        __be16 protocol;
 };
 
-static int gre_hdr_len(const struct tnl_port_config *port_config)
+static int gre_hdr_len(const struct tnl_mutable_config *mutable)
 {
        int len;
 
        len = GRE_HEADER_SECTION;
 
-       if (port_config->flags & TNL_F_CSUM)
+       if (mutable->flags & TNL_F_CSUM)
                len += GRE_HEADER_SECTION;
 
-       if (port_config->out_key ||
-           port_config->flags & TNL_F_OUT_KEY_ACTION)
+       if (mutable->out_key || mutable->flags & TNL_F_OUT_KEY_ACTION)
                len += GRE_HEADER_SECTION;
 
        return len;
 }
 
+/* Returns the least-significant 32 bits of a __be64. */
+static __be32 be64_get_low32(__be64 x)
+{
+#ifdef __BIG_ENDIAN
+       return (__force __be32)x;
+#else
+       return (__force __be32)((__force u64)x >> 32);
+#endif
+}
+
 static void gre_build_header(const struct vport *vport,
                             const struct tnl_mutable_config *mutable,
                             void *header)
@@ -60,18 +69,17 @@ static void gre_build_header(const struct vport *vport,
        greh->protocol = htons(ETH_P_TEB);
        greh->flags = 0;
 
-       if (mutable->port_config.flags & TNL_F_CSUM) {
+       if (mutable->flags & TNL_F_CSUM) {
                greh->flags |= GRE_CSUM;
                *options = 0;
                options++;
        }
 
-       if (mutable->port_config.out_key ||
-           mutable->port_config.flags & TNL_F_OUT_KEY_ACTION)
+       if (mutable->out_key || mutable->flags & TNL_F_OUT_KEY_ACTION)
                greh->flags |= GRE_KEY;
 
-       if (mutable->port_config.out_key)
-               *options = mutable->port_config.out_key;
+       if (mutable->out_key)
+               *options = be64_get_low32(mutable->out_key);
 }
 
 static struct sk_buff *gre_update_header(const struct vport *vport,
@@ -83,26 +91,39 @@ static struct sk_buff *gre_update_header(const struct vport *vport,
                                               - GRE_HEADER_SECTION);
 
        /* Work backwards over the options so the checksum is last. */
-       if (mutable->port_config.flags & TNL_F_OUT_KEY_ACTION) {
-               *options = OVS_CB(skb)->tun_id;
+       if (mutable->flags & TNL_F_OUT_KEY_ACTION) {
+               *options = be64_get_low32(OVS_CB(skb)->tun_id);
                options--;
        }
 
-       if (mutable->port_config.flags & TNL_F_CSUM)
+       if (mutable->flags & TNL_F_CSUM)
                *(__sum16 *)options = csum_fold(skb_checksum(skb,
                                                skb_transport_offset(skb),
                                                skb->len - skb_transport_offset(skb),
                                                0));
        /*
         * Allow our local IP stack to fragment the outer packet even if the
-        * DF bit is set as a last resort.
+        * DF bit is set as a last resort.  We also need to force selection of
+        * an IP ID here because Linux will otherwise leave it at 0 if the
+        * packet originally had DF set.
         */
        skb->local_df = 1;
+       __ip_select_ident(ip_hdr(skb), dst, 0);
 
        return skb;
 }
 
-static int parse_header(struct iphdr *iph, __be16 *flags, __be32 *key)
+/* Zero-extends a __be32 into the least-significant 32 bits of a __be64. */
+static __be64 be32_extend_to_be64(__be32 x)
+{
+#ifdef __BIG_ENDIAN
+       return (__force __be64)x;
+#else
+       return (__force __be64)((__force u64)x << 32);
+#endif
+}
+
+static int parse_header(struct iphdr *iph, __be16 *flags, __be64 *key)
 {
        /* IP and ICMP protocol handlers check that the IHL is valid. */
        struct gre_base_hdr *greh = (struct gre_base_hdr *)((u8 *)iph + (iph->ihl << 2));
@@ -127,7 +148,7 @@ static int parse_header(struct iphdr *iph, __be16 *flags, __be32 *key)
        if (greh->flags & GRE_KEY) {
                hdr_len += GRE_HEADER_SECTION;
 
-               *key = *options;
+               *key = be32_extend_to_be64(*options);
                options++;
        } else
                *key = 0;
@@ -149,7 +170,7 @@ static void gre_err(struct sk_buff *skb, u32 info)
 
        struct iphdr *iph;
        __be16 flags;
-       __be32 key;
+       __be64 key;
        int tunnel_hdr_len, tot_hdr_len;
        unsigned int orig_mac_header;
        unsigned int orig_nw_header;
@@ -186,14 +207,14 @@ static void gre_err(struct sk_buff *skb, u32 info)
         * out key as if it were the in key and then check to see if the input
         * and output keys are the same.
         */
-       if (mutable->port_config.in_key != mutable->port_config.out_key)
+       if (mutable->in_key != mutable->out_key)
                return;
 
-       if (!!(mutable->port_config.flags & TNL_F_IN_KEY_MATCH) !=
-           !!(mutable->port_config.flags & TNL_F_OUT_KEY_ACTION))
+       if (!!(mutable->flags & TNL_F_IN_KEY_MATCH) !=
+           !!(mutable->flags & TNL_F_OUT_KEY_ACTION))
                return;
 
-       if ((mutable->port_config.flags & TNL_F_CSUM) && !(flags & GRE_CSUM))
+       if ((mutable->flags & TNL_F_CSUM) && !(flags & GRE_CSUM))
                return;
 
        tunnel_hdr_len += iph->ihl << 2;
@@ -293,7 +314,7 @@ static int gre_rcv(struct sk_buff *skb)
        int hdr_len;
        struct iphdr *iph;
        __be16 flags;
-       __be32 key;
+       __be64 key;
 
        if (unlikely(!pskb_may_pull(skb, sizeof(struct gre_base_hdr) + ETH_HLEN)))
                goto error;
@@ -316,7 +337,7 @@ static int gre_rcv(struct sk_buff *skb)
                goto error;
        }
 
-       if (mutable->port_config.flags & TNL_F_IN_KEY_MATCH)
+       if (mutable->flags & TNL_F_IN_KEY_MATCH)
                OVS_CB(skb)->tun_id = key;
        else
                OVS_CB(skb)->tun_id = 0;
@@ -324,7 +345,7 @@ static int gre_rcv(struct sk_buff *skb)
        __skb_pull(skb, hdr_len);
        skb_postpull_rcsum(skb, skb_transport_header(skb), hdr_len + ETH_HLEN);
 
-       tnl_rcv(vport, skb);
+       tnl_rcv(vport, skb, iph->tos);
        return 0;
 
 error:
@@ -332,7 +353,7 @@ error:
        return 0;
 }
 
-struct tnl_ops gre_tnl_ops = {
+static const struct tnl_ops gre_tnl_ops = {
        .tunnel_type    = TNL_T_PROTO_GRE,
        .ipproto        = IPPROTO_GRE,
        .hdr_len        = gre_hdr_len,
@@ -340,12 +361,12 @@ struct tnl_ops gre_tnl_ops = {
        .update_header  = gre_update_header,
 };
 
-static struct vport *gre_create(const char *name, const void __user *config)
+static struct vport *gre_create(const struct vport_parms *parms)
 {
-       return tnl_create(name, config, &gre_vport_ops, &gre_tnl_ops);
+       return tnl_create(parms, &gre_vport_ops, &gre_tnl_ops);
 }
 
-static struct net_protocol gre_protocol_handlers = {
+static const struct net_protocol gre_protocol_handlers = {
        .handler        =       gre_rcv,
        .err_handler    =       gre_err,
 };
@@ -366,21 +387,20 @@ static void gre_exit(void)
        inet_del_protocol(&gre_protocol_handlers, IPPROTO_GRE);
 }
 
-struct vport_ops gre_vport_ops = {
-       .type           = "gre",
-       .flags          = VPORT_F_GEN_STATS | VPORT_F_TUN_ID,
+const struct vport_ops gre_vport_ops = {
+       .type           = OVS_VPORT_TYPE_GRE,
+       .flags          = VPORT_F_TUN_ID,
        .init           = gre_init,
        .exit           = gre_exit,
        .create         = gre_create,
-       .modify         = tnl_modify,
        .destroy        = tnl_destroy,
-       .set_mtu        = tnl_set_mtu,
        .set_addr       = tnl_set_addr,
        .get_name       = tnl_get_name,
        .get_addr       = tnl_get_addr,
+       .get_options    = tnl_get_options,
+       .set_options    = tnl_set_options,
        .get_dev_flags  = vport_gen_get_dev_flags,
        .is_running     = vport_gen_is_running,
        .get_operstate  = vport_gen_get_operstate,
-       .get_mtu        = tnl_get_mtu,
        .send           = tnl_send,
 };