@@ -184,6 +184,10 @@ verify_prefsrc(const struct in6_addr *ip6_dst,
goto out;
}
+ /* Skip the check if not the same address family */
+ if (!IN6_IS_ADDR_V4MAPPED(ip6_dst) && IN6_IS_ADDR_V4MAPPED(prefsrc))
+ goto out;
+
for (i = 0; i < n_in6; i++) {
struct in6_addr a1, a2;
a1 = ipv6_addr_bitand(ip6_dst, &mask[i]);
@@ -415,7 +419,6 @@ ovs_router_add(struct unixctl_conn *conn, int argc,
unsigned int plen;
ovs_be32 src = 0;
ovs_be32 gw = 0;
- bool is_ipv6;
ovs_be32 ip;
int err;
int i;
@@ -423,9 +426,8 @@ ovs_router_add(struct unixctl_conn *conn, int argc,
if (scan_ipv4_route(argv[1], &ip, &plen)) {
in6_addr_set_mapped_ipv4(&ip6, ip);
plen += 96;
- is_ipv6 = false;
} else if (scan_ipv6_route(argv[1], &ip6, &plen)) {
- is_ipv6 = true;
+ ;
} else {
unixctl_command_reply_error(conn,
"Invalid 'ip/plen' parameter");
@@ -438,21 +440,21 @@ ovs_router_add(struct unixctl_conn *conn, int argc,
continue;
}
- 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;
- }
+ if (ovs_scan(argv[i], "src="IPV6_SCAN_FMT, src6_s) &&
+ ipv6_parse(src6_s, &src6)) {
+ continue;
+ }
+
+ if (ipv6_parse(argv[i], &gw6)) {
+ continue;
+ }
+
+ 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,
@@ -232,6 +232,7 @@ route_table_parse(struct ofpbuf *buf, struct route_table_msg *change)
[RTA_OIF] = { .type = NL_A_U32, .optional = true },
[RTA_GATEWAY] = { .type = NL_A_U32, .optional = true },
[RTA_MARK] = { .type = NL_A_U32, .optional = true },
+ [RTA_VIA] = { .type = NL_A_UNSPEC, .optional = true },
[RTA_PREFSRC] = { .type = NL_A_U32, .optional = true },
[RTA_TABLE] = { .type = NL_A_U32, .optional = true },
};
@@ -241,6 +242,7 @@ route_table_parse(struct ofpbuf *buf, struct route_table_msg *change)
[RTA_OIF] = { .type = NL_A_U32, .optional = true },
[RTA_MARK] = { .type = NL_A_U32, .optional = true },
[RTA_GATEWAY] = { .type = NL_A_IPV6, .optional = true },
+ [RTA_VIA] = { .type = NL_A_UNSPEC, .optional = true },
[RTA_PREFSRC] = { .type = NL_A_IPV6, .optional = true },
[RTA_TABLE] = { .type = NL_A_U32, .optional = true },
};
@@ -333,6 +335,25 @@ route_table_parse(struct ofpbuf *buf, struct route_table_msg *change)
nl_attr_get_in6_addr(attrs[RTA_PREFSRC]);
}
}
+ if (attrs[RTA_VIA]) {
+ const struct rtvia *via;
+ ovs_be32 gw;
+
+ via = nl_attr_get(attrs[RTA_VIA]);
+ switch (via->rtvia_family) {
+ case AF_INET:
+ gw = *(ALIGNED_CAST(ovs_be32 *, via->rtvia_addr));
+ in6_addr_set_mapped_ipv4(&change->rd.rta_gw, gw);
+ break;
+ case AF_INET6:
+ change->rd.rta_gw = *(ALIGNED_CAST(struct in6_addr *,
+ via->rtvia_addr));
+ break;
+ default:
+ VLOG_WARN("Unknown address family %d\n", via->rtvia_family);
+ return 0;
+ }
+ }
if (attrs[RTA_GATEWAY]) {
if (ipv4) {
ovs_be32 gw;
@@ -3612,7 +3612,8 @@ tnl_route_lookup_flow(const struct xlate_ctx *ctx,
}
if (ipv6_addr_is_set(&gw) &&
- (!IN6_IS_ADDR_V4MAPPED(&gw) || in6_addr_get_mapped_ipv4(&gw))) {
+ (!IN6_IS_ADDR_V4MAPPED(&gw) || in6_addr_get_mapped_ipv4(&gw)) &&
+ (!IN6_IS_ADDR_V4MAPPED(&dst) || IN6_IS_ADDR_V4MAPPED(&gw))) {
*ip = gw;
} else {
*ip = dst;
@@ -109,6 +109,57 @@ User: 2001:db8:beef::14/128 MARK 14 dev br0 GW 2001:db8:cafe::1 SRC 2001:db8:caf
OVS_VSWITCHD_STOP
AT_CLEANUP
+AT_SETUP([appctl - route/add and del with ipv4 via ipv6])
+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
+])
+
+dnl defualt pick the first IP, 192.168.9.2, as src
+AT_CHECK([ovs-appctl ovs/route/add 192.168.9.10/32 br0 dnl
+fe80::920a:84ff:beef:9510], [0], [OK
+])
+AT_CHECK([ovs-appctl ovs/route/add 192.168.9.11/32 br0 dnl
+fe80::920a:84ff:beef:9511 src=192.168.9.2], [0], [OK
+])
+AT_CHECK([ovs-appctl ovs/route/add 192.168.9.12/32 br0 dnl
+fe80::920a:84ff:beef:9512 src=192.168.9.3], [0], [OK
+])
+AT_CHECK([ovs-appctl ovs/route/add 192.168.9.13/32 br0 dnl
+fe80::920a:84ff:beef:9513 pkt_mark=13 src=192.168.9.3], [0], [OK
+])
+
+AT_CHECK([ovs-appctl ovs/route/show | grep User | grep beef | sort], [0], [dnl
+User: 192.168.9.10/32 dev br0 GW fe80::920a:84ff:beef:9510 SRC 192.168.9.2
+User: 192.168.9.11/32 dev br0 GW fe80::920a:84ff:beef:9511 SRC 192.168.9.2
+User: 192.168.9.12/32 dev br0 GW fe80::920a:84ff:beef:9512 SRC 192.168.9.3
+User: 192.168.9.13/32 MARK 13 dev br0 GW fe80::920a:84ff:beef:9513 SRC 192.168.9.3
+])
+
+dnl DST and SRC can be in different domain
+AT_CHECK([ovs-appctl ovs/route/add 192.168.10.12/32 br0 dnl
+fe80::920a:84ff:face:9512 src=192.168.9.3], [0], [OK
+])
+AT_CHECK([ovs-appctl ovs/route/show | grep User | grep face | sort], [0], [dnl
+User: 192.168.10.12/32 dev br0 GW fe80::920a:84ff:face:9512 SRC 192.168.9.3
+])
+
+dnl Delete route
+AT_CHECK([ovs-appctl ovs/route/del 192.168.9.10/32], [0], [OK
+])
+AT_CHECK([ovs-appctl ovs/route/del 192.168.9.11/32], [0], [OK
+])
+AT_CHECK([ovs-appctl ovs/route/del 192.168.9.12/32], [0], [OK
+])
+AT_CHECK([ovs-appctl ovs/route/del 192.168.9.13/32 pkt_mark=13], [0], [OK
+])
+OVS_WAIT_UNTIL([test $(ovs-appctl ovs/route/show | grep -c '192.168.9.1') -eq 0 ])
+
+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])
@@ -65,6 +65,45 @@ Cached: fc00:db8:beef::13/128 dev br0 GW fc00:db8:cafe::1 SRC fc00:db8:cafe::2])
OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP
+AT_SETUP([ovs-route - add and del system route ipv4 via ipv6])
+AT_KEYWORDS([route])
+OVS_TRAFFIC_VSWITCHD_START()
+AT_CHECK([ip link set br0 up])
+
+AT_CHECK([ip addr add 192.168.9.2/24 dev br0], [0], [stdout])
+AT_CHECK([ip addr add 192.168.9.3/24 dev br0], [0], [stdout])
+
+AT_CHECK([ip -6 addr add fc00:db8:cafe::2/64 dev br0], [0], [stdout])
+AT_CHECK([ip -6 addr add fc00:db8:cafe::3/64 dev br0], [0], [stdout])
+
+AT_CHECK([ip route add 192.168.9.12/32 dev br0 dnl
+via inet6 fe80::920a:84ff:fe9e:9512 src 192.168.9.2], [0], [stdout])
+AT_CHECK([ip route add 192.168.9.13/32 dev br0 dnl
+via inet6 fe80::920a:84ff:fe9e:9513 src 192.168.9.3], [0], [stdout])
+
+OVS_WAIT_UNTIL_EQUAL([ovs-appctl ovs/route/show | grep -E '192.168.9.1[[23]]/32' | sort], [dnl
+Cached: 192.168.9.12/32 dev br0 GW fe80::920a:84ff:fe9e:9512 SRC 192.168.9.2
+Cached: 192.168.9.13/32 dev br0 GW fe80::920a:84ff:fe9e:9513 SRC 192.168.9.3])
+
+AT_CHECK([ovs-appctl ovs/route/add 192.168.9.14/32 br0 dnl
+fe80::920a:84ff:fe9e:9514 src=192.168.9.2], [0], [OK
+])
+
+OVS_WAIT_UNTIL_EQUAL([ovs-appctl ovs/route/show | grep -E '192.168.9.14/32' | sort], [dnl
+User: 192.168.9.14/32 dev br0 GW fe80::920a:84ff:fe9e:9514 SRC 192.168.9.2])
+
+dnl Delete system cached route
+AT_CHECK([ip route del 192.168.9.12/32 dev br0 dnl
+via inet6 fe80::920a:84ff:fe9e:9512 src 192.168.9.2], [0], [stdout])
+AT_CHECK([ip route del 192.168.9.13/32 dev br0 dnl
+via inet6 fe80::920a:84ff:fe9e:9513 src 192.168.9.3], [0], [stdout])
+
+OVS_WAIT_UNTIL([test $(ovs-appctl ovs/route/show | grep -c '192.168.9.12/32') -eq 0 ])
+OVS_WAIT_UNTIL([test $(ovs-appctl ovs/route/show | grep -c '192.168.9.13/32') -eq 0 ])
+
+OVS_TRAFFIC_VSWITCHD_STOP
+AT_CLEANUP
+
dnl Checks that OVS doesn't use routes from non-standard tables.
AT_SETUP([ovs-route - route tables])
AT_KEYWORDS([route])
@@ -196,6 +196,69 @@ OVS_WAIT_UNTIL([test `ovs-pcap p0.pcap | grep 100022eb0000000120000237 | wc -l`
OVS_VSWITCHD_STOP
AT_CLEANUP
+AT_SETUP([tunnel_push_pop - v4 via v6 route])
+
+OVS_VSWITCHD_START([add-port br0 p0 -- set Interface p0 type=dummy ofport_request=1 other-config:hwaddr=aa:55:aa:55:00:00])
+AT_CHECK([ovs-vsctl add-br int-br -- set bridge int-br datapath_type=dummy], [0])
+AT_CHECK([ovs-vsctl add-port int-br t1 -- set Interface t1 type=vxlan \
+ options:remote_ip=1.1.2.92 options:key=123 ofport_request=1\
+ ], [0])
+
+AT_CHECK([ovs-appctl dpif/show], [0], [dnl
+dummy@ovs-dummy: hit:0 missed:0
+ br0:
+ br0 65534/100: (dummy-internal)
+ p0 1/1: (dummy)
+ int-br:
+ int-br 65534/2: (dummy-internal)
+ t1 1/4789: (vxlan: key=123, remote_ip=1.1.2.92)
+])
+
+AT_CHECK([ovs-ofctl add-flow br0 action=normal])
+
+dnl Setup dummy interface IP addresses.
+AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 1.1.2.88/32], [0], [OK
+])
+AT_CHECK([ovs-appctl netdev-dummy/ip6addr br0 2001:cafe::88/64], [0], [OK
+])
+dnl Add a static v4 via v6 route
+AT_CHECK([ovs-appctl ovs/route/add 1.1.2.92/32 br0 2001:cafe::10 src=1.1.2.89], [0], [OK
+])
+
+AT_CHECK([ovs-appctl ovs/route/show | grep br0 | sort], [0], [dnl
+Cached: 1.1.2.88/32 dev br0 SRC 1.1.2.88 local
+Cached: 2001:cafe::/64 dev br0 SRC 2001:cafe::88 local
+User: 1.1.2.92/32 dev br0 GW 2001:cafe::10 SRC 1.1.2.89
+])
+
+dnl Check ARP Snoop
+AT_CHECK([ovs-appctl netdev-dummy/receive p0 'recirc_id(0),in_port(100),dnl
+eth(src=f8:bc:12:44:34:b6,dst=ff:ff:ff:ff:ff:ff),eth_type(0x0806),dnl
+arp(sip=1.1.2.92,tip=1.1.2.88,op=2,sha=f8:bc:12:44:34:b6,tha=00:00:00:00:00:00)'])
+
+ovs-appctl time/warp 1000
+ovs-appctl time/warp 1000
+
+AT_CHECK([ovs-appctl tnl/neigh/show | tail -n+3 | sort], [0], [dnl
+1.1.2.92 f8:bc:12:44:34:b6 br0
+])
+
+dnl Check VXLAN tunnel push
+AT_CHECK([ovs-ofctl add-flow int-br action=1])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),dnl
+eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),dnl
+ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+
+AT_CHECK([tail -1 stdout], [0],
+ [Datapath actions: tnl_push(tnl_port(4789),header(size=50,type=4,dnl
+eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),dnl
+ipv4(src=1.1.2.89,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),dnl
+udp(src=0,dst=4789,csum=0x0),vxlan(flags=0x8000000,vni=0x7b)),out_port(100)),1
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
AT_SETUP([tunnel_push_pop - action])
OVS_VSWITCHD_START([add-port br0 p0 -- set Interface p0 type=dummy ofport_request=1 other-config:hwaddr=aa:55:aa:55:00:00])