Line data Source code
1 : /* BGP Extended Communities Attribute
2 : Copyright (C) 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
3 :
4 : This file is part of GNU Zebra.
5 :
6 : GNU Zebra 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 : GNU Zebra 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
17 : along with GNU Zebra; see the file COPYING. If not, write to the Free
18 : Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 : 02111-1307, USA. */
20 :
21 : #include <zebra.h>
22 :
23 : #include "hash.h"
24 : #include "memory.h"
25 : #include "prefix.h"
26 : #include "command.h"
27 :
28 : #include "bgpd/bgpd.h"
29 : #include "bgpd/bgp_ecommunity.h"
30 : #include "bgpd/bgp_aspath.h"
31 :
32 : /* Hash of community attribute. */
33 : static struct hash *ecomhash;
34 :
35 : /* Allocate a new ecommunities. */
36 : static struct ecommunity *
37 8 : ecommunity_new (void)
38 : {
39 8 : return (struct ecommunity *) XCALLOC (MTYPE_ECOMMUNITY,
40 : sizeof (struct ecommunity));
41 : }
42 :
43 : /* Allocate ecommunities. */
44 : void
45 8 : ecommunity_free (struct ecommunity **ecom)
46 : {
47 8 : if ((*ecom)->val)
48 8 : XFREE (MTYPE_ECOMMUNITY_VAL, (*ecom)->val);
49 8 : if ((*ecom)->str)
50 4 : XFREE (MTYPE_ECOMMUNITY_STR, (*ecom)->str);
51 8 : XFREE (MTYPE_ECOMMUNITY, *ecom);
52 8 : ecom = NULL;
53 8 : }
54 :
55 : /* Add a new Extended Communities value to Extended Communities
56 : Attribute structure. When the value is already exists in the
57 : structure, we don't add the value. Newly added value is sorted by
58 : numerical order. When the value is added to the structure return 1
59 : else return 0. */
60 : static int
61 8 : ecommunity_add_val (struct ecommunity *ecom, struct ecommunity_val *eval)
62 : {
63 : u_int8_t *p;
64 : int ret;
65 : int c;
66 :
67 : /* When this is fist value, just add it. */
68 8 : if (ecom->val == NULL)
69 : {
70 8 : ecom->size++;
71 8 : ecom->val = XMALLOC (MTYPE_ECOMMUNITY_VAL, ecom_length (ecom));
72 8 : memcpy (ecom->val, eval->val, ECOMMUNITY_SIZE);
73 8 : return 1;
74 : }
75 :
76 : /* If the value already exists in the structure return 0. */
77 0 : c = 0;
78 0 : for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++)
79 : {
80 0 : ret = memcmp (p, eval->val, ECOMMUNITY_SIZE);
81 0 : if (ret == 0)
82 0 : return 0;
83 0 : if (ret > 0)
84 0 : break;
85 : }
86 :
87 : /* Add the value to the structure with numerical sorting. */
88 0 : ecom->size++;
89 0 : ecom->val = XREALLOC (MTYPE_ECOMMUNITY_VAL, ecom->val, ecom_length (ecom));
90 :
91 0 : memmove (ecom->val + (c + 1) * ECOMMUNITY_SIZE,
92 0 : ecom->val + c * ECOMMUNITY_SIZE,
93 0 : (ecom->size - 1 - c) * ECOMMUNITY_SIZE);
94 0 : memcpy (ecom->val + c * ECOMMUNITY_SIZE, eval->val, ECOMMUNITY_SIZE);
95 :
96 0 : return 1;
97 : }
98 :
99 : /* This function takes pointer to Extended Communites strucutre then
100 : create a new Extended Communities structure by uniq and sort each
101 : Extended Communities value. */
102 : struct ecommunity *
103 4 : ecommunity_uniq_sort (struct ecommunity *ecom)
104 : {
105 : int i;
106 : struct ecommunity *new;
107 : struct ecommunity_val *eval;
108 :
109 4 : if (! ecom)
110 0 : return NULL;
111 :
112 4 : new = ecommunity_new ();
113 :
114 8 : for (i = 0; i < ecom->size; i++)
115 : {
116 4 : eval = (struct ecommunity_val *) (ecom->val + (i * ECOMMUNITY_SIZE));
117 4 : ecommunity_add_val (new, eval);
118 : }
119 4 : return new;
120 : }
121 :
122 : /* Parse Extended Communites Attribute in BGP packet. */
123 : struct ecommunity *
124 4 : ecommunity_parse (u_int8_t *pnt, u_short length)
125 : {
126 : struct ecommunity tmp;
127 : struct ecommunity *new;
128 :
129 : /* Length check. */
130 4 : if (length % ECOMMUNITY_SIZE)
131 0 : return NULL;
132 :
133 : /* Prepare tmporary structure for making a new Extended Communities
134 : Attribute. */
135 4 : tmp.size = length / ECOMMUNITY_SIZE;
136 4 : tmp.val = pnt;
137 :
138 : /* Create a new Extended Communities Attribute by uniq and sort each
139 : Extended Communities value */
140 4 : new = ecommunity_uniq_sort (&tmp);
141 :
142 4 : return ecommunity_intern (new);
143 : }
144 :
145 : /* Duplicate the Extended Communities Attribute structure. */
146 : struct ecommunity *
147 0 : ecommunity_dup (struct ecommunity *ecom)
148 : {
149 : struct ecommunity *new;
150 :
151 0 : new = XCALLOC (MTYPE_ECOMMUNITY, sizeof (struct ecommunity));
152 0 : new->size = ecom->size;
153 0 : if (new->size)
154 : {
155 0 : new->val = XMALLOC (MTYPE_ECOMMUNITY_VAL, ecom->size * ECOMMUNITY_SIZE);
156 0 : memcpy (new->val, ecom->val, ecom->size * ECOMMUNITY_SIZE);
157 : }
158 : else
159 0 : new->val = NULL;
160 0 : return new;
161 : }
162 :
163 : /* Retrun string representation of communities attribute. */
164 : char *
165 8 : ecommunity_str (struct ecommunity *ecom)
166 : {
167 8 : if (! ecom->str)
168 0 : ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY);
169 8 : return ecom->str;
170 : }
171 :
172 : /* Merge two Extended Communities Attribute structure. */
173 : struct ecommunity *
174 0 : ecommunity_merge (struct ecommunity *ecom1, struct ecommunity *ecom2)
175 : {
176 0 : if (ecom1->val)
177 0 : ecom1->val = XREALLOC (MTYPE_ECOMMUNITY_VAL, ecom1->val,
178 : (ecom1->size + ecom2->size) * ECOMMUNITY_SIZE);
179 : else
180 0 : ecom1->val = XMALLOC (MTYPE_ECOMMUNITY_VAL,
181 : (ecom1->size + ecom2->size) * ECOMMUNITY_SIZE);
182 :
183 0 : memcpy (ecom1->val + (ecom1->size * ECOMMUNITY_SIZE),
184 0 : ecom2->val, ecom2->size * ECOMMUNITY_SIZE);
185 0 : ecom1->size += ecom2->size;
186 :
187 0 : return ecom1;
188 : }
189 :
190 : /* Intern Extended Communities Attribute. */
191 : struct ecommunity *
192 4 : ecommunity_intern (struct ecommunity *ecom)
193 : {
194 : struct ecommunity *find;
195 :
196 4 : assert (ecom->refcnt == 0);
197 :
198 4 : find = (struct ecommunity *) hash_get (ecomhash, ecom, hash_alloc_intern);
199 :
200 4 : if (find != ecom)
201 0 : ecommunity_free (&ecom);
202 :
203 4 : find->refcnt++;
204 :
205 4 : if (! find->str)
206 4 : find->str = ecommunity_ecom2str (find, ECOMMUNITY_FORMAT_DISPLAY);
207 :
208 4 : return find;
209 : }
210 :
211 : /* Unintern Extended Communities Attribute. */
212 : void
213 4 : ecommunity_unintern (struct ecommunity **ecom)
214 : {
215 : struct ecommunity *ret;
216 :
217 4 : if ((*ecom)->refcnt)
218 4 : (*ecom)->refcnt--;
219 :
220 : /* Pull off from hash. */
221 4 : if ((*ecom)->refcnt == 0)
222 : {
223 : /* Extended community must be in the hash. */
224 4 : ret = (struct ecommunity *) hash_release (ecomhash, *ecom);
225 4 : assert (ret != NULL);
226 :
227 4 : ecommunity_free (ecom);
228 : }
229 4 : }
230 :
231 : /* Utinity function to make hash key. */
232 : unsigned int
233 8 : ecommunity_hash_make (void *arg)
234 : {
235 8 : const struct ecommunity *ecom = arg;
236 8 : int size = ecom->size * ECOMMUNITY_SIZE;
237 8 : u_int8_t *pnt = ecom->val;
238 8 : unsigned int key = 0;
239 : int c;
240 :
241 16 : for (c = 0; c < size; c += ECOMMUNITY_SIZE)
242 : {
243 8 : key += pnt[c];
244 8 : key += pnt[c + 1];
245 8 : key += pnt[c + 2];
246 8 : key += pnt[c + 3];
247 8 : key += pnt[c + 4];
248 8 : key += pnt[c + 5];
249 8 : key += pnt[c + 6];
250 8 : key += pnt[c + 7];
251 : }
252 :
253 8 : return key;
254 : }
255 :
256 : /* Compare two Extended Communities Attribute structure. */
257 : int
258 4 : ecommunity_cmp (const void *arg1, const void *arg2)
259 : {
260 4 : const struct ecommunity *ecom1 = arg1;
261 4 : const struct ecommunity *ecom2 = arg2;
262 :
263 8 : return (ecom1->size == ecom2->size
264 4 : && memcmp (ecom1->val, ecom2->val, ecom1->size * ECOMMUNITY_SIZE) == 0);
265 : }
266 :
267 : /* Initialize Extended Comminities related hash. */
268 : void
269 2 : ecommunity_init (void)
270 : {
271 2 : ecomhash = hash_create (ecommunity_hash_make, ecommunity_cmp);
272 2 : }
273 :
274 : void
275 0 : ecommunity_finish (void)
276 : {
277 0 : hash_free (ecomhash);
278 0 : ecomhash = NULL;
279 0 : }
280 :
281 : /* Extended Communities token enum. */
282 : enum ecommunity_token
283 : {
284 : ecommunity_token_rt,
285 : ecommunity_token_soo,
286 : ecommunity_token_val,
287 : ecommunity_token_unknown
288 : };
289 :
290 : /* Get next Extended Communities token from the string. */
291 : static const char *
292 12 : ecommunity_gettoken (const char *str, struct ecommunity_val *eval,
293 : enum ecommunity_token *token)
294 : {
295 : int ret;
296 12 : int dot = 0;
297 12 : int digit = 0;
298 12 : int separator = 0;
299 12 : const char *p = str;
300 : char *endptr;
301 : struct in_addr ip;
302 12 : as_t as = 0;
303 12 : u_int32_t val = 0;
304 : char buf[INET_ADDRSTRLEN + 1];
305 :
306 : /* Skip white space. */
307 28 : while (isspace ((int) *p))
308 : {
309 4 : p++;
310 4 : str++;
311 : }
312 :
313 : /* Check the end of the line. */
314 12 : if (*p == '\0')
315 4 : return NULL;
316 :
317 : /* "rt" and "soo" keyword parse. */
318 8 : if (! isdigit ((int) *p))
319 : {
320 : /* "rt" match check. */
321 4 : if (tolower ((int) *p) == 'r')
322 : {
323 1 : p++;
324 1 : if (tolower ((int) *p) == 't')
325 : {
326 1 : p++;
327 1 : *token = ecommunity_token_rt;
328 1 : return p;
329 : }
330 0 : if (isspace ((int) *p) || *p == '\0')
331 : {
332 0 : *token = ecommunity_token_rt;
333 0 : return p;
334 : }
335 0 : goto error;
336 : }
337 : /* "soo" match check. */
338 3 : else if (tolower ((int) *p) == 's')
339 : {
340 3 : p++;
341 3 : if (tolower ((int) *p) == 'o')
342 : {
343 3 : p++;
344 3 : if (tolower ((int) *p) == 'o')
345 : {
346 3 : p++;
347 3 : *token = ecommunity_token_soo;
348 3 : return p;
349 : }
350 0 : if (isspace ((int) *p) || *p == '\0')
351 : {
352 0 : *token = ecommunity_token_soo;
353 0 : return p;
354 : }
355 0 : goto error;
356 : }
357 0 : if (isspace ((int) *p) || *p == '\0')
358 : {
359 0 : *token = ecommunity_token_soo;
360 0 : return p;
361 : }
362 0 : goto error;
363 : }
364 0 : goto error;
365 : }
366 :
367 : /* What a mess, there are several possibilities:
368 : *
369 : * a) A.B.C.D:MN
370 : * b) EF:OPQR
371 : * c) GHJK:MN
372 : *
373 : * A.B.C.D: Four Byte IP
374 : * EF: Two byte ASN
375 : * GHJK: Four-byte ASN
376 : * MN: Two byte value
377 : * OPQR: Four byte value
378 : *
379 : */
380 59 : while (isdigit ((int) *p) || *p == ':' || *p == '.')
381 : {
382 51 : if (*p == ':')
383 : {
384 4 : if (separator)
385 0 : goto error;
386 :
387 4 : separator = 1;
388 4 : digit = 0;
389 :
390 4 : if ((p - str) > INET_ADDRSTRLEN)
391 0 : goto error;
392 4 : memset (buf, 0, INET_ADDRSTRLEN + 1);
393 4 : memcpy (buf, str, p - str);
394 :
395 4 : if (dot)
396 : {
397 : /* Parsing A.B.C.D in:
398 : * A.B.C.D:MN
399 : */
400 2 : ret = inet_aton (buf, &ip);
401 2 : if (ret == 0)
402 0 : goto error;
403 : }
404 : else
405 : {
406 : /* ASN */
407 2 : as = strtoul (buf, &endptr, 10);
408 2 : if (*endptr != '\0' || as == BGP_AS4_MAX)
409 : goto error;
410 : }
411 : }
412 47 : else if (*p == '.')
413 : {
414 6 : if (separator)
415 0 : goto error;
416 6 : dot++;
417 6 : if (dot > 4)
418 0 : goto error;
419 : }
420 : else
421 : {
422 41 : digit = 1;
423 :
424 : /* We're past the IP/ASN part */
425 41 : if (separator)
426 : {
427 19 : val *= 10;
428 19 : val += (*p - '0');
429 : }
430 : }
431 51 : p++;
432 : }
433 :
434 : /* Low digit part must be there. */
435 4 : if (!digit || !separator)
436 : goto error;
437 :
438 : /* Encode result into routing distinguisher. */
439 4 : if (dot)
440 : {
441 2 : if (val > UINT16_MAX)
442 0 : goto error;
443 :
444 2 : eval->val[0] = ECOMMUNITY_ENCODE_IP;
445 2 : eval->val[1] = 0;
446 2 : memcpy (&eval->val[2], &ip, sizeof (struct in_addr));
447 2 : eval->val[6] = (val >> 8) & 0xff;
448 2 : eval->val[7] = val & 0xff;
449 : }
450 2 : else if (as > BGP_AS_MAX)
451 : {
452 1 : if (val > UINT16_MAX)
453 0 : goto error;
454 :
455 1 : eval->val[0] = ECOMMUNITY_ENCODE_AS4;
456 1 : eval->val[1] = 0;
457 1 : eval->val[2] = (as >>24) & 0xff;
458 1 : eval->val[3] = (as >>16) & 0xff;
459 1 : eval->val[4] = (as >>8) & 0xff;
460 1 : eval->val[5] = as & 0xff;
461 1 : eval->val[6] = (val >> 8) & 0xff;
462 1 : eval->val[7] = val & 0xff;
463 : }
464 : else
465 : {
466 1 : eval->val[0] = ECOMMUNITY_ENCODE_AS;
467 1 : eval->val[1] = 0;
468 :
469 1 : eval->val[2] = (as >>8) & 0xff;
470 1 : eval->val[3] = as & 0xff;
471 1 : eval->val[4] = (val >>24) & 0xff;
472 1 : eval->val[5] = (val >>16) & 0xff;
473 1 : eval->val[6] = (val >>8) & 0xff;
474 1 : eval->val[7] = val & 0xff;
475 : }
476 4 : *token = ecommunity_token_val;
477 4 : return p;
478 :
479 : error:
480 0 : *token = ecommunity_token_unknown;
481 0 : return p;
482 : }
483 :
484 : /* Convert string to extended community attribute.
485 :
486 : When type is already known, please specify both str and type. str
487 : should not include keyword such as "rt" and "soo". Type is
488 : ECOMMUNITY_ROUTE_TARGET or ECOMMUNITY_SITE_ORIGIN.
489 : keyword_included should be zero.
490 :
491 : For example route-map's "set extcommunity" command case:
492 :
493 : "rt 100:1 100:2 100:3" -> str = "100:1 100:2 100:3"
494 : type = ECOMMUNITY_ROUTE_TARGET
495 : keyword_included = 0
496 :
497 : "soo 100:1" -> str = "100:1"
498 : type = ECOMMUNITY_SITE_ORIGIN
499 : keyword_included = 0
500 :
501 : When string includes keyword for each extended community value.
502 : Please specify keyword_included as non-zero value.
503 :
504 : For example standard extcommunity-list case:
505 :
506 : "rt 100:1 rt 100:2 soo 100:1" -> str = "rt 100:1 rt 100:2 soo 100:1"
507 : type = 0
508 : keyword_include = 1
509 : */
510 : struct ecommunity *
511 4 : ecommunity_str2com (const char *str, int type, int keyword_included)
512 : {
513 4 : struct ecommunity *ecom = NULL;
514 : enum ecommunity_token token;
515 : struct ecommunity_val eval;
516 4 : int keyword = 0;
517 :
518 16 : while ((str = ecommunity_gettoken (str, &eval, &token)))
519 : {
520 8 : switch (token)
521 : {
522 : case ecommunity_token_rt:
523 : case ecommunity_token_soo:
524 4 : if (! keyword_included || keyword)
525 : {
526 0 : if (ecom)
527 0 : ecommunity_free (&ecom);
528 0 : return NULL;
529 : }
530 4 : keyword = 1;
531 :
532 4 : if (token == ecommunity_token_rt)
533 : {
534 1 : type = ECOMMUNITY_ROUTE_TARGET;
535 : }
536 4 : if (token == ecommunity_token_soo)
537 : {
538 3 : type = ECOMMUNITY_SITE_ORIGIN;
539 : }
540 4 : break;
541 : case ecommunity_token_val:
542 4 : if (keyword_included)
543 : {
544 4 : if (! keyword)
545 : {
546 0 : if (ecom)
547 0 : ecommunity_free (&ecom);
548 0 : return NULL;
549 : }
550 4 : keyword = 0;
551 : }
552 4 : if (ecom == NULL)
553 4 : ecom = ecommunity_new ();
554 4 : eval.val[1] = type;
555 4 : ecommunity_add_val (ecom, &eval);
556 4 : break;
557 : case ecommunity_token_unknown:
558 : default:
559 0 : if (ecom)
560 0 : ecommunity_free (&ecom);
561 0 : return NULL;
562 : }
563 : }
564 4 : return ecom;
565 : }
566 :
567 : /* Convert extended community attribute to string.
568 :
569 : Due to historical reason of industry standard implementation, there
570 : are three types of format.
571 :
572 : route-map set extcommunity format
573 : "rt 100:1 100:2"
574 : "soo 100:3"
575 :
576 : extcommunity-list
577 : "rt 100:1 rt 100:2 soo 100:3"
578 :
579 : "show ip bgp" and extcommunity-list regular expression matching
580 : "RT:100:1 RT:100:2 SoO:100:3"
581 :
582 : For each formath please use below definition for format:
583 :
584 : ECOMMUNITY_FORMAT_ROUTE_MAP
585 : ECOMMUNITY_FORMAT_COMMUNITY_LIST
586 : ECOMMUNITY_FORMAT_DISPLAY
587 : */
588 : char *
589 12 : ecommunity_ecom2str (struct ecommunity *ecom, int format)
590 : {
591 : int i;
592 : u_int8_t *pnt;
593 12 : int encode = 0;
594 12 : int type = 0;
595 : #define ECOMMUNITY_STR_DEFAULT_LEN 27
596 : int str_size;
597 : int str_pnt;
598 : char *str_buf;
599 : const char *prefix;
600 12 : int len = 0;
601 12 : int first = 1;
602 :
603 : /* For parse Extended Community attribute tupple. */
604 : struct ecommunity_as
605 : {
606 : as_t as;
607 : u_int32_t val;
608 : } eas;
609 :
610 : struct ecommunity_ip
611 : {
612 : struct in_addr ip;
613 : u_int16_t val;
614 : } eip;
615 :
616 12 : if (ecom->size == 0)
617 : {
618 0 : str_buf = XMALLOC (MTYPE_ECOMMUNITY_STR, 1);
619 0 : str_buf[0] = '\0';
620 0 : return str_buf;
621 : }
622 :
623 : /* Prepare buffer. */
624 12 : str_buf = XMALLOC (MTYPE_ECOMMUNITY_STR, ECOMMUNITY_STR_DEFAULT_LEN + 1);
625 12 : str_size = ECOMMUNITY_STR_DEFAULT_LEN + 1;
626 12 : str_pnt = 0;
627 :
628 24 : for (i = 0; i < ecom->size; i++)
629 : {
630 : /* Make it sure size is enough. */
631 24 : while (str_pnt + ECOMMUNITY_STR_DEFAULT_LEN >= str_size)
632 : {
633 0 : str_size *= 2;
634 0 : str_buf = XREALLOC (MTYPE_ECOMMUNITY_STR, str_buf, str_size);
635 : }
636 :
637 : /* Space between each value. */
638 12 : if (! first)
639 0 : str_buf[str_pnt++] = ' ';
640 :
641 12 : pnt = ecom->val + (i * 8);
642 :
643 : /* High-order octet of type. */
644 12 : encode = *pnt++;
645 12 : if (encode != ECOMMUNITY_ENCODE_AS && encode != ECOMMUNITY_ENCODE_IP
646 3 : && encode != ECOMMUNITY_ENCODE_AS4)
647 : {
648 0 : len = sprintf (str_buf + str_pnt, "?");
649 0 : str_pnt += len;
650 0 : first = 0;
651 0 : continue;
652 : }
653 :
654 : /* Low-order octet of type. */
655 12 : type = *pnt++;
656 12 : if (type != ECOMMUNITY_ROUTE_TARGET && type != ECOMMUNITY_SITE_ORIGIN)
657 : {
658 0 : len = sprintf (str_buf + str_pnt, "?");
659 0 : str_pnt += len;
660 0 : first = 0;
661 0 : continue;
662 : }
663 :
664 12 : switch (format)
665 : {
666 : case ECOMMUNITY_FORMAT_COMMUNITY_LIST:
667 8 : prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "rt " : "soo ");
668 8 : break;
669 : case ECOMMUNITY_FORMAT_DISPLAY:
670 4 : prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "RT:" : "SoO:");
671 4 : break;
672 : case ECOMMUNITY_FORMAT_ROUTE_MAP:
673 0 : prefix = "";
674 0 : break;
675 : default:
676 0 : prefix = "";
677 0 : break;
678 : }
679 :
680 : /* Put string into buffer. */
681 12 : if (encode == ECOMMUNITY_ENCODE_AS4)
682 : {
683 3 : eas.as = (*pnt++ << 24);
684 3 : eas.as |= (*pnt++ << 16);
685 3 : eas.as |= (*pnt++ << 8);
686 3 : eas.as |= (*pnt++);
687 :
688 3 : eas.val = (*pnt++ << 8);
689 3 : eas.val |= (*pnt++);
690 :
691 3 : len = sprintf( str_buf + str_pnt, "%s%u:%d", prefix,
692 : eas.as, eas.val );
693 3 : str_pnt += len;
694 3 : first = 0;
695 : }
696 12 : if (encode == ECOMMUNITY_ENCODE_AS)
697 : {
698 3 : eas.as = (*pnt++ << 8);
699 3 : eas.as |= (*pnt++);
700 :
701 3 : eas.val = (*pnt++ << 24);
702 3 : eas.val |= (*pnt++ << 16);
703 3 : eas.val |= (*pnt++ << 8);
704 3 : eas.val |= (*pnt++);
705 :
706 3 : len = sprintf (str_buf + str_pnt, "%s%u:%d", prefix,
707 : eas.as, eas.val);
708 3 : str_pnt += len;
709 3 : first = 0;
710 : }
711 9 : else if (encode == ECOMMUNITY_ENCODE_IP)
712 : {
713 6 : memcpy (&eip.ip, pnt, 4);
714 6 : pnt += 4;
715 6 : eip.val = (*pnt++ << 8);
716 6 : eip.val |= (*pnt++);
717 :
718 6 : len = sprintf (str_buf + str_pnt, "%s%s:%d", prefix,
719 6 : inet_ntoa (eip.ip), eip.val);
720 6 : str_pnt += len;
721 6 : first = 0;
722 : }
723 : }
724 12 : return str_buf;
725 : }
726 :
727 : int
728 0 : ecommunity_match (const struct ecommunity *ecom1,
729 : const struct ecommunity *ecom2)
730 : {
731 0 : int i = 0;
732 0 : int j = 0;
733 :
734 0 : if (ecom1 == NULL && ecom2 == NULL)
735 0 : return 1;
736 :
737 0 : if (ecom1 == NULL || ecom2 == NULL)
738 0 : return 0;
739 :
740 0 : if (ecom1->size < ecom2->size)
741 0 : return 0;
742 :
743 : /* Every community on com2 needs to be on com1 for this to match */
744 0 : while (i < ecom1->size && j < ecom2->size)
745 : {
746 0 : if (memcmp (ecom1->val + i, ecom2->val + j, ECOMMUNITY_SIZE) == 0)
747 0 : j++;
748 0 : i++;
749 : }
750 :
751 0 : if (j == ecom2->size)
752 0 : return 1;
753 : else
754 0 : return 0;
755 : }
756 :
|