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