Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause 2 : : * Copyright(c) 2020 Inspur Corporation 3 : : */ 4 : : 5 : : #include "gso_common.h" 6 : : #include "gso_tunnel_udp4.h" 7 : : 8 : : #define IPV4_HDR_MF_BIT (1U << 13) 9 : : 10 : : static void 11 : 0 : update_tunnel_ipv4_udp_headers(struct rte_mbuf *pkt, struct rte_mbuf **segs, 12 : : uint16_t nb_segs) 13 : : { 14 : : struct rte_ipv4_hdr *ipv4_hdr; 15 : : uint16_t outer_id, inner_id, tail_idx, i, length; 16 : : uint16_t outer_ipv4_offset, inner_ipv4_offset; 17 : : uint16_t outer_udp_offset; 18 : : uint16_t frag_offset = 0, is_mf; 19 : : 20 : 0 : outer_ipv4_offset = pkt->outer_l2_len; 21 : 0 : outer_udp_offset = outer_ipv4_offset + pkt->outer_l3_len; 22 : 0 : inner_ipv4_offset = outer_udp_offset + pkt->l2_len; 23 : : 24 : : /* Outer IPv4 header. */ 25 : 0 : ipv4_hdr = (struct rte_ipv4_hdr *)(rte_pktmbuf_mtod(pkt, char *) + 26 : : outer_ipv4_offset); 27 [ # # ]: 0 : outer_id = rte_be_to_cpu_16(ipv4_hdr->packet_id); 28 : : 29 : : /* Inner IPv4 header. */ 30 : 0 : ipv4_hdr = (struct rte_ipv4_hdr *)(rte_pktmbuf_mtod(pkt, char *) + 31 : : inner_ipv4_offset); 32 [ # # ]: 0 : inner_id = rte_be_to_cpu_16(ipv4_hdr->packet_id); 33 : : 34 : 0 : tail_idx = nb_segs - 1; 35 : : 36 [ # # ]: 0 : for (i = 0; i < nb_segs; i++) { 37 : 0 : update_ipv4_header(segs[i], outer_ipv4_offset, outer_id); 38 : : update_udp_header(segs[i], outer_udp_offset); 39 : 0 : update_ipv4_header(segs[i], inner_ipv4_offset, inner_id); 40 : : /* For the case inner packet is UDP, we must keep UDP 41 : : * datagram boundary, it must be handled as IP fragment. 42 : : * 43 : : * Set IP fragment offset for inner IP header. 44 : : */ 45 : 0 : ipv4_hdr = (struct rte_ipv4_hdr *) 46 : 0 : (rte_pktmbuf_mtod(segs[i], char *) + 47 : : inner_ipv4_offset); 48 [ # # ]: 0 : is_mf = i < tail_idx ? IPV4_HDR_MF_BIT : 0; 49 : 0 : ipv4_hdr->fragment_offset = 50 [ # # ]: 0 : rte_cpu_to_be_16(frag_offset | is_mf); 51 : 0 : length = segs[i]->pkt_len - inner_ipv4_offset - pkt->l3_len; 52 : 0 : frag_offset += (length >> 3); 53 : 0 : outer_id++; 54 : : } 55 : 0 : } 56 : : 57 : : int 58 : 0 : gso_tunnel_udp4_segment(struct rte_mbuf *pkt, 59 : : uint16_t gso_size, 60 : : struct rte_mempool *direct_pool, 61 : : struct rte_mempool *indirect_pool, 62 : : struct rte_mbuf **pkts_out, 63 : : uint16_t nb_pkts_out) 64 : : { 65 : : struct rte_ipv4_hdr *inner_ipv4_hdr; 66 : : uint16_t pyld_unit_size, hdr_offset, frag_off; 67 : : int ret; 68 : : 69 : 0 : hdr_offset = pkt->outer_l2_len + pkt->outer_l3_len + pkt->l2_len; 70 : 0 : inner_ipv4_hdr = (struct rte_ipv4_hdr *)(rte_pktmbuf_mtod(pkt, char *) + 71 : : hdr_offset); 72 : : /* 73 : : * Don't process the packet whose MF bit or offset in the inner 74 : : * IPv4 header are non-zero. 75 : : */ 76 [ # # ]: 0 : frag_off = rte_be_to_cpu_16(inner_ipv4_hdr->fragment_offset); 77 [ # # ]: 0 : if (unlikely(IS_FRAGMENTED(frag_off))) 78 : : return 0; 79 : : 80 : 0 : hdr_offset += pkt->l3_len; 81 : : /* Don't process the packet without data */ 82 [ # # ]: 0 : if ((hdr_offset + pkt->l4_len) >= pkt->pkt_len) 83 : : return 0; 84 : : 85 : : /* pyld_unit_size must be a multiple of 8 because frag_off 86 : : * uses 8 bytes as unit. 87 : : */ 88 : 0 : pyld_unit_size = (gso_size - hdr_offset) & ~7U; 89 : : 90 : : /* Segment the payload */ 91 : 0 : ret = gso_do_segment(pkt, hdr_offset, pyld_unit_size, direct_pool, 92 : : indirect_pool, pkts_out, nb_pkts_out); 93 [ # # ]: 0 : if (ret > 1) 94 : 0 : update_tunnel_ipv4_udp_headers(pkt, pkts_out, ret); 95 : : 96 : : return ret; 97 : : }