blob: 685871d46edcb34149f86cfda2a6a07bde57a287 [file] [log] [blame]
Florin Coras1c710452017-10-17 00:03:13 -07001/*
2 * Copyright (c) 2017 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14*/
15
16#include <vnet/session/mma_16.h>
17#include <vnet/session/mma_template.c>
18#include <vnet/session/mma_40.h>
19#include <vnet/session/mma_template.c>
20#include <vnet/session/session_rules_table.h>
21#include <vnet/session/transport.h>
22
23static void
24fib_pref_normalize (fib_prefix_t * pref)
25{
26 if (pref->fp_proto == FIB_PROTOCOL_IP4)
27 ip4_address_normalize (&pref->fp_addr.ip4, pref->fp_len);
28 else
29 ip6_address_normalize (&pref->fp_addr.ip6, pref->fp_len);
30}
31
32u8 *
33format_session_rule4 (u8 * s, va_list * args)
34{
35 mma_rules_table_16_t *srt = va_arg (*args, mma_rules_table_16_t *);
36 mma_rule_16_t *sr = va_arg (*args, mma_rule_16_t *);
37 session_mask_or_match_4_t *mask, *match;
38 int i;
39
40 match = (session_mask_or_match_4_t *) & sr->match;
41 mask = (session_mask_or_match_4_t *) & sr->mask;
42
43 s = format (s, "[%d] rule: %U/%d %d %U/%d %d action: %d",
44 mma_rules_table_rule_index_16 (srt, sr), format_ip4_address,
45 &match->lcl_ip,
46 ip4_mask_to_preflen (&mask->lcl_ip),
47 match->lcl_port, format_ip4_address, &match->rmt_ip,
48 ip4_mask_to_preflen (&mask->rmt_ip),
49 match->rmt_port, sr->action_index);
50 if (vec_len (sr->next_indices))
51 {
52 s = format (s, "\n children: ");
53 for (i = 0; i < vec_len (sr->next_indices); i++)
54 s = format (s, "%d ", sr->next_indices[i]);
55 }
56 return s;
57}
58
59u8 *
60format_session_rule6 (u8 * s, va_list * args)
61{
62 mma_rules_table_40_t *srt = va_arg (*args, mma_rules_table_40_t *);
63 mma_rule_40_t *sr = va_arg (*args, mma_rule_40_t *);
64 session_mask_or_match_6_t *mask, *match;
65 int i;
66
67 match = (session_mask_or_match_6_t *) & sr->match;
68 mask = (session_mask_or_match_6_t *) & sr->mask;
69
70 s = format (s, "[%d] rule: %U/%d %d %U/%d %d action: %d",
71 mma_rules_table_rule_index_40 (srt, sr), format_ip6_address,
72 &match->lcl_ip, ip6_mask_to_preflen (&mask->lcl_ip),
73 match->lcl_port, format_ip6_address, &match->rmt_ip,
74 ip6_mask_to_preflen (&mask->rmt_ip), match->rmt_port,
75 sr->action_index);
76 if (vec_len (sr->next_indices))
77 {
78 s = format (s, "\n children: ");
79 for (i = 0; i < vec_len (sr->next_indices); i++)
80 s = format (s, "%d ", sr->next_indices[i]);
81 }
82 return s;
83}
84
85void *
86session_rules_table_get (session_rules_table_t * srt, u8 transport_proto,
87 u8 fib_proto)
88{
89 if (fib_proto == FIB_PROTOCOL_IP4)
90 return &srt->session_rules_tables_16[transport_proto];
91 else if (fib_proto == FIB_PROTOCOL_IP6)
92 return &srt->session_rules_tables_40[transport_proto];
93 return 0;
94}
95
96int
97rule_cmp_16 (mma_rule_16_t * rule1, mma_rule_16_t * rule2)
98{
99 session_mask_or_match_4_t *m1, *m2;
100
101 m1 = (session_mask_or_match_4_t *) & rule1->max_match;
102 m2 = (session_mask_or_match_4_t *) & rule2->max_match;
103 if (m1->rmt_ip.as_u32 != m2->rmt_ip.as_u32)
104 return (m1->rmt_ip.as_u32 < m2->rmt_ip.as_u32 ? -1 : 1);
105 if (m1->lcl_ip.as_u32 != m2->lcl_ip.as_u32)
106 return (m1->lcl_ip.as_u32 < m2->lcl_ip.as_u32 ? -1 : 1);
107 if (m1->rmt_port != m2->rmt_port)
108 return (m1->rmt_port < m2->rmt_port ? -1 : 1);
109 if (m1->lcl_port != m2->lcl_port)
110 return (m1->lcl_port < m2->lcl_port ? -1 : 1);
111 return 0;
112}
113
114int
115rule_cmp_40 (mma_rule_40_t * rule1, mma_rule_40_t * rule2)
116{
117 session_mask_or_match_6_t *r1, *r2;
118 r1 = (session_mask_or_match_6_t *) & rule1->max_match;
119 r2 = (session_mask_or_match_6_t *) & rule2->max_match;
120 if (r1->rmt_ip.as_u64[0] != r2->rmt_ip.as_u64[0])
121 return (r1->rmt_ip.as_u64[0] < r2->rmt_ip.as_u64[0] ? -1 : 1);
122 if (r1->rmt_ip.as_u64[1] != r2->rmt_ip.as_u64[1])
123 return (r1->rmt_ip.as_u64[1] < r2->rmt_ip.as_u64[1] ? -1 : 1);
124 if (r1->lcl_ip.as_u64[0] != r2->lcl_ip.as_u64[0])
125 return (r1->lcl_ip.as_u64[0] < r2->lcl_ip.as_u64[0] ? -1 : 1);
126 if (r1->lcl_ip.as_u64[1] != r2->lcl_ip.as_u64[1])
127 return (r1->lcl_ip.as_u64[1] < r2->lcl_ip.as_u64[1]) ? -1 : 1;
128 if (r1->rmt_port != r2->rmt_port)
129 return (r1->rmt_port < r2->rmt_port ? -1 : 1);
130 if (r1->lcl_port != r2->lcl_port)
131 return (r1->lcl_port < r2->lcl_port ? -1 : 1);
132 return 0;
133}
134
135void
136session_rules_table_init_rule_16 (mma_rule_16_t * rule,
137 fib_prefix_t * lcl, u16 lcl_port,
138 fib_prefix_t * rmt, u16 rmt_port)
139{
140 session_mask_or_match_4_t *match, *mask, *max_match;
141 fib_pref_normalize (lcl);
142 fib_pref_normalize (rmt);
143 match = (session_mask_or_match_4_t *) & rule->match;
144 match->lcl_ip.as_u32 = lcl->fp_addr.ip4.as_u32;
145 match->rmt_ip.as_u32 = rmt->fp_addr.ip4.as_u32;
146 match->lcl_port = lcl_port;
147 match->rmt_port = rmt_port;
148 mask = (session_mask_or_match_4_t *) & rule->mask;
149 ip4_preflen_to_mask (lcl->fp_len, &mask->lcl_ip);
150 ip4_preflen_to_mask (rmt->fp_len, &mask->rmt_ip);
151 mask->lcl_port = lcl_port == 0 ? 0 : (u16) ~ 0;
152 mask->rmt_port = rmt_port == 0 ? 0 : (u16) ~ 0;
153 max_match = (session_mask_or_match_4_t *) & rule->max_match;
154 ip4_prefix_max_address_host_order (&rmt->fp_addr.ip4, rmt->fp_len,
155 &max_match->rmt_ip);
156 ip4_prefix_max_address_host_order (&lcl->fp_addr.ip4, lcl->fp_len,
157 &max_match->lcl_ip);
158 max_match->lcl_port = lcl_port == 0 ? (u16) ~ 0 : lcl_port;
159 max_match->rmt_port = rmt_port == 0 ? (u16) ~ 0 : rmt_port;
160}
161
162void
163session_rules_table_init_rule_40 (mma_rule_40_t * rule,
164 fib_prefix_t * lcl, u16 lcl_port,
165 fib_prefix_t * rmt, u16 rmt_port)
166{
167 session_mask_or_match_6_t *match, *mask, *max_match;
168 fib_pref_normalize (lcl);
169 fib_pref_normalize (rmt);
170 match = (session_mask_or_match_6_t *) & rule->match;
171 clib_memcpy (&match->lcl_ip, &lcl->fp_addr.ip6, sizeof (match->lcl_ip));
172 clib_memcpy (&match->rmt_ip, &rmt->fp_addr.ip6, sizeof (match->rmt_ip));
173 match->lcl_port = lcl_port;
174 match->rmt_port = rmt_port;
175 mask = (session_mask_or_match_6_t *) & rule->mask;
176 ip6_preflen_to_mask (lcl->fp_len, &mask->lcl_ip);
177 ip6_preflen_to_mask (rmt->fp_len, &mask->rmt_ip);
178 mask->lcl_port = lcl_port == 0 ? 0 : (u16) ~ 0;
179 mask->rmt_port = rmt_port == 0 ? 0 : (u16) ~ 0;
180 max_match = (session_mask_or_match_6_t *) & rule->max_match;
181 ip6_prefix_max_address_host_order (&rmt->fp_addr.ip6, rmt->fp_len,
182 &max_match->rmt_ip);
183 ip6_prefix_max_address_host_order (&lcl->fp_addr.ip6, lcl->fp_len,
184 &max_match->lcl_ip);
185 max_match->lcl_port = lcl_port == 0 ? (u16) ~ 0 : lcl_port;
186 max_match->rmt_port = rmt_port == 0 ? (u16) ~ 0 : rmt_port;
187}
188
189mma_rule_16_t *
190session_rules_table_alloc_rule_16 (mma_rules_table_16_t * srt,
191 fib_prefix_t * lcl, u16 lcl_port,
192 fib_prefix_t * rmt, u16 rmt_port)
193{
194 mma_rule_16_t *rule = 0;
195 rule = mma_rules_table_rule_alloc_16 (srt);
196 session_rules_table_init_rule_16 (rule, lcl, lcl_port, rmt, rmt_port);
197 return rule;
198}
199
200mma_rule_40_t *
201session_rules_table_alloc_rule_40 (mma_rules_table_40_t * srt,
202 fib_prefix_t * lcl, u16 lcl_port,
203 fib_prefix_t * rmt, u16 rmt_port)
204{
205 mma_rule_40_t *rule;
206 rule = mma_rules_table_rule_alloc_40 (srt);
207 session_rules_table_init_rule_40 (rule, lcl, lcl_port, rmt, rmt_port);
208 return rule;
209}
210
211clib_error_t *
212session_rules_table_add_del (session_rules_table_t * srt,
213 session_rule_table_add_del_args_t * args)
214{
215 u8 fib_proto = args->rmt.fp_proto;
216
217 if (args->transport_proto != TRANSPORT_PROTO_TCP
218 && args->transport_proto != TRANSPORT_PROTO_UDP)
219 return clib_error_return_code (0, VNET_API_ERROR_INVALID_VALUE, 0,
220 "invalid transport proto");
221
222 if (fib_proto == FIB_PROTOCOL_IP4)
223 {
224 mma_rules_table_16_t *srt4;
225 srt4 = &srt->session_rules_tables_16[args->transport_proto];
226 if (args->is_add)
227 {
228 mma_rule_16_t *rule;
229 rule = session_rules_table_alloc_rule_16 (srt4, &args->lcl,
230 args->lcl_port,
231 &args->rmt,
232 args->rmt_port);
233 rule->action_index = args->action_index;
234 mma_rules_table_add_rule_16 (srt4, rule);
235 }
236 else
237 {
238 mma_rule_16_t rule;
239 memset (&rule, 0, sizeof (rule));
240 session_rules_table_init_rule_16 (&rule, &args->lcl, args->lcl_port,
241 &args->rmt, args->rmt_port);
242 mma_rules_table_del_rule_16 (srt4, &rule, srt4->root_index);
243 }
244 }
245 else if (fib_proto == FIB_PROTOCOL_IP6)
246 {
247 mma_rules_table_40_t *srt6;
248 mma_rule_40_t *rule;
249 srt6 = &srt->session_rules_tables_40[args->transport_proto];
250 if (args->is_add)
251 {
252 rule = session_rules_table_alloc_rule_40 (srt6, &args->lcl,
253 args->lcl_port,
254 &args->rmt,
255 args->rmt_port);
256 rule->action_index = args->action_index;
257 mma_rules_table_add_rule_40 (srt6, rule);
258 }
259 else
260 {
261 mma_rule_40_t rule;
262 memset (&rule, 0, sizeof (rule));
263 session_rules_table_init_rule_40 (&rule, &args->lcl, args->lcl_port,
264 &args->rmt, args->rmt_port);
265 mma_rules_table_del_rule_40 (srt6, &rule, srt6->root_index);
266 }
267 }
268 else
269 return clib_error_return_code (0, VNET_API_ERROR_INVALID_VALUE_2, 0,
270 "invalid fib proto");
271 return 0;
272}
273
274u32
275session_rules_table_lookup4 (session_rules_table_t * srt, u8 transport_proto,
276 ip4_address_t * lcl_ip, ip4_address_t * rmt_ip,
277 u16 lcl_port, u16 rmt_port)
278{
279 mma_rules_table_16_t *srt4 = &srt->session_rules_tables_16[transport_proto];
280 session_mask_or_match_4_t key = {
281 .lcl_ip.as_u32 = lcl_ip->as_u32,
282 .rmt_ip.as_u32 = rmt_ip->as_u32,
283 .lcl_port = lcl_port,
284 .rmt_port = rmt_port,
285 };
286 return mma_rules_table_lookup_16 (srt4,
287 (mma_mask_or_match_16_t *) & key,
288 srt4->root_index);
289}
290
291u32
292session_rules_table_lookup6 (session_rules_table_t * srt, u8 transport_proto,
293 ip6_address_t * lcl_ip, ip6_address_t * rmt_ip,
294 u16 lcl_port, u16 rmt_port)
295{
296 mma_rules_table_40_t *srt6 = &srt->session_rules_tables_40[transport_proto];
297 session_mask_or_match_6_t key = {
298 .lcl_port = lcl_port,
299 .rmt_port = rmt_port,
300 };
Florin Corasa2e244c2017-10-29 10:56:15 -0700301 clib_memcpy (&key.lcl_ip, lcl_ip, sizeof (*lcl_ip));
302 clib_memcpy (&key.rmt_ip, rmt_ip, sizeof (*rmt_ip));
Florin Coras1c710452017-10-17 00:03:13 -0700303 return mma_rules_table_lookup_40 (srt6,
304 (mma_mask_or_match_40_t *) & key,
305 srt6->root_index);
306}
307
308void
309session_rules_table_init (session_rules_table_t * srt)
310{
311 mma_rules_table_16_t *srt4;
312 mma_rules_table_40_t *srt6;
313 mma_rule_16_t *rule4;
314 mma_rule_40_t *rule6;
315 fib_prefix_t null_prefix;
316 int i;
317
318 memset (&null_prefix, 0, sizeof (null_prefix));
319
320 for (i = 0; i < TRANSPORT_N_PROTO; i++)
321 {
322 srt4 = &srt->session_rules_tables_16[i];
323 rule4 = session_rules_table_alloc_rule_16 (srt4, &null_prefix, 0,
324 &null_prefix, 0);
325 rule4->action_index = SESSION_RULES_TABLE_INVALID_INDEX;
326 srt4->root_index = mma_rules_table_rule_index_16 (srt4, rule4);
327 srt4->rule_cmp_fn = rule_cmp_16;
328 }
329
330 for (i = 0; i < TRANSPORT_N_PROTO; i++)
331 {
332 srt6 = &srt->session_rules_tables_40[i];;
333 rule6 = session_rules_table_alloc_rule_40 (srt6, &null_prefix, 0,
334 &null_prefix, 0);
335 rule6->action_index = SESSION_RULES_TABLE_INVALID_INDEX;
336 srt6->root_index = mma_rules_table_rule_index_40 (srt6, rule6);
337 srt6->rule_cmp_fn = rule_cmp_40;
338 }
339}
340
341void
342session_rules_table_show_rule (vlib_main_t * vm, session_rules_table_t * srt,
343 u8 transport_proto, ip46_address_t * lcl_ip,
344 u16 lcl_port, ip46_address_t * rmt_ip,
345 u16 rmt_port, u8 is_ip4)
346{
347 mma_rules_table_16_t *srt4;
348 mma_rules_table_40_t *srt6;
349 mma_rule_16_t *sr4;
350 mma_rule_40_t *sr6;
351 u32 ri;
352
353 if (is_ip4)
354 {
355 srt4 = session_rules_table_get (srt, transport_proto, FIB_PROTOCOL_IP4);
356 session_mask_or_match_4_t key = {
357 .lcl_ip.as_u32 = lcl_ip->ip4.as_u32,
358 .rmt_ip.as_u32 = rmt_ip->ip4.as_u32,
359 .lcl_port = lcl_port,
360 .rmt_port = rmt_port,
361 };
362 ri =
363 mma_rules_table_lookup_rule_16 (srt4,
364 (mma_mask_or_match_16_t *) & key,
365 srt4->root_index);
366 sr4 = mma_rules_table_get_rule_16 (srt4, ri);
367 vlib_cli_output (vm, "%U", format_session_rule4, srt4, sr4);
368 }
369 else
370 {
371 srt6 = session_rules_table_get (srt, transport_proto, FIB_PROTOCOL_IP6);
372 session_mask_or_match_6_t key = {
373 .lcl_port = lcl_port,
374 .rmt_port = rmt_port,
375 };
Florin Corasa2e244c2017-10-29 10:56:15 -0700376 clib_memcpy (&key.lcl_ip, &lcl_ip->ip6, sizeof (lcl_ip->ip6));
377 clib_memcpy (&key.rmt_ip, &rmt_ip->ip6, sizeof (rmt_ip->ip6));
Florin Coras1c710452017-10-17 00:03:13 -0700378 ri =
379 mma_rules_table_lookup_rule_40 (srt6,
380 (mma_mask_or_match_40_t *) &
381 key, srt6->root_index);
382 sr6 = mma_rules_table_get_rule_40 (srt6, ri);
383 vlib_cli_output (vm, "%U", format_session_rule6, srt6, sr6);
384 }
385}
386
387void
388session_rules_table_cli_dump (vlib_main_t * vm, session_rules_table_t * srt,
389 u8 fib_proto, u8 transport_proto)
390{
391 if (fib_proto == FIB_PROTOCOL_IP4)
392 {
393 mma_rules_table_16_t *srt4;
394 mma_rule_16_t *sr4;
395 srt4 = &srt->session_rules_tables_16[transport_proto];
396 vlib_cli_output (vm, "%U IP4 rules table", format_transport_proto,
397 transport_proto);
398
399 /* *INDENT-OFF* */
400 pool_foreach(sr4, srt4->rules, ({
401 vlib_cli_output (vm, "%U", format_session_rule4, srt4, sr4);
402 }));
403 /* *INDENT-ON* */
404
405 }
406 else if (fib_proto == FIB_PROTOCOL_IP6)
407 {
408 mma_rules_table_40_t *srt6;
409 mma_rule_40_t *sr6;
410 srt6 = &srt->session_rules_tables_40[transport_proto];
411 vlib_cli_output (vm, "\n%U IP6 rules table", format_transport_proto,
412 transport_proto);
413
414 /* *INDENT-OFF* */
415 pool_foreach(sr6, srt6->rules, ({
416 vlib_cli_output (vm, "%U", format_session_rule6, srt6, sr6);
417 }));
418 /* *INDENT-ON* */
419
420 }
421}
422
423/*
424 * fd.io coding-style-patch-verification: ON
425 *
426 * Local Variables:
427 * eval: (c-set-style "gnu")
428 * End:
429 */