ofpbuf: Fix trivial spelling typo.
[cascardo/ovs.git] / lib / tnl-ports.c
index f510f1e..e7f2066 100644 (file)
  */
 
 #include <config.h>
+
+#include "tnl-ports.h"
+
 #include <stddef.h>
 #include <stdint.h>
+#include <string.h>
 
 #include "classifier.h"
 #include "dynamic-string.h"
 #include "hash.h"
 #include "list.h"
+#include "netdev.h"
 #include "ofpbuf.h"
 #include "ovs-thread.h"
 #include "odp-util.h"
-#include "tnl-arp-cache.h"
-#include "tnl-ports.h"
 #include "ovs-thread.h"
 #include "unixctl.h"
 #include "util.h"
@@ -37,7 +40,8 @@ static struct classifier cls;   /* Tunnel ports. */
 struct ip_device {
     struct netdev *dev;
     struct eth_addr mac;
-    ovs_be32 addr;
+    ovs_be32 addr4;
+    struct in6_addr addr6;
     uint64_t change_seq;
     struct ovs_list node;
     char dev_name[IFNAMSIZ];
@@ -78,13 +82,18 @@ tnl_port_free(struct tnl_port_in *p)
 
 static void
 tnl_port_init_flow(struct flow *flow, struct eth_addr mac,
-                   ovs_be32 addr, ovs_be16 udp_port)
+                   struct in6_addr *addr, ovs_be16 udp_port)
 {
     memset(flow, 0, sizeof *flow);
 
-    flow->dl_type = htons(ETH_TYPE_IP);
     flow->dl_dst = mac;
-    flow->nw_dst = addr;
+    if (IN6_IS_ADDR_V4MAPPED(addr)) {
+        flow->dl_type = htons(ETH_TYPE_IP);
+        flow->nw_dst = in6_addr_get_mapped_ipv4(addr);
+    } else {
+        flow->dl_type = htons(ETH_TYPE_IPV6);
+        flow->ipv6_dst = *addr;
+    }
 
     if (udp_port) {
         flow->nw_proto = IPPROTO_UDP;
@@ -95,7 +104,7 @@ tnl_port_init_flow(struct flow *flow, struct eth_addr mac,
 }
 
 static void
-map_insert(odp_port_t port, struct eth_addr mac, ovs_be32 addr,
+map_insert(odp_port_t port, struct eth_addr mac, struct in6_addr *addr,
            ovs_be16 udp_port, const char dev_name[])
 {
     const struct cls_rule *cr;
@@ -117,9 +126,19 @@ map_insert(odp_port_t port, struct eth_addr mac, ovs_be32 addr,
 
         match.wc.masks.dl_type = OVS_BE16_MAX;
         match.wc.masks.nw_proto = 0xff;
-        match.wc.masks.nw_frag = 0xff;      /* XXX: No fragments support. */
-        match.wc.masks.tp_dst = OVS_BE16_MAX;
-        match.wc.masks.nw_dst = OVS_BE32_MAX;
+         /* XXX: No fragments support. */
+        match.wc.masks.nw_frag = FLOW_NW_FRAG_MASK;
+
+        /* 'udp_port' is zero for non-UDP tunnels (e.g. GRE). In this case it
+         * doesn't make sense to match on UDP port numbers. */
+        if (udp_port) {
+            match.wc.masks.tp_dst = OVS_BE16_MAX;
+        }
+        if (IN6_IS_ADDR_V4MAPPED(addr)) {
+            match.wc.masks.nw_dst = OVS_BE32_MAX;
+        } else {
+            match.wc.masks.ipv6_dst = in6addr_exact;
+        }
         match.wc.masks.vlan_tci = OVS_BE16_MAX;
         memset(&match.wc.masks.dl_dst, 0xff, sizeof (struct eth_addr));
 
@@ -152,8 +171,15 @@ tnl_port_map_insert(odp_port_t port,
     list_insert(&port_list, &p->node);
 
     LIST_FOR_EACH(ip_dev, node, &addr_list) {
-        map_insert(p->port, ip_dev->mac, ip_dev->addr,
-                   p->udp_port, p->dev_name);
+        if (ip_dev->addr4 != INADDR_ANY) {
+            struct in6_addr addr4 = in6_addr_mapped_ipv4(ip_dev->addr4);
+            map_insert(p->port, ip_dev->mac, &addr4,
+                       p->udp_port, p->dev_name);
+        }
+        if (ipv6_addr_is_set(&ip_dev->addr6)) {
+            map_insert(p->port, ip_dev->mac, &ip_dev->addr6,
+                       p->udp_port, p->dev_name);
+        }
     }
 
 out:
@@ -173,7 +199,7 @@ tnl_port_unref(const struct cls_rule *cr)
 }
 
 static void
-map_delete(struct eth_addr mac, ovs_be32 addr, ovs_be16 udp_port)
+map_delete(struct eth_addr mac, struct in6_addr *addr, ovs_be16 udp_port)
 {
     const struct cls_rule *cr;
     struct flow flow;
@@ -204,7 +230,13 @@ tnl_port_map_delete(ovs_be16 udp_port)
         goto out;
     }
     LIST_FOR_EACH(ip_dev, node, &addr_list) {
-        map_delete(ip_dev->mac, ip_dev->addr, udp_port);
+        if (ip_dev->addr4 != INADDR_ANY) {
+            struct in6_addr addr4 = in6_addr_mapped_ipv4(ip_dev->addr4);
+            map_delete(ip_dev->mac, &addr4, udp_port);
+        }
+        if (ipv6_addr_is_set(&ip_dev->addr6)) {
+            map_delete(ip_dev->mac, &ip_dev->addr6, udp_port);
+        }
     }
 
     free(p);
@@ -299,8 +331,15 @@ map_insert_ipdev(struct ip_device *ip_dev)
     struct tnl_port *p;
 
     LIST_FOR_EACH(p, node, &port_list) {
-        map_insert(p->port, ip_dev->mac, ip_dev->addr,
-                   p->udp_port, p->dev_name);
+        if (ip_dev->addr4 != INADDR_ANY) {
+            struct in6_addr addr4 = in6_addr_mapped_ipv4(ip_dev->addr4);
+            map_insert(p->port, ip_dev->mac, &addr4,
+                       p->udp_port, p->dev_name);
+        }
+        if (ipv6_addr_is_set(&ip_dev->addr6)) {
+            map_insert(p->port, ip_dev->mac, &ip_dev->addr6,
+                       p->udp_port, p->dev_name);
+        }
     }
 }
 
@@ -311,6 +350,7 @@ insert_ipdev(const char dev_name[])
     enum netdev_flags flags;
     struct netdev *dev;
     int error;
+    int error4, error6;
 
     error = netdev_open(dev_name, NULL, &dev);
     if (error) {
@@ -328,10 +368,13 @@ insert_ipdev(const char dev_name[])
     ip_dev->change_seq = netdev_get_change_seq(dev);
     error = netdev_get_etheraddr(ip_dev->dev, &ip_dev->mac);
     if (error) {
+        free(ip_dev);
         return;
     }
-    error = netdev_get_in4(ip_dev->dev, (struct in_addr *)&ip_dev->addr, NULL);
-    if (error) {
+    error4 = netdev_get_in4(ip_dev->dev, (struct in_addr *)&ip_dev->addr4, NULL);
+    error6 = netdev_get_in6(ip_dev->dev, &ip_dev->addr6);
+    if (error4 && error6) {
+        free(ip_dev);
         return;
     }
     ovs_strlcpy(ip_dev->dev_name, netdev_get_name(dev), sizeof ip_dev->dev_name);
@@ -346,7 +389,13 @@ delete_ipdev(struct ip_device *ip_dev)
     struct tnl_port *p;
 
     LIST_FOR_EACH(p, node, &port_list) {
-        map_delete(ip_dev->mac, ip_dev->addr, p->udp_port);
+        if (ip_dev->addr4 != INADDR_ANY) {
+            struct in6_addr addr4 = in6_addr_mapped_ipv4(ip_dev->addr4);
+            map_delete(ip_dev->mac, &addr4, p->udp_port);
+        }
+        if (ipv6_addr_is_set(&ip_dev->addr6)) {
+            map_delete(ip_dev->mac, &ip_dev->addr6, p->udp_port);
+        }
     }
 
     list_remove(&ip_dev->node);
@@ -357,11 +406,11 @@ delete_ipdev(struct ip_device *ip_dev)
 void
 tnl_port_map_insert_ipdev(const char dev_name[])
 {
-    struct ip_device *ip_dev;
+    struct ip_device *ip_dev, *next;
 
     ovs_mutex_lock(&mutex);
 
-    LIST_FOR_EACH(ip_dev, node, &addr_list) {
+    LIST_FOR_EACH_SAFE(ip_dev, next, node, &addr_list) {
         if (!strcmp(netdev_get_name(ip_dev->dev), dev_name)) {
             if (ip_dev->change_seq == netdev_get_change_seq(ip_dev->dev)) {
                 goto out;
@@ -394,10 +443,10 @@ tnl_port_map_delete_ipdev(const char dev_name[])
 void
 tnl_port_map_run(void)
 {
-    struct ip_device *ip_dev;
+    struct ip_device *ip_dev, *next;
 
     ovs_mutex_lock(&mutex);
-    LIST_FOR_EACH(ip_dev, node, &addr_list) {
+    LIST_FOR_EACH_SAFE(ip_dev, next, node, &addr_list) {
         char dev_name[IFNAMSIZ];
 
         if (ip_dev->change_seq == netdev_get_change_seq(ip_dev->dev)) {