1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2018 Intel Corporation 3 */ 4 5 #include <stdalign.h> 6 #include <stdlib.h> 7 #include <string.h> 8 9 #include <rte_common.h> 10 #include <rte_malloc.h> 11 12 #include "rte_port_in_action.h" 13 14 /** 15 * RTE_PORT_IN_ACTION_FLTR 16 */ 17 static int 18 fltr_cfg_check(struct rte_port_in_action_fltr_config *cfg) 19 { 20 if (cfg == NULL) 21 return -1; 22 23 return 0; 24 } 25 26 struct fltr_data { 27 uint32_t port_id; 28 }; 29 30 static void 31 fltr_init(struct fltr_data *data, 32 struct rte_port_in_action_fltr_config *cfg) 33 { 34 data->port_id = cfg->port_id; 35 } 36 37 static int 38 fltr_apply(struct fltr_data *data, 39 struct rte_port_in_action_fltr_params *p) 40 { 41 /* Check input arguments */ 42 if (p == NULL) 43 return -1; 44 45 data->port_id = p->port_id; 46 47 return 0; 48 } 49 50 /** 51 * RTE_PORT_IN_ACTION_LB 52 */ 53 static int 54 lb_cfg_check(struct rte_port_in_action_lb_config *cfg) 55 { 56 if ((cfg == NULL) || 57 (cfg->key_size < RTE_PORT_IN_ACTION_LB_KEY_SIZE_MIN) || 58 (cfg->key_size > RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX) || 59 (!rte_is_power_of_2(cfg->key_size)) || 60 (cfg->f_hash == NULL)) 61 return -1; 62 63 return 0; 64 } 65 66 struct lb_data { 67 uint32_t port_id[RTE_PORT_IN_ACTION_LB_TABLE_SIZE]; 68 }; 69 70 static void 71 lb_init(struct lb_data *data, 72 struct rte_port_in_action_lb_config *cfg) 73 { 74 memcpy(data->port_id, cfg->port_id, sizeof(cfg->port_id)); 75 } 76 77 static int 78 lb_apply(struct lb_data *data, 79 struct rte_port_in_action_lb_params *p) 80 { 81 /* Check input arguments */ 82 if (p == NULL) 83 return -1; 84 85 memcpy(data->port_id, p->port_id, sizeof(p->port_id)); 86 87 return 0; 88 } 89 90 /** 91 * Action profile 92 */ 93 static int 94 action_valid(enum rte_port_in_action_type action) 95 { 96 switch (action) { 97 case RTE_PORT_IN_ACTION_FLTR: 98 case RTE_PORT_IN_ACTION_LB: 99 return 1; 100 default: 101 return 0; 102 } 103 } 104 105 #define RTE_PORT_IN_ACTION_MAX 64 106 107 struct ap_config { 108 uint64_t action_mask; 109 struct rte_port_in_action_fltr_config fltr; 110 struct rte_port_in_action_lb_config lb; 111 }; 112 113 static size_t 114 action_cfg_size(enum rte_port_in_action_type action) 115 { 116 switch (action) { 117 case RTE_PORT_IN_ACTION_FLTR: 118 return sizeof(struct rte_port_in_action_fltr_config); 119 case RTE_PORT_IN_ACTION_LB: 120 return sizeof(struct rte_port_in_action_lb_config); 121 default: 122 return 0; 123 } 124 } 125 126 static void* 127 action_cfg_get(struct ap_config *ap_config, 128 enum rte_port_in_action_type type) 129 { 130 switch (type) { 131 case RTE_PORT_IN_ACTION_FLTR: 132 return &ap_config->fltr; 133 134 case RTE_PORT_IN_ACTION_LB: 135 return &ap_config->lb; 136 137 default: 138 return NULL; 139 } 140 } 141 142 static void 143 action_cfg_set(struct ap_config *ap_config, 144 enum rte_port_in_action_type type, 145 void *action_cfg) 146 { 147 void *dst = action_cfg_get(ap_config, type); 148 149 if (dst) 150 memcpy(dst, action_cfg, action_cfg_size(type)); 151 152 ap_config->action_mask |= 1LLU << type; 153 } 154 155 struct ap_data { 156 size_t offset[RTE_PORT_IN_ACTION_MAX]; 157 size_t total_size; 158 }; 159 160 static size_t 161 action_data_size(enum rte_port_in_action_type action, 162 struct ap_config *ap_config __rte_unused) 163 { 164 switch (action) { 165 case RTE_PORT_IN_ACTION_FLTR: 166 return sizeof(struct fltr_data); 167 168 case RTE_PORT_IN_ACTION_LB: 169 return sizeof(struct lb_data); 170 171 default: 172 return 0; 173 } 174 } 175 176 static void 177 action_data_offset_set(struct ap_data *ap_data, 178 struct ap_config *ap_config) 179 { 180 uint64_t action_mask = ap_config->action_mask; 181 size_t offset; 182 uint32_t action; 183 184 memset(ap_data->offset, 0, sizeof(ap_data->offset)); 185 186 offset = 0; 187 for (action = 0; action < RTE_PORT_IN_ACTION_MAX; action++) 188 if (action_mask & (1LLU << action)) { 189 ap_data->offset[action] = offset; 190 offset += action_data_size((enum rte_port_in_action_type)action, 191 ap_config); 192 } 193 194 ap_data->total_size = offset; 195 } 196 197 struct rte_port_in_action_profile { 198 struct ap_config cfg; 199 struct ap_data data; 200 int frozen; 201 }; 202 203 struct rte_port_in_action_profile * 204 rte_port_in_action_profile_create(uint32_t socket_id) 205 { 206 struct rte_port_in_action_profile *ap; 207 208 /* Memory allocation */ 209 ap = rte_zmalloc_socket(NULL, 210 sizeof(struct rte_port_in_action_profile), 211 RTE_CACHE_LINE_SIZE, 212 socket_id); 213 if (ap == NULL) 214 return NULL; 215 216 return ap; 217 } 218 219 int 220 rte_port_in_action_profile_action_register(struct rte_port_in_action_profile *profile, 221 enum rte_port_in_action_type type, 222 void *action_config) 223 { 224 int status; 225 226 /* Check input arguments */ 227 if ((profile == NULL) || 228 profile->frozen || 229 (action_valid(type) == 0) || 230 (profile->cfg.action_mask & (1LLU << type)) || 231 ((action_cfg_size(type) == 0) && action_config) || 232 (action_cfg_size(type) && (action_config == NULL))) 233 return -EINVAL; 234 235 switch (type) { 236 case RTE_PORT_IN_ACTION_FLTR: 237 status = fltr_cfg_check(action_config); 238 break; 239 240 case RTE_PORT_IN_ACTION_LB: 241 status = lb_cfg_check(action_config); 242 break; 243 244 default: 245 status = 0; 246 break; 247 } 248 249 if (status) 250 return status; 251 252 /* Action enable */ 253 action_cfg_set(&profile->cfg, type, action_config); 254 255 return 0; 256 } 257 258 int 259 rte_port_in_action_profile_freeze(struct rte_port_in_action_profile *profile) 260 { 261 if (profile->frozen) 262 return -EBUSY; 263 264 action_data_offset_set(&profile->data, &profile->cfg); 265 profile->frozen = 1; 266 267 return 0; 268 } 269 270 int 271 rte_port_in_action_profile_free(struct rte_port_in_action_profile *profile) 272 { 273 if (profile == NULL) 274 return 0; 275 276 free(profile); 277 return 0; 278 } 279 280 /** 281 * Action 282 */ 283 struct rte_port_in_action { 284 struct ap_config cfg; 285 struct ap_data data; 286 alignas(RTE_CACHE_LINE_SIZE) uint8_t memory[0]; 287 }; 288 289 static __rte_always_inline void * 290 action_data_get(struct rte_port_in_action *action, 291 enum rte_port_in_action_type type) 292 { 293 size_t offset = action->data.offset[type]; 294 295 return &action->memory[offset]; 296 } 297 298 static void 299 action_data_init(struct rte_port_in_action *action, 300 enum rte_port_in_action_type type) 301 { 302 void *data = action_data_get(action, type); 303 304 switch (type) { 305 case RTE_PORT_IN_ACTION_FLTR: 306 fltr_init(data, &action->cfg.fltr); 307 return; 308 309 case RTE_PORT_IN_ACTION_LB: 310 lb_init(data, &action->cfg.lb); 311 return; 312 313 default: 314 return; 315 } 316 } 317 318 struct rte_port_in_action * 319 rte_port_in_action_create(struct rte_port_in_action_profile *profile, 320 uint32_t socket_id) 321 { 322 struct rte_port_in_action *action; 323 size_t size; 324 uint32_t i; 325 326 /* Check input arguments */ 327 if ((profile == NULL) || 328 (profile->frozen == 0)) 329 return NULL; 330 331 /* Memory allocation */ 332 size = sizeof(struct rte_port_in_action) + profile->data.total_size; 333 size = RTE_CACHE_LINE_ROUNDUP(size); 334 335 action = rte_zmalloc_socket(NULL, 336 size, 337 RTE_CACHE_LINE_SIZE, 338 socket_id); 339 if (action == NULL) 340 return NULL; 341 342 /* Initialization */ 343 memcpy(&action->cfg, &profile->cfg, sizeof(profile->cfg)); 344 memcpy(&action->data, &profile->data, sizeof(profile->data)); 345 346 for (i = 0; i < RTE_PORT_IN_ACTION_MAX; i++) 347 if (action->cfg.action_mask & (1LLU << i)) 348 action_data_init(action, 349 (enum rte_port_in_action_type)i); 350 351 return action; 352 } 353 354 int 355 rte_port_in_action_apply(struct rte_port_in_action *action, 356 enum rte_port_in_action_type type, 357 void *action_params) 358 { 359 void *action_data; 360 361 /* Check input arguments */ 362 if ((action == NULL) || 363 (action_valid(type) == 0) || 364 ((action->cfg.action_mask & (1LLU << type)) == 0) || 365 (action_params == NULL)) 366 return -EINVAL; 367 368 /* Data update */ 369 action_data = action_data_get(action, type); 370 371 switch (type) { 372 case RTE_PORT_IN_ACTION_FLTR: 373 return fltr_apply(action_data, 374 action_params); 375 376 case RTE_PORT_IN_ACTION_LB: 377 return lb_apply(action_data, 378 action_params); 379 380 default: 381 return -EINVAL; 382 } 383 } 384 385 static int 386 ah_filter_on_match(struct rte_pipeline *p, 387 struct rte_mbuf **pkts, 388 uint32_t n_pkts, 389 void *arg) 390 { 391 struct rte_port_in_action *action = arg; 392 struct rte_port_in_action_fltr_config *cfg = &action->cfg.fltr; 393 uint64_t *key_mask = (uint64_t *) cfg->key_mask; 394 uint64_t *key = (uint64_t *) cfg->key; 395 uint32_t key_offset = cfg->key_offset; 396 struct fltr_data *data = action_data_get(action, 397 RTE_PORT_IN_ACTION_FLTR); 398 uint32_t i; 399 400 for (i = 0; i < n_pkts; i++) { 401 struct rte_mbuf *pkt = pkts[i]; 402 uint64_t *pkt_key = RTE_MBUF_METADATA_UINT64_PTR(pkt, 403 key_offset); 404 405 uint64_t xor0 = (pkt_key[0] & key_mask[0]) ^ key[0]; 406 uint64_t xor1 = (pkt_key[1] & key_mask[1]) ^ key[1]; 407 uint64_t or = xor0 | xor1; 408 409 if (or == 0) { 410 rte_pipeline_ah_packet_hijack(p, 1LLU << i); 411 rte_pipeline_port_out_packet_insert(p, 412 data->port_id, pkt); 413 } 414 } 415 416 return 0; 417 } 418 419 static int 420 ah_filter_on_mismatch(struct rte_pipeline *p, 421 struct rte_mbuf **pkts, 422 uint32_t n_pkts, 423 void *arg) 424 { 425 struct rte_port_in_action *action = arg; 426 struct rte_port_in_action_fltr_config *cfg = &action->cfg.fltr; 427 uint64_t *key_mask = (uint64_t *) cfg->key_mask; 428 uint64_t *key = (uint64_t *) cfg->key; 429 uint32_t key_offset = cfg->key_offset; 430 struct fltr_data *data = action_data_get(action, 431 RTE_PORT_IN_ACTION_FLTR); 432 uint32_t i; 433 434 for (i = 0; i < n_pkts; i++) { 435 struct rte_mbuf *pkt = pkts[i]; 436 uint64_t *pkt_key = RTE_MBUF_METADATA_UINT64_PTR(pkt, 437 key_offset); 438 439 uint64_t xor0 = (pkt_key[0] & key_mask[0]) ^ key[0]; 440 uint64_t xor1 = (pkt_key[1] & key_mask[1]) ^ key[1]; 441 uint64_t or = xor0 | xor1; 442 443 if (or) { 444 rte_pipeline_ah_packet_hijack(p, 1LLU << i); 445 rte_pipeline_port_out_packet_insert(p, 446 data->port_id, pkt); 447 } 448 } 449 450 return 0; 451 } 452 453 static int 454 ah_lb(struct rte_pipeline *p, 455 struct rte_mbuf **pkts, 456 uint32_t n_pkts, 457 void *arg) 458 { 459 struct rte_port_in_action *action = arg; 460 struct rte_port_in_action_lb_config *cfg = &action->cfg.lb; 461 struct lb_data *data = action_data_get(action, RTE_PORT_IN_ACTION_LB); 462 uint64_t pkt_mask = RTE_LEN2MASK(n_pkts, uint64_t); 463 uint32_t i; 464 465 rte_pipeline_ah_packet_hijack(p, pkt_mask); 466 467 for (i = 0; i < n_pkts; i++) { 468 struct rte_mbuf *pkt = pkts[i]; 469 uint8_t *pkt_key = RTE_MBUF_METADATA_UINT8_PTR(pkt, 470 cfg->key_offset); 471 472 uint64_t digest = cfg->f_hash(pkt_key, 473 cfg->key_mask, 474 cfg->key_size, 475 cfg->seed); 476 uint64_t pos = digest & (RTE_PORT_IN_ACTION_LB_TABLE_SIZE - 1); 477 uint32_t port_id = data->port_id[pos]; 478 479 rte_pipeline_port_out_packet_insert(p, port_id, pkt); 480 } 481 482 return 0; 483 } 484 485 static rte_pipeline_port_in_action_handler 486 ah_selector(struct rte_port_in_action *action) 487 { 488 if (action->cfg.action_mask == 0) 489 return NULL; 490 491 if (action->cfg.action_mask == 1LLU << RTE_PORT_IN_ACTION_FLTR) 492 return (action->cfg.fltr.filter_on_match) ? 493 ah_filter_on_match : ah_filter_on_mismatch; 494 495 if (action->cfg.action_mask == 1LLU << RTE_PORT_IN_ACTION_LB) 496 return ah_lb; 497 498 return NULL; 499 } 500 501 int 502 rte_port_in_action_params_get(struct rte_port_in_action *action, 503 struct rte_pipeline_port_in_params *params) 504 { 505 rte_pipeline_port_in_action_handler f_action; 506 507 /* Check input arguments */ 508 if ((action == NULL) || 509 (params == NULL)) 510 return -EINVAL; 511 512 f_action = ah_selector(action); 513 514 /* Fill in params */ 515 params->f_action = f_action; 516 params->arg_ah = (f_action) ? action : NULL; 517 518 return 0; 519 } 520 521 int 522 rte_port_in_action_free(struct rte_port_in_action *action) 523 { 524 if (action == NULL) 525 return 0; 526 527 rte_free(action); 528 529 return 0; 530 } 531