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:
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
|
* 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
|
||||||
|
@ -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 "
|
||||||
|
@ -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.
|
||||||
.
|
.
|
||||||
|
@ -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])
|
||||||
|
Loading…
x
Reference in New Issue
Block a user