bgp_clist.c 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235
  1. /* BGP community-list and extcommunity-list.
  2. Copyright (C) 1999 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 "command.h"
  18. #include "prefix.h"
  19. #include "memory.h"
  20. #include "filter.h"
  21. #include "bgpd/bgpd.h"
  22. #include "bgpd/bgp_community.h"
  23. #include "bgpd/bgp_ecommunity.h"
  24. #include "bgpd/bgp_lcommunity.h"
  25. #include "bgpd/bgp_aspath.h"
  26. #include "bgpd/bgp_regex.h"
  27. #include "bgpd/bgp_clist.h"
  28. /* Lookup master structure for community-list or
  29. extcommunity-list. */
  30. struct community_list_master *
  31. community_list_master_lookup (struct community_list_handler *ch, int master)
  32. {
  33. if (ch)
  34. switch (master)
  35. {
  36. case COMMUNITY_LIST_MASTER:
  37. return &ch->community_list;
  38. case EXTCOMMUNITY_LIST_MASTER:
  39. return &ch->extcommunity_list;
  40. case LARGE_COMMUNITY_LIST_MASTER:
  41. return &ch->lcommunity_list;
  42. }
  43. return NULL;
  44. }
  45. /* Allocate a new community list entry. */
  46. static struct community_entry *
  47. community_entry_new (void)
  48. {
  49. return XCALLOC (MTYPE_COMMUNITY_LIST_ENTRY, sizeof (struct community_entry));
  50. }
  51. /* Free community list entry. */
  52. static void
  53. community_entry_free (struct community_entry *entry)
  54. {
  55. switch (entry->style)
  56. {
  57. case COMMUNITY_LIST_STANDARD:
  58. if (entry->u.com)
  59. community_free (entry->u.com);
  60. break;
  61. case LARGE_COMMUNITY_LIST_STANDARD:
  62. if (entry->u.lcom)
  63. lcommunity_free (&entry->u.lcom);
  64. break;
  65. case EXTCOMMUNITY_LIST_STANDARD:
  66. /* In case of standard extcommunity-list, configuration string
  67. is made by ecommunity_ecom2str(). */
  68. if (entry->config)
  69. XFREE (MTYPE_ECOMMUNITY_STR, entry->config);
  70. if (entry->u.ecom)
  71. ecommunity_free (&entry->u.ecom);
  72. break;
  73. case COMMUNITY_LIST_EXPANDED:
  74. case EXTCOMMUNITY_LIST_EXPANDED:
  75. case LARGE_COMMUNITY_LIST_EXPANDED:
  76. if (entry->config)
  77. XFREE (MTYPE_COMMUNITY_LIST_CONFIG, entry->config);
  78. if (entry->reg)
  79. bgp_regex_free (entry->reg);
  80. default:
  81. break;
  82. }
  83. XFREE (MTYPE_COMMUNITY_LIST_ENTRY, entry);
  84. }
  85. /* Allocate a new community-list. */
  86. static struct community_list *
  87. community_list_new (void)
  88. {
  89. return XCALLOC (MTYPE_COMMUNITY_LIST, sizeof (struct community_list));
  90. }
  91. /* Free community-list. */
  92. static void
  93. community_list_free (struct community_list *list)
  94. {
  95. if (list->name)
  96. XFREE (MTYPE_COMMUNITY_LIST_NAME, list->name);
  97. XFREE (MTYPE_COMMUNITY_LIST, list);
  98. }
  99. static struct community_list *
  100. community_list_insert (struct community_list_handler *ch,
  101. const char *name, int master)
  102. {
  103. size_t i;
  104. long number;
  105. struct community_list *new;
  106. struct community_list *point;
  107. struct community_list_list *list;
  108. struct community_list_master *cm;
  109. /* Lookup community-list master. */
  110. cm = community_list_master_lookup (ch, master);
  111. if (!cm)
  112. return NULL;
  113. /* Allocate new community_list and copy given name. */
  114. new = community_list_new ();
  115. new->name = XSTRDUP (MTYPE_COMMUNITY_LIST_NAME, name);
  116. /* If name is made by all digit character. We treat it as
  117. number. */
  118. for (number = 0, i = 0; i < strlen (name); i++)
  119. {
  120. if (isdigit ((int) name[i]))
  121. number = (number * 10) + (name[i] - '0');
  122. else
  123. break;
  124. }
  125. /* In case of name is all digit character */
  126. if (i == strlen (name))
  127. {
  128. new->sort = COMMUNITY_LIST_NUMBER;
  129. /* Set access_list to number list. */
  130. list = &cm->num;
  131. for (point = list->head; point; point = point->next)
  132. if (atol (point->name) >= number)
  133. break;
  134. }
  135. else
  136. {
  137. new->sort = COMMUNITY_LIST_STRING;
  138. /* Set access_list to string list. */
  139. list = &cm->str;
  140. /* Set point to insertion point. */
  141. for (point = list->head; point; point = point->next)
  142. if (strcmp (point->name, name) >= 0)
  143. break;
  144. }
  145. /* Link to upper list. */
  146. new->parent = list;
  147. /* In case of this is the first element of master. */
  148. if (list->head == NULL)
  149. {
  150. list->head = list->tail = new;
  151. return new;
  152. }
  153. /* In case of insertion is made at the tail of access_list. */
  154. if (point == NULL)
  155. {
  156. new->prev = list->tail;
  157. list->tail->next = new;
  158. list->tail = new;
  159. return new;
  160. }
  161. /* In case of insertion is made at the head of access_list. */
  162. if (point == list->head)
  163. {
  164. new->next = list->head;
  165. list->head->prev = new;
  166. list->head = new;
  167. return new;
  168. }
  169. /* Insertion is made at middle of the access_list. */
  170. new->next = point;
  171. new->prev = point->prev;
  172. if (point->prev)
  173. point->prev->next = new;
  174. point->prev = new;
  175. return new;
  176. }
  177. struct community_list *
  178. community_list_lookup (struct community_list_handler *ch,
  179. const char *name, int master)
  180. {
  181. struct community_list *list;
  182. struct community_list_master *cm;
  183. if (!name)
  184. return NULL;
  185. cm = community_list_master_lookup (ch, master);
  186. if (!cm)
  187. return NULL;
  188. for (list = cm->num.head; list; list = list->next)
  189. if (strcmp (list->name, name) == 0)
  190. return list;
  191. for (list = cm->str.head; list; list = list->next)
  192. if (strcmp (list->name, name) == 0)
  193. return list;
  194. return NULL;
  195. }
  196. static struct community_list *
  197. community_list_get (struct community_list_handler *ch,
  198. const char *name, int master)
  199. {
  200. struct community_list *list;
  201. list = community_list_lookup (ch, name, master);
  202. if (!list)
  203. list = community_list_insert (ch, name, master);
  204. return list;
  205. }
  206. static void
  207. community_list_delete (struct community_list *list)
  208. {
  209. struct community_list_list *clist;
  210. struct community_entry *entry, *next;
  211. for (entry = list->head; entry; entry = next)
  212. {
  213. next = entry->next;
  214. community_entry_free (entry);
  215. }
  216. clist = list->parent;
  217. if (list->next)
  218. list->next->prev = list->prev;
  219. else
  220. clist->tail = list->prev;
  221. if (list->prev)
  222. list->prev->next = list->next;
  223. else
  224. clist->head = list->next;
  225. community_list_free (list);
  226. }
  227. static int
  228. community_list_empty_p (struct community_list *list)
  229. {
  230. return (list->head == NULL && list->tail == NULL) ? 1 : 0;
  231. }
  232. /* Add community-list entry to the list. */
  233. static void
  234. community_list_entry_add (struct community_list *list,
  235. struct community_entry *entry)
  236. {
  237. entry->next = NULL;
  238. entry->prev = list->tail;
  239. if (list->tail)
  240. list->tail->next = entry;
  241. else
  242. list->head = entry;
  243. list->tail = entry;
  244. }
  245. /* Delete community-list entry from the list. */
  246. static void
  247. community_list_entry_delete (struct community_list *list,
  248. struct community_entry *entry, int style)
  249. {
  250. if (entry->next)
  251. entry->next->prev = entry->prev;
  252. else
  253. list->tail = entry->prev;
  254. if (entry->prev)
  255. entry->prev->next = entry->next;
  256. else
  257. list->head = entry->next;
  258. community_entry_free (entry);
  259. if (community_list_empty_p (list))
  260. community_list_delete (list);
  261. }
  262. /* Lookup community-list entry from the list. */
  263. static struct community_entry *
  264. community_list_entry_lookup (struct community_list *list, const void *arg,
  265. int direct)
  266. {
  267. struct community_entry *entry;
  268. for (entry = list->head; entry; entry = entry->next)
  269. {
  270. switch (entry->style)
  271. {
  272. case COMMUNITY_LIST_STANDARD:
  273. if (community_cmp (entry->u.com, arg))
  274. return entry;
  275. break;
  276. case LARGE_COMMUNITY_LIST_STANDARD:
  277. if (lcommunity_cmp (entry->u.lcom, arg))
  278. return entry;
  279. break;
  280. case EXTCOMMUNITY_LIST_STANDARD:
  281. if (ecommunity_cmp (entry->u.ecom, arg))
  282. return entry;
  283. break;
  284. case COMMUNITY_LIST_EXPANDED:
  285. case EXTCOMMUNITY_LIST_EXPANDED:
  286. case LARGE_COMMUNITY_LIST_EXPANDED:
  287. if (strcmp (entry->config, arg) == 0)
  288. return entry;
  289. break;
  290. default:
  291. break;
  292. }
  293. }
  294. return NULL;
  295. }
  296. static char *
  297. community_str_get (struct community *com, int i)
  298. {
  299. int len;
  300. u_int32_t comval;
  301. u_int16_t as;
  302. u_int16_t val;
  303. char *str;
  304. char *pnt;
  305. memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t));
  306. comval = ntohl (comval);
  307. switch (comval)
  308. {
  309. case COMMUNITY_INTERNET:
  310. len = strlen (" internet");
  311. break;
  312. case COMMUNITY_NO_EXPORT:
  313. len = strlen (" no-export");
  314. break;
  315. case COMMUNITY_NO_ADVERTISE:
  316. len = strlen (" no-advertise");
  317. break;
  318. case COMMUNITY_LOCAL_AS:
  319. len = strlen (" local-AS");
  320. break;
  321. default:
  322. len = strlen (" 65536:65535");
  323. break;
  324. }
  325. /* Allocate memory. */
  326. str = pnt = XMALLOC (MTYPE_COMMUNITY_STR, len);
  327. switch (comval)
  328. {
  329. case COMMUNITY_INTERNET:
  330. strcpy (pnt, "internet");
  331. pnt += strlen ("internet");
  332. break;
  333. case COMMUNITY_NO_EXPORT:
  334. strcpy (pnt, "no-export");
  335. pnt += strlen ("no-export");
  336. break;
  337. case COMMUNITY_NO_ADVERTISE:
  338. strcpy (pnt, "no-advertise");
  339. pnt += strlen ("no-advertise");
  340. break;
  341. case COMMUNITY_LOCAL_AS:
  342. strcpy (pnt, "local-AS");
  343. pnt += strlen ("local-AS");
  344. break;
  345. default:
  346. as = (comval >> 16) & 0xFFFF;
  347. val = comval & 0xFFFF;
  348. sprintf (pnt, "%u:%d", as, val);
  349. pnt += strlen (pnt);
  350. break;
  351. }
  352. *pnt = '\0';
  353. return str;
  354. }
  355. /* Internal function to perform regular expression match for
  356. * * a single community. */
  357. static int
  358. community_regexp_include (regex_t * reg, struct community *com, int i)
  359. {
  360. char *str;
  361. int rv;
  362. /* When there is no communities attribute it is treated as empty
  363. * string. */
  364. if (com == NULL || com->size == 0)
  365. str = XSTRDUP(MTYPE_COMMUNITY_STR, "");
  366. else
  367. str = community_str_get (com, i);
  368. /* Regular expression match. */
  369. rv = regexec (reg, str, 0, NULL, 0);
  370. XFREE(MTYPE_COMMUNITY_STR, str);
  371. if (rv == 0)
  372. return 1;
  373. /* No match. */
  374. return 0;
  375. }
  376. /* Internal function to perform regular expression match for community
  377. attribute. */
  378. static int
  379. community_regexp_match (struct community *com, regex_t * reg)
  380. {
  381. const char *str;
  382. /* When there is no communities attribute it is treated as empty
  383. string. */
  384. if (com == NULL || com->size == 0)
  385. str = "";
  386. else
  387. str = community_str (com);
  388. /* Regular expression match. */
  389. if (regexec (reg, str, 0, NULL, 0) == 0)
  390. return 1;
  391. /* No match. */
  392. return 0;
  393. }
  394. static char *
  395. lcommunity_str_get (struct lcommunity *lcom, int i)
  396. {
  397. struct lcommunity_val lcomval;
  398. u_int32_t globaladmin;
  399. u_int32_t localdata1;
  400. u_int32_t localdata2;
  401. char *str;
  402. u_char *ptr;
  403. char *pnt;
  404. ptr = lcom->val;
  405. ptr += (i * LCOMMUNITY_SIZE);
  406. memcpy (&lcomval, ptr, LCOMMUNITY_SIZE);
  407. /* Allocate memory. 48 bytes taken off bgp_lcommunity.c */
  408. str = pnt = XMALLOC (MTYPE_LCOMMUNITY_STR, 48);
  409. ptr = (u_char *)lcomval.val;
  410. globaladmin = (*ptr++ << 24);
  411. globaladmin |= (*ptr++ << 16);
  412. globaladmin |= (*ptr++ << 8);
  413. globaladmin |= (*ptr++);
  414. localdata1 = (*ptr++ << 24);
  415. localdata1 |= (*ptr++ << 16);
  416. localdata1 |= (*ptr++ << 8);
  417. localdata1 |= (*ptr++);
  418. localdata2 = (*ptr++ << 24);
  419. localdata2 |= (*ptr++ << 16);
  420. localdata2 |= (*ptr++ << 8);
  421. localdata2 |= (*ptr++);
  422. sprintf (pnt, "%u:%u:%u", globaladmin, localdata1, localdata2);
  423. pnt += strlen (pnt);
  424. *pnt = '\0';
  425. return str;
  426. }
  427. /* Internal function to perform regular expression match for
  428. * * a single community. */
  429. static int
  430. lcommunity_regexp_include (regex_t * reg, struct lcommunity *lcom, int i)
  431. {
  432. const char *str;
  433. /* When there is no communities attribute it is treated as empty
  434. * string. */
  435. if (lcom == NULL || lcom->size == 0)
  436. str = "";
  437. else
  438. str = lcommunity_str_get (lcom, i);
  439. /* Regular expression match. */
  440. if (regexec (reg, str, 0, NULL, 0) == 0)
  441. return 1;
  442. /* No match. */
  443. return 0;
  444. }
  445. static int
  446. lcommunity_regexp_match (struct lcommunity *com, regex_t * reg)
  447. {
  448. const char *str;
  449. /* When there is no communities attribute it is treated as empty
  450. string. */
  451. if (com == NULL || com->size == 0)
  452. str = "";
  453. else
  454. str = lcommunity_str (com);
  455. /* Regular expression match. */
  456. if (regexec (reg, str, 0, NULL, 0) == 0)
  457. return 1;
  458. /* No match. */
  459. return 0;
  460. }
  461. static int
  462. ecommunity_regexp_match (struct ecommunity *ecom, regex_t * reg)
  463. {
  464. const char *str;
  465. /* When there is no communities attribute it is treated as empty
  466. string. */
  467. if (ecom == NULL || ecom->size == 0)
  468. str = "";
  469. else
  470. str = ecommunity_str (ecom);
  471. /* Regular expression match. */
  472. if (regexec (reg, str, 0, NULL, 0) == 0)
  473. return 1;
  474. /* No match. */
  475. return 0;
  476. }
  477. /* When given community attribute matches to the community-list return
  478. 1 else return 0. */
  479. int
  480. community_list_match (struct community *com, struct community_list *list)
  481. {
  482. struct community_entry *entry;
  483. for (entry = list->head; entry; entry = entry->next)
  484. {
  485. if (entry->any)
  486. return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
  487. if (entry->style == COMMUNITY_LIST_STANDARD)
  488. {
  489. if (community_include (entry->u.com, COMMUNITY_INTERNET))
  490. return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
  491. if (community_match (com, entry->u.com))
  492. return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
  493. }
  494. else if (entry->style == COMMUNITY_LIST_EXPANDED)
  495. {
  496. if (community_regexp_match (com, entry->reg))
  497. return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
  498. }
  499. }
  500. return 0;
  501. }
  502. int
  503. lcommunity_list_match (struct lcommunity *lcom, struct community_list *list)
  504. {
  505. struct community_entry *entry;
  506. for (entry = list->head; entry; entry = entry->next)
  507. {
  508. if (entry->any)
  509. return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
  510. if (entry->style == LARGE_COMMUNITY_LIST_STANDARD)
  511. {
  512. if (lcommunity_match (lcom, entry->u.lcom))
  513. return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
  514. }
  515. else if (entry->style == LARGE_COMMUNITY_LIST_EXPANDED)
  516. {
  517. if (lcommunity_regexp_match (lcom, entry->reg))
  518. return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
  519. }
  520. }
  521. return 0;
  522. }
  523. int
  524. ecommunity_list_match (struct ecommunity *ecom, struct community_list *list)
  525. {
  526. struct community_entry *entry;
  527. for (entry = list->head; entry; entry = entry->next)
  528. {
  529. if (entry->any)
  530. return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
  531. if (entry->style == EXTCOMMUNITY_LIST_STANDARD)
  532. {
  533. if (ecommunity_match (ecom, entry->u.ecom))
  534. return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
  535. }
  536. else if (entry->style == EXTCOMMUNITY_LIST_EXPANDED)
  537. {
  538. if (ecommunity_regexp_match (ecom, entry->reg))
  539. return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
  540. }
  541. }
  542. return 0;
  543. }
  544. /* Perform exact matching. In case of expanded community-list, do
  545. same thing as community_list_match(). */
  546. int
  547. community_list_exact_match (struct community *com,
  548. struct community_list *list)
  549. {
  550. struct community_entry *entry;
  551. for (entry = list->head; entry; entry = entry->next)
  552. {
  553. if (entry->any)
  554. return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
  555. if (entry->style == COMMUNITY_LIST_STANDARD)
  556. {
  557. if (community_include (entry->u.com, COMMUNITY_INTERNET))
  558. return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
  559. if (community_cmp (com, entry->u.com))
  560. return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
  561. }
  562. else if (entry->style == COMMUNITY_LIST_EXPANDED)
  563. {
  564. if (community_regexp_match (com, entry->reg))
  565. return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
  566. }
  567. }
  568. return 0;
  569. }
  570. /* Delete all permitted communities in the list from com. */
  571. struct community *
  572. community_list_match_delete (struct community *com,
  573. struct community_list *list)
  574. {
  575. struct community_entry *entry;
  576. u_int32_t val;
  577. u_int32_t com_index_to_delete[com->size];
  578. int delete_index = 0;
  579. int i;
  580. /* Loop over each community value and evaluate each against the
  581. * community-list. If we need to delete a community value add its index to
  582. * com_index_to_delete.
  583. */
  584. for (i = 0; i < com->size; i++)
  585. {
  586. val = community_val_get (com, i);
  587. for (entry = list->head; entry; entry = entry->next)
  588. {
  589. if (entry->any)
  590. {
  591. if (entry->direct == COMMUNITY_PERMIT)
  592. {
  593. com_index_to_delete[delete_index] = i;
  594. delete_index++;
  595. }
  596. break;
  597. }
  598. else if ((entry->style == COMMUNITY_LIST_STANDARD)
  599. && (community_include (entry->u.com, COMMUNITY_INTERNET)
  600. || community_include (entry->u.com, val) ))
  601. {
  602. if (entry->direct == COMMUNITY_PERMIT)
  603. {
  604. com_index_to_delete[delete_index] = i;
  605. delete_index++;
  606. }
  607. break;
  608. }
  609. else if ((entry->style == COMMUNITY_LIST_EXPANDED)
  610. && community_regexp_include (entry->reg, com, i))
  611. {
  612. if (entry->direct == COMMUNITY_PERMIT)
  613. {
  614. com_index_to_delete[delete_index] = i;
  615. delete_index++;
  616. }
  617. break;
  618. }
  619. }
  620. }
  621. /* Delete all of the communities we flagged for deletion */
  622. for (i = delete_index-1; i >= 0; i--)
  623. {
  624. val = community_val_get (com, com_index_to_delete[i]);
  625. community_del_val (com, &val);
  626. }
  627. return com;
  628. }
  629. /* To avoid duplicated entry in the community-list, this function
  630. compares specified entry to existing entry. */
  631. static int
  632. community_list_dup_check (struct community_list *list,
  633. struct community_entry *new)
  634. {
  635. struct community_entry *entry;
  636. for (entry = list->head; entry; entry = entry->next)
  637. {
  638. if (entry->style != new->style)
  639. continue;
  640. if (entry->direct != new->direct)
  641. continue;
  642. if (entry->any != new->any)
  643. continue;
  644. if (entry->any)
  645. return 1;
  646. switch (entry->style)
  647. {
  648. case COMMUNITY_LIST_STANDARD:
  649. if (community_cmp (entry->u.com, new->u.com))
  650. return 1;
  651. break;
  652. case EXTCOMMUNITY_LIST_STANDARD:
  653. if (ecommunity_cmp (entry->u.ecom, new->u.ecom))
  654. return 1;
  655. break;
  656. case LARGE_COMMUNITY_LIST_STANDARD:
  657. if (lcommunity_cmp (entry->u.lcom, new->u.lcom))
  658. return 1;
  659. break;
  660. case COMMUNITY_LIST_EXPANDED:
  661. case EXTCOMMUNITY_LIST_EXPANDED:
  662. case LARGE_COMMUNITY_LIST_EXPANDED:
  663. if (entry->config && new->config
  664. && strcmp (entry->config, new->config) == 0)
  665. return 1;
  666. if (!entry->config && !new->config)
  667. return 1;
  668. break;
  669. default:
  670. break;
  671. }
  672. }
  673. return 0;
  674. }
  675. /* Set community-list. */
  676. int
  677. community_list_set (struct community_list_handler *ch,
  678. const char *name, const char *str, int direct, int style)
  679. {
  680. struct community_entry *entry = NULL;
  681. struct community_list *list;
  682. struct community *com = NULL;
  683. regex_t *regex = NULL;
  684. /* Get community list. */
  685. list = community_list_get (ch, name, COMMUNITY_LIST_MASTER);
  686. /* When community-list already has entry, new entry should have same
  687. style. If you want to have mixed style community-list, you can
  688. comment out this check. */
  689. if (!community_list_empty_p (list))
  690. {
  691. struct community_entry *first;
  692. first = list->head;
  693. if (style != first->style)
  694. {
  695. return (first->style == COMMUNITY_LIST_STANDARD
  696. ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
  697. : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
  698. }
  699. }
  700. if (str)
  701. {
  702. if (style == COMMUNITY_LIST_STANDARD)
  703. com = community_str2com (str);
  704. else
  705. regex = bgp_regcomp (str);
  706. if (! com && ! regex)
  707. return COMMUNITY_LIST_ERR_MALFORMED_VAL;
  708. }
  709. entry = community_entry_new ();
  710. entry->direct = direct;
  711. entry->style = style;
  712. entry->any = (str ? 0 : 1);
  713. entry->u.com = com;
  714. entry->reg = regex;
  715. entry->config = (regex ? XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str) : NULL);
  716. /* Do not put duplicated community entry. */
  717. if (community_list_dup_check (list, entry))
  718. community_entry_free (entry);
  719. else
  720. community_list_entry_add (list, entry);
  721. return 0;
  722. }
  723. /* Unset community-list. When str is NULL, delete all of
  724. community-list entry belongs to the specified name. */
  725. int
  726. community_list_unset (struct community_list_handler *ch,
  727. const char *name, const char *str,
  728. int direct, int style)
  729. {
  730. struct community_entry *entry = NULL;
  731. struct community_list *list;
  732. struct community *com = NULL;
  733. regex_t *regex = NULL;
  734. /* Lookup community list. */
  735. list = community_list_lookup (ch, name, COMMUNITY_LIST_MASTER);
  736. if (list == NULL)
  737. return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
  738. /* Delete all of entry belongs to this community-list. */
  739. if (!str)
  740. {
  741. community_list_delete (list);
  742. return 0;
  743. }
  744. if (style == COMMUNITY_LIST_STANDARD)
  745. com = community_str2com (str);
  746. else
  747. regex = bgp_regcomp (str);
  748. if (! com && ! regex)
  749. return COMMUNITY_LIST_ERR_MALFORMED_VAL;
  750. if (com)
  751. entry = community_list_entry_lookup (list, com, direct);
  752. else
  753. entry = community_list_entry_lookup (list, str, direct);
  754. if (com)
  755. community_free (com);
  756. if (regex)
  757. bgp_regex_free (regex);
  758. if (!entry)
  759. return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
  760. community_list_entry_delete (list, entry, style);
  761. return 0;
  762. }
  763. /* Delete all permitted large communities in the list from com. */
  764. struct lcommunity *
  765. lcommunity_list_match_delete (struct lcommunity *lcom,
  766. struct community_list *list)
  767. {
  768. struct community_entry *entry;
  769. u_int32_t com_index_to_delete[lcom->size];
  770. u_char *ptr;
  771. int delete_index = 0;
  772. int i;
  773. /* Loop over each lcommunity value and evaluate each against the
  774. * community-list. If we need to delete a community value add its index to
  775. * com_index_to_delete.
  776. */
  777. for (i = 0; i < lcom->size; i++)
  778. {
  779. ptr = lcom->val + (i * LCOMMUNITY_SIZE);
  780. for (entry = list->head; entry; entry = entry->next)
  781. {
  782. if (entry->any)
  783. {
  784. if (entry->direct == COMMUNITY_PERMIT)
  785. {
  786. com_index_to_delete[delete_index] = i;
  787. delete_index++;
  788. }
  789. break;
  790. }
  791. else if ((entry->style == LARGE_COMMUNITY_LIST_STANDARD)
  792. && lcommunity_include (entry->u.lcom, ptr) )
  793. {
  794. if (entry->direct == COMMUNITY_PERMIT)
  795. {
  796. com_index_to_delete[delete_index] = i;
  797. delete_index++;
  798. }
  799. break;
  800. }
  801. else if ((entry->style == LARGE_COMMUNITY_LIST_STANDARD)
  802. && entry->reg
  803. && lcommunity_regexp_include (entry->reg, lcom, i))
  804. {
  805. if (entry->direct == COMMUNITY_PERMIT)
  806. {
  807. com_index_to_delete[delete_index] = i;
  808. delete_index++;
  809. }
  810. break;
  811. }
  812. }
  813. }
  814. /* Delete all of the communities we flagged for deletion */
  815. for (i = delete_index-1; i >= 0; i--)
  816. {
  817. ptr = lcom->val + (com_index_to_delete[i] * LCOMMUNITY_SIZE);
  818. lcommunity_del_val (lcom, ptr);
  819. }
  820. return lcom;
  821. }
  822. /* Set lcommunity-list. */
  823. int
  824. lcommunity_list_set (struct community_list_handler *ch,
  825. const char *name, const char *str, int direct, int style)
  826. {
  827. struct community_entry *entry = NULL;
  828. struct community_list *list;
  829. struct lcommunity *lcom = NULL;
  830. regex_t *regex = NULL;
  831. /* Get community list. */
  832. list = community_list_get (ch, name, LARGE_COMMUNITY_LIST_MASTER);
  833. /* When community-list already has entry, new entry should have same
  834. style. If you want to have mixed style community-list, you can
  835. comment out this check. */
  836. if (!community_list_empty_p (list))
  837. {
  838. struct community_entry *first;
  839. first = list->head;
  840. if (style != first->style)
  841. {
  842. return (first->style == COMMUNITY_LIST_STANDARD
  843. ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
  844. : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
  845. }
  846. }
  847. if (str)
  848. {
  849. if (style == LARGE_COMMUNITY_LIST_STANDARD)
  850. lcom = lcommunity_str2com (str);
  851. else
  852. regex = bgp_regcomp (str);
  853. if (! lcom && ! regex)
  854. return COMMUNITY_LIST_ERR_MALFORMED_VAL;
  855. }
  856. entry = community_entry_new ();
  857. entry->direct = direct;
  858. entry->style = style;
  859. entry->any = (str ? 0 : 1);
  860. entry->u.lcom = lcom;
  861. entry->reg = regex;
  862. if (lcom)
  863. entry->config = lcommunity_lcom2str (lcom, LCOMMUNITY_FORMAT_COMMUNITY_LIST);
  864. else if (regex)
  865. entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str);
  866. else
  867. entry->config = NULL;
  868. /* Do not put duplicated community entry. */
  869. if (community_list_dup_check (list, entry))
  870. community_entry_free (entry);
  871. else
  872. community_list_entry_add (list, entry);
  873. return 0;
  874. }
  875. /* Unset community-list. When str is NULL, delete all of
  876. community-list entry belongs to the specified name. */
  877. int
  878. lcommunity_list_unset (struct community_list_handler *ch,
  879. const char *name, const char *str,
  880. int direct, int style)
  881. {
  882. struct community_entry *entry = NULL;
  883. struct community_list *list;
  884. struct lcommunity *lcom = NULL;
  885. regex_t *regex = NULL;
  886. /* Lookup community list. */
  887. list = community_list_lookup (ch, name, LARGE_COMMUNITY_LIST_MASTER);
  888. if (list == NULL)
  889. return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
  890. /* Delete all of entry belongs to this community-list. */
  891. if (!str)
  892. {
  893. community_list_delete (list);
  894. return 0;
  895. }
  896. if (style == LARGE_COMMUNITY_LIST_STANDARD)
  897. lcom = lcommunity_str2com (str);
  898. else
  899. regex = bgp_regcomp (str);
  900. if (! lcom && ! regex)
  901. return COMMUNITY_LIST_ERR_MALFORMED_VAL;
  902. if (lcom)
  903. entry = community_list_entry_lookup (list, lcom, direct);
  904. else
  905. entry = community_list_entry_lookup (list, str, direct);
  906. if (lcom)
  907. lcommunity_free (&lcom);
  908. if (regex)
  909. bgp_regex_free (regex);
  910. if (!entry)
  911. return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
  912. community_list_entry_delete (list, entry, style);
  913. return 0;
  914. }
  915. /* Set extcommunity-list. */
  916. int
  917. extcommunity_list_set (struct community_list_handler *ch,
  918. const char *name, const char *str,
  919. int direct, int style)
  920. {
  921. struct community_entry *entry = NULL;
  922. struct community_list *list;
  923. struct ecommunity *ecom = NULL;
  924. regex_t *regex = NULL;
  925. entry = NULL;
  926. /* Get community list. */
  927. list = community_list_get (ch, name, EXTCOMMUNITY_LIST_MASTER);
  928. /* When community-list already has entry, new entry should have same
  929. style. If you want to have mixed style community-list, you can
  930. comment out this check. */
  931. if (!community_list_empty_p (list))
  932. {
  933. struct community_entry *first;
  934. first = list->head;
  935. if (style != first->style)
  936. {
  937. return (first->style == EXTCOMMUNITY_LIST_STANDARD
  938. ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
  939. : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
  940. }
  941. }
  942. if (str)
  943. {
  944. if (style == EXTCOMMUNITY_LIST_STANDARD)
  945. ecom = ecommunity_str2com (str, 0, 1);
  946. else
  947. regex = bgp_regcomp (str);
  948. if (! ecom && ! regex)
  949. return COMMUNITY_LIST_ERR_MALFORMED_VAL;
  950. }
  951. if (ecom)
  952. ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY);
  953. entry = community_entry_new ();
  954. entry->direct = direct;
  955. entry->style = style;
  956. entry->any = (str ? 0 : 1);
  957. if (ecom)
  958. entry->config = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST);
  959. else if (regex)
  960. entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str);
  961. else
  962. entry->config = NULL;
  963. entry->u.ecom = ecom;
  964. entry->reg = regex;
  965. /* Do not put duplicated community entry. */
  966. if (community_list_dup_check (list, entry))
  967. community_entry_free (entry);
  968. else
  969. community_list_entry_add (list, entry);
  970. return 0;
  971. }
  972. /* Unset extcommunity-list. When str is NULL, delete all of
  973. extcommunity-list entry belongs to the specified name. */
  974. int
  975. extcommunity_list_unset (struct community_list_handler *ch,
  976. const char *name, const char *str,
  977. int direct, int style)
  978. {
  979. struct community_entry *entry = NULL;
  980. struct community_list *list;
  981. struct ecommunity *ecom = NULL;
  982. regex_t *regex = NULL;
  983. /* Lookup extcommunity list. */
  984. list = community_list_lookup (ch, name, EXTCOMMUNITY_LIST_MASTER);
  985. if (list == NULL)
  986. return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
  987. /* Delete all of entry belongs to this extcommunity-list. */
  988. if (!str)
  989. {
  990. community_list_delete (list);
  991. return 0;
  992. }
  993. if (style == EXTCOMMUNITY_LIST_STANDARD)
  994. ecom = ecommunity_str2com (str, 0, 1);
  995. else
  996. regex = bgp_regcomp (str);
  997. if (! ecom && ! regex)
  998. return COMMUNITY_LIST_ERR_MALFORMED_VAL;
  999. if (ecom)
  1000. entry = community_list_entry_lookup (list, ecom, direct);
  1001. else
  1002. entry = community_list_entry_lookup (list, str, direct);
  1003. if (ecom)
  1004. ecommunity_free (&ecom);
  1005. if (regex)
  1006. bgp_regex_free (regex);
  1007. if (!entry)
  1008. return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
  1009. community_list_entry_delete (list, entry, style);
  1010. return 0;
  1011. }
  1012. /* Initializa community-list. Return community-list handler. */
  1013. struct community_list_handler *
  1014. community_list_init (void)
  1015. {
  1016. struct community_list_handler *ch;
  1017. ch = XCALLOC (MTYPE_COMMUNITY_LIST_HANDLER,
  1018. sizeof (struct community_list_handler));
  1019. return ch;
  1020. }
  1021. /* Terminate community-list. */
  1022. void
  1023. community_list_terminate (struct community_list_handler *ch)
  1024. {
  1025. struct community_list_master *cm;
  1026. struct community_list *list;
  1027. cm = &ch->community_list;
  1028. while ((list = cm->num.head) != NULL)
  1029. community_list_delete (list);
  1030. while ((list = cm->str.head) != NULL)
  1031. community_list_delete (list);
  1032. cm = &ch->lcommunity_list;
  1033. while ((list = cm->num.head) != NULL)
  1034. community_list_delete (list);
  1035. while ((list = cm->str.head) != NULL)
  1036. community_list_delete (list);
  1037. cm = &ch->extcommunity_list;
  1038. while ((list = cm->num.head) != NULL)
  1039. community_list_delete (list);
  1040. while ((list = cm->str.head) != NULL)
  1041. community_list_delete (list);
  1042. XFREE (MTYPE_COMMUNITY_LIST_HANDLER, ch);
  1043. }