Merge branch 'mptcp-ipv4-mapped-ipv6-addressing-for-subflows'
Mat Martineau says: ==================== MPTCP: IPv4-mapped IPv6 addressing for subflows This patch series from the MPTCP tree adds support for IPv4-mapped IPv6 addressing that was missing when multiple subflows were first implemented. Patches 1 and 2 handle the conversion and comparison of the mapped addresses. Patch 3 contains a minor refactor in the path manager's handling of addresses. Patches 4 and 5 add selftests for the new functionality and adjust the selftest timeout. ==================== Link: https://lore.kernel.org/r/20210125185904.6997-1-mathew.j.martineau@linux.intel.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
fd0e4ec4a7
@ -60,15 +60,20 @@ static bool addresses_equal(const struct mptcp_addr_info *a,
|
||||
{
|
||||
bool addr_equals = false;
|
||||
|
||||
if (a->family != b->family)
|
||||
return false;
|
||||
|
||||
if (a->family == AF_INET)
|
||||
addr_equals = a->addr.s_addr == b->addr.s_addr;
|
||||
if (a->family == b->family) {
|
||||
if (a->family == AF_INET)
|
||||
addr_equals = a->addr.s_addr == b->addr.s_addr;
|
||||
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
|
||||
else
|
||||
addr_equals = !ipv6_addr_cmp(&a->addr6, &b->addr6);
|
||||
else
|
||||
addr_equals = !ipv6_addr_cmp(&a->addr6, &b->addr6);
|
||||
} else if (a->family == AF_INET) {
|
||||
if (ipv6_addr_v4mapped(&b->addr6))
|
||||
addr_equals = a->addr.s_addr == b->addr6.s6_addr32[3];
|
||||
} else if (b->family == AF_INET) {
|
||||
if (ipv6_addr_v4mapped(&a->addr6))
|
||||
addr_equals = a->addr6.s6_addr32[3] == b->addr.s_addr;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!addr_equals)
|
||||
return false;
|
||||
@ -137,6 +142,7 @@ select_local_address(const struct pm_nl_pernet *pernet,
|
||||
struct mptcp_sock *msk)
|
||||
{
|
||||
struct mptcp_pm_addr_entry *entry, *ret = NULL;
|
||||
struct sock *sk = (struct sock *)msk;
|
||||
|
||||
rcu_read_lock();
|
||||
__mptcp_flush_join_list(msk);
|
||||
@ -144,11 +150,20 @@ select_local_address(const struct pm_nl_pernet *pernet,
|
||||
if (!(entry->addr.flags & MPTCP_PM_ADDR_FLAG_SUBFLOW))
|
||||
continue;
|
||||
|
||||
if (entry->addr.family != sk->sk_family) {
|
||||
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
|
||||
if ((entry->addr.family == AF_INET &&
|
||||
!ipv6_addr_v4mapped(&sk->sk_v6_daddr)) ||
|
||||
(sk->sk_family == AF_INET &&
|
||||
!ipv6_addr_v4mapped(&entry->addr.addr6)))
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
/* avoid any address already in use by subflows and
|
||||
* pending join
|
||||
*/
|
||||
if (entry->addr.family == ((struct sock *)msk)->sk_family &&
|
||||
!lookup_subflow_by_saddr(&msk->conn_list, &entry->addr)) {
|
||||
if (!lookup_subflow_by_saddr(&msk->conn_list, &entry->addr)) {
|
||||
ret = entry;
|
||||
break;
|
||||
}
|
||||
@ -310,7 +325,6 @@ void mptcp_pm_free_anno_list(struct mptcp_sock *msk)
|
||||
|
||||
static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk)
|
||||
{
|
||||
struct mptcp_addr_info remote = { 0 };
|
||||
struct sock *sk = (struct sock *)msk;
|
||||
struct mptcp_pm_addr_entry *local;
|
||||
struct pm_nl_pernet *pernet;
|
||||
@ -344,13 +358,14 @@ static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk)
|
||||
/* check if should create a new subflow */
|
||||
if (msk->pm.local_addr_used < msk->pm.local_addr_max &&
|
||||
msk->pm.subflows < msk->pm.subflows_max) {
|
||||
remote_address((struct sock_common *)sk, &remote);
|
||||
|
||||
local = select_local_address(pernet, msk);
|
||||
if (local) {
|
||||
struct mptcp_addr_info remote = { 0 };
|
||||
|
||||
msk->pm.local_addr_used++;
|
||||
msk->pm.subflows++;
|
||||
check_work_pending(msk);
|
||||
remote_address((struct sock_common *)sk, &remote);
|
||||
spin_unlock_bh(&msk->pm.lock);
|
||||
__mptcp_subflow_connect(sk, &local->addr, &remote);
|
||||
spin_lock_bh(&msk->pm.lock);
|
||||
|
@ -1085,21 +1085,31 @@ void mptcpv6_handle_mapped(struct sock *sk, bool mapped)
|
||||
#endif
|
||||
|
||||
static void mptcp_info2sockaddr(const struct mptcp_addr_info *info,
|
||||
struct sockaddr_storage *addr)
|
||||
struct sockaddr_storage *addr,
|
||||
unsigned short family)
|
||||
{
|
||||
memset(addr, 0, sizeof(*addr));
|
||||
addr->ss_family = info->family;
|
||||
addr->ss_family = family;
|
||||
if (addr->ss_family == AF_INET) {
|
||||
struct sockaddr_in *in_addr = (struct sockaddr_in *)addr;
|
||||
|
||||
in_addr->sin_addr = info->addr;
|
||||
if (info->family == AF_INET)
|
||||
in_addr->sin_addr = info->addr;
|
||||
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
|
||||
else if (ipv6_addr_v4mapped(&info->addr6))
|
||||
in_addr->sin_addr.s_addr = info->addr6.s6_addr32[3];
|
||||
#endif
|
||||
in_addr->sin_port = info->port;
|
||||
}
|
||||
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
|
||||
else if (addr->ss_family == AF_INET6) {
|
||||
struct sockaddr_in6 *in6_addr = (struct sockaddr_in6 *)addr;
|
||||
|
||||
in6_addr->sin6_addr = info->addr6;
|
||||
if (info->family == AF_INET)
|
||||
ipv6_addr_set_v4mapped(info->addr.s_addr,
|
||||
&in6_addr->sin6_addr);
|
||||
else
|
||||
in6_addr->sin6_addr = info->addr6;
|
||||
in6_addr->sin6_port = info->port;
|
||||
}
|
||||
#endif
|
||||
@ -1143,11 +1153,11 @@ int __mptcp_subflow_connect(struct sock *sk, const struct mptcp_addr_info *loc,
|
||||
subflow->remote_key = msk->remote_key;
|
||||
subflow->local_key = msk->local_key;
|
||||
subflow->token = msk->token;
|
||||
mptcp_info2sockaddr(loc, &addr);
|
||||
mptcp_info2sockaddr(loc, &addr, ssk->sk_family);
|
||||
|
||||
addrlen = sizeof(struct sockaddr_in);
|
||||
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
|
||||
if (loc->family == AF_INET6)
|
||||
if (addr.ss_family == AF_INET6)
|
||||
addrlen = sizeof(struct sockaddr_in6);
|
||||
#endif
|
||||
ssk->sk_bound_dev_if = loc->ifindex;
|
||||
@ -1163,7 +1173,7 @@ int __mptcp_subflow_connect(struct sock *sk, const struct mptcp_addr_info *loc,
|
||||
subflow->remote_id = remote_id;
|
||||
subflow->request_join = 1;
|
||||
subflow->request_bkup = !!(loc->flags & MPTCP_PM_ADDR_FLAG_BACKUP);
|
||||
mptcp_info2sockaddr(remote, &addr);
|
||||
mptcp_info2sockaddr(remote, &addr, ssk->sk_family);
|
||||
|
||||
mptcp_add_pending_subflow(msk, subflow);
|
||||
err = kernel_connect(sf, (struct sockaddr *)&addr, addrlen, O_NONBLOCK);
|
||||
|
@ -790,6 +790,81 @@ chk_join_nr "remove subflow and signal IPv6" 2 2 2
|
||||
chk_add_nr 1 1
|
||||
chk_rm_nr 1 1
|
||||
|
||||
# subflow IPv4-mapped to IPv4-mapped
|
||||
reset
|
||||
ip netns exec $ns1 ./pm_nl_ctl limits 0 1
|
||||
ip netns exec $ns2 ./pm_nl_ctl limits 0 1
|
||||
ip netns exec $ns2 ./pm_nl_ctl add "::ffff:10.0.3.2" flags subflow
|
||||
run_tests $ns1 $ns2 "::ffff:10.0.1.1"
|
||||
chk_join_nr "single subflow IPv4-mapped" 1 1 1
|
||||
|
||||
# signal address IPv4-mapped with IPv4-mapped sk
|
||||
reset
|
||||
ip netns exec $ns1 ./pm_nl_ctl limits 0 1
|
||||
ip netns exec $ns2 ./pm_nl_ctl limits 1 1
|
||||
ip netns exec $ns1 ./pm_nl_ctl add "::ffff:10.0.2.1" flags signal
|
||||
run_tests $ns1 $ns2 "::ffff:10.0.1.1"
|
||||
chk_join_nr "signal address IPv4-mapped" 1 1 1
|
||||
chk_add_nr 1 1
|
||||
|
||||
# subflow v4-map-v6
|
||||
reset
|
||||
ip netns exec $ns1 ./pm_nl_ctl limits 0 1
|
||||
ip netns exec $ns2 ./pm_nl_ctl limits 0 1
|
||||
ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
|
||||
run_tests $ns1 $ns2 "::ffff:10.0.1.1"
|
||||
chk_join_nr "single subflow v4-map-v6" 1 1 1
|
||||
|
||||
# signal address v4-map-v6
|
||||
reset
|
||||
ip netns exec $ns1 ./pm_nl_ctl limits 0 1
|
||||
ip netns exec $ns2 ./pm_nl_ctl limits 1 1
|
||||
ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal
|
||||
run_tests $ns1 $ns2 "::ffff:10.0.1.1"
|
||||
chk_join_nr "signal address v4-map-v6" 1 1 1
|
||||
chk_add_nr 1 1
|
||||
|
||||
# subflow v6-map-v4
|
||||
reset
|
||||
ip netns exec $ns1 ./pm_nl_ctl limits 0 1
|
||||
ip netns exec $ns2 ./pm_nl_ctl limits 0 1
|
||||
ip netns exec $ns2 ./pm_nl_ctl add "::ffff:10.0.3.2" flags subflow
|
||||
run_tests $ns1 $ns2 10.0.1.1
|
||||
chk_join_nr "single subflow v6-map-v4" 1 1 1
|
||||
|
||||
# signal address v6-map-v4
|
||||
reset
|
||||
ip netns exec $ns1 ./pm_nl_ctl limits 0 1
|
||||
ip netns exec $ns2 ./pm_nl_ctl limits 1 1
|
||||
ip netns exec $ns1 ./pm_nl_ctl add "::ffff:10.0.2.1" flags signal
|
||||
run_tests $ns1 $ns2 10.0.1.1
|
||||
chk_join_nr "signal address v6-map-v4" 1 1 1
|
||||
chk_add_nr 1 1
|
||||
|
||||
# no subflow IPv6 to v4 address
|
||||
reset
|
||||
ip netns exec $ns1 ./pm_nl_ctl limits 0 1
|
||||
ip netns exec $ns2 ./pm_nl_ctl limits 0 1
|
||||
ip netns exec $ns2 ./pm_nl_ctl add dead:beef:2::2 flags subflow
|
||||
run_tests $ns1 $ns2 10.0.1.1
|
||||
chk_join_nr "no JOIN with diff families v4-v6" 0 0 0
|
||||
|
||||
# no subflow IPv6 to v4 address even if v6 has a valid v4 at the end
|
||||
reset
|
||||
ip netns exec $ns1 ./pm_nl_ctl limits 0 1
|
||||
ip netns exec $ns2 ./pm_nl_ctl limits 0 1
|
||||
ip netns exec $ns2 ./pm_nl_ctl add dead:beef:2::10.0.3.2 flags subflow
|
||||
run_tests $ns1 $ns2 10.0.1.1
|
||||
chk_join_nr "no JOIN with diff families v4-v6-2" 0 0 0
|
||||
|
||||
# no subflow IPv4 to v6 address, no need to slow down too then
|
||||
reset
|
||||
ip netns exec $ns1 ./pm_nl_ctl limits 0 1
|
||||
ip netns exec $ns2 ./pm_nl_ctl limits 0 1
|
||||
ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
|
||||
run_tests $ns1 $ns2 dead:beef:1::1
|
||||
chk_join_nr "no JOIN with diff families v6-v4" 0 0 0
|
||||
|
||||
# single subflow, backup
|
||||
reset
|
||||
ip netns exec $ns1 ./pm_nl_ctl limits 0 1
|
||||
|
@ -1 +1 @@
|
||||
timeout=450
|
||||
timeout=600
|
||||
|
Loading…
x
Reference in New Issue
Block a user