Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause 2 : : * Copyright(c) 2020 Inspur Corporation 3 : : */ 4 : : 5 : : #ifndef _GRO_UDP4_H_ 6 : : #define _GRO_UDP4_H_ 7 : : 8 : : #include <rte_ip.h> 9 : : 10 : : #define INVALID_ARRAY_INDEX 0xffffffffUL 11 : : #define GRO_UDP4_TBL_MAX_ITEM_NUM (1024UL * 1024UL) 12 : : 13 : : /* 14 : : * The max length of a IPv4 packet, which includes the length of the L3 15 : : * header, the L4 header and the data payload. 16 : : */ 17 : : #define MAX_IPV4_PKT_LENGTH UINT16_MAX 18 : : 19 : : /* Header fields representing a UDP/IPv4 flow */ 20 : : struct udp4_flow_key { 21 : : struct rte_ether_addr eth_saddr; 22 : : struct rte_ether_addr eth_daddr; 23 : : uint32_t ip_src_addr; 24 : : uint32_t ip_dst_addr; 25 : : 26 : : /* IP fragment for UDP does not contain UDP header 27 : : * except the first one. But IP ID must be same. 28 : : */ 29 : : uint16_t ip_id; 30 : : }; 31 : : 32 : : struct gro_udp4_flow { 33 : : struct udp4_flow_key key; 34 : : /* 35 : : * The index of the first packet in the flow. 36 : : * INVALID_ARRAY_INDEX indicates an empty flow. 37 : : */ 38 : : uint32_t start_index; 39 : : }; 40 : : 41 : : struct gro_udp4_item { 42 : : /* 43 : : * The first MBUF segment of the packet. If the value 44 : : * is NULL, it means the item is empty. 45 : : */ 46 : : struct rte_mbuf *firstseg; 47 : : /* The last MBUF segment of the packet */ 48 : : struct rte_mbuf *lastseg; 49 : : /* 50 : : * The time when the first packet is inserted into the table. 51 : : * This value won't be updated, even if the packet is merged 52 : : * with other packets. 53 : : */ 54 : : uint64_t start_time; 55 : : /* 56 : : * next_pkt_idx is used to chain the packets that 57 : : * are in the same flow but can't be merged together 58 : : * (e.g. caused by packet reordering). 59 : : */ 60 : : uint32_t next_pkt_idx; 61 : : /* offset of IP fragment packet */ 62 : : uint16_t frag_offset; 63 : : /* is last IP fragment? */ 64 : : uint8_t is_last_frag; 65 : : /* the number of merged packets */ 66 : : uint16_t nb_merged; 67 : : }; 68 : : 69 : : /* 70 : : * UDP/IPv4 reassembly table structure. 71 : : */ 72 : : struct gro_udp4_tbl { 73 : : /* item array */ 74 : : struct gro_udp4_item *items; 75 : : /* flow array */ 76 : : struct gro_udp4_flow *flows; 77 : : /* current item number */ 78 : : uint32_t item_num; 79 : : /* current flow num */ 80 : : uint32_t flow_num; 81 : : /* item array size */ 82 : : uint32_t max_item_num; 83 : : /* flow array size */ 84 : : uint32_t max_flow_num; 85 : : }; 86 : : 87 : : /** 88 : : * This function creates a UDP/IPv4 reassembly table. 89 : : * 90 : : * @param socket_id 91 : : * Socket index for allocating the UDP/IPv4 reassemble table 92 : : * @param max_flow_num 93 : : * The maximum number of flows in the UDP/IPv4 GRO table 94 : : * @param max_item_per_flow 95 : : * The maximum number of packets per flow 96 : : * 97 : : * @return 98 : : * - Return the table pointer on success. 99 : : * - Return NULL on failure. 100 : : */ 101 : : void *gro_udp4_tbl_create(uint16_t socket_id, 102 : : uint16_t max_flow_num, 103 : : uint16_t max_item_per_flow); 104 : : 105 : : /** 106 : : * This function destroys a UDP/IPv4 reassembly table. 107 : : * 108 : : * @param tbl 109 : : * Pointer pointing to the UDP/IPv4 reassembly table. 110 : : */ 111 : : void gro_udp4_tbl_destroy(void *tbl); 112 : : 113 : : /** 114 : : * This function merges a UDP/IPv4 packet. 115 : : * 116 : : * This function does not check if the packet has correct checksums and 117 : : * does not re-calculate checksums for the merged packet. It returns the 118 : : * packet if it isn't UDP fragment or there is no available space in 119 : : * the table. 120 : : * 121 : : * @param pkt 122 : : * Packet to reassemble 123 : : * @param tbl 124 : : * Pointer pointing to the UDP/IPv4 reassembly table 125 : : * @start_time 126 : : * The time when the packet is inserted into the table 127 : : * 128 : : * @return 129 : : * - Return a positive value if the packet is merged. 130 : : * - Return zero if the packet isn't merged but stored in the table. 131 : : * - Return a negative value for invalid parameters or no available 132 : : * space in the table. 133 : : */ 134 : : int32_t gro_udp4_reassemble(struct rte_mbuf *pkt, 135 : : struct gro_udp4_tbl *tbl, 136 : : uint64_t start_time); 137 : : 138 : : /** 139 : : * This function flushes timeout packets in a UDP/IPv4 reassembly table, 140 : : * and without updating checksums. 141 : : * 142 : : * @param tbl 143 : : * UDP/IPv4 reassembly table pointer 144 : : * @param flush_timestamp 145 : : * Flush packets which are inserted into the table before or at the 146 : : * flush_timestamp. 147 : : * @param out 148 : : * Pointer array used to keep flushed packets 149 : : * @param nb_out 150 : : * The element number in 'out'. It also determines the maximum number of 151 : : * packets that can be flushed finally. 152 : : * 153 : : * @return 154 : : * The number of flushed packets 155 : : */ 156 : : uint16_t gro_udp4_tbl_timeout_flush(struct gro_udp4_tbl *tbl, 157 : : uint64_t flush_timestamp, 158 : : struct rte_mbuf **out, 159 : : uint16_t nb_out); 160 : : 161 : : /** 162 : : * This function returns the number of the packets in a UDP/IPv4 163 : : * reassembly table. 164 : : * 165 : : * @param tbl 166 : : * UDP/IPv4 reassembly table pointer 167 : : * 168 : : * @return 169 : : * The number of packets in the table 170 : : */ 171 : : uint32_t gro_udp4_tbl_pkt_count(void *tbl); 172 : : 173 : : /* 174 : : * Check if two UDP/IPv4 packets belong to the same flow. 175 : : */ 176 : : static inline int 177 : : is_same_udp4_flow(struct udp4_flow_key k1, struct udp4_flow_key k2) 178 : : { 179 [ # # ]: 0 : return (rte_is_same_ether_addr(&k1.eth_saddr, &k2.eth_saddr) && 180 [ # # ]: 0 : rte_is_same_ether_addr(&k1.eth_daddr, &k2.eth_daddr) && 181 [ # # ]: 0 : (k1.ip_src_addr == k2.ip_src_addr) && 182 [ # # # # ]: 0 : (k1.ip_dst_addr == k2.ip_dst_addr) && 183 : : (k1.ip_id == k2.ip_id)); 184 : : } 185 : : 186 : : /* 187 : : * Merge two UDP/IPv4 packets without updating checksums. 188 : : * If cmp is larger than 0, append the new packet to the 189 : : * original packet. Otherwise, pre-pend the new packet to 190 : : * the original packet. 191 : : */ 192 : : static inline int 193 : 0 : merge_two_udp4_packets(struct gro_udp4_item *item, 194 : : struct rte_mbuf *pkt, 195 : : int cmp, 196 : : uint16_t frag_offset, 197 : : uint8_t is_last_frag, 198 : : uint16_t l2_offset) 199 : : { 200 : : struct rte_mbuf *pkt_head, *pkt_tail, *lastseg; 201 : : uint16_t hdr_len, l2_len; 202 : : uint32_t ip_len; 203 : : 204 [ # # ]: 0 : if (cmp > 0) { 205 : 0 : pkt_head = item->firstseg; 206 : : pkt_tail = pkt; 207 : : } else { 208 : : pkt_head = pkt; 209 : 0 : pkt_tail = item->firstseg; 210 : : } 211 : : 212 : : /* check if the IPv4 packet length is greater than the max value */ 213 : 0 : hdr_len = l2_offset + pkt_head->l2_len + pkt_head->l3_len; 214 [ # # ]: 0 : l2_len = l2_offset > 0 ? pkt_head->outer_l2_len : pkt_head->l2_len; 215 : 0 : ip_len = pkt_head->pkt_len - l2_len 216 : 0 : + pkt_tail->pkt_len - hdr_len; 217 [ # # ]: 0 : if (unlikely(ip_len > MAX_IPV4_PKT_LENGTH)) 218 : : return 0; 219 : : 220 : : /* remove the packet header for the tail packet */ 221 : : rte_pktmbuf_adj(pkt_tail, hdr_len); 222 : : 223 : : /* chain two packets together */ 224 [ # # ]: 0 : if (cmp > 0) { 225 : 0 : item->lastseg->next = pkt; 226 : 0 : item->lastseg = rte_pktmbuf_lastseg(pkt); 227 : : } else { 228 : : lastseg = rte_pktmbuf_lastseg(pkt); 229 : 0 : lastseg->next = item->firstseg; 230 : 0 : item->firstseg = pkt; 231 : 0 : item->frag_offset = frag_offset; 232 : : } 233 : 0 : item->nb_merged++; 234 [ # # ]: 0 : if (is_last_frag) 235 : 0 : item->is_last_frag = is_last_frag; 236 : : 237 : : /* update MBUF metadata for the merged packet */ 238 : 0 : pkt_head->nb_segs += pkt_tail->nb_segs; 239 : 0 : pkt_head->pkt_len += pkt_tail->pkt_len; 240 : : 241 : 0 : return 1; 242 : : } 243 : : 244 : : /* 245 : : * Check if two UDP/IPv4 packets are neighbors. 246 : : */ 247 : : static inline int 248 : : udp4_check_neighbor(struct gro_udp4_item *item, 249 : : uint16_t frag_offset, 250 : : uint16_t ip_dl, 251 : : uint16_t l2_offset) 252 : : { 253 : 0 : struct rte_mbuf *pkt_orig = item->firstseg; 254 : : uint16_t len; 255 : : 256 : : /* check if the two packets are neighbors */ 257 : 0 : len = pkt_orig->pkt_len - l2_offset - pkt_orig->l2_len - 258 : 0 : pkt_orig->l3_len; 259 [ # # # # ]: 0 : if (frag_offset == item->frag_offset + len) 260 : : /* append the new packet */ 261 : : return 1; 262 [ # # # # ]: 0 : else if (frag_offset + ip_dl == item->frag_offset) 263 : : /* pre-pend the new packet */ 264 : : return -1; 265 : : 266 : : return 0; 267 : : } 268 : : 269 : : static inline int 270 : : is_ipv4_fragment(const struct rte_ipv4_hdr *hdr) 271 : : { 272 : : uint16_t flag_offset, ip_flag, ip_ofs; 273 : : 274 [ # # ]: 0 : flag_offset = rte_be_to_cpu_16(hdr->fragment_offset); 275 : : ip_ofs = (uint16_t)(flag_offset & RTE_IPV4_HDR_OFFSET_MASK); 276 : : ip_flag = (uint16_t)(flag_offset & RTE_IPV4_HDR_MF_FLAG); 277 : : 278 [ # # ]: 0 : return ip_flag != 0 || ip_ofs != 0; 279 : : } 280 : : #endif