Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

vrf: don't run conntrack on vrf with !dflt qdisc

After the below patch, the conntrack attached to skb is set to "notrack" in
the context of vrf device, for locally generated packets.
But this is true only when the default qdisc is set to the vrf device. When
changing the qdisc, notrack is not set anymore.
In fact, there is a shortcut in the vrf driver, when the default qdisc is
set, see commit dcdd43c41e60 ("net: vrf: performance improvements for
IPv4") for more details.

This patch ensures that the behavior is always the same, whatever the qdisc
is.

To demonstrate the difference, a new test is added in conntrack_vrf.sh.

Fixes: 8c9c296adfae ("vrf: run conntrack only in context of lower/physdev for locally generated packets")
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Acked-by: Florian Westphal <fw@strlen.de>
Reviewed-by: David Ahern <dsahern@kernel.org>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Nicolas Dichtel and committed by
Pablo Neira Ayuso
d43b75fb b43c2793

+30 -8
+4 -4
drivers/net/vrf.c
··· 768 768 769 769 skb->dev = vrf_dev; 770 770 771 - vrf_nf_set_untracked(skb); 772 - 773 771 err = nf_hook(NFPROTO_IPV6, NF_INET_LOCAL_OUT, net, sk, 774 772 skb, NULL, vrf_dev, vrf_ip6_out_direct_finish); 775 773 ··· 787 789 /* don't divert link scope packets */ 788 790 if (rt6_need_strict(&ipv6_hdr(skb)->daddr)) 789 791 return skb; 792 + 793 + vrf_nf_set_untracked(skb); 790 794 791 795 if (qdisc_tx_is_default(vrf_dev) || 792 796 IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) ··· 998 998 999 999 skb->dev = vrf_dev; 1000 1000 1001 - vrf_nf_set_untracked(skb); 1002 - 1003 1001 err = nf_hook(NFPROTO_IPV4, NF_INET_LOCAL_OUT, net, sk, 1004 1002 skb, NULL, vrf_dev, vrf_ip_out_direct_finish); 1005 1003 ··· 1018 1020 if (ipv4_is_multicast(ip_hdr(skb)->daddr) || 1019 1021 ipv4_is_lbcast(ip_hdr(skb)->daddr)) 1020 1022 return skb; 1023 + 1024 + vrf_nf_set_untracked(skb); 1021 1025 1022 1026 if (qdisc_tx_is_default(vrf_dev) || 1023 1027 IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED)
+26 -4
tools/testing/selftests/netfilter/conntrack_vrf.sh
··· 150 150 # oifname is the vrf device. 151 151 test_masquerade_vrf() 152 152 { 153 + local qdisc=$1 154 + 155 + if [ "$qdisc" != "default" ]; then 156 + tc -net $ns0 qdisc add dev tvrf root $qdisc 157 + fi 158 + 153 159 ip netns exec $ns0 conntrack -F 2>/dev/null 154 160 155 161 ip netns exec $ns0 nft -f - <<EOF 156 162 flush ruleset 157 163 table ip nat { 164 + chain rawout { 165 + type filter hook output priority raw; 166 + 167 + oif tvrf ct state untracked counter 168 + } 169 + chain postrouting2 { 170 + type filter hook postrouting priority mangle; 171 + 172 + oif tvrf ct state untracked counter 173 + } 158 174 chain postrouting { 159 175 type nat hook postrouting priority 0; 160 176 # NB: masquerade should always be combined with 'oif(name) bla', ··· 187 171 fi 188 172 189 173 # must also check that nat table was evaluated on second (lower device) iteration. 190 - ip netns exec $ns0 nft list table ip nat |grep -q 'counter packets 2' 174 + ip netns exec $ns0 nft list table ip nat |grep -q 'counter packets 2' && 175 + ip netns exec $ns0 nft list table ip nat |grep -q 'untracked counter packets [1-9]' 191 176 if [ $? -eq 0 ]; then 192 - echo "PASS: iperf3 connect with masquerade + sport rewrite on vrf device" 177 + echo "PASS: iperf3 connect with masquerade + sport rewrite on vrf device ($qdisc qdisc)" 193 178 else 194 - echo "FAIL: vrf masq rule has unexpected counter value" 179 + echo "FAIL: vrf rules have unexpected counter value" 195 180 ret=1 181 + fi 182 + 183 + if [ "$qdisc" != "default" ]; then 184 + tc -net $ns0 qdisc del dev tvrf root 196 185 fi 197 186 } 198 187 ··· 234 213 } 235 214 236 215 test_ct_zone_in 237 - test_masquerade_vrf 216 + test_masquerade_vrf "default" 217 + test_masquerade_vrf "pfifo" 238 218 test_masquerade_veth 239 219 240 220 exit $ret