[ovs-dev] [PATCH ovs v1 4/4] ovs-router: Allow openvswitch installing fake routes.

xiangxia.m.yue at gmail.com xiangxia.m.yue at gmail.com
Mon Dec 14 02:20:01 UTC 2020


From: Tonghao Zhang <xiangxia.m.yue at gmail.com>

Now we can only add route entries which are on the
same subnet with openvswitch bridges.

With this patch, users can add "fake" route entries to
openvswich which can use them to encapsulate packets.

Signed-off-by: Tonghao Zhang <xiangxia.m.yue at gmail.com>
---
 lib/ovs-router.c | 121 ++++++++++++++++++++++++++++++++++---------------------
 1 file changed, 75 insertions(+), 46 deletions(-)

diff --git a/lib/ovs-router.c b/lib/ovs-router.c
index 09b81c6e5..9cb9b3540 100644
--- a/lib/ovs-router.c
+++ b/lib/ovs-router.c
@@ -47,6 +47,9 @@
 #include "unaligned.h"
 #include "openvswitch/vlog.h"
 
+#define PRIO_USER(plen) ((plen) + 32)
+#define PRIO_LOCAL(plen) ((plen) + 64)
+
 VLOG_DEFINE_THIS_MODULE(ovs_router);
 
 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
@@ -216,7 +219,8 @@ static int
 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)
+                    const struct in6_addr *gw,
+                    const struct in6_addr *ip6_src)
 {
     const struct cls_rule *cr;
     struct ovs_router_entry *p;
@@ -235,19 +239,24 @@ ovs_router_insert__(uint32_t mark, uint8_t priority, bool local,
     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)) {
-        err = get_src_addr(gw, output_bridge, &p->src_addr);
+    if (!ip6_src || !ipv6_addr_is_set(ip6_src)) {
+        err = get_src_addr(ip6_dst, output_bridge, &p->src_addr);
+        if (err && ipv6_addr_is_set(gw)) {
+            err = get_src_addr(gw, output_bridge, &p->src_addr);
+        }
+        if (err) {
+            struct ds ds = DS_EMPTY_INITIALIZER;
+
+            ipv6_format_mapped(ip6_dst, &ds);
+            VLOG_DBG_RL(&rl, "src addr not available for route %s", ds_cstr(&ds));
+            free(p);
+            ds_destroy(&ds);
+            return err;
+        }
+    } else {
+        p->src_addr = *ip6_src;
     }
-    if (err) {
-        struct ds ds = DS_EMPTY_INITIALIZER;
 
-        ipv6_format_mapped(ip6_dst, &ds);
-        VLOG_DBG_RL(&rl, "src addr not available for route %s", ds_cstr(&ds));
-        free(p);
-        ds_destroy(&ds);
-        return err;
-    }
     /* Longest prefix matches first. */
     cls_rule_init(&p->cr, &match, priority);
 
@@ -270,8 +279,9 @@ ovs_router_insert(uint32_t mark, const struct in6_addr *ip_dst, uint8_t plen,
                   const struct in6_addr *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);
+        uint8_t priority = local ? PRIO_LOCAL(plen) : plen;
+        ovs_router_insert__(mark, priority, local, ip_dst, plen,
+                            output_bridge, gw, NULL);
     }
 }
 
@@ -338,48 +348,64 @@ static void
 ovs_router_add(struct unixctl_conn *conn, int argc,
               const char *argv[], void *aux OVS_UNUSED)
 {
+    struct in6_addr src6 = in6addr_any;
     struct in6_addr gw6 = in6addr_any;
     struct in6_addr ip6;
-    uint32_t mark = 0;
-    unsigned int plen;
+    ovs_be32 src = 0;
+    ovs_be32 gw = 0;
     ovs_be32 ip;
+    bool ipv4_route_entry = true;
+    bool ipv4_local = false;
+    uint32_t lastargc = 0;
+    uint32_t mark = 0;
+    uint32_t plen;
     int err;
 
-    if (scan_ipv4_route(argv[1], &ip, &plen)) {
-        ovs_be32 gw = 0;
+    if (!scan_ipv4_route(argv[1], &ip, &plen)) {
+        if (!scan_ipv6_route(argv[1], &ip6, &plen)) {
+            unixctl_command_reply_error(conn, "Invalid parameters");
+            return;
+        }
+        ipv4_route_entry = false;
+    }
 
-        if (argc > 3) {
-            if (!ovs_scan(argv[3], "pkt_mark=%"SCNi32, &mark) &&
-                !ip_parse(argv[3], &gw)) {
-                unixctl_command_reply_error(conn, "Invalid pkt_mark or gateway");
-                return;
-            }
+    while (argc > 3 && lastargc != argc) {
+        lastargc = argc;
+
+        if (!strncmp(argv[argc - 1], "pkt_mark=", 9)) {
+            err = !ovs_scan(argv[--argc] + 9, "pkt_mark=%"SCNi32, &mark);
+        } else if (!strncmp(argv[argc - 1], "src_addr=", 9)) {
+            err = ipv4_route_entry ?
+                  !ip_parse(argv[--argc] + 9, &src) :
+                  !ipv6_parse(argv[--argc] + 9, &src6);
+        } else {
+            err = ipv4_route_entry ?
+                  !ip_parse(argv[--argc], &gw) :
+                  !ipv6_parse(argv[--argc], &gw6);
+        }
+
+        if (err) {
+            unixctl_command_reply_error(conn, "Invalid pkt_mark, src_addr or gateway");
+            return;
         }
+    }
+
+    if (ipv4_route_entry) {
         in6_addr_set_mapped_ipv4(&ip6, ip);
         if (gw) {
             in6_addr_set_mapped_ipv4(&gw6, gw);
         }
-        plen += 96;
-    } else if (scan_ipv6_route(argv[1], &ip6, &plen)) {
-        if (argc > 3) {
-            if (!ovs_scan(argv[3], "pkt_mark=%"SCNi32, &mark) &&
-                !ipv6_parse(argv[3], &gw6)) {
-                unixctl_command_reply_error(conn, "Invalid pkt_mark or IPv6 gateway");
-                return;
-            }
+        if (src) {
+            in6_addr_set_mapped_ipv4(&src6, src);
         }
-    } else {
-        unixctl_command_reply_error(conn, "Invalid parameters");
-        return;
-    }
-    if (argc > 4) {
-        if (!ovs_scan(argv[4], "pkt_mark=%"SCNi32, &mark)) {
-            unixctl_command_reply_error(conn, "Invalid pkt_mark");
-            return;
+        if (plen == 32) {
+            ipv4_local = true;
         }
+        plen += 96;
     }
 
-    err = ovs_router_insert__(mark, plen + 32, false, &ip6, plen, argv[2], &gw6);
+    err = ovs_router_insert__(mark, PRIO_USER(plen), ipv4_local, &ip6, plen,
+                              argv[2], &gw6, &src6);
     if (err) {
         unixctl_command_reply_error(conn, "Error while inserting route.");
     } else {
@@ -410,7 +436,7 @@ ovs_router_del(struct unixctl_conn *conn, int argc OVS_UNUSED,
         }
     }
 
-    if (rt_entry_delete(mark, plen + 32, &ip6, plen)) {
+    if (rt_entry_delete(mark, PRIO_USER(plen), &ip6, plen)) {
         unixctl_command_reply(conn, "OK");
         seq_change(tnl_conf_seq);
     } else {
@@ -428,7 +454,8 @@ 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 || rt->local) {
+        if (rt->priority == rt->plen ||
+            (rt->local && rt->priority == PRIO_LOCAL(rt->plen))) {
             ds_put_format(&ds, "Cached: ");
         } else {
             ds_put_format(&ds, "User: ");
@@ -505,7 +532,8 @@ ovs_router_flush(void)
     ovs_mutex_lock(&mutex);
     classifier_defer(&cls);
     CLS_FOR_EACH(rt, cr, &cls) {
-        if (rt->priority == rt->plen || rt->local) {
+        if (rt->priority == rt->plen ||
+            (rt->local && rt->priority == PRIO_LOCAL(rt->plen))) {
             rt_entry_delete__(&rt->cr);
         }
     }
@@ -530,8 +558,9 @@ ovs_router_init(void)
         classifier_init(&cls, NULL);
         unixctl_command_register("ovs/route/add",
                                  "ip_addr/prefix_len out_br_name [gw] "
-                                 "[pkt_mark=mark]",
-                                 2, 4, ovs_router_add, NULL);
+                                 "[pkt_mark=mark]"
+                                 "[src_addr=src]",
+                                 2, 5, ovs_router_add, NULL);
         unixctl_command_register("ovs/route/show", "", 0, 0,
                                  ovs_router_show, NULL);
         unixctl_command_register("ovs/route/del", "ip_addr/prefix_len "
-- 
2.14.1



More information about the dev mailing list