2018-03-06 22:16:27 +01:00
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
#
2018-03-17 02:31:42 +01:00
# Check that route PMTU values match expectations, and that initial device MTU
# values are assigned correctly
2018-03-06 22:16:27 +01:00
#
# Tests currently implemented:
#
2018-03-17 02:31:44 +01:00
# - pmtu_vti4_exception
# Set up vti tunnel on top of veth, with xfrm states and policies, in two
# namespaces with matching endpoints. Check that route exception is not
# created if link layer MTU is not exceeded, then exceed it and check that
# exception is created with the expected PMTU. The approach described
# below for IPv6 doesn't apply here, because, on IPv4, administrative MTU
# changes alone won't affect PMTU
#
2018-03-17 02:31:41 +01:00
# - pmtu_vti6_exception
2018-03-06 22:16:27 +01:00
# Set up vti6 tunnel on top of veth, with xfrm states and policies, in two
# namespaces with matching endpoints. Check that route exception is
# created by exceeding link layer MTU with ping to other endpoint. Then
# decrease and increase MTU of tunnel, checking that route exception PMTU
# changes accordingly
2018-03-17 02:31:42 +01:00
#
# - pmtu_vti4_default_mtu
# Set up vti4 tunnel on top of veth, in two namespaces with matching
# endpoints. Check that MTU assigned to vti interface is the MTU of the
# lower layer (veth) minus additional lower layer headers (zero, for veth)
# minus IPv4 header length
2018-03-17 02:31:43 +01:00
#
# - pmtu_vti6_default_mtu
# Same as above, for IPv6
2018-03-17 02:31:45 +01:00
#
# - pmtu_vti4_link_add_mtu
# Set up vti4 interface passing MTU value at link creation, check MTU is
# configured, and that link is not created with invalid MTU values
2018-03-17 02:31:46 +01:00
#
# - pmtu_vti6_link_add_mtu
# Same as above, for IPv6
2018-03-17 02:31:47 +01:00
#
# - pmtu_vti6_link_change_mtu
# Set up two dummy interfaces with different MTUs, create a vti6 tunnel
# and check that configured MTU is used on link creation and changes, and
# that MTU is properly calculated instead when MTU is not configured from
# userspace
2018-03-06 22:16:27 +01:00
2018-05-04 16:34:09 -06:00
# Kselftest framework requirement - SKIP code is 4.
ksft_skip = 4
2018-03-17 02:31:41 +01:00
tests = "
2018-03-17 02:31:47 +01:00
pmtu_vti6_exception vti6: PMTU exceptions
pmtu_vti4_exception vti4: PMTU exceptions
pmtu_vti4_default_mtu vti4: default MTU assignment
pmtu_vti6_default_mtu vti6: default MTU assignment
pmtu_vti4_link_add_mtu vti4: MTU setting on link creation
pmtu_vti6_link_add_mtu vti6: MTU setting on link creation
pmtu_vti6_link_change_mtu vti6: MTU changes on link changes"
2018-03-17 02:31:41 +01:00
2018-03-06 22:16:27 +01:00
NS_A = " ns- $( mktemp -u XXXXXX) "
NS_B = " ns- $( mktemp -u XXXXXX) "
ns_a = " ip netns exec ${ NS_A } "
ns_b = " ip netns exec ${ NS_B } "
2018-03-17 02:31:42 +01:00
veth4_a_addr = "192.168.1.1"
veth4_b_addr = "192.168.1.2"
veth4_mask = "24"
2018-03-06 22:16:27 +01:00
veth6_a_addr = "fd00:1::a"
veth6_b_addr = "fd00:1::b"
veth6_mask = "64"
2018-03-17 02:31:42 +01:00
vti4_a_addr = "192.168.2.1"
vti4_b_addr = "192.168.2.2"
vti4_mask = "24"
2018-03-06 22:16:27 +01:00
vti6_a_addr = "fd00:2::a"
vti6_b_addr = "fd00:2::b"
vti6_mask = "64"
2018-03-17 02:31:47 +01:00
dummy6_0_addr = "fc00:1000::0"
dummy6_1_addr = "fc00:1001::0"
dummy6_mask = "64"
2018-03-17 02:31:41 +01:00
cleanup_done = 1
err_buf =
err( ) {
err_buf = " ${ err_buf } ${ 1 }
"
}
err_flush( ) {
echo -n " ${ err_buf } "
err_buf =
}
2018-03-06 22:16:27 +01:00
setup_namespaces( ) {
2018-03-17 02:31:38 +01:00
ip netns add ${ NS_A } || return 1
2018-03-06 22:16:27 +01:00
ip netns add ${ NS_B }
}
setup_veth( ) {
2018-03-17 02:31:38 +01:00
${ ns_a } ip link add veth_a type veth peer name veth_b || return 1
2018-03-06 22:16:27 +01:00
${ ns_a } ip link set veth_b netns ${ NS_B }
2018-03-17 02:31:42 +01:00
${ ns_a } ip addr add ${ veth4_a_addr } /${ veth4_mask } dev veth_a
${ ns_b } ip addr add ${ veth4_b_addr } /${ veth4_mask } dev veth_b
2018-03-06 22:16:27 +01:00
${ ns_a } ip addr add ${ veth6_a_addr } /${ veth6_mask } dev veth_a
${ ns_b } ip addr add ${ veth6_b_addr } /${ veth6_mask } dev veth_b
${ ns_a } ip link set veth_a up
${ ns_b } ip link set veth_b up
}
2018-03-17 02:31:42 +01:00
setup_vti( ) {
proto = ${ 1 }
veth_a_addr = " ${ 2 } "
veth_b_addr = " ${ 3 } "
vti_a_addr = " ${ 4 } "
vti_b_addr = " ${ 5 } "
vti_mask = ${ 6 }
2018-03-06 22:16:27 +01:00
2018-03-17 02:31:42 +01:00
[ ${ proto } -eq 6 ] && vti_type = "vti6" || vti_type = "vti"
2018-03-06 22:16:27 +01:00
2018-03-17 02:31:42 +01:00
${ ns_a } ip link add vti${ proto } _a type ${ vti_type } local ${ veth_a_addr } remote ${ veth_b_addr } key 10 || return 1
${ ns_b } ip link add vti${ proto } _b type ${ vti_type } local ${ veth_b_addr } remote ${ veth_a_addr } key 10
${ ns_a } ip addr add ${ vti_a_addr } /${ vti_mask } dev vti${ proto } _a
${ ns_b } ip addr add ${ vti_b_addr } /${ vti_mask } dev vti${ proto } _b
${ ns_a } ip link set vti${ proto } _a up
${ ns_b } ip link set vti${ proto } _b up
2018-03-06 22:16:27 +01:00
sleep 1
}
2018-03-17 02:31:42 +01:00
setup_vti4( ) {
setup_vti 4 ${ veth4_a_addr } ${ veth4_b_addr } ${ vti4_a_addr } ${ vti4_b_addr } ${ vti4_mask }
}
setup_vti6( ) {
setup_vti 6 ${ veth6_a_addr } ${ veth6_b_addr } ${ vti6_a_addr } ${ vti6_b_addr } ${ vti6_mask }
}
2018-03-06 22:16:27 +01:00
setup_xfrm( ) {
2018-03-17 02:31:44 +01:00
proto = ${ 1 }
veth_a_addr = " ${ 2 } "
veth_b_addr = " ${ 3 } "
${ ns_a } ip -${ proto } xfrm state add src ${ veth_a_addr } dst ${ veth_b_addr } spi 0x1000 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel || return 1
${ ns_a } ip -${ proto } xfrm state add src ${ veth_b_addr } dst ${ veth_a_addr } spi 0x1001 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel
${ ns_a } ip -${ proto } xfrm policy add dir out mark 10 tmpl src ${ veth_a_addr } dst ${ veth_b_addr } proto esp mode tunnel
${ ns_a } ip -${ proto } xfrm policy add dir in mark 10 tmpl src ${ veth_b_addr } dst ${ veth_a_addr } proto esp mode tunnel
${ ns_b } ip -${ proto } xfrm state add src ${ veth_a_addr } dst ${ veth_b_addr } spi 0x1000 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel
${ ns_b } ip -${ proto } xfrm state add src ${ veth_b_addr } dst ${ veth_a_addr } spi 0x1001 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel
${ ns_b } ip -${ proto } xfrm policy add dir out mark 10 tmpl src ${ veth_b_addr } dst ${ veth_a_addr } proto esp mode tunnel
${ ns_b } ip -${ proto } xfrm policy add dir in mark 10 tmpl src ${ veth_a_addr } dst ${ veth_b_addr } proto esp mode tunnel
}
setup_xfrm4( ) {
setup_xfrm 4 ${ veth4_a_addr } ${ veth4_b_addr }
}
2018-03-06 22:16:27 +01:00
2018-03-17 02:31:44 +01:00
setup_xfrm6( ) {
setup_xfrm 6 ${ veth6_a_addr } ${ veth6_b_addr }
2018-03-06 22:16:27 +01:00
}
setup( ) {
2018-05-04 16:34:09 -06:00
[ " $( id -u) " -ne 0 ] && echo " need to run as root" && return $ksft_skip
2018-03-06 22:16:27 +01:00
2018-03-17 02:31:41 +01:00
cleanup_done = 0
for arg do
eval setup_${ arg } || { echo " ${ arg } not supported " ; return 1; }
done
2018-03-06 22:16:27 +01:00
}
cleanup( ) {
2018-03-17 02:31:41 +01:00
[ ${ cleanup_done } -eq 1 ] && return
2018-03-06 22:16:27 +01:00
ip netns del ${ NS_A } 2 > /dev/null
ip netns del ${ NS_B } 2 > /dev/null
2018-03-17 02:31:41 +01:00
cleanup_done = 1
2018-03-06 22:16:27 +01:00
}
mtu( ) {
ns_cmd = " ${ 1 } "
dev = " ${ 2 } "
mtu = " ${ 3 } "
${ ns_cmd } ip link set dev ${ dev } mtu ${ mtu }
}
2018-03-17 02:31:40 +01:00
mtu_parse( ) {
input = " ${ 1 } "
next = 0
for i in ${ input } ; do
[ ${ next } -eq 1 ] && echo " ${ i } " && return
[ " ${ i } " = "mtu" ] && next = 1
done
}
2018-03-17 02:31:42 +01:00
link_get( ) {
ns_cmd = " ${ 1 } "
name = " ${ 2 } "
${ ns_cmd } ip link show dev " ${ name } "
}
link_get_mtu( ) {
ns_cmd = " ${ 1 } "
name = " ${ 2 } "
mtu_parse " $( link_get " ${ ns_cmd } " ${ name } ) "
}
2018-03-06 22:16:27 +01:00
route_get_dst_exception( ) {
2018-03-17 02:31:39 +01:00
ns_cmd = " ${ 1 } "
dst = " ${ 2 } "
2018-03-06 22:16:27 +01:00
2018-03-17 02:31:39 +01:00
${ ns_cmd } ip route get " ${ dst } "
2018-03-06 22:16:27 +01:00
}
route_get_dst_pmtu_from_exception( ) {
2018-03-17 02:31:39 +01:00
ns_cmd = " ${ 1 } "
dst = " ${ 2 } "
2018-03-06 22:16:27 +01:00
2018-03-17 02:31:40 +01:00
mtu_parse " $( route_get_dst_exception " ${ ns_cmd } " ${ dst } ) "
2018-03-06 22:16:27 +01:00
}
2018-03-17 02:31:44 +01:00
test_pmtu_vti4_exception( ) {
setup namespaces veth vti4 xfrm4 || return 2
veth_mtu = 1500
vti_mtu = $(( veth_mtu - 20 ))
# SPI SN IV ICV pad length next header
esp_payload_rfc4106 = $(( vti_mtu - 4 - 4 - 8 - 16 - 1 - 1 ))
ping_payload = $(( esp_payload_rfc4106 - 28 ))
mtu " ${ ns_a } " veth_a ${ veth_mtu }
mtu " ${ ns_b } " veth_b ${ veth_mtu }
mtu " ${ ns_a } " vti4_a ${ vti_mtu }
mtu " ${ ns_b } " vti4_b ${ vti_mtu }
# Send DF packet without exceeding link layer MTU, check that no
# exception is created
${ ns_a } ping -q -M want -i 0.1 -w 2 -s ${ ping_payload } ${ vti4_b_addr } > /dev/null
pmtu = " $( route_get_dst_pmtu_from_exception " ${ ns_a } " ${ vti4_b_addr } ) "
if [ " ${ pmtu } " != "" ] ; then
err " unexpected exception created with PMTU ${ pmtu } for IP payload length ${ esp_payload_rfc4106 } "
return 1
fi
# Now exceed link layer MTU by one byte, check that exception is created
${ ns_a } ping -q -M want -i 0.1 -w 2 -s $(( ping_payload + 1 )) ${ vti4_b_addr } > /dev/null
pmtu = " $( route_get_dst_pmtu_from_exception " ${ ns_a } " ${ vti4_b_addr } ) "
if [ " ${ pmtu } " = "" ] ; then
err " exception not created for IP payload length $(( esp_payload_rfc4106 + 1 )) "
return 1
fi
# ...with the right PMTU value
if [ ${ pmtu } -ne ${ esp_payload_rfc4106 } ] ; then
err " wrong PMTU ${ pmtu } in exception, expected: ${ esp_payload_rfc4106 } "
return 1
fi
}
2018-03-06 22:16:27 +01:00
test_pmtu_vti6_exception( ) {
2018-03-17 02:31:44 +01:00
setup namespaces veth vti6 xfrm6 || return 2
2018-03-17 02:31:41 +01:00
fail = 0
2018-03-06 22:16:27 +01:00
# Create route exception by exceeding link layer MTU
mtu " ${ ns_a } " veth_a 4000
mtu " ${ ns_b } " veth_b 4000
2018-03-17 02:31:42 +01:00
mtu " ${ ns_a } " vti6_a 5000
mtu " ${ ns_b } " vti6_b 5000
2018-03-06 22:16:27 +01:00
${ ns_a } ping6 -q -i 0.1 -w 2 -s 60000 ${ vti6_b_addr } > /dev/null
# Check that exception was created
2018-03-17 02:31:39 +01:00
if [ " $( route_get_dst_pmtu_from_exception " ${ ns_a } " ${ vti6_b_addr } ) " = "" ] ; then
2018-03-17 02:31:41 +01:00
err " tunnel exceeding link layer MTU didn't create route exception"
return 1
2018-03-06 22:16:27 +01:00
fi
# Decrease tunnel MTU, check for PMTU decrease in route exception
2018-03-17 02:31:42 +01:00
mtu " ${ ns_a } " vti6_a 3000
2018-03-06 22:16:27 +01:00
2018-03-17 02:31:39 +01:00
if [ " $( route_get_dst_pmtu_from_exception " ${ ns_a } " ${ vti6_b_addr } ) " -ne 3000 ] ; then
2018-03-17 02:31:41 +01:00
err " decreasing tunnel MTU didn't decrease route exception PMTU"
fail = 1
2018-03-06 22:16:27 +01:00
fi
# Increase tunnel MTU, check for PMTU increase in route exception
2018-03-17 02:31:42 +01:00
mtu " ${ ns_a } " vti6_a 9000
2018-03-17 02:31:39 +01:00
if [ " $( route_get_dst_pmtu_from_exception " ${ ns_a } " ${ vti6_b_addr } ) " -ne 9000 ] ; then
2018-03-17 02:31:41 +01:00
err " increasing tunnel MTU didn't increase route exception PMTU"
fail = 1
2018-03-06 22:16:27 +01:00
fi
2018-03-17 02:31:41 +01:00
return ${ fail }
2018-03-06 22:16:27 +01:00
}
2018-03-17 02:31:42 +01:00
test_pmtu_vti4_default_mtu( ) {
setup namespaces veth vti4 || return 2
# Check that MTU of vti device is MTU of veth minus IPv4 header length
veth_mtu = " $( link_get_mtu " ${ ns_a } " veth_a) "
vti4_mtu = " $( link_get_mtu " ${ ns_a } " vti4_a) "
if [ $(( veth_mtu - vti4_mtu)) -ne 20 ] ; then
err " vti MTU ${ vti4_mtu } is not veth MTU ${ veth_mtu } minus IPv4 header length "
return 1
fi
}
2018-03-17 02:31:43 +01:00
test_pmtu_vti6_default_mtu( ) {
setup namespaces veth vti6 || return 2
# Check that MTU of vti device is MTU of veth minus IPv6 header length
veth_mtu = " $( link_get_mtu " ${ ns_a } " veth_a) "
vti6_mtu = " $( link_get_mtu " ${ ns_a } " vti6_a) "
if [ $(( veth_mtu - vti6_mtu)) -ne 40 ] ; then
err " vti MTU ${ vti6_mtu } is not veth MTU ${ veth_mtu } minus IPv6 header length "
return 1
fi
}
2018-03-17 02:31:45 +01:00
test_pmtu_vti4_link_add_mtu( ) {
setup namespaces || return 2
${ ns_a } ip link add vti4_a type vti local ${ veth4_a_addr } remote ${ veth4_b_addr } key 10
[ $? -ne 0 ] && err " vti not supported" && return 2
${ ns_a } ip link del vti4_a
fail = 0
min = 68
max = $(( 65528 - 20 ))
# Check invalid values first
for v in $(( min - 1 )) $(( max + 1 )) ; do
${ ns_a } ip link add vti4_a mtu ${ v } type vti local ${ veth4_a_addr } remote ${ veth4_b_addr } key 10 2>/dev/null
# This can fail, or MTU can be adjusted to a proper value
[ $? -ne 0 ] && continue
mtu = " $( link_get_mtu " ${ ns_a } " vti4_a) "
if [ ${ mtu } -lt ${ min } -o ${ mtu } -gt ${ max } ] ; then
err " vti tunnel created with invalid MTU ${ mtu } "
fail = 1
fi
${ ns_a } ip link del vti4_a
done
# Now check valid values
for v in ${ min } 1300 ${ max } ; do
${ ns_a } ip link add vti4_a mtu ${ v } type vti local ${ veth4_a_addr } remote ${ veth4_b_addr } key 10
mtu = " $( link_get_mtu " ${ ns_a } " vti4_a) "
${ ns_a } ip link del vti4_a
if [ " ${ mtu } " != " ${ v } " ] ; then
err " vti MTU ${ mtu } doesn't match configured value ${ v } "
fail = 1
fi
done
return ${ fail }
}
2018-03-17 02:31:46 +01:00
test_pmtu_vti6_link_add_mtu( ) {
setup namespaces || return 2
${ ns_a } ip link add vti6_a type vti6 local ${ veth6_a_addr } remote ${ veth6_b_addr } key 10
[ $? -ne 0 ] && err " vti6 not supported" && return 2
${ ns_a } ip link del vti6_a
fail = 0
2018-04-26 19:41:02 +02:00
min = 68 # vti6 can carry IPv4 packets too
2018-03-17 02:31:46 +01:00
max = $(( 65535 - 40 ))
# Check invalid values first
for v in $(( min - 1 )) $(( max + 1 )) ; do
${ ns_a } ip link add vti6_a mtu ${ v } type vti6 local ${ veth6_a_addr } remote ${ veth6_b_addr } key 10 2>/dev/null
# This can fail, or MTU can be adjusted to a proper value
[ $? -ne 0 ] && continue
mtu = " $( link_get_mtu " ${ ns_a } " vti6_a) "
if [ ${ mtu } -lt ${ min } -o ${ mtu } -gt ${ max } ] ; then
err " vti6 tunnel created with invalid MTU ${ v } "
fail = 1
fi
${ ns_a } ip link del vti6_a
done
# Now check valid values
2018-04-26 19:41:02 +02:00
for v in 68 1280 1300 $(( 65535 - 40 )) ; do
2018-03-17 02:31:46 +01:00
${ ns_a } ip link add vti6_a mtu ${ v } type vti6 local ${ veth6_a_addr } remote ${ veth6_b_addr } key 10
mtu = " $( link_get_mtu " ${ ns_a } " vti6_a) "
${ ns_a } ip link del vti6_a
if [ " ${ mtu } " != " ${ v } " ] ; then
err " vti6 MTU ${ mtu } doesn't match configured value ${ v } "
fail = 1
fi
done
return ${ fail }
}
2018-03-17 02:31:47 +01:00
test_pmtu_vti6_link_change_mtu( ) {
setup namespaces || return 2
${ ns_a } ip link add dummy0 mtu 1500 type dummy
[ $? -ne 0 ] && err " dummy not supported" && return 2
${ ns_a } ip link add dummy1 mtu 3000 type dummy
${ ns_a } ip link set dummy0 up
${ ns_a } ip link set dummy1 up
${ ns_a } ip addr add ${ dummy6_0_addr } /${ dummy6_mask } dev dummy0
${ ns_a } ip addr add ${ dummy6_1_addr } /${ dummy6_mask } dev dummy1
fail = 0
# Create vti6 interface bound to device, passing MTU, check it
${ ns_a } ip link add vti6_a mtu 1300 type vti6 remote ${ dummy6_0_addr } local ${ dummy6_0_addr }
mtu = " $( link_get_mtu " ${ ns_a } " vti6_a) "
if [ ${ mtu } -ne 1300 ] ; then
err " vti6 MTU ${ mtu } doesn't match configured value 1300 "
fail = 1
fi
# Move to another device with different MTU, without passing MTU, check
# MTU is adjusted
${ ns_a } ip link set vti6_a type vti6 remote ${ dummy6_1_addr } local ${ dummy6_1_addr }
mtu = " $( link_get_mtu " ${ ns_a } " vti6_a) "
if [ ${ mtu } -ne $(( 3000 - 40 )) ] ; then
err " vti MTU ${ mtu } is not dummy MTU 3000 minus IPv6 header length "
fail = 1
fi
# Move it back, passing MTU, check MTU is not overridden
${ ns_a } ip link set vti6_a mtu 1280 type vti6 remote ${ dummy6_0_addr } local ${ dummy6_0_addr }
mtu = " $( link_get_mtu " ${ ns_a } " vti6_a) "
if [ ${ mtu } -ne 1280 ] ; then
err " vti6 MTU ${ mtu } doesn't match configured value 1280 "
fail = 1
fi
return ${ fail }
}
2018-03-06 22:16:27 +01:00
trap cleanup EXIT
2018-03-17 02:31:41 +01:00
exitcode = 0
desc = 0
IFS = "
"
for t in ${ tests } ; do
[ $desc -eq 0 ] && name = " ${ t } " && desc = 1 && continue || desc = 0
(
unset IFS
eval test_${ name }
ret = $?
cleanup
if [ $ret -eq 0 ] ; then
printf "TEST: %-60s [ OK ]\n" " ${ t } "
elif [ $ret -eq 1 ] ; then
printf "TEST: %-60s [FAIL]\n" " ${ t } "
err_flush
exit 1
elif [ $ret -eq 2 ] ; then
printf "TEST: %-60s [SKIP]\n" " ${ t } "
err_flush
fi
)
[ $? -ne 0 ] && exitcode = 1
done
exit ${ exitcode }