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