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:
parent
01acf09f74
commit
b801f1aa00
3
NEWS
3
NEWS
@ -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
|
||||
|
@ -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 "
|
||||
|
@ -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.
|
||||
.
|
||||
|
@ -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])
|
||||
|
Loading…
x
Reference in New Issue
Block a user