Message ID | 20230207064816.79821-2-nmiki@yahoo-corp.jp |
---|---|
State | Superseded |
Headers | show |
Series | Add support for preferred src address in ovs-router. | expand |
Context | Check | Description |
---|---|---|
ovsrobot/apply-robot | success | apply and check: success |
ovsrobot/github-robot-_Build_and_Test | success | github build: passed |
ovsrobot/intel-ovs-compilation | success | test: success |
On 7 Feb 2023, at 7:48, Nobuhiro MIKI wrote: > 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. Thanks for this patch! Can you also update the man pages for routes, i.e. ofproto-tnl-unixctl.man? See some more comments inline below. Cheers, Eelco > Signed-off-by: Nobuhiro MIKI <nmiki@yahoo-corp.jp> > --- > NEWS | 2 ++ > lib/ovs-router.c | 79 ++++++++++++++++++++++++++++++++++----------- > tests/ovs-router.at | 46 ++++++++++++++++++++++++++ > 3 files changed, 109 insertions(+), 18 deletions(-) > > diff --git a/NEWS b/NEWS > index fe6055a2700b..929437733e3d 100644 > --- a/NEWS > +++ b/NEWS > @@ -4,6 +4,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-appctl: > + * "ovs-appctl ovs/route/add" command can now support "src" option. * Add support for selecting the source address with the “ovs-appctl ovs/route/add" command. > > v3.1.0 - xx xxx xxxx > diff --git a/lib/ovs-router.c b/lib/ovs-router.c > index 5d0fbd503e9e..fc95a91012f9 100644 > --- a/lib/ovs-router.c > +++ b/lib/ovs-router.c > @@ -217,12 +217,13 @@ 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) > { > const struct cls_rule *cr; > struct ovs_router_entry *p; > struct match match; > - int err; > + int err = 0; > > rt_init_match(&match, mark, ip6_dst, plen); > > @@ -236,8 +237,14 @@ 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; We need some verification, as any IP is accepted now. See the test cases below. > + } else { > + err = ovs_router_get_netdev_source_address(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); > @@ -274,7 +281,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); > } > } > > @@ -342,6 +350,7 @@ ovs_router_add(struct unixctl_conn *conn, int argc, > const char *argv[], void *aux OVS_UNUSED) > { > struct in6_addr gw6 = in6addr_any; > + struct in6_addr src6 = in6addr_any; > struct in6_addr ip6; > uint32_t mark = 0; > unsigned int plen; > @@ -350,11 +359,27 @@ ovs_router_add(struct unixctl_conn *conn, int argc, > > if (scan_ipv4_route(argv[1], &ip, &plen)) { > ovs_be32 gw = 0; > + ovs_be32 src = 0; > > if (argc > 3) { > - if (!ovs_scan(argv[3], "pkt_mark=%"SCNi32, &mark) && > + if (!ovs_scan(argv[3], "src="IP_SCAN_FMT, IP_SCAN_ARGS(&src)) && > + !ovs_scan(argv[3], "pkt_mark=%"SCNi32, &mark) && > !ip_parse(argv[3], &gw)) { > - unixctl_command_reply_error(conn, "Invalid pkt_mark or gateway"); > + unixctl_command_reply_error( > + conn, "Invalid src, pkt_mark or gateway"); > + return; > + } > + } > + if (argc > 4) { > + if (!ovs_scan(argv[4], "src="IP_SCAN_FMT, IP_SCAN_ARGS(&src)) && > + !ovs_scan(argv[4], "pkt_mark=%"SCNi32, &mark)) { > + unixctl_command_reply_error(conn, "Invalid src or pkt_mark"); > + return; > + } > + } > + if (argc > 5) { > + if (!ovs_scan(argv[5], "src="IP_SCAN_FMT, IP_SCAN_ARGS(&src))) { > + unixctl_command_reply_error(conn, "Invalid src"); > return; > } > } > @@ -362,12 +387,35 @@ ovs_router_add(struct unixctl_conn *conn, int argc, > if (gw) { > in6_addr_set_mapped_ipv4(&gw6, gw); > } > + if (src) { > + in6_addr_set_mapped_ipv4(&src6, src); > + } > plen += 96; > } else if (scan_ipv6_route(argv[1], &ip6, &plen)) { > + char src6_s[IPV6_SCAN_LEN + 1]; > + > if (argc > 3) { > - if (!ovs_scan(argv[3], "pkt_mark=%"SCNi32, &mark) && > + if (!(ovs_scan(argv[3], "src="IPV6_SCAN_FMT, src6_s) && > + ipv6_parse(src6_s, &src6)) && > + !ovs_scan(argv[3], "pkt_mark=%"SCNi32, &mark) && > !ipv6_parse(argv[3], &gw6)) { > - unixctl_command_reply_error(conn, "Invalid pkt_mark or IPv6 gateway"); > + unixctl_command_reply_error( > + conn, "Invalid src, pkt_mark or IPv6 gateway"); > + return; > + } > + } > + if (argc > 4) { > + if (!(ovs_scan(argv[4], "src="IPV6_SCAN_FMT, src6_s) && > + ipv6_parse(src6_s, &src6)) && > + !ovs_scan(argv[4], "pkt_mark=%"SCNi32, &mark)) { > + unixctl_command_reply_error(conn, "Invalid src or pkt_mark"); > + return; > + } > + } > + if (argc > 5) { > + if (!(ovs_scan(argv[5], "src="IPV6_SCAN_FMT, src6_s) && > + ipv6_parse(src6_s, &src6))) { > + unixctl_command_reply_error(conn, "Invalid src"); > return; > } > } I think this function needs some proper refactoring, as it has become very messy. Guess we should first parse all arguments, and then do the verification. > @@ -375,14 +423,9 @@ ovs_router_add(struct unixctl_conn *conn, int argc, > unixctl_command_reply_error(conn, "Invalid parameters"); > return; > } > - if (argc > 4) { > - if (!ovs_scan(argv[4], "pkt_mark=%"SCNi32, &mark)) { > - unixctl_command_reply_error(conn, "Invalid pkt_mark"); > - return; > - } > - } > > - 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 { > @@ -533,8 +576,8 @@ ovs_router_init(void) > classifier_init(&cls, NULL); > unixctl_command_register("ovs/route/add", > "ip_addr/prefix_len out_br_name [gw] " > - "[pkt_mark=mark]", > - 2, 4, ovs_router_add, NULL); > + "[pkt_mark=mark] [src=src_ip_addr]", > + 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_addr/prefix_len " > diff --git a/tests/ovs-router.at b/tests/ovs-router.at > index 6dacc2954bc6..d4e39b4dd995 100644 > --- a/tests/ovs-router.at > +++ b/tests/ovs-router.at > @@ -12,6 +12,52 @@ AT_CHECK([ovs-appctl ovs/route/add 1.1.1.0/24 br0 2.2.2.10], [0], [OK > 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.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 > +]) I’ve added the below, and the test case is also passing (for this AT_CHECK). We might need to add a check, see the earlier comment. AT_CHECK([ovs-appctl ovs/route/add 192.168.10.14/32 br0 192.168.9.1 pkt_mark=14 src=192.168.9.20], [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 src or pkt_mark > +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: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 > +]) Do we need an invalid and unknown source IP added to this test case also? > +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]) > -- > 2.31.1 > > _______________________________________________ > dev mailing list > dev@openvswitch.org > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
On 2023/02/10 20:16, Eelco Chaudron wrote: > On 7 Feb 2023, at 7:48, Nobuhiro MIKI wrote: > >> 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. > > Thanks for this patch! Can you also update the man pages for routes, i.e. ofproto-tnl-unixctl.man? > > See some more comments inline below. > > Cheers, > > Eelco Hi, Thanks for your review. Sure. I'll update the ofproto-tnl-unixctl.man in the next patch. Best Regards, Nobuhiro MIKI >> + - ovs-appctl: >> + * "ovs-appctl ovs/route/add" command can now support "src" option. > > > * Add support for selecting the source address with the “ovs-appctl ovs/route/add" command. I'll fix it. >> @@ -236,8 +237,14 @@ 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; > > We need some verification, as any IP is accepted now. See the test cases below. I think src should be chosen from the IP addresses that the interface has. I'll add the validation. >> @@ -342,6 +350,7 @@ ovs_router_add(struct unixctl_conn *conn, int argc, >> const char *argv[], void *aux OVS_UNUSED) >> { >> struct in6_addr gw6 = in6addr_any; >> + struct in6_addr src6 = in6addr_any; >> struct in6_addr ip6; >> uint32_t mark = 0; >> unsigned int plen; >> @@ -350,11 +359,27 @@ ovs_router_add(struct unixctl_conn *conn, int argc, >> >> if (scan_ipv4_route(argv[1], &ip, &plen)) { >> ovs_be32 gw = 0; >> + ovs_be32 src = 0; >> >> if (argc > 3) { >> - if (!ovs_scan(argv[3], "pkt_mark=%"SCNi32, &mark) && >> + if (!ovs_scan(argv[3], "src="IP_SCAN_FMT, IP_SCAN_ARGS(&src)) && >> + !ovs_scan(argv[3], "pkt_mark=%"SCNi32, &mark) && >> !ip_parse(argv[3], &gw)) { >> - unixctl_command_reply_error(conn, "Invalid pkt_mark or gateway"); >> + unixctl_command_reply_error( >> + conn, "Invalid src, pkt_mark or gateway"); >> + return; >> + } >> + } >> + if (argc > 4) { >> + if (!ovs_scan(argv[4], "src="IP_SCAN_FMT, IP_SCAN_ARGS(&src)) && >> + !ovs_scan(argv[4], "pkt_mark=%"SCNi32, &mark)) { >> + unixctl_command_reply_error(conn, "Invalid src or pkt_mark"); >> + return; >> + } >> + } >> + if (argc > 5) { >> + if (!ovs_scan(argv[5], "src="IP_SCAN_FMT, IP_SCAN_ARGS(&src))) { >> + unixctl_command_reply_error(conn, "Invalid src"); >> return; >> } >> } >> @@ -362,12 +387,35 @@ ovs_router_add(struct unixctl_conn *conn, int argc, >> if (gw) { >> in6_addr_set_mapped_ipv4(&gw6, gw); >> } >> + if (src) { >> + in6_addr_set_mapped_ipv4(&src6, src); >> + } >> plen += 96; >> } else if (scan_ipv6_route(argv[1], &ip6, &plen)) { >> + char src6_s[IPV6_SCAN_LEN + 1]; >> + >> if (argc > 3) { >> - if (!ovs_scan(argv[3], "pkt_mark=%"SCNi32, &mark) && >> + if (!(ovs_scan(argv[3], "src="IPV6_SCAN_FMT, src6_s) && >> + ipv6_parse(src6_s, &src6)) && >> + !ovs_scan(argv[3], "pkt_mark=%"SCNi32, &mark) && >> !ipv6_parse(argv[3], &gw6)) { >> - unixctl_command_reply_error(conn, "Invalid pkt_mark or IPv6 gateway"); >> + unixctl_command_reply_error( >> + conn, "Invalid src, pkt_mark or IPv6 gateway"); >> + return; >> + } >> + } >> + if (argc > 4) { >> + if (!(ovs_scan(argv[4], "src="IPV6_SCAN_FMT, src6_s) && >> + ipv6_parse(src6_s, &src6)) && >> + !ovs_scan(argv[4], "pkt_mark=%"SCNi32, &mark)) { >> + unixctl_command_reply_error(conn, "Invalid src or pkt_mark"); >> + return; >> + } >> + } >> + if (argc > 5) { >> + if (!(ovs_scan(argv[5], "src="IPV6_SCAN_FMT, src6_s) && >> + ipv6_parse(src6_s, &src6))) { >> + unixctl_command_reply_error(conn, "Invalid src"); >> return; >> } >> } > > I think this function needs some proper refactoring, as it has become very messy. > Guess we should first parse all arguments, and then do the verification. OK. I will refactor the code. >> diff --git a/tests/ovs-router.at b/tests/ovs-router.at >> index 6dacc2954bc6..d4e39b4dd995 100644 >> --- a/tests/ovs-router.at >> +++ b/tests/ovs-router.at >> @@ -12,6 +12,52 @@ AT_CHECK([ovs-appctl ovs/route/add 1.1.1.0/24 br0 2.2.2.10], [0], [OK >> 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.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 >> +]) > > I’ve added the below, and the test case is also passing (for this AT_CHECK). > We might need to add a check, see the earlier comment. > > > AT_CHECK([ovs-appctl ovs/route/add 192.168.10.14/32 br0 192.168.9.1 pkt_mark=14 src=192.168.9.20], [0], [OK > ]) > I think the test case should fail because the src option is an IP address that is not assigned to br0. Thank you. I will add a validation. >> +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 src or pkt_mark >> +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: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 >> +]) > > Do we need an invalid and unknown source IP added to this test case also? > Yes, that test case is missing. Thank you.
diff --git a/NEWS b/NEWS index fe6055a2700b..929437733e3d 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,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-appctl: + * "ovs-appctl ovs/route/add" command can now support "src" option. v3.1.0 - xx xxx xxxx diff --git a/lib/ovs-router.c b/lib/ovs-router.c index 5d0fbd503e9e..fc95a91012f9 100644 --- a/lib/ovs-router.c +++ b/lib/ovs-router.c @@ -217,12 +217,13 @@ 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) { const struct cls_rule *cr; struct ovs_router_entry *p; struct match match; - int err; + int err = 0; rt_init_match(&match, mark, ip6_dst, plen); @@ -236,8 +237,14 @@ 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; + } else { + err = ovs_router_get_netdev_source_address(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); @@ -274,7 +281,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); } } @@ -342,6 +350,7 @@ ovs_router_add(struct unixctl_conn *conn, int argc, const char *argv[], void *aux OVS_UNUSED) { struct in6_addr gw6 = in6addr_any; + struct in6_addr src6 = in6addr_any; struct in6_addr ip6; uint32_t mark = 0; unsigned int plen; @@ -350,11 +359,27 @@ ovs_router_add(struct unixctl_conn *conn, int argc, if (scan_ipv4_route(argv[1], &ip, &plen)) { ovs_be32 gw = 0; + ovs_be32 src = 0; if (argc > 3) { - if (!ovs_scan(argv[3], "pkt_mark=%"SCNi32, &mark) && + if (!ovs_scan(argv[3], "src="IP_SCAN_FMT, IP_SCAN_ARGS(&src)) && + !ovs_scan(argv[3], "pkt_mark=%"SCNi32, &mark) && !ip_parse(argv[3], &gw)) { - unixctl_command_reply_error(conn, "Invalid pkt_mark or gateway"); + unixctl_command_reply_error( + conn, "Invalid src, pkt_mark or gateway"); + return; + } + } + if (argc > 4) { + if (!ovs_scan(argv[4], "src="IP_SCAN_FMT, IP_SCAN_ARGS(&src)) && + !ovs_scan(argv[4], "pkt_mark=%"SCNi32, &mark)) { + unixctl_command_reply_error(conn, "Invalid src or pkt_mark"); + return; + } + } + if (argc > 5) { + if (!ovs_scan(argv[5], "src="IP_SCAN_FMT, IP_SCAN_ARGS(&src))) { + unixctl_command_reply_error(conn, "Invalid src"); return; } } @@ -362,12 +387,35 @@ ovs_router_add(struct unixctl_conn *conn, int argc, if (gw) { in6_addr_set_mapped_ipv4(&gw6, gw); } + if (src) { + in6_addr_set_mapped_ipv4(&src6, src); + } plen += 96; } else if (scan_ipv6_route(argv[1], &ip6, &plen)) { + char src6_s[IPV6_SCAN_LEN + 1]; + if (argc > 3) { - if (!ovs_scan(argv[3], "pkt_mark=%"SCNi32, &mark) && + if (!(ovs_scan(argv[3], "src="IPV6_SCAN_FMT, src6_s) && + ipv6_parse(src6_s, &src6)) && + !ovs_scan(argv[3], "pkt_mark=%"SCNi32, &mark) && !ipv6_parse(argv[3], &gw6)) { - unixctl_command_reply_error(conn, "Invalid pkt_mark or IPv6 gateway"); + unixctl_command_reply_error( + conn, "Invalid src, pkt_mark or IPv6 gateway"); + return; + } + } + if (argc > 4) { + if (!(ovs_scan(argv[4], "src="IPV6_SCAN_FMT, src6_s) && + ipv6_parse(src6_s, &src6)) && + !ovs_scan(argv[4], "pkt_mark=%"SCNi32, &mark)) { + unixctl_command_reply_error(conn, "Invalid src or pkt_mark"); + return; + } + } + if (argc > 5) { + if (!(ovs_scan(argv[5], "src="IPV6_SCAN_FMT, src6_s) && + ipv6_parse(src6_s, &src6))) { + unixctl_command_reply_error(conn, "Invalid src"); return; } } @@ -375,14 +423,9 @@ ovs_router_add(struct unixctl_conn *conn, int argc, unixctl_command_reply_error(conn, "Invalid parameters"); return; } - if (argc > 4) { - if (!ovs_scan(argv[4], "pkt_mark=%"SCNi32, &mark)) { - unixctl_command_reply_error(conn, "Invalid pkt_mark"); - return; - } - } - 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 { @@ -533,8 +576,8 @@ ovs_router_init(void) classifier_init(&cls, NULL); unixctl_command_register("ovs/route/add", "ip_addr/prefix_len out_br_name [gw] " - "[pkt_mark=mark]", - 2, 4, ovs_router_add, NULL); + "[pkt_mark=mark] [src=src_ip_addr]", + 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_addr/prefix_len " diff --git a/tests/ovs-router.at b/tests/ovs-router.at index 6dacc2954bc6..d4e39b4dd995 100644 --- a/tests/ovs-router.at +++ b/tests/ovs-router.at @@ -12,6 +12,52 @@ AT_CHECK([ovs-appctl ovs/route/add 1.1.1.0/24 br0 2.2.2.10], [0], [OK 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.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 src or pkt_mark +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: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/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])
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. Signed-off-by: Nobuhiro MIKI <nmiki@yahoo-corp.jp> --- NEWS | 2 ++ lib/ovs-router.c | 79 ++++++++++++++++++++++++++++++++++----------- tests/ovs-router.at | 46 ++++++++++++++++++++++++++ 3 files changed, 109 insertions(+), 18 deletions(-)