blob: 244ffd1601f35fa5d6468a9822310b730be2fbde [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* 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"
27
28#include "bgpd/bgpd.h"
29#include "bgpd/bgp_ecommunity.h"
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000030#include "bgpd/bgp_aspath.h"
paul718e3742002-12-13 20:15:29 +000031
32/* Hash of community attribute. */
Stephen Hemmingerffa4e2c2009-05-15 10:28:11 -070033static struct hash *ecomhash;
paul718e3742002-12-13 20:15:29 +000034
35/* Allocate a new ecommunities. */
Stephen Hemmingerffa4e2c2009-05-15 10:28:11 -070036static struct ecommunity *
Stephen Hemminger66e5cd82009-02-09 10:14:16 -080037ecommunity_new (void)
paul718e3742002-12-13 20:15:29 +000038{
39 return (struct ecommunity *) XCALLOC (MTYPE_ECOMMUNITY,
40 sizeof (struct ecommunity));
41}
42
43/* Allocate ecommunities. */
44void
45ecommunity_free (struct ecommunity *ecom)
46{
47 if (ecom->val)
48 XFREE (MTYPE_ECOMMUNITY_VAL, ecom->val);
49 if (ecom->str)
50 XFREE (MTYPE_ECOMMUNITY_STR, ecom->str);
51 XFREE (MTYPE_ECOMMUNITY, ecom);
52}
53
54/* Add a new Extended Communities value to Extended Communities
55 Attribute structure. When the value is already exists in the
56 structure, we don't add the value. Newly added value is sorted by
57 numerical order. When the value is added to the structure return 1
58 else return 0. */
59static int
60ecommunity_add_val (struct ecommunity *ecom, struct ecommunity_val *eval)
61{
paul5228ad22004-06-04 17:58:18 +000062 u_int8_t *p;
paul718e3742002-12-13 20:15:29 +000063 int ret;
64 int c;
65
66 /* When this is fist value, just add it. */
67 if (ecom->val == NULL)
68 {
69 ecom->size++;
70 ecom->val = XMALLOC (MTYPE_ECOMMUNITY_VAL, ecom_length (ecom));
71 memcpy (ecom->val, eval->val, ECOMMUNITY_SIZE);
72 return 1;
73 }
74
75 /* If the value already exists in the structure return 0. */
76 c = 0;
77 for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++)
78 {
79 ret = memcmp (p, eval->val, ECOMMUNITY_SIZE);
80 if (ret == 0)
81 return 0;
82 if (ret > 0)
83 break;
84 }
85
86 /* Add the value to the structure with numerical sorting. */
87 ecom->size++;
88 ecom->val = XREALLOC (MTYPE_ECOMMUNITY_VAL, ecom->val, ecom_length (ecom));
89
90 memmove (ecom->val + (c + 1) * ECOMMUNITY_SIZE,
91 ecom->val + c * ECOMMUNITY_SIZE,
92 (ecom->size - 1 - c) * ECOMMUNITY_SIZE);
93 memcpy (ecom->val + c * ECOMMUNITY_SIZE, eval->val, ECOMMUNITY_SIZE);
94
95 return 1;
96}
97
98/* This function takes pointer to Extended Communites strucutre then
99 create a new Extended Communities structure by uniq and sort each
Denis Ovsienkoe6b6a562009-06-01 20:20:36 +0400100 Extended Communities value. */
Josh Bailey0b597ef2011-07-20 20:49:11 -0700101struct ecommunity *
paul718e3742002-12-13 20:15:29 +0000102ecommunity_uniq_sort (struct ecommunity *ecom)
103{
104 int i;
105 struct ecommunity *new;
106 struct ecommunity_val *eval;
107
108 if (! ecom)
109 return NULL;
110
Stephen Hemminger66e5cd82009-02-09 10:14:16 -0800111 new = ecommunity_new ();
paul718e3742002-12-13 20:15:29 +0000112
113 for (i = 0; i < ecom->size; i++)
114 {
115 eval = (struct ecommunity_val *) (ecom->val + (i * ECOMMUNITY_SIZE));
116 ecommunity_add_val (new, eval);
117 }
118 return new;
119}
120
121/* Parse Extended Communites Attribute in BGP packet. */
122struct ecommunity *
paul5228ad22004-06-04 17:58:18 +0000123ecommunity_parse (u_int8_t *pnt, u_short length)
paul718e3742002-12-13 20:15:29 +0000124{
125 struct ecommunity tmp;
126 struct ecommunity *new;
127
128 /* Length check. */
129 if (length % ECOMMUNITY_SIZE)
130 return NULL;
131
132 /* Prepare tmporary structure for making a new Extended Communities
133 Attribute. */
134 tmp.size = length / ECOMMUNITY_SIZE;
135 tmp.val = pnt;
136
137 /* Create a new Extended Communities Attribute by uniq and sort each
138 Extended Communities value */
139 new = ecommunity_uniq_sort (&tmp);
140
141 return ecommunity_intern (new);
142}
143
144/* Duplicate the Extended Communities Attribute structure. */
145struct ecommunity *
146ecommunity_dup (struct ecommunity *ecom)
147{
148 struct ecommunity *new;
149
150 new = XCALLOC (MTYPE_ECOMMUNITY, sizeof (struct ecommunity));
151 new->size = ecom->size;
152 if (new->size)
153 {
154 new->val = XMALLOC (MTYPE_ECOMMUNITY_VAL, ecom->size * ECOMMUNITY_SIZE);
155 memcpy (new->val, ecom->val, ecom->size * ECOMMUNITY_SIZE);
156 }
157 else
158 new->val = NULL;
159 return new;
160}
161
hasso4372df72004-05-20 10:20:02 +0000162/* Retrun string representation of communities attribute. */
163char *
164ecommunity_str (struct ecommunity *ecom)
165{
166 if (! ecom->str)
167 ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY);
168 return ecom->str;
169}
170
paul718e3742002-12-13 20:15:29 +0000171/* Merge two Extended Communities Attribute structure. */
172struct ecommunity *
173ecommunity_merge (struct ecommunity *ecom1, struct ecommunity *ecom2)
174{
175 if (ecom1->val)
176 ecom1->val = XREALLOC (MTYPE_ECOMMUNITY_VAL, ecom1->val,
177 (ecom1->size + ecom2->size) * ECOMMUNITY_SIZE);
178 else
179 ecom1->val = XMALLOC (MTYPE_ECOMMUNITY_VAL,
180 (ecom1->size + ecom2->size) * ECOMMUNITY_SIZE);
181
182 memcpy (ecom1->val + (ecom1->size * ECOMMUNITY_SIZE),
183 ecom2->val, ecom2->size * ECOMMUNITY_SIZE);
184 ecom1->size += ecom2->size;
185
186 return ecom1;
187}
188
189/* Intern Extended Communities Attribute. */
190struct ecommunity *
191ecommunity_intern (struct ecommunity *ecom)
192{
193 struct ecommunity *find;
194
195 assert (ecom->refcnt == 0);
196
197 find = (struct ecommunity *) hash_get (ecomhash, ecom, hash_alloc_intern);
198
199 if (find != ecom)
200 ecommunity_free (ecom);
201
202 find->refcnt++;
203
204 if (! find->str)
205 find->str = ecommunity_ecom2str (find, ECOMMUNITY_FORMAT_DISPLAY);
206
207 return find;
208}
209
210/* Unintern Extended Communities Attribute. */
211void
212ecommunity_unintern (struct ecommunity *ecom)
213{
214 struct ecommunity *ret;
215
216 if (ecom->refcnt)
217 ecom->refcnt--;
218
219 /* Pull off from hash. */
220 if (ecom->refcnt == 0)
221 {
222 /* Extended community must be in the hash. */
223 ret = (struct ecommunity *) hash_release (ecomhash, ecom);
224 assert (ret != NULL);
225
226 ecommunity_free (ecom);
227 }
228}
229
230/* Utinity function to make hash key. */
231unsigned int
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000232ecommunity_hash_make (void *arg)
paul718e3742002-12-13 20:15:29 +0000233{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000234 const struct ecommunity *ecom = arg;
paul718e3742002-12-13 20:15:29 +0000235 int c;
236 unsigned int key;
paul5228ad22004-06-04 17:58:18 +0000237 u_int8_t *pnt;
paul718e3742002-12-13 20:15:29 +0000238
239 key = 0;
240 pnt = ecom->val;
241
242 for (c = 0; c < ecom->size * ECOMMUNITY_SIZE; c++)
243 key += pnt[c];
244
245 return key;
246}
247
248/* Compare two Extended Communities Attribute structure. */
249int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100250ecommunity_cmp (const void *arg1, const void *arg2)
paul718e3742002-12-13 20:15:29 +0000251{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000252 const struct ecommunity *ecom1 = arg1;
253 const struct ecommunity *ecom2 = arg2;
254
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100255 return (ecom1->size == ecom2->size
256 && memcmp (ecom1->val, ecom2->val, ecom1->size * ECOMMUNITY_SIZE) == 0);
paul718e3742002-12-13 20:15:29 +0000257}
258
259/* Initialize Extended Comminities related hash. */
260void
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000261ecommunity_init (void)
paul718e3742002-12-13 20:15:29 +0000262{
263 ecomhash = hash_create (ecommunity_hash_make, ecommunity_cmp);
264}
Chris Caputo228da422009-07-18 05:44:03 +0000265
266void
267ecommunity_finish (void)
268{
269 hash_free (ecomhash);
270 ecomhash = NULL;
271}
paul718e3742002-12-13 20:15:29 +0000272
273/* Extended Communities token enum. */
274enum ecommunity_token
275{
276 ecommunity_token_rt,
277 ecommunity_token_soo,
278 ecommunity_token_val,
279 ecommunity_token_unknown
280};
281
282/* Get next Extended Communities token from the string. */
paul94f2b392005-06-28 12:44:16 +0000283static const char *
paulfd79ac92004-10-13 05:06:08 +0000284ecommunity_gettoken (const char *str, struct ecommunity_val *eval,
paul718e3742002-12-13 20:15:29 +0000285 enum ecommunity_token *token)
286{
287 int ret;
288 int dot = 0;
289 int digit = 0;
290 int separator = 0;
paulfd79ac92004-10-13 05:06:08 +0000291 const char *p = str;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000292 char *endptr;
paul718e3742002-12-13 20:15:29 +0000293 struct in_addr ip;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000294 as_t as = 0;
295 u_int32_t val = 0;
296 char buf[INET_ADDRSTRLEN + 1];
paul718e3742002-12-13 20:15:29 +0000297
298 /* Skip white space. */
299 while (isspace ((int) *p))
300 {
301 p++;
302 str++;
303 }
304
305 /* Check the end of the line. */
306 if (*p == '\0')
307 return NULL;
308
309 /* "rt" and "soo" keyword parse. */
310 if (! isdigit ((int) *p))
311 {
312 /* "rt" match check. */
313 if (tolower ((int) *p) == 'r')
314 {
315 p++;
316 if (tolower ((int) *p) == 't')
317 {
318 p++;
319 *token = ecommunity_token_rt;
320 return p;
321 }
322 if (isspace ((int) *p) || *p == '\0')
323 {
324 *token = ecommunity_token_rt;
325 return p;
326 }
327 goto error;
328 }
329 /* "soo" match check. */
330 else if (tolower ((int) *p) == 's')
331 {
332 p++;
333 if (tolower ((int) *p) == 'o')
334 {
335 p++;
336 if (tolower ((int) *p) == 'o')
337 {
338 p++;
339 *token = ecommunity_token_soo;
340 return p;
341 }
342 if (isspace ((int) *p) || *p == '\0')
343 {
344 *token = ecommunity_token_soo;
345 return p;
346 }
347 goto error;
348 }
349 if (isspace ((int) *p) || *p == '\0')
350 {
351 *token = ecommunity_token_soo;
352 return p;
353 }
354 goto error;
355 }
356 goto error;
357 }
358
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000359 /* What a mess, there are several possibilities:
360 *
361 * a) A.B.C.D:MN
362 * b) EF:OPQR
363 * c) GHJK:MN
364 *
365 * A.B.C.D: Four Byte IP
366 * EF: Two byte ASN
367 * GHJK: Four-byte ASN
368 * MN: Two byte value
369 * OPQR: Four byte value
370 *
371 */
paul718e3742002-12-13 20:15:29 +0000372 while (isdigit ((int) *p) || *p == ':' || *p == '.')
373 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000374 if (*p == ':')
paul718e3742002-12-13 20:15:29 +0000375 {
376 if (separator)
377 goto error;
378
379 separator = 1;
380 digit = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000381
382 if ((p - str) > INET_ADDRSTRLEN)
383 goto error;
384 memset (buf, 0, INET_ADDRSTRLEN + 1);
385 memcpy (buf, str, p - str);
386
paul718e3742002-12-13 20:15:29 +0000387 if (dot)
388 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000389 /* Parsing A.B.C.D in:
390 * A.B.C.D:MN
391 */
392 ret = inet_aton (buf, &ip);
paul718e3742002-12-13 20:15:29 +0000393 if (ret == 0)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000394 goto error;
paul718e3742002-12-13 20:15:29 +0000395 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000396 else
397 {
398 /* ASN */
399 as = strtoul (buf, &endptr, 10);
400 if (*endptr != '\0' || as == BGP_AS4_MAX)
401 goto error;
402 }
paul718e3742002-12-13 20:15:29 +0000403 }
404 else if (*p == '.')
405 {
406 if (separator)
407 goto error;
408 dot++;
409 if (dot > 4)
410 goto error;
411 }
412 else
413 {
414 digit = 1;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000415
416 /* We're past the IP/ASN part */
417 if (separator)
418 {
419 val *= 10;
420 val += (*p - '0');
421 }
paul718e3742002-12-13 20:15:29 +0000422 }
423 p++;
424 }
425
426 /* Low digit part must be there. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000427 if (!digit || !separator)
paul718e3742002-12-13 20:15:29 +0000428 goto error;
429
430 /* Encode result into routing distinguisher. */
431 if (dot)
432 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000433 if (val > UINT16_MAX)
434 goto error;
435
paul718e3742002-12-13 20:15:29 +0000436 eval->val[0] = ECOMMUNITY_ENCODE_IP;
437 eval->val[1] = 0;
438 memcpy (&eval->val[2], &ip, sizeof (struct in_addr));
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000439 eval->val[6] = (val >> 8) & 0xff;
440 eval->val[7] = val & 0xff;
441 }
442 else if (as > BGP_AS_MAX)
443 {
444 if (val > UINT16_MAX)
445 goto error;
446
447 eval->val[0] = ECOMMUNITY_ENCODE_AS4;
448 eval->val[1] = 0;
449 eval->val[2] = (as >>24) & 0xff;
450 eval->val[3] = (as >>16) & 0xff;
451 eval->val[4] = (as >>8) & 0xff;
452 eval->val[5] = as & 0xff;
453 eval->val[6] = (val >> 8) & 0xff;
454 eval->val[7] = val & 0xff;
paul718e3742002-12-13 20:15:29 +0000455 }
456 else
457 {
458 eval->val[0] = ECOMMUNITY_ENCODE_AS;
459 eval->val[1] = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000460
461 eval->val[2] = (as >>8) & 0xff;
462 eval->val[3] = as & 0xff;
463 eval->val[4] = (val >>24) & 0xff;
464 eval->val[5] = (val >>16) & 0xff;
465 eval->val[6] = (val >>8) & 0xff;
466 eval->val[7] = val & 0xff;
paul718e3742002-12-13 20:15:29 +0000467 }
468 *token = ecommunity_token_val;
469 return p;
470
471 error:
472 *token = ecommunity_token_unknown;
473 return p;
474}
475
476/* Convert string to extended community attribute.
477
478 When type is already known, please specify both str and type. str
479 should not include keyword such as "rt" and "soo". Type is
480 ECOMMUNITY_ROUTE_TARGET or ECOMMUNITY_SITE_ORIGIN.
481 keyword_included should be zero.
482
483 For example route-map's "set extcommunity" command case:
484
485 "rt 100:1 100:2 100:3" -> str = "100:1 100:2 100:3"
486 type = ECOMMUNITY_ROUTE_TARGET
487 keyword_included = 0
488
489 "soo 100:1" -> str = "100:1"
490 type = ECOMMUNITY_SITE_ORIGIN
491 keyword_included = 0
492
493 When string includes keyword for each extended community value.
494 Please specify keyword_included as non-zero value.
495
496 For example standard extcommunity-list case:
497
498 "rt 100:1 rt 100:2 soo 100:1" -> str = "rt 100:1 rt 100:2 soo 100:1"
499 type = 0
500 keyword_include = 1
501*/
502struct ecommunity *
paulfd79ac92004-10-13 05:06:08 +0000503ecommunity_str2com (const char *str, int type, int keyword_included)
paul718e3742002-12-13 20:15:29 +0000504{
505 struct ecommunity *ecom = NULL;
506 enum ecommunity_token token;
507 struct ecommunity_val eval;
508 int keyword = 0;
509
510 while ((str = ecommunity_gettoken (str, &eval, &token)))
511 {
512 switch (token)
513 {
514 case ecommunity_token_rt:
515 case ecommunity_token_soo:
516 if (! keyword_included || keyword)
517 {
518 if (ecom)
519 ecommunity_free (ecom);
520 return NULL;
521 }
522 keyword = 1;
523
524 if (token == ecommunity_token_rt)
525 {
526 type = ECOMMUNITY_ROUTE_TARGET;
527 }
528 if (token == ecommunity_token_soo)
529 {
530 type = ECOMMUNITY_SITE_ORIGIN;
531 }
532 break;
533 case ecommunity_token_val:
534 if (keyword_included)
535 {
536 if (! keyword)
537 {
538 if (ecom)
539 ecommunity_free (ecom);
540 return NULL;
541 }
542 keyword = 0;
543 }
544 if (ecom == NULL)
545 ecom = ecommunity_new ();
546 eval.val[1] = type;
547 ecommunity_add_val (ecom, &eval);
548 break;
549 case ecommunity_token_unknown:
550 default:
551 if (ecom)
552 ecommunity_free (ecom);
553 return NULL;
paul718e3742002-12-13 20:15:29 +0000554 }
555 }
556 return ecom;
557}
558
559/* Convert extended community attribute to string.
560
561 Due to historical reason of industry standard implementation, there
562 are three types of format.
563
564 route-map set extcommunity format
565 "rt 100:1 100:2"
566 "soo 100:3"
567
568 extcommunity-list
569 "rt 100:1 rt 100:2 soo 100:3"
570
571 "show ip bgp" and extcommunity-list regular expression matching
572 "RT:100:1 RT:100:2 SoO:100:3"
573
574 For each formath please use below definition for format:
575
576 ECOMMUNITY_FORMAT_ROUTE_MAP
577 ECOMMUNITY_FORMAT_COMMUNITY_LIST
578 ECOMMUNITY_FORMAT_DISPLAY
579*/
580char *
581ecommunity_ecom2str (struct ecommunity *ecom, int format)
582{
583 int i;
paul5228ad22004-06-04 17:58:18 +0000584 u_int8_t *pnt;
paul718e3742002-12-13 20:15:29 +0000585 int encode = 0;
586 int type = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000587#define ECOMMUNITY_STR_DEFAULT_LEN 27
paul718e3742002-12-13 20:15:29 +0000588 int str_size;
589 int str_pnt;
paul5228ad22004-06-04 17:58:18 +0000590 char *str_buf;
paulfd79ac92004-10-13 05:06:08 +0000591 const char *prefix;
paul718e3742002-12-13 20:15:29 +0000592 int len = 0;
593 int first = 1;
594
595 /* For parse Extended Community attribute tupple. */
596 struct ecommunity_as
597 {
598 as_t as;
599 u_int32_t val;
600 } eas;
601
602 struct ecommunity_ip
603 {
604 struct in_addr ip;
605 u_int16_t val;
606 } eip;
607
608 if (ecom->size == 0)
609 {
610 str_buf = XMALLOC (MTYPE_ECOMMUNITY_STR, 1);
611 str_buf[0] = '\0';
612 return str_buf;
613 }
614
615 /* Prepare buffer. */
616 str_buf = XMALLOC (MTYPE_ECOMMUNITY_STR, ECOMMUNITY_STR_DEFAULT_LEN + 1);
617 str_size = ECOMMUNITY_STR_DEFAULT_LEN + 1;
618 str_pnt = 0;
619
620 for (i = 0; i < ecom->size; i++)
621 {
hasso4372df72004-05-20 10:20:02 +0000622 /* Space between each value. */
623 if (! first)
624 str_buf[str_pnt++] = ' ';
625
paul718e3742002-12-13 20:15:29 +0000626 pnt = ecom->val + (i * 8);
627
628 /* High-order octet of type. */
629 encode = *pnt++;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000630 if (encode != ECOMMUNITY_ENCODE_AS && encode != ECOMMUNITY_ENCODE_IP
631 && encode != ECOMMUNITY_ENCODE_AS4)
paul718e3742002-12-13 20:15:29 +0000632 {
hasso4372df72004-05-20 10:20:02 +0000633 len = sprintf (str_buf + str_pnt, "?");
634 str_pnt += len;
635 first = 0;
636 continue;
paul718e3742002-12-13 20:15:29 +0000637 }
638
639 /* Low-order octet of type. */
640 type = *pnt++;
641 if (type != ECOMMUNITY_ROUTE_TARGET && type != ECOMMUNITY_SITE_ORIGIN)
642 {
hasso4372df72004-05-20 10:20:02 +0000643 len = sprintf (str_buf + str_pnt, "?");
644 str_pnt += len;
645 first = 0;
646 continue;
paul718e3742002-12-13 20:15:29 +0000647 }
648
649 switch (format)
650 {
651 case ECOMMUNITY_FORMAT_COMMUNITY_LIST:
652 prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "rt " : "soo ");
653 break;
654 case ECOMMUNITY_FORMAT_DISPLAY:
655 prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "RT:" : "SoO:");
656 break;
657 case ECOMMUNITY_FORMAT_ROUTE_MAP:
658 prefix = "";
659 break;
660 default:
hasso4372df72004-05-20 10:20:02 +0000661 prefix = "";
paul718e3742002-12-13 20:15:29 +0000662 break;
663 }
664
665 /* Make it sure size is enough. */
666 while (str_pnt + ECOMMUNITY_STR_DEFAULT_LEN >= str_size)
667 {
668 str_size *= 2;
669 str_buf = XREALLOC (MTYPE_ECOMMUNITY_STR, str_buf, str_size);
670 }
671
paul718e3742002-12-13 20:15:29 +0000672 /* Put string into buffer. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000673 if (encode == ECOMMUNITY_ENCODE_AS4)
674 {
675 eas.as = (*pnt++ << 24);
676 eas.as |= (*pnt++ << 16);
677 eas.as |= (*pnt++ << 8);
678 eas.as |= (*pnt++);
679
680 eas.val = (*pnt++ << 8);
681 eas.val |= (*pnt++);
682
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400683 len = sprintf( str_buf + str_pnt, "%s%u:%d", prefix,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000684 eas.as, eas.val );
685 str_pnt += len;
686 first = 0;
687 }
paul718e3742002-12-13 20:15:29 +0000688 if (encode == ECOMMUNITY_ENCODE_AS)
689 {
690 eas.as = (*pnt++ << 8);
691 eas.as |= (*pnt++);
692
693 eas.val = (*pnt++ << 24);
694 eas.val |= (*pnt++ << 16);
695 eas.val |= (*pnt++ << 8);
696 eas.val |= (*pnt++);
697
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400698 len = sprintf (str_buf + str_pnt, "%s%u:%d", prefix,
paul718e3742002-12-13 20:15:29 +0000699 eas.as, eas.val);
700 str_pnt += len;
701 first = 0;
702 }
703 else if (encode == ECOMMUNITY_ENCODE_IP)
704 {
705 memcpy (&eip.ip, pnt, 4);
706 pnt += 4;
707 eip.val = (*pnt++ << 8);
708 eip.val |= (*pnt++);
709
710 len = sprintf (str_buf + str_pnt, "%s%s:%d", prefix,
711 inet_ntoa (eip.ip), eip.val);
712 str_pnt += len;
713 first = 0;
714 }
715 }
716 return str_buf;
717}
hasso4372df72004-05-20 10:20:02 +0000718
719int
paulfd79ac92004-10-13 05:06:08 +0000720ecommunity_match (const struct ecommunity *ecom1,
721 const struct ecommunity *ecom2)
hasso4372df72004-05-20 10:20:02 +0000722{
723 int i = 0;
724 int j = 0;
725
726 if (ecom1 == NULL && ecom2 == NULL)
727 return 1;
728
729 if (ecom1 == NULL || ecom2 == NULL)
730 return 0;
731
732 if (ecom1->size < ecom2->size)
733 return 0;
734
735 /* Every community on com2 needs to be on com1 for this to match */
736 while (i < ecom1->size && j < ecom2->size)
737 {
738 if (memcmp (ecom1->val + i, ecom2->val + j, ECOMMUNITY_SIZE) == 0)
739 j++;
740 i++;
741 }
742
743 if (j == ecom2->size)
744 return 1;
745 else
746 return 0;
747}
748