]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_routemap.c
Merge pull request #7639 from qlyoung/frr-lua
[mirror_frr.git] / bgpd / bgp_routemap.c
1 /* Route map function of bgpd.
2 * Copyright (C) 1998, 1999 Kunihiro Ishiguro
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include <zebra.h>
22
23 #include "prefix.h"
24 #include "filter.h"
25 #include "routemap.h"
26 #include "command.h"
27 #include "linklist.h"
28 #include "plist.h"
29 #include "memory.h"
30 #include "log.h"
31 #include "frrlua.h"
32 #ifdef HAVE_LIBPCREPOSIX
33 #include <pcreposix.h>
34 #else
35 #include <regex.h>
36 #endif /* HAVE_LIBPCREPOSIX */
37 #include "buffer.h"
38 #include "sockunion.h"
39 #include "hash.h"
40 #include "queue.h"
41 #include "frrstr.h"
42 #include "network.h"
43
44 #include "bgpd/bgpd.h"
45 #include "bgpd/bgp_table.h"
46 #include "bgpd/bgp_attr.h"
47 #include "bgpd/bgp_aspath.h"
48 #include "bgpd/bgp_packet.h"
49 #include "bgpd/bgp_route.h"
50 #include "bgpd/bgp_zebra.h"
51 #include "bgpd/bgp_regex.h"
52 #include "bgpd/bgp_community.h"
53 #include "bgpd/bgp_clist.h"
54 #include "bgpd/bgp_filter.h"
55 #include "bgpd/bgp_mplsvpn.h"
56 #include "bgpd/bgp_ecommunity.h"
57 #include "bgpd/bgp_lcommunity.h"
58 #include "bgpd/bgp_vty.h"
59 #include "bgpd/bgp_debug.h"
60 #include "bgpd/bgp_evpn.h"
61 #include "bgpd/bgp_evpn_private.h"
62 #include "bgpd/bgp_evpn_vty.h"
63 #include "bgpd/bgp_mplsvpn.h"
64 #include "bgpd/bgp_pbr.h"
65 #include "bgpd/bgp_flowspec_util.h"
66 #include "bgpd/bgp_encap_types.h"
67 #include "bgpd/bgp_mpath.h"
68 #include "bgpd/bgp_script.h"
69
70 #ifdef ENABLE_BGP_VNC
71 #include "bgpd/rfapi/bgp_rfapi_cfg.h"
72 #endif
73
74 #ifndef VTYSH_EXTRACT_PL
75 #include "bgpd/bgp_routemap_clippy.c"
76 #endif
77
78 /* Memo of route-map commands.
79
80 o Cisco route-map
81
82 match as-path : Done
83 community : Done
84 interface : Done
85 ip address : Done
86 ip next-hop : Done
87 ip route-source : Done
88 ip prefix-list : Done
89 ipv6 address : Done
90 ipv6 next-hop : Done
91 ipv6 route-source: (This will not be implemented by bgpd)
92 ipv6 prefix-list : Done
93 length : (This will not be implemented by bgpd)
94 metric : Done
95 route-type : (This will not be implemented by bgpd)
96 tag : Done
97 local-preference : Done
98
99 set as-path prepend : Done
100 as-path tag : Not yet
101 automatic-tag : (This will not be implemented by bgpd)
102 community : Done
103 large-community : Done
104 large-comm-list : Done
105 comm-list : Not yet
106 dampning : Not yet
107 default : (This will not be implemented by bgpd)
108 interface : (This will not be implemented by bgpd)
109 ip default : (This will not be implemented by bgpd)
110 ip next-hop : Done
111 ip precedence : (This will not be implemented by bgpd)
112 ip tos : (This will not be implemented by bgpd)
113 level : (This will not be implemented by bgpd)
114 local-preference : Done
115 metric : Done
116 metric-type : Not yet
117 origin : Done
118 tag : Done
119 weight : Done
120 table : Done
121
122 o Local extensions
123
124 set ipv6 next-hop global: Done
125 set ipv6 next-hop prefer-global: Done
126 set ipv6 next-hop local : Done
127 set as-path exclude : Done
128
129 */
130
131 /* generic value manipulation to be shared in multiple rules */
132
133 #define RMAP_VALUE_SET 0
134 #define RMAP_VALUE_ADD 1
135 #define RMAP_VALUE_SUB 2
136
137 struct rmap_value {
138 uint8_t action;
139 uint8_t variable;
140 uint32_t value;
141 };
142
143 static int route_value_match(struct rmap_value *rv, uint32_t value)
144 {
145 if (rv->variable == 0 && value == rv->value)
146 return RMAP_MATCH;
147
148 return RMAP_NOMATCH;
149 }
150
151 static uint32_t route_value_adjust(struct rmap_value *rv, uint32_t current,
152 struct peer *peer)
153 {
154 uint32_t value;
155
156 switch (rv->variable) {
157 case 1:
158 value = peer->rtt;
159 break;
160 default:
161 value = rv->value;
162 break;
163 }
164
165 switch (rv->action) {
166 case RMAP_VALUE_ADD:
167 if (current > UINT32_MAX - value)
168 return UINT32_MAX;
169 return current + value;
170 case RMAP_VALUE_SUB:
171 if (current <= value)
172 return 0;
173 return current - value;
174 default:
175 return value;
176 }
177 }
178
179 static void *route_value_compile(const char *arg)
180 {
181 uint8_t action = RMAP_VALUE_SET, var = 0;
182 unsigned long larg = 0;
183 char *endptr = NULL;
184 struct rmap_value *rv;
185
186 if (arg[0] == '+') {
187 action = RMAP_VALUE_ADD;
188 arg++;
189 } else if (arg[0] == '-') {
190 action = RMAP_VALUE_SUB;
191 arg++;
192 }
193
194 if (all_digit(arg)) {
195 errno = 0;
196 larg = strtoul(arg, &endptr, 10);
197 if (*arg == 0 || *endptr != 0 || errno || larg > UINT32_MAX)
198 return NULL;
199 } else {
200 if (strcmp(arg, "rtt") == 0)
201 var = 1;
202 else
203 return NULL;
204 }
205
206 rv = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_value));
207
208 rv->action = action;
209 rv->variable = var;
210 rv->value = larg;
211 return rv;
212 }
213
214 static void route_value_free(void *rule)
215 {
216 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
217 }
218
219 /* generic as path object to be shared in multiple rules */
220
221 static void *route_aspath_compile(const char *arg)
222 {
223 struct aspath *aspath;
224
225 aspath = aspath_str2aspath(arg);
226 if (!aspath)
227 return NULL;
228 return aspath;
229 }
230
231 static void route_aspath_free(void *rule)
232 {
233 struct aspath *aspath = rule;
234 aspath_free(aspath);
235 }
236
237 struct bgp_match_peer_compiled {
238 char *interface;
239 union sockunion su;
240 };
241
242 /* 'match peer (A.B.C.D|X:X::X:X|WORD)' */
243
244 /* Compares the peer specified in the 'match peer' clause with the peer
245 received in bgp_path_info->peer. If it is the same, or if the peer structure
246 received is a peer_group containing it, returns RMAP_MATCH. */
247 static enum route_map_cmd_result_t
248 route_match_peer(void *rule, const struct prefix *prefix, void *object)
249 {
250 struct bgp_match_peer_compiled *pc;
251 union sockunion *su;
252 union sockunion su_def = {
253 .sin = {.sin_family = AF_INET, .sin_addr.s_addr = INADDR_ANY}};
254 struct peer_group *group;
255 struct peer *peer;
256 struct listnode *node, *nnode;
257
258 pc = rule;
259 su = &pc->su;
260 peer = ((struct bgp_path_info *)object)->peer;
261
262 if (pc->interface) {
263 if (!peer->conf_if)
264 return RMAP_NOMATCH;
265
266 if (strcmp(peer->conf_if, pc->interface) == 0)
267 return RMAP_MATCH;
268
269 return RMAP_NOMATCH;
270 }
271
272 /* If su='0.0.0.0' (command 'match peer local'), and it's a
273 NETWORK,
274 REDISTRIBUTE, AGGREGATE-ADDRESS or DEFAULT_GENERATED route
275 => return RMAP_MATCH
276 */
277 if (sockunion_same(su, &su_def)) {
278 int ret;
279 if (CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_NETWORK)
280 || CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_REDISTRIBUTE)
281 || CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_AGGREGATE)
282 || CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_DEFAULT))
283 ret = RMAP_MATCH;
284 else
285 ret = RMAP_NOMATCH;
286 return ret;
287 }
288
289 if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
290 if (sockunion_same(su, &peer->su))
291 return RMAP_MATCH;
292
293 return RMAP_NOMATCH;
294 } else {
295 group = peer->group;
296 for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
297 if (sockunion_same(su, &peer->su))
298 return RMAP_MATCH;
299 }
300 return RMAP_NOMATCH;
301 }
302
303 return RMAP_NOMATCH;
304 }
305
306 static void *route_match_peer_compile(const char *arg)
307 {
308 struct bgp_match_peer_compiled *pc;
309 int ret;
310
311 pc = XCALLOC(MTYPE_ROUTE_MAP_COMPILED,
312 sizeof(struct bgp_match_peer_compiled));
313
314 ret = str2sockunion(strcmp(arg, "local") ? arg : "0.0.0.0", &pc->su);
315 if (ret < 0) {
316 pc->interface = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
317 return pc;
318 }
319
320 return pc;
321 }
322
323 /* Free route map's compiled `ip address' value. */
324 static void route_match_peer_free(void *rule)
325 {
326 struct bgp_match_peer_compiled *pc = rule;
327
328 XFREE(MTYPE_ROUTE_MAP_COMPILED, pc->interface);
329
330 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
331 }
332
333 /* Route map commands for ip address matching. */
334 static const struct route_map_rule_cmd route_match_peer_cmd = {
335 "peer",
336 route_match_peer,
337 route_match_peer_compile,
338 route_match_peer_free
339 };
340
341 #ifdef HAVE_SCRIPTING
342
343 enum frrlua_rm_status {
344 /*
345 * Script function run failure. This will translate into a deny
346 */
347 LUA_RM_FAILURE = 0,
348 /*
349 * No Match was found for the route map function
350 */
351 LUA_RM_NOMATCH,
352 /*
353 * Match was found but no changes were made to the incoming data.
354 */
355 LUA_RM_MATCH,
356 /*
357 * Match was found and data was modified, so figure out what changed
358 */
359 LUA_RM_MATCH_AND_CHANGE,
360 };
361
362 static enum route_map_cmd_result_t
363 route_match_script(void *rule, const struct prefix *prefix, void *object)
364 {
365 const char *scriptname = rule;
366 struct bgp_path_info *path = (struct bgp_path_info *)object;
367
368 struct frrscript *fs = frrscript_load(scriptname, NULL);
369
370 if (!fs) {
371 zlog_err("Issue loading script rule; defaulting to no match");
372 return RMAP_NOMATCH;
373 }
374
375 enum frrlua_rm_status status_failure = LUA_RM_FAILURE,
376 status_nomatch = LUA_RM_NOMATCH,
377 status_match = LUA_RM_MATCH,
378 status_match_and_change = LUA_RM_MATCH_AND_CHANGE;
379
380 /* Make result values available */
381 struct frrscript_env env[] = {
382 {"integer", "RM_FAILURE", &status_failure},
383 {"integer", "RM_NOMATCH", &status_nomatch},
384 {"integer", "RM_MATCH", &status_match},
385 {"integer", "RM_MATCH_AND_CHANGE", &status_match_and_change},
386 {"integer", "action", &status_failure},
387 {"prefix", "prefix", prefix},
388 {"attr", "attributes", path->attr},
389 {"peer", "peer", path->peer},
390 {}};
391
392 struct frrscript_env results[] = {
393 {"integer", "action"},
394 {"attr", "attributes"},
395 {},
396 };
397
398 int result = frrscript_call(fs, env);
399
400 if (result) {
401 zlog_err("Issue running script rule; defaulting to no match");
402 return RMAP_NOMATCH;
403 }
404
405 enum frrlua_rm_status *lrm_status =
406 frrscript_get_result(fs, &results[0]);
407
408 int status = RMAP_NOMATCH;
409
410 switch (*lrm_status) {
411 case LUA_RM_FAILURE:
412 zlog_err(
413 "Executing route-map match script '%s' failed; defaulting to no match",
414 scriptname);
415 status = RMAP_NOMATCH;
416 break;
417 case LUA_RM_NOMATCH:
418 status = RMAP_NOMATCH;
419 break;
420 case LUA_RM_MATCH_AND_CHANGE:
421 status = RMAP_MATCH;
422 zlog_debug("Updating attribute based on script's values");
423
424 uint32_t locpref = 0;
425 struct attr *newattr = frrscript_get_result(fs, &results[1]);
426
427 path->attr->med = newattr->med;
428
429 if (path->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF))
430 locpref = path->attr->local_pref;
431 if (locpref != newattr->local_pref) {
432 SET_FLAG(path->attr->flag,
433 ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF));
434 path->attr->local_pref = newattr->local_pref;
435 }
436
437 aspath_free(newattr->aspath);
438 XFREE(MTYPE_TMP, newattr);
439 break;
440 case LUA_RM_MATCH:
441 status = RMAP_MATCH;
442 break;
443 }
444
445 XFREE(MTYPE_TMP, lrm_status);
446 frrscript_unload(fs);
447
448 return status;
449 }
450
451 static void *route_match_script_compile(const char *arg)
452 {
453 char *scriptname;
454
455 scriptname = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
456
457 return scriptname;
458 }
459
460 static void route_match_script_free(void *rule)
461 {
462 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
463 }
464
465 static const struct route_map_rule_cmd route_match_script_cmd = {
466 "script",
467 route_match_script,
468 route_match_script_compile,
469 route_match_script_free
470 };
471
472 #endif /* HAVE_SCRIPTING */
473
474 /* `match ip address IP_ACCESS_LIST' */
475
476 /* Match function should return 1 if match is success else return
477 zero. */
478 static enum route_map_cmd_result_t
479 route_match_ip_address(void *rule, const struct prefix *prefix, void *object)
480 {
481 struct access_list *alist;
482
483 if (prefix->family == AF_INET) {
484 alist = access_list_lookup(AFI_IP, (char *)rule);
485 if (alist == NULL)
486 return RMAP_NOMATCH;
487
488 return (access_list_apply(alist, prefix) == FILTER_DENY
489 ? RMAP_NOMATCH
490 : RMAP_MATCH);
491 }
492 return RMAP_NOMATCH;
493 }
494
495 /* Route map `ip address' match statement. `arg' should be
496 access-list name. */
497 static void *route_match_ip_address_compile(const char *arg)
498 {
499 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
500 }
501
502 /* Free route map's compiled `ip address' value. */
503 static void route_match_ip_address_free(void *rule)
504 {
505 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
506 }
507
508 /* Route map commands for ip address matching. */
509 static const struct route_map_rule_cmd route_match_ip_address_cmd = {
510 "ip address",
511 route_match_ip_address,
512 route_match_ip_address_compile,
513 route_match_ip_address_free
514 };
515
516 /* `match ip next-hop IP_ADDRESS' */
517
518 /* Match function return 1 if match is success else return zero. */
519 static enum route_map_cmd_result_t
520 route_match_ip_next_hop(void *rule, const struct prefix *prefix, void *object)
521 {
522 struct access_list *alist;
523 struct bgp_path_info *path;
524 struct prefix_ipv4 p;
525
526 if (prefix->family == AF_INET) {
527 path = object;
528 p.family = AF_INET;
529 p.prefix = path->attr->nexthop;
530 p.prefixlen = IPV4_MAX_BITLEN;
531
532 alist = access_list_lookup(AFI_IP, (char *)rule);
533 if (alist == NULL)
534 return RMAP_NOMATCH;
535
536 return (access_list_apply(alist, &p) == FILTER_DENY
537 ? RMAP_NOMATCH
538 : RMAP_MATCH);
539 }
540 return RMAP_NOMATCH;
541 }
542
543 /* Route map `ip next-hop' match statement. `arg' is
544 access-list name. */
545 static void *route_match_ip_next_hop_compile(const char *arg)
546 {
547 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
548 }
549
550 /* Free route map's compiled `ip address' value. */
551 static void route_match_ip_next_hop_free(void *rule)
552 {
553 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
554 }
555
556 /* Route map commands for ip next-hop matching. */
557 static const struct route_map_rule_cmd route_match_ip_next_hop_cmd = {
558 "ip next-hop",
559 route_match_ip_next_hop,
560 route_match_ip_next_hop_compile,
561 route_match_ip_next_hop_free
562 };
563
564 /* `match ip route-source ACCESS-LIST' */
565
566 /* Match function return 1 if match is success else return zero. */
567 static enum route_map_cmd_result_t
568 route_match_ip_route_source(void *rule, const struct prefix *pfx, void *object)
569 {
570 struct access_list *alist;
571 struct bgp_path_info *path;
572 struct peer *peer;
573 struct prefix_ipv4 p;
574
575 if (pfx->family == AF_INET) {
576 path = object;
577 peer = path->peer;
578
579 if (!peer || sockunion_family(&peer->su) != AF_INET)
580 return RMAP_NOMATCH;
581
582 p.family = AF_INET;
583 p.prefix = peer->su.sin.sin_addr;
584 p.prefixlen = IPV4_MAX_BITLEN;
585
586 alist = access_list_lookup(AFI_IP, (char *)rule);
587 if (alist == NULL)
588 return RMAP_NOMATCH;
589
590 return (access_list_apply(alist, &p) == FILTER_DENY
591 ? RMAP_NOMATCH
592 : RMAP_MATCH);
593 }
594 return RMAP_NOMATCH;
595 }
596
597 /* Route map `ip route-source' match statement. `arg' is
598 access-list name. */
599 static void *route_match_ip_route_source_compile(const char *arg)
600 {
601 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
602 }
603
604 /* Free route map's compiled `ip address' value. */
605 static void route_match_ip_route_source_free(void *rule)
606 {
607 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
608 }
609
610 /* Route map commands for ip route-source matching. */
611 static const struct route_map_rule_cmd route_match_ip_route_source_cmd = {
612 "ip route-source",
613 route_match_ip_route_source,
614 route_match_ip_route_source_compile,
615 route_match_ip_route_source_free
616 };
617
618 static enum route_map_cmd_result_t
619 route_match_prefix_list_flowspec(afi_t afi, struct prefix_list *plist,
620 const struct prefix *p)
621 {
622 int ret;
623 struct bgp_pbr_entry_main api;
624
625 memset(&api, 0, sizeof(api));
626
627 if (family2afi(p->u.prefix_flowspec.family) != afi)
628 return RMAP_NOMATCH;
629
630 /* extract match from flowspec entries */
631 ret = bgp_flowspec_match_rules_fill(
632 (uint8_t *)p->u.prefix_flowspec.ptr,
633 p->u.prefix_flowspec.prefixlen, &api,
634 afi);
635 if (ret < 0)
636 return RMAP_NOMATCH;
637 if (api.match_bitmask & PREFIX_DST_PRESENT ||
638 api.match_bitmask_iprule & PREFIX_DST_PRESENT) {
639 if (family2afi((&api.dst_prefix)->family) != afi)
640 return RMAP_NOMATCH;
641 return prefix_list_apply(plist, &api.dst_prefix) == PREFIX_DENY
642 ? RMAP_NOMATCH
643 : RMAP_MATCH;
644 } else if (api.match_bitmask & PREFIX_SRC_PRESENT ||
645 api.match_bitmask_iprule & PREFIX_SRC_PRESENT) {
646 if (family2afi((&api.src_prefix)->family) != afi)
647 return RMAP_NOMATCH;
648 return (prefix_list_apply(plist, &api.src_prefix) == PREFIX_DENY
649 ? RMAP_NOMATCH
650 : RMAP_MATCH);
651 }
652 return RMAP_NOMATCH;
653 }
654
655 static enum route_map_cmd_result_t
656 route_match_address_prefix_list(void *rule, afi_t afi,
657 const struct prefix *prefix, void *object)
658 {
659 struct prefix_list *plist;
660
661 plist = prefix_list_lookup(afi, (char *)rule);
662 if (plist == NULL)
663 return RMAP_NOMATCH;
664
665 if (prefix->family == AF_FLOWSPEC)
666 return route_match_prefix_list_flowspec(afi, plist,
667 prefix);
668 return (prefix_list_apply(plist, prefix) == PREFIX_DENY ? RMAP_NOMATCH
669 : RMAP_MATCH);
670 }
671
672 static enum route_map_cmd_result_t
673 route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix,
674 void *object)
675 {
676 return route_match_address_prefix_list(rule, AFI_IP, prefix, object);
677 }
678
679 static void *route_match_ip_address_prefix_list_compile(const char *arg)
680 {
681 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
682 }
683
684 static void route_match_ip_address_prefix_list_free(void *rule)
685 {
686 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
687 }
688
689 static const struct route_map_rule_cmd
690 route_match_ip_address_prefix_list_cmd = {
691 "ip address prefix-list",
692 route_match_ip_address_prefix_list,
693 route_match_ip_address_prefix_list_compile,
694 route_match_ip_address_prefix_list_free
695 };
696
697 /* `match ip next-hop prefix-list PREFIX_LIST' */
698
699 static enum route_map_cmd_result_t
700 route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix,
701 void *object)
702 {
703 struct prefix_list *plist;
704 struct bgp_path_info *path;
705 struct prefix_ipv4 p;
706
707 if (prefix->family == AF_INET) {
708 path = object;
709 p.family = AF_INET;
710 p.prefix = path->attr->nexthop;
711 p.prefixlen = IPV4_MAX_BITLEN;
712
713 plist = prefix_list_lookup(AFI_IP, (char *)rule);
714 if (plist == NULL)
715 return RMAP_NOMATCH;
716
717 return (prefix_list_apply(plist, &p) == PREFIX_DENY
718 ? RMAP_NOMATCH
719 : RMAP_MATCH);
720 }
721 return RMAP_NOMATCH;
722 }
723
724 static void *route_match_ip_next_hop_prefix_list_compile(const char *arg)
725 {
726 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
727 }
728
729 static void route_match_ip_next_hop_prefix_list_free(void *rule)
730 {
731 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
732 }
733
734 static const struct route_map_rule_cmd
735 route_match_ip_next_hop_prefix_list_cmd = {
736 "ip next-hop prefix-list",
737 route_match_ip_next_hop_prefix_list,
738 route_match_ip_next_hop_prefix_list_compile,
739 route_match_ip_next_hop_prefix_list_free
740 };
741
742 /* `match ip next-hop type <blackhole>' */
743
744 static enum route_map_cmd_result_t
745 route_match_ip_next_hop_type(void *rule, const struct prefix *prefix,
746 void *object)
747 {
748 struct bgp_path_info *path;
749
750 if (prefix->family == AF_INET) {
751 path = (struct bgp_path_info *)object;
752 if (!path)
753 return RMAP_NOMATCH;
754
755 /* If nexthop interface's index can't be resolved and nexthop is
756 set to any address then mark it as type `blackhole`.
757 This logic works for matching kernel/static routes like:
758 `ip route add blackhole 10.0.0.1`. */
759 if (path->attr->nexthop.s_addr == INADDR_ANY
760 && !path->attr->nh_ifindex)
761 return RMAP_MATCH;
762 }
763 return RMAP_NOMATCH;
764 }
765
766 static void *route_match_ip_next_hop_type_compile(const char *arg)
767 {
768 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
769 }
770
771 static void route_match_ip_next_hop_type_free(void *rule)
772 {
773 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
774 }
775
776 static const struct route_map_rule_cmd
777 route_match_ip_next_hop_type_cmd = {
778 "ip next-hop type",
779 route_match_ip_next_hop_type,
780 route_match_ip_next_hop_type_compile,
781 route_match_ip_next_hop_type_free
782 };
783
784 /* `match ip route-source prefix-list PREFIX_LIST' */
785
786 static enum route_map_cmd_result_t
787 route_match_ip_route_source_prefix_list(void *rule, const struct prefix *prefix,
788 void *object)
789 {
790 struct prefix_list *plist;
791 struct bgp_path_info *path;
792 struct peer *peer;
793 struct prefix_ipv4 p;
794
795 if (prefix->family == AF_INET) {
796 path = object;
797 peer = path->peer;
798
799 if (!peer || sockunion_family(&peer->su) != AF_INET)
800 return RMAP_NOMATCH;
801
802 p.family = AF_INET;
803 p.prefix = peer->su.sin.sin_addr;
804 p.prefixlen = IPV4_MAX_BITLEN;
805
806 plist = prefix_list_lookup(AFI_IP, (char *)rule);
807 if (plist == NULL)
808 return RMAP_NOMATCH;
809
810 return (prefix_list_apply(plist, &p) == PREFIX_DENY
811 ? RMAP_NOMATCH
812 : RMAP_MATCH);
813 }
814 return RMAP_NOMATCH;
815 }
816
817 static void *route_match_ip_route_source_prefix_list_compile(const char *arg)
818 {
819 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
820 }
821
822 static void route_match_ip_route_source_prefix_list_free(void *rule)
823 {
824 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
825 }
826
827 static const struct route_map_rule_cmd
828 route_match_ip_route_source_prefix_list_cmd = {
829 "ip route-source prefix-list",
830 route_match_ip_route_source_prefix_list,
831 route_match_ip_route_source_prefix_list_compile,
832 route_match_ip_route_source_prefix_list_free
833 };
834
835 /* `match evpn default-route' */
836
837 /* Match function should return 1 if match is success else 0 */
838 static enum route_map_cmd_result_t
839 route_match_evpn_default_route(void *rule, const struct prefix *p, void *object)
840 {
841 if (is_evpn_prefix_default(p))
842 return RMAP_MATCH;
843
844 return RMAP_NOMATCH;
845 }
846
847 /* Route map commands for default-route matching. */
848 static const struct route_map_rule_cmd
849 route_match_evpn_default_route_cmd = {
850 "evpn default-route",
851 route_match_evpn_default_route,
852 NULL,
853 NULL
854 };
855
856 /* `match mac address MAC_ACCESS_LIST' */
857
858 /* Match function should return 1 if match is success else return
859 zero. */
860 static enum route_map_cmd_result_t
861 route_match_mac_address(void *rule, const struct prefix *prefix, void *object)
862 {
863 struct access_list *alist;
864 struct prefix p;
865
866 alist = access_list_lookup(AFI_L2VPN, (char *)rule);
867 if (alist == NULL)
868 return RMAP_NOMATCH;
869
870 if (prefix->u.prefix_evpn.route_type != BGP_EVPN_MAC_IP_ROUTE)
871 return RMAP_NOMATCH;
872
873 p.family = AF_ETHERNET;
874 p.prefixlen = ETH_ALEN * 8;
875 p.u.prefix_eth = prefix->u.prefix_evpn.macip_addr.mac;
876
877 return (access_list_apply(alist, &p) == FILTER_DENY ? RMAP_NOMATCH
878 : RMAP_MATCH);
879 }
880
881 /* Route map `mac address' match statement. `arg' should be
882 access-list name. */
883 static void *route_match_mac_address_compile(const char *arg)
884 {
885 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
886 }
887
888 /* Free route map's compiled `ip address' value. */
889 static void route_match_mac_address_free(void *rule)
890 {
891 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
892 }
893
894 /* Route map commands for mac address matching. */
895 static const struct route_map_rule_cmd route_match_mac_address_cmd = {
896 "mac address",
897 route_match_mac_address,
898 route_match_mac_address_compile,
899 route_match_mac_address_free
900 };
901
902 /*
903 * Match function returns:
904 * ...RMAP_MATCH if match is found.
905 * ...RMAP_NOMATCH if match is not found.
906 * ...RMAP_NOOP to ignore this match check.
907 */
908 static enum route_map_cmd_result_t
909 route_match_vni(void *rule, const struct prefix *prefix, void *object)
910 {
911 vni_t vni = 0;
912 unsigned int label_cnt = 0;
913 struct bgp_path_info *path = NULL;
914 struct prefix_evpn *evp = (struct prefix_evpn *) prefix;
915
916 vni = *((vni_t *)rule);
917 path = (struct bgp_path_info *)object;
918
919 /*
920 * This rmap filter is valid for vxlan tunnel type only.
921 * For any other tunnel type, return noop to ignore
922 * this check.
923 */
924 if (path->attr->encap_tunneltype != BGP_ENCAP_TYPE_VXLAN)
925 return RMAP_NOOP;
926
927 /*
928 * Apply filter to type 1, 2, 5 routes only.
929 * Other route types do not have vni label.
930 */
931 if (evp
932 && (evp->prefix.route_type != BGP_EVPN_AD_ROUTE
933 && evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE
934 && evp->prefix.route_type != BGP_EVPN_IP_PREFIX_ROUTE))
935 return RMAP_NOOP;
936
937 if (path->extra == NULL)
938 return RMAP_NOMATCH;
939
940 for (;
941 label_cnt < BGP_MAX_LABELS && label_cnt < path->extra->num_labels;
942 label_cnt++) {
943 if (vni == label2vni(&path->extra->label[label_cnt]))
944 return RMAP_MATCH;
945 }
946
947 return RMAP_NOMATCH;
948 }
949
950 /* Route map `vni' match statement. */
951 static void *route_match_vni_compile(const char *arg)
952 {
953 vni_t *vni = NULL;
954 char *end = NULL;
955
956 vni = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(vni_t));
957
958 *vni = strtoul(arg, &end, 10);
959 if (*end != '\0') {
960 XFREE(MTYPE_ROUTE_MAP_COMPILED, vni);
961 return NULL;
962 }
963
964 return vni;
965 }
966
967 /* Free route map's compiled `vni' value. */
968 static void route_match_vni_free(void *rule)
969 {
970 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
971 }
972
973 /* Route map commands for vni matching. */
974 static const struct route_map_rule_cmd route_match_evpn_vni_cmd = {
975 "evpn vni",
976 route_match_vni,
977 route_match_vni_compile,
978 route_match_vni_free
979 };
980
981 /* `match evpn route-type' */
982
983 /* Match function should return 1 if match is success else return
984 zero. */
985 static enum route_map_cmd_result_t
986 route_match_evpn_route_type(void *rule, const struct prefix *pfx, void *object)
987 {
988 uint8_t route_type = 0;
989
990 route_type = *((uint8_t *)rule);
991
992 if (route_type == pfx->u.prefix_evpn.route_type)
993 return RMAP_MATCH;
994
995 return RMAP_NOMATCH;
996 }
997
998 /* Route map `route-type' match statement. */
999 static void *route_match_evpn_route_type_compile(const char *arg)
1000 {
1001 uint8_t *route_type = NULL;
1002
1003 route_type = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint8_t));
1004
1005 if (strncmp(arg, "ma", 2) == 0)
1006 *route_type = BGP_EVPN_MAC_IP_ROUTE;
1007 else if (strncmp(arg, "mu", 2) == 0)
1008 *route_type = BGP_EVPN_IMET_ROUTE;
1009 else
1010 *route_type = BGP_EVPN_IP_PREFIX_ROUTE;
1011
1012 return route_type;
1013 }
1014
1015 /* Free route map's compiled `route-type' value. */
1016 static void route_match_evpn_route_type_free(void *rule)
1017 {
1018 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
1019 }
1020
1021 /* Route map commands for evpn route-type matching. */
1022 static const struct route_map_rule_cmd route_match_evpn_route_type_cmd = {
1023 "evpn route-type",
1024 route_match_evpn_route_type,
1025 route_match_evpn_route_type_compile,
1026 route_match_evpn_route_type_free
1027 };
1028
1029 /* `match rd' */
1030
1031 /* Match function should return 1 if match is success else return zero. */
1032 static enum route_map_cmd_result_t
1033 route_match_rd(void *rule, const struct prefix *prefix, void *object)
1034 {
1035 struct prefix_rd *prd_rule = NULL;
1036 const struct prefix_rd *prd_route = NULL;
1037 struct bgp_path_info *path = NULL;
1038
1039 if (prefix->family != AF_EVPN)
1040 return RMAP_NOMATCH;
1041
1042 prd_rule = (struct prefix_rd *)rule;
1043 path = (struct bgp_path_info *)object;
1044
1045 if (path->net == NULL || path->net->pdest == NULL)
1046 return RMAP_NOMATCH;
1047
1048 prd_route = (struct prefix_rd *)bgp_dest_get_prefix(path->net->pdest);
1049 if (memcmp(prd_route->val, prd_rule->val, ECOMMUNITY_SIZE) == 0)
1050 return RMAP_MATCH;
1051
1052 return RMAP_NOMATCH;
1053 }
1054
1055 /* Route map `rd' match statement. */
1056 static void *route_match_rd_compile(const char *arg)
1057 {
1058 struct prefix_rd *prd;
1059 int ret;
1060
1061 prd = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct prefix_rd));
1062
1063 ret = str2prefix_rd(arg, prd);
1064 if (!ret) {
1065 XFREE(MTYPE_ROUTE_MAP_COMPILED, prd);
1066 return NULL;
1067 }
1068
1069 return prd;
1070 }
1071
1072 /* Free route map's compiled `rd' value. */
1073 static void route_match_rd_free(void *rule)
1074 {
1075 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
1076 }
1077
1078 /* Route map commands for rd matching. */
1079 static const struct route_map_rule_cmd route_match_evpn_rd_cmd = {
1080 "evpn rd",
1081 route_match_rd,
1082 route_match_rd_compile,
1083 route_match_rd_free
1084 };
1085
1086 /* Route map commands for VRF route leak with source vrf matching */
1087 static enum route_map_cmd_result_t
1088 route_match_vrl_source_vrf(void *rule, const struct prefix *prefix,
1089 void *object)
1090 {
1091 struct bgp_path_info *path;
1092 char *vrf_name;
1093
1094 vrf_name = rule;
1095 path = (struct bgp_path_info *)object;
1096
1097 if (strncmp(vrf_name, "n/a", VRF_NAMSIZ) == 0)
1098 return RMAP_NOMATCH;
1099
1100 if (path->extra == NULL)
1101 return RMAP_NOMATCH;
1102
1103 if (strncmp(vrf_name, vrf_id_to_name(path->extra->bgp_orig->vrf_id),
1104 VRF_NAMSIZ)
1105 == 0)
1106 return RMAP_MATCH;
1107
1108 return RMAP_NOMATCH;
1109 }
1110
1111 static void *route_match_vrl_source_vrf_compile(const char *arg)
1112 {
1113 uint8_t *vrf_name = NULL;
1114
1115 vrf_name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
1116
1117 return vrf_name;
1118 }
1119
1120 /* Free route map's compiled `route-type' value. */
1121 static void route_match_vrl_source_vrf_free(void *rule)
1122 {
1123 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
1124 }
1125
1126 static const struct route_map_rule_cmd route_match_vrl_source_vrf_cmd = {
1127 "source-vrf",
1128 route_match_vrl_source_vrf,
1129 route_match_vrl_source_vrf_compile,
1130 route_match_vrl_source_vrf_free
1131 };
1132
1133 /* `match local-preference LOCAL-PREF' */
1134
1135 /* Match function return 1 if match is success else return zero. */
1136 static enum route_map_cmd_result_t
1137 route_match_local_pref(void *rule, const struct prefix *prefix, void *object)
1138 {
1139 uint32_t *local_pref;
1140 struct bgp_path_info *path;
1141
1142 local_pref = rule;
1143 path = object;
1144
1145 if (path->attr->local_pref == *local_pref)
1146 return RMAP_MATCH;
1147 else
1148 return RMAP_NOMATCH;
1149 }
1150
1151 /*
1152 * Route map `match local-preference' match statement.
1153 * `arg' is local-pref value
1154 */
1155 static void *route_match_local_pref_compile(const char *arg)
1156 {
1157 uint32_t *local_pref;
1158 char *endptr = NULL;
1159 unsigned long tmpval;
1160
1161 /* Locpref value shoud be integer. */
1162 if (!all_digit(arg))
1163 return NULL;
1164
1165 errno = 0;
1166 tmpval = strtoul(arg, &endptr, 10);
1167 if (*endptr != '\0' || errno || tmpval > UINT32_MAX)
1168 return NULL;
1169
1170 local_pref = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint32_t));
1171
1172 *local_pref = tmpval;
1173 return local_pref;
1174 }
1175
1176 /* Free route map's compiled `match local-preference' value. */
1177 static void route_match_local_pref_free(void *rule)
1178 {
1179 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
1180 }
1181
1182 /* Route map commands for metric matching. */
1183 static const struct route_map_rule_cmd route_match_local_pref_cmd = {
1184 "local-preference",
1185 route_match_local_pref,
1186 route_match_local_pref_compile,
1187 route_match_local_pref_free
1188 };
1189
1190 /* `match metric METRIC' */
1191
1192 /* Match function return 1 if match is success else return zero. */
1193 static enum route_map_cmd_result_t
1194 route_match_metric(void *rule, const struct prefix *prefix, void *object)
1195 {
1196 struct rmap_value *rv;
1197 struct bgp_path_info *path;
1198
1199 rv = rule;
1200 path = object;
1201 return route_value_match(rv, path->attr->med);
1202 }
1203
1204 /* Route map commands for metric matching. */
1205 static const struct route_map_rule_cmd route_match_metric_cmd = {
1206 "metric",
1207 route_match_metric,
1208 route_value_compile,
1209 route_value_free,
1210 };
1211
1212 /* `match as-path ASPATH' */
1213
1214 /* Match function for as-path match. I assume given object is */
1215 static enum route_map_cmd_result_t
1216 route_match_aspath(void *rule, const struct prefix *prefix, void *object)
1217 {
1218
1219 struct as_list *as_list;
1220 struct bgp_path_info *path;
1221
1222 as_list = as_list_lookup((char *)rule);
1223 if (as_list == NULL)
1224 return RMAP_NOMATCH;
1225
1226 path = object;
1227
1228 /* Perform match. */
1229 return ((as_list_apply(as_list, path->attr->aspath) == AS_FILTER_DENY)
1230 ? RMAP_NOMATCH
1231 : RMAP_MATCH);
1232 }
1233
1234 /* Compile function for as-path match. */
1235 static void *route_match_aspath_compile(const char *arg)
1236 {
1237 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
1238 }
1239
1240 /* Compile function for as-path match. */
1241 static void route_match_aspath_free(void *rule)
1242 {
1243 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
1244 }
1245
1246 /* Route map commands for aspath matching. */
1247 static const struct route_map_rule_cmd route_match_aspath_cmd = {
1248 "as-path",
1249 route_match_aspath,
1250 route_match_aspath_compile,
1251 route_match_aspath_free
1252 };
1253
1254 /* `match community COMMUNIY' */
1255 struct rmap_community {
1256 char *name;
1257 uint32_t name_hash;
1258 int exact;
1259 };
1260
1261 /* Match function for community match. */
1262 static enum route_map_cmd_result_t
1263 route_match_community(void *rule, const struct prefix *prefix, void *object)
1264 {
1265 struct community_list *list;
1266 struct bgp_path_info *path;
1267 struct rmap_community *rcom = rule;
1268
1269 path = object;
1270 rcom = rule;
1271
1272 list = community_list_lookup(bgp_clist, rcom->name, rcom->name_hash,
1273 COMMUNITY_LIST_MASTER);
1274 if (!list)
1275 return RMAP_NOMATCH;
1276
1277 if (rcom->exact) {
1278 if (community_list_exact_match(path->attr->community, list))
1279 return RMAP_MATCH;
1280 } else {
1281 if (community_list_match(path->attr->community, list))
1282 return RMAP_MATCH;
1283 }
1284
1285 return RMAP_NOMATCH;
1286 }
1287
1288 /* Compile function for community match. */
1289 static void *route_match_community_compile(const char *arg)
1290 {
1291 struct rmap_community *rcom;
1292 int len;
1293 char *p;
1294
1295 rcom = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_community));
1296
1297 p = strchr(arg, ' ');
1298 if (p) {
1299 len = p - arg;
1300 rcom->name = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, len + 1);
1301 memcpy(rcom->name, arg, len);
1302 rcom->exact = 1;
1303 } else {
1304 rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
1305 rcom->exact = 0;
1306 }
1307
1308 rcom->name_hash = bgp_clist_hash_key(rcom->name);
1309 return rcom;
1310 }
1311
1312 /* Compile function for community match. */
1313 static void route_match_community_free(void *rule)
1314 {
1315 struct rmap_community *rcom = rule;
1316
1317 XFREE(MTYPE_ROUTE_MAP_COMPILED, rcom->name);
1318 XFREE(MTYPE_ROUTE_MAP_COMPILED, rcom);
1319 }
1320
1321 /*
1322 * In routemap processing there is a need to add the
1323 * name as a rule_key in the dependency table. Routemap
1324 * lib is unaware of rule_key when exact-match clause
1325 * is in use. routemap lib uses the compiled output to
1326 * get the rule_key value.
1327 */
1328 static void *route_match_get_community_key(void *rule)
1329 {
1330 struct rmap_community *rcom;
1331
1332 rcom = rule;
1333 return rcom->name;
1334 }
1335
1336
1337 /* Route map commands for community matching. */
1338 static const struct route_map_rule_cmd route_match_community_cmd = {
1339 "community",
1340 route_match_community,
1341 route_match_community_compile,
1342 route_match_community_free,
1343 route_match_get_community_key
1344 };
1345
1346 /* Match function for lcommunity match. */
1347 static enum route_map_cmd_result_t
1348 route_match_lcommunity(void *rule, const struct prefix *prefix, void *object)
1349 {
1350 struct community_list *list;
1351 struct bgp_path_info *path;
1352 struct rmap_community *rcom = rule;
1353
1354 path = object;
1355
1356 list = community_list_lookup(bgp_clist, rcom->name, rcom->name_hash,
1357 LARGE_COMMUNITY_LIST_MASTER);
1358 if (!list)
1359 return RMAP_NOMATCH;
1360
1361 if (rcom->exact) {
1362 if (lcommunity_list_exact_match(path->attr->lcommunity, list))
1363 return RMAP_MATCH;
1364 } else {
1365 if (lcommunity_list_match(path->attr->lcommunity, list))
1366 return RMAP_MATCH;
1367 }
1368
1369 return RMAP_NOMATCH;
1370 }
1371
1372 /* Compile function for community match. */
1373 static void *route_match_lcommunity_compile(const char *arg)
1374 {
1375 struct rmap_community *rcom;
1376 int len;
1377 char *p;
1378
1379 rcom = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_community));
1380
1381 p = strchr(arg, ' ');
1382 if (p) {
1383 len = p - arg;
1384 rcom->name = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, len + 1);
1385 memcpy(rcom->name, arg, len);
1386 rcom->exact = 1;
1387 } else {
1388 rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
1389 rcom->exact = 0;
1390 }
1391
1392 rcom->name_hash = bgp_clist_hash_key(rcom->name);
1393 return rcom;
1394 }
1395
1396 /* Compile function for community match. */
1397 static void route_match_lcommunity_free(void *rule)
1398 {
1399 struct rmap_community *rcom = rule;
1400
1401 XFREE(MTYPE_ROUTE_MAP_COMPILED, rcom->name);
1402 XFREE(MTYPE_ROUTE_MAP_COMPILED, rcom);
1403 }
1404
1405 /* Route map commands for community matching. */
1406 static const struct route_map_rule_cmd route_match_lcommunity_cmd = {
1407 "large-community",
1408 route_match_lcommunity,
1409 route_match_lcommunity_compile,
1410 route_match_lcommunity_free,
1411 route_match_get_community_key
1412 };
1413
1414
1415 /* Match function for extcommunity match. */
1416 static enum route_map_cmd_result_t
1417 route_match_ecommunity(void *rule, const struct prefix *prefix, void *object)
1418 {
1419 struct community_list *list;
1420 struct bgp_path_info *path;
1421 struct rmap_community *rcom = rule;
1422
1423 path = object;
1424
1425 list = community_list_lookup(bgp_clist, rcom->name, rcom->name_hash,
1426 EXTCOMMUNITY_LIST_MASTER);
1427 if (!list)
1428 return RMAP_NOMATCH;
1429
1430 if (ecommunity_list_match(path->attr->ecommunity, list))
1431 return RMAP_MATCH;
1432
1433 return RMAP_NOMATCH;
1434 }
1435
1436 /* Compile function for extcommunity match. */
1437 static void *route_match_ecommunity_compile(const char *arg)
1438 {
1439 struct rmap_community *rcom;
1440
1441 rcom = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_community));
1442 rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
1443 rcom->name_hash = bgp_clist_hash_key(rcom->name);
1444
1445 return rcom;
1446 }
1447
1448 /* Compile function for extcommunity match. */
1449 static void route_match_ecommunity_free(void *rule)
1450 {
1451 struct rmap_community *rcom = rule;
1452
1453 XFREE(MTYPE_ROUTE_MAP_COMPILED, rcom->name);
1454 XFREE(MTYPE_ROUTE_MAP_COMPILED, rcom);
1455 }
1456
1457 /* Route map commands for community matching. */
1458 static const struct route_map_rule_cmd route_match_ecommunity_cmd = {
1459 "extcommunity",
1460 route_match_ecommunity,
1461 route_match_ecommunity_compile,
1462 route_match_ecommunity_free
1463 };
1464
1465 /* `match nlri` and `set nlri` are replaced by `address-family ipv4`
1466 and `address-family vpnv4'. */
1467
1468 /* `match origin' */
1469 static enum route_map_cmd_result_t
1470 route_match_origin(void *rule, const struct prefix *prefix, void *object)
1471 {
1472 uint8_t *origin;
1473 struct bgp_path_info *path;
1474
1475 origin = rule;
1476 path = object;
1477
1478 if (path->attr->origin == *origin)
1479 return RMAP_MATCH;
1480
1481 return RMAP_NOMATCH;
1482 }
1483
1484 static void *route_match_origin_compile(const char *arg)
1485 {
1486 uint8_t *origin;
1487
1488 origin = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint8_t));
1489
1490 if (strcmp(arg, "igp") == 0)
1491 *origin = 0;
1492 else if (strcmp(arg, "egp") == 0)
1493 *origin = 1;
1494 else
1495 *origin = 2;
1496
1497 return origin;
1498 }
1499
1500 /* Free route map's compiled `ip address' value. */
1501 static void route_match_origin_free(void *rule)
1502 {
1503 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
1504 }
1505
1506 /* Route map commands for origin matching. */
1507 static const struct route_map_rule_cmd route_match_origin_cmd = {
1508 "origin",
1509 route_match_origin,
1510 route_match_origin_compile,
1511 route_match_origin_free
1512 };
1513
1514 /* match probability { */
1515
1516 static enum route_map_cmd_result_t
1517 route_match_probability(void *rule, const struct prefix *prefix, void *object)
1518 {
1519 long r = frr_weak_random();
1520
1521 switch (*(long *)rule) {
1522 case 0:
1523 break;
1524 case RAND_MAX:
1525 return RMAP_MATCH;
1526 default:
1527 if (r < *(long *)rule) {
1528 return RMAP_MATCH;
1529 }
1530 }
1531
1532 return RMAP_NOMATCH;
1533 }
1534
1535 static void *route_match_probability_compile(const char *arg)
1536 {
1537 long *lobule;
1538 unsigned perc;
1539
1540 perc = atoi(arg);
1541 lobule = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(long));
1542
1543 switch (perc) {
1544 case 0:
1545 *lobule = 0;
1546 break;
1547 case 100:
1548 *lobule = RAND_MAX;
1549 break;
1550 default:
1551 *lobule = RAND_MAX / 100 * perc;
1552 }
1553
1554 return lobule;
1555 }
1556
1557 static void route_match_probability_free(void *rule)
1558 {
1559 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
1560 }
1561
1562 static const struct route_map_rule_cmd route_match_probability_cmd = {
1563 "probability",
1564 route_match_probability,
1565 route_match_probability_compile,
1566 route_match_probability_free
1567 };
1568
1569 /* `match interface IFNAME' */
1570 /* Match function should return 1 if match is success else return
1571 zero. */
1572 static enum route_map_cmd_result_t
1573 route_match_interface(void *rule, const struct prefix *prefix, void *object)
1574 {
1575 struct interface *ifp;
1576 struct bgp_path_info *path;
1577
1578 path = object;
1579
1580 if (!path)
1581 return RMAP_NOMATCH;
1582
1583 ifp = if_lookup_by_name_all_vrf((char *)rule);
1584
1585 if (ifp == NULL || ifp->ifindex != path->attr->nh_ifindex)
1586 return RMAP_NOMATCH;
1587
1588 return RMAP_MATCH;
1589 }
1590
1591 /* Route map `interface' match statement. `arg' should be
1592 interface name. */
1593 static void *route_match_interface_compile(const char *arg)
1594 {
1595 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
1596 }
1597
1598 /* Free route map's compiled `interface' value. */
1599 static void route_match_interface_free(void *rule)
1600 {
1601 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
1602 }
1603
1604 /* Route map commands for ip address matching. */
1605 static const struct route_map_rule_cmd route_match_interface_cmd = {
1606 "interface",
1607 route_match_interface,
1608 route_match_interface_compile,
1609 route_match_interface_free
1610 };
1611
1612 /* } */
1613
1614 /* `set ip next-hop IP_ADDRESS' */
1615
1616 /* Match function return 1 if match is success else return zero. */
1617 static enum route_map_cmd_result_t
1618 route_match_tag(void *rule, const struct prefix *prefix, void *object)
1619 {
1620 route_tag_t *tag;
1621 struct bgp_path_info *path;
1622
1623 tag = rule;
1624 path = object;
1625
1626 return ((path->attr->tag == *tag) ? RMAP_MATCH : RMAP_NOMATCH);
1627 }
1628
1629
1630 /* Route map commands for tag matching. */
1631 static const struct route_map_rule_cmd route_match_tag_cmd = {
1632 "tag",
1633 route_match_tag,
1634 route_map_rule_tag_compile,
1635 route_map_rule_tag_free,
1636 };
1637
1638 static enum route_map_cmd_result_t
1639 route_set_srte_color(void *rule, const struct prefix *prefix, void *object)
1640 {
1641 uint32_t *srte_color = rule;
1642 struct bgp_path_info *path;
1643
1644 path = object;
1645
1646 path->attr->srte_color = *srte_color;
1647 path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_SRTE_COLOR);
1648
1649 return RMAP_OKAY;
1650 }
1651
1652 /* Route map `sr-te color' compile function */
1653 static void *route_set_srte_color_compile(const char *arg)
1654 {
1655 uint32_t *color;
1656
1657 color = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint32_t));
1658 *color = atoi(arg);
1659
1660 return color;
1661 }
1662
1663 /* Free route map's compiled `sr-te color' value. */
1664 static void route_set_srte_color_free(void *rule)
1665 {
1666 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
1667 }
1668
1669 /* Route map commands for sr-te color set. */
1670 struct route_map_rule_cmd route_set_srte_color_cmd = {
1671 "sr-te color", route_set_srte_color, route_set_srte_color_compile,
1672 route_set_srte_color_free};
1673
1674 /* Set nexthop to object. ojbect must be pointer to struct attr. */
1675 struct rmap_ip_nexthop_set {
1676 struct in_addr *address;
1677 int peer_address;
1678 int unchanged;
1679 };
1680
1681 static enum route_map_cmd_result_t
1682 route_set_ip_nexthop(void *rule, const struct prefix *prefix, void *object)
1683 {
1684 struct rmap_ip_nexthop_set *rins = rule;
1685 struct bgp_path_info *path;
1686 struct peer *peer;
1687
1688 if (prefix->family == AF_INET6)
1689 return RMAP_OKAY;
1690
1691 path = object;
1692 peer = path->peer;
1693
1694 if (rins->unchanged) {
1695 SET_FLAG(path->attr->rmap_change_flags,
1696 BATTR_RMAP_NEXTHOP_UNCHANGED);
1697 } else if (rins->peer_address) {
1698 if ((CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN)
1699 || CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IMPORT))
1700 && peer->su_remote
1701 && sockunion_family(peer->su_remote) == AF_INET) {
1702 path->attr->nexthop.s_addr =
1703 sockunion2ip(peer->su_remote);
1704 path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
1705 } else if (CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_OUT)) {
1706 /* The next hop value will be set as part of
1707 * packet rewrite. Set the flags here to indicate
1708 * that rewrite needs to be done.
1709 * Also, clear the value.
1710 */
1711 SET_FLAG(path->attr->rmap_change_flags,
1712 BATTR_RMAP_NEXTHOP_PEER_ADDRESS);
1713 path->attr->nexthop.s_addr = INADDR_ANY;
1714 }
1715 } else {
1716 /* Set next hop value. */
1717 path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
1718 path->attr->nexthop = *rins->address;
1719 SET_FLAG(path->attr->rmap_change_flags,
1720 BATTR_RMAP_IPV4_NHOP_CHANGED);
1721 /* case for MP-BGP : MPLS VPN */
1722 path->attr->mp_nexthop_global_in = *rins->address;
1723 path->attr->mp_nexthop_len = sizeof(*rins->address);
1724 }
1725
1726 return RMAP_OKAY;
1727 }
1728
1729 /* Route map `ip nexthop' compile function. Given string is converted
1730 to struct in_addr structure. */
1731 static void *route_set_ip_nexthop_compile(const char *arg)
1732 {
1733 struct rmap_ip_nexthop_set *rins;
1734 struct in_addr *address = NULL;
1735 int peer_address = 0;
1736 int unchanged = 0;
1737 int ret;
1738
1739 if (strcmp(arg, "peer-address") == 0)
1740 peer_address = 1;
1741 else if (strcmp(arg, "unchanged") == 0)
1742 unchanged = 1;
1743 else {
1744 address = XMALLOC(MTYPE_ROUTE_MAP_COMPILED,
1745 sizeof(struct in_addr));
1746 ret = inet_aton(arg, address);
1747
1748 if (ret == 0) {
1749 XFREE(MTYPE_ROUTE_MAP_COMPILED, address);
1750 return NULL;
1751 }
1752 }
1753
1754 rins = XCALLOC(MTYPE_ROUTE_MAP_COMPILED,
1755 sizeof(struct rmap_ip_nexthop_set));
1756
1757 rins->address = address;
1758 rins->peer_address = peer_address;
1759 rins->unchanged = unchanged;
1760
1761 return rins;
1762 }
1763
1764 /* Free route map's compiled `ip nexthop' value. */
1765 static void route_set_ip_nexthop_free(void *rule)
1766 {
1767 struct rmap_ip_nexthop_set *rins = rule;
1768
1769 XFREE(MTYPE_ROUTE_MAP_COMPILED, rins->address);
1770
1771 XFREE(MTYPE_ROUTE_MAP_COMPILED, rins);
1772 }
1773
1774 /* Route map commands for ip nexthop set. */
1775 static const struct route_map_rule_cmd route_set_ip_nexthop_cmd = {
1776 "ip next-hop",
1777 route_set_ip_nexthop,
1778 route_set_ip_nexthop_compile,
1779 route_set_ip_nexthop_free
1780 };
1781
1782 /* `set local-preference LOCAL_PREF' */
1783
1784 /* Set local preference. */
1785 static enum route_map_cmd_result_t
1786 route_set_local_pref(void *rule, const struct prefix *prefix, void *object)
1787 {
1788 struct rmap_value *rv;
1789 struct bgp_path_info *path;
1790 uint32_t locpref = 0;
1791
1792 /* Fetch routemap's rule information. */
1793 rv = rule;
1794 path = object;
1795
1796 /* Set local preference value. */
1797 if (path->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF))
1798 locpref = path->attr->local_pref;
1799
1800 path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF);
1801 path->attr->local_pref = route_value_adjust(rv, locpref, path->peer);
1802
1803 return RMAP_OKAY;
1804 }
1805
1806 /* Set local preference rule structure. */
1807 static const struct route_map_rule_cmd route_set_local_pref_cmd = {
1808 "local-preference",
1809 route_set_local_pref,
1810 route_value_compile,
1811 route_value_free,
1812 };
1813
1814 /* `set weight WEIGHT' */
1815
1816 /* Set weight. */
1817 static enum route_map_cmd_result_t
1818 route_set_weight(void *rule, const struct prefix *prefix, void *object)
1819 {
1820 struct rmap_value *rv;
1821 struct bgp_path_info *path;
1822
1823 /* Fetch routemap's rule information. */
1824 rv = rule;
1825 path = object;
1826
1827 /* Set weight value. */
1828 path->attr->weight = route_value_adjust(rv, 0, path->peer);
1829
1830 return RMAP_OKAY;
1831 }
1832
1833 /* Set local preference rule structure. */
1834 static const struct route_map_rule_cmd route_set_weight_cmd = {
1835 "weight",
1836 route_set_weight,
1837 route_value_compile,
1838 route_value_free,
1839 };
1840
1841 /* `set distance DISTANCE */
1842 static enum route_map_cmd_result_t
1843 route_set_distance(void *rule, const struct prefix *prefix, void *object)
1844 {
1845 struct bgp_path_info *path = object;
1846 struct rmap_value *rv = rule;
1847
1848 path->attr->distance = rv->value;
1849
1850 return RMAP_OKAY;
1851 }
1852
1853 /* set distance rule structure */
1854 static const struct route_map_rule_cmd route_set_distance_cmd = {
1855 "distance",
1856 route_set_distance,
1857 route_value_compile,
1858 route_value_free,
1859 };
1860
1861 /* `set metric METRIC' */
1862
1863 /* Set metric to attribute. */
1864 static enum route_map_cmd_result_t
1865 route_set_metric(void *rule, const struct prefix *prefix, void *object)
1866 {
1867 struct rmap_value *rv;
1868 struct bgp_path_info *path;
1869 uint32_t med = 0;
1870
1871 /* Fetch routemap's rule information. */
1872 rv = rule;
1873 path = object;
1874
1875 if (path->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC))
1876 med = path->attr->med;
1877
1878 path->attr->med = route_value_adjust(rv, med, path->peer);
1879 path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC);
1880
1881 return RMAP_OKAY;
1882 }
1883
1884 /* Set metric rule structure. */
1885 static const struct route_map_rule_cmd route_set_metric_cmd = {
1886 "metric",
1887 route_set_metric,
1888 route_value_compile,
1889 route_value_free,
1890 };
1891
1892 /* `set table (1-4294967295)' */
1893
1894 static enum route_map_cmd_result_t
1895 route_set_table_id(void *rule, const struct prefix *prefix,
1896
1897 void *object)
1898 {
1899 struct rmap_value *rv;
1900 struct bgp_path_info *path;
1901
1902 /* Fetch routemap's rule information. */
1903 rv = rule;
1904 path = object;
1905
1906 path->attr->rmap_table_id = rv->value;
1907
1908 return RMAP_OKAY;
1909 }
1910
1911 /* Set table_id rule structure. */
1912 static const struct route_map_rule_cmd route_set_table_id_cmd = {
1913 "table",
1914 route_set_table_id,
1915 route_value_compile,
1916 route_value_free
1917 };
1918
1919 /* `set as-path prepend ASPATH' */
1920
1921 /* For AS path prepend mechanism. */
1922 static enum route_map_cmd_result_t
1923 route_set_aspath_prepend(void *rule, const struct prefix *prefix, void *object)
1924 {
1925 struct aspath *aspath;
1926 struct aspath *new;
1927 struct bgp_path_info *path;
1928
1929 path = object;
1930
1931 if (path->attr->aspath->refcnt)
1932 new = aspath_dup(path->attr->aspath);
1933 else
1934 new = path->attr->aspath;
1935
1936 if ((uintptr_t)rule > 10) {
1937 aspath = rule;
1938 aspath_prepend(aspath, new);
1939 } else {
1940 as_t as = aspath_leftmost(new);
1941 if (!as)
1942 as = path->peer->as;
1943 new = aspath_add_seq_n(new, as, (uintptr_t)rule);
1944 }
1945
1946 path->attr->aspath = new;
1947
1948 return RMAP_OKAY;
1949 }
1950
1951 static void *route_set_aspath_prepend_compile(const char *arg)
1952 {
1953 unsigned int num;
1954
1955 if (sscanf(arg, "last-as %u", &num) == 1 && num > 0 && num <= 10)
1956 return (void *)(uintptr_t)num;
1957
1958 return route_aspath_compile(arg);
1959 }
1960
1961 static void route_set_aspath_prepend_free(void *rule)
1962 {
1963 if ((uintptr_t)rule > 10)
1964 route_aspath_free(rule);
1965 }
1966
1967
1968 /* Set as-path prepend rule structure. */
1969 static const struct route_map_rule_cmd route_set_aspath_prepend_cmd = {
1970 "as-path prepend",
1971 route_set_aspath_prepend,
1972 route_set_aspath_prepend_compile,
1973 route_set_aspath_prepend_free,
1974 };
1975
1976 /* `set as-path exclude ASn' */
1977
1978 /* For ASN exclude mechanism.
1979 * Iterate over ASns requested and filter them from the given AS_PATH one by
1980 * one.
1981 * Make a deep copy of existing AS_PATH, but for the first ASn only.
1982 */
1983 static enum route_map_cmd_result_t
1984 route_set_aspath_exclude(void *rule, const struct prefix *dummy, void *object)
1985 {
1986 struct aspath *new_path, *exclude_path;
1987 struct bgp_path_info *path;
1988
1989 exclude_path = rule;
1990 path = object;
1991 if (path->attr->aspath->refcnt)
1992 new_path = aspath_dup(path->attr->aspath);
1993 else
1994 new_path = path->attr->aspath;
1995 path->attr->aspath = aspath_filter_exclude(new_path, exclude_path);
1996
1997 return RMAP_OKAY;
1998 }
1999
2000 /* Set ASn exlude rule structure. */
2001 static const struct route_map_rule_cmd route_set_aspath_exclude_cmd = {
2002 "as-path exclude",
2003 route_set_aspath_exclude,
2004 route_aspath_compile,
2005 route_aspath_free,
2006 };
2007
2008 /* `set community COMMUNITY' */
2009 struct rmap_com_set {
2010 struct community *com;
2011 int additive;
2012 int none;
2013 };
2014
2015 /* For community set mechanism. */
2016 static enum route_map_cmd_result_t
2017 route_set_community(void *rule, const struct prefix *prefix, void *object)
2018 {
2019 struct rmap_com_set *rcs;
2020 struct bgp_path_info *path;
2021 struct attr *attr;
2022 struct community *new = NULL;
2023 struct community *old;
2024 struct community *merge;
2025
2026 rcs = rule;
2027 path = object;
2028 attr = path->attr;
2029 old = attr->community;
2030
2031 /* "none" case. */
2032 if (rcs->none) {
2033 attr->flag &= ~(ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES));
2034 attr->community = NULL;
2035 /* See the longer comment down below. */
2036 if (old && old->refcnt == 0)
2037 community_free(&old);
2038 return RMAP_OKAY;
2039 }
2040
2041 /* "additive" case. */
2042 if (rcs->additive && old) {
2043 merge = community_merge(community_dup(old), rcs->com);
2044
2045 new = community_uniq_sort(merge);
2046 community_free(&merge);
2047 } else
2048 new = community_dup(rcs->com);
2049
2050 /* HACK: if the old community is not intern'd,
2051 * we should free it here, or all reference to it may be
2052 * lost.
2053 * Really need to cleanup attribute caching sometime.
2054 */
2055 if (old && old->refcnt == 0)
2056 community_free(&old);
2057
2058 /* will be interned by caller if required */
2059 attr->community = new;
2060
2061 attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES);
2062
2063 return RMAP_OKAY;
2064 }
2065
2066 /* Compile function for set community. */
2067 static void *route_set_community_compile(const char *arg)
2068 {
2069 struct rmap_com_set *rcs;
2070 struct community *com = NULL;
2071 char *sp;
2072 int additive = 0;
2073 int none = 0;
2074
2075 if (strcmp(arg, "none") == 0)
2076 none = 1;
2077 else {
2078 sp = strstr(arg, "additive");
2079
2080 if (sp && sp > arg) {
2081 /* "additive" keyword is included. */
2082 additive = 1;
2083 *(sp - 1) = '\0';
2084 }
2085
2086 com = community_str2com(arg);
2087
2088 if (additive)
2089 *(sp - 1) = ' ';
2090
2091 if (!com)
2092 return NULL;
2093 }
2094
2095 rcs = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_com_set));
2096 rcs->com = com;
2097 rcs->additive = additive;
2098 rcs->none = none;
2099
2100 return rcs;
2101 }
2102
2103 /* Free function for set community. */
2104 static void route_set_community_free(void *rule)
2105 {
2106 struct rmap_com_set *rcs = rule;
2107
2108 if (rcs->com)
2109 community_free(&rcs->com);
2110 XFREE(MTYPE_ROUTE_MAP_COMPILED, rcs);
2111 }
2112
2113 /* Set community rule structure. */
2114 static const struct route_map_rule_cmd route_set_community_cmd = {
2115 "community",
2116 route_set_community,
2117 route_set_community_compile,
2118 route_set_community_free,
2119 };
2120
2121 /* `set community COMMUNITY' */
2122 struct rmap_lcom_set {
2123 struct lcommunity *lcom;
2124 int additive;
2125 int none;
2126 };
2127
2128
2129 /* For lcommunity set mechanism. */
2130 static enum route_map_cmd_result_t
2131 route_set_lcommunity(void *rule, const struct prefix *prefix, void *object)
2132 {
2133 struct rmap_lcom_set *rcs;
2134 struct bgp_path_info *path;
2135 struct attr *attr;
2136 struct lcommunity *new = NULL;
2137 struct lcommunity *old;
2138 struct lcommunity *merge;
2139
2140 rcs = rule;
2141 path = object;
2142 attr = path->attr;
2143 old = attr->lcommunity;
2144
2145 /* "none" case. */
2146 if (rcs->none) {
2147 attr->flag &= ~(ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES));
2148 attr->lcommunity = NULL;
2149
2150 /* See the longer comment down below. */
2151 if (old && old->refcnt == 0)
2152 lcommunity_free(&old);
2153 return RMAP_OKAY;
2154 }
2155
2156 if (rcs->additive && old) {
2157 merge = lcommunity_merge(lcommunity_dup(old), rcs->lcom);
2158
2159 new = lcommunity_uniq_sort(merge);
2160 lcommunity_free(&merge);
2161 } else
2162 new = lcommunity_dup(rcs->lcom);
2163
2164 /* HACK: if the old large-community is not intern'd,
2165 * we should free it here, or all reference to it may be
2166 * lost.
2167 * Really need to cleanup attribute caching sometime.
2168 */
2169 if (old && old->refcnt == 0)
2170 lcommunity_free(&old);
2171
2172 /* will be intern()'d or attr_flush()'d by bgp_update_main() */
2173 attr->lcommunity = new;
2174
2175 attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES);
2176
2177 return RMAP_OKAY;
2178 }
2179
2180 /* Compile function for set community. */
2181 static void *route_set_lcommunity_compile(const char *arg)
2182 {
2183 struct rmap_lcom_set *rcs;
2184 struct lcommunity *lcom = NULL;
2185 char *sp;
2186 int additive = 0;
2187 int none = 0;
2188
2189 if (strcmp(arg, "none") == 0)
2190 none = 1;
2191 else {
2192 sp = strstr(arg, "additive");
2193
2194 if (sp && sp > arg) {
2195 /* "additive" keyworkd is included. */
2196 additive = 1;
2197 *(sp - 1) = '\0';
2198 }
2199
2200 lcom = lcommunity_str2com(arg);
2201
2202 if (additive)
2203 *(sp - 1) = ' ';
2204
2205 if (!lcom)
2206 return NULL;
2207 }
2208
2209 rcs = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_com_set));
2210 rcs->lcom = lcom;
2211 rcs->additive = additive;
2212 rcs->none = none;
2213
2214 return rcs;
2215 }
2216
2217 /* Free function for set lcommunity. */
2218 static void route_set_lcommunity_free(void *rule)
2219 {
2220 struct rmap_lcom_set *rcs = rule;
2221
2222 if (rcs->lcom) {
2223 lcommunity_free(&rcs->lcom);
2224 }
2225 XFREE(MTYPE_ROUTE_MAP_COMPILED, rcs);
2226 }
2227
2228 /* Set community rule structure. */
2229 static const struct route_map_rule_cmd route_set_lcommunity_cmd = {
2230 "large-community",
2231 route_set_lcommunity,
2232 route_set_lcommunity_compile,
2233 route_set_lcommunity_free,
2234 };
2235
2236 /* `set large-comm-list (<1-99>|<100-500>|WORD) delete' */
2237
2238 /* For large community set mechanism. */
2239 static enum route_map_cmd_result_t
2240 route_set_lcommunity_delete(void *rule, const struct prefix *pfx, void *object)
2241 {
2242 struct community_list *list;
2243 struct lcommunity *merge;
2244 struct lcommunity *new;
2245 struct lcommunity *old;
2246 struct bgp_path_info *path;
2247 struct rmap_community *rcom = rule;
2248
2249 if (!rcom)
2250 return RMAP_OKAY;
2251
2252 path = object;
2253 list = community_list_lookup(bgp_clist, rcom->name, rcom->name_hash,
2254 LARGE_COMMUNITY_LIST_MASTER);
2255 old = path->attr->lcommunity;
2256
2257 if (list && old) {
2258 merge = lcommunity_list_match_delete(lcommunity_dup(old), list);
2259 new = lcommunity_uniq_sort(merge);
2260 lcommunity_free(&merge);
2261
2262 /* HACK: if the old community is not intern'd,
2263 * we should free it here, or all reference to it may be
2264 * lost.
2265 * Really need to cleanup attribute caching sometime.
2266 */
2267 if (old->refcnt == 0)
2268 lcommunity_free(&old);
2269
2270 if (new->size == 0) {
2271 path->attr->lcommunity = NULL;
2272 path->attr->flag &=
2273 ~ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES);
2274 lcommunity_free(&new);
2275 } else {
2276 path->attr->lcommunity = new;
2277 path->attr->flag |=
2278 ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES);
2279 }
2280 }
2281
2282 return RMAP_OKAY;
2283 }
2284
2285 /* Compile function for set lcommunity. */
2286 static void *route_set_lcommunity_delete_compile(const char *arg)
2287 {
2288 struct rmap_community *rcom;
2289 char **splits;
2290 int num;
2291
2292 frrstr_split(arg, " ", &splits, &num);
2293
2294 rcom = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_community));
2295 rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, splits[0]);
2296 rcom->name_hash = bgp_clist_hash_key(rcom->name);
2297
2298 for (int i = 0; i < num; i++)
2299 XFREE(MTYPE_TMP, splits[i]);
2300 XFREE(MTYPE_TMP, splits);
2301
2302 return rcom;
2303 }
2304
2305 /* Free function for set lcommunity. */
2306 static void route_set_lcommunity_delete_free(void *rule)
2307 {
2308 struct rmap_community *rcom = rule;
2309
2310 XFREE(MTYPE_ROUTE_MAP_COMPILED, rcom->name);
2311 XFREE(MTYPE_ROUTE_MAP_COMPILED, rcom);
2312 }
2313
2314 /* Set lcommunity rule structure. */
2315 static const struct route_map_rule_cmd route_set_lcommunity_delete_cmd = {
2316 "large-comm-list",
2317 route_set_lcommunity_delete,
2318 route_set_lcommunity_delete_compile,
2319 route_set_lcommunity_delete_free,
2320 };
2321
2322
2323 /* `set comm-list (<1-99>|<100-500>|WORD) delete' */
2324
2325 /* For community set mechanism. */
2326 static enum route_map_cmd_result_t
2327 route_set_community_delete(void *rule, const struct prefix *prefix,
2328 void *object)
2329 {
2330 struct community_list *list;
2331 struct community *merge;
2332 struct community *new;
2333 struct community *old;
2334 struct bgp_path_info *path;
2335 struct rmap_community *rcom = rule;
2336
2337 if (!rcom)
2338 return RMAP_OKAY;
2339
2340 path = object;
2341 list = community_list_lookup(bgp_clist, rcom->name, rcom->name_hash,
2342 COMMUNITY_LIST_MASTER);
2343 old = path->attr->community;
2344
2345 if (list && old) {
2346 merge = community_list_match_delete(community_dup(old), list);
2347 new = community_uniq_sort(merge);
2348 community_free(&merge);
2349
2350 /* HACK: if the old community is not intern'd,
2351 * we should free it here, or all reference to it may be
2352 * lost.
2353 * Really need to cleanup attribute caching sometime.
2354 */
2355 if (old->refcnt == 0)
2356 community_free(&old);
2357
2358 if (new->size == 0) {
2359 path->attr->community = NULL;
2360 path->attr->flag &=
2361 ~ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES);
2362 community_free(&new);
2363 } else {
2364 path->attr->community = new;
2365 path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES);
2366 }
2367 }
2368
2369 return RMAP_OKAY;
2370 }
2371
2372 /* Compile function for set community. */
2373 static void *route_set_community_delete_compile(const char *arg)
2374 {
2375 struct rmap_community *rcom;
2376 char **splits;
2377 int num;
2378
2379 frrstr_split(arg, " ", &splits, &num);
2380
2381 rcom = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_community));
2382 rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, splits[0]);
2383 rcom->name_hash = bgp_clist_hash_key(rcom->name);
2384
2385 for (int i = 0; i < num; i++)
2386 XFREE(MTYPE_TMP, splits[i]);
2387 XFREE(MTYPE_TMP, splits);
2388
2389 return rcom;
2390 }
2391
2392 /* Free function for set community. */
2393 static void route_set_community_delete_free(void *rule)
2394 {
2395 struct rmap_community *rcom = rule;
2396
2397 XFREE(MTYPE_ROUTE_MAP_COMPILED, rcom->name);
2398 XFREE(MTYPE_ROUTE_MAP_COMPILED, rcom);
2399 }
2400
2401 /* Set community rule structure. */
2402 static const struct route_map_rule_cmd route_set_community_delete_cmd = {
2403 "comm-list",
2404 route_set_community_delete,
2405 route_set_community_delete_compile,
2406 route_set_community_delete_free,
2407 };
2408
2409 /* `set extcommunity rt COMMUNITY' */
2410
2411 /* For community set mechanism. Used by _rt and _soo. */
2412 static enum route_map_cmd_result_t
2413 route_set_ecommunity(void *rule, const struct prefix *prefix, void *object)
2414 {
2415 struct ecommunity *ecom;
2416 struct ecommunity *new_ecom;
2417 struct ecommunity *old_ecom;
2418 struct bgp_path_info *path;
2419
2420 ecom = rule;
2421 path = object;
2422
2423 if (!ecom)
2424 return RMAP_OKAY;
2425
2426 /* We assume additive for Extended Community. */
2427 old_ecom = path->attr->ecommunity;
2428
2429 if (old_ecom) {
2430 new_ecom = ecommunity_merge(ecommunity_dup(old_ecom), ecom);
2431
2432 /* old_ecom->refcnt = 1 => owned elsewhere, e.g.
2433 * bgp_update_receive()
2434 * ->refcnt = 0 => set by a previous route-map
2435 * statement */
2436 if (!old_ecom->refcnt)
2437 ecommunity_free(&old_ecom);
2438 } else
2439 new_ecom = ecommunity_dup(ecom);
2440
2441 /* will be intern()'d or attr_flush()'d by bgp_update_main() */
2442 path->attr->ecommunity = new_ecom;
2443
2444 path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES);
2445
2446 return RMAP_OKAY;
2447 }
2448
2449 /* Compile function for set community. */
2450 static void *route_set_ecommunity_rt_compile(const char *arg)
2451 {
2452 struct ecommunity *ecom;
2453
2454 ecom = ecommunity_str2com(arg, ECOMMUNITY_ROUTE_TARGET, 0);
2455 if (!ecom)
2456 return NULL;
2457 return ecommunity_intern(ecom);
2458 }
2459
2460 /* Free function for set community. Used by _rt and _soo */
2461 static void route_set_ecommunity_free(void *rule)
2462 {
2463 struct ecommunity *ecom = rule;
2464 ecommunity_unintern(&ecom);
2465 }
2466
2467 /* Set community rule structure. */
2468 static const struct route_map_rule_cmd route_set_ecommunity_rt_cmd = {
2469 "extcommunity rt",
2470 route_set_ecommunity,
2471 route_set_ecommunity_rt_compile,
2472 route_set_ecommunity_free,
2473 };
2474
2475 /* `set extcommunity soo COMMUNITY' */
2476
2477 /* Compile function for set community. */
2478 static void *route_set_ecommunity_soo_compile(const char *arg)
2479 {
2480 struct ecommunity *ecom;
2481
2482 ecom = ecommunity_str2com(arg, ECOMMUNITY_SITE_ORIGIN, 0);
2483 if (!ecom)
2484 return NULL;
2485
2486 return ecommunity_intern(ecom);
2487 }
2488
2489 /* Set community rule structure. */
2490 static const struct route_map_rule_cmd route_set_ecommunity_soo_cmd = {
2491 "extcommunity soo",
2492 route_set_ecommunity,
2493 route_set_ecommunity_soo_compile,
2494 route_set_ecommunity_free,
2495 };
2496
2497 /* `set extcommunity bandwidth' */
2498
2499 struct rmap_ecomm_lb_set {
2500 uint8_t lb_type;
2501 #define RMAP_ECOMM_LB_SET_VALUE 1
2502 #define RMAP_ECOMM_LB_SET_CUMUL 2
2503 #define RMAP_ECOMM_LB_SET_NUM_MPATH 3
2504 bool non_trans;
2505 uint32_t bw;
2506 };
2507
2508 static enum route_map_cmd_result_t
2509 route_set_ecommunity_lb(void *rule, const struct prefix *prefix, void *object)
2510 {
2511 struct rmap_ecomm_lb_set *rels = rule;
2512 struct bgp_path_info *path;
2513 struct peer *peer;
2514 struct ecommunity ecom_lb = {0};
2515 struct ecommunity_val lb_eval;
2516 uint32_t bw_bytes = 0;
2517 uint16_t mpath_count = 0;
2518 struct ecommunity *new_ecom;
2519 struct ecommunity *old_ecom;
2520 as_t as;
2521
2522 path = object;
2523 peer = path->peer;
2524 if (!peer || !peer->bgp)
2525 return RMAP_ERROR;
2526
2527 /* Build link bandwidth extended community */
2528 as = (peer->bgp->as > BGP_AS_MAX) ? BGP_AS_TRANS : peer->bgp->as;
2529 if (rels->lb_type == RMAP_ECOMM_LB_SET_VALUE) {
2530 bw_bytes = ((uint64_t)rels->bw * 1000 * 1000) / 8;
2531 } else if (rels->lb_type == RMAP_ECOMM_LB_SET_CUMUL) {
2532 /* process this only for the best path. */
2533 if (!CHECK_FLAG(path->flags, BGP_PATH_SELECTED))
2534 return RMAP_OKAY;
2535
2536 bw_bytes = (uint32_t)bgp_path_info_mpath_cumbw(path);
2537 if (!bw_bytes)
2538 return RMAP_OKAY;
2539
2540 } else if (rels->lb_type == RMAP_ECOMM_LB_SET_NUM_MPATH) {
2541
2542 /* process this only for the best path. */
2543 if (!CHECK_FLAG(path->flags, BGP_PATH_SELECTED))
2544 return RMAP_OKAY;
2545
2546 bw_bytes = ((uint64_t)peer->bgp->lb_ref_bw * 1000 * 1000) / 8;
2547 mpath_count = bgp_path_info_mpath_count(path) + 1;
2548 bw_bytes *= mpath_count;
2549 }
2550
2551 encode_lb_extcomm(as, bw_bytes, rels->non_trans, &lb_eval);
2552
2553 /* add to route or merge with existing */
2554 old_ecom = path->attr->ecommunity;
2555 if (old_ecom) {
2556 new_ecom = ecommunity_dup(old_ecom);
2557 ecommunity_add_val(new_ecom, &lb_eval, true, true);
2558 if (!old_ecom->refcnt)
2559 ecommunity_free(&old_ecom);
2560 } else {
2561 ecom_lb.size = 1;
2562 ecom_lb.unit_size = ECOMMUNITY_SIZE;
2563 ecom_lb.val = (uint8_t *)lb_eval.val;
2564 new_ecom = ecommunity_dup(&ecom_lb);
2565 }
2566
2567 /* new_ecom will be intern()'d or attr_flush()'d in call stack */
2568 path->attr->ecommunity = new_ecom;
2569 path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES);
2570
2571 /* Mark that route-map has set link bandwidth; used in attribute
2572 * setting decisions.
2573 */
2574 SET_FLAG(path->attr->rmap_change_flags, BATTR_RMAP_LINK_BW_SET);
2575
2576 return RMAP_OKAY;
2577 }
2578
2579 static void *route_set_ecommunity_lb_compile(const char *arg)
2580 {
2581 struct rmap_ecomm_lb_set *rels;
2582 uint8_t lb_type;
2583 uint32_t bw = 0;
2584 char bw_str[40] = {0};
2585 char *p, *str;
2586 bool non_trans = false;
2587
2588 str = (char *)arg;
2589 p = strchr(arg, ' ');
2590 if (p) {
2591 int len;
2592
2593 len = p - arg;
2594 memcpy(bw_str, arg, len);
2595 non_trans = true;
2596 str = bw_str;
2597 }
2598
2599 if (strcmp(str, "cumulative") == 0)
2600 lb_type = RMAP_ECOMM_LB_SET_CUMUL;
2601 else if (strcmp(str, "num-multipaths") == 0)
2602 lb_type = RMAP_ECOMM_LB_SET_NUM_MPATH;
2603 else {
2604 char *end = NULL;
2605
2606 bw = strtoul(str, &end, 10);
2607 if (*end != '\0')
2608 return NULL;
2609 lb_type = RMAP_ECOMM_LB_SET_VALUE;
2610 }
2611
2612 rels = XCALLOC(MTYPE_ROUTE_MAP_COMPILED,
2613 sizeof(struct rmap_ecomm_lb_set));
2614 rels->lb_type = lb_type;
2615 rels->bw = bw;
2616 rels->non_trans = non_trans;
2617
2618 return rels;
2619 }
2620
2621 static void route_set_ecommunity_lb_free(void *rule)
2622 {
2623 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
2624 }
2625
2626 /* Set community rule structure. */
2627 struct route_map_rule_cmd route_set_ecommunity_lb_cmd = {
2628 "extcommunity bandwidth",
2629 route_set_ecommunity_lb,
2630 route_set_ecommunity_lb_compile,
2631 route_set_ecommunity_lb_free,
2632 };
2633
2634 /* `set origin ORIGIN' */
2635
2636 /* For origin set. */
2637 static enum route_map_cmd_result_t
2638 route_set_origin(void *rule, const struct prefix *prefix, void *object)
2639 {
2640 uint8_t *origin;
2641 struct bgp_path_info *path;
2642
2643 origin = rule;
2644 path = object;
2645
2646 path->attr->origin = *origin;
2647
2648 return RMAP_OKAY;
2649 }
2650
2651 /* Compile function for origin set. */
2652 static void *route_set_origin_compile(const char *arg)
2653 {
2654 uint8_t *origin;
2655
2656 origin = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint8_t));
2657
2658 if (strcmp(arg, "igp") == 0)
2659 *origin = 0;
2660 else if (strcmp(arg, "egp") == 0)
2661 *origin = 1;
2662 else
2663 *origin = 2;
2664
2665 return origin;
2666 }
2667
2668 /* Compile function for origin set. */
2669 static void route_set_origin_free(void *rule)
2670 {
2671 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
2672 }
2673
2674 /* Set origin rule structure. */
2675 static const struct route_map_rule_cmd route_set_origin_cmd = {
2676 "origin",
2677 route_set_origin,
2678 route_set_origin_compile,
2679 route_set_origin_free,
2680 };
2681
2682 /* `set atomic-aggregate' */
2683
2684 /* For atomic aggregate set. */
2685 static enum route_map_cmd_result_t
2686 route_set_atomic_aggregate(void *rule, const struct prefix *pfx, void *object)
2687 {
2688 struct bgp_path_info *path;
2689
2690 path = object;
2691 path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE);
2692
2693 return RMAP_OKAY;
2694 }
2695
2696 /* Compile function for atomic aggregate. */
2697 static void *route_set_atomic_aggregate_compile(const char *arg)
2698 {
2699 return (void *)1;
2700 }
2701
2702 /* Compile function for atomic aggregate. */
2703 static void route_set_atomic_aggregate_free(void *rule)
2704 {
2705 return;
2706 }
2707
2708 /* Set atomic aggregate rule structure. */
2709 static const struct route_map_rule_cmd route_set_atomic_aggregate_cmd = {
2710 "atomic-aggregate",
2711 route_set_atomic_aggregate,
2712 route_set_atomic_aggregate_compile,
2713 route_set_atomic_aggregate_free,
2714 };
2715
2716 /* `set aggregator as AS A.B.C.D' */
2717 struct aggregator {
2718 as_t as;
2719 struct in_addr address;
2720 };
2721
2722 static enum route_map_cmd_result_t
2723 route_set_aggregator_as(void *rule, const struct prefix *prefix, void *object)
2724 {
2725 struct bgp_path_info *path;
2726 struct aggregator *aggregator;
2727
2728 path = object;
2729 aggregator = rule;
2730
2731 path->attr->aggregator_as = aggregator->as;
2732 path->attr->aggregator_addr = aggregator->address;
2733 path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR);
2734
2735 return RMAP_OKAY;
2736 }
2737
2738 static void *route_set_aggregator_as_compile(const char *arg)
2739 {
2740 struct aggregator *aggregator;
2741 char as[10];
2742 char address[20];
2743 int ret;
2744
2745 aggregator =
2746 XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct aggregator));
2747 if (sscanf(arg, "%s %s", as, address) != 2) {
2748 XFREE(MTYPE_ROUTE_MAP_COMPILED, aggregator);
2749 return NULL;
2750 }
2751
2752 aggregator->as = strtoul(as, NULL, 10);
2753 ret = inet_aton(address, &aggregator->address);
2754 if (ret == 0) {
2755 XFREE(MTYPE_ROUTE_MAP_COMPILED, aggregator);
2756 return NULL;
2757 }
2758 return aggregator;
2759 }
2760
2761 static void route_set_aggregator_as_free(void *rule)
2762 {
2763 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
2764 }
2765
2766 static const struct route_map_rule_cmd route_set_aggregator_as_cmd = {
2767 "aggregator as",
2768 route_set_aggregator_as,
2769 route_set_aggregator_as_compile,
2770 route_set_aggregator_as_free,
2771 };
2772
2773 /* Set tag to object. object must be pointer to struct bgp_path_info */
2774 static enum route_map_cmd_result_t
2775 route_set_tag(void *rule, const struct prefix *prefix, void *object)
2776 {
2777 route_tag_t *tag;
2778 struct bgp_path_info *path;
2779
2780 tag = rule;
2781 path = object;
2782
2783 /* Set tag value */
2784 path->attr->tag = *tag;
2785
2786 return RMAP_OKAY;
2787 }
2788
2789 /* Route map commands for tag set. */
2790 static const struct route_map_rule_cmd route_set_tag_cmd = {
2791 "tag",
2792 route_set_tag,
2793 route_map_rule_tag_compile,
2794 route_map_rule_tag_free,
2795 };
2796
2797 /* Set label-index to object. object must be pointer to struct bgp_path_info */
2798 static enum route_map_cmd_result_t
2799 route_set_label_index(void *rule, const struct prefix *prefix, void *object)
2800 {
2801 struct rmap_value *rv;
2802 struct bgp_path_info *path;
2803 uint32_t label_index;
2804
2805 /* Fetch routemap's rule information. */
2806 rv = rule;
2807 path = object;
2808
2809 /* Set label-index value. */
2810 label_index = rv->value;
2811 if (label_index) {
2812 path->attr->label_index = label_index;
2813 path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID);
2814 }
2815
2816 return RMAP_OKAY;
2817 }
2818
2819 /* Route map commands for label-index set. */
2820 static const struct route_map_rule_cmd route_set_label_index_cmd = {
2821 "label-index",
2822 route_set_label_index,
2823 route_value_compile,
2824 route_value_free,
2825 };
2826
2827 /* `match ipv6 address IP_ACCESS_LIST' */
2828
2829 static enum route_map_cmd_result_t
2830 route_match_ipv6_address(void *rule, const struct prefix *prefix, void *object)
2831 {
2832 struct access_list *alist;
2833
2834 if (prefix->family == AF_INET6) {
2835 alist = access_list_lookup(AFI_IP6, (char *)rule);
2836 if (alist == NULL)
2837 return RMAP_NOMATCH;
2838
2839 return (access_list_apply(alist, prefix) == FILTER_DENY
2840 ? RMAP_NOMATCH
2841 : RMAP_MATCH);
2842 }
2843 return RMAP_NOMATCH;
2844 }
2845
2846 static void *route_match_ipv6_address_compile(const char *arg)
2847 {
2848 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
2849 }
2850
2851 static void route_match_ipv6_address_free(void *rule)
2852 {
2853 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
2854 }
2855
2856 /* Route map commands for ip address matching. */
2857 static const struct route_map_rule_cmd route_match_ipv6_address_cmd = {
2858 "ipv6 address",
2859 route_match_ipv6_address,
2860 route_match_ipv6_address_compile,
2861 route_match_ipv6_address_free
2862 };
2863
2864 /* `match ipv6 next-hop IP_ADDRESS' */
2865
2866 static enum route_map_cmd_result_t
2867 route_match_ipv6_next_hop(void *rule, const struct prefix *prefix, void *object)
2868 {
2869 struct in6_addr *addr = rule;
2870 struct bgp_path_info *path;
2871
2872 path = object;
2873
2874 if (IPV6_ADDR_SAME(&path->attr->mp_nexthop_global, addr))
2875 return RMAP_MATCH;
2876
2877 if (path->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
2878 && IPV6_ADDR_SAME(&path->attr->mp_nexthop_local, rule))
2879 return RMAP_MATCH;
2880
2881 return RMAP_NOMATCH;
2882 }
2883
2884 static void *route_match_ipv6_next_hop_compile(const char *arg)
2885 {
2886 struct in6_addr *address;
2887 int ret;
2888
2889 address = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct in6_addr));
2890
2891 ret = inet_pton(AF_INET6, arg, address);
2892 if (!ret) {
2893 XFREE(MTYPE_ROUTE_MAP_COMPILED, address);
2894 return NULL;
2895 }
2896
2897 return address;
2898 }
2899
2900 static void route_match_ipv6_next_hop_free(void *rule)
2901 {
2902 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
2903 }
2904
2905 static const struct route_map_rule_cmd route_match_ipv6_next_hop_cmd = {
2906 "ipv6 next-hop",
2907 route_match_ipv6_next_hop,
2908 route_match_ipv6_next_hop_compile,
2909 route_match_ipv6_next_hop_free
2910 };
2911
2912 /* `match ip next-hop IP_ADDRESS' */
2913
2914 static enum route_map_cmd_result_t
2915 route_match_ipv4_next_hop(void *rule, const struct prefix *prefix, void *object)
2916 {
2917 struct in_addr *addr = rule;
2918 struct bgp_path_info *path;
2919
2920 path = object;
2921
2922 if (path->attr->nexthop.s_addr == addr->s_addr
2923 || (path->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV4
2924 && IPV4_ADDR_SAME(&path->attr->mp_nexthop_global_in, addr)))
2925 return RMAP_MATCH;
2926
2927 return RMAP_NOMATCH;
2928 }
2929
2930 static void *route_match_ipv4_next_hop_compile(const char *arg)
2931 {
2932 struct in_addr *address;
2933 int ret;
2934
2935 address = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct in_addr));
2936
2937 ret = inet_pton(AF_INET, arg, address);
2938 if (!ret) {
2939 XFREE(MTYPE_ROUTE_MAP_COMPILED, address);
2940 return NULL;
2941 }
2942
2943 return address;
2944 }
2945
2946 static void route_match_ipv4_next_hop_free(void *rule)
2947 {
2948 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
2949 }
2950
2951 static const struct route_map_rule_cmd route_match_ipv4_next_hop_cmd = {
2952 "ip next-hop address",
2953 route_match_ipv4_next_hop,
2954 route_match_ipv4_next_hop_compile,
2955 route_match_ipv4_next_hop_free
2956 };
2957
2958 /* `match ipv6 address prefix-list PREFIX_LIST' */
2959
2960 static enum route_map_cmd_result_t
2961 route_match_ipv6_address_prefix_list(void *rule, const struct prefix *prefix,
2962 void *object)
2963 {
2964 return route_match_address_prefix_list(rule, AFI_IP6, prefix, object);
2965 }
2966
2967 static void *route_match_ipv6_address_prefix_list_compile(const char *arg)
2968 {
2969 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
2970 }
2971
2972 static void route_match_ipv6_address_prefix_list_free(void *rule)
2973 {
2974 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
2975 }
2976
2977 static const struct route_map_rule_cmd
2978 route_match_ipv6_address_prefix_list_cmd = {
2979 "ipv6 address prefix-list",
2980 route_match_ipv6_address_prefix_list,
2981 route_match_ipv6_address_prefix_list_compile,
2982 route_match_ipv6_address_prefix_list_free
2983 };
2984
2985 /* `match ipv6 next-hop type <TYPE>' */
2986
2987 static enum route_map_cmd_result_t
2988 route_match_ipv6_next_hop_type(void *rule, const struct prefix *prefix,
2989 void *object)
2990 {
2991 struct bgp_path_info *path;
2992 struct in6_addr *addr = rule;
2993
2994 if (prefix->family == AF_INET6) {
2995 path = (struct bgp_path_info *)object;
2996 if (!path)
2997 return RMAP_NOMATCH;
2998
2999 if (IPV6_ADDR_SAME(&path->attr->mp_nexthop_global, addr)
3000 && !path->attr->nh_ifindex)
3001 return RMAP_MATCH;
3002 }
3003
3004 return RMAP_NOMATCH;
3005 }
3006
3007 static void *route_match_ipv6_next_hop_type_compile(const char *arg)
3008 {
3009 struct in6_addr *address;
3010 int ret;
3011
3012 address = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct in6_addr));
3013
3014 ret = inet_pton(AF_INET6, "::0", address);
3015 if (!ret) {
3016 XFREE(MTYPE_ROUTE_MAP_COMPILED, address);
3017 return NULL;
3018 }
3019
3020 return address;
3021 }
3022
3023 static void route_match_ipv6_next_hop_type_free(void *rule)
3024 {
3025 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
3026 }
3027
3028 static const struct route_map_rule_cmd
3029 route_match_ipv6_next_hop_type_cmd = {
3030 "ipv6 next-hop type",
3031 route_match_ipv6_next_hop_type,
3032 route_match_ipv6_next_hop_type_compile,
3033 route_match_ipv6_next_hop_type_free
3034 };
3035
3036 /* `set ipv6 nexthop global IP_ADDRESS' */
3037
3038 /* Set nexthop to object. ojbect must be pointer to struct attr. */
3039 static enum route_map_cmd_result_t
3040 route_set_ipv6_nexthop_global(void *rule, const struct prefix *p, void *object)
3041 {
3042 struct in6_addr *address;
3043 struct bgp_path_info *path;
3044
3045 /* Fetch routemap's rule information. */
3046 address = rule;
3047 path = object;
3048
3049 /* Set next hop value. */
3050 path->attr->mp_nexthop_global = *address;
3051
3052 /* Set nexthop length. */
3053 if (path->attr->mp_nexthop_len == 0)
3054 path->attr->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL;
3055
3056 SET_FLAG(path->attr->rmap_change_flags,
3057 BATTR_RMAP_IPV6_GLOBAL_NHOP_CHANGED);
3058
3059 return RMAP_OKAY;
3060 }
3061
3062 /* Route map `ip next-hop' compile function. Given string is converted
3063 to struct in_addr structure. */
3064 static void *route_set_ipv6_nexthop_global_compile(const char *arg)
3065 {
3066 int ret;
3067 struct in6_addr *address;
3068
3069 address = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct in6_addr));
3070
3071 ret = inet_pton(AF_INET6, arg, address);
3072
3073 if (ret == 0) {
3074 XFREE(MTYPE_ROUTE_MAP_COMPILED, address);
3075 return NULL;
3076 }
3077
3078 return address;
3079 }
3080
3081 /* Free route map's compiled `ip next-hop' value. */
3082 static void route_set_ipv6_nexthop_global_free(void *rule)
3083 {
3084 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
3085 }
3086
3087 /* Route map commands for ip nexthop set. */
3088 static const struct route_map_rule_cmd
3089 route_set_ipv6_nexthop_global_cmd = {
3090 "ipv6 next-hop global",
3091 route_set_ipv6_nexthop_global,
3092 route_set_ipv6_nexthop_global_compile,
3093 route_set_ipv6_nexthop_global_free
3094 };
3095
3096 /* Set next-hop preference value. */
3097 static enum route_map_cmd_result_t
3098 route_set_ipv6_nexthop_prefer_global(void *rule, const struct prefix *prefix,
3099 void *object)
3100 {
3101 struct bgp_path_info *path;
3102 struct peer *peer;
3103
3104 /* Fetch routemap's rule information. */
3105 path = object;
3106 peer = path->peer;
3107
3108 if (CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN)
3109 || CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IMPORT)) {
3110 /* Set next hop preference to global */
3111 path->attr->mp_nexthop_prefer_global = true;
3112 SET_FLAG(path->attr->rmap_change_flags,
3113 BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED);
3114 } else {
3115 path->attr->mp_nexthop_prefer_global = false;
3116 SET_FLAG(path->attr->rmap_change_flags,
3117 BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED);
3118 }
3119
3120 return RMAP_OKAY;
3121 }
3122
3123 static void *route_set_ipv6_nexthop_prefer_global_compile(const char *arg)
3124 {
3125 int *rins = NULL;
3126
3127 rins = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(int));
3128 *rins = 1;
3129
3130 return rins;
3131 }
3132
3133 /* Free route map's compiled `ip next-hop' value. */
3134 static void route_set_ipv6_nexthop_prefer_global_free(void *rule)
3135 {
3136 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
3137 }
3138
3139 /* Route map commands for ip nexthop set preferred. */
3140 static const struct route_map_rule_cmd
3141 route_set_ipv6_nexthop_prefer_global_cmd = {
3142 "ipv6 next-hop prefer-global",
3143 route_set_ipv6_nexthop_prefer_global,
3144 route_set_ipv6_nexthop_prefer_global_compile,
3145 route_set_ipv6_nexthop_prefer_global_free
3146 };
3147
3148 /* `set ipv6 nexthop local IP_ADDRESS' */
3149
3150 /* Set nexthop to object. ojbect must be pointer to struct attr. */
3151 static enum route_map_cmd_result_t
3152 route_set_ipv6_nexthop_local(void *rule, const struct prefix *p, void *object)
3153 {
3154 struct in6_addr *address;
3155 struct bgp_path_info *path;
3156
3157 /* Fetch routemap's rule information. */
3158 address = rule;
3159 path = object;
3160
3161 /* Set next hop value. */
3162 path->attr->mp_nexthop_local = *address;
3163
3164 /* Set nexthop length. */
3165 if (path->attr->mp_nexthop_len != BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
3166 path->attr->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL;
3167
3168 SET_FLAG(path->attr->rmap_change_flags,
3169 BATTR_RMAP_IPV6_LL_NHOP_CHANGED);
3170
3171 return RMAP_OKAY;
3172 }
3173
3174 /* Route map `ip nexthop' compile function. Given string is converted
3175 to struct in_addr structure. */
3176 static void *route_set_ipv6_nexthop_local_compile(const char *arg)
3177 {
3178 int ret;
3179 struct in6_addr *address;
3180
3181 address = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct in6_addr));
3182
3183 ret = inet_pton(AF_INET6, arg, address);
3184
3185 if (ret == 0) {
3186 XFREE(MTYPE_ROUTE_MAP_COMPILED, address);
3187 return NULL;
3188 }
3189
3190 return address;
3191 }
3192
3193 /* Free route map's compiled `ip nexthop' value. */
3194 static void route_set_ipv6_nexthop_local_free(void *rule)
3195 {
3196 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
3197 }
3198
3199 /* Route map commands for ip nexthop set. */
3200 static const struct route_map_rule_cmd
3201 route_set_ipv6_nexthop_local_cmd = {
3202 "ipv6 next-hop local",
3203 route_set_ipv6_nexthop_local,
3204 route_set_ipv6_nexthop_local_compile,
3205 route_set_ipv6_nexthop_local_free
3206 };
3207
3208 /* `set ipv6 nexthop peer-address' */
3209
3210 /* Set nexthop to object. ojbect must be pointer to struct attr. */
3211 static enum route_map_cmd_result_t
3212 route_set_ipv6_nexthop_peer(void *rule, const struct prefix *pfx, void *object)
3213 {
3214 struct in6_addr peer_address;
3215 struct bgp_path_info *path;
3216 struct peer *peer;
3217
3218 /* Fetch routemap's rule information. */
3219 path = object;
3220 peer = path->peer;
3221
3222 if ((CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN)
3223 || CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IMPORT))
3224 && peer->su_remote
3225 && sockunion_family(peer->su_remote) == AF_INET6) {
3226 peer_address = peer->su_remote->sin6.sin6_addr;
3227 /* Set next hop value and length in attribute. */
3228 if (IN6_IS_ADDR_LINKLOCAL(&peer_address)) {
3229 path->attr->mp_nexthop_local = peer_address;
3230 if (path->attr->mp_nexthop_len
3231 != BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
3232 path->attr->mp_nexthop_len =
3233 BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL;
3234 } else {
3235 path->attr->mp_nexthop_global = peer_address;
3236 if (path->attr->mp_nexthop_len == 0)
3237 path->attr->mp_nexthop_len =
3238 BGP_ATTR_NHLEN_IPV6_GLOBAL;
3239 }
3240
3241 } else if (CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_OUT)) {
3242 /* The next hop value will be set as part of packet
3243 * rewrite.
3244 * Set the flags here to indicate that rewrite needs to
3245 * be done.
3246 * Also, clear the value - we clear both global and
3247 * link-local
3248 * nexthops, whether we send one or both is determined
3249 * elsewhere.
3250 */
3251 SET_FLAG(path->attr->rmap_change_flags,
3252 BATTR_RMAP_NEXTHOP_PEER_ADDRESS);
3253 /* clear next hop value. */
3254 memset(&(path->attr->mp_nexthop_global), 0,
3255 sizeof(struct in6_addr));
3256 memset(&(path->attr->mp_nexthop_local), 0,
3257 sizeof(struct in6_addr));
3258 }
3259
3260 return RMAP_OKAY;
3261 }
3262
3263 /* Route map `ip next-hop' compile function. Given string is converted
3264 to struct in_addr structure. */
3265 static void *route_set_ipv6_nexthop_peer_compile(const char *arg)
3266 {
3267 int *rins = NULL;
3268
3269 rins = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(int));
3270 *rins = 1;
3271
3272 return rins;
3273 }
3274
3275 /* Free route map's compiled `ip next-hop' value. */
3276 static void route_set_ipv6_nexthop_peer_free(void *rule)
3277 {
3278 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
3279 }
3280
3281 /* Route map commands for ip nexthop set. */
3282 static const struct route_map_rule_cmd route_set_ipv6_nexthop_peer_cmd = {
3283 "ipv6 next-hop peer-address",
3284 route_set_ipv6_nexthop_peer,
3285 route_set_ipv6_nexthop_peer_compile,
3286 route_set_ipv6_nexthop_peer_free
3287 };
3288
3289 /* `set ipv4 vpn next-hop A.B.C.D' */
3290
3291 static enum route_map_cmd_result_t
3292 route_set_vpnv4_nexthop(void *rule, const struct prefix *prefix, void *object)
3293 {
3294 struct in_addr *address;
3295 struct bgp_path_info *path;
3296
3297 /* Fetch routemap's rule information. */
3298 address = rule;
3299 path = object;
3300
3301 /* Set next hop value. */
3302 path->attr->mp_nexthop_global_in = *address;
3303 path->attr->mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
3304
3305 return RMAP_OKAY;
3306 }
3307
3308 static void *route_set_vpnv4_nexthop_compile(const char *arg)
3309 {
3310 int ret;
3311 struct in_addr *address;
3312
3313 address = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct in_addr));
3314
3315 ret = inet_aton(arg, address);
3316
3317 if (ret == 0) {
3318 XFREE(MTYPE_ROUTE_MAP_COMPILED, address);
3319 return NULL;
3320 }
3321
3322 return address;
3323 }
3324
3325 /* `set ipv6 vpn next-hop A.B.C.D' */
3326
3327 static enum route_map_cmd_result_t
3328 route_set_vpnv6_nexthop(void *rule, const struct prefix *prefix, void *object)
3329 {
3330 struct in6_addr *address;
3331 struct bgp_path_info *path;
3332
3333 /* Fetch routemap's rule information. */
3334 address = rule;
3335 path = object;
3336
3337 /* Set next hop value. */
3338 memcpy(&path->attr->mp_nexthop_global, address,
3339 sizeof(struct in6_addr));
3340 path->attr->mp_nexthop_len = BGP_ATTR_NHLEN_VPNV6_GLOBAL;
3341
3342 return RMAP_OKAY;
3343 }
3344
3345 static void *route_set_vpnv6_nexthop_compile(const char *arg)
3346 {
3347 int ret;
3348 struct in6_addr *address;
3349
3350 address = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct in6_addr));
3351 ret = inet_pton(AF_INET6, arg, address);
3352
3353 if (ret == 0) {
3354 XFREE(MTYPE_ROUTE_MAP_COMPILED, address);
3355 return NULL;
3356 }
3357
3358 return address;
3359 }
3360
3361 static void route_set_vpn_nexthop_free(void *rule)
3362 {
3363 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
3364 }
3365
3366 /* Route map commands for ipv4 next-hop set. */
3367 static const struct route_map_rule_cmd route_set_vpnv4_nexthop_cmd = {
3368 "ipv4 vpn next-hop",
3369 route_set_vpnv4_nexthop,
3370 route_set_vpnv4_nexthop_compile,
3371 route_set_vpn_nexthop_free
3372 };
3373
3374 /* Route map commands for ipv6 next-hop set. */
3375 static const struct route_map_rule_cmd route_set_vpnv6_nexthop_cmd = {
3376 "ipv6 vpn next-hop",
3377 route_set_vpnv6_nexthop,
3378 route_set_vpnv6_nexthop_compile,
3379 route_set_vpn_nexthop_free
3380 };
3381
3382 /* `set originator-id' */
3383
3384 /* For origin set. */
3385 static enum route_map_cmd_result_t
3386 route_set_originator_id(void *rule, const struct prefix *prefix, void *object)
3387 {
3388 struct in_addr *address;
3389 struct bgp_path_info *path;
3390
3391 address = rule;
3392 path = object;
3393
3394 path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID);
3395 path->attr->originator_id = *address;
3396
3397 return RMAP_OKAY;
3398 }
3399
3400 /* Compile function for originator-id set. */
3401 static void *route_set_originator_id_compile(const char *arg)
3402 {
3403 int ret;
3404 struct in_addr *address;
3405
3406 address = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct in_addr));
3407
3408 ret = inet_aton(arg, address);
3409
3410 if (ret == 0) {
3411 XFREE(MTYPE_ROUTE_MAP_COMPILED, address);
3412 return NULL;
3413 }
3414
3415 return address;
3416 }
3417
3418 /* Compile function for originator_id set. */
3419 static void route_set_originator_id_free(void *rule)
3420 {
3421 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
3422 }
3423
3424 /* Set originator-id rule structure. */
3425 static const struct route_map_rule_cmd route_set_originator_id_cmd = {
3426 "originator-id",
3427 route_set_originator_id,
3428 route_set_originator_id_compile,
3429 route_set_originator_id_free,
3430 };
3431
3432 /* Add bgp route map rule. */
3433 static int bgp_route_match_add(struct vty *vty, const char *command,
3434 const char *arg, route_map_event_t type)
3435 {
3436 VTY_DECLVAR_CONTEXT(route_map_index, index);
3437 int retval = CMD_SUCCESS;
3438 enum rmap_compile_rets ret;
3439
3440 ret = route_map_add_match(index, command, arg, type);
3441 switch (ret) {
3442 case RMAP_RULE_MISSING:
3443 vty_out(vty, "%% BGP Can't find rule.\n");
3444 retval = CMD_WARNING_CONFIG_FAILED;
3445 break;
3446 case RMAP_COMPILE_ERROR:
3447 vty_out(vty, "%% BGP Argument is malformed.\n");
3448 retval = CMD_WARNING_CONFIG_FAILED;
3449 break;
3450 case RMAP_COMPILE_SUCCESS:
3451 /*
3452 * Intentionally doing nothing here.
3453 */
3454 break;
3455 }
3456
3457 return retval;
3458 }
3459
3460 /* Delete bgp route map rule. */
3461 static int bgp_route_match_delete(struct vty *vty, const char *command,
3462 const char *arg, route_map_event_t type)
3463 {
3464 VTY_DECLVAR_CONTEXT(route_map_index, index);
3465 enum rmap_compile_rets ret;
3466 int retval = CMD_SUCCESS;
3467 char *dep_name = NULL;
3468 const char *tmpstr;
3469 char *rmap_name = NULL;
3470
3471 if (type != RMAP_EVENT_MATCH_DELETED) {
3472 /* ignore the mundane, the types without any dependency */
3473 if (arg == NULL) {
3474 if ((tmpstr = route_map_get_match_arg(index, command))
3475 != NULL)
3476 dep_name =
3477 XSTRDUP(MTYPE_ROUTE_MAP_RULE, tmpstr);
3478 } else {
3479 dep_name = XSTRDUP(MTYPE_ROUTE_MAP_RULE, arg);
3480 }
3481 rmap_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, index->map->name);
3482 }
3483
3484 ret = route_map_delete_match(index, command, dep_name, type);
3485 switch (ret) {
3486 case RMAP_RULE_MISSING:
3487 vty_out(vty, "%% BGP Can't find rule.\n");
3488 retval = CMD_WARNING_CONFIG_FAILED;
3489 break;
3490 case RMAP_COMPILE_ERROR:
3491 vty_out(vty, "%% BGP Argument is malformed.\n");
3492 retval = CMD_WARNING_CONFIG_FAILED;
3493 break;
3494 case RMAP_COMPILE_SUCCESS:
3495 /*
3496 * Nothing to do here
3497 */
3498 break;
3499 }
3500
3501 XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
3502 XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
3503
3504 return retval;
3505 }
3506
3507 /*
3508 * This is the workhorse routine for processing in/out routemap
3509 * modifications.
3510 */
3511 static void bgp_route_map_process_peer(const char *rmap_name,
3512 struct route_map *map, struct peer *peer,
3513 int afi, int safi, int route_update)
3514 {
3515 struct bgp_filter *filter;
3516
3517 if (!peer || !rmap_name)
3518 return;
3519
3520 filter = &peer->filter[afi][safi];
3521 /*
3522 * in is for non-route-server clients,
3523 * out is for all peers
3524 */
3525 if (filter->map[RMAP_IN].name
3526 && (strcmp(rmap_name, filter->map[RMAP_IN].name) == 0)) {
3527 filter->map[RMAP_IN].map = map;
3528
3529 if (route_update && peer->status == Established) {
3530 if (CHECK_FLAG(peer->af_flags[afi][safi],
3531 PEER_FLAG_SOFT_RECONFIG)) {
3532 if (bgp_debug_update(peer, NULL, NULL, 1))
3533 zlog_debug(
3534 "Processing route_map %s update on peer %s (inbound, soft-reconfig)",
3535 rmap_name, peer->host);
3536
3537 bgp_soft_reconfig_in(peer, afi, safi);
3538 } else if (CHECK_FLAG(peer->cap,
3539 PEER_CAP_REFRESH_OLD_RCV)
3540 || CHECK_FLAG(peer->cap,
3541 PEER_CAP_REFRESH_NEW_RCV)) {
3542 if (bgp_debug_update(peer, NULL, NULL, 1))
3543 zlog_debug(
3544 "Processing route_map %s update on peer %s (inbound, route-refresh)",
3545 rmap_name, peer->host);
3546 bgp_route_refresh_send(
3547 peer, afi, safi, 0, 0, 0,
3548 BGP_ROUTE_REFRESH_NORMAL);
3549 }
3550 }
3551 }
3552
3553 /*
3554 * For outbound, unsuppress and default-originate map change (content or
3555 * map created), merely update the "config" here, the actual route
3556 * announcement happens at the group level.
3557 */
3558 if (filter->map[RMAP_OUT].name
3559 && (strcmp(rmap_name, filter->map[RMAP_OUT].name) == 0))
3560 filter->map[RMAP_OUT].map = map;
3561
3562 if (filter->usmap.name && (strcmp(rmap_name, filter->usmap.name) == 0))
3563 filter->usmap.map = map;
3564
3565 if (filter->advmap.aname
3566 && (strcmp(rmap_name, filter->advmap.aname) == 0)) {
3567 filter->advmap.amap = map;
3568 }
3569
3570 if (filter->advmap.cname
3571 && (strcmp(rmap_name, filter->advmap.cname) == 0)) {
3572 filter->advmap.cmap = map;
3573 }
3574
3575 if (peer->default_rmap[afi][safi].name
3576 && (strcmp(rmap_name, peer->default_rmap[afi][safi].name) == 0))
3577 peer->default_rmap[afi][safi].map = map;
3578
3579 /* Notify BGP conditional advertisement scanner percess */
3580 peer->advmap_config_change[afi][safi] = true;
3581 }
3582
3583 static void bgp_route_map_update_peer_group(const char *rmap_name,
3584 struct route_map *map,
3585 struct bgp *bgp)
3586 {
3587 struct peer_group *group;
3588 struct listnode *node, *nnode;
3589 struct bgp_filter *filter;
3590 int afi, safi;
3591 int direct;
3592
3593 if (!bgp)
3594 return;
3595
3596 /* All the peers have been updated correctly already. This is
3597 * just updating the placeholder data. No real update required.
3598 */
3599 for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group)) {
3600 FOREACH_AFI_SAFI (afi, safi) {
3601 filter = &group->conf->filter[afi][safi];
3602
3603 for (direct = RMAP_IN; direct < RMAP_MAX; direct++) {
3604 if ((filter->map[direct].name)
3605 && (strcmp(rmap_name,
3606 filter->map[direct].name)
3607 == 0))
3608 filter->map[direct].map = map;
3609 }
3610
3611 if (filter->usmap.name
3612 && (strcmp(rmap_name, filter->usmap.name) == 0))
3613 filter->usmap.map = map;
3614 }
3615 }
3616 }
3617
3618 /*
3619 * Note that if an extreme number (tens of thousands) of route-maps are in use
3620 * and if bgp has an extreme number of peers, network statements, etc then this
3621 * function can consume a lot of cycles. This is due to this function being
3622 * called for each route-map and within this function we walk the list of peers,
3623 * network statements, etc looking to see if they use this route-map.
3624 */
3625 static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,
3626 int route_update)
3627 {
3628 int i;
3629 bool matched;
3630 afi_t afi;
3631 safi_t safi;
3632 struct peer *peer;
3633 struct bgp_dest *bn;
3634 struct bgp_static *bgp_static;
3635 struct bgp_aggregate *aggregate;
3636 struct listnode *node, *nnode;
3637 struct route_map *map;
3638 char buf[INET6_ADDRSTRLEN];
3639
3640 map = route_map_lookup_by_name(rmap_name);
3641
3642 for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
3643
3644 /* Ignore dummy peer-group structure */
3645 if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
3646 continue;
3647
3648 FOREACH_AFI_SAFI (afi, safi) {
3649 /* process in/out/import/export/default-orig
3650 * route-maps */
3651 bgp_route_map_process_peer(rmap_name, map, peer, afi,
3652 safi, route_update);
3653 }
3654 }
3655
3656 /* for outbound/default-orig route-maps, process for groups */
3657 update_group_policy_update(bgp, BGP_POLICY_ROUTE_MAP, rmap_name,
3658 route_update, 0);
3659
3660 /* update peer-group config (template) */
3661 bgp_route_map_update_peer_group(rmap_name, map, bgp);
3662
3663 FOREACH_AFI_SAFI (afi, safi) {
3664 /* For table route-map updates. */
3665 if (!bgp_fibupd_safi(safi))
3666 continue;
3667
3668 if (bgp->table_map[afi][safi].name
3669 && (strcmp(rmap_name, bgp->table_map[afi][safi].name)
3670 == 0)) {
3671
3672 /* bgp->table_map[afi][safi].map is NULL.
3673 * i.e Route map creation event.
3674 * So update applied_counter.
3675 * If it is not NULL, i.e It may be routemap updation or
3676 * deletion. so no need to update the counter.
3677 */
3678 if (!bgp->table_map[afi][safi].map)
3679 route_map_counter_increment(map);
3680 bgp->table_map[afi][safi].map = map;
3681
3682 if (BGP_DEBUG(zebra, ZEBRA))
3683 zlog_debug(
3684 "Processing route_map %s update on table map",
3685 rmap_name);
3686 if (route_update)
3687 bgp_zebra_announce_table(bgp, afi, safi);
3688 }
3689
3690 /* For network route-map updates. */
3691 for (bn = bgp_table_top(bgp->route[afi][safi]); bn;
3692 bn = bgp_route_next(bn)) {
3693 bgp_static = bgp_dest_get_bgp_static_info(bn);
3694 if (!bgp_static)
3695 continue;
3696
3697 if (!bgp_static->rmap.name
3698 || (strcmp(rmap_name, bgp_static->rmap.name) != 0))
3699 continue;
3700
3701 if (!bgp_static->rmap.map)
3702 route_map_counter_increment(map);
3703
3704 bgp_static->rmap.map = map;
3705
3706 if (route_update && !bgp_static->backdoor) {
3707 const struct prefix *bn_p =
3708 bgp_dest_get_prefix(bn);
3709
3710 if (bgp_debug_zebra(bn_p))
3711 zlog_debug(
3712 "Processing route_map %s update on static route %s",
3713 rmap_name,
3714 inet_ntop(bn_p->family,
3715 &bn_p->u.prefix, buf,
3716 INET6_ADDRSTRLEN));
3717 bgp_static_update(bgp, bn_p, bgp_static, afi,
3718 safi);
3719 }
3720 }
3721
3722 /* For aggregate-address route-map updates. */
3723 for (bn = bgp_table_top(bgp->aggregate[afi][safi]); bn;
3724 bn = bgp_route_next(bn)) {
3725 aggregate = bgp_dest_get_bgp_aggregate_info(bn);
3726 if (!aggregate)
3727 continue;
3728
3729 matched = false;
3730
3731 /* Update suppress map pointer. */
3732 if (aggregate->suppress_map_name
3733 && strmatch(aggregate->suppress_map_name,
3734 rmap_name)) {
3735 if (aggregate->rmap.map == NULL)
3736 route_map_counter_increment(map);
3737
3738 aggregate->suppress_map = map;
3739
3740 bgp_aggregate_toggle_suppressed(
3741 aggregate, bgp, bgp_dest_get_prefix(bn),
3742 afi, safi, false);
3743
3744 matched = true;
3745 }
3746
3747 if (aggregate->rmap.name
3748 && strmatch(rmap_name, aggregate->rmap.name)) {
3749 if (aggregate->rmap.map == NULL)
3750 route_map_counter_increment(map);
3751
3752 aggregate->rmap.map = map;
3753
3754 matched = true;
3755 }
3756
3757 if (matched && route_update) {
3758 const struct prefix *bn_p =
3759 bgp_dest_get_prefix(bn);
3760
3761 if (bgp_debug_zebra(bn_p))
3762 zlog_debug(
3763 "Processing route_map %s update on aggregate-address route %s",
3764 rmap_name,
3765 inet_ntop(bn_p->family,
3766 &bn_p->u.prefix, buf,
3767 INET6_ADDRSTRLEN));
3768 bgp_aggregate_route(bgp, bn_p, afi, safi,
3769 aggregate);
3770 }
3771 }
3772 }
3773
3774 /* For redistribute route-map updates. */
3775 for (afi = AFI_IP; afi < AFI_MAX; afi++)
3776 for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
3777 struct list *red_list;
3778 struct bgp_redist *red;
3779
3780 red_list = bgp->redist[afi][i];
3781 if (!red_list)
3782 continue;
3783
3784 for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) {
3785 if (!red->rmap.name
3786 || (strcmp(rmap_name, red->rmap.name) != 0))
3787 continue;
3788
3789 if (!red->rmap.map)
3790 route_map_counter_increment(map);
3791
3792 red->rmap.map = map;
3793
3794 if (!route_update)
3795 continue;
3796
3797 if (BGP_DEBUG(zebra, ZEBRA))
3798 zlog_debug(
3799 "Processing route_map %s update on redistributed routes",
3800 rmap_name);
3801
3802 bgp_redistribute_resend(bgp, afi, i,
3803 red->instance);
3804 }
3805 }
3806
3807 /* for type5 command route-maps */
3808 FOREACH_AFI_SAFI (afi, safi) {
3809 if (!bgp->adv_cmd_rmap[afi][safi].name
3810 || strcmp(rmap_name, bgp->adv_cmd_rmap[afi][safi].name)
3811 != 0)
3812 continue;
3813
3814 /* Make sure the route-map is populated here if not already done */
3815 bgp->adv_cmd_rmap[afi][safi].map = map;
3816
3817 if (BGP_DEBUG(zebra, ZEBRA))
3818 zlog_debug(
3819 "Processing route_map %s update on advertise type5 route command",
3820 rmap_name);
3821
3822 if (route_update && advertise_type5_routes(bgp, afi)) {
3823 bgp_evpn_withdraw_type5_routes(bgp, afi, safi);
3824 bgp_evpn_advertise_type5_routes(bgp, afi, safi);
3825 }
3826 }
3827 }
3828
3829 static void bgp_route_map_process_update_cb(char *rmap_name)
3830 {
3831 struct listnode *node, *nnode;
3832 struct bgp *bgp;
3833
3834 for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
3835 bgp_route_map_process_update(bgp, rmap_name, 1);
3836
3837 #ifdef ENABLE_BGP_VNC
3838 /* zlog_debug("%s: calling vnc_routemap_update", __func__); */
3839 vnc_routemap_update(bgp, __func__);
3840 #endif
3841 }
3842
3843 vpn_policy_routemap_event(rmap_name);
3844 }
3845
3846 int bgp_route_map_update_timer(struct thread *thread)
3847 {
3848 bm->t_rmap_update = NULL;
3849
3850 route_map_walk_update_list(bgp_route_map_process_update_cb);
3851
3852 return 0;
3853 }
3854
3855 static void bgp_route_map_mark_update(const char *rmap_name)
3856 {
3857 struct listnode *node, *nnode;
3858 struct bgp *bgp;
3859
3860 /* If new update is received before the current timer timed out,
3861 * turn it off and start a new timer.
3862 */
3863 THREAD_OFF(bm->t_rmap_update);
3864
3865 /* rmap_update_timer of 0 means don't do route updates */
3866 if (bm->rmap_update_timer) {
3867 thread_add_timer(bm->master, bgp_route_map_update_timer,
3868 NULL, bm->rmap_update_timer,
3869 &bm->t_rmap_update);
3870
3871 /* Signal the groups that a route-map update event has
3872 * started */
3873 for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp))
3874 update_group_policy_update(bgp,
3875 BGP_POLICY_ROUTE_MAP,
3876 rmap_name, 1, 1);
3877 } else {
3878 for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp))
3879 bgp_route_map_process_update(bgp, rmap_name, 0);
3880 #ifdef ENABLE_BGP_VNC
3881 zlog_debug("%s: calling vnc_routemap_update", __func__);
3882 vnc_routemap_update(bgp, __func__);
3883 #endif
3884 }
3885 }
3886
3887 static void bgp_route_map_add(const char *rmap_name)
3888 {
3889 if (route_map_mark_updated(rmap_name) == 0)
3890 bgp_route_map_mark_update(rmap_name);
3891
3892 route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
3893 }
3894
3895 static void bgp_route_map_delete(const char *rmap_name)
3896 {
3897 if (route_map_mark_updated(rmap_name) == 0)
3898 bgp_route_map_mark_update(rmap_name);
3899
3900 route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_DELETED);
3901 }
3902
3903 static void bgp_route_map_event(const char *rmap_name)
3904 {
3905 if (route_map_mark_updated(rmap_name) == 0)
3906 bgp_route_map_mark_update(rmap_name);
3907
3908 route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
3909 }
3910
3911 DEFUN (match_mac_address,
3912 match_mac_address_cmd,
3913 "match mac address WORD",
3914 MATCH_STR
3915 "mac address\n"
3916 "Match address of route\n"
3917 "MAC Access-list name\n")
3918 {
3919 return bgp_route_match_add(vty, "mac address", argv[3]->arg,
3920 RMAP_EVENT_FILTER_ADDED);
3921 }
3922
3923 DEFUN (no_match_mac_address,
3924 no_match_mac_address_cmd,
3925 "no match mac address WORD",
3926 NO_STR
3927 MATCH_STR
3928 "mac\n"
3929 "Match address of route\n"
3930 "MAC acess-list name\n")
3931 {
3932 return bgp_route_match_delete(vty, "mac address", argv[4]->arg,
3933 RMAP_EVENT_FILTER_DELETED);
3934 }
3935
3936 /*
3937 * Helper to handle the case of the user passing in a number or type string
3938 */
3939 static const char *parse_evpn_rt_type(const char *num_rt_type)
3940 {
3941 switch (num_rt_type[0]) {
3942 case '1':
3943 return "ead";
3944 case '2':
3945 return "macip";
3946 case '3':
3947 return "multicast";
3948 case '4':
3949 return "es";
3950 case '5':
3951 return "prefix";
3952 default:
3953 break;
3954 }
3955
3956 /* Was already full type string */
3957 return num_rt_type;
3958 }
3959
3960 DEFUN (match_evpn_route_type,
3961 match_evpn_route_type_cmd,
3962 "match evpn route-type <macip|2|multicast|3|prefix|5>",
3963 MATCH_STR
3964 EVPN_HELP_STR
3965 EVPN_TYPE_HELP_STR
3966 EVPN_TYPE_2_HELP_STR
3967 EVPN_TYPE_2_HELP_STR
3968 EVPN_TYPE_3_HELP_STR
3969 EVPN_TYPE_3_HELP_STR
3970 EVPN_TYPE_5_HELP_STR
3971 EVPN_TYPE_5_HELP_STR)
3972 {
3973 return bgp_route_match_add(vty, "evpn route-type",
3974 parse_evpn_rt_type(argv[3]->arg),
3975 RMAP_EVENT_MATCH_ADDED);
3976 }
3977
3978 DEFUN (no_match_evpn_route_type,
3979 no_match_evpn_route_type_cmd,
3980 "no match evpn route-type <macip|2|multicast|3|prefix|5>",
3981 NO_STR
3982 MATCH_STR
3983 EVPN_HELP_STR
3984 EVPN_TYPE_HELP_STR
3985 EVPN_TYPE_2_HELP_STR
3986 EVPN_TYPE_2_HELP_STR
3987 EVPN_TYPE_3_HELP_STR
3988 EVPN_TYPE_3_HELP_STR
3989 EVPN_TYPE_5_HELP_STR
3990 EVPN_TYPE_5_HELP_STR)
3991 {
3992 return bgp_route_match_delete(vty, "evpn route-type",
3993 parse_evpn_rt_type(argv[4]->arg),
3994 RMAP_EVENT_MATCH_DELETED);
3995 }
3996
3997
3998 DEFUN (match_evpn_vni,
3999 match_evpn_vni_cmd,
4000 "match evpn vni " CMD_VNI_RANGE,
4001 MATCH_STR
4002 EVPN_HELP_STR
4003 "Match VNI\n"
4004 "VNI ID\n")
4005 {
4006 return bgp_route_match_add(vty, "evpn vni", argv[3]->arg,
4007 RMAP_EVENT_MATCH_ADDED);
4008 }
4009
4010 DEFUN (no_match_evpn_vni,
4011 no_match_evpn_vni_cmd,
4012 "no match evpn vni " CMD_VNI_RANGE,
4013 NO_STR
4014 MATCH_STR
4015 EVPN_HELP_STR
4016 "Match VNI\n"
4017 "VNI ID\n")
4018 {
4019 return bgp_route_match_delete(vty, "evpn vni", argv[4]->arg,
4020 RMAP_EVENT_MATCH_DELETED);
4021 }
4022
4023 DEFUN (match_evpn_default_route,
4024 match_evpn_default_route_cmd,
4025 "match evpn default-route",
4026 MATCH_STR
4027 EVPN_HELP_STR
4028 "default EVPN type-5 route\n")
4029 {
4030 return bgp_route_match_add(vty, "evpn default-route", NULL,
4031 RMAP_EVENT_MATCH_ADDED);
4032 }
4033
4034 DEFUN (no_match_evpn_default_route,
4035 no_match_evpn_default_route_cmd,
4036 "no match evpn default-route",
4037 NO_STR
4038 MATCH_STR
4039 EVPN_HELP_STR
4040 "default EVPN type-5 route\n")
4041 {
4042 return bgp_route_match_delete(vty, "evpn default-route", NULL,
4043 RMAP_EVENT_MATCH_DELETED);
4044 }
4045
4046 DEFUN (match_evpn_rd,
4047 match_evpn_rd_cmd,
4048 "match evpn rd ASN:NN_OR_IP-ADDRESS:NN",
4049 MATCH_STR
4050 EVPN_HELP_STR
4051 "Route Distinguisher\n"
4052 "ASN:XX or A.B.C.D:XX\n")
4053 {
4054 return bgp_route_match_add(vty, "evpn rd", argv[3]->arg,
4055 RMAP_EVENT_MATCH_ADDED);
4056 }
4057
4058 DEFUN (no_match_evpn_rd,
4059 no_match_evpn_rd_cmd,
4060 "no match evpn rd ASN:NN_OR_IP-ADDRESS:NN",
4061 NO_STR
4062 MATCH_STR
4063 EVPN_HELP_STR
4064 "Route Distinguisher\n"
4065 "ASN:XX or A.B.C.D:XX\n")
4066 {
4067 return bgp_route_match_delete(vty, "evpn rd", argv[4]->arg,
4068 RMAP_EVENT_MATCH_DELETED);
4069 }
4070
4071 DEFPY(match_vrl_source_vrf,
4072 match_vrl_source_vrf_cmd,
4073 "match source-vrf NAME$vrf_name",
4074 MATCH_STR
4075 "source vrf\n"
4076 "The VRF name\n")
4077 {
4078 return bgp_route_match_add(vty, "source-vrf", vrf_name,
4079 RMAP_EVENT_MATCH_ADDED);
4080 }
4081
4082 DEFPY(no_match_vrl_source_vrf,
4083 no_match_vrl_source_vrf_cmd,
4084 "no match source-vrf NAME$vrf_name",
4085 NO_STR
4086 MATCH_STR
4087 "source vrf\n"
4088 "The VRF name\n")
4089 {
4090 return bgp_route_match_delete(vty, "source-vrf", vrf_name,
4091 RMAP_EVENT_MATCH_DELETED);
4092 }
4093
4094 DEFUN (match_peer,
4095 match_peer_cmd,
4096 "match peer <A.B.C.D|X:X::X:X|WORD>",
4097 MATCH_STR
4098 "Match peer address\n"
4099 "IP address of peer\n"
4100 "IPv6 address of peer\n"
4101 "Interface name of peer\n")
4102 {
4103 int idx_ip = 2;
4104 return bgp_route_match_add(vty, "peer", argv[idx_ip]->arg,
4105 RMAP_EVENT_MATCH_ADDED);
4106 }
4107
4108 DEFUN (match_peer_local,
4109 match_peer_local_cmd,
4110 "match peer local",
4111 MATCH_STR
4112 "Match peer address\n"
4113 "Static or Redistributed routes\n")
4114 {
4115 return bgp_route_match_add(vty, "peer", "local",
4116 RMAP_EVENT_MATCH_DELETED);
4117 }
4118
4119 DEFUN (no_match_peer,
4120 no_match_peer_cmd,
4121 "no match peer [<local|A.B.C.D|X:X::X:X|WORD>]",
4122 NO_STR
4123 MATCH_STR
4124 "Match peer address\n"
4125 "Static or Redistributed routes\n"
4126 "IP address of peer\n"
4127 "IPv6 address of peer\n"
4128 "Interface name of peer\n")
4129 {
4130 int idx_peer = 3;
4131
4132 if (argc <= idx_peer)
4133 return bgp_route_match_delete(vty, "peer", NULL,
4134 RMAP_EVENT_MATCH_DELETED);
4135 return bgp_route_match_delete(vty, "peer", argv[idx_peer]->arg,
4136 RMAP_EVENT_MATCH_DELETED);
4137 }
4138
4139 #ifdef HAVE_SCRIPTING
4140 DEFUN (match_script,
4141 match_script_cmd,
4142 "[no] match script WORD",
4143 NO_STR
4144 MATCH_STR
4145 "Execute script to determine match\n"
4146 "The script name to run, without .lua; e.g. 'myroutemap' to run myroutemap.lua\n")
4147 {
4148 bool no = strmatch(argv[0]->text, "no");
4149 int i = 0;
4150 argv_find(argv, argc, "WORD", &i);
4151 const char *script = argv[i]->arg;
4152
4153 if (no) {
4154 return bgp_route_match_delete(vty, "script", script,
4155 RMAP_EVENT_FILTER_DELETED);
4156 } else {
4157 return bgp_route_match_add(vty, "script", script,
4158 RMAP_EVENT_FILTER_ADDED);
4159 }
4160 }
4161 #endif /* HAVE_SCRIPTING */
4162
4163 /* match probability */
4164 DEFUN (match_probability,
4165 match_probability_cmd,
4166 "match probability (0-100)",
4167 MATCH_STR
4168 "Match portion of routes defined by percentage value\n"
4169 "Percentage of routes\n")
4170 {
4171 int idx_number = 2;
4172 return bgp_route_match_add(vty, "probability", argv[idx_number]->arg,
4173 RMAP_EVENT_MATCH_ADDED);
4174 }
4175
4176
4177 DEFUN (no_match_probability,
4178 no_match_probability_cmd,
4179 "no match probability [(1-99)]",
4180 NO_STR
4181 MATCH_STR
4182 "Match portion of routes defined by percentage value\n"
4183 "Percentage of routes\n")
4184 {
4185 int idx_number = 3;
4186 if (argc <= idx_number)
4187 return bgp_route_match_delete(vty, "probability", NULL,
4188 RMAP_EVENT_MATCH_DELETED);
4189 return bgp_route_match_delete(vty, "probability", argv[idx_number]->arg,
4190 RMAP_EVENT_MATCH_DELETED);
4191 }
4192
4193
4194 DEFUN (match_ip_route_source,
4195 match_ip_route_source_cmd,
4196 "match ip route-source <(1-199)|(1300-2699)|WORD>",
4197 MATCH_STR
4198 IP_STR
4199 "Match advertising source address of route\n"
4200 "IP access-list number\n"
4201 "IP access-list number (expanded range)\n"
4202 "IP standard access-list name\n")
4203 {
4204 int idx_acl = 3;
4205 return bgp_route_match_add(vty, "ip route-source", argv[idx_acl]->arg,
4206 RMAP_EVENT_FILTER_ADDED);
4207 }
4208
4209
4210 DEFUN (no_match_ip_route_source,
4211 no_match_ip_route_source_cmd,
4212 "no match ip route-source [<(1-199)|(1300-2699)|WORD>]",
4213 NO_STR
4214 MATCH_STR
4215 IP_STR
4216 "Match advertising source address of route\n"
4217 "IP access-list number\n"
4218 "IP access-list number (expanded range)\n"
4219 "IP standard access-list name\n")
4220 {
4221 int idx_number = 4;
4222 if (argc <= idx_number)
4223 return bgp_route_match_delete(vty, "ip route-source", NULL,
4224 RMAP_EVENT_FILTER_DELETED);
4225 return bgp_route_match_delete(vty, "ip route-source",
4226 argv[idx_number]->arg,
4227 RMAP_EVENT_FILTER_DELETED);
4228 }
4229
4230
4231 DEFUN (match_ip_route_source_prefix_list,
4232 match_ip_route_source_prefix_list_cmd,
4233 "match ip route-source prefix-list WORD",
4234 MATCH_STR
4235 IP_STR
4236 "Match advertising source address of route\n"
4237 "Match entries of prefix-lists\n"
4238 "IP prefix-list name\n")
4239 {
4240 int idx_word = 4;
4241 return bgp_route_match_add(vty, "ip route-source prefix-list",
4242 argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
4243 }
4244
4245
4246 DEFUN (no_match_ip_route_source_prefix_list,
4247 no_match_ip_route_source_prefix_list_cmd,
4248 "no match ip route-source prefix-list [WORD]",
4249 NO_STR
4250 MATCH_STR
4251 IP_STR
4252 "Match advertising source address of route\n"
4253 "Match entries of prefix-lists\n"
4254 "IP prefix-list name\n")
4255 {
4256 int idx_word = 5;
4257 if (argc <= idx_word)
4258 return bgp_route_match_delete(vty,
4259 "ip route-source prefix-list",
4260 NULL, RMAP_EVENT_PLIST_DELETED);
4261 return bgp_route_match_delete(vty, "ip route-source prefix-list",
4262 argv[idx_word]->arg,
4263 RMAP_EVENT_PLIST_DELETED);
4264 }
4265
4266
4267 DEFUN (match_local_pref,
4268 match_local_pref_cmd,
4269 "match local-preference (0-4294967295)",
4270 MATCH_STR
4271 "Match local-preference of route\n"
4272 "Metric value\n")
4273 {
4274 int idx_number = 2;
4275 return bgp_route_match_add(vty, "local-preference",
4276 argv[idx_number]->arg,
4277 RMAP_EVENT_MATCH_ADDED);
4278 }
4279
4280
4281 DEFUN (no_match_local_pref,
4282 no_match_local_pref_cmd,
4283 "no match local-preference [(0-4294967295)]",
4284 NO_STR
4285 MATCH_STR
4286 "Match local preference of route\n"
4287 "Local preference value\n")
4288 {
4289 int idx_localpref = 3;
4290 if (argc <= idx_localpref)
4291 return bgp_route_match_delete(vty, "local-preference", NULL,
4292 RMAP_EVENT_MATCH_DELETED);
4293 return bgp_route_match_delete(vty, "local-preference",
4294 argv[idx_localpref]->arg,
4295 RMAP_EVENT_MATCH_DELETED);
4296 }
4297
4298
4299 DEFUN (match_community,
4300 match_community_cmd,
4301 "match community <(1-99)|(100-500)|WORD> [exact-match]",
4302 MATCH_STR
4303 "Match BGP community list\n"
4304 "Community-list number (standard)\n"
4305 "Community-list number (expanded)\n"
4306 "Community-list name\n"
4307 "Do exact matching of communities\n")
4308 {
4309 int idx_comm_list = 2;
4310 int ret;
4311 char *argstr;
4312
4313 if (argc == 4) {
4314 argstr = XMALLOC(MTYPE_ROUTE_MAP_COMPILED,
4315 strlen(argv[idx_comm_list]->arg)
4316 + strlen("exact-match") + 2);
4317
4318 sprintf(argstr, "%s exact-match", argv[idx_comm_list]->arg);
4319 } else
4320 argstr = argv[idx_comm_list]->arg;
4321
4322 ret = bgp_route_match_add(vty, "community", argstr,
4323 RMAP_EVENT_CLIST_ADDED);
4324
4325 if (argstr != argv[idx_comm_list]->arg)
4326 XFREE(MTYPE_ROUTE_MAP_COMPILED, argstr);
4327
4328 return ret;
4329 }
4330
4331 DEFUN (no_match_community,
4332 no_match_community_cmd,
4333 "no match community [<(1-99)|(100-500)|WORD> [exact-match]]",
4334 NO_STR
4335 MATCH_STR
4336 "Match BGP community list\n"
4337 "Community-list number (standard)\n"
4338 "Community-list number (expanded)\n"
4339 "Community-list name\n"
4340 "Do exact matching of communities\n")
4341 {
4342 return bgp_route_match_delete(vty, "community", NULL,
4343 RMAP_EVENT_CLIST_DELETED);
4344 }
4345
4346 DEFUN (match_lcommunity,
4347 match_lcommunity_cmd,
4348 "match large-community <(1-99)|(100-500)|WORD> [exact-match]",
4349 MATCH_STR
4350 "Match BGP large community list\n"
4351 "Large Community-list number (standard)\n"
4352 "Large Community-list number (expanded)\n"
4353 "Large Community-list name\n"
4354 "Do exact matching of communities\n")
4355 {
4356 int idx_lcomm_list = 2;
4357 int ret;
4358 char *argstr;
4359
4360 if (argc == 4) {
4361 argstr = XMALLOC(MTYPE_ROUTE_MAP_COMPILED,
4362 strlen(argv[idx_lcomm_list]->arg)
4363 + strlen("exact-match") + 2);
4364
4365 sprintf(argstr, "%s exact-match", argv[idx_lcomm_list]->arg);
4366 } else
4367 argstr = argv[idx_lcomm_list]->arg;
4368
4369 ret = bgp_route_match_add(vty, "large-community", argstr,
4370 RMAP_EVENT_LLIST_ADDED);
4371 if (argstr != argv[idx_lcomm_list]->arg)
4372 XFREE(MTYPE_ROUTE_MAP_COMPILED, argstr);
4373
4374 return ret;
4375 }
4376
4377 DEFUN (no_match_lcommunity,
4378 no_match_lcommunity_cmd,
4379 "no match large-community [<(1-99)|(100-500)|WORD> [exact-match]]",
4380 NO_STR
4381 MATCH_STR
4382 "Match BGP large community list\n"
4383 "Large Community-list number (standard)\n"
4384 "Large Community-list number (expanded)\n"
4385 "Large Community-list name\n"
4386 "Do exact matching of communities\n")
4387 {
4388 return bgp_route_match_delete(vty, "large-community", NULL,
4389 RMAP_EVENT_LLIST_DELETED);
4390 }
4391
4392 DEFUN (match_ecommunity,
4393 match_ecommunity_cmd,
4394 "match extcommunity <(1-99)|(100-500)|WORD>",
4395 MATCH_STR
4396 "Match BGP/VPN extended community list\n"
4397 "Extended community-list number (standard)\n"
4398 "Extended community-list number (expanded)\n"
4399 "Extended community-list name\n")
4400 {
4401 int idx_comm_list = 2;
4402 return bgp_route_match_add(vty, "extcommunity",
4403 argv[idx_comm_list]->arg,
4404 RMAP_EVENT_ECLIST_ADDED);
4405 }
4406
4407
4408 DEFUN (no_match_ecommunity,
4409 no_match_ecommunity_cmd,
4410 "no match extcommunity [<(1-99)|(100-500)|WORD>]",
4411 NO_STR
4412 MATCH_STR
4413 "Match BGP/VPN extended community list\n"
4414 "Extended community-list number (standard)\n"
4415 "Extended community-list number (expanded)\n"
4416 "Extended community-list name\n")
4417 {
4418 return bgp_route_match_delete(vty, "extcommunity", NULL,
4419 RMAP_EVENT_ECLIST_DELETED);
4420 }
4421
4422
4423 DEFUN (match_aspath,
4424 match_aspath_cmd,
4425 "match as-path WORD",
4426 MATCH_STR
4427 "Match BGP AS path list\n"
4428 "AS path access-list name\n")
4429 {
4430 int idx_word = 2;
4431 return bgp_route_match_add(vty, "as-path", argv[idx_word]->arg,
4432 RMAP_EVENT_ASLIST_ADDED);
4433 }
4434
4435
4436 DEFUN (no_match_aspath,
4437 no_match_aspath_cmd,
4438 "no match as-path [WORD]",
4439 NO_STR
4440 MATCH_STR
4441 "Match BGP AS path list\n"
4442 "AS path access-list name\n")
4443 {
4444 return bgp_route_match_delete(vty, "as-path", NULL,
4445 RMAP_EVENT_ASLIST_DELETED);
4446 }
4447
4448
4449 DEFUN (match_origin,
4450 match_origin_cmd,
4451 "match origin <egp|igp|incomplete>",
4452 MATCH_STR
4453 "BGP origin code\n"
4454 "remote EGP\n"
4455 "local IGP\n"
4456 "unknown heritage\n")
4457 {
4458 int idx_origin = 2;
4459 if (strncmp(argv[idx_origin]->arg, "igp", 2) == 0)
4460 return bgp_route_match_add(vty, "origin", "igp",
4461 RMAP_EVENT_MATCH_ADDED);
4462 if (strncmp(argv[idx_origin]->arg, "egp", 1) == 0)
4463 return bgp_route_match_add(vty, "origin", "egp",
4464 RMAP_EVENT_MATCH_ADDED);
4465 if (strncmp(argv[idx_origin]->arg, "incomplete", 2) == 0)
4466 return bgp_route_match_add(vty, "origin", "incomplete",
4467 RMAP_EVENT_MATCH_ADDED);
4468
4469 vty_out(vty, "%% Invalid match origin type\n");
4470 return CMD_WARNING_CONFIG_FAILED;
4471 }
4472
4473
4474 DEFUN (no_match_origin,
4475 no_match_origin_cmd,
4476 "no match origin [<egp|igp|incomplete>]",
4477 NO_STR
4478 MATCH_STR
4479 "BGP origin code\n"
4480 "remote EGP\n"
4481 "local IGP\n"
4482 "unknown heritage\n")
4483 {
4484 return bgp_route_match_delete(vty, "origin", NULL,
4485 RMAP_EVENT_MATCH_DELETED);
4486 }
4487
4488 DEFUN (set_table_id,
4489 set_table_id_cmd,
4490 "set table (1-4294967295)",
4491 SET_STR
4492 "export route to non-main kernel table\n"
4493 "Kernel routing table id\n")
4494 {
4495 int idx_id = 2;
4496
4497 VTY_DECLVAR_CONTEXT(route_map_index, index);
4498
4499 return generic_set_add(vty, index, "table", argv[idx_id]->arg);
4500 }
4501
4502 DEFUN (no_set_table_id,
4503 no_set_table_id_cmd,
4504 "no set table",
4505 NO_STR
4506 SET_STR
4507 "export route to non-main kernel table\n")
4508 {
4509 VTY_DECLVAR_CONTEXT(route_map_index, index);
4510
4511 return generic_set_delete(vty, index, "table", NULL);
4512 }
4513
4514 DEFUN (set_ip_nexthop_peer,
4515 set_ip_nexthop_peer_cmd,
4516 "[no] set ip next-hop peer-address",
4517 NO_STR
4518 SET_STR
4519 IP_STR
4520 "Next hop address\n"
4521 "Use peer address (for BGP only)\n")
4522 {
4523 int (*func)(struct vty *, struct route_map_index *, const char *,
4524 const char *) = strmatch(argv[0]->text, "no")
4525 ? generic_set_delete
4526 : generic_set_add;
4527
4528 return func(vty, VTY_GET_CONTEXT(route_map_index), "ip next-hop",
4529 "peer-address");
4530 }
4531
4532 DEFUN (set_ip_nexthop_unchanged,
4533 set_ip_nexthop_unchanged_cmd,
4534 "[no] set ip next-hop unchanged",
4535 NO_STR
4536 SET_STR
4537 IP_STR
4538 "Next hop address\n"
4539 "Don't modify existing Next hop address\n")
4540 {
4541 int (*func)(struct vty *, struct route_map_index *, const char *,
4542 const char *) = strmatch(argv[0]->text, "no")
4543 ? generic_set_delete
4544 : generic_set_add;
4545
4546 return func(vty, VTY_GET_CONTEXT(route_map_index), "ip next-hop",
4547 "unchanged");
4548 }
4549
4550 DEFUN (set_distance,
4551 set_distance_cmd,
4552 "set distance (0-255)",
4553 SET_STR
4554 "BGP Administrative Distance to use\n"
4555 "Distance value\n")
4556 {
4557 int idx_number = 2;
4558
4559 return generic_set_add(vty, VTY_GET_CONTEXT(route_map_index),
4560 "distance", argv[idx_number]->arg);
4561 }
4562
4563 DEFUN (no_set_distance,
4564 no_set_distance_cmd,
4565 "no set distance [(0-255)]",
4566 NO_STR SET_STR
4567 "BGP Administrative Distance to use\n"
4568 "Distance value\n")
4569 {
4570 return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index),
4571 "distance", NULL);
4572 }
4573
4574 DEFUN (set_local_pref,
4575 set_local_pref_cmd,
4576 "set local-preference WORD",
4577 SET_STR
4578 "BGP local preference path attribute\n"
4579 "Preference value (0-4294967295)\n")
4580 {
4581 int idx_number = 2;
4582 return generic_set_add(vty, VTY_GET_CONTEXT(route_map_index),
4583 "local-preference", argv[idx_number]->arg);
4584 }
4585
4586
4587 DEFUN (no_set_local_pref,
4588 no_set_local_pref_cmd,
4589 "no set local-preference [WORD]",
4590 NO_STR
4591 SET_STR
4592 "BGP local preference path attribute\n"
4593 "Preference value (0-4294967295)\n")
4594 {
4595 int idx_localpref = 3;
4596 if (argc <= idx_localpref)
4597 return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index),
4598 "local-preference", NULL);
4599 return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index),
4600 "local-preference", argv[idx_localpref]->arg);
4601 }
4602
4603
4604 DEFUN (set_weight,
4605 set_weight_cmd,
4606 "set weight (0-4294967295)",
4607 SET_STR
4608 "BGP weight for routing table\n"
4609 "Weight value\n")
4610 {
4611 int idx_number = 2;
4612 return generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), "weight",
4613 argv[idx_number]->arg);
4614 }
4615
4616
4617 DEFUN (no_set_weight,
4618 no_set_weight_cmd,
4619 "no set weight [(0-4294967295)]",
4620 NO_STR
4621 SET_STR
4622 "BGP weight for routing table\n"
4623 "Weight value\n")
4624 {
4625 int idx_weight = 3;
4626 if (argc <= idx_weight)
4627 return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index),
4628 "weight", NULL);
4629 return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index),
4630 "weight", argv[idx_weight]->arg);
4631 }
4632
4633 DEFUN (set_label_index,
4634 set_label_index_cmd,
4635 "set label-index (0-1048560)",
4636 SET_STR
4637 "Label index to associate with the prefix\n"
4638 "Label index value\n")
4639 {
4640 int idx_number = 2;
4641 return generic_set_add(vty, VTY_GET_CONTEXT(route_map_index),
4642 "label-index", argv[idx_number]->arg);
4643 }
4644
4645 DEFUN (no_set_label_index,
4646 no_set_label_index_cmd,
4647 "no set label-index [(0-1048560)]",
4648 NO_STR
4649 SET_STR
4650 "Label index to associate with the prefix\n"
4651 "Label index value\n")
4652 {
4653 int idx_label_index = 3;
4654 if (argc <= idx_label_index)
4655 return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index),
4656 "label-index", NULL);
4657 return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index),
4658 "label-index", argv[idx_label_index]->arg);
4659 }
4660
4661 DEFUN (set_aspath_prepend_asn,
4662 set_aspath_prepend_asn_cmd,
4663 "set as-path prepend (1-4294967295)...",
4664 SET_STR
4665 "Transform BGP AS_PATH attribute\n"
4666 "Prepend to the as-path\n"
4667 "AS number\n")
4668 {
4669 int idx_asn = 3;
4670 int ret;
4671 char *str;
4672
4673 str = argv_concat(argv, argc, idx_asn);
4674 ret = generic_set_add(vty, VTY_GET_CONTEXT(route_map_index),
4675 "as-path prepend", str);
4676 XFREE(MTYPE_TMP, str);
4677
4678 return ret;
4679 }
4680
4681 DEFUN (set_aspath_prepend_lastas,
4682 set_aspath_prepend_lastas_cmd,
4683 "set as-path prepend last-as (1-10)",
4684 SET_STR
4685 "Transform BGP AS_PATH attribute\n"
4686 "Prepend to the as-path\n"
4687 "Use the peer's AS-number\n"
4688 "Number of times to insert\n")
4689 {
4690 return set_aspath_prepend_asn(self, vty, argc, argv);
4691 }
4692
4693 DEFUN (no_set_aspath_prepend,
4694 no_set_aspath_prepend_cmd,
4695 "no set as-path prepend [(1-4294967295)]",
4696 NO_STR
4697 SET_STR
4698 "Transform BGP AS_PATH attribute\n"
4699 "Prepend to the as-path\n"
4700 "AS number\n")
4701 {
4702 int idx_asn = 4;
4703 int ret;
4704 char *str;
4705
4706 str = argv_concat(argv, argc, idx_asn);
4707 ret = generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index),
4708 "as-path prepend", str);
4709 XFREE(MTYPE_TMP, str);
4710 return ret;
4711 }
4712
4713 DEFUN (no_set_aspath_prepend_lastas,
4714 no_set_aspath_prepend_lastas_cmd,
4715 "no set as-path prepend last-as [(1-10)]",
4716 NO_STR
4717 SET_STR
4718 "Transform BGP AS_PATH attribute\n"
4719 "Prepend to the as-path\n"
4720 "Use the peers AS-number\n"
4721 "Number of times to insert\n")
4722 {
4723 return no_set_aspath_prepend(self, vty, argc, argv);
4724 }
4725
4726 DEFUN (set_aspath_exclude,
4727 set_aspath_exclude_cmd,
4728 "set as-path exclude (1-4294967295)...",
4729 SET_STR
4730 "Transform BGP AS-path attribute\n"
4731 "Exclude from the as-path\n"
4732 "AS number\n")
4733 {
4734 int idx_asn = 3;
4735 int ret;
4736 char *str;
4737
4738 str = argv_concat(argv, argc, idx_asn);
4739 ret = generic_set_add(vty, VTY_GET_CONTEXT(route_map_index),
4740 "as-path exclude", str);
4741 XFREE(MTYPE_TMP, str);
4742 return ret;
4743 }
4744
4745 DEFUN (no_set_aspath_exclude,
4746 no_set_aspath_exclude_cmd,
4747 "no set as-path exclude (1-4294967295)...",
4748 NO_STR
4749 SET_STR
4750 "Transform BGP AS_PATH attribute\n"
4751 "Exclude from the as-path\n"
4752 "AS number\n")
4753 {
4754 int idx_asn = 4;
4755 int ret;
4756 char *str;
4757
4758 str = argv_concat(argv, argc, idx_asn);
4759 ret = generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index),
4760 "as-path exclude", str);
4761 XFREE(MTYPE_TMP, str);
4762 return ret;
4763 }
4764
4765 ALIAS(no_set_aspath_exclude, no_set_aspath_exclude_all_cmd,
4766 "no set as-path exclude",
4767 NO_STR SET_STR
4768 "Transform BGP AS_PATH attribute\n"
4769 "Exclude from the as-path\n")
4770
4771 DEFUN (set_community,
4772 set_community_cmd,
4773 "set community AA:NN...",
4774 SET_STR
4775 "BGP community attribute\n"
4776 COMMUNITY_VAL_STR)
4777 {
4778 int idx_aa_nn = 2;
4779 int i;
4780 int first = 0;
4781 int additive = 0;
4782 struct buffer *b;
4783 struct community *com = NULL;
4784 char *str;
4785 char *argstr;
4786 int ret;
4787
4788 b = buffer_new(1024);
4789
4790 for (i = idx_aa_nn; i < argc; i++) {
4791 if (strncmp(argv[i]->arg, "additive", strlen(argv[i]->arg))
4792 == 0) {
4793 additive = 1;
4794 continue;
4795 }
4796
4797 if (first)
4798 buffer_putc(b, ' ');
4799 else
4800 first = 1;
4801
4802 if (strncmp(argv[i]->arg, "internet", strlen(argv[i]->arg))
4803 == 0) {
4804 buffer_putstr(b, "internet");
4805 continue;
4806 }
4807 if (strncmp(argv[i]->arg, "local-AS", strlen(argv[i]->arg))
4808 == 0) {
4809 buffer_putstr(b, "local-AS");
4810 continue;
4811 }
4812 if (strncmp(argv[i]->arg, "no-a", strlen("no-a")) == 0
4813 && strncmp(argv[i]->arg, "no-advertise",
4814 strlen(argv[i]->arg))
4815 == 0) {
4816 buffer_putstr(b, "no-advertise");
4817 continue;
4818 }
4819 if (strncmp(argv[i]->arg, "no-e", strlen("no-e")) == 0
4820 && strncmp(argv[i]->arg, "no-export", strlen(argv[i]->arg))
4821 == 0) {
4822 buffer_putstr(b, "no-export");
4823 continue;
4824 }
4825 if (strncmp(argv[i]->arg, "graceful-shutdown",
4826 strlen(argv[i]->arg))
4827 == 0) {
4828 buffer_putstr(b, "graceful-shutdown");
4829 continue;
4830 }
4831 buffer_putstr(b, argv[i]->arg);
4832 }
4833 buffer_putc(b, '\0');
4834
4835 /* Fetch result string then compile it to communities attribute. */
4836 str = buffer_getstr(b);
4837 buffer_free(b);
4838
4839 if (str) {
4840 com = community_str2com(str);
4841 XFREE(MTYPE_TMP, str);
4842 }
4843
4844 /* Can't compile user input into communities attribute. */
4845 if (!com) {
4846 vty_out(vty, "%% Malformed communities attribute\n");
4847 return CMD_WARNING_CONFIG_FAILED;
4848 }
4849
4850 /* Set communites attribute string. */
4851 str = community_str(com, false);
4852
4853 if (additive) {
4854 size_t argstr_sz = strlen(str) + strlen(" additive") + 1;
4855 argstr = XCALLOC(MTYPE_TMP, argstr_sz);
4856 strlcpy(argstr, str, argstr_sz);
4857 strlcat(argstr, " additive", argstr_sz);
4858 ret = generic_set_add(vty, VTY_GET_CONTEXT(route_map_index),
4859 "community", argstr);
4860 XFREE(MTYPE_TMP, argstr);
4861 } else
4862 ret = generic_set_add(vty, VTY_GET_CONTEXT(route_map_index),
4863 "community", str);
4864
4865 community_free(&com);
4866
4867 return ret;
4868 }
4869
4870 DEFUN (set_community_none,
4871 set_community_none_cmd,
4872 "set community none",
4873 SET_STR
4874 "BGP community attribute\n"
4875 "No community attribute\n")
4876 {
4877 return generic_set_add(vty, VTY_GET_CONTEXT(route_map_index),
4878 "community", "none");
4879 }
4880
4881 DEFUN (no_set_community,
4882 no_set_community_cmd,
4883 "no set community AA:NN...",
4884 NO_STR
4885 SET_STR
4886 "BGP community attribute\n"
4887 COMMUNITY_VAL_STR)
4888 {
4889 return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index),
4890 "community", NULL);
4891 }
4892
4893 ALIAS (no_set_community,
4894 no_set_community_short_cmd,
4895 "no set community",
4896 NO_STR
4897 SET_STR
4898 "BGP community attribute\n")
4899
4900
4901 DEFUN (set_community_delete,
4902 set_community_delete_cmd,
4903 "set comm-list <(1-99)|(100-500)|WORD> delete",
4904 SET_STR
4905 "set BGP community list (for deletion)\n"
4906 "Community-list number (standard)\n"
4907 "Community-list number (expanded)\n"
4908 "Community-list name\n"
4909 "Delete matching communities\n")
4910 {
4911 int idx_comm_list = 2;
4912 char *args;
4913
4914 args = argv_concat(argv, argc, idx_comm_list);
4915 generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), "comm-list",
4916 args);
4917 XFREE(MTYPE_TMP, args);
4918
4919 return CMD_SUCCESS;
4920 }
4921
4922 DEFUN (no_set_community_delete,
4923 no_set_community_delete_cmd,
4924 "no set comm-list [<(1-99)|(100-500)|WORD> delete]",
4925 NO_STR
4926 SET_STR
4927 "set BGP community list (for deletion)\n"
4928 "Community-list number (standard)\n"
4929 "Community-list number (expanded)\n"
4930 "Community-list name\n"
4931 "Delete matching communities\n")
4932 {
4933 return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index),
4934 "comm-list", NULL);
4935 }
4936
4937 DEFUN (set_lcommunity,
4938 set_lcommunity_cmd,
4939 "set large-community AA:BB:CC...",
4940 SET_STR
4941 "BGP large community attribute\n"
4942 "Large Community number in aa:bb:cc format or additive\n")
4943 {
4944 int ret;
4945 char *str;
4946
4947 str = argv_concat(argv, argc, 2);
4948 ret = generic_set_add(vty, VTY_GET_CONTEXT(route_map_index),
4949 "large-community", str);
4950 XFREE(MTYPE_TMP, str);
4951
4952 return ret;
4953 }
4954
4955 DEFUN (set_lcommunity_none,
4956 set_lcommunity_none_cmd,
4957 "set large-community none",
4958 SET_STR
4959 "BGP large community attribute\n"
4960 "No large community attribute\n")
4961 {
4962 return generic_set_add(vty, VTY_GET_CONTEXT(route_map_index),
4963 "large-community", "none");
4964 }
4965
4966 DEFUN (no_set_lcommunity,
4967 no_set_lcommunity_cmd,
4968 "no set large-community none",
4969 NO_STR
4970 SET_STR
4971 "BGP large community attribute\n"
4972 "No community attribute\n")
4973 {
4974 return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index),
4975 "large-community", NULL);
4976 }
4977
4978 DEFUN (no_set_lcommunity1,
4979 no_set_lcommunity1_cmd,
4980 "no set large-community AA:BB:CC...",
4981 NO_STR
4982 SET_STR
4983 "BGP large community attribute\n"
4984 "Large community in AA:BB:CC... format or additive\n")
4985 {
4986 return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index),
4987 "large-community", NULL);
4988 }
4989
4990 ALIAS (no_set_lcommunity1,
4991 no_set_lcommunity1_short_cmd,
4992 "no set large-community",
4993 NO_STR
4994 SET_STR
4995 "BGP large community attribute\n")
4996
4997 DEFUN (set_lcommunity_delete,
4998 set_lcommunity_delete_cmd,
4999 "set large-comm-list <(1-99)|(100-500)|WORD> delete",
5000 SET_STR
5001 "set BGP large community list (for deletion)\n"
5002 "Large Community-list number (standard)\n"
5003 "Large Communitly-list number (expanded)\n"
5004 "Large Community-list name\n"
5005 "Delete matching large communities\n")
5006 {
5007 int idx_lcomm_list = 2;
5008 char *args;
5009
5010 args = argv_concat(argv, argc, idx_lcomm_list);
5011 generic_set_add(vty, VTY_GET_CONTEXT(route_map_index),
5012 "large-comm-list", args);
5013 XFREE(MTYPE_TMP, args);
5014
5015 return CMD_SUCCESS;
5016 }
5017
5018 DEFUN (no_set_lcommunity_delete,
5019 no_set_lcommunity_delete_cmd,
5020 "no set large-comm-list <(1-99)|(100-500)|WORD> [delete]",
5021 NO_STR
5022 SET_STR
5023 "set BGP large community list (for deletion)\n"
5024 "Large Community-list number (standard)\n"
5025 "Large Communitly-list number (expanded)\n"
5026 "Large Community-list name\n"
5027 "Delete matching large communities\n")
5028 {
5029 return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index),
5030 "large-comm-list", NULL);
5031 }
5032
5033 ALIAS (no_set_lcommunity_delete,
5034 no_set_lcommunity_delete_short_cmd,
5035 "no set large-comm-list",
5036 NO_STR
5037 SET_STR
5038 "set BGP large community list (for deletion)\n")
5039
5040 DEFUN (set_ecommunity_rt,
5041 set_ecommunity_rt_cmd,
5042 "set extcommunity rt ASN:NN_OR_IP-ADDRESS:NN...",
5043 SET_STR
5044 "BGP extended community attribute\n"
5045 "Route Target extended community\n"
5046 "VPN extended community\n")
5047 {
5048 int idx_asn_nn = 3;
5049 int ret;
5050 char *str;
5051
5052 str = argv_concat(argv, argc, idx_asn_nn);
5053 ret = generic_set_add(vty, VTY_GET_CONTEXT(route_map_index),
5054 "extcommunity rt", str);
5055 XFREE(MTYPE_TMP, str);
5056
5057 return ret;
5058 }
5059
5060 DEFUN (no_set_ecommunity_rt,
5061 no_set_ecommunity_rt_cmd,
5062 "no set extcommunity rt ASN:NN_OR_IP-ADDRESS:NN...",
5063 NO_STR
5064 SET_STR
5065 "BGP extended community attribute\n"
5066 "Route Target extended community\n"
5067 "VPN extended community\n")
5068 {
5069 return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index),
5070 "extcommunity rt", NULL);
5071 }
5072
5073 ALIAS (no_set_ecommunity_rt,
5074 no_set_ecommunity_rt_short_cmd,
5075 "no set extcommunity rt",
5076 NO_STR
5077 SET_STR
5078 "BGP extended community attribute\n"
5079 "Route Target extended community\n")
5080
5081 DEFUN (set_ecommunity_soo,
5082 set_ecommunity_soo_cmd,
5083 "set extcommunity soo ASN:NN_OR_IP-ADDRESS:NN...",
5084 SET_STR
5085 "BGP extended community attribute\n"
5086 "Site-of-Origin extended community\n"
5087 "VPN extended community\n")
5088 {
5089 int idx_asn_nn = 3;
5090 int ret;
5091 char *str;
5092
5093 str = argv_concat(argv, argc, idx_asn_nn);
5094 ret = generic_set_add(vty, VTY_GET_CONTEXT(route_map_index),
5095 "extcommunity soo", str);
5096 XFREE(MTYPE_TMP, str);
5097 return ret;
5098 }
5099
5100
5101 DEFUN (no_set_ecommunity_soo,
5102 no_set_ecommunity_soo_cmd,
5103 "no set extcommunity soo ASN:NN_OR_IP-ADDRESS:NN...",
5104 NO_STR
5105 SET_STR
5106 "BGP extended community attribute\n"
5107 "Site-of-Origin extended community\n"
5108 "VPN extended community\n")
5109 {
5110 return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index),
5111 "extcommunity soo", NULL);
5112 }
5113
5114 ALIAS (no_set_ecommunity_soo,
5115 no_set_ecommunity_soo_short_cmd,
5116 "no set extcommunity soo",
5117 NO_STR
5118 SET_STR
5119 "GP extended community attribute\n"
5120 "Site-of-Origin extended community\n")
5121
5122 DEFUN (set_ecommunity_lb,
5123 set_ecommunity_lb_cmd,
5124 "set extcommunity bandwidth <(1-25600)|cumulative|num-multipaths> [non-transitive]",
5125 SET_STR
5126 "BGP extended community attribute\n"
5127 "Link bandwidth extended community\n"
5128 "Bandwidth value in Mbps\n"
5129 "Cumulative bandwidth of all multipaths (outbound-only)\n"
5130 "Internally computed bandwidth based on number of multipaths (outbound-only)\n"
5131 "Attribute is set as non-transitive\n")
5132 {
5133 int idx_lb = 3;
5134 int ret;
5135 char *str;
5136
5137 str = argv_concat(argv, argc, idx_lb);
5138 ret = generic_set_add(vty, VTY_GET_CONTEXT(route_map_index),
5139 "extcommunity bandwidth", str);
5140 XFREE(MTYPE_TMP, str);
5141 return ret;
5142 }
5143
5144
5145 DEFUN (no_set_ecommunity_lb,
5146 no_set_ecommunity_lb_cmd,
5147 "no set extcommunity bandwidth <(1-25600)|cumulative|num-multipaths> [non-transitive]",
5148 NO_STR
5149 SET_STR
5150 "BGP extended community attribute\n"
5151 "Link bandwidth extended community\n"
5152 "Bandwidth value in Mbps\n"
5153 "Cumulative bandwidth of all multipaths (outbound-only)\n"
5154 "Internally computed bandwidth based on number of multipaths (outbound-only)\n"
5155 "Attribute is set as non-transitive\n")
5156 {
5157 return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index),
5158 "extcommunity bandwidth", NULL);
5159 }
5160
5161 ALIAS (no_set_ecommunity_lb,
5162 no_set_ecommunity_lb_short_cmd,
5163 "no set extcommunity bandwidth",
5164 NO_STR
5165 SET_STR
5166 "BGP extended community attribute\n"
5167 "Link bandwidth extended community\n")
5168
5169 DEFUN (set_origin,
5170 set_origin_cmd,
5171 "set origin <egp|igp|incomplete>",
5172 SET_STR
5173 "BGP origin code\n"
5174 "remote EGP\n"
5175 "local IGP\n"
5176 "unknown heritage\n")
5177 {
5178 int idx_origin = 2;
5179 if (strncmp(argv[idx_origin]->arg, "igp", 2) == 0)
5180 return generic_set_add(vty, VTY_GET_CONTEXT(route_map_index),
5181 "origin", "igp");
5182 if (strncmp(argv[idx_origin]->arg, "egp", 1) == 0)
5183 return generic_set_add(vty, VTY_GET_CONTEXT(route_map_index),
5184 "origin", "egp");
5185 if (strncmp(argv[idx_origin]->arg, "incomplete", 2) == 0)
5186 return generic_set_add(vty, VTY_GET_CONTEXT(route_map_index),
5187 "origin", "incomplete");
5188
5189 vty_out(vty, "%% Invalid set origin type\n");
5190 return CMD_WARNING_CONFIG_FAILED;
5191 }
5192
5193
5194 DEFUN (no_set_origin,
5195 no_set_origin_cmd,
5196 "no set origin [<egp|igp|incomplete>]",
5197 NO_STR
5198 SET_STR
5199 "BGP origin code\n"
5200 "remote EGP\n"
5201 "local IGP\n"
5202 "unknown heritage\n")
5203 {
5204 return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index),
5205 "origin", NULL);
5206 }
5207
5208
5209 DEFUN (set_atomic_aggregate,
5210 set_atomic_aggregate_cmd,
5211 "set atomic-aggregate",
5212 SET_STR
5213 "BGP atomic aggregate attribute\n" )
5214 {
5215 return generic_set_add(vty, VTY_GET_CONTEXT(route_map_index),
5216 "atomic-aggregate", NULL);
5217 }
5218
5219 DEFUN (no_set_atomic_aggregate,
5220 no_set_atomic_aggregate_cmd,
5221 "no set atomic-aggregate",
5222 NO_STR
5223 SET_STR
5224 "BGP atomic aggregate attribute\n" )
5225 {
5226 return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index),
5227 "atomic-aggregate", NULL);
5228 }
5229
5230 DEFUN (set_aggregator_as,
5231 set_aggregator_as_cmd,
5232 "set aggregator as (1-4294967295) A.B.C.D",
5233 SET_STR
5234 "BGP aggregator attribute\n"
5235 "AS number of aggregator\n"
5236 "AS number\n"
5237 "IP address of aggregator\n")
5238 {
5239 int idx_number = 3;
5240 int idx_ipv4 = 4;
5241 int ret;
5242 struct in_addr address;
5243 char *argstr;
5244
5245 ret = inet_aton(argv[idx_ipv4]->arg, &address);
5246 if (ret == 0) {
5247 vty_out(vty, "Aggregator IP address is invalid\n");
5248 return CMD_WARNING_CONFIG_FAILED;
5249 }
5250
5251 argstr = XMALLOC(MTYPE_ROUTE_MAP_COMPILED,
5252 strlen(argv[idx_number]->arg)
5253 + strlen(argv[idx_ipv4]->arg) + 2);
5254
5255 sprintf(argstr, "%s %s", argv[idx_number]->arg, argv[idx_ipv4]->arg);
5256
5257 ret = generic_set_add(vty, VTY_GET_CONTEXT(route_map_index),
5258 "aggregator as", argstr);
5259
5260 XFREE(MTYPE_ROUTE_MAP_COMPILED, argstr);
5261
5262 return ret;
5263 }
5264
5265
5266 DEFUN (no_set_aggregator_as,
5267 no_set_aggregator_as_cmd,
5268 "no set aggregator as [(1-4294967295) A.B.C.D]",
5269 NO_STR
5270 SET_STR
5271 "BGP aggregator attribute\n"
5272 "AS number of aggregator\n"
5273 "AS number\n"
5274 "IP address of aggregator\n")
5275 {
5276 int idx_asn = 4;
5277 int idx_ip = 5;
5278 int ret;
5279 struct in_addr address;
5280 char *argstr;
5281
5282 if (argc <= idx_asn)
5283 return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index),
5284 "aggregator as", NULL);
5285
5286 ret = inet_aton(argv[idx_ip]->arg, &address);
5287 if (ret == 0) {
5288 vty_out(vty, "Aggregator IP address is invalid\n");
5289 return CMD_WARNING_CONFIG_FAILED;
5290 }
5291
5292 argstr = XMALLOC(MTYPE_ROUTE_MAP_COMPILED,
5293 strlen(argv[idx_asn]->arg) + strlen(argv[idx_ip]->arg)
5294 + 2);
5295
5296 sprintf(argstr, "%s %s", argv[idx_asn]->arg, argv[idx_ip]->arg);
5297
5298 ret = generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index),
5299 "aggregator as", argstr);
5300
5301 XFREE(MTYPE_ROUTE_MAP_COMPILED, argstr);
5302
5303 return ret;
5304 }
5305
5306 DEFUN (match_ipv6_next_hop,
5307 match_ipv6_next_hop_cmd,
5308 "match ipv6 next-hop X:X::X:X",
5309 MATCH_STR
5310 IPV6_STR
5311 "Match IPv6 next-hop address of route\n"
5312 "IPv6 address of next hop\n")
5313 {
5314 int idx_ipv6 = 3;
5315 return bgp_route_match_add(vty, "ipv6 next-hop", argv[idx_ipv6]->arg,
5316 RMAP_EVENT_MATCH_ADDED);
5317 }
5318
5319 DEFUN (no_match_ipv6_next_hop,
5320 no_match_ipv6_next_hop_cmd,
5321 "no match ipv6 next-hop X:X::X:X",
5322 NO_STR
5323 MATCH_STR
5324 IPV6_STR
5325 "Match IPv6 next-hop address of route\n"
5326 "IPv6 address of next hop\n")
5327 {
5328 int idx_ipv6 = 4;
5329 return bgp_route_match_delete(vty, "ipv6 next-hop", argv[idx_ipv6]->arg,
5330 RMAP_EVENT_MATCH_DELETED);
5331 }
5332
5333 DEFPY (match_ipv4_next_hop,
5334 match_ipv4_next_hop_cmd,
5335 "match ip next-hop address A.B.C.D",
5336 MATCH_STR
5337 IP_STR
5338 "Match IP next-hop address of route\n"
5339 "IP address\n"
5340 "IP address of next-hop\n")
5341 {
5342 int idx_ipv4 = 4;
5343
5344 return bgp_route_match_add(vty, "ip next-hop address",
5345 argv[idx_ipv4]->arg, RMAP_EVENT_MATCH_ADDED);
5346 }
5347
5348 DEFPY (no_match_ipv4_next_hop,
5349 no_match_ipv4_next_hop_cmd,
5350 "no match ip next-hop address [A.B.C.D]",
5351 NO_STR
5352 MATCH_STR
5353 IP_STR
5354 "Match IP next-hop address of route\n"
5355 "IP address\n"
5356 "IP address of next-hop\n")
5357 {
5358 return bgp_route_match_delete(vty, "ip next-hop address", NULL,
5359 RMAP_EVENT_MATCH_DELETED);
5360 }
5361
5362 DEFUN (set_ipv6_nexthop_peer,
5363 set_ipv6_nexthop_peer_cmd,
5364 "set ipv6 next-hop peer-address",
5365 SET_STR
5366 IPV6_STR
5367 "Next hop address\n"
5368 "Use peer address (for BGP only)\n")
5369 {
5370 return generic_set_add(vty, VTY_GET_CONTEXT(route_map_index),
5371 "ipv6 next-hop peer-address", NULL);
5372 }
5373
5374 DEFUN (no_set_ipv6_nexthop_peer,
5375 no_set_ipv6_nexthop_peer_cmd,
5376 "no set ipv6 next-hop peer-address",
5377 NO_STR
5378 SET_STR
5379 IPV6_STR
5380 "IPv6 next-hop address\n"
5381 "Use peer address (for BGP only)\n")
5382 {
5383 return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index),
5384 "ipv6 next-hop peer-address", NULL);
5385 }
5386
5387 DEFUN (set_ipv6_nexthop_prefer_global,
5388 set_ipv6_nexthop_prefer_global_cmd,
5389 "set ipv6 next-hop prefer-global",
5390 SET_STR
5391 IPV6_STR
5392 "IPv6 next-hop address\n"
5393 "Prefer global over link-local if both exist\n")
5394 {
5395 return generic_set_add(vty, VTY_GET_CONTEXT(route_map_index),
5396 "ipv6 next-hop prefer-global", NULL);
5397 ;
5398 }
5399
5400 DEFUN (no_set_ipv6_nexthop_prefer_global,
5401 no_set_ipv6_nexthop_prefer_global_cmd,
5402 "no set ipv6 next-hop prefer-global",
5403 NO_STR
5404 SET_STR
5405 IPV6_STR
5406 "IPv6 next-hop address\n"
5407 "Prefer global over link-local if both exist\n")
5408 {
5409 return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index),
5410 "ipv6 next-hop prefer-global", NULL);
5411 }
5412
5413 DEFUN (set_ipv6_nexthop_global,
5414 set_ipv6_nexthop_global_cmd,
5415 "set ipv6 next-hop global X:X::X:X",
5416 SET_STR
5417 IPV6_STR
5418 "IPv6 next-hop address\n"
5419 "IPv6 global address\n"
5420 "IPv6 address of next hop\n")
5421 {
5422 int idx_ipv6 = 4;
5423 struct in6_addr addr;
5424 int ret;
5425
5426 ret = inet_pton(AF_INET6, argv[idx_ipv6]->arg, &addr);
5427 if (!ret) {
5428 vty_out(vty, "%% Malformed nexthop address\n");
5429 return CMD_WARNING_CONFIG_FAILED;
5430 }
5431 if (IN6_IS_ADDR_UNSPECIFIED(&addr) || IN6_IS_ADDR_LOOPBACK(&addr)
5432 || IN6_IS_ADDR_MULTICAST(&addr) || IN6_IS_ADDR_LINKLOCAL(&addr)) {
5433 vty_out(vty, "%% Invalid global nexthop address\n");
5434 return CMD_WARNING_CONFIG_FAILED;
5435 }
5436
5437 return generic_set_add(vty, VTY_GET_CONTEXT(route_map_index),
5438 "ipv6 next-hop global", argv[idx_ipv6]->arg);
5439 }
5440
5441
5442 DEFUN (no_set_ipv6_nexthop_global,
5443 no_set_ipv6_nexthop_global_cmd,
5444 "no set ipv6 next-hop global X:X::X:X",
5445 NO_STR
5446 SET_STR
5447 IPV6_STR
5448 "IPv6 next-hop address\n"
5449 "IPv6 global address\n"
5450 "IPv6 address of next hop\n")
5451 {
5452 int idx_ipv6 = 5;
5453 if (argc <= idx_ipv6)
5454 return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index),
5455 "ipv6 next-hop global", NULL);
5456 return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index),
5457 "ipv6 next-hop global", argv[idx_ipv6]->arg);
5458 }
5459
5460 #ifdef KEEP_OLD_VPN_COMMANDS
5461 DEFUN (set_vpn_nexthop,
5462 set_vpn_nexthop_cmd,
5463 "set <vpnv4 next-hop A.B.C.D|vpnv6 next-hop X:X::X:X>",
5464 SET_STR
5465 "VPNv4 information\n"
5466 "VPN next-hop address\n"
5467 "IP address of next hop\n"
5468 "VPNv6 information\n"
5469 "VPN next-hop address\n"
5470 "IPv6 address of next hop\n")
5471 {
5472 int idx_ip = 3;
5473 afi_t afi;
5474 int idx = 0;
5475
5476 if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) {
5477 if (afi == AFI_IP)
5478 return generic_set_add(
5479 vty, VTY_GET_CONTEXT(route_map_index),
5480 "ipv4 vpn next-hop", argv[idx_ip]->arg);
5481 else
5482 return generic_set_add(
5483 vty, VTY_GET_CONTEXT(route_map_index),
5484 "ipv6 vpn next-hop", argv[idx_ip]->arg);
5485 }
5486 return CMD_SUCCESS;
5487 }
5488
5489 DEFUN (no_set_vpn_nexthop,
5490 no_set_vpn_nexthop_cmd,
5491 "no set <vpnv4 next-hop A.B.C.D|vpnv6 next-hop X:X::X:X>",
5492 NO_STR
5493 SET_STR
5494 "VPNv4 information\n"
5495 "VPN next-hop address\n"
5496 "IP address of next hop\n"
5497 "VPNv6 information\n"
5498 "VPN next-hop address\n"
5499 "IPv6 address of next hop\n")
5500 {
5501 int idx_ip = 4;
5502 char *arg;
5503 afi_t afi;
5504 int idx = 0;
5505
5506 if (argc <= idx_ip)
5507 arg = NULL;
5508 else
5509 arg = argv[idx_ip]->arg;
5510 if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) {
5511 if (afi == AFI_IP)
5512 return generic_set_delete(
5513 vty, VTY_GET_CONTEXT(route_map_index),
5514 "ipv4 vpn next-hop", arg);
5515 else
5516 return generic_set_delete(
5517 vty, VTY_GET_CONTEXT(route_map_index),
5518 "ipv6 vpn next-hop", argv[idx_ip]->arg);
5519 }
5520 return CMD_SUCCESS;
5521 }
5522 #endif /* KEEP_OLD_VPN_COMMANDS */
5523
5524 DEFUN (set_ipx_vpn_nexthop,
5525 set_ipx_vpn_nexthop_cmd,
5526 "set <ipv4|ipv6> vpn next-hop <A.B.C.D|X:X::X:X>",
5527 SET_STR
5528 "IPv4 information\n"
5529 "IPv6 information\n"
5530 "VPN information\n"
5531 "VPN next-hop address\n"
5532 "IP address of next hop\n"
5533 "IPv6 address of next hop\n")
5534 {
5535 int idx_ip = 4;
5536 afi_t afi;
5537 int idx = 0;
5538
5539 if (argv_find_and_parse_afi(argv, argc, &idx, &afi)) {
5540 if (afi == AFI_IP)
5541 return generic_set_add(
5542 vty, VTY_GET_CONTEXT(route_map_index),
5543 "ipv4 vpn next-hop", argv[idx_ip]->arg);
5544 else
5545 return generic_set_add(
5546 vty, VTY_GET_CONTEXT(route_map_index),
5547 "ipv6 vpn next-hop", argv[idx_ip]->arg);
5548 }
5549 return CMD_SUCCESS;
5550 }
5551
5552 DEFUN (no_set_ipx_vpn_nexthop,
5553 no_set_ipx_vpn_nexthop_cmd,
5554 "no set <ipv4|ipv6> vpn next-hop [<A.B.C.D|X:X::X:X>]",
5555 NO_STR
5556 SET_STR
5557 "IPv4 information\n"
5558 "IPv6 information\n"
5559 "VPN information\n"
5560 "VPN next-hop address\n"
5561 "IP address of next hop\n"
5562 "IPv6 address of next hop\n")
5563 {
5564 int idx_ip = 5;
5565 char *arg;
5566 afi_t afi;
5567 int idx = 0;
5568
5569 if (argc <= idx_ip)
5570 arg = NULL;
5571 else
5572 arg = argv[idx_ip]->arg;
5573 if (argv_find_and_parse_afi(argv, argc, &idx, &afi)) {
5574 if (afi == AFI_IP)
5575 return generic_set_delete(
5576 vty, VTY_GET_CONTEXT(route_map_index),
5577 "ipv4 vpn next-hop", arg);
5578 else
5579 return generic_set_delete(
5580 vty, VTY_GET_CONTEXT(route_map_index),
5581 "ipv6 vpn next-hop", arg);
5582 }
5583 return CMD_SUCCESS;
5584 }
5585
5586 DEFUN (set_originator_id,
5587 set_originator_id_cmd,
5588 "set originator-id A.B.C.D",
5589 SET_STR
5590 "BGP originator ID attribute\n"
5591 "IP address of originator\n")
5592 {
5593 int idx_ipv4 = 2;
5594 return generic_set_add(vty, VTY_GET_CONTEXT(route_map_index),
5595 "originator-id", argv[idx_ipv4]->arg);
5596 }
5597
5598
5599 DEFUN (no_set_originator_id,
5600 no_set_originator_id_cmd,
5601 "no set originator-id [A.B.C.D]",
5602 NO_STR
5603 SET_STR
5604 "BGP originator ID attribute\n"
5605 "IP address of originator\n")
5606 {
5607 int idx = 0;
5608 char *arg =
5609 argv_find(argv, argc, "A.B.C.D", &idx) ? argv[idx]->arg : NULL;
5610
5611 return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index),
5612 "originator-id", arg);
5613 }
5614
5615
5616 /* Initialization of route map. */
5617 void bgp_route_map_init(void)
5618 {
5619 route_map_init();
5620
5621 route_map_add_hook(bgp_route_map_add);
5622 route_map_delete_hook(bgp_route_map_delete);
5623 route_map_event_hook(bgp_route_map_event);
5624
5625 route_map_match_interface_hook(generic_match_add);
5626 route_map_no_match_interface_hook(generic_match_delete);
5627
5628 route_map_match_ip_address_hook(generic_match_add);
5629 route_map_no_match_ip_address_hook(generic_match_delete);
5630
5631 route_map_match_ip_address_prefix_list_hook(generic_match_add);
5632 route_map_no_match_ip_address_prefix_list_hook(generic_match_delete);
5633
5634 route_map_match_ip_next_hop_hook(generic_match_add);
5635 route_map_no_match_ip_next_hop_hook(generic_match_delete);
5636
5637 route_map_match_ip_next_hop_prefix_list_hook(generic_match_add);
5638 route_map_no_match_ip_next_hop_prefix_list_hook(generic_match_delete);
5639
5640 route_map_match_ip_next_hop_type_hook(generic_match_add);
5641 route_map_no_match_ip_next_hop_type_hook(generic_match_delete);
5642
5643 route_map_match_ipv6_address_hook(generic_match_add);
5644 route_map_no_match_ipv6_address_hook(generic_match_delete);
5645
5646 route_map_match_ipv6_address_prefix_list_hook(generic_match_add);
5647 route_map_no_match_ipv6_address_prefix_list_hook(generic_match_delete);
5648
5649 route_map_match_ipv6_next_hop_type_hook(generic_match_add);
5650 route_map_no_match_ipv6_next_hop_type_hook(generic_match_delete);
5651
5652 route_map_match_metric_hook(generic_match_add);
5653 route_map_no_match_metric_hook(generic_match_delete);
5654
5655 route_map_match_tag_hook(generic_match_add);
5656 route_map_no_match_tag_hook(generic_match_delete);
5657
5658 route_map_set_srte_color_hook(generic_set_add);
5659 route_map_no_set_srte_color_hook(generic_set_delete);
5660
5661 route_map_set_ip_nexthop_hook(generic_set_add);
5662 route_map_no_set_ip_nexthop_hook(generic_set_delete);
5663
5664 route_map_set_ipv6_nexthop_local_hook(generic_set_add);
5665 route_map_no_set_ipv6_nexthop_local_hook(generic_set_delete);
5666
5667 route_map_set_metric_hook(generic_set_add);
5668 route_map_no_set_metric_hook(generic_set_delete);
5669
5670 route_map_set_tag_hook(generic_set_add);
5671 route_map_no_set_tag_hook(generic_set_delete);
5672
5673 route_map_install_match(&route_match_peer_cmd);
5674 route_map_install_match(&route_match_local_pref_cmd);
5675 #ifdef HAVE_SCRIPTING
5676 route_map_install_match(&route_match_script_cmd);
5677 #endif
5678 route_map_install_match(&route_match_ip_address_cmd);
5679 route_map_install_match(&route_match_ip_next_hop_cmd);
5680 route_map_install_match(&route_match_ip_route_source_cmd);
5681 route_map_install_match(&route_match_ip_address_prefix_list_cmd);
5682 route_map_install_match(&route_match_ip_next_hop_prefix_list_cmd);
5683 route_map_install_match(&route_match_ip_next_hop_type_cmd);
5684 route_map_install_match(&route_match_ip_route_source_prefix_list_cmd);
5685 route_map_install_match(&route_match_aspath_cmd);
5686 route_map_install_match(&route_match_community_cmd);
5687 route_map_install_match(&route_match_lcommunity_cmd);
5688 route_map_install_match(&route_match_ecommunity_cmd);
5689 route_map_install_match(&route_match_local_pref_cmd);
5690 route_map_install_match(&route_match_metric_cmd);
5691 route_map_install_match(&route_match_origin_cmd);
5692 route_map_install_match(&route_match_probability_cmd);
5693 route_map_install_match(&route_match_interface_cmd);
5694 route_map_install_match(&route_match_tag_cmd);
5695 route_map_install_match(&route_match_mac_address_cmd);
5696 route_map_install_match(&route_match_evpn_vni_cmd);
5697 route_map_install_match(&route_match_evpn_route_type_cmd);
5698 route_map_install_match(&route_match_evpn_rd_cmd);
5699 route_map_install_match(&route_match_evpn_default_route_cmd);
5700 route_map_install_match(&route_match_vrl_source_vrf_cmd);
5701
5702 route_map_install_set(&route_set_table_id_cmd);
5703 route_map_install_set(&route_set_srte_color_cmd);
5704 route_map_install_set(&route_set_ip_nexthop_cmd);
5705 route_map_install_set(&route_set_local_pref_cmd);
5706 route_map_install_set(&route_set_weight_cmd);
5707 route_map_install_set(&route_set_label_index_cmd);
5708 route_map_install_set(&route_set_metric_cmd);
5709 route_map_install_set(&route_set_distance_cmd);
5710 route_map_install_set(&route_set_aspath_prepend_cmd);
5711 route_map_install_set(&route_set_aspath_exclude_cmd);
5712 route_map_install_set(&route_set_origin_cmd);
5713 route_map_install_set(&route_set_atomic_aggregate_cmd);
5714 route_map_install_set(&route_set_aggregator_as_cmd);
5715 route_map_install_set(&route_set_community_cmd);
5716 route_map_install_set(&route_set_community_delete_cmd);
5717 route_map_install_set(&route_set_lcommunity_cmd);
5718 route_map_install_set(&route_set_lcommunity_delete_cmd);
5719 route_map_install_set(&route_set_vpnv4_nexthop_cmd);
5720 route_map_install_set(&route_set_vpnv6_nexthop_cmd);
5721 route_map_install_set(&route_set_originator_id_cmd);
5722 route_map_install_set(&route_set_ecommunity_rt_cmd);
5723 route_map_install_set(&route_set_ecommunity_soo_cmd);
5724 route_map_install_set(&route_set_ecommunity_lb_cmd);
5725 route_map_install_set(&route_set_tag_cmd);
5726 route_map_install_set(&route_set_label_index_cmd);
5727
5728 install_element(RMAP_NODE, &match_peer_cmd);
5729 install_element(RMAP_NODE, &match_peer_local_cmd);
5730 install_element(RMAP_NODE, &no_match_peer_cmd);
5731 install_element(RMAP_NODE, &match_ip_route_source_cmd);
5732 install_element(RMAP_NODE, &no_match_ip_route_source_cmd);
5733 install_element(RMAP_NODE, &match_ip_route_source_prefix_list_cmd);
5734 install_element(RMAP_NODE, &no_match_ip_route_source_prefix_list_cmd);
5735 install_element(RMAP_NODE, &match_mac_address_cmd);
5736 install_element(RMAP_NODE, &no_match_mac_address_cmd);
5737 install_element(RMAP_NODE, &match_evpn_vni_cmd);
5738 install_element(RMAP_NODE, &no_match_evpn_vni_cmd);
5739 install_element(RMAP_NODE, &match_evpn_route_type_cmd);
5740 install_element(RMAP_NODE, &no_match_evpn_route_type_cmd);
5741 install_element(RMAP_NODE, &match_evpn_rd_cmd);
5742 install_element(RMAP_NODE, &no_match_evpn_rd_cmd);
5743 install_element(RMAP_NODE, &match_evpn_default_route_cmd);
5744 install_element(RMAP_NODE, &no_match_evpn_default_route_cmd);
5745 install_element(RMAP_NODE, &match_vrl_source_vrf_cmd);
5746 install_element(RMAP_NODE, &no_match_vrl_source_vrf_cmd);
5747
5748 install_element(RMAP_NODE, &match_aspath_cmd);
5749 install_element(RMAP_NODE, &no_match_aspath_cmd);
5750 install_element(RMAP_NODE, &match_local_pref_cmd);
5751 install_element(RMAP_NODE, &no_match_local_pref_cmd);
5752 install_element(RMAP_NODE, &match_community_cmd);
5753 install_element(RMAP_NODE, &no_match_community_cmd);
5754 install_element(RMAP_NODE, &match_lcommunity_cmd);
5755 install_element(RMAP_NODE, &no_match_lcommunity_cmd);
5756 install_element(RMAP_NODE, &match_ecommunity_cmd);
5757 install_element(RMAP_NODE, &no_match_ecommunity_cmd);
5758 install_element(RMAP_NODE, &match_origin_cmd);
5759 install_element(RMAP_NODE, &no_match_origin_cmd);
5760 install_element(RMAP_NODE, &match_probability_cmd);
5761 install_element(RMAP_NODE, &no_match_probability_cmd);
5762
5763 install_element(RMAP_NODE, &no_set_table_id_cmd);
5764 install_element(RMAP_NODE, &set_table_id_cmd);
5765 install_element(RMAP_NODE, &set_ip_nexthop_peer_cmd);
5766 install_element(RMAP_NODE, &set_ip_nexthop_unchanged_cmd);
5767 install_element(RMAP_NODE, &set_local_pref_cmd);
5768 install_element(RMAP_NODE, &set_distance_cmd);
5769 install_element(RMAP_NODE, &no_set_distance_cmd);
5770 install_element(RMAP_NODE, &no_set_local_pref_cmd);
5771 install_element(RMAP_NODE, &set_weight_cmd);
5772 install_element(RMAP_NODE, &set_label_index_cmd);
5773 install_element(RMAP_NODE, &no_set_weight_cmd);
5774 install_element(RMAP_NODE, &no_set_label_index_cmd);
5775 install_element(RMAP_NODE, &set_aspath_prepend_asn_cmd);
5776 install_element(RMAP_NODE, &set_aspath_prepend_lastas_cmd);
5777 install_element(RMAP_NODE, &set_aspath_exclude_cmd);
5778 install_element(RMAP_NODE, &no_set_aspath_prepend_cmd);
5779 install_element(RMAP_NODE, &no_set_aspath_prepend_lastas_cmd);
5780 install_element(RMAP_NODE, &no_set_aspath_exclude_cmd);
5781 install_element(RMAP_NODE, &no_set_aspath_exclude_all_cmd);
5782 install_element(RMAP_NODE, &set_origin_cmd);
5783 install_element(RMAP_NODE, &no_set_origin_cmd);
5784 install_element(RMAP_NODE, &set_atomic_aggregate_cmd);
5785 install_element(RMAP_NODE, &no_set_atomic_aggregate_cmd);
5786 install_element(RMAP_NODE, &set_aggregator_as_cmd);
5787 install_element(RMAP_NODE, &no_set_aggregator_as_cmd);
5788 install_element(RMAP_NODE, &set_community_cmd);
5789 install_element(RMAP_NODE, &set_community_none_cmd);
5790 install_element(RMAP_NODE, &no_set_community_cmd);
5791 install_element(RMAP_NODE, &no_set_community_short_cmd);
5792 install_element(RMAP_NODE, &set_community_delete_cmd);
5793 install_element(RMAP_NODE, &no_set_community_delete_cmd);
5794 install_element(RMAP_NODE, &set_lcommunity_cmd);
5795 install_element(RMAP_NODE, &set_lcommunity_none_cmd);
5796 install_element(RMAP_NODE, &no_set_lcommunity_cmd);
5797 install_element(RMAP_NODE, &no_set_lcommunity1_cmd);
5798 install_element(RMAP_NODE, &no_set_lcommunity1_short_cmd);
5799 install_element(RMAP_NODE, &set_lcommunity_delete_cmd);
5800 install_element(RMAP_NODE, &no_set_lcommunity_delete_cmd);
5801 install_element(RMAP_NODE, &no_set_lcommunity_delete_short_cmd);
5802 install_element(RMAP_NODE, &set_ecommunity_rt_cmd);
5803 install_element(RMAP_NODE, &no_set_ecommunity_rt_cmd);
5804 install_element(RMAP_NODE, &no_set_ecommunity_rt_short_cmd);
5805 install_element(RMAP_NODE, &set_ecommunity_soo_cmd);
5806 install_element(RMAP_NODE, &no_set_ecommunity_soo_cmd);
5807 install_element(RMAP_NODE, &no_set_ecommunity_soo_short_cmd);
5808 install_element(RMAP_NODE, &set_ecommunity_lb_cmd);
5809 install_element(RMAP_NODE, &no_set_ecommunity_lb_cmd);
5810 install_element(RMAP_NODE, &no_set_ecommunity_lb_short_cmd);
5811 #ifdef KEEP_OLD_VPN_COMMANDS
5812 install_element(RMAP_NODE, &set_vpn_nexthop_cmd);
5813 install_element(RMAP_NODE, &no_set_vpn_nexthop_cmd);
5814 #endif /* KEEP_OLD_VPN_COMMANDS */
5815 install_element(RMAP_NODE, &set_ipx_vpn_nexthop_cmd);
5816 install_element(RMAP_NODE, &no_set_ipx_vpn_nexthop_cmd);
5817 install_element(RMAP_NODE, &set_originator_id_cmd);
5818 install_element(RMAP_NODE, &no_set_originator_id_cmd);
5819
5820 route_map_install_match(&route_match_ipv6_address_cmd);
5821 route_map_install_match(&route_match_ipv6_next_hop_cmd);
5822 route_map_install_match(&route_match_ipv4_next_hop_cmd);
5823 route_map_install_match(&route_match_ipv6_address_prefix_list_cmd);
5824 route_map_install_match(&route_match_ipv6_next_hop_type_cmd);
5825 route_map_install_set(&route_set_ipv6_nexthop_global_cmd);
5826 route_map_install_set(&route_set_ipv6_nexthop_prefer_global_cmd);
5827 route_map_install_set(&route_set_ipv6_nexthop_local_cmd);
5828 route_map_install_set(&route_set_ipv6_nexthop_peer_cmd);
5829
5830 install_element(RMAP_NODE, &match_ipv6_next_hop_cmd);
5831 install_element(RMAP_NODE, &no_match_ipv6_next_hop_cmd);
5832 install_element(RMAP_NODE, &match_ipv4_next_hop_cmd);
5833 install_element(RMAP_NODE, &no_match_ipv4_next_hop_cmd);
5834 install_element(RMAP_NODE, &set_ipv6_nexthop_global_cmd);
5835 install_element(RMAP_NODE, &no_set_ipv6_nexthop_global_cmd);
5836 install_element(RMAP_NODE, &set_ipv6_nexthop_prefer_global_cmd);
5837 install_element(RMAP_NODE, &no_set_ipv6_nexthop_prefer_global_cmd);
5838 install_element(RMAP_NODE, &set_ipv6_nexthop_peer_cmd);
5839 install_element(RMAP_NODE, &no_set_ipv6_nexthop_peer_cmd);
5840 #ifdef HAVE_SCRIPTING
5841 install_element(RMAP_NODE, &match_script_cmd);
5842 #endif
5843 }
5844
5845 void bgp_route_map_terminate(void)
5846 {
5847 /* ToDo: Cleanup all the used memory */
5848 route_map_finish();
5849 }