On 8/20/25 4:34 PM, Dima Chumak via dev wrote:
> For route lookup based on the destination address a single routing table
> is sufficient. For a more advanced routing when a lookup needs to take
> into consideration other parameters, such as a source address, a
> multi-table lookup is needed.
>
> This change introduces infrastructure for using multiple routing
> tables that can be added dynamically, as a pre-step towards importing
> non-default routing tables from kernel.
>
> Signed-off-by: Dima Chumak <[email protected]>
> ---
> lib/netdev-dummy.c | 14 ++-
> lib/ovs-router.c | 159 +++++++++++++++++++++++++++-------
> lib/ovs-router.h | 13 ++-
> lib/route-table.c | 6 +-
> tests/nsh.at | 9 +-
> tests/ofproto-dpif.at | 9 +-
> tests/ovs-router.at | 36 +++++---
> tests/packet-type-aware.at | 15 ++--
> tests/tunnel-push-pop-ipv6.at | 30 ++++---
> tests/tunnel-push-pop.at | 42 ++++++---
> tests/tunnel.at | 6 +-
> 11 files changed, 249 insertions(+), 90 deletions(-)
>
> diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c
> index b72820fcc506..bad86d3c4c76 100644
> --- a/lib/netdev-dummy.c
> +++ b/lib/netdev-dummy.c
> @@ -2221,10 +2221,13 @@ netdev_dummy_ip4addr(struct unixctl_conn *conn, int
> argc OVS_UNUSED,
> mask.s_addr = be32_prefix_mask(plen);
> netdev_dummy_add_in4(netdev, ip, mask);
>
> - /* Insert local route entry for the new address. */
> in6_addr_set_mapped_ipv4(&ip6, ip.s_addr);
> - ovs_router_force_insert(0, &ip6, plen + 96, true, argv[1],
> - &in6addr_any, &ip6);
> + /* Insert local route entry for the new address. */
> + ovs_router_force_insert(CLS_MAIN, 0, &ip6, 32 + 96, true,
> + argv[1], &in6addr_any, &ip6);
> + /* Insert network route entry for the new address. */
> + ovs_router_force_insert(CLS_MAIN, 0, &ip6, plen + 96, false,
> + argv[1], &in6addr_any, &ip6);
>
> unixctl_command_reply(conn, "OK");
> } else {
> @@ -2257,7 +2260,10 @@ netdev_dummy_ip6addr(struct unixctl_conn *conn, int
> argc OVS_UNUSED,
> netdev_dummy_add_in6(netdev, &ip6, &mask);
>
> /* Insert local route entry for the new address. */
> - ovs_router_force_insert(0, &ip6, plen, true, argv[1],
> + ovs_router_force_insert(CLS_MAIN, 0, &ip6, 128, true, argv[1],
> + &in6addr_any, &ip6);
> + /* Insert network route entry for the new address. */
> + ovs_router_force_insert(CLS_MAIN, 0, &ip6, plen, false, argv[1],
> &in6addr_any, &ip6);
>
> unixctl_command_reply(conn, "OK");
> diff --git a/lib/ovs-router.c b/lib/ovs-router.c
> index 2827a6e43574..0fcaf1dc7443 100644
> --- a/lib/ovs-router.c
> +++ b/lib/ovs-router.c
> @@ -33,6 +33,7 @@
> #include "classifier.h"
> #include "command-line.h"
> #include "compiler.h"
> +#include "cmap.h"
> #include "dpif.h"
> #include "fatal-signal.h"
> #include "openvswitch/dynamic-string.h"
> @@ -50,10 +51,16 @@
>
> VLOG_DEFINE_THIS_MODULE(ovs_router);
>
> +struct clsmap_node {
> + struct cmap_node cmap_node;
> + struct classifier cls;
> + uint32_t table;
Might be better to put the table before the classifier, so it is in the
same cache line with the node. The classfier structure is large, it
might be an unnecessary cache miss to check the table during the lookup.
> +};
> +
> static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
>
> static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
> -static struct classifier cls;
> +static struct cmap clsmap OVS_GUARDED_BY(mutex) = CMAP_INITIALIZER;
Not sure if GUARDED is a good annotation for a cmap as it is supposed
to be accessed by readers without holding a mutex. Sometimes clang
doesn't complain, but it probably should.
>
> /* By default, use the system routing table. For system-independent testing,
> * the unit tests disable using the system routing table. */
> @@ -71,6 +78,52 @@ struct ovs_router_entry {
> uint32_t mark;
> };
>
> +static void
> +rt_entry_delete__(const struct cls_rule *cr, struct classifier *cls);
Unlike the implementation, prototype name should not start from a new line.
Also, no need to name the arguments when they are obviously typed.
> +
> +static struct classifier *
> +cls_find(uint32_t table)
> +{
> + struct clsmap_node *node;
> +
> + CMAP_FOR_EACH_WITH_HASH (node, cmap_node, hash_int(table, 0), &clsmap) {
> + if (node->table == table) {
> + return &node->cls;
> + }
> + }
> +
> + return NULL;
> +}
> +
> +static struct classifier *
> +cls_create(uint32_t table)
> +{
> + struct clsmap_node *node;
> +
> + node = xmalloc(sizeof *node);
> + classifier_init(&node->cls, NULL);
> + node->table = table;
> + ovs_mutex_lock(&mutex);
> + cmap_insert(&clsmap, &node->cmap_node, hash_int(table, 0));
> + ovs_mutex_unlock(&mutex);
> +
> + return &node->cls;
> +}
> +
> +static void
> +cls_flush(struct classifier *cls, bool flush_all)
A thread-safety annotation would be good here:
OVS_REQUIRES(mutex)
> +{
> + struct ovs_router_entry *rt;
> +
> + classifier_defer(cls);
> + CLS_FOR_EACH (rt, cr, cls) {
> + if (flush_all || rt->priority == rt->plen || rt->local) {
> + rt_entry_delete__(&rt->cr, cls);
> + }
> + }
> + classifier_publish(cls);
> +}
> +
> static struct ovs_router_entry *
> ovs_router_entry_cast(const struct cls_rule *cr)
> {
> @@ -110,15 +163,20 @@ ovs_router_lookup(uint32_t mark, const struct in6_addr
> *ip6_dst,
> char output_netdev[],
> struct in6_addr *src, struct in6_addr *gw)
> {
> - const struct cls_rule *cr;
> struct flow flow = {.ipv6_dst = *ip6_dst, .pkt_mark = mark};
> + struct classifier *cls_main = cls_find(CLS_MAIN);
> + const struct cls_rule *cr;
> +
> + if (!cls_main) {
> + return false;
> + }
>
> 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,
> - NULL);
> + cr_src = classifier_lookup(cls_main, OVS_VERSION_MAX, &flow_src,
> + NULL, NULL);
> if (cr_src) {
> struct ovs_router_entry *p_src = ovs_router_entry_cast(cr_src);
> if (!p_src->local) {
> @@ -129,7 +187,7 @@ ovs_router_lookup(uint32_t mark, const struct in6_addr
> *ip6_dst,
> }
> }
>
> - cr = classifier_lookup(&cls, OVS_VERSION_MAX, &flow, NULL, NULL);
> + cr = classifier_lookup(cls_main, OVS_VERSION_MAX, &flow, NULL, NULL);
> if (cr) {
> struct ovs_router_entry *p = ovs_router_entry_cast(cr);
>
> @@ -257,8 +315,8 @@ out:
> }
>
> static int
> -ovs_router_insert__(uint32_t mark, uint8_t priority, bool local,
> - const struct in6_addr *ip6_dst,
> +ovs_router_insert__(uint32_t table, uint32_t mark, uint8_t priority,
> + bool local, const struct in6_addr *ip6_dst,
> uint8_t plen, const char output_netdev[],
> const struct in6_addr *gw,
> const struct in6_addr *ip6_src)
> @@ -268,6 +326,7 @@ ovs_router_insert__(uint32_t mark, uint8_t priority, bool
> local,
> struct in6_addr *prefsrc);
> const struct cls_rule *cr;
> struct ovs_router_entry *p;
> + struct classifier *cls;
> struct match match;
> int err;
>
> @@ -307,8 +366,12 @@ ovs_router_insert__(uint32_t mark, uint8_t priority,
> bool local,
> /* Longest prefix matches first. */
> cls_rule_init(&p->cr, &match, priority);
>
> + cls = cls_find(table);
> + if (!cls) {
> + cls = cls_create(table);
> + }
The whole find+create sequence should happen under the mutex, otherwise
we can end up creating the same table multiple times from different
threads. May just extend the critical section from below, remove the
mutex from cls_create() and add an annotation instead.
> ovs_mutex_lock(&mutex);
> - cr = classifier_replace(&cls, &p->cr, OVS_VERSION_MIN, NULL, 0);
> + cr = classifier_replace(cls, &p->cr, OVS_VERSION_MIN, NULL, 0);
> ovs_mutex_unlock(&mutex);
>
> if (cr) {
> @@ -321,13 +384,13 @@ ovs_router_insert__(uint32_t mark, uint8_t priority,
> bool local,
> }
>
> void
> -ovs_router_insert(uint32_t mark, const struct in6_addr *ip_dst, uint8_t plen,
> - bool local, const char output_netdev[],
> +ovs_router_insert(uint32_t table, uint32_t mark, const struct in6_addr
> *ip_dst,
> + uint8_t plen, bool local, const char output_netdev[],
> const struct in6_addr *gw, const struct in6_addr *prefsrc)
> {
> if (use_system_routing_table) {
> uint8_t priority = local ? plen + 64 : plen;
> - ovs_router_insert__(mark, priority, local, ip_dst, plen,
> + ovs_router_insert__(table, mark, priority, local, ip_dst, plen,
> output_netdev, gw, prefsrc);
> }
> }
> @@ -335,24 +398,25 @@ ovs_router_insert(uint32_t mark, const struct in6_addr
> *ip_dst, uint8_t plen,
> /* The same as 'ovs_router_insert', but it adds the route even if updates
> * from the system routing table are disabled. Used for unit tests. */
> void
> -ovs_router_force_insert(uint32_t mark, const struct in6_addr *ip_dst,
> +ovs_router_force_insert(uint32_t table, uint32_t mark,
> + const struct in6_addr *ip_dst,
> uint8_t plen, bool local, const char output_netdev[],
> const struct in6_addr *gw,
> const struct in6_addr *prefsrc)
> {
> uint8_t priority = local ? plen + 64 : plen;
>
> - ovs_router_insert__(mark, priority, local, ip_dst, plen,
> + ovs_router_insert__(table, mark, priority, local, ip_dst, plen,
> output_netdev, gw, prefsrc);
> }
>
> static void
> -rt_entry_delete__(const struct cls_rule *cr)
> +rt_entry_delete__(const struct cls_rule *cr, struct classifier *cls)
> {
> struct ovs_router_entry *p = ovs_router_entry_cast(cr);
>
> tnl_port_map_delete_ipdev(p->output_netdev);
> - classifier_remove_assert(&cls, cr);
> + classifier_remove_assert(cls, cr);
> ovsrcu_postpone(rt_entry_free, ovs_router_entry_cast(cr));
> }
>
> @@ -360,20 +424,25 @@ static bool
> rt_entry_delete(uint32_t mark, uint8_t priority,
> const struct in6_addr *ip6_dst, uint8_t plen)
> {
> + struct classifier *cls_main = cls_find(CLS_MAIN);
> const struct cls_rule *cr;
> struct cls_rule rule;
> struct match match;
> bool res = false;
>
> + if (!cls_main) {
> + return false;
> + }
> +
> rt_init_match(&match, mark, ip6_dst, plen);
>
> cls_rule_init(&rule, &match, priority);
>
> /* Find the exact rule. */
> - cr = classifier_find_rule_exactly(&cls, &rule, OVS_VERSION_MAX);
> + cr = classifier_find_rule_exactly(cls_main, &rule, OVS_VERSION_MAX);
> if (cr) {
> ovs_mutex_lock(&mutex);
> - rt_entry_delete__(cr);
> + rt_entry_delete__(cr, cls_main);
> ovs_mutex_unlock(&mutex);
>
> res = true;
> @@ -469,8 +538,8 @@ ovs_router_add(struct unixctl_conn *conn, int argc,
> in6_addr_set_mapped_ipv4(&src6, src);
> }
>
> - err = ovs_router_insert__(mark, plen + 32, false, &ip6, plen, argv[2],
> - &gw6, &src6);
> + err = ovs_router_insert__(CLS_MAIN, mark, plen + 32, false, &ip6, plen,
> + argv[2], &gw6, &src6);
> if (err) {
> unixctl_command_reply_error(conn, "Error while inserting route.");
> } else {
> @@ -512,12 +581,19 @@ ovs_router_del(struct unixctl_conn *conn, int argc
> OVS_UNUSED,
> static void
> ovs_router_show_json(struct json **routes)
> {
> - int n_rules = classifier_count(&cls);
> struct json **json_entries = NULL;
> struct ovs_router_entry *rt;
> + struct classifier *cls_main;
> struct ds ds;
> + int n_rules;
> int i = 0;
>
> + cls_main = cls_find(CLS_MAIN);
> + if (!cls_main) {
> + goto out;
> + }
> +
> + n_rules = classifier_count(cls_main);
> if (!n_rules) {
> goto out;
> }
> @@ -525,7 +601,7 @@ ovs_router_show_json(struct json **routes)
> json_entries = xmalloc(n_rules * sizeof *json_entries);
> ds_init(&ds);
>
> - CLS_FOR_EACH (rt, cr, &cls) {
> + CLS_FOR_EACH (rt, cr, cls_main) {
> bool user = rt->priority != rt->plen && !rt->local;
> uint8_t plen = rt->plen;
> struct json *json, *nh;
> @@ -579,9 +655,15 @@ static void
> ovs_router_show_text(struct ds *ds)
> {
> struct ovs_router_entry *rt;
> + struct classifier *cls_main;
> +
> + cls_main = cls_find(CLS_MAIN);
> + if (!cls_main) {
> + return;
> + }
>
> ds_put_format(ds, "Route Table:\n");
> - CLS_FOR_EACH (rt, cr, &cls) {
> + CLS_FOR_EACH (rt, cr, cls_main) {
> uint8_t plen;
> if (rt->priority == rt->plen || rt->local) {
> ds_put_format(ds, "Cached: ");
> @@ -668,19 +750,26 @@ ovs_router_lookup_cmd(struct unixctl_conn *conn, int
> argc,
> }
> }
>
> +static void
> +clsmap_node_destroy_cb(struct clsmap_node *node)
> +{
> + classifier_destroy(&node->cls);
> + ovsrcu_postpone(free, node);
> +}
> +
> void
> -ovs_router_flush(void)
> +ovs_router_flush(bool flush_all)
> {
> - struct ovs_router_entry *rt;
> + struct clsmap_node *node;
>
> ovs_mutex_lock(&mutex);
> - classifier_defer(&cls);
> - CLS_FOR_EACH(rt, cr, &cls) {
> - if (rt->priority == rt->plen || rt->local) {
> - rt_entry_delete__(&rt->cr);
> + CMAP_FOR_EACH (node, cmap_node, &clsmap) {
> + cls_flush(&node->cls, flush_all);
The "local" check disappeared here and re-added in a later patch.
> + if (!node->cls.n_rules) {
> + cmap_remove(&clsmap, &node->cmap_node, hash_int(node->table, 0));
> + ovsrcu_postpone(clsmap_node_destroy_cb, node);
> }
> }
> - classifier_publish(&cls);
> ovs_mutex_unlock(&mutex);
> seq_change(tnl_conf_seq);
> }
> @@ -688,7 +777,13 @@ ovs_router_flush(void)
> static void
> ovs_router_flush_handler(void *aux OVS_UNUSED)
> {
> - ovs_router_flush();
> + ovs_router_flush(true);
> +
> + ovs_mutex_lock(&mutex);
> + ovs_assert(cmap_is_empty(&clsmap));
There is an unlock+lock after the flush, so this might technically fail.
I guess, the problem is that ovs_router_flush() also takes the mutes, so
it can't be moved under this critical section. In that case we normally
create a _protected() variant with OVS_REQUIRES(mutex) and call it from
both places while under the mutex.
> + cmap_destroy(&clsmap);
> + cmap_init(&clsmap);
> + ovs_mutex_unlock(&mutex);
> }
>
> void
> @@ -697,8 +792,10 @@ ovs_router_init(void)
> static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
>
> if (ovsthread_once_start(&once)) {
> + ovs_mutex_lock(&mutex);
> + cmap_init(&clsmap);
Is this necessary? There is a CMAP_INITIALIZER at the top.
> + ovs_mutex_unlock(&mutex);
> fatal_signal_add_hook(ovs_router_flush_handler, NULL, NULL, true);
> - classifier_init(&cls, NULL);
> unixctl_command_register("ovs/route/add",
> "ip/plen dev [gw] "
> "[pkt_mark=mark] [src=src_ip]",
> diff --git a/lib/ovs-router.h b/lib/ovs-router.h
> index b61712707b1e..f4e6487d3dc6 100644
> --- a/lib/ovs-router.h
> +++ b/lib/ovs-router.h
> @@ -26,20 +26,27 @@
> extern "C" {
> #endif
>
> +enum {
> + CLS_MAIN = 254,
> + CLS_ALL = UINT32_MAX,
> +};
> +
> bool ovs_router_lookup(uint32_t mark, const struct in6_addr *ip_dst,
> char output_netdev[],
> struct in6_addr *src, struct in6_addr *gw);
> void ovs_router_init(void);
> -void ovs_router_insert(uint32_t mark, const struct in6_addr *ip_dst,
> +void ovs_router_insert(uint32_t table, uint32_t mark,
> + const struct in6_addr *ip_dst,
> uint8_t plen, bool local,
> const char output_netdev[], const struct in6_addr *gw,
> const struct in6_addr *prefsrc);
> -void ovs_router_force_insert(uint32_t mark, const struct in6_addr *ip_dst,
> +void ovs_router_force_insert(uint32_t table, uint32_t mark,
> + const struct in6_addr *ip_dst,
> uint8_t plen, bool local,
> const char output_netdev[],
> const struct in6_addr *gw,
> const struct in6_addr *prefsrc);
> -void ovs_router_flush(void);
> +void ovs_router_flush(bool flush_all);
>
> void ovs_router_disable_system_routing_table(void);
>
> diff --git a/lib/route-table.c b/lib/route-table.c
> index 2bbb51c08f7e..96b7d495e1a5 100644
> --- a/lib/route-table.c
> +++ b/lib/route-table.c
> @@ -48,6 +48,8 @@ VLOG_DEFINE_THIS_MODULE(route_table);
>
> COVERAGE_DEFINE(route_table_dump);
>
> +BUILD_ASSERT_DECL((enum rt_class_t) CLS_MAIN == RT_TABLE_MAIN);
> +
> static struct ovs_mutex route_table_mutex = OVS_MUTEX_INITIALIZER;
> static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
>
> @@ -556,7 +558,7 @@ route_table_handle_msg(const struct route_table_msg
> *change,
> rdnh = CONTAINER_OF(ovs_list_front(&change->rd.nexthops),
> const struct route_data_nexthop, nexthop_node);
>
> - ovs_router_insert(rd->rta_mark, &rd->rta_dst,
> + ovs_router_insert(CLS_MAIN, rd->rta_mark, &rd->rta_dst,
> IN6_IS_ADDR_V4MAPPED(&rd->rta_dst)
> ? rd->rtm_dst_len + 96 : rd->rtm_dst_len,
> rd->rtn_local, rdnh->ifname, &rdnh->addr,
> @@ -567,7 +569,7 @@ route_table_handle_msg(const struct route_table_msg
> *change,
> static void
> route_map_clear(void)
> {
> - ovs_router_flush();
> + ovs_router_flush(false);
> }
>
> bool
> diff --git a/tests/nsh.at b/tests/nsh.at
> index 0040a50b36c5..b4da9b118bae 100644
> --- a/tests/nsh.at
> +++ b/tests/nsh.at
> @@ -557,9 +557,12 @@ AT_CHECK([
> AT_CHECK([
> ovs-appctl ovs/route/show | grep Cached: | sort
> ], [0], [dnl
> -Cached: 10.0.0.0/24 dev br-p1 SRC 10.0.0.1 local
> -Cached: 20.0.0.0/24 dev br-p2 SRC 20.0.0.2 local
> -Cached: 30.0.0.0/24 dev br-p3 SRC 30.0.0.3 local
> +Cached: 10.0.0.0/24 dev br-p1 SRC 10.0.0.1
> +Cached: 10.0.0.1/32 dev br-p1 SRC 10.0.0.1 local
> +Cached: 20.0.0.0/24 dev br-p2 SRC 20.0.0.2
> +Cached: 20.0.0.2/32 dev br-p2 SRC 20.0.0.2 local
> +Cached: 30.0.0.0/24 dev br-p3 SRC 30.0.0.3
> +Cached: 30.0.0.3/32 dev br-p3 SRC 30.0.0.3 local
> ])
>
> AT_CHECK([
> diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
> index a0cd4a5cec95..dd2a38cfe126 100644
> --- a/tests/ofproto-dpif.at
> +++ b/tests/ofproto-dpif.at
> @@ -8504,7 +8504,8 @@ AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0
> 1.1.2.88/24], [0], [OK
> AT_CHECK([ovs-ofctl add-flow br0 action=normal])
> dnl Checking that a local route for added IP was successfully installed.
> AT_CHECK([ovs-appctl ovs/route/show | grep Cached], [0], [dnl
> -Cached: 1.1.2.0/24 dev br0 SRC 1.1.2.88 local
> +Cached: 1.1.2.88/32 dev br0 SRC 1.1.2.88 local
> +Cached: 1.1.2.0/24 dev br0 SRC 1.1.2.88
> ])
>
> dnl Prime ARP Cache for 1.1.2.92
> @@ -8521,8 +8522,10 @@ AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0
> 192.168.1.1/16], [0], [OK
> ])
> dnl Checking that a local route for added IP was successfully installed.
> AT_CHECK([ovs-appctl ovs/route/show | grep Cached | sort], [0], [dnl
> -Cached: 1.1.2.0/24 dev br0 SRC 1.1.2.88 local
> -Cached: 192.168.0.0/16 dev br0 SRC 192.168.1.1 local
> +Cached: 1.1.2.0/24 dev br0 SRC 1.1.2.88
> +Cached: 1.1.2.88/32 dev br0 SRC 1.1.2.88 local
> +Cached: 192.168.0.0/16 dev br0 SRC 192.168.1.1
> +Cached: 192.168.1.1/32 dev br0 SRC 192.168.1.1 local
> ])
>
> dnl add rule for int-br to force packet onto tunnel. There is no ifindex
> diff --git a/tests/ovs-router.at b/tests/ovs-router.at
> index 641b780a582a..d5f56da786d9 100644
> --- a/tests/ovs-router.at
> +++ b/tests/ovs-router.at
> @@ -31,14 +31,35 @@ User: 2.2.2.3/32 MARK 1 dev br0 SRC 2.2.2.2
> AT_CHECK([ovs-appctl --format=json --pretty ovs/route/show], [0], [dnl
> [[
> {
> - "dst": "2.2.2.0",
> + "dst": "2.2.2.2",
> "local": true,
> + "nexthops": [
> + {
> + "dev": "br0"}],
> + "prefix": 32,
> + "prefsrc": "2.2.2.2",
> + "priority": 192,
> + "user": false},
> + {
> + "dst": "2.2.2.3",
> + "local": false,
> + "mark": 1,
> + "nexthops": [
> + {
> + "dev": "br0"}],
> + "prefix": 32,
> + "prefsrc": "2.2.2.2",
> + "priority": 160,
> + "user": true},
> + {
> + "dst": "2.2.2.0",
> + "local": false,
> "nexthops": [
> {
> "dev": "br0"}],
> "prefix": 24,
> "prefsrc": "2.2.2.2",
> - "priority": 184,
> + "priority": 120,
> "user": false},
> {
> "dst": "1.1.1.0",
> @@ -62,17 +83,6 @@ AT_CHECK([ovs-appctl --format=json --pretty
> ovs/route/show], [0], [dnl
> "prefix": 24,
> "prefsrc": "2.2.2.2",
> "priority": 152,
> - "user": true},
> - {
> - "dst": "2.2.2.3",
> - "local": false,
> - "mark": 1,
> - "nexthops": [
> - {
> - "dev": "br0"}],
> - "prefix": 32,
> - "prefsrc": "2.2.2.2",
> - "priority": 160,
> "user": true}]]
> ])
> OVS_VSWITCHD_STOP
> diff --git a/tests/packet-type-aware.at b/tests/packet-type-aware.at
> index d634930fd529..3161fddcd37e 100644
> --- a/tests/packet-type-aware.at
> +++ b/tests/packet-type-aware.at
> @@ -160,9 +160,12 @@ AT_CHECK([
> AT_CHECK([
> ovs-appctl ovs/route/show | grep Cached: | sort
> ], [0], [dnl
> -Cached: 10.0.0.0/24 dev br-p1 SRC 10.0.0.1 local
> -Cached: 20.0.0.0/24 dev br-p2 SRC 20.0.0.2 local
> -Cached: 30.0.0.0/24 dev br-p3 SRC 30.0.0.3 local
> +Cached: 10.0.0.0/24 dev br-p1 SRC 10.0.0.1
> +Cached: 10.0.0.1/32 dev br-p1 SRC 10.0.0.1 local
> +Cached: 20.0.0.0/24 dev br-p2 SRC 20.0.0.2
> +Cached: 20.0.0.2/32 dev br-p2 SRC 20.0.0.2 local
> +Cached: 30.0.0.0/24 dev br-p3 SRC 30.0.0.3
> +Cached: 30.0.0.3/32 dev br-p3 SRC 30.0.0.3 local
> ])
>
> AT_CHECK([
> @@ -684,7 +687,8 @@ AT_CHECK([
> AT_CHECK([
> ovs-appctl ovs/route/show | grep Cached:
> ], [0], [dnl
> -Cached: 10.0.0.0/24 dev br2 SRC 10.0.0.1 local
> +Cached: 10.0.0.1/32 dev br2 SRC 10.0.0.1 local
> +Cached: 10.0.0.0/24 dev br2 SRC 10.0.0.1
> ])
>
>
> @@ -960,7 +964,8 @@ ovs-appctl time/warp 1000
> AT_CHECK([
> ovs-appctl ovs/route/show | grep Cached:
> ],[0], [dnl
> -Cached: 20.0.0.0/24 dev br0 SRC 20.0.0.1 local
> +Cached: 20.0.0.1/32 dev br0 SRC 20.0.0.1 local
> +Cached: 20.0.0.0/24 dev br0 SRC 20.0.0.1
> ])
>
> AT_CHECK([
> diff --git a/tests/tunnel-push-pop-ipv6.at b/tests/tunnel-push-pop-ipv6.at
> index 39fbd2d35f55..2c8c9d9fb881 100644
> --- a/tests/tunnel-push-pop-ipv6.at
> +++ b/tests/tunnel-push-pop-ipv6.at
> @@ -24,7 +24,8 @@ AT_CHECK([ovs-appctl netdev-dummy/ip6addr br0
> 2001:cafe::88/24], [0], [OK
> ])
> dnl Checking that a local routes for added IPs were successfully installed.
> AT_CHECK([ovs-appctl ovs/route/show | grep Cached], [0], [dnl
> -Cached: 2001:ca00::/24 dev br0 SRC 2001:cafe::88 local
> +Cached: 2001:cafe::88/128 dev br0 SRC 2001:cafe::88 local
> +Cached: 2001:ca00::/24 dev br0 SRC 2001:cafe::88
> ])
> AT_CHECK([ovs-appctl tnl/neigh/set br0 2001:cafe::91 aa:55:aa:55:00:01],
> [0], [OK
> ])
> @@ -113,8 +114,10 @@ AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0
> 1.1.2.88/24], [0], [OK
> ])
> dnl Checking that a local routes for added IPs were successfully installed.
> AT_CHECK([ovs-appctl ovs/route/show | grep Cached | sort], [0], [dnl
> -Cached: 1.1.2.0/24 dev br0 SRC 1.1.2.88 local
> -Cached: 2001:ca00::/24 dev br0 SRC 2001:cafe::88 local
> +Cached: 1.1.2.0/24 dev br0 SRC 1.1.2.88
> +Cached: 1.1.2.88/32 dev br0 SRC 1.1.2.88 local
> +Cached: 2001:ca00::/24 dev br0 SRC 2001:cafe::88
> +Cached: 2001:cafe::88/128 dev br0 SRC 2001:cafe::88 local
> ])
>
> AT_CHECK([ovs-ofctl add-flow br0 action=normal])
> @@ -189,8 +192,10 @@ AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0
> 1.1.2.88/24], [0], [OK
> ])
> dnl Checking that a local routes for added IPs were successfully installed.
> AT_CHECK([ovs-appctl ovs/route/show | grep Cached | sort], [0], [dnl
> -Cached: 1.1.2.0/24 dev br0 SRC 1.1.2.88 local
> -Cached: 2001:ca00::/24 dev br0 SRC 2001:cafe::88 local
> +Cached: 1.1.2.0/24 dev br0 SRC 1.1.2.88
> +Cached: 1.1.2.88/32 dev br0 SRC 1.1.2.88 local
> +Cached: 2001:ca00::/24 dev br0 SRC 2001:cafe::88
> +Cached: 2001:cafe::88/128 dev br0 SRC 2001:cafe::88 local
> ])
>
> AT_CHECK([ovs-ofctl add-flow br0 action=normal])
> @@ -328,8 +333,10 @@ AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0
> 1.1.2.88/24], [0], [OK
> ])
> dnl Checking that a local routes for added IPs were successfully installed.
> AT_CHECK([ovs-appctl ovs/route/show | grep Cached | sort], [0], [dnl
> -Cached: 1.1.2.0/24 dev br0 SRC 1.1.2.88 local
> -Cached: 2001:ca00::/24 dev br0 SRC 2001:cafe::88 local
> +Cached: 1.1.2.0/24 dev br0 SRC 1.1.2.88
> +Cached: 1.1.2.88/32 dev br0 SRC 1.1.2.88 local
> +Cached: 2001:ca00::/24 dev br0 SRC 2001:cafe::88
> +Cached: 2001:cafe::88/128 dev br0 SRC 2001:cafe::88 local
> ])
>
> AT_CHECK([ovs-ofctl add-flow br0 action=normal])
> @@ -701,8 +708,10 @@ AT_CHECK([ovs-appctl netdev-dummy/ip6addr br0
> 2001:beef::88/64], [0], [OK
> ])
> dnl Checking that a local route for added IP was successfully installed.
> AT_CHECK([ovs-appctl ovs/route/show | grep Cached | sort], [0], [dnl
> -Cached: 2001:beef::/64 dev br0 SRC 2001:beef::88 local
> -Cached: 2001:cafe::/64 dev br0 SRC 2001:cafe::88 local
> +Cached: 2001:beef::/64 dev br0 SRC 2001:beef::88
> +Cached: 2001:beef::88/128 dev br0 SRC 2001:beef::88 local
> +Cached: 2001:cafe::/64 dev br0 SRC 2001:cafe::88
> +Cached: 2001:cafe::88/128 dev br0 SRC 2001:cafe::88 local
> ])
> AT_CHECK([ovs-ofctl add-flow br0 action=normal])
> AT_CHECK([ovs-ofctl add-flow int-br action=normal])
> @@ -784,7 +793,8 @@ AT_CHECK([ovs-appctl netdev-dummy/ip6addr br0
> 2001:cafe::88/64], [0], [OK
> ])
> dnl Checking that a local route for added IP was successfully installed.
> AT_CHECK([ovs-appctl ovs/route/show | grep Cached | sort], [0], [dnl
> -Cached: 2001:cafe::/64 dev br0 SRC 2001:cafe::88 local
> +Cached: 2001:cafe::/64 dev br0 SRC 2001:cafe::88
> +Cached: 2001:cafe::88/128 dev br0 SRC 2001:cafe::88 local
> ])
>
> dnl Add a dp-hash selection group.
> diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at
> index 64c41460bbb2..dfd967e9802d 100644
> --- a/tests/tunnel-push-pop.at
> +++ b/tests/tunnel-push-pop.at
> @@ -37,8 +37,10 @@ AT_CHECK([ovs-appctl netdev-dummy/ip6addr br0
> 2001:cafe::88/24], [0], [OK
> ])
> dnl Checking that a local routes for added IPs were successfully installed.
> AT_CHECK([ovs-appctl ovs/route/show | grep Cached | sort], [0], [dnl
> -Cached: 1.1.2.0/24 dev br0 SRC 1.1.2.88 local
> -Cached: 2001:ca00::/24 dev br0 SRC 2001:cafe::88 local
> +Cached: 1.1.2.0/24 dev br0 SRC 1.1.2.88
> +Cached: 1.1.2.88/32 dev br0 SRC 1.1.2.88 local
> +Cached: 2001:ca00::/24 dev br0 SRC 2001:cafe::88
> +Cached: 2001:cafe::88/128 dev br0 SRC 2001:cafe::88 local
> ])
>
> AT_CHECK([ovs-ofctl add-flow br0 action=normal])
> @@ -246,8 +248,10 @@ AT_CHECK([ovs-appctl ovs/route/add 1.1.2.92/24 br0
> pkt_mark=1234], [0], [OK
> dnl Checking that local routes for added IPs and the static route with a mark
> dnl were successfully installed.
> AT_CHECK([ovs-appctl ovs/route/show | grep br0 | sort], [0], [dnl
> -Cached: 1.1.2.0/24 dev br0 SRC 1.1.2.88 local
> -Cached: 2001:ca00::/24 dev br0 SRC 2001:cafe::88 local
> +Cached: 1.1.2.0/24 dev br0 SRC 1.1.2.88
> +Cached: 1.1.2.88/32 dev br0 SRC 1.1.2.88 local
> +Cached: 2001:ca00::/24 dev br0 SRC 2001:cafe::88
> +Cached: 2001:cafe::88/128 dev br0 SRC 2001:cafe::88 local
> User: 1.1.2.0/24 MARK 1234 dev br0 SRC 1.1.2.88
> ])
>
> @@ -779,7 +783,8 @@ AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0
> 1.1.2.88/24], [0], [OK
> ])
> dnl Checking that a local route for added IP was successfully installed.
> AT_CHECK([ovs-appctl ovs/route/show | grep Cached], [0], [dnl
> -Cached: 1.1.2.0/24 dev br0 SRC 1.1.2.88 local
> +Cached: 1.1.2.88/32 dev br0 SRC 1.1.2.88 local
> +Cached: 1.1.2.0/24 dev br0 SRC 1.1.2.88
> ])
>
> AT_CHECK([ovs-ofctl add-flow br0 action=normal])
> @@ -820,7 +825,8 @@ AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0
> 1.1.2.88/24], [0], [OK
> ])
> dnl Checking that a local route for added IP was successfully installed.
> AT_CHECK([ovs-appctl ovs/route/show | grep Cached], [0], [dnl
> -Cached: 1.1.2.0/24 dev br0 SRC 1.1.2.88 local
> +Cached: 1.1.2.88/32 dev br0 SRC 1.1.2.88 local
> +Cached: 1.1.2.0/24 dev br0 SRC 1.1.2.88
> ])
> AT_CHECK([ovs-ofctl add-flow br0 action=normal])
>
> @@ -893,8 +899,10 @@ AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0
> 2.2.2.88/24], [0], [OK
> ])
> dnl Checking that a local route for added IP was successfully installed.
> AT_CHECK([ovs-appctl ovs/route/show | grep Cached | sort], [0], [dnl
> -Cached: 1.1.2.0/24 dev br0 SRC 1.1.2.88 local
> -Cached: 2.2.2.0/24 dev br0 SRC 2.2.2.88 local
> +Cached: 1.1.2.0/24 dev br0 SRC 1.1.2.88
> +Cached: 1.1.2.88/32 dev br0 SRC 1.1.2.88 local
> +Cached: 2.2.2.0/24 dev br0 SRC 2.2.2.88
> +Cached: 2.2.2.88/32 dev br0 SRC 2.2.2.88 local
> ])
> AT_CHECK([ovs-ofctl add-flow br0 action=normal])
> AT_CHECK([ovs-ofctl add-flow int-br action=normal])
> @@ -975,7 +983,8 @@ AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0
> 1.1.2.88/24], [0], [OK
> ])
> dnl Checking that a local route for added IP was successfully installed.
> AT_CHECK([ovs-appctl ovs/route/show | grep Cached], [0], [dnl
> -Cached: 1.1.2.0/24 dev br0 SRC 1.1.2.88 local
> +Cached: 1.1.2.88/32 dev br0 SRC 1.1.2.88 local
> +Cached: 1.1.2.0/24 dev br0 SRC 1.1.2.88
> ])
>
> AT_CHECK([ovs-ofctl add-flow br0 'arp,priority=1,action=normal'])
> @@ -1025,7 +1034,8 @@ AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0
> 1.1.2.88/24], [0], [OK
> ])
> dnl Checking that a local route for added IP was successfully installed.
> AT_CHECK([ovs-appctl ovs/route/show | grep Cached], [0], [dnl
> -Cached: 1.1.2.0/24 dev br0 SRC 1.1.2.88 local
> +Cached: 1.1.2.88/32 dev br0 SRC 1.1.2.88 local
> +Cached: 1.1.2.0/24 dev br0 SRC 1.1.2.88
> ])
> AT_CHECK([ovs-ofctl add-flow br0 action=normal])
>
> @@ -1094,7 +1104,8 @@ AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0
> 10.0.0.2/24], [0], [OK
> ])
> dnl Checking that a local route for added IP was successfully installed.
> AT_CHECK([ovs-appctl ovs/route/show | grep Cached], [0], [dnl
> -Cached: 10.0.0.0/24 dev br0 SRC 10.0.0.2 local
> +Cached: 10.0.0.2/32 dev br0 SRC 10.0.0.2 local
> +Cached: 10.0.0.0/24 dev br0 SRC 10.0.0.2
> ])
>
> dnl Send an ARP reply to port b8 on br0, so that packets will be forwarded
> @@ -1141,7 +1152,8 @@ AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0
> 10.0.0.2/24], [0], [OK
> ])
> dnl Checking that a local route for added IP was successfully installed.
> AT_CHECK([ovs-appctl ovs/route/show | grep Cached], [0], [dnl
> -Cached: 10.0.0.0/24 dev br0 SRC 10.0.0.2 local
> +Cached: 10.0.0.2/32 dev br0 SRC 10.0.0.2 local
> +Cached: 10.0.0.0/24 dev br0 SRC 10.0.0.2
> ])
>
> dnl Send an ARP reply to port b8 on br0, so that packets will be forwarded
> @@ -1213,7 +1225,8 @@ AT_CHECK([ovs-appctl netdev-dummy/ip4addr vtep0
> 1.1.2.88/24], [0], [OK
> ])
> dnl Checking that a local route for added IP was successfully installed.
> AT_CHECK([ovs-appctl ovs/route/show | grep Cached], [0], [dnl
> -Cached: 1.1.2.0/24 dev vtep0 SRC 1.1.2.88 local
> +Cached: 1.1.2.88/32 dev vtep0 SRC 1.1.2.88 local
> +Cached: 1.1.2.0/24 dev vtep0 SRC 1.1.2.88
> ])
>
> AT_CHECK([ovs-ofctl add-flow br0 action=normal])
> @@ -1277,7 +1290,8 @@ AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0
> 1.1.2.88/24], [0], [OK
> ])
> dnl Checking that a local route for added IP was successfully installed.
> AT_CHECK([ovs-appctl ovs/route/show | grep Cached | sort], [0], [dnl
> -Cached: 1.1.2.0/24 dev br0 SRC 1.1.2.88 local
> +Cached: 1.1.2.0/24 dev br0 SRC 1.1.2.88
> +Cached: 1.1.2.88/32 dev br0 SRC 1.1.2.88 local
> ])
>
> dnl Add a dp-hash selection group.
> diff --git a/tests/tunnel.at b/tests/tunnel.at
> index 09e3c94c7a0a..35d8c581a0f4 100644
> --- a/tests/tunnel.at
> +++ b/tests/tunnel.at
> @@ -529,7 +529,8 @@ AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0
> 172.31.1.1/24], [0], [OK
> ])
> dnl Checking that a local route for added IP was successfully installed.
> AT_CHECK([ovs-appctl ovs/route/show | grep Cached], [0], [dnl
> -Cached: 172.31.1.0/24 dev br0 SRC 172.31.1.1 local
> +Cached: 172.31.1.1/32 dev br0 SRC 172.31.1.1 local
> +Cached: 172.31.1.0/24 dev br0 SRC 172.31.1.1
> ])
>
> dnl change the flow table to bump the internal table version
> @@ -1288,7 +1289,8 @@ AT_CHECK([ovs-appctl netdev-dummy/ip6addr br0
> fc00::1/64], [0], [OK
> ])
> dnl Checking that a local route for added IP was successfully installed.
> AT_CHECK([ovs-appctl ovs/route/show | grep Cached], [0], [dnl
> -Cached: fc00::/64 dev br0 SRC fc00::1 local
> +Cached: fc00::1/128 dev br0 SRC fc00::1 local
> +Cached: fc00::/64 dev br0 SRC fc00::1
> ])
>
> AT_DATA([flows.txt], [dnl
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev