Commit 68fe503c authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'ipmr-always-call-ip-6-_mr_forward-from-rcu-read-side-critical-section'

Ido Schimmel says:

====================
ipmr: Always call ip{,6}_mr_forward() from RCU read-side critical section

Patch #1 fixes a bug in ipmr code.

Patch #2 adds corresponding test cases.
====================

Link: https://lore.kernel.org/r/20220914075339.4074096-1-idosch@nvidia.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents cf412ec3 2b5a8c8f
...@@ -1004,7 +1004,9 @@ static void ipmr_cache_resolve(struct net *net, struct mr_table *mrt, ...@@ -1004,7 +1004,9 @@ static void ipmr_cache_resolve(struct net *net, struct mr_table *mrt,
rtnl_unicast(skb, net, NETLINK_CB(skb).portid); rtnl_unicast(skb, net, NETLINK_CB(skb).portid);
} else { } else {
rcu_read_lock();
ip_mr_forward(net, mrt, skb->dev, skb, c, 0); ip_mr_forward(net, mrt, skb->dev, skb, c, 0);
rcu_read_unlock();
} }
} }
} }
......
...@@ -1028,8 +1028,11 @@ static void ip6mr_cache_resolve(struct net *net, struct mr_table *mrt, ...@@ -1028,8 +1028,11 @@ static void ip6mr_cache_resolve(struct net *net, struct mr_table *mrt,
((struct nlmsgerr *)nlmsg_data(nlh))->error = -EMSGSIZE; ((struct nlmsgerr *)nlmsg_data(nlh))->error = -EMSGSIZE;
} }
rtnl_unicast(skb, net, NETLINK_CB(skb).portid); rtnl_unicast(skb, net, NETLINK_CB(skb).portid);
} else } else {
rcu_read_lock();
ip6_mr_forward(net, mrt, skb->dev, skb, c); ip6_mr_forward(net, mrt, skb->dev, skb, c);
rcu_read_unlock();
}
} }
} }
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
# +------------------+ +------------------+ # +------------------+ +------------------+
# #
ALL_TESTS="mcast_v4 mcast_v6 rpf_v4 rpf_v6" ALL_TESTS="mcast_v4 mcast_v6 rpf_v4 rpf_v6 unres_v4 unres_v6"
NUM_NETIFS=6 NUM_NETIFS=6
source lib.sh source lib.sh
source tc_common.sh source tc_common.sh
...@@ -406,6 +406,96 @@ rpf_v6() ...@@ -406,6 +406,96 @@ rpf_v6()
log_test "RPF IPv6" log_test "RPF IPv6"
} }
unres_v4()
{
# Send a multicast packet not corresponding to an installed route,
# causing the kernel to queue the packet for resolution and emit an
# IGMPMSG_NOCACHE notification. smcrouted will react to this
# notification by consulting its (*, G) list and installing an (S, G)
# route, which will be used to forward the queued packet.
RET=0
tc filter add dev $h2 ingress protocol ip pref 1 handle 1 flower \
dst_ip 225.1.2.3 ip_proto udp dst_port 12345 action drop
tc filter add dev $h3 ingress protocol ip pref 1 handle 1 flower \
dst_ip 225.1.2.3 ip_proto udp dst_port 12345 action drop
# Forwarding should fail before installing a matching (*, G).
$MZ $h1 -c 1 -p 128 -t udp "ttl=10,sp=54321,dp=12345" \
-a 00:11:22:33:44:55 -b 01:00:5e:01:02:03 \
-A 198.51.100.2 -B 225.1.2.3 -q
tc_check_packets "dev $h2 ingress" 1 0
check_err $? "Multicast received on first host when should not"
tc_check_packets "dev $h3 ingress" 1 0
check_err $? "Multicast received on second host when should not"
# Create (*, G). Will not be installed in the kernel.
create_mcast_sg $rp1 0.0.0.0 225.1.2.3 $rp2 $rp3
$MZ $h1 -c 1 -p 128 -t udp "ttl=10,sp=54321,dp=12345" \
-a 00:11:22:33:44:55 -b 01:00:5e:01:02:03 \
-A 198.51.100.2 -B 225.1.2.3 -q
tc_check_packets "dev $h2 ingress" 1 1
check_err $? "Multicast not received on first host"
tc_check_packets "dev $h3 ingress" 1 1
check_err $? "Multicast not received on second host"
delete_mcast_sg $rp1 0.0.0.0 225.1.2.3 $rp2 $rp3
tc filter del dev $h3 ingress protocol ip pref 1 handle 1 flower
tc filter del dev $h2 ingress protocol ip pref 1 handle 1 flower
log_test "Unresolved queue IPv4"
}
unres_v6()
{
# Send a multicast packet not corresponding to an installed route,
# causing the kernel to queue the packet for resolution and emit an
# MRT6MSG_NOCACHE notification. smcrouted will react to this
# notification by consulting its (*, G) list and installing an (S, G)
# route, which will be used to forward the queued packet.
RET=0
tc filter add dev $h2 ingress protocol ipv6 pref 1 handle 1 flower \
dst_ip ff0e::3 ip_proto udp dst_port 12345 action drop
tc filter add dev $h3 ingress protocol ipv6 pref 1 handle 1 flower \
dst_ip ff0e::3 ip_proto udp dst_port 12345 action drop
# Forwarding should fail before installing a matching (*, G).
$MZ $h1 -6 -c 1 -p 128 -t udp "ttl=10,sp=54321,dp=12345" \
-a 00:11:22:33:44:55 -b 33:33:00:00:00:03 \
-A 2001:db8:1::2 -B ff0e::3 -q
tc_check_packets "dev $h2 ingress" 1 0
check_err $? "Multicast received on first host when should not"
tc_check_packets "dev $h3 ingress" 1 0
check_err $? "Multicast received on second host when should not"
# Create (*, G). Will not be installed in the kernel.
create_mcast_sg $rp1 :: ff0e::3 $rp2 $rp3
$MZ $h1 -6 -c 1 -p 128 -t udp "ttl=10,sp=54321,dp=12345" \
-a 00:11:22:33:44:55 -b 33:33:00:00:00:03 \
-A 2001:db8:1::2 -B ff0e::3 -q
tc_check_packets "dev $h2 ingress" 1 1
check_err $? "Multicast not received on first host"
tc_check_packets "dev $h3 ingress" 1 1
check_err $? "Multicast not received on second host"
delete_mcast_sg $rp1 :: ff0e::3 $rp2 $rp3
tc filter del dev $h3 ingress protocol ipv6 pref 1 handle 1 flower
tc filter del dev $h2 ingress protocol ipv6 pref 1 handle 1 flower
log_test "Unresolved queue IPv6"
}
trap cleanup EXIT trap cleanup EXIT
setup_prepare setup_prepare
......
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