Global replace of Nicira Networks.
[sliver-openvswitch.git] / datapath / tunnel.c
index 41907b9..c2133bb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2011 Nicira Networks.
+ * Copyright (c) 2007-2012 Nicira, Inc.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of version 2 of the GNU General Public
@@ -16,6 +16,8 @@
  * 02110-1301, USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/if_arp.h>
 #include <linux/if_ether.h>
 #include <linux/ip.h>
@@ -109,7 +111,7 @@ static unsigned int multicast_ports __read_mostly;
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0)
 static struct hh_cache *rt_hh(struct rtable *rt)
 {
-       struct neighbour *neigh = dst_get_neighbour(&rt->dst);
+       struct neighbour *neigh = dst_get_neighbour_noref(&rt->dst);
        if (!neigh || !(neigh->nud_state & NUD_CONNECTED) ||
                        !neigh->hh.hh_len)
                return NULL;
@@ -169,7 +171,7 @@ static void free_mutable_rtnl(struct tnl_mutable_config *mutable)
        ASSERT_RTNL();
        if (ipv4_is_multicast(mutable->key.daddr) && mutable->mlink) {
                struct in_device *in_dev;
-               in_dev = inetdev_by_index(&init_net, mutable->mlink);
+               in_dev = inetdev_by_index(port_key_get_net(&mutable->key), mutable->mlink);
                if (in_dev)
                        ip_mc_dec_group(in_dev, mutable->key.daddr);
        }
@@ -299,14 +301,15 @@ static struct vport *port_table_lookup(struct port_lookup_key *key,
        return NULL;
 }
 
-struct vport *ovs_tnl_find_port(__be32 saddr, __be32 daddr, __be64 key,
-                               int tunnel_type,
+struct vport *ovs_tnl_find_port(struct net *net, __be32 saddr, __be32 daddr,
+                               __be64 key, int tunnel_type,
                                const struct tnl_mutable_config **mutable)
 {
        struct port_lookup_key lookup;
        struct vport *vport;
        bool is_multicast = ipv4_is_multicast(saddr);
 
+       port_key_set_net(&lookup, net);
        lookup.saddr = saddr;
        lookup.daddr = daddr;
 
@@ -538,6 +541,7 @@ static bool ipv6_should_icmp(struct sk_buff *skb)
        int addr_type;
        int payload_off = (u8 *)(old_ipv6h + 1) - skb->data;
        u8 nexthdr = ipv6_hdr(skb)->nexthdr;
+       __be16 frag_off;
 
        /* Check source address is valid. */
        addr_type = ipv6_addr_type(&old_ipv6h->saddr);
@@ -549,7 +553,7 @@ static bool ipv6_should_icmp(struct sk_buff *skb)
                return false;
 
        /* Don't respond to ICMP error messages. */
-       payload_off = ipv6_skip_exthdr(skb, payload_off, &nexthdr);
+       payload_off = ipv6_skip_exthdr(skb, payload_off, &nexthdr, &frag_off);
        if (payload_off < 0)
                return false;
 
@@ -587,8 +591,8 @@ static void ipv6_build_icmp(struct sk_buff *skb, struct sk_buff *nskb,
                                              + payload_length);
        ipv6h->nexthdr          =       NEXTHDR_ICMP;
        ipv6h->hop_limit        =       IPV6_DEFAULT_HOPLIMIT;
-       ipv6_addr_copy(&ipv6h->daddr, &old_ipv6h->saddr);
-       ipv6_addr_copy(&ipv6h->saddr, &old_ipv6h->daddr);
+       ipv6h->daddr            =       old_ipv6h->saddr;
+       ipv6h->saddr            =       old_ipv6h->daddr;
 
        /* ICMPv6 */
        icmp6h->icmp6_type      =       ICMPV6_PKT_TOOBIG;
@@ -810,6 +814,13 @@ static void *get_cached_header(const struct tnl_cache *cache)
        return (void *)cache + ALIGN(sizeof(struct tnl_cache), CACHE_DATA_ALIGN);
 }
 
+#ifdef HAVE_RT_GENID
+static inline int rt_genid(struct net *net)
+{
+       return atomic_read(&net->ipv4.rt_genid);
+}
+#endif
+
 static bool check_cache_valid(const struct tnl_cache *cache,
                              const struct tnl_mutable_config *mutable)
 {
@@ -824,7 +835,7 @@ static bool check_cache_valid(const struct tnl_cache *cache,
                time_before(jiffies, cache->expiration) &&
 #endif
 #ifdef HAVE_RT_GENID
-               atomic_read(&init_net.ipv4.rt_genid) == cache->rt->rt_genid &&
+               rt_genid(dev_net(rt_dst(cache->rt).dev)) == cache->rt->rt_genid &&
 #endif
 #ifdef HAVE_HH_SEQ
                hh->hh_lock.sequence == cache->hh_seq &&
@@ -857,7 +868,7 @@ static void cache_cleaner(struct work_struct *work)
        for (i = 0; i < PORT_TABLE_SIZE; i++) {
                struct hlist_node *n;
                struct hlist_head *bucket;
-               struct tnl_vport  *tnl_vport;
+               struct tnl_vport *tnl_vport;
 
                bucket = &port_table[i];
                hlist_for_each_entry_rcu(tnl_vport, n, bucket, hash_node)
@@ -999,7 +1010,7 @@ static struct rtable *__find_route(const struct tnl_mutable_config *mutable,
                            .proto = ipproto };
        struct rtable *rt;
 
-       if (unlikely(ip_route_output_key(&init_net, &rt, &fl)))
+       if (unlikely(ip_route_output_key(port_key_get_net(&mutable->key), &rt, &fl)))
                return ERR_PTR(-EADDRNOTAVAIL);
 
        return rt;
@@ -1009,7 +1020,7 @@ static struct rtable *__find_route(const struct tnl_mutable_config *mutable,
                             .flowi4_tos = tos,
                             .flowi4_proto = ipproto };
 
-       return ip_route_output_key(&init_net, &fl);
+       return ip_route_output_key(port_key_get_net(&mutable->key), &fl);
 #endif
 }
 
@@ -1359,7 +1370,8 @@ static const struct nla_policy tnl_policy[OVS_TUNNEL_ATTR_MAX + 1] = {
 
 /* Sets OVS_TUNNEL_ATTR_* fields in 'mutable', which must initially be
  * zeroed. */
-static int tnl_set_config(struct nlattr *options, const struct tnl_ops *tnl_ops,
+static int tnl_set_config(struct net *net, struct nlattr *options,
+                         const struct tnl_ops *tnl_ops,
                          const struct vport *cur_vport,
                          struct tnl_mutable_config *mutable)
 {
@@ -1380,6 +1392,7 @@ static int tnl_set_config(struct nlattr *options, const struct tnl_ops *tnl_ops,
 
        mutable->flags = nla_get_u32(a[OVS_TUNNEL_ATTR_FLAGS]) & TNL_F_PUBLIC;
 
+       port_key_set_net(&mutable->key, net);
        mutable->key.daddr = nla_get_be32(a[OVS_TUNNEL_ATTR_DST_IPV4]);
        if (a[OVS_TUNNEL_ATTR_SRC_IPV4]) {
                if (ipv4_is_multicast(mutable->key.daddr))
@@ -1471,7 +1484,8 @@ struct vport *ovs_tnl_create(const struct vport_parms *parms,
        get_random_bytes(&initial_frag_id, sizeof(int));
        atomic_set(&tnl_vport->frag_id, initial_frag_id);
 
-       err = tnl_set_config(parms->options, tnl_ops, NULL, mutable);
+       err = tnl_set_config(ovs_dp_get_net(parms->dp), parms->options, tnl_ops,
+                            NULL, mutable);
        if (err)
                goto error_free_mutable;
 
@@ -1515,7 +1529,8 @@ int ovs_tnl_set_options(struct vport *vport, struct nlattr *options)
        memcpy(mutable->eth_addr, old_mutable->eth_addr, ETH_ALEN);
 
        /* Parse the others configured by userspace. */
-       err = tnl_set_config(options, tnl_vport->tnl_ops, vport, mutable);
+       err = tnl_set_config(ovs_dp_get_net(vport->dp), options, tnl_vport->tnl_ops,
+                            vport, mutable);
        if (err)
                goto error_free;
 
@@ -1538,19 +1553,24 @@ int ovs_tnl_get_options(const struct vport *vport, struct sk_buff *skb)
        const struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
        const struct tnl_mutable_config *mutable = rcu_dereference_rtnl(tnl_vport->mutable);
 
-       NLA_PUT_U32(skb, OVS_TUNNEL_ATTR_FLAGS, mutable->flags & TNL_F_PUBLIC);
-       NLA_PUT_BE32(skb, OVS_TUNNEL_ATTR_DST_IPV4, mutable->key.daddr);
-
-       if (!(mutable->flags & TNL_F_IN_KEY_MATCH))
-               NLA_PUT_BE64(skb, OVS_TUNNEL_ATTR_IN_KEY, mutable->key.in_key);
-       if (!(mutable->flags & TNL_F_OUT_KEY_ACTION))
-               NLA_PUT_BE64(skb, OVS_TUNNEL_ATTR_OUT_KEY, mutable->out_key);
-       if (mutable->key.saddr)
-               NLA_PUT_BE32(skb, OVS_TUNNEL_ATTR_SRC_IPV4, mutable->key.saddr);
-       if (mutable->tos)
-               NLA_PUT_U8(skb, OVS_TUNNEL_ATTR_TOS, mutable->tos);
-       if (mutable->ttl)
-               NLA_PUT_U8(skb, OVS_TUNNEL_ATTR_TTL, mutable->ttl);
+       if (nla_put_u32(skb, OVS_TUNNEL_ATTR_FLAGS,
+                     mutable->flags & TNL_F_PUBLIC) ||
+           nla_put_be32(skb, OVS_TUNNEL_ATTR_DST_IPV4, mutable->key.daddr))
+               goto nla_put_failure;
+
+       if (!(mutable->flags & TNL_F_IN_KEY_MATCH) &&
+           nla_put_be64(skb, OVS_TUNNEL_ATTR_IN_KEY, mutable->key.in_key))
+               goto nla_put_failure;
+       if (!(mutable->flags & TNL_F_OUT_KEY_ACTION) &&
+           nla_put_be64(skb, OVS_TUNNEL_ATTR_OUT_KEY, mutable->out_key))
+               goto nla_put_failure;
+       if (mutable->key.saddr &&
+           nla_put_be32(skb, OVS_TUNNEL_ATTR_SRC_IPV4, mutable->key.saddr))
+               goto nla_put_failure;
+       if (mutable->tos && nla_put_u8(skb, OVS_TUNNEL_ATTR_TOS, mutable->tos))
+               goto nla_put_failure;
+       if (mutable->ttl && nla_put_u8(skb, OVS_TUNNEL_ATTR_TTL, mutable->ttl))
+               goto nla_put_failure;
 
        return 0;
 
@@ -1623,7 +1643,7 @@ int ovs_tnl_init(void)
        int i;
 
        port_table = kmalloc(PORT_TABLE_SIZE * sizeof(struct hlist_head *),
-                       GFP_KERNEL);
+                            GFP_KERNEL);
        if (!port_table)
                return -ENOMEM;
 
@@ -1635,19 +1655,5 @@ int ovs_tnl_init(void)
 
 void ovs_tnl_exit(void)
 {
-       int i;
-
-       for (i = 0; i < PORT_TABLE_SIZE; i++) {
-               struct tnl_vport *tnl_vport;
-               struct hlist_head *hash_head;
-               struct hlist_node *n;
-
-               hash_head = &port_table[i];
-               hlist_for_each_entry(tnl_vport, n, hash_head, hash_node) {
-                       BUG();
-                       goto out;
-               }
-       }
-out:
        kfree(port_table);
 }