]> git.proxmox.com Git - mirror_ovs.git/blobdiff - lib/ovs-router.c
stopwatch: Remove tabs from output.
[mirror_ovs.git] / lib / ovs-router.c
index b387657f8faae2d533d664402bd814467d469907..bfb2b7071bc08c582a4f42685dfcadaa269dc914 100644 (file)
 
 #include "ovs-router.h"
 
+#include <sys/types.h>
+#include <netinet/in.h>
 #include <arpa/inet.h>
 #include <errno.h>
 #include <inttypes.h>
 #include <sys/socket.h>
 #include <net/if.h>
-#include <netinet/in.h>
 #include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
@@ -44,8 +45,6 @@
 #include "unixctl.h"
 #include "util.h"
 #include "unaligned.h"
-#include "unixctl.h"
-#include "util.h"
 #include "openvswitch/vlog.h"
 
 VLOG_DEFINE_THIS_MODULE(ovs_router);
@@ -55,6 +54,10 @@ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
 static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
 static struct classifier cls;
 
+/* By default, use the system routing table.  For system-independent testing,
+ * the unit tests disable using the system routing table. */
+static bool use_system_routing_table = true;
+
 struct ovs_router_entry {
     struct cls_rule cr;
     char output_bridge[IFNAMSIZ];
@@ -63,17 +66,22 @@ struct ovs_router_entry {
     struct in6_addr src_addr;
     uint8_t plen;
     uint8_t priority;
+    bool local;
     uint32_t mark;
 };
 
 static struct ovs_router_entry *
 ovs_router_entry_cast(const struct cls_rule *cr)
 {
-    if (offsetof(struct ovs_router_entry, cr) == 0) {
-        return CONTAINER_OF(cr, struct ovs_router_entry, cr);
-    } else {
-        return cr ? CONTAINER_OF(cr, struct ovs_router_entry, cr) : NULL;
-    }
+    return cr ? CONTAINER_OF(cr, struct ovs_router_entry, cr) : NULL;
+}
+
+/* Disables obtaining routes from the system routing table, for testing
+ * purposes. */
+void
+ovs_router_disable_system_routing_table(void)
+{
+    use_system_routing_table = false;
 }
 
 static bool
@@ -82,7 +90,8 @@ ovs_router_lookup_fallback(const struct in6_addr *ip6_dst, char output_bridge[],
 {
     ovs_be32 src;
 
-    if (!route_table_fallback_lookup(ip6_dst, output_bridge, gw6)) {
+    if (!use_system_routing_table
+        || !route_table_fallback_lookup(ip6_dst, output_bridge, gw6)) {
         return false;
     }
     if (netdev_get_in4_by_name(output_bridge, (struct in_addr *)&src)) {
@@ -102,13 +111,28 @@ ovs_router_lookup(uint32_t mark, const struct in6_addr *ip6_dst,
     const struct cls_rule *cr;
     struct flow flow = {.ipv6_dst = *ip6_dst, .pkt_mark = mark};
 
+    if (src && ipv6_addr_is_set(src)) {
+        const struct cls_rule *cr_src;
+        struct flow flow_src = {.ipv6_dst = *src, .pkt_mark = mark};
+
+        cr_src = classifier_lookup(&cls, OVS_VERSION_MAX, &flow_src, NULL);
+        if (cr_src) {
+            struct ovs_router_entry *p_src = ovs_router_entry_cast(cr_src);
+            if (!p_src->local) {
+                return false;
+            }
+        } else {
+            return false;
+        }
+    }
+
     cr = classifier_lookup(&cls, OVS_VERSION_MAX, &flow, NULL);
     if (cr) {
         struct ovs_router_entry *p = ovs_router_entry_cast(cr);
 
         ovs_strlcpy(output_bridge, p->output_bridge, IFNAMSIZ);
         *gw = p->gw;
-        if (src) {
+        if (src && !ipv6_addr_is_set(src)) {
             *src = p->src_addr;
         }
         return true;
@@ -189,7 +213,7 @@ out:
 }
 
 static int
-ovs_router_insert__(uint32_t mark, uint8_t priority,
+ovs_router_insert__(uint32_t mark, uint8_t priority, bool local,
                     const struct in6_addr *ip6_dst,
                     uint8_t plen, const char output_bridge[],
                     const struct in6_addr *gw)
@@ -209,6 +233,7 @@ ovs_router_insert__(uint32_t mark, uint8_t priority,
     p->mark = mark;
     p->nw_addr = match.flow.ipv6_dst;
     p->plen = plen;
+    p->local = local;
     p->priority = priority;
     err = get_src_addr(ip6_dst, output_bridge, &p->src_addr);
     if (err && ipv6_addr_is_set(gw)) {
@@ -241,24 +266,23 @@ ovs_router_insert__(uint32_t mark, uint8_t priority,
 
 void
 ovs_router_insert(uint32_t mark, const struct in6_addr *ip_dst, uint8_t plen,
-                  const char output_bridge[], const struct in6_addr *gw)
+                  bool local, const char output_bridge[], 
+                  const struct in6_addr *gw)
 {
-    ovs_router_insert__(mark, plen, ip_dst, plen, output_bridge, gw);
+    if (use_system_routing_table) {
+        uint8_t priority = local ? plen + 64 : plen;
+        ovs_router_insert__(mark, priority, local, ip_dst, plen, output_bridge, gw);
+    }
 }
 
-static bool
-__rt_entry_delete(const struct cls_rule *cr)
+static void
+rt_entry_delete__(const struct cls_rule *cr)
 {
     struct ovs_router_entry *p = ovs_router_entry_cast(cr);
 
     tnl_port_map_delete_ipdev(p->output_bridge);
-    /* Remove it. */
-    cr = classifier_remove(&cls, cr);
-    if (cr) {
-        ovsrcu_postpone(rt_entry_free, ovs_router_entry_cast(cr));
-        return true;
-    }
-    return false;
+    classifier_remove_assert(&cls, cr);
+    ovsrcu_postpone(rt_entry_free, ovs_router_entry_cast(cr));
 }
 
 static bool
@@ -278,8 +302,10 @@ rt_entry_delete(uint32_t mark, uint8_t priority,
     cr = classifier_find_rule_exactly(&cls, &rule, OVS_VERSION_MAX);
     if (cr) {
         ovs_mutex_lock(&mutex);
-        res = __rt_entry_delete(cr);
+        rt_entry_delete__(cr);
         ovs_mutex_unlock(&mutex);
+
+        res = true;
     }
 
     cls_rule_destroy(&rule);
@@ -353,7 +379,7 @@ ovs_router_add(struct unixctl_conn *conn, int argc,
         }
     }
 
-    err = ovs_router_insert__(mark, plen + 32, &ip6, plen, argv[2], &gw6);
+    err = ovs_router_insert__(mark, plen + 32, false, &ip6, plen, argv[2], &gw6);
     if (err) {
         unixctl_command_reply_error(conn, "Error while inserting route.");
     } else {
@@ -402,7 +428,7 @@ ovs_router_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
     ds_put_format(&ds, "Route Table:\n");
     CLS_FOR_EACH(rt, cr, &cls) {
         uint8_t plen;
-        if (rt->priority == rt->plen) {
+        if (rt->priority == rt->plen || rt->local) {
             ds_put_format(&ds, "Cached: ");
         } else {
             ds_put_format(&ds, "User: ");
@@ -424,6 +450,9 @@ ovs_router_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
         }
         ds_put_format(&ds, " SRC ");
         ipv6_format_mapped(&rt->src_addr, &ds);
+        if (rt->local) {
+            ds_put_format(&ds, " local");
+        }
         ds_put_format(&ds, "\n");
     }
     unixctl_command_reply(conn, ds_cstr(&ds));
@@ -434,7 +463,7 @@ static void
 ovs_router_lookup_cmd(struct unixctl_conn *conn, int argc,
                       const char *argv[], void *aux OVS_UNUSED)
 {
-    struct in6_addr gw, src;
+    struct in6_addr gw, src = in6addr_any;
     char iface[IFNAMSIZ];
     struct in6_addr ip6;
     unsigned int plen;
@@ -477,7 +506,7 @@ ovs_router_flush(void)
     classifier_defer(&cls);
     CLS_FOR_EACH(rt, cr, &cls) {
         if (rt->priority == rt->plen) {
-            __rt_entry_delete(&rt->cr);
+            rt_entry_delete__(&rt->cr);
         }
     }
     classifier_publish(&cls);