blob: c76f01e3d3d90faee868ff5cf173feeed1986bd0 [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"
Donald Sharp04907292016-01-07 10:03:01 -050027#include "filter.h"
paul718e3742002-12-13 20:15:29 +000028
29#include "bgpd/bgpd.h"
30#include "bgpd/bgp_ecommunity.h"
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000031#include "bgpd/bgp_aspath.h"
paul718e3742002-12-13 20:15:29 +000032
33/* Hash of community attribute. */
Stephen Hemmingerffa4e2c2009-05-15 10:28:11 -070034static struct hash *ecomhash;
David Lamparter6b0655a2014-06-04 06:53:35 +020035
paul718e3742002-12-13 20:15:29 +000036/* Allocate a new ecommunities. */
Stephen Hemmingerffa4e2c2009-05-15 10:28:11 -070037static struct ecommunity *
Stephen Hemminger66e5cd82009-02-09 10:14:16 -080038ecommunity_new (void)
paul718e3742002-12-13 20:15:29 +000039{
40 return (struct ecommunity *) XCALLOC (MTYPE_ECOMMUNITY,
41 sizeof (struct ecommunity));
42}
43
44/* Allocate ecommunities. */
45void
Paul Jakmaf6f434b2010-11-23 21:28:03 +000046ecommunity_free (struct ecommunity **ecom)
paul718e3742002-12-13 20:15:29 +000047{
Paul Jakmaf6f434b2010-11-23 21:28:03 +000048 if ((*ecom)->val)
49 XFREE (MTYPE_ECOMMUNITY_VAL, (*ecom)->val);
50 if ((*ecom)->str)
51 XFREE (MTYPE_ECOMMUNITY_STR, (*ecom)->str);
52 XFREE (MTYPE_ECOMMUNITY, *ecom);
53 ecom = NULL;
paul718e3742002-12-13 20:15:29 +000054}
55
56/* Add a new Extended Communities value to Extended Communities
57 Attribute structure. When the value is already exists in the
58 structure, we don't add the value. Newly added value is sorted by
59 numerical order. When the value is added to the structure return 1
60 else return 0. */
61static int
62ecommunity_add_val (struct ecommunity *ecom, struct ecommunity_val *eval)
63{
paul5228ad22004-06-04 17:58:18 +000064 u_int8_t *p;
paul718e3742002-12-13 20:15:29 +000065 int ret;
66 int c;
67
68 /* When this is fist value, just add it. */
69 if (ecom->val == NULL)
70 {
71 ecom->size++;
72 ecom->val = XMALLOC (MTYPE_ECOMMUNITY_VAL, ecom_length (ecom));
73 memcpy (ecom->val, eval->val, ECOMMUNITY_SIZE);
74 return 1;
75 }
76
77 /* If the value already exists in the structure return 0. */
78 c = 0;
79 for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++)
80 {
81 ret = memcmp (p, eval->val, ECOMMUNITY_SIZE);
82 if (ret == 0)
83 return 0;
84 if (ret > 0)
85 break;
86 }
87
88 /* Add the value to the structure with numerical sorting. */
89 ecom->size++;
90 ecom->val = XREALLOC (MTYPE_ECOMMUNITY_VAL, ecom->val, ecom_length (ecom));
91
92 memmove (ecom->val + (c + 1) * ECOMMUNITY_SIZE,
93 ecom->val + c * ECOMMUNITY_SIZE,
94 (ecom->size - 1 - c) * ECOMMUNITY_SIZE);
95 memcpy (ecom->val + c * ECOMMUNITY_SIZE, eval->val, ECOMMUNITY_SIZE);
96
97 return 1;
98}
99
100/* This function takes pointer to Extended Communites strucutre then
101 create a new Extended Communities structure by uniq and sort each
Denis Ovsienkoe6b6a562009-06-01 20:20:36 +0400102 Extended Communities value. */
Josh Bailey0b597ef2011-07-20 20:49:11 -0700103struct ecommunity *
paul718e3742002-12-13 20:15:29 +0000104ecommunity_uniq_sort (struct ecommunity *ecom)
105{
106 int i;
107 struct ecommunity *new;
108 struct ecommunity_val *eval;
109
110 if (! ecom)
111 return NULL;
112
Stephen Hemminger66e5cd82009-02-09 10:14:16 -0800113 new = ecommunity_new ();
paul718e3742002-12-13 20:15:29 +0000114
115 for (i = 0; i < ecom->size; i++)
116 {
117 eval = (struct ecommunity_val *) (ecom->val + (i * ECOMMUNITY_SIZE));
118 ecommunity_add_val (new, eval);
119 }
120 return new;
121}
122
123/* Parse Extended Communites Attribute in BGP packet. */
124struct ecommunity *
paul5228ad22004-06-04 17:58:18 +0000125ecommunity_parse (u_int8_t *pnt, u_short length)
paul718e3742002-12-13 20:15:29 +0000126{
127 struct ecommunity tmp;
128 struct ecommunity *new;
129
130 /* Length check. */
131 if (length % ECOMMUNITY_SIZE)
132 return NULL;
133
134 /* Prepare tmporary structure for making a new Extended Communities
135 Attribute. */
136 tmp.size = length / ECOMMUNITY_SIZE;
137 tmp.val = pnt;
138
139 /* Create a new Extended Communities Attribute by uniq and sort each
140 Extended Communities value */
141 new = ecommunity_uniq_sort (&tmp);
142
143 return ecommunity_intern (new);
144}
145
146/* Duplicate the Extended Communities Attribute structure. */
147struct ecommunity *
148ecommunity_dup (struct ecommunity *ecom)
149{
150 struct ecommunity *new;
151
152 new = XCALLOC (MTYPE_ECOMMUNITY, sizeof (struct ecommunity));
153 new->size = ecom->size;
154 if (new->size)
155 {
156 new->val = XMALLOC (MTYPE_ECOMMUNITY_VAL, ecom->size * ECOMMUNITY_SIZE);
157 memcpy (new->val, ecom->val, ecom->size * ECOMMUNITY_SIZE);
158 }
159 else
160 new->val = NULL;
161 return new;
162}
163
hasso4372df72004-05-20 10:20:02 +0000164/* Retrun string representation of communities attribute. */
165char *
166ecommunity_str (struct ecommunity *ecom)
167{
168 if (! ecom->str)
169 ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY);
170 return ecom->str;
171}
172
paul718e3742002-12-13 20:15:29 +0000173/* Merge two Extended Communities Attribute structure. */
174struct ecommunity *
175ecommunity_merge (struct ecommunity *ecom1, struct ecommunity *ecom2)
176{
177 if (ecom1->val)
178 ecom1->val = XREALLOC (MTYPE_ECOMMUNITY_VAL, ecom1->val,
179 (ecom1->size + ecom2->size) * ECOMMUNITY_SIZE);
180 else
181 ecom1->val = XMALLOC (MTYPE_ECOMMUNITY_VAL,
182 (ecom1->size + ecom2->size) * ECOMMUNITY_SIZE);
183
184 memcpy (ecom1->val + (ecom1->size * ECOMMUNITY_SIZE),
185 ecom2->val, ecom2->size * ECOMMUNITY_SIZE);
186 ecom1->size += ecom2->size;
187
188 return ecom1;
189}
190
191/* Intern Extended Communities Attribute. */
192struct ecommunity *
193ecommunity_intern (struct ecommunity *ecom)
194{
195 struct ecommunity *find;
196
197 assert (ecom->refcnt == 0);
198
199 find = (struct ecommunity *) hash_get (ecomhash, ecom, hash_alloc_intern);
200
201 if (find != ecom)
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000202 ecommunity_free (&ecom);
paul718e3742002-12-13 20:15:29 +0000203
204 find->refcnt++;
205
206 if (! find->str)
207 find->str = ecommunity_ecom2str (find, ECOMMUNITY_FORMAT_DISPLAY);
208
209 return find;
210}
211
212/* Unintern Extended Communities Attribute. */
213void
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000214ecommunity_unintern (struct ecommunity **ecom)
paul718e3742002-12-13 20:15:29 +0000215{
216 struct ecommunity *ret;
217
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000218 if ((*ecom)->refcnt)
219 (*ecom)->refcnt--;
220
paul718e3742002-12-13 20:15:29 +0000221 /* Pull off from hash. */
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000222 if ((*ecom)->refcnt == 0)
paul718e3742002-12-13 20:15:29 +0000223 {
224 /* Extended community must be in the hash. */
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000225 ret = (struct ecommunity *) hash_release (ecomhash, *ecom);
paul718e3742002-12-13 20:15:29 +0000226 assert (ret != NULL);
227
228 ecommunity_free (ecom);
229 }
230}
231
232/* Utinity function to make hash key. */
233unsigned int
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000234ecommunity_hash_make (void *arg)
paul718e3742002-12-13 20:15:29 +0000235{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000236 const struct ecommunity *ecom = arg;
Jorge Boncompte [DTI2]c76275e2012-05-07 16:52:55 +0000237 int size = ecom->size * ECOMMUNITY_SIZE;
238 u_int8_t *pnt = ecom->val;
239 unsigned int key = 0;
paul718e3742002-12-13 20:15:29 +0000240 int c;
paul718e3742002-12-13 20:15:29 +0000241
Jorge Boncompte [DTI2]c76275e2012-05-07 16:52:55 +0000242 for (c = 0; c < size; c += ECOMMUNITY_SIZE)
243 {
244 key += pnt[c];
245 key += pnt[c + 1];
246 key += pnt[c + 2];
247 key += pnt[c + 3];
248 key += pnt[c + 4];
249 key += pnt[c + 5];
250 key += pnt[c + 6];
251 key += pnt[c + 7];
252 }
paul718e3742002-12-13 20:15:29 +0000253
254 return key;
255}
256
257/* Compare two Extended Communities Attribute structure. */
258int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100259ecommunity_cmp (const void *arg1, const void *arg2)
paul718e3742002-12-13 20:15:29 +0000260{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000261 const struct ecommunity *ecom1 = arg1;
262 const struct ecommunity *ecom2 = arg2;
263
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100264 return (ecom1->size == ecom2->size
265 && memcmp (ecom1->val, ecom2->val, ecom1->size * ECOMMUNITY_SIZE) == 0);
paul718e3742002-12-13 20:15:29 +0000266}
267
268/* Initialize Extended Comminities related hash. */
269void
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000270ecommunity_init (void)
paul718e3742002-12-13 20:15:29 +0000271{
272 ecomhash = hash_create (ecommunity_hash_make, ecommunity_cmp);
273}
Chris Caputo228da422009-07-18 05:44:03 +0000274
275void
276ecommunity_finish (void)
277{
278 hash_free (ecomhash);
279 ecomhash = NULL;
280}
David Lamparter6b0655a2014-06-04 06:53:35 +0200281
paul718e3742002-12-13 20:15:29 +0000282/* Extended Communities token enum. */
283enum ecommunity_token
284{
David Lamparterb1672ce2015-04-19 15:17:02 +0200285 ecommunity_token_unknown = 0,
paul718e3742002-12-13 20:15:29 +0000286 ecommunity_token_rt,
287 ecommunity_token_soo,
288 ecommunity_token_val,
paul718e3742002-12-13 20:15:29 +0000289};
290
291/* Get next Extended Communities token from the string. */
paul94f2b392005-06-28 12:44:16 +0000292static const char *
paulfd79ac92004-10-13 05:06:08 +0000293ecommunity_gettoken (const char *str, struct ecommunity_val *eval,
paul718e3742002-12-13 20:15:29 +0000294 enum ecommunity_token *token)
295{
296 int ret;
297 int dot = 0;
298 int digit = 0;
299 int separator = 0;
paulfd79ac92004-10-13 05:06:08 +0000300 const char *p = str;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000301 char *endptr;
paul718e3742002-12-13 20:15:29 +0000302 struct in_addr ip;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000303 as_t as = 0;
304 u_int32_t val = 0;
305 char buf[INET_ADDRSTRLEN + 1];
paul718e3742002-12-13 20:15:29 +0000306
307 /* Skip white space. */
308 while (isspace ((int) *p))
309 {
310 p++;
311 str++;
312 }
313
314 /* Check the end of the line. */
315 if (*p == '\0')
316 return NULL;
317
318 /* "rt" and "soo" keyword parse. */
319 if (! isdigit ((int) *p))
320 {
321 /* "rt" match check. */
322 if (tolower ((int) *p) == 'r')
323 {
324 p++;
325 if (tolower ((int) *p) == 't')
326 {
327 p++;
328 *token = ecommunity_token_rt;
329 return p;
330 }
331 if (isspace ((int) *p) || *p == '\0')
332 {
333 *token = ecommunity_token_rt;
334 return p;
335 }
336 goto error;
337 }
338 /* "soo" match check. */
339 else if (tolower ((int) *p) == 's')
340 {
341 p++;
342 if (tolower ((int) *p) == 'o')
343 {
344 p++;
345 if (tolower ((int) *p) == 'o')
346 {
347 p++;
348 *token = ecommunity_token_soo;
349 return p;
350 }
351 if (isspace ((int) *p) || *p == '\0')
352 {
353 *token = ecommunity_token_soo;
354 return p;
355 }
356 goto error;
357 }
358 if (isspace ((int) *p) || *p == '\0')
359 {
360 *token = ecommunity_token_soo;
361 return p;
362 }
363 goto error;
364 }
365 goto error;
366 }
367
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000368 /* What a mess, there are several possibilities:
369 *
370 * a) A.B.C.D:MN
371 * b) EF:OPQR
372 * c) GHJK:MN
373 *
374 * A.B.C.D: Four Byte IP
375 * EF: Two byte ASN
376 * GHJK: Four-byte ASN
377 * MN: Two byte value
378 * OPQR: Four byte value
379 *
380 */
paul718e3742002-12-13 20:15:29 +0000381 while (isdigit ((int) *p) || *p == ':' || *p == '.')
382 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000383 if (*p == ':')
paul718e3742002-12-13 20:15:29 +0000384 {
385 if (separator)
386 goto error;
387
388 separator = 1;
389 digit = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000390
391 if ((p - str) > INET_ADDRSTRLEN)
392 goto error;
393 memset (buf, 0, INET_ADDRSTRLEN + 1);
394 memcpy (buf, str, p - str);
395
paul718e3742002-12-13 20:15:29 +0000396 if (dot)
397 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000398 /* Parsing A.B.C.D in:
399 * A.B.C.D:MN
400 */
401 ret = inet_aton (buf, &ip);
paul718e3742002-12-13 20:15:29 +0000402 if (ret == 0)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000403 goto error;
paul718e3742002-12-13 20:15:29 +0000404 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000405 else
406 {
407 /* ASN */
408 as = strtoul (buf, &endptr, 10);
409 if (*endptr != '\0' || as == BGP_AS4_MAX)
410 goto error;
411 }
paul718e3742002-12-13 20:15:29 +0000412 }
413 else if (*p == '.')
414 {
415 if (separator)
416 goto error;
417 dot++;
418 if (dot > 4)
419 goto error;
420 }
421 else
422 {
423 digit = 1;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000424
425 /* We're past the IP/ASN part */
426 if (separator)
427 {
428 val *= 10;
429 val += (*p - '0');
430 }
paul718e3742002-12-13 20:15:29 +0000431 }
432 p++;
433 }
434
435 /* Low digit part must be there. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000436 if (!digit || !separator)
paul718e3742002-12-13 20:15:29 +0000437 goto error;
438
439 /* Encode result into routing distinguisher. */
440 if (dot)
441 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000442 if (val > UINT16_MAX)
443 goto error;
444
paul718e3742002-12-13 20:15:29 +0000445 eval->val[0] = ECOMMUNITY_ENCODE_IP;
446 eval->val[1] = 0;
447 memcpy (&eval->val[2], &ip, sizeof (struct in_addr));
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000448 eval->val[6] = (val >> 8) & 0xff;
449 eval->val[7] = val & 0xff;
450 }
451 else if (as > BGP_AS_MAX)
452 {
453 if (val > UINT16_MAX)
454 goto error;
455
456 eval->val[0] = ECOMMUNITY_ENCODE_AS4;
457 eval->val[1] = 0;
458 eval->val[2] = (as >>24) & 0xff;
459 eval->val[3] = (as >>16) & 0xff;
460 eval->val[4] = (as >>8) & 0xff;
461 eval->val[5] = as & 0xff;
462 eval->val[6] = (val >> 8) & 0xff;
463 eval->val[7] = val & 0xff;
paul718e3742002-12-13 20:15:29 +0000464 }
465 else
466 {
467 eval->val[0] = ECOMMUNITY_ENCODE_AS;
468 eval->val[1] = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000469
470 eval->val[2] = (as >>8) & 0xff;
471 eval->val[3] = as & 0xff;
472 eval->val[4] = (val >>24) & 0xff;
473 eval->val[5] = (val >>16) & 0xff;
474 eval->val[6] = (val >>8) & 0xff;
475 eval->val[7] = val & 0xff;
paul718e3742002-12-13 20:15:29 +0000476 }
477 *token = ecommunity_token_val;
478 return p;
479
480 error:
481 *token = ecommunity_token_unknown;
482 return p;
483}
484
485/* Convert string to extended community attribute.
486
487 When type is already known, please specify both str and type. str
488 should not include keyword such as "rt" and "soo". Type is
489 ECOMMUNITY_ROUTE_TARGET or ECOMMUNITY_SITE_ORIGIN.
490 keyword_included should be zero.
491
492 For example route-map's "set extcommunity" command case:
493
494 "rt 100:1 100:2 100:3" -> str = "100:1 100:2 100:3"
495 type = ECOMMUNITY_ROUTE_TARGET
496 keyword_included = 0
497
498 "soo 100:1" -> str = "100:1"
499 type = ECOMMUNITY_SITE_ORIGIN
500 keyword_included = 0
501
502 When string includes keyword for each extended community value.
503 Please specify keyword_included as non-zero value.
504
505 For example standard extcommunity-list case:
506
507 "rt 100:1 rt 100:2 soo 100:1" -> str = "rt 100:1 rt 100:2 soo 100:1"
508 type = 0
509 keyword_include = 1
510*/
511struct ecommunity *
paulfd79ac92004-10-13 05:06:08 +0000512ecommunity_str2com (const char *str, int type, int keyword_included)
paul718e3742002-12-13 20:15:29 +0000513{
514 struct ecommunity *ecom = NULL;
David Lamparterb1672ce2015-04-19 15:17:02 +0200515 enum ecommunity_token token = ecommunity_token_unknown;
paul718e3742002-12-13 20:15:29 +0000516 struct ecommunity_val eval;
517 int keyword = 0;
518
519 while ((str = ecommunity_gettoken (str, &eval, &token)))
520 {
521 switch (token)
522 {
523 case ecommunity_token_rt:
524 case ecommunity_token_soo:
525 if (! keyword_included || keyword)
526 {
527 if (ecom)
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000528 ecommunity_free (&ecom);
paul718e3742002-12-13 20:15:29 +0000529 return NULL;
530 }
531 keyword = 1;
532
533 if (token == ecommunity_token_rt)
534 {
535 type = ECOMMUNITY_ROUTE_TARGET;
536 }
537 if (token == ecommunity_token_soo)
538 {
539 type = ECOMMUNITY_SITE_ORIGIN;
540 }
541 break;
542 case ecommunity_token_val:
543 if (keyword_included)
544 {
545 if (! keyword)
546 {
547 if (ecom)
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000548 ecommunity_free (&ecom);
paul718e3742002-12-13 20:15:29 +0000549 return NULL;
550 }
551 keyword = 0;
552 }
553 if (ecom == NULL)
554 ecom = ecommunity_new ();
555 eval.val[1] = type;
556 ecommunity_add_val (ecom, &eval);
557 break;
558 case ecommunity_token_unknown:
559 default:
560 if (ecom)
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000561 ecommunity_free (&ecom);
paul718e3742002-12-13 20:15:29 +0000562 return NULL;
paul718e3742002-12-13 20:15:29 +0000563 }
564 }
565 return ecom;
566}
567
568/* Convert extended community attribute to string.
569
570 Due to historical reason of industry standard implementation, there
571 are three types of format.
572
573 route-map set extcommunity format
574 "rt 100:1 100:2"
575 "soo 100:3"
576
577 extcommunity-list
578 "rt 100:1 rt 100:2 soo 100:3"
579
580 "show ip bgp" and extcommunity-list regular expression matching
581 "RT:100:1 RT:100:2 SoO:100:3"
582
583 For each formath please use below definition for format:
584
585 ECOMMUNITY_FORMAT_ROUTE_MAP
586 ECOMMUNITY_FORMAT_COMMUNITY_LIST
587 ECOMMUNITY_FORMAT_DISPLAY
588*/
589char *
590ecommunity_ecom2str (struct ecommunity *ecom, int format)
591{
592 int i;
paul5228ad22004-06-04 17:58:18 +0000593 u_int8_t *pnt;
paul718e3742002-12-13 20:15:29 +0000594 int encode = 0;
595 int type = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000596#define ECOMMUNITY_STR_DEFAULT_LEN 27
paul718e3742002-12-13 20:15:29 +0000597 int str_size;
598 int str_pnt;
paul5228ad22004-06-04 17:58:18 +0000599 char *str_buf;
paulfd79ac92004-10-13 05:06:08 +0000600 const char *prefix;
paul718e3742002-12-13 20:15:29 +0000601 int len = 0;
602 int first = 1;
603
604 /* For parse Extended Community attribute tupple. */
605 struct ecommunity_as
606 {
607 as_t as;
608 u_int32_t val;
609 } eas;
610
611 struct ecommunity_ip
612 {
613 struct in_addr ip;
614 u_int16_t val;
615 } eip;
616
617 if (ecom->size == 0)
618 {
619 str_buf = XMALLOC (MTYPE_ECOMMUNITY_STR, 1);
620 str_buf[0] = '\0';
621 return str_buf;
622 }
623
624 /* Prepare buffer. */
625 str_buf = XMALLOC (MTYPE_ECOMMUNITY_STR, ECOMMUNITY_STR_DEFAULT_LEN + 1);
626 str_size = ECOMMUNITY_STR_DEFAULT_LEN + 1;
627 str_pnt = 0;
628
629 for (i = 0; i < ecom->size; i++)
630 {
CROSS94431db2011-09-26 13:17:05 +0400631 /* Make it sure size is enough. */
632 while (str_pnt + ECOMMUNITY_STR_DEFAULT_LEN >= str_size)
633 {
634 str_size *= 2;
635 str_buf = XREALLOC (MTYPE_ECOMMUNITY_STR, str_buf, str_size);
636 }
637
hasso4372df72004-05-20 10:20:02 +0000638 /* Space between each value. */
639 if (! first)
640 str_buf[str_pnt++] = ' ';
641
paul718e3742002-12-13 20:15:29 +0000642 pnt = ecom->val + (i * 8);
643
644 /* High-order octet of type. */
645 encode = *pnt++;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000646 if (encode != ECOMMUNITY_ENCODE_AS && encode != ECOMMUNITY_ENCODE_IP
647 && encode != ECOMMUNITY_ENCODE_AS4)
paul718e3742002-12-13 20:15:29 +0000648 {
hasso4372df72004-05-20 10:20:02 +0000649 len = sprintf (str_buf + str_pnt, "?");
650 str_pnt += len;
651 first = 0;
652 continue;
paul718e3742002-12-13 20:15:29 +0000653 }
654
655 /* Low-order octet of type. */
656 type = *pnt++;
657 if (type != ECOMMUNITY_ROUTE_TARGET && type != ECOMMUNITY_SITE_ORIGIN)
658 {
hasso4372df72004-05-20 10:20:02 +0000659 len = sprintf (str_buf + str_pnt, "?");
660 str_pnt += len;
661 first = 0;
662 continue;
paul718e3742002-12-13 20:15:29 +0000663 }
664
665 switch (format)
666 {
667 case ECOMMUNITY_FORMAT_COMMUNITY_LIST:
668 prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "rt " : "soo ");
669 break;
670 case ECOMMUNITY_FORMAT_DISPLAY:
671 prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "RT:" : "SoO:");
672 break;
673 case ECOMMUNITY_FORMAT_ROUTE_MAP:
674 prefix = "";
675 break;
676 default:
hasso4372df72004-05-20 10:20:02 +0000677 prefix = "";
paul718e3742002-12-13 20:15:29 +0000678 break;
679 }
680
paul718e3742002-12-13 20:15:29 +0000681 /* Put string into buffer. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000682 if (encode == ECOMMUNITY_ENCODE_AS4)
683 {
684 eas.as = (*pnt++ << 24);
685 eas.as |= (*pnt++ << 16);
686 eas.as |= (*pnt++ << 8);
687 eas.as |= (*pnt++);
688
689 eas.val = (*pnt++ << 8);
690 eas.val |= (*pnt++);
691
Milan Kociancb4fc592014-12-01 12:48:25 +0000692 len = sprintf( str_buf + str_pnt, "%s%u:%u", prefix,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000693 eas.as, eas.val );
694 str_pnt += len;
695 first = 0;
696 }
paul718e3742002-12-13 20:15:29 +0000697 if (encode == ECOMMUNITY_ENCODE_AS)
698 {
699 eas.as = (*pnt++ << 8);
700 eas.as |= (*pnt++);
701
702 eas.val = (*pnt++ << 24);
703 eas.val |= (*pnt++ << 16);
704 eas.val |= (*pnt++ << 8);
705 eas.val |= (*pnt++);
706
Milan Kociancb4fc592014-12-01 12:48:25 +0000707 len = sprintf (str_buf + str_pnt, "%s%u:%u", prefix,
paul718e3742002-12-13 20:15:29 +0000708 eas.as, eas.val);
709 str_pnt += len;
710 first = 0;
711 }
712 else if (encode == ECOMMUNITY_ENCODE_IP)
713 {
714 memcpy (&eip.ip, pnt, 4);
715 pnt += 4;
716 eip.val = (*pnt++ << 8);
717 eip.val |= (*pnt++);
718
Milan Kociancb4fc592014-12-01 12:48:25 +0000719 len = sprintf (str_buf + str_pnt, "%s%s:%u", prefix,
paul718e3742002-12-13 20:15:29 +0000720 inet_ntoa (eip.ip), eip.val);
721 str_pnt += len;
722 first = 0;
723 }
724 }
725 return str_buf;
726}
hasso4372df72004-05-20 10:20:02 +0000727
728int
paulfd79ac92004-10-13 05:06:08 +0000729ecommunity_match (const struct ecommunity *ecom1,
730 const struct ecommunity *ecom2)
hasso4372df72004-05-20 10:20:02 +0000731{
732 int i = 0;
733 int j = 0;
734
735 if (ecom1 == NULL && ecom2 == NULL)
736 return 1;
737
738 if (ecom1 == NULL || ecom2 == NULL)
739 return 0;
740
741 if (ecom1->size < ecom2->size)
742 return 0;
743
744 /* Every community on com2 needs to be on com1 for this to match */
745 while (i < ecom1->size && j < ecom2->size)
746 {
747 if (memcmp (ecom1->val + i, ecom2->val + j, ECOMMUNITY_SIZE) == 0)
748 j++;
749 i++;
750 }
751
752 if (j == ecom2->size)
753 return 1;
754 else
755 return 0;
756}
757