summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS2
-rw-r--r--lib/ovs-router.c6
-rw-r--r--lib/ovs-router.h3
-rw-r--r--lib/route-table.c16
-rw-r--r--tests/system-route.at39
5 files changed, 61 insertions, 5 deletions
diff --git a/NEWS b/NEWS
index 3fe30bbf6..72b9024e6 100644
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,8 @@ Post-v3.1.0
* OVS now collects per-interface upcall statistics that can be obtained
via 'ovs-appctl dpctl/show -s' or the interface's statistics column
in OVSDB. Available with upstream kernel 6.2+.
+ - OVS route table in userspace now takes into account preferred source
+ address from cached kernel routes.
- ovs-appctl:
* Add support for selecting the source address with the
'ovs-appctl ovs/route/add' command.
diff --git a/lib/ovs-router.c b/lib/ovs-router.c
index 3107f2d56..7c04bb0e6 100644
--- a/lib/ovs-router.c
+++ b/lib/ovs-router.c
@@ -319,13 +319,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_bridge[],
- const struct in6_addr *gw)
+ bool local, const char output_bridge[],
+ 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,
- output_bridge, gw, &in6addr_any);
+ output_bridge, gw, prefsrc);
}
}
diff --git a/lib/ovs-router.h b/lib/ovs-router.h
index d8ce3c00d..eb4ff85d9 100644
--- a/lib/ovs-router.h
+++ b/lib/ovs-router.h
@@ -32,7 +32,8 @@ bool ovs_router_lookup(uint32_t mark, const struct in6_addr *ip_dst,
void ovs_router_init(void);
void ovs_router_insert(uint32_t mark, const struct in6_addr *ip_dst,
uint8_t plen, bool local,
- const char output_bridge[], const struct in6_addr *gw);
+ const char output_bridge[], const struct in6_addr *gw,
+ const struct in6_addr *prefsrc);
void ovs_router_flush(void);
void ovs_router_disable_system_routing_table(void);
diff --git a/lib/route-table.c b/lib/route-table.c
index ac82cf262..9927dcc18 100644
--- a/lib/route-table.c
+++ b/lib/route-table.c
@@ -51,6 +51,7 @@ 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;
@@ -201,6 +202,7 @@ route_table_parse(struct ofpbuf *buf, struct route_table_msg *change)
[RTA_OIF] = { .type = NL_A_U32, .optional = true },
[RTA_GATEWAY] = { .type = NL_A_U32, .optional = true },
[RTA_MARK] = { .type = NL_A_U32, .optional = true },
+ [RTA_PREFSRC] = { .type = NL_A_U32, .optional = true },
};
static const struct nl_policy policy6[] = {
@@ -208,6 +210,7 @@ route_table_parse(struct ofpbuf *buf, struct route_table_msg *change)
[RTA_OIF] = { .type = NL_A_U32, .optional = true },
[RTA_MARK] = { .type = NL_A_U32, .optional = true },
[RTA_GATEWAY] = { .type = NL_A_IPV6, .optional = true },
+ [RTA_PREFSRC] = { .type = NL_A_IPV6, .optional = true },
};
struct nlattr *attrs[ARRAY_SIZE(policy)];
@@ -274,6 +277,16 @@ route_table_parse(struct ofpbuf *buf, struct route_table_msg *change)
} else if (ipv4) {
in6_addr_set_mapped_ipv4(&change->rd.rta_dst, 0);
}
+ if (attrs[RTA_PREFSRC]) {
+ if (ipv4) {
+ ovs_be32 prefsrc;
+ prefsrc = nl_attr_get_be32(attrs[RTA_PREFSRC]);
+ in6_addr_set_mapped_ipv4(&change->rd.rta_prefsrc, prefsrc);
+ } else {
+ change->rd.rta_prefsrc =
+ nl_attr_get_in6_addr(attrs[RTA_PREFSRC]);
+ }
+ }
if (attrs[RTA_GATEWAY]) {
if (ipv4) {
ovs_be32 gw;
@@ -309,7 +322,8 @@ route_table_handle_msg(const struct route_table_msg *change)
const struct route_data *rd = &change->rd;
ovs_router_insert(rd->mark, &rd->rta_dst, rd->rtm_dst_len,
- rd->local, rd->ifname, &rd->rta_gw);
+ rd->local, rd->ifname, &rd->rta_gw,
+ &rd->rta_prefsrc);
}
}
diff --git a/tests/system-route.at b/tests/system-route.at
index 270956d13..114aaebc7 100644
--- a/tests/system-route.at
+++ b/tests/system-route.at
@@ -25,3 +25,42 @@ OVS_WAIT_UNTIL([test `ovs-appctl ovs/route/show | grep -c 'p1-route'` -eq 0 ])
OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP
+
+AT_SETUP([ovs-route - add system route with src - ipv4])
+AT_KEYWORDS([route])
+OVS_TRAFFIC_VSWITCHD_START()
+AT_CHECK([ip link set br0 up])
+
+AT_CHECK([ip addr add 192.168.9.2/24 dev br0], [0], [stdout])
+AT_CHECK([ip addr add 192.168.9.3/24 dev br0], [0], [stdout])
+
+AT_CHECK([ip route add 192.168.10.12/32 dev br0 via 192.168.9.1 src 192.168.9.2], [0], [stdout])
+AT_CHECK([ip route add 192.168.10.13/32 dev br0 via 192.168.9.1 src 192.168.9.3], [0], [stdout])
+
+OVS_WAIT_UNTIL_EQUAL([ovs-appctl ovs/route/show | grep -E '192.168.10.1[[23]]/32' | sort], [dnl
+Cached: 192.168.10.12/32 dev br0 GW 192.168.9.1 SRC 192.168.9.2
+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 src - ipv6])
+AT_KEYWORDS([route])
+OVS_TRAFFIC_VSWITCHD_START()
+AT_CHECK([ip link set br0 up])
+
+AT_CHECK([ip -6 addr add fc00:db8:cafe::2/64 dev br0], [0], [stdout])
+AT_CHECK([ip -6 addr add fc00:db8:cafe::3/64 dev br0], [0], [stdout])
+
+dnl If we try to add a route immediately after assigning ipv6 addresses,
+dnl iproute2 would give us "Invalid source address" error,
+dnl so wait a while to succeed.
+OVS_WAIT_UNTIL([ip -6 route add fc00:db8:beef::12/128 via fc00:db8:cafe::1 dev br0 src fc00:db8:cafe::3])
+OVS_WAIT_UNTIL([ip -6 route add fc00:db8:beef::13/128 via fc00:db8:cafe::1 dev br0 src fc00:db8:cafe::2])
+
+OVS_WAIT_UNTIL_EQUAL([ovs-appctl ovs/route/show | grep -E 'fc00:db8:beef::1[[23]]/128' | sort], [dnl
+Cached: fc00:db8:beef::12/128 dev br0 GW fc00:db8:cafe::1 SRC fc00:db8:cafe::3
+Cached: fc00:db8:beef::13/128 dev br0 GW fc00:db8:cafe::1 SRC fc00:db8:cafe::2])
+
+OVS_TRAFFIC_VSWITCHD_STOP
+AT_CLEANUP