2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-22 09:58:01 +00:00

route-table: Retrieving the preferred source address from Netlink.

We can use the "ip route add ... src ..." command to set the preferred
source address for each entry in the kernel FIB. OVS has a mechanism to
cache the FIB, but the preferred source address is ignored and
calculated with its own logic. This patch resolves the difference
between kernel FIB and OVS route table cache by retrieving the
RTA_PREFSRC attribute of Netlink messages.

Acked-by: Eelco Chaudron <echaudro@redhat.com>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: Nobuhiro MIKI <nmiki@yahoo-corp.jp>
Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
This commit is contained in:
Nobuhiro MIKI 2023-03-06 11:49:19 +09:00 committed by Ilya Maximets
parent b801f1aa00
commit 49e534cd37
5 changed files with 61 additions and 5 deletions

2
NEWS
View File

@ -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.

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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