In preparation for adding support for parsing attributes such as
RTA_VIA and RTA_MULTIPATH, we need dynamic storage for route
nexthops.

For the common case of one nexthop we store nexthop information in
a static variable to avoid unnecessary memory allocations.

This patch makes this change in isolation so that it is easier to
review subsequent patches.

Signed-off-by: Frode Nordahl <fnord...@ubuntu.com>
---
 lib/route-table.c | 63 ++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 51 insertions(+), 12 deletions(-)

diff --git a/lib/route-table.c b/lib/route-table.c
index 33e0df2b8..fd26ac688 100644
--- a/lib/route-table.c
+++ b/lib/route-table.c
@@ -32,6 +32,7 @@
 #include "netlink.h"
 #include "netlink-notifier.h"
 #include "netlink-socket.h"
+#include "openvswitch/list.h"
 #include "openvswitch/ofpbuf.h"
 #include "ovs-router.h"
 #include "packets.h"
@@ -47,7 +48,16 @@ VLOG_DEFINE_THIS_MODULE(route_table);
 
 COVERAGE_DEFINE(route_table_dump);
 
+struct route_data_nexthop {
+    struct ovs_list nexthop_node;
+
+    struct in6_addr addr;
+    char ifname[IFNAMSIZ]; /* Interface name. */
+};
+
 struct route_data {
+    struct ovs_list nexthops;
+
     /* Copied from struct rtmsg. */
     unsigned char rtm_dst_len;
     unsigned char rtm_protocol;
@@ -56,8 +66,6 @@ struct route_data {
     /* Extracted from Netlink attributes. */
     struct in6_addr rta_dst; /* 0 if missing. */
     struct in6_addr rta_prefsrc; /* 0 if missing. */
-    struct in6_addr rta_gw;
-    char ifname[IFNAMSIZ]; /* Interface name. */
     uint32_t mark;
     uint32_t rta_table_id; /* 0 if missing. */
     uint32_t rta_priority; /* 0 if missing. */
@@ -80,6 +88,7 @@ static uint64_t rt_change_seq;
 
 static struct nln *nln = NULL;
 static struct route_table_msg rtmsg;
+static struct route_data_nexthop rdnh_single;
 static struct nln_notifier *route_notifier = NULL;
 static struct nln_notifier *route6_notifier = NULL;
 static struct nln_notifier *name_notifier = NULL;
@@ -89,12 +98,24 @@ static bool route_table_valid = false;
 static void route_table_reset(void);
 static void route_table_handle_msg(const struct route_table_msg *);
 static int route_table_parse(struct ofpbuf *, void *change);
-static void route_table_change(const struct route_table_msg *, void *);
+static void route_table_change(struct route_table_msg *, void *);
 static void route_map_clear(void);
 
 static void name_table_init(void);
 static void name_table_change(const struct rtnetlink_change *, void *);
 
+static void
+route_data_destroy(struct route_data *rd)
+{
+    struct route_data_nexthop *rdnh;
+
+    LIST_FOR_EACH_POP (rdnh, nexthop_node, &rd->nexthops) {
+        if (rdnh && rdnh != &rdnh_single) {
+            free(rdnh);
+        }
+    }
+}
+
 uint64_t
 route_table_get_change_seq(void)
 {
@@ -190,6 +211,7 @@ route_table_dump_one_table(unsigned char id)
                 filtered = false;
             }
             route_table_handle_msg(&msg);
+            route_data_destroy(&msg.rd);
         }
     }
     ofpbuf_uninit(&buf);
