PageRenderTime 62ms CodeModel.GetById 31ms RepoModel.GetById 1ms app.codeStats 0ms

/uClinux-dist/user/quagga/bgpd/bgp_community.c

https://bitbucket.org/__wp__/mb-linux-msli
C | 632 lines | 463 code | 96 blank | 73 comment | 91 complexity | eaecbb18dc52e49ef6af60b09ac463cd MD5 | raw file
Possible License(s): AGPL-3.0, GPL-2.0, LGPL-2.0, MPL-2.0, ISC, BSD-3-Clause, LGPL-2.1, MPL-2.0-no-copyleft-exception, 0BSD, CC-BY-SA-3.0, GPL-3.0, LGPL-3.0, AGPL-1.0, Unlicense
  1. /* Community attribute related functions.
  2. Copyright (C) 1998, 2001 Kunihiro Ishiguro
  3. This file is part of GNU Zebra.
  4. GNU Zebra is free software; you can redistribute it and/or modify it
  5. under the terms of the GNU General Public License as published by the
  6. Free Software Foundation; either version 2, or (at your option) any
  7. later version.
  8. GNU Zebra is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNU Zebra; see the file COPYING. If not, write to the Free
  14. Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  15. 02111-1307, USA. */
  16. #include <zebra.h>
  17. #include "hash.h"
  18. #include "memory.h"
  19. #include "bgpd/bgp_community.h"
  20. /* Hash of community attribute. */
  21. struct hash *comhash;
  22. /* Allocate a new communities value. */
  23. struct community *
  24. community_new ()
  25. {
  26. return (struct community *) XCALLOC (MTYPE_COMMUNITY,
  27. sizeof (struct community));
  28. }
  29. /* Free communities value. */
  30. void
  31. community_free (struct community *com)
  32. {
  33. if (com->val)
  34. XFREE (MTYPE_COMMUNITY_VAL, com->val);
  35. if (com->str)
  36. XFREE (MTYPE_COMMUNITY_STR, com->str);
  37. XFREE (MTYPE_COMMUNITY, com);
  38. }
  39. /* Add one community value to the community. */
  40. void
  41. community_add_val (struct community *com, u_int32_t val)
  42. {
  43. com->size++;
  44. if (com->val)
  45. com->val = XREALLOC (MTYPE_COMMUNITY_VAL, com->val, com_length (com));
  46. else
  47. com->val = XMALLOC (MTYPE_COMMUNITY_VAL, com_length (com));
  48. val = htonl (val);
  49. memcpy (com_lastval (com), &val, sizeof (u_int32_t));
  50. }
  51. /* Delete one community. */
  52. void
  53. community_del_val (struct community *com, u_int32_t *val)
  54. {
  55. int i = 0;
  56. int c = 0;
  57. if (! com->val)
  58. return;
  59. while (i < com->size)
  60. {
  61. if (memcmp (com->val + i, val, sizeof (u_int32_t)) == 0)
  62. {
  63. c = com->size -i -1;
  64. if (c > 0)
  65. memcpy (com->val + i, com->val + (i + 1), c * sizeof (val));
  66. com->size--;
  67. if (com->size > 0)
  68. com->val = XREALLOC (MTYPE_COMMUNITY_VAL, com->val,
  69. com_length (com));
  70. else
  71. {
  72. XFREE (MTYPE_COMMUNITY_VAL, com->val);
  73. com->val = NULL;
  74. }
  75. return;
  76. }
  77. i++;
  78. }
  79. }
  80. /* Delete all communities listed in com2 from com1 */
  81. struct community *
  82. community_delete (struct community *com1, struct community *com2)
  83. {
  84. int i = 0;
  85. while(i < com2->size)
  86. {
  87. community_del_val (com1, com2->val + i);
  88. i++;
  89. }
  90. return com1;
  91. }
  92. /* Callback function from qsort(). */
  93. int
  94. community_compare (const void *a1, const void *a2)
  95. {
  96. u_int32_t v1;
  97. u_int32_t v2;
  98. memcpy (&v1, a1, sizeof (u_int32_t));
  99. memcpy (&v2, a2, sizeof (u_int32_t));
  100. v1 = ntohl (v1);
  101. v2 = ntohl (v2);
  102. if (v1 < v2)
  103. return -1;
  104. if (v1 > v2)
  105. return 1;
  106. return 0;
  107. }
  108. int
  109. community_include (struct community *com, u_int32_t val)
  110. {
  111. int i;
  112. val = htonl (val);
  113. for (i = 0; i < com->size; i++)
  114. if (memcmp (&val, com_nthval (com, i), sizeof (u_int32_t)) == 0)
  115. return 1;
  116. return 0;
  117. }
  118. u_int32_t
  119. community_val_get (struct community *com, int i)
  120. {
  121. u_char *p;
  122. u_int32_t val;
  123. p = (u_char *) com->val;
  124. p += (i * 4);
  125. memcpy (&val, p, sizeof (u_int32_t));
  126. return ntohl (val);
  127. }
  128. /* Sort and uniq given community. */
  129. struct community *
  130. community_uniq_sort (struct community *com)
  131. {
  132. int i;
  133. struct community *new;
  134. u_int32_t val;
  135. if (! com)
  136. return NULL;
  137. new = community_new ();;
  138. for (i = 0; i < com->size; i++)
  139. {
  140. val = community_val_get (com, i);
  141. if (! community_include (new, val))
  142. community_add_val (new, val);
  143. }
  144. qsort (new->val, new->size, sizeof (u_int32_t), community_compare);
  145. return new;
  146. }
  147. /* Convert communities attribute to string.
  148. For Well-known communities value, below keyword is used.
  149. 0x0 "internet"
  150. 0xFFFFFF01 "no-export"
  151. 0xFFFFFF02 "no-advertise"
  152. 0xFFFFFF03 "local-AS"
  153. For other values, "AS:VAL" format is used. */
  154. static char *
  155. community_com2str (struct community *com)
  156. {
  157. int i;
  158. char *str;
  159. char *pnt;
  160. int len;
  161. int first;
  162. u_int32_t comval;
  163. u_int16_t as;
  164. u_int16_t val;
  165. /* When communities attribute is empty. */
  166. if (com->size == 0)
  167. {
  168. str = XMALLOC (MTYPE_COMMUNITY_STR, 1);
  169. str[0] = '\0';
  170. return str;
  171. }
  172. /* Memory allocation is time consuming work. So we calculate
  173. required string length first. */
  174. len = 0;
  175. for (i = 0; i < com->size; i++)
  176. {
  177. memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t));
  178. comval = ntohl (comval);
  179. switch (comval)
  180. {
  181. case COMMUNITY_INTERNET:
  182. len += strlen (" internet");
  183. break;
  184. case COMMUNITY_NO_EXPORT:
  185. len += strlen (" no-export");
  186. break;
  187. case COMMUNITY_NO_ADVERTISE:
  188. len += strlen (" no-advertise");
  189. break;
  190. case COMMUNITY_LOCAL_AS:
  191. len += strlen (" local-AS");
  192. break;
  193. default:
  194. len += strlen (" 65536:65535");
  195. break;
  196. }
  197. }
  198. /* Allocate memory. */
  199. str = pnt = XMALLOC (MTYPE_COMMUNITY_STR, len);
  200. first = 1;
  201. /* Fill in string. */
  202. for (i = 0; i < com->size; i++)
  203. {
  204. memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t));
  205. comval = ntohl (comval);
  206. if (first)
  207. first = 0;
  208. else
  209. *pnt++ = ' ';
  210. switch (comval)
  211. {
  212. case COMMUNITY_INTERNET:
  213. strcpy (pnt, "internet");
  214. pnt += strlen ("internet");
  215. break;
  216. case COMMUNITY_NO_EXPORT:
  217. strcpy (pnt, "no-export");
  218. pnt += strlen ("no-export");
  219. break;
  220. case COMMUNITY_NO_ADVERTISE:
  221. strcpy (pnt, "no-advertise");
  222. pnt += strlen ("no-advertise");
  223. break;
  224. case COMMUNITY_LOCAL_AS:
  225. strcpy (pnt, "local-AS");
  226. pnt += strlen ("local-AS");
  227. break;
  228. default:
  229. as = (comval >> 16) & 0xFFFF;
  230. val = comval & 0xFFFF;
  231. sprintf (pnt, "%d:%d", as, val);
  232. pnt += strlen (pnt);
  233. break;
  234. }
  235. }
  236. *pnt = '\0';
  237. return str;
  238. }
  239. /* Intern communities attribute. */
  240. struct community *
  241. community_intern (struct community *com)
  242. {
  243. struct community *find;
  244. /* Assert this community structure is not interned. */
  245. assert (com->refcnt == 0);
  246. /* Lookup community hash. */
  247. find = (struct community *) hash_get (comhash, com, hash_alloc_intern);
  248. /* Arguemnt com is allocated temporary. So when it is not used in
  249. hash, it should be freed. */
  250. if (find != com)
  251. community_free (com);
  252. /* Increment refrence counter. */
  253. find->refcnt++;
  254. /* Make string. */
  255. if (! find->str)
  256. find->str = community_com2str (find);
  257. return find;
  258. }
  259. /* Free community attribute. */
  260. void
  261. community_unintern (struct community *com)
  262. {
  263. struct community *ret;
  264. if (com->refcnt)
  265. com->refcnt--;
  266. /* Pull off from hash. */
  267. if (com->refcnt == 0)
  268. {
  269. /* Community value com must exist in hash. */
  270. ret = (struct community *) hash_release (comhash, com);
  271. assert (ret != NULL);
  272. community_free (com);
  273. }
  274. }
  275. /* Create new community attribute. */
  276. struct community *
  277. community_parse (u_int32_t *pnt, u_short length)
  278. {
  279. struct community tmp;
  280. struct community *new;
  281. /* If length is malformed return NULL. */
  282. if (length % 4)
  283. return NULL;
  284. /* Make temporary community for hash look up. */
  285. tmp.size = length / 4;
  286. tmp.val = pnt;
  287. new = community_uniq_sort (&tmp);
  288. return community_intern (new);
  289. }
  290. struct community *
  291. community_dup (struct community *com)
  292. {
  293. struct community *new;
  294. new = XCALLOC (MTYPE_COMMUNITY, sizeof (struct community));
  295. new->size = com->size;
  296. if (new->size)
  297. {
  298. new->val = XMALLOC (MTYPE_COMMUNITY_VAL, com->size * 4);
  299. memcpy (new->val, com->val, com->size * 4);
  300. }
  301. else
  302. new->val = NULL;
  303. return new;
  304. }
  305. /* Retrun string representation of communities attribute. */
  306. char *
  307. community_str (struct community *com)
  308. {
  309. if (! com->str)
  310. com->str = community_com2str (com);
  311. return com->str;
  312. }
  313. /* Make hash value of community attribute. This function is used by
  314. hash package.*/
  315. unsigned int
  316. community_hash_make (struct community *com)
  317. {
  318. int c;
  319. unsigned int key;
  320. unsigned char *pnt;
  321. key = 0;
  322. pnt = (unsigned char *)com->val;
  323. for(c = 0; c < com->size * 4; c++)
  324. key += pnt[c];
  325. return key;
  326. }
  327. int
  328. community_match (const struct community *com1, const struct community *com2)
  329. {
  330. int i = 0;
  331. int j = 0;
  332. if (com1 == NULL && com2 == NULL)
  333. return 1;
  334. if (com1 == NULL || com2 == NULL)
  335. return 0;
  336. if (com1->size < com2->size)
  337. return 0;
  338. /* Every community on com2 needs to be on com1 for this to match */
  339. while (i < com1->size && j < com2->size)
  340. {
  341. if (memcmp (com1->val + i, com2->val + j, sizeof (u_int32_t)) == 0)
  342. j++;
  343. i++;
  344. }
  345. if (j == com2->size)
  346. return 1;
  347. else
  348. return 0;
  349. }
  350. /* If two aspath have same value then return 1 else return 0. This
  351. function is used by hash package. */
  352. int
  353. community_cmp (const struct community *com1, const struct community *com2)
  354. {
  355. if (com1 == NULL && com2 == NULL)
  356. return 1;
  357. if (com1 == NULL || com2 == NULL)
  358. return 0;
  359. if (com1->size == com2->size)
  360. if (memcmp (com1->val, com2->val, com1->size * 4) == 0)
  361. return 1;
  362. return 0;
  363. }
  364. /* Add com2 to the end of com1. */
  365. struct community *
  366. community_merge (struct community *com1, struct community *com2)
  367. {
  368. if (com1->val)
  369. com1->val = XREALLOC (MTYPE_COMMUNITY_VAL, com1->val,
  370. (com1->size + com2->size) * 4);
  371. else
  372. com1->val = XMALLOC (MTYPE_COMMUNITY_VAL, (com1->size + com2->size) * 4);
  373. memcpy (com1->val + com1->size, com2->val, com2->size * 4);
  374. com1->size += com2->size;
  375. return com1;
  376. }
  377. /* Community token enum. */
  378. enum community_token
  379. {
  380. community_token_val,
  381. community_token_no_export,
  382. community_token_no_advertise,
  383. community_token_local_as,
  384. community_token_unknown
  385. };
  386. /* Get next community token from string. */
  387. const char *
  388. community_gettoken (const char *buf, enum community_token *token,
  389. u_int32_t *val)
  390. {
  391. const char *p = buf;
  392. /* Skip white space. */
  393. while (isspace ((int) *p))
  394. p++;
  395. /* Check the end of the line. */
  396. if (*p == '\0')
  397. return NULL;
  398. /* Well known community string check. */
  399. if (isalpha ((int) *p))
  400. {
  401. if (strncmp (p, "internet", strlen ("internet")) == 0)
  402. {
  403. *val = COMMUNITY_INTERNET;
  404. *token = community_token_no_export;
  405. p += strlen ("internet");
  406. return p;
  407. }
  408. if (strncmp (p, "no-export", strlen ("no-export")) == 0)
  409. {
  410. *val = COMMUNITY_NO_EXPORT;
  411. *token = community_token_no_export;
  412. p += strlen ("no-export");
  413. return p;
  414. }
  415. if (strncmp (p, "no-advertise", strlen ("no-advertise")) == 0)
  416. {
  417. *val = COMMUNITY_NO_ADVERTISE;
  418. *token = community_token_no_advertise;
  419. p += strlen ("no-advertise");
  420. return p;
  421. }
  422. if (strncmp (p, "local-AS", strlen ("local-AS")) == 0)
  423. {
  424. *val = COMMUNITY_LOCAL_AS;
  425. *token = community_token_local_as;
  426. p += strlen ("local-AS");
  427. return p;
  428. }
  429. /* Unknown string. */
  430. *token = community_token_unknown;
  431. return NULL;
  432. }
  433. /* Community value. */
  434. if (isdigit ((int) *p))
  435. {
  436. int separator = 0;
  437. int digit = 0;
  438. u_int32_t community_low = 0;
  439. u_int32_t community_high = 0;
  440. while (isdigit ((int) *p) || *p == ':')
  441. {
  442. if (*p == ':')
  443. {
  444. if (separator)
  445. {
  446. *token = community_token_unknown;
  447. return NULL;
  448. }
  449. else
  450. {
  451. separator = 1;
  452. digit = 0;
  453. community_high = community_low << 16;
  454. community_low = 0;
  455. }
  456. }
  457. else
  458. {
  459. digit = 1;
  460. community_low *= 10;
  461. community_low += (*p - '0');
  462. }
  463. p++;
  464. }
  465. if (! digit)
  466. {
  467. *token = community_token_unknown;
  468. return NULL;
  469. }
  470. *val = community_high + community_low;
  471. *token = community_token_val;
  472. return p;
  473. }
  474. *token = community_token_unknown;
  475. return NULL;
  476. }
  477. /* convert string to community structure */
  478. struct community *
  479. community_str2com (const char *str)
  480. {
  481. struct community *com = NULL;
  482. struct community *com_sort = NULL;
  483. u_int32_t val;
  484. enum community_token token;
  485. do
  486. {
  487. str = community_gettoken (str, &token, &val);
  488. switch (token)
  489. {
  490. case community_token_val:
  491. case community_token_no_export:
  492. case community_token_no_advertise:
  493. case community_token_local_as:
  494. if (com == NULL)
  495. com = community_new();
  496. community_add_val (com, val);
  497. break;
  498. case community_token_unknown:
  499. default:
  500. if (com)
  501. community_free (com);
  502. return NULL;
  503. break;
  504. }
  505. } while (str);
  506. if (! com)
  507. return NULL;
  508. com_sort = community_uniq_sort (com);
  509. community_free (com);
  510. return com_sort;
  511. }
  512. /* Return communities hash entry count. */
  513. unsigned long
  514. community_count ()
  515. {
  516. return comhash->count;
  517. }
  518. /* Return communities hash. */
  519. struct hash *
  520. community_hash ()
  521. {
  522. return comhash;
  523. }
  524. /* Initialize comminity related hash. */
  525. void
  526. community_init ()
  527. {
  528. comhash = hash_create (community_hash_make, community_cmp);
  529. }