1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2014 Intel Corporation 3 */ 4 #include <string.h> 5 6 #include <rte_ether.h> 7 #include <rte_ip_frag.h> 8 #include <rte_cycles.h> 9 #include <rte_log.h> 10 11 #include "rte_port_ras.h" 12 13 #ifndef RTE_PORT_RAS_N_BUCKETS 14 #define RTE_PORT_RAS_N_BUCKETS 4094 15 #endif 16 17 #ifndef RTE_PORT_RAS_N_ENTRIES_PER_BUCKET 18 #define RTE_PORT_RAS_N_ENTRIES_PER_BUCKET 8 19 #endif 20 21 #ifndef RTE_PORT_RAS_N_ENTRIES 22 #define RTE_PORT_RAS_N_ENTRIES (RTE_PORT_RAS_N_BUCKETS * RTE_PORT_RAS_N_ENTRIES_PER_BUCKET) 23 #endif 24 25 #ifdef RTE_PORT_STATS_COLLECT 26 27 #define RTE_PORT_RING_WRITER_RAS_STATS_PKTS_IN_ADD(port, val) \ 28 port->stats.n_pkts_in += val 29 #define RTE_PORT_RING_WRITER_RAS_STATS_PKTS_DROP_ADD(port, val) \ 30 port->stats.n_pkts_drop += val 31 32 #else 33 34 #define RTE_PORT_RING_WRITER_RAS_STATS_PKTS_IN_ADD(port, val) 35 #define RTE_PORT_RING_WRITER_RAS_STATS_PKTS_DROP_ADD(port, val) 36 37 #endif 38 39 struct rte_port_ring_writer_ras; 40 41 typedef void (*ras_op)( 42 struct rte_port_ring_writer_ras *p, 43 struct rte_mbuf *pkt); 44 45 static void 46 process_ipv4(struct rte_port_ring_writer_ras *p, struct rte_mbuf *pkt); 47 static void 48 process_ipv6(struct rte_port_ring_writer_ras *p, struct rte_mbuf *pkt); 49 50 struct rte_port_ring_writer_ras { 51 struct rte_port_out_stats stats; 52 53 struct rte_mbuf *tx_buf[RTE_PORT_IN_BURST_SIZE_MAX]; 54 struct rte_ring *ring; 55 uint32_t tx_burst_sz; 56 uint32_t tx_buf_count; 57 struct rte_ip_frag_tbl *frag_tbl; 58 struct rte_ip_frag_death_row death_row; 59 60 ras_op f_ras; 61 }; 62 63 static void * 64 rte_port_ring_writer_ras_create(void *params, int socket_id, int is_ipv4) 65 { 66 struct rte_port_ring_writer_ras_params *conf = 67 params; 68 struct rte_port_ring_writer_ras *port; 69 uint64_t frag_cycles; 70 71 /* Check input parameters */ 72 if (conf == NULL) { 73 RTE_LOG(ERR, PORT, "%s: Parameter conf is NULL\n", __func__); 74 return NULL; 75 } 76 if (conf->ring == NULL) { 77 RTE_LOG(ERR, PORT, "%s: Parameter ring is NULL\n", __func__); 78 return NULL; 79 } 80 if ((conf->tx_burst_sz == 0) || 81 (conf->tx_burst_sz > RTE_PORT_IN_BURST_SIZE_MAX)) { 82 RTE_LOG(ERR, PORT, "%s: Parameter tx_burst_sz is invalid\n", 83 __func__); 84 return NULL; 85 } 86 87 /* Memory allocation */ 88 port = rte_zmalloc_socket("PORT", sizeof(*port), 89 RTE_CACHE_LINE_SIZE, socket_id); 90 if (port == NULL) { 91 RTE_LOG(ERR, PORT, "%s: Failed to allocate socket\n", __func__); 92 return NULL; 93 } 94 95 /* Create fragmentation table */ 96 frag_cycles = (rte_get_tsc_hz() + MS_PER_S - 1) / MS_PER_S * MS_PER_S; 97 frag_cycles *= 100; 98 99 port->frag_tbl = rte_ip_frag_table_create( 100 RTE_PORT_RAS_N_BUCKETS, 101 RTE_PORT_RAS_N_ENTRIES_PER_BUCKET, 102 RTE_PORT_RAS_N_ENTRIES, 103 frag_cycles, 104 socket_id); 105 106 if (port->frag_tbl == NULL) { 107 RTE_LOG(ERR, PORT, "%s: rte_ip_frag_table_create failed\n", 108 __func__); 109 rte_free(port); 110 return NULL; 111 } 112 113 /* Initialization */ 114 port->ring = conf->ring; 115 port->tx_burst_sz = conf->tx_burst_sz; 116 port->tx_buf_count = 0; 117 118 port->f_ras = (is_ipv4 == 1) ? process_ipv4 : process_ipv6; 119 120 return port; 121 } 122 123 static void * 124 rte_port_ring_writer_ipv4_ras_create(void *params, int socket_id) 125 { 126 return rte_port_ring_writer_ras_create(params, socket_id, 1); 127 } 128 129 static void * 130 rte_port_ring_writer_ipv6_ras_create(void *params, int socket_id) 131 { 132 return rte_port_ring_writer_ras_create(params, socket_id, 0); 133 } 134 135 static inline void 136 send_burst(struct rte_port_ring_writer_ras *p) 137 { 138 uint32_t nb_tx; 139 140 nb_tx = rte_ring_sp_enqueue_burst(p->ring, (void **)p->tx_buf, 141 p->tx_buf_count, NULL); 142 143 RTE_PORT_RING_WRITER_RAS_STATS_PKTS_DROP_ADD(p, p->tx_buf_count - nb_tx); 144 for ( ; nb_tx < p->tx_buf_count; nb_tx++) 145 rte_pktmbuf_free(p->tx_buf[nb_tx]); 146 147 p->tx_buf_count = 0; 148 } 149 150 static void 151 process_ipv4(struct rte_port_ring_writer_ras *p, struct rte_mbuf *pkt) 152 { 153 /* Assume there is no ethernet header */ 154 struct rte_ipv4_hdr *pkt_hdr = 155 rte_pktmbuf_mtod(pkt, struct rte_ipv4_hdr *); 156 157 /* Get "More fragments" flag and fragment offset */ 158 uint16_t frag_field = rte_be_to_cpu_16(pkt_hdr->fragment_offset); 159 uint16_t frag_offset = (uint16_t)(frag_field & RTE_IPV4_HDR_OFFSET_MASK); 160 uint16_t frag_flag = (uint16_t)(frag_field & RTE_IPV4_HDR_MF_FLAG); 161 162 /* If it is a fragmented packet, then try to reassemble */ 163 if ((frag_flag == 0) && (frag_offset == 0)) 164 p->tx_buf[p->tx_buf_count++] = pkt; 165 else { 166 struct rte_mbuf *mo; 167 struct rte_ip_frag_tbl *tbl = p->frag_tbl; 168 struct rte_ip_frag_death_row *dr = &p->death_row; 169 170 pkt->l3_len = sizeof(*pkt_hdr); 171 172 /* Process this fragment */ 173 mo = rte_ipv4_frag_reassemble_packet(tbl, dr, pkt, rte_rdtsc(), 174 pkt_hdr); 175 if (mo != NULL) 176 p->tx_buf[p->tx_buf_count++] = mo; 177 178 rte_ip_frag_free_death_row(&p->death_row, 3); 179 } 180 } 181 182 static void 183 process_ipv6(struct rte_port_ring_writer_ras *p, struct rte_mbuf *pkt) 184 { 185 /* Assume there is no ethernet header */ 186 struct rte_ipv6_hdr *pkt_hdr = 187 rte_pktmbuf_mtod(pkt, struct rte_ipv6_hdr *); 188 189 struct ipv6_extension_fragment *frag_hdr; 190 uint16_t frag_data = 0; 191 frag_hdr = rte_ipv6_frag_get_ipv6_fragment_header(pkt_hdr); 192 if (frag_hdr != NULL) 193 frag_data = rte_be_to_cpu_16(frag_hdr->frag_data); 194 195 /* If it is a fragmented packet, then try to reassemble */ 196 if ((frag_data & RTE_IPV6_FRAG_USED_MASK) == 0) 197 p->tx_buf[p->tx_buf_count++] = pkt; 198 else { 199 struct rte_mbuf *mo; 200 struct rte_ip_frag_tbl *tbl = p->frag_tbl; 201 struct rte_ip_frag_death_row *dr = &p->death_row; 202 203 pkt->l3_len = sizeof(*pkt_hdr) + sizeof(*frag_hdr); 204 205 /* Process this fragment */ 206 mo = rte_ipv6_frag_reassemble_packet(tbl, dr, pkt, rte_rdtsc(), pkt_hdr, 207 frag_hdr); 208 if (mo != NULL) 209 p->tx_buf[p->tx_buf_count++] = mo; 210 211 rte_ip_frag_free_death_row(&p->death_row, 3); 212 } 213 } 214 215 static int 216 rte_port_ring_writer_ras_tx(void *port, struct rte_mbuf *pkt) 217 { 218 struct rte_port_ring_writer_ras *p = 219 port; 220 221 RTE_PORT_RING_WRITER_RAS_STATS_PKTS_IN_ADD(p, 1); 222 p->f_ras(p, pkt); 223 if (p->tx_buf_count >= p->tx_burst_sz) 224 send_burst(p); 225 226 return 0; 227 } 228 229 static int 230 rte_port_ring_writer_ras_tx_bulk(void *port, 231 struct rte_mbuf **pkts, 232 uint64_t pkts_mask) 233 { 234 struct rte_port_ring_writer_ras *p = 235 port; 236 237 if ((pkts_mask & (pkts_mask + 1)) == 0) { 238 uint64_t n_pkts = __builtin_popcountll(pkts_mask); 239 uint32_t i; 240 241 for (i = 0; i < n_pkts; i++) { 242 struct rte_mbuf *pkt = pkts[i]; 243 244 RTE_PORT_RING_WRITER_RAS_STATS_PKTS_IN_ADD(p, 1); 245 p->f_ras(p, pkt); 246 if (p->tx_buf_count >= p->tx_burst_sz) 247 send_burst(p); 248 } 249 } else { 250 for ( ; pkts_mask; ) { 251 uint32_t pkt_index = __builtin_ctzll(pkts_mask); 252 uint64_t pkt_mask = 1LLU << pkt_index; 253 struct rte_mbuf *pkt = pkts[pkt_index]; 254 255 RTE_PORT_RING_WRITER_RAS_STATS_PKTS_IN_ADD(p, 1); 256 p->f_ras(p, pkt); 257 if (p->tx_buf_count >= p->tx_burst_sz) 258 send_burst(p); 259 260 pkts_mask &= ~pkt_mask; 261 } 262 } 263 264 return 0; 265 } 266 267 static int 268 rte_port_ring_writer_ras_flush(void *port) 269 { 270 struct rte_port_ring_writer_ras *p = 271 port; 272 273 if (p->tx_buf_count > 0) 274 send_burst(p); 275 276 return 0; 277 } 278 279 static int 280 rte_port_ring_writer_ras_free(void *port) 281 { 282 struct rte_port_ring_writer_ras *p = 283 port; 284 285 if (port == NULL) { 286 RTE_LOG(ERR, PORT, "%s: Parameter port is NULL\n", __func__); 287 return -1; 288 } 289 290 rte_port_ring_writer_ras_flush(port); 291 rte_ip_frag_table_destroy(p->frag_tbl); 292 rte_free(port); 293 294 return 0; 295 } 296 297 static int 298 rte_port_ras_writer_stats_read(void *port, 299 struct rte_port_out_stats *stats, int clear) 300 { 301 struct rte_port_ring_writer_ras *p = 302 port; 303 304 if (stats != NULL) 305 memcpy(stats, &p->stats, sizeof(p->stats)); 306 307 if (clear) 308 memset(&p->stats, 0, sizeof(p->stats)); 309 310 return 0; 311 } 312 313 /* 314 * Summary of port operations 315 */ 316 struct rte_port_out_ops rte_port_ring_writer_ipv4_ras_ops = { 317 .f_create = rte_port_ring_writer_ipv4_ras_create, 318 .f_free = rte_port_ring_writer_ras_free, 319 .f_tx = rte_port_ring_writer_ras_tx, 320 .f_tx_bulk = rte_port_ring_writer_ras_tx_bulk, 321 .f_flush = rte_port_ring_writer_ras_flush, 322 .f_stats = rte_port_ras_writer_stats_read, 323 }; 324 325 struct rte_port_out_ops rte_port_ring_writer_ipv6_ras_ops = { 326 .f_create = rte_port_ring_writer_ipv6_ras_create, 327 .f_free = rte_port_ring_writer_ras_free, 328 .f_tx = rte_port_ring_writer_ras_tx, 329 .f_tx_bulk = rte_port_ring_writer_ras_tx_bulk, 330 .f_flush = rte_port_ring_writer_ras_flush, 331 .f_stats = rte_port_ras_writer_stats_read, 332 }; 333