]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_flowspec_util.c
bgpd: add bgp_pbr_route structure
[mirror_frr.git] / bgpd / bgp_flowspec_util.c
CommitLineData
034cdee9
PG
1/* BGP FlowSpec Utilities
2 * Portions:
3 * Copyright (C) 2017 ChinaTelecom SDN Group
4 * Copyright (C) 2018 6WIND
5 *
6 * FRRouting is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * FRRouting is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#include "zebra.h"
22
23#include "prefix.h"
98a9dbc7
PG
24
25#include "bgp_table.h"
034cdee9 26#include "bgp_flowspec_util.h"
98a9dbc7 27#include "bgp_flowspec_private.h"
034cdee9
PG
28
29static void hex2bin(uint8_t *hex, int *bin)
30{
31 int remainder = *hex;
32 int i = 0;
33
34 while (remainder >= 1 && i < 8) {
35 bin[7-i] = remainder % 2;
36 remainder = remainder / 2;
37 i++;
38 }
39 for (; i < 8; i++)
40 bin[7-i] = 0;
41}
42
43static int hexstr2num(uint8_t *hexstr, int len)
44{
45 int i = 0;
46 int num = 0;
47
48 for (i = 0; i < len; i++)
49 num = hexstr[i] + 16*16*num;
50 return num;
51}
52
53
54/*
55 * handle the flowspec address src/dst or generic address NLRI
56 * return number of bytes analysed ( >= 0).
57 */
58int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type,
59 uint8_t *nlri_ptr,
60 uint32_t max_len,
61 void *result, int *error)
62{
63 char *display = (char *)result; /* for return_string */
64 struct prefix *prefix = (struct prefix *)result;
65 uint32_t offset = 0;
66 struct prefix prefix_local;
67 int psize;
68
69 *error = 0;
70 memset(&prefix_local, 0, sizeof(struct prefix));
71 /* read the prefix length */
72 prefix_local.prefixlen = nlri_ptr[offset];
73 psize = PSIZE(prefix_local.prefixlen);
74 offset++;
75 /* TODO Flowspec IPv6 Support */
76 prefix_local.family = AF_INET;
77 /* Prefix length check. */
78 if (prefix_local.prefixlen > prefix_blen(&prefix_local) * 8)
79 *error = -1;
80 /* When packet overflow occur return immediately. */
81 if (psize + offset > max_len)
82 *error = -1;
83 /* Defensive coding, double-check
84 * the psize fits in a struct prefix
85 */
86 if (psize > (ssize_t)sizeof(prefix_local.u))
87 *error = -1;
88 memcpy(&prefix_local.u.prefix, &nlri_ptr[offset], psize);
89 offset += psize;
90 switch (type) {
91 case BGP_FLOWSPEC_RETURN_STRING:
92 prefix2str(&prefix_local, display,
93 BGP_FLOWSPEC_STRING_DISPLAY_MAX);
94 break;
95 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
96 PREFIX_COPY_IPV4(prefix, &prefix_local)
97 break;
98 case BGP_FLOWSPEC_VALIDATE_ONLY:
99 default:
100 break;
101 }
102 return offset;
103}
104
105/*
106 * handle the flowspec operator NLRI
107 * return number of bytes analysed
108 * if there is an error, the passed error param is used to give error:
109 * -1 if decoding error,
362a06e3
PG
110 * if result is a string, its assumed length
111 * is BGP_FLOWSPEC_STRING_DISPLAY_MAX
034cdee9
PG
112 */
113int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type,
114 uint8_t *nlri_ptr,
115 uint32_t max_len,
116 void *result, int *error)
117{
118 int op[8];
119 int len, value, value_size;
120 int loop = 0;
121 char *ptr = (char *)result; /* for return_string */
122 uint32_t offset = 0;
362a06e3
PG
123 int len_string = BGP_FLOWSPEC_STRING_DISPLAY_MAX;
124 int len_written;
034cdee9
PG
125
126 *error = 0;
127 do {
128 hex2bin(&nlri_ptr[offset], op);
129 offset++;
130 len = 2*op[2]+op[3];
131 value_size = 1 << len;
132 value = hexstr2num(&nlri_ptr[offset], value_size);
133 /* can not be < and > at the same time */
134 if (op[5] == 1 && op[6] == 1)
135 *error = -1;
136 /* if first element, AND bit can not be set */
137 if (op[1] == 1 && loop == 0)
138 *error = -1;
139 switch (type) {
140 case BGP_FLOWSPEC_RETURN_STRING:
362a06e3
PG
141 if (loop) {
142 len_written = snprintf(ptr, len_string,
143 ", ");
144 len_string -= len_written;
145 ptr += len_written;
146 }
147 if (op[5] == 1) {
148 len_written = snprintf(ptr, len_string,
149 "<");
150 len_string -= len_written;
151 ptr += len_written;
152 }
153 if (op[6] == 1) {
154 len_written = snprintf(ptr, len_string,
155 ">");
156 len_string -= len_written;
157 ptr += len_written;
158 }
159 if (op[7] == 1) {
160 len_written = snprintf(ptr, len_string,
161 "=");
162 len_string -= len_written;
163 ptr += len_written;
164 }
165 len_written = snprintf(ptr, len_string,
166 " %d ", value);
167 len_string -= len_written;
168 ptr += len_written;
034cdee9
PG
169 break;
170 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
171 /* TODO : FS OPAQUE */
172 break;
173 case BGP_FLOWSPEC_VALIDATE_ONLY:
174 default:
175 /* no action */
176 break;
177 }
178 offset += value_size;
179 loop++;
180 } while (op[0] == 0 && offset < max_len - 1);
181 if (offset > max_len)
182 *error = -1;
183 /* use error parameter to count the number of entries */
184 if (*error == 0)
185 *error = loop;
186 return offset;
187}
188
189
190/*
191 * handle the flowspec tcpflags field
192 * return number of bytes analysed
193 * if there is an error, the passed error param is used to give error:
194 * -1 if decoding error,
362a06e3
PG
195 * if result is a string, its assumed length
196 * is BGP_FLOWSPEC_STRING_DISPLAY_MAX
034cdee9
PG
197 */
198int bgp_flowspec_tcpflags_decode(enum bgp_flowspec_util_nlri_t type,
199 uint8_t *nlri_ptr,
200 uint32_t max_len,
201 void *result, int *error)
202{
203 int op[8];
204 int len, value_size, loop = 0, value;
205 char *ptr = (char *)result; /* for return_string */
206 uint32_t offset = 0;
362a06e3
PG
207 int len_string = BGP_FLOWSPEC_STRING_DISPLAY_MAX;
208 int len_written;
034cdee9
PG
209
210 *error = 0;
211 do {
212 hex2bin(&nlri_ptr[offset], op);
213 /* if first element, AND bit can not be set */
214 if (op[1] == 1 && loop == 0)
215 *error = -1;
216 offset++;
217 len = 2 * op[2] + op[3];
218 value_size = 1 << len;
219 value = hexstr2num(&nlri_ptr[offset], value_size);
220 switch (type) {
221 case BGP_FLOWSPEC_RETURN_STRING:
362a06e3
PG
222 if (op[1] == 1 && loop != 0) {
223 len_written = snprintf(ptr, len_string,
224 ", and ");
225 len_string -= len_written;
226 ptr += len_written;
227 } else if (op[1] == 0 && loop != 0) {
228 len_written = snprintf(ptr, len_string,
229 ", or ");
230 len_string -= len_written;
231 ptr += len_written;
232 }
233 len_written = snprintf(ptr, len_string,
234 "tcp flags is ");
235 len_string -= len_written;
236 ptr += len_written;
237 if (op[6] == 1) {
238 ptr += snprintf(ptr, len_string,
239 "not ");
240 len_string -= len_written;
241 ptr += len_written;
242 }
243 if (op[7] == 1) {
244 ptr += snprintf(ptr, len_string,
245 "exactly match ");
246 len_string -= len_written;
247 ptr += len_written;
248 }
249 ptr += snprintf(ptr, len_string,
250 "%d", value);
251 len_string -= len_written;
252 ptr += len_written;
034cdee9
PG
253 break;
254 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
255 /* TODO : FS OPAQUE */
256 break;
257 case BGP_FLOWSPEC_VALIDATE_ONLY:
258 default:
259 /* no action */
260 break;
261 }
262 offset += value_size;
263 loop++;
264 } while (op[0] == 0 && offset < max_len - 1);
265 if (offset > max_len)
266 *error = -1;
267 /* use error parameter to count the number of entries */
268 if (*error == 0)
269 *error = loop;
270 return offset;
271}
272
273/*
274 * handle the flowspec fragment type field
275 * return error (returned values are invalid) or number of bytes analysed
276 * -1 if error in decoding
277 * >= 0 : number of bytes analysed (ok).
278 */
279int bgp_flowspec_fragment_type_decode(enum bgp_flowspec_util_nlri_t type,
280 uint8_t *nlri_ptr,
281 uint32_t max_len,
282 void *result, int *error)
283{
284 int op[8];
285 int len, value, value_size, loop = 0;
286 char *ptr = (char *)result; /* for return_string */
287 uint32_t offset = 0;
362a06e3
PG
288 int len_string = BGP_FLOWSPEC_STRING_DISPLAY_MAX;
289 int len_written;
034cdee9
PG
290
291 *error = 0;
292 do {
293 hex2bin(&nlri_ptr[offset], op);
294 offset++;
295 len = 2 * op[2] + op[3];
296 value_size = 1 << len;
297 value = hexstr2num(&nlri_ptr[offset], value_size);
298 if (value != 1 && value != 2 && value != 4 && value != 8)
299 *error = -1;
300 offset += value_size;
301 /* TODO : as per RFC5574 : first Fragment bits are Reserved
302 * does that mean that it is not possible
303 * to handle multiple occurences ?
304 * as of today, we only grab the first TCP fragment
305 */
306 if (loop) {
307 *error = -2;
308 loop++;
309 continue;
310 }
311 switch (type) {
312 case BGP_FLOWSPEC_RETURN_STRING:
313 switch (value) {
314 case 1:
362a06e3
PG
315 len_written = snprintf(ptr, len_string,
316 "dont-fragment");
317 len_string -= len_written;
318 ptr += len_written;
034cdee9
PG
319 break;
320 case 2:
362a06e3
PG
321 len_written = snprintf(ptr, len_string,
322 "is-fragment");
323 len_string -= len_written;
324 ptr += len_written;
034cdee9
PG
325 break;
326 case 4:
362a06e3
PG
327 len_written = snprintf(ptr, len_string,
328 "first-fragment");
329 len_string -= len_written;
330 ptr += len_written;
034cdee9
PG
331 break;
332 case 8:
362a06e3
PG
333 len_written = snprintf(ptr, len_string,
334 "last-fragment");
335 len_string -= len_written;
336 ptr += len_written;
034cdee9
PG
337 break;
338 default:
339 {}
340 }
341 break;
342 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
343 /* TODO : FS OPAQUE */
344 break;
345 case BGP_FLOWSPEC_VALIDATE_ONLY:
346 default:
347 /* no action */
348 break;
349 }
350 loop++;
351 } while (op[0] == 0 && offset < max_len - 1);
352 if (offset > max_len)
353 *error = -1;
354 return offset;
355}
98a9dbc7
PG
356
357
358static bool bgp_flowspec_contains_prefix(struct prefix *pfs,
359 struct prefix *input,
360 int prefix_check)
361{
362 uint32_t offset = 0;
363 int type;
364 int ret = 0, error = 0;
365 uint8_t *nlri_content = (uint8_t *)pfs->u.prefix_flowspec.ptr;
366 size_t len = pfs->u.prefix_flowspec.prefixlen;
367 struct prefix compare;
368
369 error = 0;
370 while (offset < len-1 && error >= 0) {
371 type = nlri_content[offset];
372 offset++;
373 switch (type) {
374 case FLOWSPEC_DEST_PREFIX:
375 case FLOWSPEC_SRC_PREFIX:
376 memset(&compare, 0, sizeof(struct prefix));
377 ret = bgp_flowspec_ip_address(
378 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE,
379 nlri_content+offset,
380 len - offset,
381 &compare, &error);
382 if (ret <= 0)
383 break;
384 if (prefix_check &&
385 compare.prefixlen != input->prefixlen)
386 break;
387 if (compare.family != input->family)
388 break;
389 if ((input->family == AF_INET) &&
390 IPV4_ADDR_SAME(&input->u.prefix4,
391 &compare.u.prefix4))
392 return true;
393 if ((input->family == AF_INET6) &&
394 IPV6_ADDR_SAME(&input->u.prefix6.s6_addr,
395 &compare.u.prefix6.s6_addr))
396 return true;
397 break;
398 case FLOWSPEC_IP_PROTOCOL:
399 case FLOWSPEC_PORT:
400 case FLOWSPEC_DEST_PORT:
401 case FLOWSPEC_SRC_PORT:
402 case FLOWSPEC_ICMP_TYPE:
403 case FLOWSPEC_ICMP_CODE:
404 ret = bgp_flowspec_op_decode(BGP_FLOWSPEC_VALIDATE_ONLY,
405 nlri_content+offset,
406 len - offset,
407 NULL, &error);
408 break;
409 case FLOWSPEC_TCP_FLAGS:
410 ret = bgp_flowspec_tcpflags_decode(
411 BGP_FLOWSPEC_VALIDATE_ONLY,
412 nlri_content+offset,
413 len - offset,
414 NULL, &error);
415 break;
416 case FLOWSPEC_PKT_LEN:
417 case FLOWSPEC_DSCP:
418 ret = bgp_flowspec_op_decode(
419 BGP_FLOWSPEC_VALIDATE_ONLY,
420 nlri_content + offset,
421 len - offset, NULL,
422 &error);
423 break;
424 case FLOWSPEC_FRAGMENT:
425 ret = bgp_flowspec_fragment_type_decode(
426 BGP_FLOWSPEC_VALIDATE_ONLY,
427 nlri_content + offset,
428 len - offset, NULL,
429 &error);
430 break;
431 default:
432 error = -1;
433 break;
434 }
435 offset += ret;
436 }
437 return false;
438}
439
440struct bgp_node *bgp_flowspec_get_match_per_ip(afi_t afi,
441 struct bgp_table *rib,
442 struct prefix *match,
443 int prefix_check)
444{
445 struct bgp_node *rn;
446 struct prefix *prefix;
447
448 for (rn = bgp_table_top(rib); rn; rn = bgp_route_next(rn)) {
449 prefix = &rn->p;
450
451 if (prefix->family != AF_FLOWSPEC)
452 continue;
453
454 if (bgp_flowspec_contains_prefix(prefix, match, prefix_check))
455 return rn;
456 }
457 return NULL;
458}