On 16 Dec 2024, at 8:59, Frode Nordahl wrote:

> On Fri, Dec 13, 2024 at 3:39 PM Eelco Chaudron <echau...@redhat.com> wrote:
>>
>>
>>
>> On 10 Dec 2024, at 23:18, Frode Nordahl wrote:
>>
>>> The route-table code is useful outside the scope of Open vSwitch.
>>> In a subsequent patch we will expose the route-table data
>>> structures to allow projects compiling against the private Open
>>> vSwitch library to consume this data.
>>>
>>> Add support for storing and parsing multipath routes.
>>>
>>> Note that the internal handling of routes in the ovs-route module
>>> does currently not support multipath routes, so when presented
>>> with one the latter occurrence will be stored.  This is not a
>>> regression as these routes were previously not considered at all.
>>
>> Why is this not a regression, in the past the first (RTA_GATEWAY) was 
>> stored, or is this still the case if present?
>
> This is not what I see. When a route is inserted in the system with
> multiple nexthops, from the list of attributes OVS knows about, the
> outer message only contains RTA_TABLE, RTA_DST and RTA_MULTIPATH.
>
> So before this series such routes were not considered relevant and
> subsequently not inserted into ovs-router at all.
>
> I guess an alternative could be to retain that behavior and only store
> the information in the route-table data structure for external
> consumption?

Thanks for the clarification, I guess I need(ed) to play a bit more with the 
different type of route messages. If this is the case, I think the way you 
handle it currently is fine.

>
>>> Storing the information in the route-table module data structure
>>> will allow external to OVS projects make use of this data.  A
>>> test program ran as part of the system tests that excercise the
>>> exported interfaces is added in this patch.
>>>
>>> Co-Authored-by: Felix Huettner <felix.huettner@stackit.cloud>
>>> Signed-off-by: Felix Huettner <felix.huettner@stackit.cloud>
>>> Signed-off-by: Frode Nordahl <fnord...@ubuntu.com>
>>> ---
>>>  Makefile.am                  |   3 +-
>>>  lib/route-table.c            |  51 +++++++++++++---
>>>  tests/automake.mk            |   1 +
>>>  tests/system-route.at        | 111 ++++++++++++++++++++++++++++++++++
>>>  tests/test-lib-route-table.c | 112 +++++++++++++++++++++++++++++++++++
>>>  5 files changed, 269 insertions(+), 9 deletions(-)
>>>  create mode 100644 tests/test-lib-route-table.c
>>>
>>> diff --git a/Makefile.am b/Makefile.am
>>> index dc5c34a6a..3c7cb51d9 100644
>>> --- a/Makefile.am
>>> +++ b/Makefile.am
>>> @@ -346,7 +346,8 @@ thread-safety-check:
>>>         grep -n -f build-aux/thread-safety-forbidden \
>>>           `git ls-files | grep '\.[ch]$$' \
>>>             | $(EGREP) -v '^datapath-windows|^lib/sflow|^third-party'` 
>>> /dev/null \
>>> -           | $(EGREP) -v ':[         ]*/?\*'; \
>>> +           | $(EGREP) -v ':[         ]*/?\*' \
>>> +           | $(EGREP) -v '^tests/test-lib-route-table.c'; \
>>
>> We should not introduce any thread safety issues. They should be fixed if 
>> they exist, especially in the test code. I assume this is due to using a 
>> single global structure for the first next hop, as commented on earlier.
>
> This check is actually triggered by the use of the system() call in
> the test program. The alternative would be to implement netlink code
> to insert routes in the test program, which we of course can do, but
> it felt a bit extravagant at the time of writing.

Can we explicitly mention this here so it’s clear why this file is excluded?

