1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2020 Marvell International Ltd. 3 */ 4 5 #include <stdio.h> 6 #include <stdlib.h> 7 8 #include <rte_common.h> 9 #include <rte_flow.h> 10 #include <rte_ip.h> 11 12 #include "flow.h" 13 #include "ipsec-secgw.h" 14 #include "parser.h" 15 16 #define FLOW_RULES_MAX 128 17 18 struct flow_rule_entry { 19 uint8_t is_eth; 20 uint8_t is_ipv4; 21 uint8_t is_ipv6; 22 RTE_STD_C11 23 union { 24 struct { 25 struct rte_flow_item_ipv4 spec; 26 struct rte_flow_item_ipv4 mask; 27 } ipv4; 28 struct { 29 struct rte_flow_item_ipv6 spec; 30 struct rte_flow_item_ipv6 mask; 31 } ipv6; 32 }; 33 struct rte_flow_item_mark mark_val; 34 uint16_t port; 35 uint16_t queue; 36 bool is_queue_set; 37 bool enable_count; 38 bool enable_mark; 39 bool set_security_action; 40 bool set_mark_action; 41 uint32_t mark_action_val; 42 struct rte_flow *flow; 43 } flow_rule_tbl[FLOW_RULES_MAX]; 44 45 int nb_flow_rule; 46 47 static void 48 ipv4_hdr_print(struct rte_ipv4_hdr *hdr) 49 { 50 char a, b, c, d; 51 52 uint32_t_to_char(rte_bswap32(hdr->src_addr), &a, &b, &c, &d); 53 printf("src: %3hhu.%3hhu.%3hhu.%3hhu \t", a, b, c, d); 54 55 uint32_t_to_char(rte_bswap32(hdr->dst_addr), &a, &b, &c, &d); 56 printf("dst: %3hhu.%3hhu.%3hhu.%3hhu", a, b, c, d); 57 } 58 59 static int 60 ipv4_addr_cpy(rte_be32_t *spec, rte_be32_t *mask, char *token, 61 struct parse_status *status) 62 { 63 struct in_addr ip; 64 uint32_t depth; 65 66 APP_CHECK(parse_ipv4_addr(token, &ip, &depth) == 0, status, 67 "unrecognized input \"%s\", expect valid ipv4 addr", token); 68 if (status->status < 0) 69 return -1; 70 71 if (depth > 32) 72 return -1; 73 74 memcpy(mask, &rte_flow_item_ipv4_mask.hdr.src_addr, sizeof(ip)); 75 76 *spec = ip.s_addr; 77 78 if (depth < 32) 79 *mask = htonl(*mask << (32 - depth)); 80 81 return 0; 82 } 83 84 static void 85 ipv6_hdr_print(struct rte_ipv6_hdr *hdr) 86 { 87 uint8_t *addr; 88 89 addr = hdr->src_addr; 90 printf("src: %4hx:%4hx:%4hx:%4hx:%4hx:%4hx:%4hx:%4hx \t", 91 (uint16_t)((addr[0] << 8) | addr[1]), 92 (uint16_t)((addr[2] << 8) | addr[3]), 93 (uint16_t)((addr[4] << 8) | addr[5]), 94 (uint16_t)((addr[6] << 8) | addr[7]), 95 (uint16_t)((addr[8] << 8) | addr[9]), 96 (uint16_t)((addr[10] << 8) | addr[11]), 97 (uint16_t)((addr[12] << 8) | addr[13]), 98 (uint16_t)((addr[14] << 8) | addr[15])); 99 100 addr = hdr->dst_addr; 101 printf("dst: %4hx:%4hx:%4hx:%4hx:%4hx:%4hx:%4hx:%4hx", 102 (uint16_t)((addr[0] << 8) | addr[1]), 103 (uint16_t)((addr[2] << 8) | addr[3]), 104 (uint16_t)((addr[4] << 8) | addr[5]), 105 (uint16_t)((addr[6] << 8) | addr[7]), 106 (uint16_t)((addr[8] << 8) | addr[9]), 107 (uint16_t)((addr[10] << 8) | addr[11]), 108 (uint16_t)((addr[12] << 8) | addr[13]), 109 (uint16_t)((addr[14] << 8) | addr[15])); 110 } 111 112 static int 113 ipv6_addr_cpy(uint8_t *spec, uint8_t *mask, char *token, 114 struct parse_status *status) 115 { 116 struct in6_addr ip; 117 uint32_t depth, i; 118 119 APP_CHECK(parse_ipv6_addr(token, &ip, &depth) == 0, status, 120 "unrecognized input \"%s\", expect valid ipv6 address", token); 121 if (status->status < 0) 122 return -1; 123 124 memcpy(mask, &rte_flow_item_ipv6_mask.hdr.src_addr, sizeof(ip)); 125 memcpy(spec, ip.s6_addr, sizeof(struct in6_addr)); 126 127 for (i = 0; i < depth && (i%8 <= sizeof(struct in6_addr)); i++) 128 mask[i/8] &= ~(1 << (7-i%8)); 129 130 return 0; 131 } 132 133 void 134 parse_flow_tokens(char **tokens, uint32_t n_tokens, 135 struct parse_status *status) 136 { 137 struct flow_rule_entry *rule; 138 uint32_t ti = 0; 139 140 if (nb_flow_rule >= FLOW_RULES_MAX) { 141 printf("Too many flow rules\n"); 142 return; 143 } 144 145 rule = &flow_rule_tbl[nb_flow_rule]; 146 memset(rule, 0, sizeof(*rule)); 147 148 for (ti = 0; ti < n_tokens; ti++) { 149 if (strcmp(tokens[ti], "mark") == 0) { 150 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 151 if (status->status < 0) 152 return; 153 APP_CHECK_TOKEN_IS_NUM(tokens, ti, status); 154 if (status->status < 0) 155 return; 156 157 rule->mark_val.id = atoi(tokens[ti]); 158 rule->enable_mark = true; 159 continue; 160 } 161 if (strcmp(tokens[ti], "eth") == 0) { 162 rule->is_eth = true; 163 continue; 164 } 165 166 if (strcmp(tokens[ti], "ipv4") == 0) { 167 rule->is_ipv4 = true; 168 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 169 if (status->status < 0) 170 return; 171 if (strcmp(tokens[ti], "src") == 0) { 172 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 173 if (status->status < 0) 174 return; 175 if (ipv4_addr_cpy(&rule->ipv4.spec.hdr.src_addr, 176 &rule->ipv4.mask.hdr.src_addr, 177 tokens[ti], status)) 178 return; 179 } 180 if (strcmp(tokens[ti], "dst") == 0) { 181 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 182 if (status->status < 0) 183 return; 184 if (ipv4_addr_cpy(&rule->ipv4.spec.hdr.dst_addr, 185 &rule->ipv4.mask.hdr.dst_addr, 186 tokens[ti], status)) 187 return; 188 } 189 continue; 190 } 191 if (strcmp(tokens[ti], "ipv6") == 0) { 192 rule->is_ipv6 = true; 193 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 194 if (status->status < 0) 195 return; 196 if (strcmp(tokens[ti], "src") == 0) { 197 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 198 if (status->status < 0) 199 return; 200 if (ipv6_addr_cpy(rule->ipv6.spec.hdr.src_addr, 201 rule->ipv6.mask.hdr.src_addr, 202 tokens[ti], status)) 203 return; 204 } 205 if (strcmp(tokens[ti], "dst") == 0) { 206 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 207 if (status->status < 0) 208 return; 209 if (ipv6_addr_cpy(rule->ipv6.spec.hdr.dst_addr, 210 rule->ipv6.mask.hdr.dst_addr, 211 tokens[ti], status)) 212 return; 213 } 214 continue; 215 } 216 217 if (strcmp(tokens[ti], "port") == 0) { 218 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 219 if (status->status < 0) 220 return; 221 APP_CHECK_TOKEN_IS_NUM(tokens, ti, status); 222 if (status->status < 0) 223 return; 224 225 rule->port = atoi(tokens[ti]); 226 continue; 227 } 228 229 if (strcmp(tokens[ti], "queue") == 0) { 230 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 231 if (status->status < 0) 232 return; 233 APP_CHECK_TOKEN_IS_NUM(tokens, ti, status); 234 if (status->status < 0) 235 return; 236 237 rule->queue = atoi(tokens[ti]); 238 rule->is_queue_set = true; 239 continue; 240 } 241 242 if (strcmp(tokens[ti], "count") == 0) { 243 rule->enable_count = true; 244 continue; 245 } 246 247 if (strcmp(tokens[ti], "security") == 0) { 248 rule->set_security_action = true; 249 continue; 250 } 251 if (strcmp(tokens[ti], "set_mark") == 0) { 252 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 253 if (status->status < 0) 254 return; 255 APP_CHECK_TOKEN_IS_NUM(tokens, ti, status); 256 if (status->status < 0) 257 return; 258 259 rule->set_mark_action = true; 260 rule->mark_action_val = atoi(tokens[ti]); 261 continue; 262 } 263 264 sprintf(status->parse_msg, "Unrecognized input:%s\n", 265 tokens[ti]); 266 status->status = -1; 267 return; 268 } 269 printf("\n"); 270 271 nb_flow_rule++; 272 } 273 274 #define MAX_RTE_FLOW_PATTERN (4) 275 #define MAX_RTE_FLOW_ACTIONS (5) 276 277 static void 278 flow_init_single(struct flow_rule_entry *rule) 279 { 280 struct rte_flow_action action[MAX_RTE_FLOW_ACTIONS] = {}; 281 struct rte_flow_item pattern[MAX_RTE_FLOW_PATTERN] = {}; 282 struct rte_flow_action_queue queue_action; 283 struct rte_flow_action_mark mark_action; 284 int ret, pattern_idx = 0, act_idx = 0; 285 struct rte_flow_item_mark mark_mask; 286 struct rte_flow_attr attr = {}; 287 struct rte_flow_error err = {}; 288 289 attr.egress = 0; 290 attr.ingress = 1; 291 292 if (rule->is_queue_set) { 293 queue_action.index = rule->queue; 294 action[act_idx].type = RTE_FLOW_ACTION_TYPE_QUEUE; 295 action[act_idx].conf = &queue_action; 296 act_idx++; 297 } 298 299 if (rule->enable_count) { 300 action[act_idx].type = RTE_FLOW_ACTION_TYPE_COUNT; 301 act_idx++; 302 } 303 304 if (rule->set_security_action) { 305 action[act_idx].type = RTE_FLOW_ACTION_TYPE_SECURITY; 306 action[act_idx].conf = NULL; 307 act_idx++; 308 } 309 310 if (rule->set_mark_action) { 311 mark_action.id = rule->mark_action_val; 312 action[act_idx].type = RTE_FLOW_ACTION_TYPE_MARK; 313 action[act_idx].conf = &mark_action; 314 act_idx++; 315 } 316 317 action[act_idx].type = RTE_FLOW_ACTION_TYPE_END; 318 action[act_idx].conf = NULL; 319 320 if (rule->enable_mark) { 321 mark_mask.id = UINT32_MAX; 322 pattern[pattern_idx].type = RTE_FLOW_ITEM_TYPE_MARK; 323 pattern[pattern_idx].spec = &rule->mark_val; 324 pattern[pattern_idx].mask = &mark_mask; 325 pattern_idx++; 326 } 327 328 if (rule->is_eth) { 329 pattern[pattern_idx].type = RTE_FLOW_ITEM_TYPE_ETH; 330 pattern_idx++; 331 } 332 333 if (rule->is_ipv4) { 334 pattern[pattern_idx].type = RTE_FLOW_ITEM_TYPE_IPV4; 335 pattern[pattern_idx].spec = &rule->ipv4.spec; 336 pattern[pattern_idx].mask = &rule->ipv4.mask; 337 pattern_idx++; 338 } 339 340 if (rule->is_ipv6) { 341 pattern[pattern_idx].type = RTE_FLOW_ITEM_TYPE_IPV6; 342 pattern[pattern_idx].spec = &rule->ipv6.spec; 343 pattern[pattern_idx].mask = &rule->ipv6.mask; 344 pattern_idx++; 345 } 346 347 if (rule->set_security_action) { 348 pattern[pattern_idx].type = RTE_FLOW_ITEM_TYPE_ESP; 349 pattern[pattern_idx].spec = NULL; 350 pattern[pattern_idx].mask = NULL; 351 pattern[pattern_idx].last = NULL; 352 pattern_idx++; 353 } 354 355 pattern[pattern_idx].type = RTE_FLOW_ITEM_TYPE_END; 356 357 ret = rte_flow_validate(rule->port, &attr, pattern, action, &err); 358 if (ret < 0) { 359 RTE_LOG(ERR, IPSEC, "Flow validation failed %s\n", err.message); 360 rule->flow = 0; 361 return; 362 } 363 364 rule->flow = rte_flow_create(rule->port, &attr, pattern, action, &err); 365 if (rule->flow == NULL) 366 RTE_LOG(ERR, IPSEC, "Flow creation return %s\n", err.message); 367 } 368 369 void 370 flow_print_counters(void) 371 { 372 struct rte_flow_query_count count_query; 373 struct rte_flow_action action; 374 struct flow_rule_entry *rule; 375 struct rte_flow_error error; 376 int i = 0, ret = 0; 377 378 action.type = RTE_FLOW_ACTION_TYPE_COUNT; 379 380 for (i = 0; i < nb_flow_rule; i++) { 381 rule = &flow_rule_tbl[i]; 382 if (!rule->flow || !rule->enable_count) 383 continue; 384 385 /* Poisoning to make sure PMDs update it in case of error. */ 386 memset(&error, 0x55, sizeof(error)); 387 memset(&count_query, 0, sizeof(count_query)); 388 ret = rte_flow_query(rule->port, rule->flow, &action, 389 &count_query, &error); 390 if (ret) 391 RTE_LOG(ERR, IPSEC, 392 "Failed to get flow counter " 393 " for port %u, err msg: %s\n", 394 rule->port, error.message); 395 396 printf("Flow #%3d:", i); 397 if (rule->is_ipv4) { 398 printf(" spec ipv4 "); 399 ipv4_hdr_print(&rule->ipv4.spec.hdr); 400 } 401 if (rule->is_ipv6) { 402 printf(" spec ipv6 "); 403 ipv6_hdr_print(&rule->ipv6.spec.hdr); 404 } 405 406 if (rule->set_security_action) 407 printf(" Security action set,"); 408 409 if (rule->enable_mark) 410 printf(" Mark Enabled"); 411 412 printf(" Port: %d,", rule->port); 413 if (rule->is_queue_set) 414 printf(" Queue: %d", rule->queue); 415 printf(" Hits: %"PRIu64"\n", count_query.hits); 416 } 417 } 418 419 void 420 flow_init(void) 421 { 422 struct flow_rule_entry *rule; 423 int i; 424 425 for (i = 0; i < nb_flow_rule; i++) { 426 rule = &flow_rule_tbl[i]; 427 flow_init_single(rule); 428 } 429 430 for (i = 0; i < nb_flow_rule; i++) { 431 rule = &flow_rule_tbl[i]; 432 printf("Flow #%3d: ", i); 433 if (rule->is_ipv4) { 434 printf("spec ipv4 "); 435 ipv4_hdr_print(&rule->ipv4.spec.hdr); 436 printf("\n"); 437 printf(" mask ipv4 "); 438 ipv4_hdr_print(&rule->ipv4.mask.hdr); 439 } 440 if (rule->is_ipv6) { 441 printf("spec ipv6 "); 442 ipv6_hdr_print(&rule->ipv6.spec.hdr); 443 printf("\n"); 444 printf(" mask ipv6 "); 445 ipv6_hdr_print(&rule->ipv6.mask.hdr); 446 } 447 448 if (rule->enable_mark) 449 printf(", Mark enabled"); 450 451 printf("\tPort: %d,", rule->port); 452 if (rule->is_queue_set) 453 printf(" Queue: %d,", rule->queue); 454 455 if (rule->set_security_action) 456 printf(" Security action set,"); 457 458 if (rule->set_mark_action) 459 printf(" Mark: %d,", rule->mark_action_val); 460 461 if (rule->enable_count) 462 printf(" Counter enabled,"); 463 464 if (rule->flow == NULL) 465 printf(" [UNSUPPORTED]"); 466 printf("\n"); 467 } 468 } 469