@@ -230,6 +252,7 @@ route_table_parse__(struct ofpbuf *buf, size_t ofs,
                     const struct rtmsg *rtm, void *change_)
 {
     struct route_table_msg *change = change_;
+    struct route_data_nexthop *rdnh = NULL;
     bool parsed, ipv4 = false;
 
     static const struct nl_policy policy[] = {
@@ -270,6 +293,9 @@ route_table_parse__(struct ofpbuf *buf, size_t ofs,
         int rta_oif;      /* Output interface index. */
 
         memset(change, 0, sizeof *change);
+        ovs_list_init(&change->rd.nexthops);
+        memset(&rdnh_single, 0, sizeof *rdnh);
+        rdnh = &rdnh_single;
         change->relevant = true;
 
         if (rtm->rtm_scope == RT_SCOPE_NOWHERE) {
@@ -293,7 +319,7 @@ route_table_parse__(struct ofpbuf *buf, size_t ofs,
         if (attrs[RTA_OIF]) {
             rta_oif = nl_attr_get_u32(attrs[RTA_OIF]);
 
-            if (!if_indextoname(rta_oif, change->rd.ifname)) {
+            if (!if_indextoname(rta_oif, rdnh->ifname)) {
                 int error = errno;
 
                 VLOG_DBG_RL(&rl, "Could not find interface name[%u]: %s",
@@ -301,7 +327,7 @@ route_table_parse__(struct ofpbuf *buf, size_t ofs,
                 if (error == ENXIO) {
                     change->relevant = false;
                 } else {
-                    return 0;
+                    goto error_out;
                 }
             }
         }
@@ -331,9 +357,9 @@ route_table_parse__(struct ofpbuf *buf, size_t ofs,
             if (ipv4) {
                 ovs_be32 gw;
                 gw = nl_attr_get_be32(attrs[RTA_GATEWAY]);
-                in6_addr_set_mapped_ipv4(&change->rd.rta_gw, gw);
+                in6_addr_set_mapped_ipv4(&rdnh->addr, gw);
             } else {
-                change->rd.rta_gw = nl_attr_get_in6_addr(attrs[RTA_GATEWAY]);
+                rdnh->addr = nl_attr_get_in6_addr(attrs[RTA_GATEWAY]);
             }
         }
         if (attrs[RTA_MARK]) {
@@ -342,13 +368,20 @@ route_table_parse__(struct ofpbuf *buf, size_t ofs,
         if (attrs[RTA_PRIORITY]) {
             change->rd.rta_priority = nl_attr_get_u32(attrs[RTA_PRIORITY]);
         }
+        ovs_list_insert(&change->rd.nexthops, &rdnh->nexthop_node);
     } else {
         VLOG_DBG_RL(&rl, "received unparseable rtnetlink route message");
-        return 0;
+        goto error_out;
     }
 
     /* Success. */
     return ipv4 ? RTNLGRP_IPV4_ROUTE : RTNLGRP_IPV6_ROUTE;
+
+error_out:
+    if (rdnh && rdnh != &rdnh_single) {
+        free (rdnh);
+    }
+    return 0;
 }
 
 static int
@@ -374,7 +407,7 @@ route_table_standard_table(uint32_t table_id)
 }
 
 static void
-route_table_change(const struct route_table_msg *change OVS_UNUSED,
+route_table_change(struct route_table_msg *change,
                    void *aux OVS_UNUSED)
 {
     if (!change
@@ -382,6 +415,9 @@ route_table_change(const struct route_table_msg *change 
OVS_UNUSED,
             && route_table_standard_table(change->rd.rta_table_id))) {
         route_table_valid = false;
     }
+    if (change && !ovs_list_is_empty(&change->rd.nexthops)) {
+        route_data_destroy(&change->rd);
+    }
 }
 
 static void
@@ -389,10 +425,13 @@ route_table_handle_msg(const struct route_table_msg 
*change)
 {
     if (change->relevant && change->nlmsg_type == RTM_NEWROUTE) {
         const struct route_data *rd = &change->rd;
+        const struct route_data_nexthop *rdnh;
 
-        ovs_router_insert(rd->mark, &rd->rta_dst, rd->rtm_dst_len,
-                          rd->local, rd->ifname, &rd->rta_gw,
-                          &rd->rta_prefsrc);
+        LIST_FOR_EACH (rdnh, nexthop_node, &rd->nexthops) {
+            ovs_router_insert(rd->mark, &rd->rta_dst, rd->rtm_dst_len,
+                              rd->local, rdnh->ifname, &rdnh->addr,
+                              &rd->rta_prefsrc);
+        }
     }
 }
 
-- 
2.45.2

_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to