Commit c5cf13fb authored by David S. Miller's avatar David S. Miller

Merge branch 'ipv4-address-protocol'

Petr Machata says:

====================
net: Allow changing IPv4 address protocol

IPv4 and IPv6 addresses can be assigned a protocol value that indicates the
provenance of the IP address. The attribute is modeled after ip route
protocols, and essentially allows the administrator or userspace stack to
tag addresses in some way that makes sense to the actor in question.

When IP address protocol field was added in commit 47f0bd50 ("net: Add
new protocol attribute to IP addresses"), the semantics included the
ability to change the protocol for IPv6 addresses, but not for IPv4
addresses. It seems this was not deliberate, but rather by accident.

One particular use case is tagging the addresses differently depending on
whether the routing stack should advertise them or not. Without support for
protocol replacement, this can not be done.

In this patchset, extend IPv4 to allow changing the protocol defined at an
address (in patch #1). Then in patches #2 and #3 add selftest coverage for
ip address protocols.

Currently the kernel simply ignores the new value. Thus allowing the
replacement changes the observable behavior. However, since IPv6 already
behaves like this anyway, and since the feature as such is relatively new,
it seems like the change is safe to make.

An example session with the feature in action:

	bash-5.2# ip address add dev d 192.0.2.1/28 proto 0xab
	bash-5.2# ip address show dev d
	4: d: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 1000
	    link/ether 06:29:74:fd:1f:eb brd ff:ff:ff:ff:ff:ff
	    inet 192.0.2.1/28 scope global proto 0xab d
	       valid_lft forever preferred_lft forever

	bash-5.2# ip address replace dev d 192.0.2.1/28 proto 0x11
	bash-5.2# ip address show dev d
	4: d: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 1000
	    link/ether 06:29:74:fd:1f:eb brd ff:ff:ff:ff:ff:ff
	    inet 192.0.2.1/28 scope global proto 0x11 d
	       valid_lft forever preferred_lft forever
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 90bf6610 6a414fd7
...@@ -962,6 +962,7 @@ static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -962,6 +962,7 @@ static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
extack); extack);
} else { } else {
u32 new_metric = ifa->ifa_rt_priority; u32 new_metric = ifa->ifa_rt_priority;
u8 new_proto = ifa->ifa_proto;
inet_free_ifa(ifa); inet_free_ifa(ifa);
...@@ -975,6 +976,8 @@ static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -975,6 +976,8 @@ static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
ifa->ifa_rt_priority = new_metric; ifa->ifa_rt_priority = new_metric;
} }
ifa->ifa_proto = new_proto;
set_ifa_lifetime(ifa, valid_lft, prefered_lft); set_ifa_lifetime(ifa, valid_lft, prefered_lft);
cancel_delayed_work(&check_lifetime_work); cancel_delayed_work(&check_lifetime_work);
queue_delayed_work(system_power_efficient_wq, queue_delayed_work(system_power_efficient_wq,
......
...@@ -4,6 +4,31 @@ ...@@ -4,6 +4,31 @@
# #
# set -e # set -e
ALL_TESTS="
kci_test_polrouting
kci_test_route_get
kci_test_addrlft
kci_test_promote_secondaries
kci_test_tc
kci_test_gre
kci_test_gretap
kci_test_ip6gretap
kci_test_erspan
kci_test_ip6erspan
kci_test_bridge
kci_test_addrlabel
kci_test_ifalias
kci_test_vrf
kci_test_encap
kci_test_macsec
kci_test_ipsec
kci_test_ipsec_offload
kci_test_fdb_get
kci_test_neigh_get
kci_test_bridge_parent_id
kci_test_address_proto
"
devdummy="test-dummy0" devdummy="test-dummy0"
# Kselftest framework requirement - SKIP code is 4. # Kselftest framework requirement - SKIP code is 4.
...@@ -1225,62 +1250,126 @@ kci_test_bridge_parent_id() ...@@ -1225,62 +1250,126 @@ kci_test_bridge_parent_id()
echo "PASS: bridge_parent_id" echo "PASS: bridge_parent_id"
} }
kci_test_rtnl() address_get_proto()
{
local addr=$1; shift
ip -N -j address show dev "$devdummy" |
jq -e -r --arg addr "${addr%/*}" \
'.[].addr_info[] | select(.local == $addr) | .protocol'
}
address_count()
{
ip -N -j address show dev "$devdummy" "$@" |
jq -e -r '[.[].addr_info[] | .local | select(. != null)] | length'
}
do_test_address_proto()
{ {
local what=$1; shift
local addr=$1; shift
local addr2=${addr%/*}2/${addr#*/}
local addr3=${addr%/*}3/${addr#*/}
local proto
local count
local ret=0 local ret=0
kci_add_dummy local err
if [ $ret -ne 0 ];then
echo "FAIL: cannot add dummy interface"
return 1
fi
kci_test_polrouting ip address add dev "$devdummy" "$addr3"
check_err $?
kci_test_route_get
check_err $?
kci_test_addrlft
check_err $?
kci_test_promote_secondaries
check_err $? check_err $?
kci_test_tc proto=$(address_get_proto "$addr3")
[[ "$proto" == null ]]
check_err $? check_err $?
kci_test_gre
check_err $? ip address add dev "$devdummy" "$addr2" proto 0x99
kci_test_gretap
check_err $?
kci_test_ip6gretap
check_err $?
kci_test_erspan
check_err $?
kci_test_ip6erspan
check_err $? check_err $?
kci_test_bridge proto=$(address_get_proto "$addr2")
[[ "$proto" == 0x99 ]]
check_err $? check_err $?
kci_test_addrlabel
ip address add dev "$devdummy" "$addr" proto 0xab
check_err $? check_err $?
kci_test_ifalias proto=$(address_get_proto "$addr")
[[ "$proto" == 0xab ]]
check_err $? check_err $?
kci_test_vrf
ip address replace dev "$devdummy" "$addr" proto 0x11
proto=$(address_get_proto "$addr")
check_err $? check_err $?
kci_test_encap [[ "$proto" == 0x11 ]]
check_err $? check_err $?
kci_test_macsec
count=$(address_count)
check_err $? check_err $?
kci_test_ipsec (( count == 3 )) # $addr, $addr2 and $addr3
count=$(address_count proto 0)
check_err $? check_err $?
kci_test_ipsec_offload (( count == 1 )) # just $addr2
count=$(address_count proto 0x11)
check_err $? check_err $?
kci_test_fdb_get (( count == 2 )) # $addr and $addr2
count=$(address_count proto 0xab)
check_err $? check_err $?
kci_test_neigh_get (( count == 1 )) # just $addr2
ip address del dev "$devdummy" "$addr"
ip address del dev "$devdummy" "$addr2"
ip address del dev "$devdummy" "$addr3"
if [ $ret -ne 0 ]; then
echo "FAIL: address proto $what"
return 1
fi
echo "PASS: address proto $what"
}
kci_test_address_proto()
{
local ret=0
do_test_address_proto IPv4 192.0.2.1/28
check_err $? check_err $?
kci_test_bridge_parent_id
do_test_address_proto IPv6 2001:db8:1::1/64
check_err $? check_err $?
return $ret
}
kci_test_rtnl()
{
local current_test
local ret=0
kci_add_dummy
if [ $ret -ne 0 ];then
echo "FAIL: cannot add dummy interface"
return 1
fi
for current_test in ${TESTS:-$ALL_TESTS}; do
$current_test
check_err $?
done
kci_del_dummy kci_del_dummy
return $ret return $ret
} }
usage()
{
cat <<EOF
usage: ${0##*/} OPTS
-t <test> Test(s) to run (default: all)
(options: $(echo $ALL_TESTS))
EOF
}
#check for needed privileges #check for needed privileges
if [ "$(id -u)" -ne 0 ];then if [ "$(id -u)" -ne 0 ];then
echo "SKIP: Need root privileges" echo "SKIP: Need root privileges"
...@@ -1295,6 +1384,14 @@ for x in ip tc;do ...@@ -1295,6 +1384,14 @@ for x in ip tc;do
fi fi
done done
while getopts t:h o; do
case $o in
t) TESTS=$OPTARG;;
h) usage; exit 0;;
*) usage; exit 1;;
esac
done
kci_test_rtnl kci_test_rtnl
exit $? exit $?
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment