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

ovs-router: Introduce src option in ovs/route/add command.

When adding a route with ovs/route/add command, the source address
in "ovs_router_entry" structure is always the FIRST address that the
interface has. See "ovs_router_get_netdev_source_address"
function for more information.

If an interface has multiple ipv4 and/or ipv6 addresses, there are use
cases where the user wants to control the source address. This patch
therefore addresses this issue by adding a src parameter.

Note that same constraints also exist when caching routes from
Kernel FIB with Netlink, but are not dealt with in this patch.

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:18 +09:00 committed by Ilya Maximets
parent 01acf09f74
commit b801f1aa00
4 changed files with 161 additions and 13 deletions

3
NEWS
View File

@ -6,6 +6,9 @@ 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-appctl:
* Add support for selecting the source address with the
'ovs-appctl ovs/route/add' command.
- ovs-ctl:
* Added new options --[ovsdb-server|ovs-vswitchd]-umask=MODE to set umask
value when starting OVS daemons. E.g., use --ovsdb-server-umask=0002

View File

@ -164,6 +164,46 @@ static void rt_init_match(struct match *match, uint32_t mark,
match->flow.pkt_mark = mark;
}
static int
verify_prefsrc(const struct in6_addr *ip6_dst,
const char output_bridge[],
struct in6_addr *prefsrc)
{
struct in6_addr *mask, *addr6;
struct netdev *dev;
int err, n_in6, i;
err = netdev_open(output_bridge, NULL, &dev);
if (err) {
return err;
}
err = netdev_get_addr_list(dev, &addr6, &mask, &n_in6);
if (err) {
goto out;
}
for (i = 0; i < n_in6; i++) {
struct in6_addr a1, a2;
a1 = ipv6_addr_bitand(ip6_dst, &mask[i]);
a2 = ipv6_addr_bitand(prefsrc, &mask[i]);
/* Check that the interface has "prefsrc" and
* it is same broadcast domain with "ip6_dst". */
if (IN6_ARE_ADDR_EQUAL(prefsrc, &addr6[i]) &&
IN6_ARE_ADDR_EQUAL(&a1, &a2)) {
goto out;
}
}
err = ENOENT;
out:
free(addr6);
free(mask);
netdev_close(dev);
return err;
}
int
ovs_router_get_netdev_source_address(const struct in6_addr *ip6_dst,
const char output_bridge[],
@ -217,8 +257,12 @@ static int
ovs_router_insert__(uint32_t mark, uint8_t priority, bool local,
const struct in6_addr *ip6_dst,
uint8_t plen, const char output_bridge[],
const struct in6_addr *gw)
const struct in6_addr *gw,
const struct in6_addr *ip6_src)
{
int (*get_src_addr)(const struct in6_addr *ip6_dst,
const char output_bridge[],
struct in6_addr *prefsrc);
const struct cls_rule *cr;
struct ovs_router_entry *p;
struct match match;
@ -236,11 +280,17 @@ ovs_router_insert__(uint32_t mark, uint8_t priority, bool local,
p->plen = plen;
p->local = local;
p->priority = priority;
err = ovs_router_get_netdev_source_address(ip6_dst, output_bridge,
&p->src_addr);
if (ipv6_addr_is_set(ip6_src)) {
p->src_addr = *ip6_src;
get_src_addr = verify_prefsrc;
} else {
get_src_addr = ovs_router_get_netdev_source_address;
}
err = get_src_addr(ip6_dst, output_bridge, &p->src_addr);
if (err && ipv6_addr_is_set(gw)) {
err = ovs_router_get_netdev_source_address(gw, output_bridge,
&p->src_addr);
err = get_src_addr(gw, output_bridge, &p->src_addr);
}
if (err) {
struct ds ds = DS_EMPTY_INITIALIZER;
@ -274,7 +324,8 @@ ovs_router_insert(uint32_t mark, const struct in6_addr *ip_dst, uint8_t plen,
{
if (use_system_routing_table) {
uint8_t priority = local ? plen + 64 : plen;
ovs_router_insert__(mark, priority, local, ip_dst, plen, output_bridge, gw);
ovs_router_insert__(mark, priority, local, ip_dst, plen,
output_bridge, gw, &in6addr_any);
}
}
@ -341,10 +392,13 @@ static void
ovs_router_add(struct unixctl_conn *conn, int argc,
const char *argv[], void *aux OVS_UNUSED)
{
struct in6_addr src6 = in6addr_any;
struct in6_addr gw6 = in6addr_any;
char src6_s[IPV6_SCAN_LEN + 1];
struct in6_addr ip6;
uint32_t mark = 0;
unsigned int plen;
ovs_be32 src = 0;
ovs_be32 gw = 0;
bool is_ipv6;
ovs_be32 ip;
@ -370,24 +424,36 @@ ovs_router_add(struct unixctl_conn *conn, int argc,
}
if (is_ipv6) {
if (ovs_scan(argv[i], "src="IPV6_SCAN_FMT, src6_s) &&
ipv6_parse(src6_s, &src6)) {
continue;
}
if (ipv6_parse(argv[i], &gw6)) {
continue;
}
} else {
if (ovs_scan(argv[i], "src="IP_SCAN_FMT, IP_SCAN_ARGS(&src))) {
continue;
}
if (ip_parse(argv[i], &gw)) {
continue;
}
}
unixctl_command_reply_error(conn, "Invalid pkt_mark or IP gateway");
unixctl_command_reply_error(conn,
"Invalid pkt_mark, IP gateway or src_ip");
return;
}
if (gw) {
in6_addr_set_mapped_ipv4(&gw6, gw);
}
if (src) {
in6_addr_set_mapped_ipv4(&src6, src);
}
err = ovs_router_insert__(mark, plen + 32, false, &ip6, plen, argv[2], &gw6);
err = ovs_router_insert__(mark, plen + 32, false, &ip6, plen, argv[2],
&gw6, &src6);
if (err) {
unixctl_command_reply_error(conn, "Error while inserting route.");
} else {
@ -538,8 +604,8 @@ ovs_router_init(void)
classifier_init(&cls, NULL);
unixctl_command_register("ovs/route/add",
"ip/plen output_bridge [gw] "
"[pkt_mark=mark]",
2, 4, ovs_router_add, NULL);
"[pkt_mark=mark] [src=src_ip]",
2, 5, ovs_router_add, NULL);
unixctl_command_register("ovs/route/show", "", 0, 0,
ovs_router_show, NULL);
unixctl_command_register("ovs/route/del", "ip/plen "

View File

@ -1,8 +1,9 @@
.SS "OPENVSWITCH TUNNELING COMMANDS"
These commands query and modify OVS tunnel components.
.
.IP "\fBovs/route/add ip/plen output_bridge [gw] [pkt_mark=mark]\fR"
Adds ip/plen route to vswitchd routing table. output_bridge
.IP "\fBovs/route/add \fIip\fB/\fIplen\fB \fIoutput_bridge\fB \
[\fIgw\fB] [pkt_mark=\fImark\fB] [src=\fIsrc_ip\fB]\fR"
Adds \fIip\fR/\fIplen\fR route to vswitchd routing table. \fIoutput_bridge\fR
needs to be OVS bridge name. This command is useful if OVS cached
routes does not look right.
.

View File

@ -20,7 +20,7 @@ Invalid 'ip/plen' parameter
ovs-appctl: ovs-vswitchd: server returned an error
])
AT_CHECK([ovs-appctl ovs/route/add 2.2.2.4/24 br0 pkt_mark=baz], [2], [], [dnl
Invalid pkt_mark or IP gateway
Invalid pkt_mark, IP gateway or src_ip
ovs-appctl: ovs-vswitchd: server returned an error
])
AT_CHECK([ovs-appctl ovs/route/show | grep User | sort], [0], [dnl
@ -31,6 +31,84 @@ User: 2.2.2.3/32 MARK 1 dev br0 SRC 2.2.2.2
OVS_VSWITCHD_STOP
AT_CLEANUP
AT_SETUP([appctl - route/add with src - ipv4])
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.168.9.2/24], [0], [OK
])
AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 192.168.9.3/24], [0], [OK
])
AT_CHECK([ovs-appctl ovs/route/add 192.168.9.11/32 br0 src=192.168.9.3], [0], [OK
])
AT_CHECK([ovs-appctl ovs/route/add 192.168.10.12/32 br0 192.168.9.1 src=192.168.9.3], [0], [OK
])
AT_CHECK([ovs-appctl ovs/route/add 192.168.10.13/32 br0 192.168.9.1 pkt_mark=13 src=192.168.9.3], [0], [OK
])
AT_CHECK([ovs-appctl ovs/route/add 192.168.10.14/32 br0 192.168.9.1 pkt_mark=14 src=192.168.9.2], [0], [OK
])
AT_CHECK([ovs-appctl ovs/route/add 192.168.10.15/32 br0 192.168.9.1 src=foo.bar.9.200], [2], [], [dnl
Invalid pkt_mark, IP gateway or src_ip
ovs-appctl: ovs-vswitchd: server returned an error
])
AT_CHECK([ovs-appctl ovs/route/add 192.168.10.16/32 br0 192.168.9.1 src=192.168.9.200], [2], [], [dnl
Error while inserting route.
ovs-appctl: ovs-vswitchd: server returned an error
])
AT_CHECK([ovs-appctl ovs/route/add 192.168.10.17/32 br0 192.168.11.1 src=192.168.9.3], [2], [], [dnl
Error while inserting route.
ovs-appctl: ovs-vswitchd: server returned an error
])
AT_CHECK([ovs-appctl ovs/route/add 192.168.10.18/32 br0 src=192.168.9.3], [2], [], [dnl
Error while inserting route.
ovs-appctl: ovs-vswitchd: server returned an error
])
AT_CHECK([ovs-appctl ovs/route/show | grep User | grep 192.168.10 | sort], [0], [dnl
User: 192.168.10.12/32 dev br0 GW 192.168.9.1 SRC 192.168.9.3
User: 192.168.10.13/32 MARK 13 dev br0 GW 192.168.9.1 SRC 192.168.9.3
User: 192.168.10.14/32 MARK 14 dev br0 GW 192.168.9.1 SRC 192.168.9.2
])
OVS_VSWITCHD_STOP
AT_CLEANUP
AT_SETUP([appctl - route/add with src - ipv6])
AT_KEYWORDS([ovs_router])
OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=dummy])
AT_CHECK([ovs-appctl netdev-dummy/ip6addr br0 2001:db8:cafe::2/64], [0], [OK
])
AT_CHECK([ovs-appctl netdev-dummy/ip6addr br0 2001:db8:cafe::3/64], [0], [OK
])
AT_CHECK([ovs-appctl ovs/route/add 2001:db8:cafe::11/128 br0 src=2001:db8:cafe::3], [0], [OK
])
AT_CHECK([ovs-appctl ovs/route/add 2001:db8:beef::12/128 br0 2001:db8:cafe::1 src=2001:db8:cafe::3], [0], [OK
])
AT_CHECK([ovs-appctl ovs/route/add 2001:db8:beef::13/128 br0 2001:db8:cafe::1 pkt_mark=13 src=2001:db8:cafe::3], [0], [OK
])
AT_CHECK([ovs-appctl ovs/route/add 2001:db8:beef::14/128 br0 2001:db8:cafe::1 pkt_mark=14 src=2001:db8:cafe::2], [0], [OK
])
AT_CHECK([ovs-appctl ovs/route/add 2001:db8:beef::15/128 br0 2001:db8:cafe::1 src=foo:bar:2001:db8:cafe], [2], [], [dnl
Invalid pkt_mark, IP gateway or src_ip
ovs-appctl: ovs-vswitchd: server returned an error
])
AT_CHECK([ovs-appctl ovs/route/add 2001:db8:beef::16/128 br0 2001:db8:cafe::1 src=2001:db8:cafe::200], [2], [], [dnl
Error while inserting route.
ovs-appctl: ovs-vswitchd: server returned an error
])
AT_CHECK([ovs-appctl ovs/route/add 2001:db8:beef::17/128 br0 2001:db8:face::1 src=2001:db8:cafe::3], [2], [], [dnl
Error while inserting route.
ovs-appctl: ovs-vswitchd: server returned an error
])
AT_CHECK([ovs-appctl ovs/route/add 2001:db8:beef::18/128 br0 src=2001:db8:cafe::3], [2], [], [dnl
Error while inserting route.
ovs-appctl: ovs-vswitchd: server returned an error
])
AT_CHECK([ovs-appctl ovs/route/show | grep User | grep 2001:db8:beef | sort], [0], [dnl
User: 2001:db8:beef::12/128 dev br0 GW 2001:db8:cafe::1 SRC 2001:db8:cafe::3
User: 2001:db8:beef::13/128 MARK 13 dev br0 GW 2001:db8:cafe::1 SRC 2001:db8:cafe::3
User: 2001:db8:beef::14/128 MARK 14 dev br0 GW 2001:db8:cafe::1 SRC 2001:db8:cafe::2
])
OVS_VSWITCHD_STOP
AT_CLEANUP
AT_SETUP([appctl - route/lookup])
AT_KEYWORDS([ovs_router])
OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=dummy])