>>>       then \
>>>         echo "See above for list of calls to functions that are"; \
>>>         echo "forbidden due to thread safety issues"; \
>>> diff --git a/lib/route-table.c b/lib/route-table.c
>>> index 1fabb8c03..db2100403 100644
>>> --- a/lib/route-table.c
>>> +++ b/lib/route-table.c
>>> @@ -222,8 +222,8 @@ route_table_reset(void)
>>>   * error. */
>>>  static int
>>>  route_table_parse__(struct ofpbuf *buf, size_t ofs,
>>> -                    const struct nlmsghdr *nlmsg,
>>> -                    const struct rtmsg *rtm, void *change_)
>>> +                    const struct nlmsghdr *nlmsg, const struct rtmsg *rtm,
>>> +                    const struct rtnexthop *rtnh, void *change_)
>>>  {
>>>      struct route_table_msg *change = change_;
>>>      struct route_data_nexthop *rdnh = NULL;
>>> @@ -238,6 +238,7 @@ route_table_parse__(struct ofpbuf *buf, size_t ofs,
>>>          [RTA_TABLE] = { .type = NL_A_U32, .optional = true },
>>>          [RTA_PRIORITY] = { .type = NL_A_U32, .optional = true },
>>>          [RTA_VIA] = { .type = NL_A_UNSPEC, .optional = true },
>>> +        [RTA_MULTIPATH] = { .type = NL_A_NESTED, .optional = true },
>>>      };
>>>
>>>      static const struct nl_policy policy6[] = {
>>> @@ -249,6 +250,7 @@ route_table_parse__(struct ofpbuf *buf, size_t ofs,
>>>          [RTA_TABLE] = { .type = NL_A_U32, .optional = true },
>>>          [RTA_PRIORITY] = { .type = NL_A_U32, .optional = true },
>>>          [RTA_VIA] = { .type = NL_A_UNSPEC, .optional = true },
>>> +        [RTA_MULTIPATH] = { .type = NL_A_NESTED, .optional = true },
>>>      };
>>>
>>>      struct nlattr *attrs[ARRAY_SIZE(policy)];
>>> @@ -270,8 +272,8 @@ route_table_parse__(struct ofpbuf *buf, size_t ofs,
>>>
>>>          memset(change, 0, sizeof *change);
>>>          ovs_list_init(&change->rd.nexthops);
>>> -        memset(&rdnh_single, 0, sizeof *rdnh);
>>> -        rdnh = &rdnh_single;
>>> +        rdnh = rtnh ? xmalloc(sizeof *rdnh) : &rdnh_single;
>>> +        memset(rdnh, 0, sizeof *rdnh);
>>>          change->relevant = true;
>>>
>>>          if (rtm->rtm_scope == RT_SCOPE_NOWHERE) {
>>> @@ -292,8 +294,9 @@ route_table_parse__(struct ofpbuf *buf, size_t ofs,
>>>          change->rd.rtm_dst_len = rtm->rtm_dst_len + (ipv4 ? 96 : 0);
>>>          change->rd.rtm_protocol = rtm->rtm_protocol;
>>>          change->rd.local = rtm->rtm_type == RTN_LOCAL;
>>> -        if (attrs[RTA_OIF]) {
>>> -            rta_oif = nl_attr_get_u32(attrs[RTA_OIF]);
>>> +        if (attrs[RTA_OIF] || rtnh) {
>>> +            rta_oif = rtnh
>>> +                ? rtnh->rtnh_ifindex : nl_attr_get_u32(attrs[RTA_OIF]);
>>>
>>>              if (!if_indextoname(rta_oif, rdnh->ifname)) {
>>>                  int error = errno;
>>> @@ -374,7 +377,38 @@ route_table_parse__(struct ofpbuf *buf, size_t ofs,
>>>                  goto error_out;
>>>              }
>>>          }
>>> -        ovs_list_insert(&change->rd.nexthops, &rdnh->nexthop_node);
>>> +        if (!attrs[RTA_MULTIPATH]) {
>>> +            ovs_list_insert(&change->rd.nexthops, &rdnh->nexthop_node);
>>> +        } else {
>>> +            if (rtnh) {
>>> +                VLOG_DBG_RL(&rl, "Unexpected nested RTA_MULTIPATH 
>>> attribute.");
>>> +                goto error_out;
>>> +            }
>>> +            const struct nlattr *nla;
>>> +            size_t left;
>>
>> These definitions should happen before the error if above.
>
> Ack.
>
>>> +
>>> +            NL_NESTED_FOR_EACH (nla, left, attrs[RTA_MULTIPATH]) {
>>> +                struct route_table_msg mp_change;
>>> +                struct rtnexthop *mp_rtnh;
>>> +                struct ofpbuf mp_buf;
>>> +
>>> +                ofpbuf_use_data(&mp_buf, nla, nla->nla_len);
>>> +                mp_rtnh = ofpbuf_try_pull(&mp_buf, sizeof *mp_rtnh);
>>> +                if (!mp_rtnh) {
>>> +                    VLOG_DBG_RL(&rl, "Got short message while parsing "
>>> +                                "multipath attribute.");
>>> +                    goto error_out;
>>> +                }
>>> +
>>> +                if (!route_table_parse__(&mp_buf, 0, nlmsg, rtm, mp_rtnh,
>>> +                                         &mp_change)) {
>>> +                    goto error_out;
>>> +                }
>>> +                ovs_list_push_back_all(&change->rd.nexthops,
>>> +                                       &mp_change.rd.nexthops);
>>> +            }
>>> +        }
>>> +        /* Add any additional RTA attribute processing before 
>>> RTA_MULTIPATH. */
>>>      } else {
>>>          VLOG_DBG_RL(&rl, "received unparseable rtnetlink route message");
>>>          goto error_out;
>>> @@ -387,6 +421,7 @@ error_out:
>>>      if (rdnh && rdnh != &rdnh_single) {
>>>          free (rdnh);
>>>      }
>>> +    route_data_destroy(&change->rd);
>>
>> This should probably be part of an earlier patch.
>
> It only becomes relevant here, but it could of course be introduced at
> the same time as the introduction of the linked list.
>
>>>      return 0;
>>>  }
>>>
>>> @@ -400,7 +435,7 @@ route_table_parse(struct ofpbuf *buf, void *change_)
>>>      rtm = ofpbuf_at(buf, NLMSG_HDRLEN, sizeof *rtm);
>>>
>>>      return route_table_parse__(buf, NLMSG_HDRLEN + sizeof *rtm,
>>> -                               nlmsg, rtm, change_);
>>> +                               nlmsg, rtm, NULL, change_);
>>>  }
>>>
>>>  static bool
>>> diff --git a/tests/automake.mk b/tests/automake.mk
>>> index edfc2cb33..59f538761 100644
>>> --- a/tests/automake.mk
>>> +++ b/tests/automake.mk
>>> @@ -498,6 +498,7 @@ endif
>>>
>>>  if LINUX
>>>  tests_ovstest_SOURCES += \
>>> +     tests/test-lib-route-table.c \
>>>       tests/test-netlink-conntrack.c \
>>>       tests/test-netlink-policy.c \
>>>       tests/test-psample.c
>>> diff --git a/tests/system-route.at b/tests/system-route.at
>>> index 46db676f2..82b029e1e 100644
>>> --- a/tests/system-route.at
>>> +++ b/tests/system-route.at
>>> @@ -44,6 +44,36 @@ Cached: 192.168.10.13/32 dev br0 GW 192.168.9.1 SRC 
>>> 192.168.9.3])
>>>  OVS_TRAFFIC_VSWITCHD_STOP
>>>  AT_CLEANUP
>>>
>>> +AT_SETUP([ovs-route - add system route with multiple nexthop - ipv4])
>>> +AT_KEYWORDS([route])
>>> +OVS_TRAFFIC_VSWITCHD_START()
>>> +
>>> +dnl Create tap ports.
>>> +AT_CHECK([ip tuntap add name p1-route mode tap])
>>> +AT_CHECK([ip link set p1-route up])
>>> +on_exit 'ip link del p1-route'
>>> +AT_CHECK([ip tuntap add name p2-route mode tap])
>>> +AT_CHECK([ip link set p2-route up])
>>> +on_exit 'ip link del p2-route'
>>> +
>>> +AT_CHECK([ip addr add 192.168.42.10/24 dev p1-route], [0], [stdout])
>>> +AT_CHECK([ip addr add 192.168.51.10/24 dev p2-route], [0], [stdout])
>>> +AT_CHECK([ip route add 172.16.42.0/24 nexthop via 192.168.42.1 dev 
>>> p1-route nexthop via 192.168.51.1 dev p2-route], [0], [stdout])
>>> +
>>> +dnl NOTE(fnordahl): At the time of this writing, it is expected that only 
>>> the
>>> +dnl                 second route will be stored in ovs-router.
>>> +OVS_WAIT_UNTIL_EQUAL([ovs-appctl ovs/route/show | grep -E '172.16.42.0/24' 
>>> | sort], [dnl
>>> +Cached: 172.16.42.0/24 dev p2-route GW 192.168.51.1 SRC 192.168.51.10])
>>> +
>>> +dnl Confirm that both nexthops are available when using the route-table 
>>> library
>>> +dnl directly.
>>> +OVS_WAIT_UNTIL_EQUAL([ovstest test-lib-route-table-dump | grep 
>>> 172.16.42.0.*nexthop | sort], [dnl
>>> +    rta_dst: ::ffff:172.16.42.0 nexthop family: 0 addr: 
>>> ::ffff:192.168.42.1 ifname: p1-route
>>> +    rta_dst: ::ffff:172.16.42.0 nexthop family: 0 addr: 
>>> ::ffff:192.168.51.1 ifname: p2-route])
>>> +
>>> +OVS_TRAFFIC_VSWITCHD_STOP
>>> +AT_CLEANUP
>>> +
>>>  AT_SETUP([ovs-route - add system route with src - ipv6])
>>>  AT_KEYWORDS([route])
>>>  OVS_TRAFFIC_VSWITCHD_START()
>>> @@ -65,6 +95,36 @@ Cached: fc00:db8:beef::13/128 dev br0 GW 
>>> fc00:db8:cafe::1 SRC fc00:db8:cafe::2])
>>>  OVS_TRAFFIC_VSWITCHD_STOP
>>>  AT_CLEANUP
>>>
>>> +AT_SETUP([ovs-route - add system route with multiple nexthop - ipv6])
>>> +AT_KEYWORDS([route])
>>> +OVS_TRAFFIC_VSWITCHD_START()
>>> +
>>> +dnl Create tap ports.
>>> +AT_CHECK([ip tuntap add name p1-route mode tap])
>>> +AT_CHECK([ip link set p1-route up])
>>> +on_exit 'ip link del p1-route'
>>> +AT_CHECK([ip tuntap add name p2-route mode tap])
>>> +AT_CHECK([ip link set p2-route up])
>>> +on_exit 'ip link del p2-route'
>>> +
>>> +AT_CHECK([ip -6 addr add fc00:db8:dead::10/64 dev p1-route], [0], [stdout])
>>> +AT_CHECK([ip -6 addr add fc00:db8:beef::10/64 dev p2-route], [0], [stdout])
>>> +AT_CHECK([ip -6 route add fc00:db8:cafe::/64 nexthop via fc00:db8:dead::1 
>>> dev p1-route nexthop via fc00:db8:beef::1 dev p2-route], [0], [stdout])
>>> +
>>> +dnl NOTE(fnordahl): At the time of this writing, it is expected that only 
>>> the
>>
>> No, need to put your name here, just NOTE:...
>
> Ack.
>
>> Without these changes, are we also reporting the second one with RTA_GATEWAY 
>> option?
>
> No, as commented above the existing code does not consider multipath
> routes at all today.
>
>>> +dnl                 second route will be stored in ovs-router.
>>> +OVS_WAIT_UNTIL_EQUAL([ovs-appctl ovs/route/show | grep -E 
>>> 'fc00:db8:cafe::/64' | sort], [dnl
>>> +Cached: fc00:db8:cafe::/64 dev p2-route GW fc00:db8:beef::1 SRC 
>>> fc00:db8:beef::10])
>>> +
>>> +dnl Confirm that both nexthops are available when using the route-table 
>>> library
>>> +dnl directly.
>>> +OVS_WAIT_UNTIL_EQUAL([ovstest test-lib-route-table-dump | grep 
>>> fc00:db8:cafe::.*nexthop | sort], [dnl
>>> +    rta_dst: fc00:db8:cafe:: nexthop family: 0 addr: fc00:db8:beef::1 
>>> ifname: p2-route
>>> +    rta_dst: fc00:db8:cafe:: nexthop family: 0 addr: fc00:db8:dead::1 
>>> ifname: p1-route])
>>
>> This test does not check the route protocol and route tale ID introduced in 
>> earlier patches.
>> Should be tested with none zero values.
>
> Thanks for pointing that out, I'll extend the test cases to include
> check for the three new attributes added at the beginning of the
> series.
>
>>> +
>>> +OVS_TRAFFIC_VSWITCHD_STOP
>>> +AT_CLEANUP
>>> +
>>>  AT_SETUP([ovs-route - add system route - ipv4 via ipv6 nexthop])
>>>  AT_KEYWORDS([route])
>>>  OVS_TRAFFIC_VSWITCHD_START()
>>> @@ -83,6 +143,36 @@ Cached: 192.168.10.12/32 dev br0 GW 
>>> fe80::253:ff:fe00:51 SRC fe80::253:ff:fe00:4
>>>  OVS_TRAFFIC_VSWITCHD_STOP
>>>  AT_CLEANUP
>>>
>>> +AT_SETUP([ovs-route - add system route - ipv4 via multiple ipv6 nexthop])
>>> +AT_KEYWORDS([route])
>>> +OVS_TRAFFIC_VSWITCHD_START()
>>> +
>>> +dnl Create tap ports.
>>> +AT_CHECK([ip tuntap add name p1-route mode tap])
>>> +AT_CHECK([ip link set p1-route up])
>>> +on_exit 'ip link del p1-route'
>>> +AT_CHECK([ip tuntap add name p2-route mode tap])
>>> +AT_CHECK([ip link set p2-route up])
>>> +on_exit 'ip link del p2-route'
>>> +
>>> +AT_CHECK([ip -6 addr add fc00:db8:dead::10/64 dev p1-route], [0], [stdout])
>>> +AT_CHECK([ip -6 addr add fc00:db8:beef::10/64 dev p2-route], [0], [stdout])
>>> +AT_CHECK([ip route add 172.16.42.0/24 nexthop via inet6 fc00:db8:dead::1 
>>> dev p1-route nexthop via inet6 fc00:db8:beef::1 dev p2-route], [0], 
>>> [stdout])
>>> +
>>> +dnl NOTE(fnordahl): At the time of this writing, it is expected that only 
>>> the
>>> +dnl                 second route will be stored in ovs-router.
>>> +OVS_WAIT_UNTIL_EQUAL([ovs-appctl ovs/route/show | grep -E '172.16.42.0/24' 
>>> | sort], [dnl
>>> +Cached: 172.16.42.0/24 dev p2-route GW fc00:db8:beef::1 SRC 
>>> fc00:db8:beef::10])
>>> +
>>> +dnl Confirm that both nexthops are available when using the route-table 
>>> library
>>> +dnl directly.
>>> +OVS_WAIT_UNTIL_EQUAL([ovstest test-lib-route-table-dump | grep 
>>> 172.16.42.0.*nexthop | sort], [dnl
>>> +    rta_dst: ::ffff:172.16.42.0 nexthop family: 10 addr: fc00:db8:beef::1 
>>> ifname: p2-route
>>> +    rta_dst: ::ffff:172.16.42.0 nexthop family: 10 addr: fc00:db8:dead::1 
>>> ifname: p1-route])
>>> +
>>> +OVS_TRAFFIC_VSWITCHD_STOP
>>> +AT_CLEANUP
>>> +
>>>  dnl Checks that OVS doesn't use routes from non-standard tables.
>>>  AT_SETUP([ovs-route - route tables])
>>>  AT_KEYWORDS([route])
>>> @@ -148,3 +238,24 @@ OVS_WAIT_UNTIL([test $(ovs-appctl ovs/route/show | 
>>> grep -c 'p1-route') -eq 0 ])
>>>
>>>  OVS_TRAFFIC_VSWITCHD_STOP
>>>  AT_CLEANUP
>>> +
>>> +AT_SETUP([route-table - exported functions work for netlink-notifier])
>>> +AT_KEYWORDS([route])
>>> +
>>> +dnl Create tap ports.
>>> +AT_CHECK([ip tuntap add name p1-route mode tap])
>>> +AT_CHECK([ip link set p1-route up])
>>> +on_exit 'ip link del p1-route'
>>> +AT_CHECK([ip tuntap add name p2-route mode tap])
>>> +AT_CHECK([ip link set p2-route up])
>>> +on_exit 'ip link del p2-route'
>>> +
>>> +AT_CHECK([ip -6 addr add fc00:db8:dead::10/64 dev p1-route], [0], [stdout])
>>> +AT_CHECK([ip -6 addr add fc00:db8:beef::10/64 dev p2-route], [0], [stdout])
>>> +
>>> +AT_CHECK([ovstest test-lib-route-table-monitor 'ip route add 
>>> 172.16.42.0/24 nexthop via inet6 fc00:db8:dead::1 dev p1-route nexthop via 
>>> inet6 fc00:db8:beef::1 dev p2-route'| grep 172.16.42.0.*nexthop | sort], 
>>> [0], [dnl
>>> +    rta_dst: ::ffff:172.16.42.0 nexthop family: 10 addr: fc00:db8:beef::1 
>>> ifname: p2-route
>>> +    rta_dst: ::ffff:172.16.42.0 nexthop family: 10 addr: fc00:db8:dead::1 
>>> ifname: p1-route
>>> +])
>>> +
>>> +AT_CLEANUP
>>> diff --git a/tests/test-lib-route-table.c b/tests/test-lib-route-table.c
>>> new file mode 100644
>>> index 000000000..82d1dbc69
>>> --- /dev/null
>>> +++ b/tests/test-lib-route-table.c
>>> @@ -0,0 +1,112 @@
>>> +/*
>>> + * Copyright (c) 2009, 2014 Nicira, Inc.
>>> + *
>>> + * Licensed under the Apache License, Version 2.0 (the "License");
>>> + * you may not use this file except in compliance with the License.
>>> + * You may obtain a copy of the License at:
>>> + *
>>> + *     http://www.apache.org/licenses/LICENSE-2.0
>>> + *
>>> + * Unless required by applicable law or agreed to in writing, software
>>> + * distributed under the License is distributed on an "AS IS" BASIS,
>>> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
>>> + * See the License for the specific language governing permissions and
>>> + * limitations under the License.
>>> + */
>>> +
>>> +#include <config.h>
>>> +
>>> +#undef NDEBUG
>>> +
>>> +#include <linux/rtnetlink.h>
>>> +#include <stdio.h>
>>> +#include <stdlib.h>
>>> +
>>> +#include "netlink-notifier.h"
>>> +#include "ovstest.h"
>>> +#include "packets.h"
>>> +#include "route-table.h"
>>> +
>>> +static void
>>> +test_lib_route_table_handle_msg(const struct route_table_msg *change,
>>> +                                void *data OVS_UNUSED)
>>> +{
>>> +    const struct route_data *rd = &change->rd;
>>> +    const struct route_data_nexthop *rdnh;
>>> +    struct ds rta_dst = DS_EMPTY_INITIALIZER;
>>> +    struct ds rta_prefsrc = DS_EMPTY_INITIALIZER;
>>> +    struct ds nexthop_addr = DS_EMPTY_INITIALIZER;
>>
>> Revere Christmas tree.
>
> Ack, the test code is arguably very hastily written and ugly, I'll clean it 
> up.
>
> --
> Frode Nordahl
>
>>> +
>>> +    ipv6_format_addr(&change->rd.rta_dst, &rta_dst);
>>> +    ipv6_format_addr(&change->rd.rta_prefsrc, &rta_prefsrc);
>>> +    printf("relevant: %d nlmsg_type: %d rtm_dst_len: %u rtm_protocol: %u "
>>> +           "local: %d rta_dst: %s rta_prefsrc: %s mark: %"PRIu32" "
>>> +           "rta_table_id: %"PRIu32" rta_priority: %"PRIu32"\n",
>>> +           change->relevant, change->nlmsg_type,
>>> +           rd->rtm_dst_len, rd->rtm_protocol, rd->local,
>>> +           ds_cstr(&rta_dst), ds_cstr(&rta_prefsrc),
>>> +           rd->mark, rd->rta_table_id, rd->rta_priority);
>>> +
>>> +    LIST_FOR_EACH (rdnh, nexthop_node, &rd->nexthops) {
>>> +        ds_clear(&nexthop_addr);
>>> +        ipv6_format_addr(&rdnh->addr, &nexthop_addr);
>>> +        printf("    rta_dst: %s nexthop family: %d addr: %s ifname: %s\n",
>>> +               ds_cstr(&rta_dst), rdnh->family, ds_cstr(&nexthop_addr),
>>> +               rdnh->ifname);
>>> +    }
>>> +    ds_destroy(&rta_dst);
>>> +    ds_destroy(&rta_prefsrc);
>>> +    ds_destroy(&nexthop_addr);
>>> +}
>>> +
>>> +static void
>>> +test_lib_route_table_dump(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
>>> +{
>>> +    route_table_dump_one_table(RT_TABLE_MAIN,
>>> +                               test_lib_route_table_handle_msg,
>>> +                               NULL);
>>> +}
>>> +
>>> +static void
>>> +test_lib_route_table_change(struct route_table_msg *change,
>>> +                            void *aux OVS_UNUSED)
>>> +{
>>> +    test_lib_route_table_handle_msg(change, NULL);
>>> +    route_data_destroy(&change->rd);
>>> +}
>>> +
>>> +static struct nln *nln = NULL;
>>> +static struct nln_notifier *route_notifier = NULL;
>>> +static struct nln_notifier *route6_notifier = NULL;
>>> +static struct route_table_msg rtmsg;
>>> +
>>> +static void
>>> +test_lib_route_table_monitor(int argc, char *argv[])
>>> +{
>>> +    if (argc != 2) {
>>> +        printf("usage: ovstest %s 'ip route add ...'\n", argv[0]);
>>> +        exit(EXIT_FAILURE);
>>> +    }
>>> +    const char *cmd = argv[1];
>>> +
>>> +    nln = nln_create(NETLINK_ROUTE, route_table_parse, &rtmsg);
>>> +
>>> +    route_notifier =
>>> +        nln_notifier_create(nln, RTNLGRP_IPV4_ROUTE,
>>> +                            (nln_notify_func *) 
>>> test_lib_route_table_change,
>>> +                            NULL);
>>> +    route6_notifier =
>>> +        nln_notifier_create(nln, RTNLGRP_IPV6_ROUTE,
>>> +                            (nln_notify_func *) 
>>> test_lib_route_table_change,
>>> +                            NULL);
>>> +    nln_run(nln);
>>> +    nln_wait(nln);
>>> +    int rc = system(cmd);
>>> +    if (rc) {
>>> +        exit(rc);
>>> +    }
>>> +    nln_run(nln);
>>> +}
>>> +
>>> +OVSTEST_REGISTER("test-lib-route-table-dump", test_lib_route_table_dump);
>>> +OVSTEST_REGISTER("test-lib-route-table-monitor", 
>>> test_lib_route_table_monitor);
>>> --
>>> 2.45.2
>>

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

Reply via email to