blob: 5722425e1d5b8efe206c66bb0ddc6bf7e7e6872d [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
Paul Jakmaf6f434b2010-11-23 21:28:03 +000045ecommunity_free (struct ecommunity **ecom)
paul718e3742002-12-13 20:15:29 +000046{
Paul Jakmaf6f434b2010-11-23 21:28:03 +000047 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 ecom = NULL;
paul718e3742002-12-13 20:15:29 +000053}
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. */
60static int
61ecommunity_add_val (struct ecommunity *ecom, struct ecommunity_val *eval)
62{
paul5228ad22004-06-04 17:58:18 +000063 u_int8_t *p;
paul718e3742002-12-13 20:15:29 +000064 int ret;
65 int c;
66
67 /* When this is fist value, just add it. */
68 if (ecom->val == NULL)
69 {
70 ecom->size++;
71 ecom->val = XMALLOC (MTYPE_ECOMMUNITY_VAL, ecom_length (ecom));
72 memcpy (ecom->val, eval->val, ECOMMUNITY_SIZE);
73 return 1;
74 }
75
76 /* If the value already exists in the structure return 0. */
77 c = 0;
78 for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++)
79 {
80 ret = memcmp (p, eval->val, ECOMMUNITY_SIZE);
81 if (ret == 0)
82 return 0;
83 if (ret > 0)
84 break;
85 }
86
87 /* Add the value to the structure with numerical sorting. */
88 ecom->size++;
89 ecom->val = XREALLOC (MTYPE_ECOMMUNITY_VAL, ecom->val, ecom_length (ecom));
90
91 memmove (ecom->val + (c + 1) * ECOMMUNITY_SIZE,
92 ecom->val + c * ECOMMUNITY_SIZE,
93 (ecom->size - 1 - c) * ECOMMUNITY_SIZE);
94 memcpy (ecom->val + c * ECOMMUNITY_SIZE, eval->val, ECOMMUNITY_SIZE);
95
96 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
Denis Ovsienkoe6b6a562009-06-01 20:20:36 +0400101 Extended Communities value. */
Josh Bailey0b597ef2011-07-20 20:49:11 -0700102struct ecommunity *
paul718e3742002-12-13 20:15:29 +0000103ecommunity_uniq_sort (struct ecommunity *ecom)
104{
105 int i;
106 struct ecommunity *new;
107 struct ecommunity_val *eval;
108
109 if (! ecom)
110 return NULL;
111
Stephen Hemminger66e5cd82009-02-09 10:14:16 -0800112 new = ecommunity_new ();
paul718e3742002-12-13 20:15:29 +0000113
114 for (i = 0; i < ecom->size; i++)
115 {
116 eval = (struct ecommunity_val *) (ecom->val + (i * ECOMMUNITY_SIZE));
117 ecommunity_add_val (new, eval);
118 }
119 return new;
120}
121
122/* Parse Extended Communites Attribute in BGP packet. */
123struct ecommunity *
paul5228ad22004-06-04 17:58:18 +0000124ecommunity_parse (u_int8_t *pnt, u_short length)
paul718e3742002-12-13 20:15:29 +0000125{
126 struct ecommunity tmp;
127 struct ecommunity *new;
128
129 /* Length check. */
130 if (length % ECOMMUNITY_SIZE)
131 return NULL;
132
133 /* Prepare tmporary structure for making a new Extended Communities
134 Attribute. */
135 tmp.size = length / ECOMMUNITY_SIZE;
136 tmp.val = pnt;
137
138 /* Create a new Extended Communities Attribute by uniq and sort each
139 Extended Communities value */
140 new = ecommunity_uniq_sort (&tmp);
141
142 return ecommunity_intern (new);
143}
144
145/* Duplicate the Extended Communities Attribute structure. */
146struct ecommunity *
147ecommunity_dup (struct ecommunity *ecom)
148{
149 struct ecommunity *new;
150
151 new = XCALLOC (MTYPE_ECOMMUNITY, sizeof (struct ecommunity));
152 new->size = ecom->size;
153 if (new->size)
154 {
155 new->val = XMALLOC (MTYPE_ECOMMUNITY_VAL, ecom->size * ECOMMUNITY_SIZE);
156 memcpy (new->val, ecom->val, ecom->size * ECOMMUNITY_SIZE);
157 }
158 else
159 new->val = NULL;
160 return new;
161}
162
hasso4372df72004-05-20 10:20:02 +0000163/* Retrun string representation of communities attribute. */
164char *
165ecommunity_str (struct ecommunity *ecom)
166{
167 if (! ecom->str)
168 ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY);
169 return ecom->str;
170}
171
paul718e3742002-12-13 20:15:29 +0000172/* Merge two Extended Communities Attribute structure. */
173struct ecommunity *
174ecommunity_merge (struct ecommunity *ecom1, struct ecommunity *ecom2)
175{
176 if (ecom1->val)
177 ecom1->val = XREALLOC (MTYPE_ECOMMUNITY_VAL, ecom1->val,
178 (ecom1->size + ecom2->size) * ECOMMUNITY_SIZE);
179 else
180 ecom1->val = XMALLOC (MTYPE_ECOMMUNITY_VAL,
181 (ecom1->size + ecom2->size) * ECOMMUNITY_SIZE);
182
183 memcpy (ecom1->val + (ecom1->size * ECOMMUNITY_SIZE),
184 ecom2->val, ecom2->size * ECOMMUNITY_SIZE);
185 ecom1->size += ecom2->size;
186
187 return ecom1;
188}
189
190/* Intern Extended Communities Attribute. */
191struct ecommunity *
192ecommunity_intern (struct ecommunity *ecom)
193{
194 struct ecommunity *find;
195
196 assert (ecom->refcnt == 0);
197
198 find = (struct ecommunity *) hash_get (ecomhash, ecom, hash_alloc_intern);
199
200 if (find != ecom)
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000201 ecommunity_free (&ecom);
paul718e3742002-12-13 20:15:29 +0000202
203 find->refcnt++;
204
205 if (! find->str)
206 find->str = ecommunity_ecom2str (find, ECOMMUNITY_FORMAT_DISPLAY);
207
208 return find;
209}
210
211/* Unintern Extended Communities Attribute. */
212void
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000213ecommunity_unintern (struct ecommunity **ecom)
paul718e3742002-12-13 20:15:29 +0000214{
215 struct ecommunity *ret;
216
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000217 if ((*ecom)->refcnt)
218 (*ecom)->refcnt--;
219
paul718e3742002-12-13 20:15:29 +0000220 /* Pull off from hash. */
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000221 if ((*ecom)->refcnt == 0)
paul718e3742002-12-13 20:15:29 +0000222 {
223 /* Extended community must be in the hash. */
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000224 ret = (struct ecommunity *) hash_release (ecomhash, *ecom);
paul718e3742002-12-13 20:15:29 +0000225 assert (ret != NULL);
226
227 ecommunity_free (ecom);
228 }
229}
230
231/* Utinity function to make hash key. */
232unsigned int
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000233ecommunity_hash_make (void *arg)
paul718e3742002-12-13 20:15:29 +0000234{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000235 const struct ecommunity *ecom = arg;
Jorge Boncompte [DTI2]c76275e2012-05-07 16:52:55 +0000236 int size = ecom->size * ECOMMUNITY_SIZE;
237 u_int8_t *pnt = ecom->val;
238 unsigned int key = 0;
paul718e3742002-12-13 20:15:29 +0000239 int c;
paul718e3742002-12-13 20:15:29 +0000240
Jorge Boncompte [DTI2]c76275e2012-05-07 16:52:55 +0000241 for (c = 0; c < size; c += ECOMMUNITY_SIZE)
242 {
243 key += pnt[c];
244 key += pnt[c + 1];
245 key += pnt[c + 2];
246 key += pnt[c + 3];
247 key += pnt[c + 4];
248 key += pnt[c + 5];
249 key += pnt[c + 6];
250 key += pnt[c + 7];
251 }
paul718e3742002-12-13 20:15:29 +0000252
253 return key;
254}
255
256/* Compare two Extended Communities Attribute structure. */
257int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100258ecommunity_cmp (const void *arg1, const void *arg2)
paul718e3742002-12-13 20:15:29 +0000259{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000260 const struct ecommunity *ecom1 = arg1;
261 const struct ecommunity *ecom2 = arg2;
262
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100263 return (ecom1->size == ecom2->size
264 && memcmp (ecom1->val, ecom2->val, ecom1->size * ECOMMUNITY_SIZE) == 0);
paul718e3742002-12-13 20:15:29 +0000265}
266
267/* Initialize Extended Comminities related hash. */
268void
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000269ecommunity_init (void)
paul718e3742002-12-13 20:15:29 +0000270{
271 ecomhash = hash_create (ecommunity_hash_make, ecommunity_cmp);
272}
Chris Caputo228da422009-07-18 05:44:03 +0000273
274void
275ecommunity_finish (void)
276{
277 hash_free (ecomhash);
278 ecomhash = NULL;
279}
paul718e3742002-12-13 20:15:29 +0000280
281/* Extended Communities token enum. */
282enum 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. */
paul94f2b392005-06-28 12:44:16 +0000291static const char *
paulfd79ac92004-10-13 05:06:08 +0000292ecommunity_gettoken (const char *str, struct ecommunity_val *eval,
paul718e3742002-12-13 20:15:29 +0000293 enum ecommunity_token *token)
294{
295 int ret;
296 int dot = 0;
297 int digit = 0;
298 int separator = 0;
paulfd79ac92004-10-13 05:06:08 +0000299 const char *p = str;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000300 char *endptr;
paul718e3742002-12-13 20:15:29 +0000301 struct in_addr ip;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000302 as_t as = 0;
303 u_int32_t val = 0;
304 char buf[INET_ADDRSTRLEN + 1];
paul718e3742002-12-13 20:15:29 +0000305
306 /* Skip white space. */
307 while (isspace ((int) *p))
308 {
309 p++;
310 str++;
311 }
312
313 /* Check the end of the line. */
314 if (*p == '\0')
315 return NULL;
316
317 /* "rt" and "soo" keyword parse. */
318 if (! isdigit ((int) *p))
319 {
320 /* "rt" match check. */
321 if (tolower ((int) *p) == 'r')
322 {
323 p++;
324 if (tolower ((int) *p) == 't')
325 {
326 p++;
327 *token = ecommunity_token_rt;
328 return p;
329 }
330 if (isspace ((int) *p) || *p == '\0')
331 {
332 *token = ecommunity_token_rt;
333 return p;
334 }
335 goto error;
336 }
337 /* "soo" match check. */
338 else if (tolower ((int) *p) == 's')
339 {
340 p++;
341 if (tolower ((int) *p) == 'o')
342 {
343 p++;
344 if (tolower ((int) *p) == 'o')
345 {
346 p++;
347 *token = ecommunity_token_soo;
348 return p;
349 }
350 if (isspace ((int) *p) || *p == '\0')
351 {
352 *token = ecommunity_token_soo;
353 return p;
354 }
355 goto error;
356 }
357 if (isspace ((int) *p) || *p == '\0')
358 {
359 *token = ecommunity_token_soo;
360 return p;
361 }
362 goto error;
363 }
364 goto error;
365 }
366
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000367 /* 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 */
paul718e3742002-12-13 20:15:29 +0000380 while (isdigit ((int) *p) || *p == ':' || *p == '.')
381 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000382 if (*p == ':')
paul718e3742002-12-13 20:15:29 +0000383 {
384 if (separator)
385 goto error;
386
387 separator = 1;
388 digit = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000389
390 if ((p - str) > INET_ADDRSTRLEN)
391 goto error;
392 memset (buf, 0, INET_ADDRSTRLEN + 1);
393 memcpy (buf, str, p - str);
394
paul718e3742002-12-13 20:15:29 +0000395 if (dot)
396 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000397 /* Parsing A.B.C.D in:
398 * A.B.C.D:MN
399 */
400 ret = inet_aton (buf, &ip);
paul718e3742002-12-13 20:15:29 +0000401 if (ret == 0)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000402 goto error;
paul718e3742002-12-13 20:15:29 +0000403 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000404 else
405 {
406 /* ASN */
407 as = strtoul (buf, &endptr, 10);
408 if (*endptr != '\0' || as == BGP_AS4_MAX)
409 goto error;
410 }
paul718e3742002-12-13 20:15:29 +0000411 }
412 else if (*p == '.')
413 {
414 if (separator)
415 goto error;
416 dot++;
417 if (dot > 4)
418 goto error;
419 }
420 else
421 {
422 digit = 1;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000423
424 /* We're past the IP/ASN part */
425 if (separator)
426 {
427 val *= 10;
428 val += (*p - '0');
429 }
paul718e3742002-12-13 20:15:29 +0000430 }
431 p++;
432 }
433
434 /* Low digit part must be there. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000435 if (!digit || !separator)
paul718e3742002-12-13 20:15:29 +0000436 goto error;
437
438 /* Encode result into routing distinguisher. */
439 if (dot)
440 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000441 if (val > UINT16_MAX)
442 goto error;
443
paul718e3742002-12-13 20:15:29 +0000444 eval->val[0] = ECOMMUNITY_ENCODE_IP;
445 eval->val[1] = 0;
446 memcpy (&eval->val[2], &ip, sizeof (struct in_addr));
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000447 eval->val[6] = (val >> 8) & 0xff;
448 eval->val[7] = val & 0xff;
449 }
450 else if (as > BGP_AS_MAX)
451 {
452 if (val > UINT16_MAX)
453 goto error;
454
455 eval->val[0] = ECOMMUNITY_ENCODE_AS4;
456 eval->val[1] = 0;
457 eval->val[2] = (as >>24) & 0xff;
458 eval->val[3] = (as >>16) & 0xff;
459 eval->val[4] = (as >>8) & 0xff;
460 eval->val[5] = as & 0xff;
461 eval->val[6] = (val >> 8) & 0xff;
462 eval->val[7] = val & 0xff;
paul718e3742002-12-13 20:15:29 +0000463 }
464 else
465 {
466 eval->val[0] = ECOMMUNITY_ENCODE_AS;
467 eval->val[1] = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000468
469 eval->val[2] = (as >>8) & 0xff;
470 eval->val[3] = as & 0xff;
471 eval->val[4] = (val >>24) & 0xff;
472 eval->val[5] = (val >>16) & 0xff;
473 eval->val[6] = (val >>8) & 0xff;
474 eval->val[7] = val & 0xff;
paul718e3742002-12-13 20:15:29 +0000475 }
476 *token = ecommunity_token_val;
477 return p;
478
479 error:
480 *token = ecommunity_token_unknown;
481 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*/
510struct ecommunity *
paulfd79ac92004-10-13 05:06:08 +0000511ecommunity_str2com (const char *str, int type, int keyword_included)
paul718e3742002-12-13 20:15:29 +0000512{
513 struct ecommunity *ecom = NULL;
514 enum ecommunity_token token;
515 struct ecommunity_val eval;
516 int keyword = 0;
517
518 while ((str = ecommunity_gettoken (str, &eval, &token)))
519 {
520 switch (token)
521 {
522 case ecommunity_token_rt:
523 case ecommunity_token_soo:
524 if (! keyword_included || keyword)
525 {
526 if (ecom)
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000527 ecommunity_free (&ecom);
paul718e3742002-12-13 20:15:29 +0000528 return NULL;
529 }
530 keyword = 1;
531
532 if (token == ecommunity_token_rt)
533 {
534 type = ECOMMUNITY_ROUTE_TARGET;
535 }
536 if (token == ecommunity_token_soo)
537 {
538 type = ECOMMUNITY_SITE_ORIGIN;
539 }
540 break;
541 case ecommunity_token_val:
542 if (keyword_included)
543 {
544 if (! keyword)
545 {
546 if (ecom)
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000547 ecommunity_free (&ecom);
paul718e3742002-12-13 20:15:29 +0000548 return NULL;
549 }
550 keyword = 0;
551 }
552 if (ecom == NULL)
553 ecom = ecommunity_new ();
554 eval.val[1] = type;
555 ecommunity_add_val (ecom, &eval);
556 break;
557 case ecommunity_token_unknown:
558 default:
559 if (ecom)
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000560 ecommunity_free (&ecom);
paul718e3742002-12-13 20:15:29 +0000561 return NULL;
paul718e3742002-12-13 20:15:29 +0000562 }
563 }
564 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*/
588char *
589ecommunity_ecom2str (struct ecommunity *ecom, int format)
590{
591 int i;
paul5228ad22004-06-04 17:58:18 +0000592 u_int8_t *pnt;
paul718e3742002-12-13 20:15:29 +0000593 int encode = 0;
594 int type = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000595#define ECOMMUNITY_STR_DEFAULT_LEN 27
paul718e3742002-12-13 20:15:29 +0000596 int str_size;
597 int str_pnt;
paul5228ad22004-06-04 17:58:18 +0000598 char *str_buf;
paulfd79ac92004-10-13 05:06:08 +0000599 const char *prefix;
paul718e3742002-12-13 20:15:29 +0000600 int len = 0;
601 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 if (ecom->size == 0)
617 {
618 str_buf = XMALLOC (MTYPE_ECOMMUNITY_STR, 1);
619 str_buf[0] = '\0';
620 return str_buf;
621 }
622
623 /* Prepare buffer. */
624 str_buf = XMALLOC (MTYPE_ECOMMUNITY_STR, ECOMMUNITY_STR_DEFAULT_LEN + 1);
625 str_size = ECOMMUNITY_STR_DEFAULT_LEN + 1;
626 str_pnt = 0;
627
628 for (i = 0; i < ecom->size; i++)
629 {
CROSS94431db2011-09-26 13:17:05 +0400630 /* Make it sure size is enough. */
631 while (str_pnt + ECOMMUNITY_STR_DEFAULT_LEN >= str_size)
632 {
633 str_size *= 2;
634 str_buf = XREALLOC (MTYPE_ECOMMUNITY_STR, str_buf, str_size);
635 }
636
hasso4372df72004-05-20 10:20:02 +0000637 /* Space between each value. */
638 if (! first)
639 str_buf[str_pnt++] = ' ';
640
paul718e3742002-12-13 20:15:29 +0000641 pnt = ecom->val + (i * 8);
642
643 /* High-order octet of type. */
644 encode = *pnt++;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000645 if (encode != ECOMMUNITY_ENCODE_AS && encode != ECOMMUNITY_ENCODE_IP
646 && encode != ECOMMUNITY_ENCODE_AS4)
paul718e3742002-12-13 20:15:29 +0000647 {
hasso4372df72004-05-20 10:20:02 +0000648 len = sprintf (str_buf + str_pnt, "?");
649 str_pnt += len;
650 first = 0;
651 continue;
paul718e3742002-12-13 20:15:29 +0000652 }
653
654 /* Low-order octet of type. */
655 type = *pnt++;
656 if (type != ECOMMUNITY_ROUTE_TARGET && type != ECOMMUNITY_SITE_ORIGIN)
657 {
hasso4372df72004-05-20 10:20:02 +0000658 len = sprintf (str_buf + str_pnt, "?");
659 str_pnt += len;
660 first = 0;
661 continue;
paul718e3742002-12-13 20:15:29 +0000662 }
663
664 switch (format)
665 {
666 case ECOMMUNITY_FORMAT_COMMUNITY_LIST:
667 prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "rt " : "soo ");
668 break;
669 case ECOMMUNITY_FORMAT_DISPLAY:
670 prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "RT:" : "SoO:");
671 break;
672 case ECOMMUNITY_FORMAT_ROUTE_MAP:
673 prefix = "";
674 break;
675 default:
hasso4372df72004-05-20 10:20:02 +0000676 prefix = "";
paul718e3742002-12-13 20:15:29 +0000677 break;
678 }
679
paul718e3742002-12-13 20:15:29 +0000680 /* Put string into buffer. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000681 if (encode == ECOMMUNITY_ENCODE_AS4)
682 {
683 eas.as = (*pnt++ << 24);
684 eas.as |= (*pnt++ << 16);
685 eas.as |= (*pnt++ << 8);
686 eas.as |= (*pnt++);
687
688 eas.val = (*pnt++ << 8);
689 eas.val |= (*pnt++);
690
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400691 len = sprintf( str_buf + str_pnt, "%s%u:%d", prefix,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000692 eas.as, eas.val );
693 str_pnt += len;
694 first = 0;
695 }
paul718e3742002-12-13 20:15:29 +0000696 if (encode == ECOMMUNITY_ENCODE_AS)
697 {
698 eas.as = (*pnt++ << 8);
699 eas.as |= (*pnt++);
700
701 eas.val = (*pnt++ << 24);
702 eas.val |= (*pnt++ << 16);
703 eas.val |= (*pnt++ << 8);
704 eas.val |= (*pnt++);
705
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400706 len = sprintf (str_buf + str_pnt, "%s%u:%d", prefix,
paul718e3742002-12-13 20:15:29 +0000707 eas.as, eas.val);
708 str_pnt += len;
709 first = 0;
710 }
711 else if (encode == ECOMMUNITY_ENCODE_IP)
712 {
713 memcpy (&eip.ip, pnt, 4);
714 pnt += 4;
715 eip.val = (*pnt++ << 8);
716 eip.val |= (*pnt++);
717
718 len = sprintf (str_buf + str_pnt, "%s%s:%d", prefix,
719 inet_ntoa (eip.ip), eip.val);
720 str_pnt += len;
721 first = 0;
722 }
723 }
724 return str_buf;
725}
hasso4372df72004-05-20 10:20:02 +0000726
727int
paulfd79ac92004-10-13 05:06:08 +0000728ecommunity_match (const struct ecommunity *ecom1,
729 const struct ecommunity *ecom2)
hasso4372df72004-05-20 10:20:02 +0000730{
731 int i = 0;
732 int j = 0;
733
734 if (ecom1 == NULL && ecom2 == NULL)
735 return 1;
736
737 if (ecom1 == NULL || ecom2 == NULL)
738 return 0;
739
740 if (ecom1->size < ecom2->size)
741 return 0;
742
743 /* Every community on com2 needs to be on com1 for this to match */
744 while (i < ecom1->size && j < ecom2->size)
745 {
746 if (memcmp (ecom1->val + i, ecom2->val + j, ECOMMUNITY_SIZE) == 0)
747 j++;
748 i++;
749 }
750
751 if (j == ecom2->size)
752 return 1;
753 else
754 return 0;
755}
756