1*2d9fd380Sjfb8856606 /* SPDX-License-Identifier: BSD-3-Clause
2*2d9fd380Sjfb8856606 * Copyright (C) 2020 Marvell International Ltd.
3*2d9fd380Sjfb8856606 */
4*2d9fd380Sjfb8856606
5*2d9fd380Sjfb8856606 #include <stdio.h>
6*2d9fd380Sjfb8856606
7*2d9fd380Sjfb8856606 #include <rte_common.h>
8*2d9fd380Sjfb8856606 #include <rte_flow.h>
9*2d9fd380Sjfb8856606 #include <rte_ip.h>
10*2d9fd380Sjfb8856606
11*2d9fd380Sjfb8856606 #include "flow.h"
12*2d9fd380Sjfb8856606 #include "ipsec-secgw.h"
13*2d9fd380Sjfb8856606 #include "parser.h"
14*2d9fd380Sjfb8856606
15*2d9fd380Sjfb8856606 #define FLOW_RULES_MAX 128
16*2d9fd380Sjfb8856606
17*2d9fd380Sjfb8856606 struct flow_rule_entry {
18*2d9fd380Sjfb8856606 uint8_t is_ipv4;
19*2d9fd380Sjfb8856606 RTE_STD_C11
20*2d9fd380Sjfb8856606 union {
21*2d9fd380Sjfb8856606 struct {
22*2d9fd380Sjfb8856606 struct rte_flow_item_ipv4 spec;
23*2d9fd380Sjfb8856606 struct rte_flow_item_ipv4 mask;
24*2d9fd380Sjfb8856606 } ipv4;
25*2d9fd380Sjfb8856606 struct {
26*2d9fd380Sjfb8856606 struct rte_flow_item_ipv6 spec;
27*2d9fd380Sjfb8856606 struct rte_flow_item_ipv6 mask;
28*2d9fd380Sjfb8856606 } ipv6;
29*2d9fd380Sjfb8856606 };
30*2d9fd380Sjfb8856606 uint16_t port;
31*2d9fd380Sjfb8856606 uint16_t queue;
32*2d9fd380Sjfb8856606 struct rte_flow *flow;
33*2d9fd380Sjfb8856606 } flow_rule_tbl[FLOW_RULES_MAX];
34*2d9fd380Sjfb8856606
35*2d9fd380Sjfb8856606 int nb_flow_rule;
36*2d9fd380Sjfb8856606
37*2d9fd380Sjfb8856606 static void
ipv4_hdr_print(struct rte_ipv4_hdr * hdr)38*2d9fd380Sjfb8856606 ipv4_hdr_print(struct rte_ipv4_hdr *hdr)
39*2d9fd380Sjfb8856606 {
40*2d9fd380Sjfb8856606 char a, b, c, d;
41*2d9fd380Sjfb8856606
42*2d9fd380Sjfb8856606 uint32_t_to_char(rte_bswap32(hdr->src_addr), &a, &b, &c, &d);
43*2d9fd380Sjfb8856606 printf("src: %3hhu.%3hhu.%3hhu.%3hhu \t", a, b, c, d);
44*2d9fd380Sjfb8856606
45*2d9fd380Sjfb8856606 uint32_t_to_char(rte_bswap32(hdr->dst_addr), &a, &b, &c, &d);
46*2d9fd380Sjfb8856606 printf("dst: %3hhu.%3hhu.%3hhu.%3hhu", a, b, c, d);
47*2d9fd380Sjfb8856606 }
48*2d9fd380Sjfb8856606
49*2d9fd380Sjfb8856606 static int
ipv4_addr_cpy(rte_be32_t * spec,rte_be32_t * mask,char * token,struct parse_status * status)50*2d9fd380Sjfb8856606 ipv4_addr_cpy(rte_be32_t *spec, rte_be32_t *mask, char *token,
51*2d9fd380Sjfb8856606 struct parse_status *status)
52*2d9fd380Sjfb8856606 {
53*2d9fd380Sjfb8856606 struct in_addr ip;
54*2d9fd380Sjfb8856606 uint32_t depth;
55*2d9fd380Sjfb8856606
56*2d9fd380Sjfb8856606 APP_CHECK(parse_ipv4_addr(token, &ip, &depth) == 0, status,
57*2d9fd380Sjfb8856606 "unrecognized input \"%s\", expect valid ipv4 addr", token);
58*2d9fd380Sjfb8856606 if (status->status < 0)
59*2d9fd380Sjfb8856606 return -1;
60*2d9fd380Sjfb8856606
61*2d9fd380Sjfb8856606 if (depth > 32)
62*2d9fd380Sjfb8856606 return -1;
63*2d9fd380Sjfb8856606
64*2d9fd380Sjfb8856606 memcpy(mask, &rte_flow_item_ipv4_mask.hdr.src_addr, sizeof(ip));
65*2d9fd380Sjfb8856606
66*2d9fd380Sjfb8856606 *spec = ip.s_addr;
67*2d9fd380Sjfb8856606 if (depth < 32)
68*2d9fd380Sjfb8856606 *mask = *mask << (32-depth);
69*2d9fd380Sjfb8856606
70*2d9fd380Sjfb8856606 return 0;
71*2d9fd380Sjfb8856606 }
72*2d9fd380Sjfb8856606
73*2d9fd380Sjfb8856606 static void
ipv6_hdr_print(struct rte_ipv6_hdr * hdr)74*2d9fd380Sjfb8856606 ipv6_hdr_print(struct rte_ipv6_hdr *hdr)
75*2d9fd380Sjfb8856606 {
76*2d9fd380Sjfb8856606 uint8_t *addr;
77*2d9fd380Sjfb8856606
78*2d9fd380Sjfb8856606 addr = hdr->src_addr;
79*2d9fd380Sjfb8856606 printf("src: %4hx:%4hx:%4hx:%4hx:%4hx:%4hx:%4hx:%4hx \t",
80*2d9fd380Sjfb8856606 (uint16_t)((addr[0] << 8) | addr[1]),
81*2d9fd380Sjfb8856606 (uint16_t)((addr[2] << 8) | addr[3]),
82*2d9fd380Sjfb8856606 (uint16_t)((addr[4] << 8) | addr[5]),
83*2d9fd380Sjfb8856606 (uint16_t)((addr[6] << 8) | addr[7]),
84*2d9fd380Sjfb8856606 (uint16_t)((addr[8] << 8) | addr[9]),
85*2d9fd380Sjfb8856606 (uint16_t)((addr[10] << 8) | addr[11]),
86*2d9fd380Sjfb8856606 (uint16_t)((addr[12] << 8) | addr[13]),
87*2d9fd380Sjfb8856606 (uint16_t)((addr[14] << 8) | addr[15]));
88*2d9fd380Sjfb8856606
89*2d9fd380Sjfb8856606 addr = hdr->dst_addr;
90*2d9fd380Sjfb8856606 printf("dst: %4hx:%4hx:%4hx:%4hx:%4hx:%4hx:%4hx:%4hx",
91*2d9fd380Sjfb8856606 (uint16_t)((addr[0] << 8) | addr[1]),
92*2d9fd380Sjfb8856606 (uint16_t)((addr[2] << 8) | addr[3]),
93*2d9fd380Sjfb8856606 (uint16_t)((addr[4] << 8) | addr[5]),
94*2d9fd380Sjfb8856606 (uint16_t)((addr[6] << 8) | addr[7]),
95*2d9fd380Sjfb8856606 (uint16_t)((addr[8] << 8) | addr[9]),
96*2d9fd380Sjfb8856606 (uint16_t)((addr[10] << 8) | addr[11]),
97*2d9fd380Sjfb8856606 (uint16_t)((addr[12] << 8) | addr[13]),
98*2d9fd380Sjfb8856606 (uint16_t)((addr[14] << 8) | addr[15]));
99*2d9fd380Sjfb8856606 }
100*2d9fd380Sjfb8856606
101*2d9fd380Sjfb8856606 static int
ipv6_addr_cpy(uint8_t * spec,uint8_t * mask,char * token,struct parse_status * status)102*2d9fd380Sjfb8856606 ipv6_addr_cpy(uint8_t *spec, uint8_t *mask, char *token,
103*2d9fd380Sjfb8856606 struct parse_status *status)
104*2d9fd380Sjfb8856606 {
105*2d9fd380Sjfb8856606 struct in6_addr ip;
106*2d9fd380Sjfb8856606 uint32_t depth, i;
107*2d9fd380Sjfb8856606
108*2d9fd380Sjfb8856606 APP_CHECK(parse_ipv6_addr(token, &ip, &depth) == 0, status,
109*2d9fd380Sjfb8856606 "unrecognized input \"%s\", expect valid ipv6 address", token);
110*2d9fd380Sjfb8856606 if (status->status < 0)
111*2d9fd380Sjfb8856606 return -1;
112*2d9fd380Sjfb8856606
113*2d9fd380Sjfb8856606 memcpy(mask, &rte_flow_item_ipv6_mask.hdr.src_addr, sizeof(ip));
114*2d9fd380Sjfb8856606 memcpy(spec, ip.s6_addr, sizeof(struct in6_addr));
115*2d9fd380Sjfb8856606
116*2d9fd380Sjfb8856606 for (i = 0; i < depth && (i%8 <= sizeof(struct in6_addr)); i++)
117*2d9fd380Sjfb8856606 mask[i/8] &= ~(1 << (7-i%8));
118*2d9fd380Sjfb8856606
119*2d9fd380Sjfb8856606 return 0;
120*2d9fd380Sjfb8856606 }
121*2d9fd380Sjfb8856606
122*2d9fd380Sjfb8856606 void
parse_flow_tokens(char ** tokens,uint32_t n_tokens,struct parse_status * status)123*2d9fd380Sjfb8856606 parse_flow_tokens(char **tokens, uint32_t n_tokens,
124*2d9fd380Sjfb8856606 struct parse_status *status)
125*2d9fd380Sjfb8856606 {
126*2d9fd380Sjfb8856606 struct flow_rule_entry *rule;
127*2d9fd380Sjfb8856606 uint32_t ti;
128*2d9fd380Sjfb8856606
129*2d9fd380Sjfb8856606 if (nb_flow_rule >= FLOW_RULES_MAX) {
130*2d9fd380Sjfb8856606 printf("Too many flow rules\n");
131*2d9fd380Sjfb8856606 return;
132*2d9fd380Sjfb8856606 }
133*2d9fd380Sjfb8856606
134*2d9fd380Sjfb8856606 rule = &flow_rule_tbl[nb_flow_rule];
135*2d9fd380Sjfb8856606 memset(rule, 0, sizeof(*rule));
136*2d9fd380Sjfb8856606
137*2d9fd380Sjfb8856606 if (strcmp(tokens[0], "ipv4") == 0) {
138*2d9fd380Sjfb8856606 rule->is_ipv4 = 1;
139*2d9fd380Sjfb8856606 } else if (strcmp(tokens[0], "ipv6") == 0) {
140*2d9fd380Sjfb8856606 rule->is_ipv4 = 0;
141*2d9fd380Sjfb8856606 } else {
142*2d9fd380Sjfb8856606 APP_CHECK(0, status, "unrecognized input \"%s\"", tokens[0]);
143*2d9fd380Sjfb8856606 return;
144*2d9fd380Sjfb8856606 }
145*2d9fd380Sjfb8856606
146*2d9fd380Sjfb8856606 for (ti = 1; ti < n_tokens; ti++) {
147*2d9fd380Sjfb8856606 if (strcmp(tokens[ti], "src") == 0) {
148*2d9fd380Sjfb8856606 INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
149*2d9fd380Sjfb8856606 if (status->status < 0)
150*2d9fd380Sjfb8856606 return;
151*2d9fd380Sjfb8856606
152*2d9fd380Sjfb8856606 if (rule->is_ipv4) {
153*2d9fd380Sjfb8856606 if (ipv4_addr_cpy(&rule->ipv4.spec.hdr.src_addr,
154*2d9fd380Sjfb8856606 &rule->ipv4.mask.hdr.src_addr,
155*2d9fd380Sjfb8856606 tokens[ti], status))
156*2d9fd380Sjfb8856606 return;
157*2d9fd380Sjfb8856606 } else {
158*2d9fd380Sjfb8856606 if (ipv6_addr_cpy(rule->ipv6.spec.hdr.src_addr,
159*2d9fd380Sjfb8856606 rule->ipv6.mask.hdr.src_addr,
160*2d9fd380Sjfb8856606 tokens[ti], status))
161*2d9fd380Sjfb8856606 return;
162*2d9fd380Sjfb8856606 }
163*2d9fd380Sjfb8856606 }
164*2d9fd380Sjfb8856606 if (strcmp(tokens[ti], "dst") == 0) {
165*2d9fd380Sjfb8856606 INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
166*2d9fd380Sjfb8856606 if (status->status < 0)
167*2d9fd380Sjfb8856606 return;
168*2d9fd380Sjfb8856606
169*2d9fd380Sjfb8856606 if (rule->is_ipv4) {
170*2d9fd380Sjfb8856606 if (ipv4_addr_cpy(&rule->ipv4.spec.hdr.dst_addr,
171*2d9fd380Sjfb8856606 &rule->ipv4.mask.hdr.dst_addr,
172*2d9fd380Sjfb8856606 tokens[ti], status))
173*2d9fd380Sjfb8856606 return;
174*2d9fd380Sjfb8856606 } else {
175*2d9fd380Sjfb8856606 if (ipv6_addr_cpy(rule->ipv6.spec.hdr.dst_addr,
176*2d9fd380Sjfb8856606 rule->ipv6.mask.hdr.dst_addr,
177*2d9fd380Sjfb8856606 tokens[ti], status))
178*2d9fd380Sjfb8856606 return;
179*2d9fd380Sjfb8856606 }
180*2d9fd380Sjfb8856606 }
181*2d9fd380Sjfb8856606
182*2d9fd380Sjfb8856606 if (strcmp(tokens[ti], "port") == 0) {
183*2d9fd380Sjfb8856606 INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
184*2d9fd380Sjfb8856606 if (status->status < 0)
185*2d9fd380Sjfb8856606 return;
186*2d9fd380Sjfb8856606 APP_CHECK_TOKEN_IS_NUM(tokens, ti, status);
187*2d9fd380Sjfb8856606 if (status->status < 0)
188*2d9fd380Sjfb8856606 return;
189*2d9fd380Sjfb8856606
190*2d9fd380Sjfb8856606 rule->port = atoi(tokens[ti]);
191*2d9fd380Sjfb8856606
192*2d9fd380Sjfb8856606 INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
193*2d9fd380Sjfb8856606 if (status->status < 0)
194*2d9fd380Sjfb8856606 return;
195*2d9fd380Sjfb8856606 APP_CHECK_TOKEN_IS_NUM(tokens, ti, status);
196*2d9fd380Sjfb8856606 if (status->status < 0)
197*2d9fd380Sjfb8856606 return;
198*2d9fd380Sjfb8856606
199*2d9fd380Sjfb8856606 rule->queue = atoi(tokens[ti]);
200*2d9fd380Sjfb8856606 }
201*2d9fd380Sjfb8856606 }
202*2d9fd380Sjfb8856606
203*2d9fd380Sjfb8856606 nb_flow_rule++;
204*2d9fd380Sjfb8856606 }
205*2d9fd380Sjfb8856606
206*2d9fd380Sjfb8856606 #define MAX_RTE_FLOW_PATTERN (3)
207*2d9fd380Sjfb8856606 #define MAX_RTE_FLOW_ACTIONS (2)
208*2d9fd380Sjfb8856606
209*2d9fd380Sjfb8856606 static void
flow_init_single(struct flow_rule_entry * rule)210*2d9fd380Sjfb8856606 flow_init_single(struct flow_rule_entry *rule)
211*2d9fd380Sjfb8856606 {
212*2d9fd380Sjfb8856606 struct rte_flow_item pattern[MAX_RTE_FLOW_PATTERN] = {};
213*2d9fd380Sjfb8856606 struct rte_flow_action action[MAX_RTE_FLOW_ACTIONS] = {};
214*2d9fd380Sjfb8856606 struct rte_flow_attr attr = {};
215*2d9fd380Sjfb8856606 struct rte_flow_error err;
216*2d9fd380Sjfb8856606 int ret;
217*2d9fd380Sjfb8856606
218*2d9fd380Sjfb8856606 attr.egress = 0;
219*2d9fd380Sjfb8856606 attr.ingress = 1;
220*2d9fd380Sjfb8856606
221*2d9fd380Sjfb8856606 action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
222*2d9fd380Sjfb8856606 action[0].conf = &(struct rte_flow_action_queue) {
223*2d9fd380Sjfb8856606 .index = rule->queue,
224*2d9fd380Sjfb8856606 };
225*2d9fd380Sjfb8856606 action[1].type = RTE_FLOW_ACTION_TYPE_END;
226*2d9fd380Sjfb8856606
227*2d9fd380Sjfb8856606 pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
228*2d9fd380Sjfb8856606
229*2d9fd380Sjfb8856606 if (rule->is_ipv4) {
230*2d9fd380Sjfb8856606 pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
231*2d9fd380Sjfb8856606 pattern[1].spec = &rule->ipv4.spec;
232*2d9fd380Sjfb8856606 pattern[1].mask = &rule->ipv4.mask;
233*2d9fd380Sjfb8856606 } else {
234*2d9fd380Sjfb8856606 pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;
235*2d9fd380Sjfb8856606 pattern[1].spec = &rule->ipv6.spec;
236*2d9fd380Sjfb8856606 pattern[1].mask = &rule->ipv6.mask;
237*2d9fd380Sjfb8856606 }
238*2d9fd380Sjfb8856606
239*2d9fd380Sjfb8856606 pattern[2].type = RTE_FLOW_ITEM_TYPE_END;
240*2d9fd380Sjfb8856606
241*2d9fd380Sjfb8856606 ret = rte_flow_validate(rule->port, &attr, pattern, action, &err);
242*2d9fd380Sjfb8856606 if (ret < 0) {
243*2d9fd380Sjfb8856606 RTE_LOG(ERR, IPSEC, "Flow validation failed %s\n", err.message);
244*2d9fd380Sjfb8856606 return;
245*2d9fd380Sjfb8856606 }
246*2d9fd380Sjfb8856606
247*2d9fd380Sjfb8856606 rule->flow = rte_flow_create(rule->port, &attr, pattern, action, &err);
248*2d9fd380Sjfb8856606 if (rule->flow == NULL)
249*2d9fd380Sjfb8856606 RTE_LOG(ERR, IPSEC, "Flow creation return %s\n", err.message);
250*2d9fd380Sjfb8856606 }
251*2d9fd380Sjfb8856606
252*2d9fd380Sjfb8856606 void
flow_init(void)253*2d9fd380Sjfb8856606 flow_init(void)
254*2d9fd380Sjfb8856606 {
255*2d9fd380Sjfb8856606 struct flow_rule_entry *rule;
256*2d9fd380Sjfb8856606 int i;
257*2d9fd380Sjfb8856606
258*2d9fd380Sjfb8856606 for (i = 0; i < nb_flow_rule; i++) {
259*2d9fd380Sjfb8856606 rule = &flow_rule_tbl[i];
260*2d9fd380Sjfb8856606 flow_init_single(rule);
261*2d9fd380Sjfb8856606 }
262*2d9fd380Sjfb8856606
263*2d9fd380Sjfb8856606 for (i = 0; i < nb_flow_rule; i++) {
264*2d9fd380Sjfb8856606 rule = &flow_rule_tbl[i];
265*2d9fd380Sjfb8856606 if (rule->is_ipv4) {
266*2d9fd380Sjfb8856606 printf("Flow #%3d: spec ipv4 ", i);
267*2d9fd380Sjfb8856606 ipv4_hdr_print(&rule->ipv4.spec.hdr);
268*2d9fd380Sjfb8856606 printf("\n");
269*2d9fd380Sjfb8856606 printf(" mask ipv4 ");
270*2d9fd380Sjfb8856606 ipv4_hdr_print(&rule->ipv4.mask.hdr);
271*2d9fd380Sjfb8856606 } else {
272*2d9fd380Sjfb8856606 printf("Flow #%3d: spec ipv6 ", i);
273*2d9fd380Sjfb8856606 ipv6_hdr_print(&rule->ipv6.spec.hdr);
274*2d9fd380Sjfb8856606 printf("\n");
275*2d9fd380Sjfb8856606 printf(" mask ipv6 ");
276*2d9fd380Sjfb8856606 ipv6_hdr_print(&rule->ipv6.mask.hdr);
277*2d9fd380Sjfb8856606 }
278*2d9fd380Sjfb8856606
279*2d9fd380Sjfb8856606 printf("\tPort: %d, Queue: %d", rule->port, rule->queue);
280*2d9fd380Sjfb8856606
281*2d9fd380Sjfb8856606 if (rule->flow == NULL)
282*2d9fd380Sjfb8856606 printf(" [UNSUPPORTED]");
283*2d9fd380Sjfb8856606 printf("\n");
284*2d9fd380Sjfb8856606 }
285*2d9fd380Sjfb8856606 }
286