@@ -938,6 +938,91 @@ static struct sk_buff *receive_big(struct net_device *dev,
938938 return NULL ;
939939}
940940
941+ /* TODO: build xdp in big mode */
942+ static int virtnet_build_xdp_buff_mrg (struct net_device * dev ,
943+ struct virtnet_info * vi ,
944+ struct receive_queue * rq ,
945+ struct xdp_buff * xdp ,
946+ void * buf ,
947+ unsigned int len ,
948+ unsigned int frame_sz ,
949+ u16 * num_buf ,
950+ unsigned int * xdp_frags_truesize ,
951+ struct virtnet_rq_stats * stats )
952+ {
953+ struct virtio_net_hdr_mrg_rxbuf * hdr = buf ;
954+ unsigned int headroom , tailroom , room ;
955+ unsigned int truesize , cur_frag_size ;
956+ struct skb_shared_info * shinfo ;
957+ unsigned int xdp_frags_truesz = 0 ;
958+ struct page * page ;
959+ skb_frag_t * frag ;
960+ int offset ;
961+ void * ctx ;
962+
963+ xdp_init_buff (xdp , frame_sz , & rq -> xdp_rxq );
964+ xdp_prepare_buff (xdp , buf - VIRTIO_XDP_HEADROOM ,
965+ VIRTIO_XDP_HEADROOM + vi -> hdr_len , len - vi -> hdr_len , true);
966+
967+ if (* num_buf > 1 ) {
968+ /* If we want to build multi-buffer xdp, we need
969+ * to specify that the flags of xdp_buff have the
970+ * XDP_FLAGS_HAS_FRAG bit.
971+ */
972+ if (!xdp_buff_has_frags (xdp ))
973+ xdp_buff_set_frags_flag (xdp );
974+
975+ shinfo = xdp_get_shared_info_from_buff (xdp );
976+ shinfo -> nr_frags = 0 ;
977+ shinfo -> xdp_frags_size = 0 ;
978+ }
979+
980+ if ((* num_buf - 1 ) > MAX_SKB_FRAGS )
981+ return - EINVAL ;
982+
983+ while ((-- * num_buf ) >= 1 ) {
984+ buf = virtqueue_get_buf_ctx (rq -> vq , & len , & ctx );
985+ if (unlikely (!buf )) {
986+ pr_debug ("%s: rx error: %d buffers out of %d missing\n" ,
987+ dev -> name , * num_buf ,
988+ virtio16_to_cpu (vi -> vdev , hdr -> num_buffers ));
989+ dev -> stats .rx_length_errors ++ ;
990+ return - EINVAL ;
991+ }
992+
993+ stats -> bytes += len ;
994+ page = virt_to_head_page (buf );
995+ offset = buf - page_address (page );
996+
997+ truesize = mergeable_ctx_to_truesize (ctx );
998+ headroom = mergeable_ctx_to_headroom (ctx );
999+ tailroom = headroom ? sizeof (struct skb_shared_info ) : 0 ;
1000+ room = SKB_DATA_ALIGN (headroom + tailroom );
1001+
1002+ cur_frag_size = truesize ;
1003+ xdp_frags_truesz += cur_frag_size ;
1004+ if (unlikely (len > truesize - room || cur_frag_size > PAGE_SIZE )) {
1005+ put_page (page );
1006+ pr_debug ("%s: rx error: len %u exceeds truesize %lu\n" ,
1007+ dev -> name , len , (unsigned long )(truesize - room ));
1008+ dev -> stats .rx_length_errors ++ ;
1009+ return - EINVAL ;
1010+ }
1011+
1012+ frag = & shinfo -> frags [shinfo -> nr_frags ++ ];
1013+ __skb_frag_set_page (frag , page );
1014+ skb_frag_off_set (frag , offset );
1015+ skb_frag_size_set (frag , len );
1016+ if (page_is_pfmemalloc (page ))
1017+ xdp_buff_set_frag_pfmemalloc (xdp );
1018+
1019+ shinfo -> xdp_frags_size += len ;
1020+ }
1021+
1022+ * xdp_frags_truesize = xdp_frags_truesz ;
1023+ return 0 ;
1024+ }
1025+
9411026static struct sk_buff * receive_mergeable (struct net_device * dev ,
9421027 struct virtnet_info * vi ,
9431028 struct receive_queue * rq ,
@@ -956,15 +1041,17 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
9561041 unsigned int truesize = mergeable_ctx_to_truesize (ctx );
9571042 unsigned int headroom = mergeable_ctx_to_headroom (ctx );
9581043 unsigned int metasize = 0 ;
1044+ unsigned int tailroom = headroom ? sizeof (struct skb_shared_info ) : 0 ;
1045+ unsigned int room = SKB_DATA_ALIGN (headroom + tailroom );
9591046 unsigned int frame_sz ;
9601047 int err ;
9611048
9621049 head_skb = NULL ;
9631050 stats -> bytes += len - vi -> hdr_len ;
9641051
965- if (unlikely (len > truesize )) {
1052+ if (unlikely (len > truesize - room )) {
9661053 pr_debug ("%s: rx error: len %u exceeds truesize %lu\n" ,
967- dev -> name , len , (unsigned long )ctx );
1054+ dev -> name , len , (unsigned long )( truesize - room ) );
9681055 dev -> stats .rx_length_errors ++ ;
9691056 goto err_skb ;
9701057 }
@@ -990,10 +1077,12 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
9901077 if (unlikely (hdr -> hdr .gso_type ))
9911078 goto err_xdp ;
9921079
993- /* Buffers with headroom use PAGE_SIZE as alloc size,
994- * see add_recvbuf_mergeable() + get_mergeable_buf_len()
1080+ /* Now XDP core assumes frag size is PAGE_SIZE, but buffers
1081+ * with headroom may add hole in truesize, which
1082+ * make their length exceed PAGE_SIZE. So we disabled the
1083+ * hole mechanism for xdp. See add_recvbuf_mergeable().
9951084 */
996- frame_sz = headroom ? PAGE_SIZE : truesize ;
1085+ frame_sz = truesize ;
9971086
9981087 /* This happens when rx buffer size is underestimated
9991088 * or headroom is not enough because of the buffer
@@ -1146,9 +1235,12 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
11461235 page = virt_to_head_page (buf );
11471236
11481237 truesize = mergeable_ctx_to_truesize (ctx );
1149- if (unlikely (len > truesize )) {
1238+ headroom = mergeable_ctx_to_headroom (ctx );
1239+ tailroom = headroom ? sizeof (struct skb_shared_info ) : 0 ;
1240+ room = SKB_DATA_ALIGN (headroom + tailroom );
1241+ if (unlikely (len > truesize - room )) {
11501242 pr_debug ("%s: rx error: len %u exceeds truesize %lu\n" ,
1151- dev -> name , len , (unsigned long )ctx );
1243+ dev -> name , len , (unsigned long )( truesize - room ) );
11521244 dev -> stats .rx_length_errors ++ ;
11531245 goto err_skb ;
11541246 }
@@ -1435,7 +1527,7 @@ static int add_recvbuf_mergeable(struct virtnet_info *vi,
14351527 }
14361528
14371529 sg_init_one (rq -> sg , buf , len );
1438- ctx = mergeable_len_to_ctx (len , headroom );
1530+ ctx = mergeable_len_to_ctx (len + room , headroom );
14391531 err = virtqueue_add_inbuf_ctx (rq -> vq , rq -> sg , 1 , buf , ctx , gfp );
14401532 if (err < 0 )
14411533 put_page (virt_to_head_page (buf ));
0 commit comments