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