Add two new commands `ovs-appctl ovs/route/rule/add` and `ovs-appctl ovs/route/rule/del` for adding and deleting user routing rules in OVS:
ovs/route/rule/add [-6] [not] from=all|ip/plen [prio=num] table=local|main|default|id ovs/route/rule/del [-6] [not] from=all|ip/plen [prio=num] table=local|main|default|id Examples for adding user rules: ovs-appctl ovs/route/rule/add from=all table=10 ovs-appctl ovs/route/rule/add from=all prio=10 table=10 ovs-appctl ovs/route/rule/add not from=10.0.0.0/24 table=10 Examples for deleting user rules: ovs-appctl ovs/route/rule/del from=all prio=10 table=10 ovs-appctl ovs/route/rule/del from=all table=10 ovs-appctl ovs/route/rule/del not from=10.0.0.0/24 table=10 When adding a new rule, if priority is not specified, the lowest unused priority will be selected automatically. Multiple rules with the same priority may exist. User added rules and kernel cached rules co-exist together. Only user added rules can be deleted with 'ovs/route/rule/del' command. For kernel cached rules they must be deleted using `ip rule del` system command. If priority is not specified when deleting a rule, the first matching rule will be selected for deletion. Signed-off-by: Dima Chumak <[email protected]> --- Documentation/howto/userspace-tunneling.rst | 7 + NEWS | 2 + lib/ovs-router.c | 242 +++++++++++++++++++- lib/ovs-router.h | 11 +- lib/route-table.c | 6 +- ofproto/ofproto-tnl-unixctl.man | 16 ++ tests/ovs-router.at | 91 +++++++- tests/system-route.at | 20 +- tests/tunnel-push-pop.at | 123 ++++++++++ 9 files changed, 484 insertions(+), 34 deletions(-) diff --git a/Documentation/howto/userspace-tunneling.rst b/Documentation/howto/userspace-tunneling.rst index fc458ada6a2e..1ff5252fb67f 100644 --- a/Documentation/howto/userspace-tunneling.rst +++ b/Documentation/howto/userspace-tunneling.rst @@ -208,6 +208,13 @@ To see all routes configured:: $ ovs-appctl ovs/route/show [table=ID|all] +To add/delete router rule:: + + $ ovs-appctl ovs/route/rule/add [-6] [not] from=all|IP/PLEN [prio=NUM] + table=local|main|default|ID + $ ovs-appctl ovs/route/rule/del [-6] [not] from=all|IP/PLEN [prio=NUM] + table=local|main|default|ID + To see all router rules configured:: $ ovs-appctl ovs/route/rule/show [-6] diff --git a/NEWS b/NEWS index c805c282eb8e..36b18eabcff0 100644 --- a/NEWS +++ b/NEWS @@ -43,6 +43,8 @@ Post-v3.6.0 add/delete a route from a specific table. * 'ovs/route/lookup': added new option, src=IP, to perform lookup with a specific source IP address. + * Added new sub-commands, ovs/route/rule/{add,del}, to add and remove + user routing rules in OVS. v3.6.0 - 18 Aug 2025 diff --git a/lib/ovs-router.c b/lib/ovs-router.c index 1e03edf42c23..a8cfcea7694f 100644 --- a/lib/ovs-router.c +++ b/lib/ovs-router.c @@ -62,6 +62,7 @@ struct router_rule { uint32_t prio; bool invert; bool ipv4; + bool user; uint8_t src_prefix; struct in6_addr from_addr; uint32_t lookup_table; @@ -860,6 +861,7 @@ ovs_router_rules_show_json(struct json *rule_entries, bool ipv6) } json_object_put(entry, "priority", json_integer_create(rule->prio)); + json_object_put(entry, "user", json_integer_create(rule->user)); json_object_put(entry, "invert", json_boolean_create(rule->invert)); json_object_put(entry, "ipv4", json_boolean_create(rule->ipv4)); json_object_put(entry, "src-prefix", @@ -904,6 +906,19 @@ ovs_router_rules_show_text(struct ds *ds, bool ipv6) if (rule->ipv4 == ipv6) { continue; } + if (rule->user) { + if (rule->ipv4) { + ds_put_format(ds, "User: "); + } else { + ds_put_format(ds, "User6: "); + } + } else { + if (rule->ipv4) { + ds_put_format(ds, "Cached: "); + } else { + ds_put_format(ds, "Cached6: "); + } + } ds_put_format(ds, "%"PRIu32": ", rule->prio); if (rule->invert) { ds_put_format(ds, "not "); @@ -952,6 +967,168 @@ ovs_router_rules_show(struct unixctl_conn *conn, int argc OVS_UNUSED, } } +static void +ovs_router_rule_add_cmd(struct unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) +{ + unsigned int src_len = 0; + struct in6_addr from; + bool invert = false; + bool ipv4 = true; + uint32_t prio = 0; + uint32_t table; + ovs_be32 ip; + int i = 1; + + if (ovs_scan(argv[i], "-6")) { + ipv4 = false; + i++; + } + if (ovs_scan(argv[i], "not")) { + invert = true; + i++; + } + + if (ovs_scan(argv[i], "from=all")) { + from = in6addr_any; + } else if (ovs_scan(argv[i], "from=")) { + const char *arg = &argv[i][strlen("from=")]; + + if (scan_ipv4_route(arg, &ip, &src_len)) { + in6_addr_set_mapped_ipv4(&from, ip); + ipv4 = true; + } else if (scan_ipv6_route(arg, &from, &src_len)) { + ipv4 = false; + } else { + unixctl_command_reply_error(conn, "Invalid from=ip/plen"); + return; + } + } else { + unixctl_command_reply_error(conn, "Invalid 'from' parameter"); + return; + } + if (argc <= ++i) { + unixctl_command_reply_error(conn, "Not enough arguments"); + return; + } + + if (ovs_scan(argv[i], "prio=%"SCNu32, &prio)) { + if (argc <= ++i) { + unixctl_command_reply_error(conn, "Not enough arguments"); + return; + } + } + + if (ovs_scan(argv[i], "table=local")) { + table = CLS_LOCAL; + } else if (ovs_scan(argv[i], "table=main")) { + table = CLS_MAIN; + } else if (ovs_scan(argv[i], "table=default")) { + table = CLS_DEFAULT; + } else if (!ovs_scan(argv[i], "table=%"SCNu32, &table)) { + unixctl_command_reply_error(conn, "Invalid 'table' format"); + return; + } + + ovs_mutex_lock(&mutex); + if (!prio) { + struct router_rule *rule; + uint32_t prev_prio = 0; + + PVECTOR_FOR_EACH (rule, &rules) { + if ((!prio && rule->prio) || + (rule->prio - prev_prio > 1)) { + prio = rule->prio - 1; + } + prev_prio = rule->prio; + } + } + ovs_router_rule_add(prio, invert, true, src_len, &from, table, ipv4); + ovs_mutex_unlock(&mutex); + + unixctl_command_reply(conn, "OK"); +} + +static void +ovs_router_rule_del_cmd(struct unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) +{ + unsigned int src_len = 0; + struct in6_addr from; + bool invert = false; + bool ipv4 = true; + uint32_t prio = 0; + uint32_t table; + ovs_be32 ip; + int i = 1; + int err; + + if (ovs_scan(argv[i], "-6")) { + ipv4 = false; + i++; + } + if (ovs_scan(argv[i], "not")) { + invert = true; + i++; + } + + if (ovs_scan(argv[i], "from=all")) { + from = in6addr_any; + } else if (ovs_scan(argv[i], "from=")) { + const char *arg = &argv[i][strlen("from=")]; + + if (scan_ipv4_route(arg, &ip, &src_len)) { + in6_addr_set_mapped_ipv4(&from, ip); + ipv4 = true; + } else if (scan_ipv6_route(arg, &from, &src_len)) { + ipv4 = false; + } else { + unixctl_command_reply_error(conn, "Invalid from=ip/plen"); + return; + } + } else { + unixctl_command_reply_error(conn, "Invalid 'from' parameter"); + return; + } + if (argc <= ++i) { + unixctl_command_reply_error(conn, "Not enough arguments"); + return; + } + + if (ovs_scan(argv[i], "prio=%"SCNu32, &prio)) { + if (argc <= ++i) { + unixctl_command_reply_error(conn, "Not enough arguments"); + return; + } + } + + if (ovs_scan(argv[i], "table=local")) { + table = CLS_LOCAL; + } else if (ovs_scan(argv[i], "table=main")) { + table = CLS_MAIN; + } else if (ovs_scan(argv[i], "table=default")) { + table = CLS_DEFAULT; + } else if (!ovs_scan(argv[i], "table=%"SCNu32, &table)) { + unixctl_command_reply_error(conn, "Invalid 'table' format"); + return; + } + + ovs_mutex_lock(&mutex); + err = ovs_router_rule_del(prio, invert, src_len, &from, table, ipv4); + ovs_mutex_unlock(&mutex); + + if (err) { + struct ds ds = DS_EMPTY_INITIALIZER; + + ds_put_format(&ds, "Failed to delete router rule: %d (%s)", err, + ovs_strerror(err)); + unixctl_command_reply_error(conn, ds_cstr_ro(&ds)); + ds_destroy(&ds); + } else { + unixctl_command_reply(conn, "OK"); + } +} + static void ovs_router_lookup_cmd(struct unixctl_conn *conn, int argc, const char *argv[], void *aux OVS_UNUSED) @@ -1052,16 +1229,16 @@ static void init_standard_rules(void) { /* Add default rules using same priorities as Linux kernel does. */ - ovs_router_rule_add(0, false, 0, + ovs_router_rule_add(0, false, false, 0, &in6addr_v4mapped_any, CLS_LOCAL, true); - ovs_router_rule_add(0x7FFE, false, 0, + ovs_router_rule_add(0x7FFE, false, false, 0, &in6addr_v4mapped_any, CLS_MAIN, true); - ovs_router_rule_add(0x7FFF, false, 0, + ovs_router_rule_add(0x7FFF, false, false, 0, &in6addr_v4mapped_any, CLS_DEFAULT, true); - ovs_router_rule_add(0, false, 0, + ovs_router_rule_add(0, false, false, 0, &in6addr_any, CLS_LOCAL, false); - ovs_router_rule_add(0x7FFE, false, 0, + ovs_router_rule_add(0x7FFE, false, false, 0, &in6addr_any, CLS_MAIN, false); } @@ -1072,22 +1249,24 @@ rule_destroy_cb(struct router_rule *rule) } static void -ovs_router_rules_flush_protected(void) +ovs_router_rules_flush_protected(bool flush_all) { struct router_rule *rule; PVECTOR_FOR_EACH (rule, &rules) { - pvector_remove(&rules, rule); - ovsrcu_postpone(rule_destroy_cb, rule); + if (flush_all || !rule->user) { + pvector_remove(&rules, rule); + ovsrcu_postpone(rule_destroy_cb, rule); + } } pvector_publish(&rules); } void -ovs_router_rules_flush(void) +ovs_router_rules_flush(bool flush_all) { ovs_mutex_lock(&mutex); - ovs_router_rules_flush_protected(); + ovs_router_rules_flush_protected(flush_all); ovs_mutex_unlock(&mutex); } @@ -1095,7 +1274,7 @@ static void ovs_router_flush_handler(void *aux OVS_UNUSED) { ovs_mutex_lock(&mutex); - ovs_router_rules_flush_protected(); + ovs_router_rules_flush_protected(true); ovs_router_flush_protected(true); pvector_destroy(&rules); ovs_assert(cmap_is_empty(&clsmap)); @@ -1137,14 +1316,16 @@ rule_pvec_prio(uint32_t prio) } void -ovs_router_rule_add(uint32_t prio, bool invert, uint8_t src_len, +ovs_router_rule_add(uint32_t prio, bool invert, bool user, uint8_t src_len, const struct in6_addr *from, uint32_t lookup_table, bool ipv4) + OVS_REQUIRES(mutex) { struct router_rule *rule = xzalloc(sizeof *rule); rule->prio = prio; rule->invert = invert; + rule->user = user; rule->src_prefix = src_len; rule->from_addr = *from; rule->lookup_table = lookup_table; @@ -1154,6 +1335,35 @@ ovs_router_rule_add(uint32_t prio, bool invert, uint8_t src_len, pvector_publish(&rules); } +int +ovs_router_rule_del(uint32_t prio, bool invert, uint8_t src_len, + const struct in6_addr *from, uint32_t lookup_table, + bool ipv4) + OVS_REQUIRES(mutex) +{ + struct router_rule *rule; + + PVECTOR_FOR_EACH (rule, &rules) { + if (prio && rule->prio > prio) { + break; + } + if (rule->user + && rule->invert == invert + && (!prio || rule->prio == prio) + && rule->ipv4 == ipv4 + && rule->src_prefix == src_len + && ipv6_addr_equals(&rule->from_addr, from) + && rule->lookup_table == lookup_table) { + pvector_remove(&rules, rule); + ovsrcu_postpone(rule_destroy_cb, rule); + pvector_publish(&rules); + return 0; + } + } + + return -ENOENT; +} + void ovs_router_init(void) { @@ -1179,6 +1389,14 @@ ovs_router_init(void) ovs_router_lookup_cmd, NULL); unixctl_command_register("ovs/route/rule/show", "-6", 0, 1, ovs_router_rules_show, NULL); + unixctl_command_register("ovs/route/rule/add", + "[-6] [not] from=all|ip/plen [prio=num] " + "table=local|main|default|id", + 2, 5, ovs_router_rule_add_cmd, NULL); + unixctl_command_register("ovs/route/rule/del", + "[-6] [not] from=all|ip/plen [prio=num] " + "table=local|main|default|id", + 2, 5, ovs_router_rule_del_cmd, NULL); ovsthread_once_done(&once); } } diff --git a/lib/ovs-router.h b/lib/ovs-router.h index f9c1d90d39b0..bd1ab7a9af48 100644 --- a/lib/ovs-router.h +++ b/lib/ovs-router.h @@ -48,11 +48,14 @@ void ovs_router_force_insert(uint32_t table, uint32_t mark, uint8_t plen, const char output_netdev[], const struct in6_addr *gw, const struct in6_addr *prefsrc); -void ovs_router_rule_add(uint32_t prio, bool invert, uint8_t src_len, - const struct in6_addr *from, uint32_t lookup_table, - bool ipv4); +void ovs_router_rule_add(uint32_t prio, bool invert, bool user, + uint8_t src_len, const struct in6_addr *from, + uint32_t lookup_table, bool ipv4); +int ovs_router_rule_del(uint32_t prio, bool invert, uint8_t src_len, + const struct in6_addr *from, uint32_t lookup_table, + bool ipv4); void ovs_router_flush(bool flush_all); -void ovs_router_rules_flush(void); +void ovs_router_rules_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 53bf5a8d5561..c2b815ac1906 100644 --- a/lib/route-table.c +++ b/lib/route-table.c @@ -288,8 +288,8 @@ rule_handle_msg(const struct route_table_msg *change) route_table_dump_one_table(rd->lookup_table, route_table_handle_msg, NULL); - ovs_router_rule_add(rd->prio, rd->invert, rd->src_len, &rd->from_addr, - rd->lookup_table, rd->ipv4); + ovs_router_rule_add(rd->prio, rd->invert, false, rd->src_len, + &rd->from_addr, rd->lookup_table, rd->ipv4); } } @@ -769,7 +769,7 @@ rules_change(const struct route_table_msg *change OVS_UNUSED, static void route_map_clear(void) { - ovs_router_rules_flush(); + ovs_router_rules_flush(false); ovs_router_flush(false); } diff --git a/ofproto/ofproto-tnl-unixctl.man b/ofproto/ofproto-tnl-unixctl.man index 10116df638f3..b2a401564070 100644 --- a/ofproto/ofproto-tnl-unixctl.man +++ b/ofproto/ofproto-tnl-unixctl.man @@ -34,6 +34,22 @@ Print routing rules in OVS. This includes routing rules cached from the system routing policy database and user configured routing rules. By default only IPv4 rules are displayed. For displaying IPv6 rules \fB-6\fR option is required. . +.IP "\fBovs/route/rule/add\fR [\fB-6\fR] [\fBnot\fR] \ +\fBfrom\fR=\fBall\fR|\fIip/plen\fR [\fBprio\fR=\fInum\fR] \ +\fBtable\fR=\fBlocal\fR|\fBmain\fR|\fBdefault\fR|\fIid\fR" +Add user-configured routing rule to vswitchd. It can be useful to reference +non-standard routing tables for configuring advanced routing policies, for +example matching on the source IP address. If priority is not specified, the +lowest unused priority will be selected automatically. Multiple rules with the +same priority may exist. User-configured rules and system cached rules co-exist +together. +. +.IP "\fBovs/route/rule/del\fR [\fB-6\fR] [\fBnot\fR] \ +\fBfrom\fR=\fBall\fR|\fIip/plen\fR [\fBprio\fR=\fInum\fR] \ +\fBtable\fR=\fBlocal\fR|\fBmain\fR|\fBdefault\fR|\fIid\fR" +Delete user-configured routing rule from vswitchd. If priority is not specified +the first matching rule will be selected for deletion. +. .IP "\fBtnl/neigh/show\fR" .IP "\fBtnl/arp/show\fR" OVS builds ARP cache by snooping are messages. This command shows diff --git a/tests/ovs-router.at b/tests/ovs-router.at index 0cd338371350..529f527bbd3b 100644 --- a/tests/ovs-router.at +++ b/tests/ovs-router.at @@ -249,14 +249,95 @@ AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 192.0.2.1/24], [0], [OK dnl Check standard rules exist. AT_CHECK([ovs-appctl ovs/route/rule/show], [0], [dnl -0: from all lookup local -32766: from all lookup main -32767: from all lookup default +Cached: 0: from all lookup local +Cached: 32766: from all lookup main +Cached: 32767: from all lookup default ]) AT_CHECK([ovs-appctl ovs/route/rule/show -6], [0], [dnl -0: from all lookup local -32766: from all lookup main +Cached6: 0: from all lookup local +Cached6: 32766: from all lookup main ]) OVS_VSWITCHD_STOP AT_CLEANUP + +AT_SETUP([appctl - route/rule/{add,del}]) +AT_KEYWORDS([ovs_router]) +OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=dummy]) +AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 192.0.2.1/24], [0], [OK +]) + +AT_CHECK([ovs-appctl ovs/route/add 10.1.1.0/24 br0 192.0.2.2 table=11], [0], [OK +]) +AT_CHECK([ovs-appctl ovs/route/add 10.2.2.0/24 br0 192.0.2.2 table=12], [0], [OK +]) +AT_CHECK([ovs-appctl ovs/route/show table=all | sort], [0], [dnl +Cached: 192.0.2.0/24 dev br0 SRC 192.0.2.1 +Cached: 192.0.2.1/32 dev br0 SRC 192.0.2.1 local +User: 10.1.1.0/24 dev br0 GW 192.0.2.2 SRC 192.0.2.1 table 11 +User: 10.2.2.0/24 dev br0 GW 192.0.2.2 SRC 192.0.2.1 table 12 +]) + +AT_CHECK([ovs-appctl ovs/route/rule/add from=192.0.2.10/32 table=11], [0], [OK +]) +AT_CHECK([ovs-appctl ovs/route/rule/add from=192.0.2.20/32 table=12], [0], [OK +]) +AT_CHECK([ovs-appctl ovs/route/rule/show], [0], [dnl +Cached: 0: from all lookup local +User: 32764: from 192.0.2.20 lookup 12 +User: 32765: from 192.0.2.10 lookup 11 +Cached: 32766: from all lookup main +Cached: 32767: from all lookup default +]) + +AT_CHECK([ovs-appctl ovs/route/rule/add from=192.0.2.10/32 table=11], [0], [OK +]) +AT_CHECK([ovs-appctl ovs/route/rule/add from=192.0.2.10/32 table=11], [0], [OK +]) +AT_CHECK([ovs-appctl ovs/route/rule/show], [0], [dnl +Cached: 0: from all lookup local +User: 32762: from 192.0.2.10 lookup 11 +User: 32763: from 192.0.2.10 lookup 11 +User: 32764: from 192.0.2.20 lookup 12 +User: 32765: from 192.0.2.10 lookup 11 +Cached: 32766: from all lookup main +Cached: 32767: from all lookup default +]) + +AT_CHECK([ovs-appctl ovs/route/rule/del from=192.0.2.10/32 table=11], [0], [OK +]) +AT_CHECK([ovs-appctl ovs/route/rule/show], [0], [dnl +Cached: 0: from all lookup local +User: 32763: from 192.0.2.10 lookup 11 +User: 32764: from 192.0.2.20 lookup 12 +User: 32765: from 192.0.2.10 lookup 11 +Cached: 32766: from all lookup main +Cached: 32767: from all lookup default +]) + +AT_CHECK([ovs-appctl ovs/route/rule/del from=192.0.2.10/32 prio=32765 table=11], [0], [OK +]) +AT_CHECK([ovs-appctl ovs/route/rule/show], [0], [dnl +Cached: 0: from all lookup local +User: 32763: from 192.0.2.10 lookup 11 +User: 32764: from 192.0.2.20 lookup 12 +Cached: 32766: from all lookup main +Cached: 32767: from all lookup default +]) + +OVS_VSWITCHD_STOP +AT_CLEANUP + +AT_SETUP([appctl - route/rule cleanup]) +AT_KEYWORDS([ovs_router]) +OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=dummy]) +AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 192.0.2.1/24], [0], [OK +]) + +AT_CHECK([for i in `seq 1 100`; do ovs-appctl ovs/route/add 10.1.$i.0/24 br0 192.0.2.2 table=11 ; done >/dev/null]) +AT_CHECK([test `ovs-appctl ovs/route/show table=11 | grep '^User:' | wc -l` -eq 100]) +AT_CHECK([for i in `seq 1 50`; do ovs-appctl ovs/route/del 10.1.$i.0/24 table=11 ; done >/dev/null]) +AT_CHECK([test `ovs-appctl ovs/route/show table=11 | grep '^User:' | wc -l` -eq 50]) + +OVS_VSWITCHD_STOP +AT_CLEANUP diff --git a/tests/system-route.at b/tests/system-route.at index 182a628fe270..a0740cfad552 100644 --- a/tests/system-route.at +++ b/tests/system-route.at @@ -345,13 +345,13 @@ AT_CHECK([ip link set p1-route up]) dnl Check there are no non-standard rules cached in OVS. AT_CHECK([ovs-appctl ovs/route/rule/show], [0], [dnl -0: from all lookup local -32766: from all lookup main -32767: from all lookup default +Cached: 0: from all lookup local +Cached: 32766: from all lookup main +Cached: 32767: from all lookup default ]) AT_CHECK([ovs-appctl ovs/route/rule/show -6], [0], [dnl -0: from all lookup local -32766: from all lookup main +Cached6: 0: from all lookup local +Cached6: 32766: from all lookup main ]) dnl Add unsupported rules to kernel. @@ -367,13 +367,13 @@ dnl Give the main thread a chance to act. AT_CHECK([ovs-appctl revalidator/wait]) dnl Check OVS rules cache hasn't changed. AT_CHECK([ovs-appctl ovs/route/rule/show], [0], [dnl -0: from all lookup local -32766: from all lookup main -32767: from all lookup default +Cached: 0: from all lookup local +Cached: 32766: from all lookup main +Cached: 32767: from all lookup default ]) AT_CHECK([ovs-appctl ovs/route/rule/show -6], [0], [dnl -0: from all lookup local -32766: from all lookup main +Cached6: 0: from all lookup local +Cached6: 32766: from all lookup main ]) dnl Add unsupported rules to kernel. diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at index 5e5a1013acfa..f22a37570426 100644 --- a/tests/tunnel-push-pop.at +++ b/tests/tunnel-push-pop.at @@ -1467,3 +1467,126 @@ AT_CHECK([tail -1 stdout], [0], OVS_VSWITCHD_STOP AT_CLEANUP + +AT_SETUP([tunnel_push_pop - use two VTEPs in same subnet with rules]) + +dnl Create bridge that has a MAC address. +OVS_VSWITCHD_START([set bridge br0 datapath_type=dummy dnl + -- set Interface br0 other-config:hwaddr=aa:55:aa:55:00:00]) + +AT_CHECK([ovs-vsctl add-port br0 p0 \ + -- set Interface p0 type=dummy ofport_request=1]) + +AT_CHECK([ovs-vsctl add-br br1 \ + -- set bridge br1 datapath_type=dummy \ + -- set Interface br1 other-config:hwaddr=aa:66:aa:66:00:00]) +AT_CHECK([ovs-vsctl add-port br1 p1 \ + -- set interface p1 type=dummy ofport_request=2]) + +AT_CHECK([ovs-vsctl \ + -- add-br int-br \ + -- set bridge int-br datapath_type=dummy \ + -- set Interface int-br other-config:hwaddr=aa:77:aa:77:00:00]) +AT_CHECK([ovs-vsctl \ + -- add-port int-br t0 \ + -- set Interface t0 type=gre ofport_request=3 \ + options:local_ip=1.1.2.80 \ + options:remote_ip=1.1.2.90 +]) +AT_CHECK([ovs-vsctl \ + -- add-port int-br t1 \ + -- set Interface t1 type=gre ofport_request=4 \ + options:local_ip=1.1.2.81 \ + options:remote_ip=1.1.2.91 +]) + +AT_CHECK([ovs-appctl dpif/show], [0], [dnl +dummy@ovs-dummy: hit:0 missed:0 + br0: + br0 65534/100: (dummy-internal) + p0 1/1: (dummy) + br1: + br1 65534/101: (dummy-internal) + p1 2/2: (dummy) + int-br: + int-br 65534/3: (dummy-internal) + t0 3/4: (gre: local_ip=1.1.2.80, remote_ip=1.1.2.90) + t1 4/4: (gre: local_ip=1.1.2.81, remote_ip=1.1.2.91) +]) + +AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 1.1.2.80/24], [0], [OK +]) +AT_CHECK([ovs-appctl netdev-dummy/ip4addr br1 1.1.2.81/24], [0], [OK +]) +dnl Checking that a local route for added IP was successfully installed +dnl on br1 only. +AT_CHECK([ovs-appctl ovs/route/show | grep Cached], [0], [dnl +Cached: 1.1.2.80/32 dev br0 SRC 1.1.2.80 local +Cached: 1.1.2.81/32 dev br1 SRC 1.1.2.81 local +Cached: 1.1.2.0/24 dev br1 SRC 1.1.2.81 +]) + +AT_CHECK([ovs-ofctl add-flow br0 action=normal]) +AT_CHECK([ovs-ofctl add-flow br1 action=normal]) +AT_CHECK([ovs-ofctl add-flow int-br action=normal]) + +dnl Use arp reply to achieve tunnel next hop mac binding. +AT_CHECK([ovs-appctl netdev-dummy/receive p0 dnl + 'recirc_id(0),in_port(1),dnl + eth(src=f8:bc:12:44:34:b0,dst=aa:55:aa:55:00:00),eth_type(0x0806),dnl + arp(sip=1.1.2.90,tip=1.1.2.80,op=2,sha=f8:bc:12:44:34:b0,tha=00:00:00:00:00:00)' +]) +AT_CHECK([ovs-appctl netdev-dummy/receive p1 dnl + 'recirc_id(0),in_port(2),dnl + eth(src=f8:bc:12:44:34:b1,dst=aa:66:aa:66:00:00),eth_type(0x0806),dnl + arp(sip=1.1.2.91,tip=1.1.2.81,op=2,sha=f8:bc:12:44:34:b1,tha=00:00:00:00:00:00)' +]) + +AT_CHECK([ovs-appctl tnl/neigh/show | tail -n+3 | sort], [0], [dnl +1.1.2.90 f8:bc:12:44:34:b0 br0 +1.1.2.91 f8:bc:12:44:34:b1 br1 +]) + +AT_CHECK([ovs-appctl ovs/route/add 1.1.2.0/24 br0 src=1.1.2.80 table=10], [0], [OK +]) +AT_CHECK([ovs-appctl ovs/route/add 1.1.2.0/24 br1 src=1.1.2.81 table=11], [0], [OK +]) + +AT_CHECK([ovs-appctl ovs/route/show table=all | sort], [0], [dnl +Cached: 1.1.2.0/24 dev br1 SRC 1.1.2.81 +Cached: 1.1.2.80/32 dev br0 SRC 1.1.2.80 local +Cached: 1.1.2.81/32 dev br1 SRC 1.1.2.81 local +User: 1.1.2.0/24 dev br0 SRC 1.1.2.80 table 10 +User: 1.1.2.0/24 dev br1 SRC 1.1.2.81 table 11 +]) + +AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(int-br),dnl + eth(src=00:00:00:00:00:00,dst=f8:bc:12:44:34:b0),eth_type(0x0800),dnl + ipv4(src=1.1.3.100,dst=1.1.3.200,proto=1,tos=0,ttl=64,frag=no),dnl + icmp(type=8,code=0)' | grep 'tunneling to.*via'], [0], [dnl + -> tunneling to 1.1.2.90 via br1 + -> tunneling to 1.1.2.91 via br1 +]) + +AT_CHECK([ovs-appctl ovs/route/rule/add from=1.1.2.80/32 table=10], [0], [OK +]) +AT_CHECK([ovs-appctl ovs/route/rule/add from=1.1.2.81/32 table=11], [0], [OK +]) +AT_CHECK([ovs-appctl ovs/route/rule/show], [0], [dnl +Cached: 0: from all lookup local +User: 32764: from 1.1.2.81 lookup 11 +User: 32765: from 1.1.2.80 lookup 10 +Cached: 32766: from all lookup main +Cached: 32767: from all lookup default +]) + +AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(int-br),dnl + eth(src=00:00:00:00:00:00,dst=f8:bc:12:44:34:b0),eth_type(0x0800),dnl + ipv4(src=1.1.3.100,dst=1.1.3.200,proto=1,tos=0,ttl=64,frag=no),dnl + icmp(type=8,code=0)' | grep 'tunneling to.*via'], [0], [dnl + -> tunneling to 1.1.2.90 via br0 + -> tunneling to 1.1.2.91 via br1 +]) + +OVS_VSWITCHD_STOP +AT_CLEANUP -- 2.52.0 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
