ovsdb-server: Fix a reference count leak bug
[cascardo/ovs.git] / lib / ovs-router.c
index 3962aef..d416bdb 100644 (file)
@@ -86,10 +86,9 @@ ovs_router_lookup(const struct in6_addr *ip6_dst, char output_bridge[],
 bool
 ovs_router_lookup4(ovs_be32 ip_dst, char output_bridge[], ovs_be32 *gw)
 {
-    struct in6_addr ip6_dst;
+    struct in6_addr ip6_dst = in6_addr_mapped_ipv4(ip_dst);
     struct in6_addr gw6;
 
-    in6_addr_set_mapped_ipv4(&ip6_dst, ip_dst);
     if (ovs_router_lookup(&ip6_dst, output_bridge, &gw6)) {
         *gw = in6_addr_get_mapped_ipv4(&gw6);
         return true;
@@ -200,82 +199,52 @@ rt_entry_delete(uint8_t priority, const struct in6_addr *ip6_dst, uint8_t plen)
 static bool
 scan_ipv6_route(const char *s, struct in6_addr *addr, unsigned int *plen)
 {
-    int len, n;
-    int slen = strlen(s);
-    char ipv6_s[IPV6_SCAN_LEN + 1];
-
-    if (ovs_scan(s, IPV6_SCAN_FMT"%n", ipv6_s, &len)
-        && inet_pton(AF_INET6, ipv6_s, addr) == 1) {
-        if (len == slen) {
-            *plen = 128;
-            return true;
-        }
-        if (ovs_scan(s + len, "/%u%n", plen, &n)
-            && len + n == slen && *plen <= 128) {
-            return true;
-        }
+    char *error = ipv6_parse_cidr(s, addr, plen);
+    if (error) {
+        free(error);
+        return false;
     }
-    return false;
+    return true;
 }
 
 static bool
 scan_ipv4_route(const char *s, ovs_be32 *addr, unsigned int *plen)
 {
-    int len, max_plen, n;
-    int slen = strlen(s);
-    uint8_t *ip = (uint8_t *)addr;
-
-    *addr = htonl(0);
-    if (!ovs_scan(s, "%"SCNu8"%n", &ip[0], &n)) {
+    char *error = ip_parse_cidr(s, addr, plen);
+    if (error) {
+        free(error);
         return false;
     }
-    len = n;
-    max_plen = 8;
-    for (int i = 1; i < 4; i++) {
-        if (ovs_scan(s + len, ".%"SCNu8"%n", &ip[i], &n)) {
-            len += n;
-            max_plen += 8;
-        } else {
-            break;
-        }
-    }
-    if (len == slen && max_plen == 32) {
-        *plen = 32;
-        return true;
-    }
-    if (ovs_scan(s + len, "/%u%n", plen, &n)
-        && len + n == slen && *plen <= max_plen) {
-        return true;
-    }
-    return false;
+    return true;
 }
 
 static void
 ovs_router_add(struct unixctl_conn *conn, int argc,
               const char *argv[], void *aux OVS_UNUSED)
 {
-    ovs_be32 ip, gw;
+    ovs_be32 ip;
     unsigned int plen;
     struct in6_addr ip6;
     struct in6_addr gw6;
 
     if (scan_ipv4_route(argv[1], &ip, &plen)) {
-        if (argc > 3) {
-            inet_pton(AF_INET, argv[3], (struct in_addr *)&gw);
-        } else {
-            gw = 0;
+        ovs_be32 gw = 0;
+        if (argc > 3 && !ip_parse(argv[3], &gw)) {
+            unixctl_command_reply_error(conn, "Invalid gateway");
+            return;
         }
         in6_addr_set_mapped_ipv4(&ip6, ip);
         in6_addr_set_mapped_ipv4(&gw6, gw);
         plen += 96;
     } else if (scan_ipv6_route(argv[1], &ip6, &plen)) {
-        if (argc > 3) {
-            inet_pton(AF_INET6, argv[3], &gw6);
-        } else {
-            gw6 = in6addr_any;
+        gw6 = in6addr_any;
+        if (argc > 3 && !ipv6_parse(argv[3], &gw6)) {
+            unixctl_command_reply_error(conn, "Invalid IPv6 gateway");
+            return;
         }
     } else {
-        unixctl_command_reply(conn, "Invalid parameters");
+        unixctl_command_reply_error(conn, "Invalid parameters");
+        return;
     }
     ovs_router_insert__(plen + 32, &ip6, plen, argv[2], &gw6);
     unixctl_command_reply(conn, "OK");
@@ -293,13 +262,14 @@ ovs_router_del(struct unixctl_conn *conn, int argc OVS_UNUSED,
         in6_addr_set_mapped_ipv4(&ip6, ip);
         plen += 96;
     } else if (!scan_ipv6_route(argv[1], &ip6, &plen)) {
-        unixctl_command_reply(conn, "Invalid parameters");
+        unixctl_command_reply_error(conn, "Invalid parameters");
+        return;
     }
     if (rt_entry_delete(plen + 32, &ip6, plen)) {
         unixctl_command_reply(conn, "OK");
         seq_change(tnl_conf_seq);
     } else {
-        unixctl_command_reply(conn, "Not found");
+        unixctl_command_reply_error(conn, "Not found");
     }
 }
 
@@ -347,7 +317,8 @@ ovs_router_lookup_cmd(struct unixctl_conn *conn, int argc OVS_UNUSED,
     if (scan_ipv4_route(argv[1], &ip, &plen) && plen == 32) {
         in6_addr_set_mapped_ipv4(&ip6, ip);
     } else if (!(scan_ipv6_route(argv[1], &ip6, &plen) && plen == 128)) {
-        unixctl_command_reply(conn, "Invalid parameters");
+        unixctl_command_reply_error(conn, "Invalid parameters");
+        return;
     }
 
     if (ovs_router_lookup(&ip6, iface, &gw)) {
@@ -358,7 +329,7 @@ ovs_router_lookup_cmd(struct unixctl_conn *conn, int argc OVS_UNUSED,
         unixctl_command_reply(conn, ds_cstr(&ds));
         ds_destroy(&ds);
     } else {
-        unixctl_command_reply(conn, "Not found");
+        unixctl_command_reply_error(conn, "Not found");
     }
 }