2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-22 09:58:01 +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 * OVS now collects per-interface upcall statistics that can be obtained
via 'ovs-appctl dpctl/show -s' or the interface's statistics column via 'ovs-appctl dpctl/show -s' or the interface's statistics column
in OVSDB. Available with upstream kernel 6.2+. 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: - ovs-ctl:
* Added new options --[ovsdb-server|ovs-vswitchd]-umask=MODE to set umask * Added new options --[ovsdb-server|ovs-vswitchd]-umask=MODE to set umask
value when starting OVS daemons. E.g., use --ovsdb-server-umask=0002 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; 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 int
ovs_router_get_netdev_source_address(const struct in6_addr *ip6_dst, ovs_router_get_netdev_source_address(const struct in6_addr *ip6_dst,
const char output_bridge[], const char output_bridge[],
@ -217,8 +257,12 @@ static int
ovs_router_insert__(uint32_t mark, uint8_t priority, bool local, ovs_router_insert__(uint32_t mark, uint8_t priority, bool local,
const struct in6_addr *ip6_dst, const struct in6_addr *ip6_dst,
uint8_t plen, const char output_bridge[], 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; const struct cls_rule *cr;
struct ovs_router_entry *p; struct ovs_router_entry *p;
struct match match; struct match match;
@ -236,11 +280,17 @@ ovs_router_insert__(uint32_t mark, uint8_t priority, bool local,
p->plen = plen; p->plen = plen;
p->local = local; p->local = local;
p->priority = priority; 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)) { if (err && ipv6_addr_is_set(gw)) {
err = ovs_router_get_netdev_source_address(gw, output_bridge, err = get_src_addr(gw, output_bridge, &p->src_addr);
&p->src_addr);
} }
if (err) { if (err) {
struct ds ds = DS_EMPTY_INITIALIZER; 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) { if (use_system_routing_table) {
uint8_t priority = local ? plen + 64 : plen; 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, ovs_router_add(struct unixctl_conn *conn, int argc,
const char *argv[], void *aux OVS_UNUSED) const char *argv[], void *aux OVS_UNUSED)
{ {
struct in6_addr src6 = in6addr_any;
struct in6_addr gw6 = in6addr_any; struct in6_addr gw6 = in6addr_any;
char src6_s[IPV6_SCAN_LEN + 1];
struct in6_addr ip6; struct in6_addr ip6;
uint32_t mark = 0; uint32_t mark = 0;
unsigned int plen; unsigned int plen;
ovs_be32 src = 0;
ovs_be32 gw = 0; ovs_be32 gw = 0;
bool is_ipv6; bool is_ipv6;
ovs_be32 ip; ovs_be32 ip;
@ -370,24 +424,36 @@ ovs_router_add(struct unixctl_conn *conn, int argc,
} }
if (is_ipv6) { 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)) { if (ipv6_parse(argv[i], &gw6)) {
continue; continue;
} }
} else { } else {
if (ovs_scan(argv[i], "src="IP_SCAN_FMT, IP_SCAN_ARGS(&src))) {
continue;
}
if (ip_parse(argv[i], &gw)) { if (ip_parse(argv[i], &gw)) {
continue; 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; return;
} }
if (gw) { if (gw) {
in6_addr_set_mapped_ipv4(&gw6, 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) { if (err) {
unixctl_command_reply_error(conn, "Error while inserting route."); unixctl_command_reply_error(conn, "Error while inserting route.");
} else { } else {
@ -538,8 +604,8 @@ ovs_router_init(void)
classifier_init(&cls, NULL); classifier_init(&cls, NULL);
unixctl_command_register("ovs/route/add", unixctl_command_register("ovs/route/add",
"ip/plen output_bridge [gw] " "ip/plen output_bridge [gw] "
"[pkt_mark=mark]", "[pkt_mark=mark] [src=src_ip]",
2, 4, ovs_router_add, NULL); 2, 5, ovs_router_add, NULL);
unixctl_command_register("ovs/route/show", "", 0, 0, unixctl_command_register("ovs/route/show", "", 0, 0,
ovs_router_show, NULL); ovs_router_show, NULL);
unixctl_command_register("ovs/route/del", "ip/plen " unixctl_command_register("ovs/route/del", "ip/plen "

View File

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

View File

@ -20,7 +20,7 @@ Invalid 'ip/plen' parameter
ovs-appctl: ovs-vswitchd: server returned an error 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 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 ovs-appctl: ovs-vswitchd: server returned an error
]) ])
AT_CHECK([ovs-appctl ovs/route/show | grep User | sort], [0], [dnl 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 OVS_VSWITCHD_STOP
AT_CLEANUP 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_SETUP([appctl - route/lookup])
AT_KEYWORDS([ovs_router]) AT_KEYWORDS([ovs_router])
OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=dummy]) OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=dummy])