The source address parameter in ovs_router_lookup is both an input and
an output. However, the interface was complex. The caller could
inadvertently set a search over v4 or v6 rules based on if the source
address was initialized to in6addr_any or in6addr_v4mapped_any. The
lookup function even used these two values interchangeably.
This patch uses dst address to determine if the lookup is v4 or v6, and
considers both v6_any and v4mapped_any to be the null value equally. Now
if the caller just wants src as output, they can initialize it to v6_any
and lookup will still work correctly.
Fixes: dc14e92bcc25 ("route-table: Introduce multi-table route lookup.")
Signed-off-by: Mike Pattrick <[email protected]>
---
lib/ovs-router.c | 47 ++++++++++++++++++++++++---------------------
lib/packets.h | 5 +++++
tests/ovs-router.at | 26 +++++++++++++++++++++++++
3 files changed, 56 insertions(+), 22 deletions(-)
diff --git a/lib/ovs-router.c b/lib/ovs-router.c
index c11a52764..3ac421915 100644
--- a/lib/ovs-router.c
+++ b/lib/ovs-router.c
@@ -175,28 +175,31 @@ ovs_router_lookup(uint32_t mark, const struct in6_addr
*ip6_dst,
struct in6_addr *src, struct in6_addr *gw)
{
struct flow flow = {.ipv6_dst = *ip6_dst, .pkt_mark = mark};
+ bool is_ipv4 = IN6_IS_ADDR_V4MAPPED(ip6_dst);
const struct in6_addr *from_src = src;
const struct cls_rule *cr = NULL;
struct router_rule *rule;
+ bool is_any = true;
- if (src && ipv6_addr_is_set(src)) {
- struct flow flow_src = {.ipv6_dst = *src, .pkt_mark = mark};
- struct classifier *cls_local = cls_find(CLS_LOCAL);
- const struct cls_rule *cr_src;
+ if (src) {
+ if (ipv4_addr_is_set(src) || ipv6_addr_is_set(src)) {
+ struct flow flow_src = {.ipv6_dst = *src, .pkt_mark = mark};
+ struct classifier *cls_local = cls_find(CLS_LOCAL);
+ const struct cls_rule *cr_src;
- if (!cls_local) {
- return false;
- }
+ if (!cls_local) {
+ return false;
+ }
- cr_src = classifier_lookup(cls_local, OVS_VERSION_MAX, &flow_src,
- NULL, NULL);
- if (!cr_src) {
- return false;
+ cr_src = classifier_lookup(cls_local, OVS_VERSION_MAX, &flow_src,
+ NULL, NULL);
+ if (!cr_src) {
+ return false;
+ }
+ is_any = false;
}
- }
-
- if (!from_src) {
- if (IN6_IS_ADDR_V4MAPPED(ip6_dst)) {
+ } else {
+ if (is_ipv4) {
from_src = &in6addr_v4mapped_any;
} else {
from_src = &in6addr_any;
@@ -207,8 +210,7 @@ ovs_router_lookup(uint32_t mark, const struct in6_addr
*ip6_dst,
uint8_t plen = rule->ipv4 ? rule->src_prefix + 96 : rule->src_prefix;
bool matched;
- if ((IN6_IS_ADDR_V4MAPPED(from_src) && !rule->ipv4) ||
- (!IN6_IS_ADDR_V4MAPPED(from_src) && rule->ipv4)) {
+ if (is_ipv4 != rule->ipv4) {
continue;
}
@@ -231,12 +233,13 @@ ovs_router_lookup(uint32_t mark, const struct in6_addr
*ip6_dst,
if (cr) {
struct ovs_router_entry *p = ovs_router_entry_cast(cr);
/* Avoid matching mapped IPv4 of a packet against default IPv6
- * route entry. Either packet dst is IPv6 or both packet and
- * route entry dst are mapped IPv4.
+ * route entry. IPv6 status of the packet dst and route dst
+ * must be the same.
*/
- if (!IN6_IS_ADDR_V4MAPPED(ip6_dst) ||
- IN6_IS_ADDR_V4MAPPED(&p->nw_addr)) {
+ if (is_ipv4 == IN6_IS_ADDR_V4MAPPED(&p->nw_addr)) {
break;
+ } else {
+ cr = NULL;
}
}
}
@@ -247,7 +250,7 @@ ovs_router_lookup(uint32_t mark, const struct in6_addr
*ip6_dst,
ovs_strlcpy(output_netdev, p->output_netdev, IFNAMSIZ);
*gw = p->gw;
- if (src && !ipv6_addr_is_set(src)) {
+ if (src && is_any) {
*src = p->src_addr;
}
return true;
diff --git a/lib/packets.h b/lib/packets.h
index 61666f3ad..7e2e6be72 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -1202,6 +1202,11 @@ static inline bool ipv6_is_all_hosts(const struct
in6_addr *addr) {
return ipv6_addr_equals(addr, &in6addr_all_hosts);
}
+static inline bool ipv4_addr_is_set(const struct in6_addr *addr) {
+ return IN6_IS_ADDR_V4MAPPED(addr) &&
+ !ipv6_addr_equals(addr, &in6addr_v4mapped_any);
+}
+
static inline bool ipv6_addr_is_set(const struct in6_addr *addr) {
return !ipv6_addr_equals(addr, &in6addr_any);
}
diff --git a/tests/ovs-router.at b/tests/ovs-router.at
index b5282fd19..258ff5c80 100644
--- a/tests/ovs-router.at
+++ b/tests/ovs-router.at
@@ -315,6 +315,32 @@ 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/rule/add from=all table=15], [0], [dnl
+OK
+])
+AT_CHECK([ovs-appctl ovs/route/add 2.2.2.3/32 br0 192.0.2.1 table=15], [0],
[dnl
+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: 2.2.2.3/32 dev br0 GW 192.0.2.1 SRC 192.0.2.1 table 15
+])
+
+AT_CHECK([ovs-appctl ovs/route/lookup 2.2.2.3], [0], [dnl
+src 192.0.2.1
+gateway 192.0.2.1
+dev br0
+])
+
+AT_CHECK([ovs-appctl ovs/route/del 2.2.2.3/32 table=15], [0], [dnl
+OK
+])
+AT_CHECK([ovs-appctl ovs/route/rule/del from=all table=15], [0], [dnl
+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
--
2.52.0
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev