xref: /dpdk/examples/ipsec-secgw/rt.c (revision 9ac91e2f7339e66658ef55b756a06b328e336fde)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2016 Intel Corporation
3  */
4 
5 /*
6  * Routing Table (RT)
7  */
8 #include <stdlib.h>
9 #include <sys/types.h>
10 #include <rte_lpm.h>
11 #include <rte_lpm6.h>
12 #include <rte_errno.h>
13 #include <rte_ip.h>
14 
15 #include "ipsec.h"
16 #include "parser.h"
17 
18 #define RT_IPV4_MAX_RULES	1024
19 #define RT_IPV6_MAX_RULES	1024
20 
21 struct ip4_route {
22 	uint32_t ip;
23 	uint8_t depth;
24 	uint8_t if_out;
25 };
26 
27 struct ip6_route {
28 	struct rte_ipv6_addr ip;
29 	uint8_t depth;
30 	uint8_t if_out;
31 };
32 
33 struct ip4_route rt_ip4[RT_IPV4_MAX_RULES];
34 uint32_t nb_rt_ip4;
35 
36 struct ip6_route rt_ip6[RT_IPV4_MAX_RULES];
37 uint32_t nb_rt_ip6;
38 
39 void
40 parse_rt_tokens(char **tokens, uint32_t n_tokens,
41 	struct parse_status *status)
42 {
43 	uint32_t ti;
44 	uint32_t *n_rts = NULL;
45 	struct ip4_route *route_ipv4 = NULL;
46 	struct ip6_route *route_ipv6 = NULL;
47 
48 	if (strcmp(tokens[0], "ipv4") == 0) {
49 		n_rts = &nb_rt_ip4;
50 		route_ipv4 = &rt_ip4[*n_rts];
51 
52 		APP_CHECK(*n_rts <= RT_IPV4_MAX_RULES - 1, status,
53 			"too many rt rules, abort insertion\n");
54 		if (status->status < 0)
55 			return;
56 
57 	} else if (strcmp(tokens[0], "ipv6") == 0) {
58 		n_rts = &nb_rt_ip6;
59 		route_ipv6 = &rt_ip6[*n_rts];
60 
61 		APP_CHECK(*n_rts <= RT_IPV6_MAX_RULES - 1, status,
62 			"too many rt rules, abort insertion\n");
63 		if (status->status < 0)
64 			return;
65 	} else {
66 		APP_CHECK(0, status, "unrecognized input \"%s\"",
67 			tokens[0]);
68 		return;
69 	}
70 
71 	for (ti = 1; ti < n_tokens; ti++) {
72 		if (strcmp(tokens[ti], "dst") == 0) {
73 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
74 			if (status->status < 0)
75 				return;
76 
77 			if (route_ipv4 != NULL) {
78 				struct in_addr ip;
79 				uint32_t depth = 0;
80 
81 				APP_CHECK(parse_ipv4_addr(tokens[ti],
82 					&ip, &depth) == 0, status,
83 					"unrecognized input \"%s\", "
84 					"expect valid ipv4 addr",
85 					tokens[ti]);
86 				if (status->status < 0)
87 					return;
88 				route_ipv4->ip = rte_bswap32(
89 					(uint32_t)ip.s_addr);
90 				route_ipv4->depth = (uint8_t)depth;
91 			} else {
92 				struct rte_ipv6_addr ip;
93 				uint32_t depth;
94 
95 				APP_CHECK(parse_ipv6_addr(tokens[ti],
96 					&ip, &depth) == 0, status,
97 					"unrecognized input \"%s\", "
98 					"expect valid ipv6 address",
99 					tokens[ti]);
100 				if (status->status < 0)
101 					return;
102 				route_ipv6->ip = ip;
103 				route_ipv6->depth = (uint8_t)depth;
104 			}
105 		}
106 
107 		if (strcmp(tokens[ti], "port") == 0) {
108 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
109 			if (status->status < 0)
110 				return;
111 			APP_CHECK_TOKEN_IS_NUM(tokens, ti, status);
112 			if (status->status < 0)
113 				return;
114 			if (route_ipv4 != NULL)
115 				route_ipv4->if_out = atoi(tokens[ti]);
116 			else
117 				route_ipv6->if_out = atoi(tokens[ti]);
118 		}
119 	}
120 
121 	*n_rts = *n_rts + 1;
122 }
123 
124 void
125 rt_init(struct socket_ctx *ctx, int32_t socket_id)
126 {
127 	char name[PATH_MAX];
128 	uint32_t i;
129 	int32_t ret;
130 	struct rte_lpm *lpm;
131 	struct rte_lpm6 *lpm6;
132 	char a, b, c, d;
133 	struct rte_lpm_config conf = { 0 };
134 	struct rte_lpm6_config conf6 = { 0 };
135 
136 	if (ctx == NULL)
137 		rte_exit(EXIT_FAILURE, "NULL context.\n");
138 
139 	if (ctx->rt_ip4 != NULL)
140 		rte_exit(EXIT_FAILURE, "IPv4 Routing Table for socket %u "
141 			"already initialized\n", socket_id);
142 
143 	if (ctx->rt_ip6 != NULL)
144 		rte_exit(EXIT_FAILURE, "IPv6 Routing Table for socket %u "
145 			"already initialized\n", socket_id);
146 
147 	if (nb_rt_ip4 == 0 && nb_rt_ip6 == 0)
148 		RTE_LOG(WARNING, IPSEC, "No Routing rule specified\n");
149 
150 	printf("Creating IPv4 Routing Table (RT) context with %u max routes\n",
151 			RT_IPV4_MAX_RULES);
152 
153 	/* create the LPM table */
154 	snprintf(name, sizeof(name), "%s_%u", "rt_ip4", socket_id);
155 	conf.max_rules = RT_IPV4_MAX_RULES;
156 	conf.number_tbl8s = RTE_LPM_TBL8_NUM_ENTRIES;
157 	lpm = rte_lpm_create(name, socket_id, &conf);
158 	if (lpm == NULL)
159 		rte_exit(EXIT_FAILURE, "Unable to create %s LPM table "
160 			"on socket %d\n", name, socket_id);
161 
162 	/* populate the LPM table */
163 	for (i = 0; i < nb_rt_ip4; i++) {
164 		ret = rte_lpm_add(lpm, rt_ip4[i].ip, rt_ip4[i].depth,
165 			rt_ip4[i].if_out);
166 		if (ret < 0)
167 			rte_exit(EXIT_FAILURE, "Fail to add entry num %u to %s "
168 				"LPM table on socket %d\n", i, name, socket_id);
169 
170 		uint32_t_to_char(rt_ip4[i].ip, &a, &b, &c, &d);
171 		printf("LPM: Adding route %hhu.%hhu.%hhu.%hhu/%hhu (%hhu)\n",
172 				a, b, c, d, rt_ip4[i].depth,
173 				rt_ip4[i].if_out);
174 	}
175 
176 	snprintf(name, sizeof(name), "%s_%u", "rt_ip6", socket_id);
177 	conf6.max_rules = RT_IPV6_MAX_RULES;
178 	conf6.number_tbl8s = RTE_LPM_TBL8_NUM_ENTRIES;
179 	lpm6 = rte_lpm6_create(name, socket_id, &conf6);
180 	if (lpm6 == NULL)
181 		rte_exit(EXIT_FAILURE, "Unable to create %s LPM table "
182 			"on socket %d\n", name, socket_id);
183 
184 	/* populate the LPM table */
185 	for (i = 0; i < nb_rt_ip6; i++) {
186 		ret = rte_lpm6_add(lpm6, &rt_ip6[i].ip, rt_ip6[i].depth,
187 				rt_ip6[i].if_out);
188 		if (ret < 0)
189 			rte_exit(EXIT_FAILURE, "Fail to add entry num %u to %s "
190 				"LPM table on socket %d\n", i, name, socket_id);
191 
192 		printf("LPM6: Adding route "
193 			" %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%hhx (%hhx)\n",
194 			(uint16_t)((rt_ip6[i].ip.a[0] << 8) | rt_ip6[i].ip.a[1]),
195 			(uint16_t)((rt_ip6[i].ip.a[2] << 8) | rt_ip6[i].ip.a[3]),
196 			(uint16_t)((rt_ip6[i].ip.a[4] << 8) | rt_ip6[i].ip.a[5]),
197 			(uint16_t)((rt_ip6[i].ip.a[6] << 8) | rt_ip6[i].ip.a[7]),
198 			(uint16_t)((rt_ip6[i].ip.a[8] << 8) | rt_ip6[i].ip.a[9]),
199 			(uint16_t)((rt_ip6[i].ip.a[10] << 8) | rt_ip6[i].ip.a[11]),
200 			(uint16_t)((rt_ip6[i].ip.a[12] << 8) | rt_ip6[i].ip.a[13]),
201 			(uint16_t)((rt_ip6[i].ip.a[14] << 8) | rt_ip6[i].ip.a[15]),
202 			rt_ip6[i].depth, rt_ip6[i].if_out);
203 	}
204 
205 	ctx->rt_ip4 = (struct rt_ctx *)lpm;
206 	ctx->rt_ip6 = (struct rt_ctx *)lpm6;
207 }
208