@@ -1636,14 +1636,14 @@ static bool tun_can_build_skb(struct tun_struct *tun, struct tun_file *tfile,
16361636}
16371637
16381638static struct sk_buff * __tun_build_skb (struct page_frag * alloc_frag , char * buf ,
1639- int buflen , int len , int pad , int delta )
1639+ int buflen , int len , int pad )
16401640{
16411641 struct sk_buff * skb = build_skb (buf , buflen );
16421642
16431643 if (!skb )
16441644 return ERR_PTR (- ENOMEM );
16451645
1646- skb_reserve (skb , pad - delta );
1646+ skb_reserve (skb , pad );
16471647 skb_put (skb , len );
16481648
16491649 get_page (alloc_frag -> page );
@@ -1652,6 +1652,39 @@ static struct sk_buff *__tun_build_skb(struct page_frag *alloc_frag, char *buf,
16521652 return skb ;
16531653}
16541654
1655+ static int tun_xdp_act (struct tun_struct * tun , struct bpf_prog * xdp_prog ,
1656+ struct xdp_buff * xdp , u32 act )
1657+ {
1658+ int err ;
1659+
1660+ switch (act ) {
1661+ case XDP_REDIRECT :
1662+ err = xdp_do_redirect (tun -> dev , xdp , xdp_prog );
1663+ xdp_do_flush_map ();
1664+ if (err )
1665+ return err ;
1666+ break ;
1667+ case XDP_TX :
1668+ err = tun_xdp_tx (tun -> dev , xdp );
1669+ if (err < 0 )
1670+ return err ;
1671+ break ;
1672+ case XDP_PASS :
1673+ break ;
1674+ default :
1675+ bpf_warn_invalid_xdp_action (act );
1676+ /* fall through */
1677+ case XDP_ABORTED :
1678+ trace_xdp_exception (tun -> dev , xdp_prog , act );
1679+ /* fall through */
1680+ case XDP_DROP :
1681+ this_cpu_inc (tun -> pcpu_stats -> rx_dropped );
1682+ break ;
1683+ }
1684+
1685+ return act ;
1686+ }
1687+
16551688static struct sk_buff * tun_build_skb (struct tun_struct * tun ,
16561689 struct tun_file * tfile ,
16571690 struct iov_iter * from ,
@@ -1661,10 +1694,10 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun,
16611694 struct page_frag * alloc_frag = & current -> task_frag ;
16621695 struct bpf_prog * xdp_prog ;
16631696 int buflen = SKB_DATA_ALIGN (sizeof (struct skb_shared_info ));
1664- unsigned int delta = 0 ;
16651697 char * buf ;
16661698 size_t copied ;
1667- int err , pad = TUN_RX_PAD ;
1699+ int pad = TUN_RX_PAD ;
1700+ int err = 0 ;
16681701
16691702 rcu_read_lock ();
16701703 xdp_prog = rcu_dereference (tun -> xdp_prog );
@@ -1690,67 +1723,48 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun,
16901723 */
16911724 if (hdr -> gso_type || !xdp_prog ) {
16921725 * skb_xdp = 1 ;
1693- return __tun_build_skb (alloc_frag , buf , buflen , len , pad , delta );
1726+ return __tun_build_skb (alloc_frag , buf , buflen , len , pad );
16941727 }
16951728
16961729 * skb_xdp = 0 ;
16971730
16981731 local_bh_disable ();
16991732 rcu_read_lock ();
17001733 xdp_prog = rcu_dereference (tun -> xdp_prog );
1701- if (xdp_prog && ! * skb_xdp ) {
1734+ if (xdp_prog ) {
17021735 struct xdp_buff xdp ;
1703- void * orig_data ;
17041736 u32 act ;
17051737
17061738 xdp .data_hard_start = buf ;
17071739 xdp .data = buf + pad ;
17081740 xdp_set_data_meta_invalid (& xdp );
17091741 xdp .data_end = xdp .data + len ;
17101742 xdp .rxq = & tfile -> xdp_rxq ;
1711- orig_data = xdp .data ;
1712- act = bpf_prog_run_xdp (xdp_prog , & xdp );
17131743
1714- switch (act ) {
1715- case XDP_REDIRECT :
1716- get_page (alloc_frag -> page );
1717- alloc_frag -> offset += buflen ;
1718- err = xdp_do_redirect (tun -> dev , & xdp , xdp_prog );
1719- xdp_do_flush_map ();
1720- if (err )
1721- goto err_redirect ;
1722- goto out ;
1723- case XDP_TX :
1744+ act = bpf_prog_run_xdp (xdp_prog , & xdp );
1745+ if (act == XDP_REDIRECT || act == XDP_TX ) {
17241746 get_page (alloc_frag -> page );
17251747 alloc_frag -> offset += buflen ;
1726- if (tun_xdp_tx (tun -> dev , & xdp ) < 0 )
1727- goto err_redirect ;
1728- goto out ;
1729- case XDP_PASS :
1730- delta = orig_data - xdp .data ;
1731- len = xdp .data_end - xdp .data ;
1732- break ;
1733- default :
1734- bpf_warn_invalid_xdp_action (act );
1735- /* fall through */
1736- case XDP_ABORTED :
1737- trace_xdp_exception (tun -> dev , xdp_prog , act );
1738- /* fall through */
1739- case XDP_DROP :
1740- goto out ;
17411748 }
1749+ err = tun_xdp_act (tun , xdp_prog , & xdp , act );
1750+ if (err < 0 )
1751+ goto err_xdp ;
1752+ if (err != XDP_PASS )
1753+ goto out ;
1754+
1755+ pad = xdp .data - xdp .data_hard_start ;
1756+ len = xdp .data_end - xdp .data ;
17421757 }
17431758 rcu_read_unlock ();
17441759 local_bh_enable ();
17451760
1746- return __tun_build_skb (alloc_frag , buf , buflen , len , pad , delta );
1761+ return __tun_build_skb (alloc_frag , buf , buflen , len , pad );
17471762
1748- err_redirect :
1763+ err_xdp :
17491764 put_page (alloc_frag -> page );
17501765out :
17511766 rcu_read_unlock ();
17521767 local_bh_enable ();
1753- this_cpu_inc (tun -> pcpu_stats -> rx_dropped );
17541768 return NULL ;
17551769}
17561770
0 commit comments