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