Skip to content

Commit 9e2b7fa

Browse files
martinwillikuba-moo
authored andcommitted
vrf: Fix fast path output packet handling with async Netfilter rules
VRF devices use an optimized direct path on output if a default qdisc is involved, calling Netfilter hooks directly. This path, however, does not consider Netfilter rules completing asynchronously, such as with NFQUEUE. The Netfilter okfn() is called for asynchronously accepted packets, but the VRF never passes that packet down the stack to send it out over the slave device. Using the slower redirect path for this seems not feasible, as we do not know beforehand if a Netfilter hook has asynchronously completing rules. Fix the use of asynchronously completing Netfilter rules in OUTPUT and POSTROUTING by using a special completion function that additionally calls dst_output() to pass the packet down the stack. Also, slightly adjust the use of nf_reset_ct() so that is called in the asynchronous case, too. Fixes: dcdd43c ("net: vrf: performance improvements for IPv4") Fixes: a9ec54d ("net: vrf: performance improvements for IPv6") Signed-off-by: Martin Willi <martin@strongswan.org> Link: https://lore.kernel.org/r/20201106073030.3974927-1-martin@strongswan.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent 52755b6 commit 9e2b7fa

1 file changed

Lines changed: 69 additions & 23 deletions

File tree

drivers/net/vrf.c

Lines changed: 69 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -608,8 +608,7 @@ static netdev_tx_t vrf_xmit(struct sk_buff *skb, struct net_device *dev)
608608
return ret;
609609
}
610610

611-
static int vrf_finish_direct(struct net *net, struct sock *sk,
612-
struct sk_buff *skb)
611+
static void vrf_finish_direct(struct sk_buff *skb)
613612
{
614613
struct net_device *vrf_dev = skb->dev;
615614

@@ -628,7 +627,8 @@ static int vrf_finish_direct(struct net *net, struct sock *sk,
628627
skb_pull(skb, ETH_HLEN);
629628
}
630629

631-
return 1;
630+
/* reset skb device */
631+
nf_reset_ct(skb);
632632
}
633633

634634
#if IS_ENABLED(CONFIG_IPV6)
@@ -707,15 +707,41 @@ static struct sk_buff *vrf_ip6_out_redirect(struct net_device *vrf_dev,
707707
return skb;
708708
}
709709

710+
static int vrf_output6_direct_finish(struct net *net, struct sock *sk,
711+
struct sk_buff *skb)
712+
{
713+
vrf_finish_direct(skb);
714+
715+
return vrf_ip6_local_out(net, sk, skb);
716+
}
717+
710718
static int vrf_output6_direct(struct net *net, struct sock *sk,
711719
struct sk_buff *skb)
712720
{
721+
int err = 1;
722+
713723
skb->protocol = htons(ETH_P_IPV6);
714724

715-
return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING,
716-
net, sk, skb, NULL, skb->dev,
717-
vrf_finish_direct,
718-
!(IPCB(skb)->flags & IPSKB_REROUTED));
725+
if (!(IPCB(skb)->flags & IPSKB_REROUTED))
726+
err = nf_hook(NFPROTO_IPV6, NF_INET_POST_ROUTING, net, sk, skb,
727+
NULL, skb->dev, vrf_output6_direct_finish);
728+
729+
if (likely(err == 1))
730+
vrf_finish_direct(skb);
731+
732+
return err;
733+
}
734+
735+
static int vrf_ip6_out_direct_finish(struct net *net, struct sock *sk,
736+
struct sk_buff *skb)
737+
{
738+
int err;
739+
740+
err = vrf_output6_direct(net, sk, skb);
741+
if (likely(err == 1))
742+
err = vrf_ip6_local_out(net, sk, skb);
743+
744+
return err;
719745
}
720746

721747
static struct sk_buff *vrf_ip6_out_direct(struct net_device *vrf_dev,
@@ -728,18 +754,15 @@ static struct sk_buff *vrf_ip6_out_direct(struct net_device *vrf_dev,
728754
skb->dev = vrf_dev;
729755

730756
err = nf_hook(NFPROTO_IPV6, NF_INET_LOCAL_OUT, net, sk,
731-
skb, NULL, vrf_dev, vrf_output6_direct);
757+
skb, NULL, vrf_dev, vrf_ip6_out_direct_finish);
732758

733759
if (likely(err == 1))
734760
err = vrf_output6_direct(net, sk, skb);
735761

736-
/* reset skb device */
737762
if (likely(err == 1))
738-
nf_reset_ct(skb);
739-
else
740-
skb = NULL;
763+
return skb;
741764

742-
return skb;
765+
return NULL;
743766
}
744767

745768
static struct sk_buff *vrf_ip6_out(struct net_device *vrf_dev,
@@ -919,15 +942,41 @@ static struct sk_buff *vrf_ip_out_redirect(struct net_device *vrf_dev,
919942
return skb;
920943
}
921944

945+
static int vrf_output_direct_finish(struct net *net, struct sock *sk,
946+
struct sk_buff *skb)
947+
{
948+
vrf_finish_direct(skb);
949+
950+
return vrf_ip_local_out(net, sk, skb);
951+
}
952+
922953
static int vrf_output_direct(struct net *net, struct sock *sk,
923954
struct sk_buff *skb)
924955
{
956+
int err = 1;
957+
925958
skb->protocol = htons(ETH_P_IP);
926959

927-
return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING,
928-
net, sk, skb, NULL, skb->dev,
929-
vrf_finish_direct,
930-
!(IPCB(skb)->flags & IPSKB_REROUTED));
960+
if (!(IPCB(skb)->flags & IPSKB_REROUTED))
961+
err = nf_hook(NFPROTO_IPV4, NF_INET_POST_ROUTING, net, sk, skb,
962+
NULL, skb->dev, vrf_output_direct_finish);
963+
964+
if (likely(err == 1))
965+
vrf_finish_direct(skb);
966+
967+
return err;
968+
}
969+
970+
static int vrf_ip_out_direct_finish(struct net *net, struct sock *sk,
971+
struct sk_buff *skb)
972+
{
973+
int err;
974+
975+
err = vrf_output_direct(net, sk, skb);
976+
if (likely(err == 1))
977+
err = vrf_ip_local_out(net, sk, skb);
978+
979+
return err;
931980
}
932981

933982
static struct sk_buff *vrf_ip_out_direct(struct net_device *vrf_dev,
@@ -940,18 +989,15 @@ static struct sk_buff *vrf_ip_out_direct(struct net_device *vrf_dev,
940989
skb->dev = vrf_dev;
941990

942991
err = nf_hook(NFPROTO_IPV4, NF_INET_LOCAL_OUT, net, sk,
943-
skb, NULL, vrf_dev, vrf_output_direct);
992+
skb, NULL, vrf_dev, vrf_ip_out_direct_finish);
944993

945994
if (likely(err == 1))
946995
err = vrf_output_direct(net, sk, skb);
947996

948-
/* reset skb device */
949997
if (likely(err == 1))
950-
nf_reset_ct(skb);
951-
else
952-
skb = NULL;
998+
return skb;
953999

954-
return skb;
1000+
return NULL;
9551001
}
9561002

9571003
static struct sk_buff *vrf_ip_out(struct net_device *vrf_dev,

0 commit comments

Comments
 (0)