1 /* Route map function.
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
17 along with GNU Zebra; see the file COPYING.  If not, write to the Free
18 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 02111-1307, USA.  */
20 
21 #include <zebra.h>
22 
23 #include "linklist.h"
24 #include "memory.h"
25 #include "vector.h"
26 #include "prefix.h"
27 #include "routemap.h"
28 #include "command.h"
29 #include "vty.h"
30 #include "log.h"
31 
32 /* Vector for route match rules. */
33 static vector route_match_vec;
34 
35 /* Vector for route set rules. */
36 static vector route_set_vec;
37 
38 /* Route map rule. This rule has both `match' rule and `set' rule. */
39 struct route_map_rule
40 {
41   /* Rule type. */
42   struct route_map_rule_cmd *cmd;
43 
44   /* For pretty printing. */
45   char *rule_str;
46 
47   /* Pre-compiled match rule. */
48   void *value;
49 
50   /* Linked list. */
51   struct route_map_rule *next;
52   struct route_map_rule *prev;
53 };
54 
55 /* Making route map list. */
56 struct route_map_list
57 {
58   struct route_map *head;
59   struct route_map *tail;
60 
61   void (*add_hook) (const char *);
62   void (*delete_hook) (const char *);
63   void (*event_hook) (route_map_event_t, const char *);
64 };
65 
66 /* Master list of route map. */
67 static struct route_map_list route_map_master = { NULL, NULL, NULL, NULL };
68 
69 static void
70 route_map_rule_delete (struct route_map_rule_list *,
71 		       struct route_map_rule *);
72 
73 static void
74 route_map_index_delete (struct route_map_index *, int);
75 
76 /* New route map allocation. Please note route map's name must be
77    specified. */
78 static struct route_map *
route_map_new(const char * name)79 route_map_new (const char *name)
80 {
81   struct route_map *new;
82 
83   new =  XCALLOC (MTYPE_ROUTE_MAP, sizeof (struct route_map));
84   new->name = XSTRDUP (MTYPE_ROUTE_MAP_NAME, name);
85   return new;
86 }
87 
88 /* Add new name to route_map. */
89 static struct route_map *
route_map_add(const char * name)90 route_map_add (const char *name)
91 {
92   struct route_map *map;
93   struct route_map_list *list;
94 
95   map = route_map_new (name);
96   list = &route_map_master;
97 
98   map->next = NULL;
99   map->prev = list->tail;
100   if (list->tail)
101     list->tail->next = map;
102   else
103     list->head = map;
104   list->tail = map;
105 
106   /* Execute hook. */
107   if (route_map_master.add_hook)
108     (*route_map_master.add_hook) (name);
109 
110   return map;
111 }
112 
113 /* Route map delete from list. */
114 static void
route_map_delete(struct route_map * map)115 route_map_delete (struct route_map *map)
116 {
117   struct route_map_list *list;
118   struct route_map_index *index;
119   char *name;
120 
121   while ((index = map->head) != NULL)
122     route_map_index_delete (index, 0);
123 
124   name = map->name;
125 
126   list = &route_map_master;
127 
128   if (map->next)
129     map->next->prev = map->prev;
130   else
131     list->tail = map->prev;
132 
133   if (map->prev)
134     map->prev->next = map->next;
135   else
136     list->head = map->next;
137 
138   XFREE (MTYPE_ROUTE_MAP, map);
139 
140   /* Execute deletion hook. */
141   if (route_map_master.delete_hook)
142     (*route_map_master.delete_hook) (name);
143 
144   if (name)
145     XFREE (MTYPE_ROUTE_MAP_NAME, name);
146 
147 }
148 
149 /* Lookup route map by route map name string. */
150 struct route_map *
route_map_lookup_by_name(const char * name)151 route_map_lookup_by_name (const char *name)
152 {
153   struct route_map *map;
154 
155   for (map = route_map_master.head; map; map = map->next)
156     if (strcmp (map->name, name) == 0)
157       return map;
158   return NULL;
159 }
160 
161 /* Lookup route map.  If there isn't route map create one and return
162    it. */
163 static struct route_map *
route_map_get(const char * name)164 route_map_get (const char *name)
165 {
166   struct route_map *map;
167 
168   map = route_map_lookup_by_name (name);
169   if (map == NULL)
170     map = route_map_add (name);
171   return map;
172 }
173 
174 /* Return route map's type string. */
175 static const char *
route_map_type_str(enum route_map_type type)176 route_map_type_str (enum route_map_type type)
177 {
178   switch (type)
179     {
180     case RMAP_PERMIT:
181       return "permit";
182       break;
183     case RMAP_DENY:
184       return "deny";
185       break;
186     default:
187       return "";
188       break;
189     }
190 }
191 
192 static int
route_map_empty(struct route_map * map)193 route_map_empty (struct route_map *map)
194 {
195   if (map->head == NULL && map->tail == NULL)
196     return 1;
197   else
198     return 0;
199 }
200 
201 /* show route-map */
202 static void
vty_show_route_map_entry(struct vty * vty,struct route_map * map)203 vty_show_route_map_entry (struct vty *vty, struct route_map *map)
204 {
205   struct route_map_index *index;
206   struct route_map_rule *rule;
207 
208   /* Print the name of the protocol */
209   if (zlog_default)
210     vty_out (vty, "%s:%s", zlog_proto_names[zlog_default->protocol],
211              VTY_NEWLINE);
212 
213   for (index = map->head; index; index = index->next)
214     {
215       vty_out (vty, "route-map %s, %s, sequence %d%s",
216                map->name, route_map_type_str (index->type),
217                index->pref, VTY_NEWLINE);
218 
219       /* Description */
220       if (index->description)
221 	vty_out (vty, "  Description:%s    %s%s", VTY_NEWLINE,
222 		 index->description, VTY_NEWLINE);
223 
224       /* Match clauses */
225       vty_out (vty, "  Match clauses:%s", VTY_NEWLINE);
226       for (rule = index->match_list.head; rule; rule = rule->next)
227         vty_out (vty, "    %s %s%s",
228                  rule->cmd->str, rule->rule_str, VTY_NEWLINE);
229 
230       vty_out (vty, "  Set clauses:%s", VTY_NEWLINE);
231       for (rule = index->set_list.head; rule; rule = rule->next)
232         vty_out (vty, "    %s %s%s",
233                  rule->cmd->str, rule->rule_str, VTY_NEWLINE);
234 
235       /* Call clause */
236       vty_out (vty, "  Call clause:%s", VTY_NEWLINE);
237       if (index->nextrm)
238         vty_out (vty, "    Call %s%s", index->nextrm, VTY_NEWLINE);
239 
240       /* Exit Policy */
241       vty_out (vty, "  Action:%s", VTY_NEWLINE);
242       if (index->exitpolicy == RMAP_GOTO)
243         vty_out (vty, "    Goto %d%s", index->nextpref, VTY_NEWLINE);
244       else if (index->exitpolicy == RMAP_NEXT)
245         vty_out (vty, "    Continue to next entry%s", VTY_NEWLINE);
246       else if (index->exitpolicy == RMAP_EXIT)
247         vty_out (vty, "    Exit routemap%s", VTY_NEWLINE);
248     }
249 }
250 
251 static int
vty_show_route_map(struct vty * vty,const char * name)252 vty_show_route_map (struct vty *vty, const char *name)
253 {
254   struct route_map *map;
255 
256   if (name)
257     {
258       map = route_map_lookup_by_name (name);
259 
260       if (map)
261         {
262           vty_show_route_map_entry (vty, map);
263           return CMD_SUCCESS;
264         }
265       else
266         {
267           vty_out (vty, "%%route-map %s not found%s", name, VTY_NEWLINE);
268           return CMD_WARNING;
269         }
270     }
271   else
272     {
273       for (map = route_map_master.head; map; map = map->next)
274 	vty_show_route_map_entry (vty, map);
275     }
276   return CMD_SUCCESS;
277 }
278 
279 
280 /* New route map allocation. Please note route map's name must be
281    specified. */
282 static struct route_map_index *
route_map_index_new(void)283 route_map_index_new (void)
284 {
285   struct route_map_index *new;
286 
287   new =  XCALLOC (MTYPE_ROUTE_MAP_INDEX, sizeof (struct route_map_index));
288   new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */
289   return new;
290 }
291 
292 /* Free route map index. */
293 static void
route_map_index_delete(struct route_map_index * index,int notify)294 route_map_index_delete (struct route_map_index *index, int notify)
295 {
296   struct route_map_rule *rule;
297 
298   /* Free route match. */
299   while ((rule = index->match_list.head) != NULL)
300     route_map_rule_delete (&index->match_list, rule);
301 
302   /* Free route set. */
303   while ((rule = index->set_list.head) != NULL)
304     route_map_rule_delete (&index->set_list, rule);
305 
306   /* Remove index from route map list. */
307   if (index->next)
308     index->next->prev = index->prev;
309   else
310     index->map->tail = index->prev;
311 
312   if (index->prev)
313     index->prev->next = index->next;
314   else
315     index->map->head = index->next;
316 
317   /* Free 'char *nextrm' if not NULL */
318   if (index->nextrm)
319     XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
320 
321     /* Execute event hook. */
322   if (route_map_master.event_hook && notify)
323     (*route_map_master.event_hook) (RMAP_EVENT_INDEX_DELETED,
324 				    index->map->name);
325 
326   XFREE (MTYPE_ROUTE_MAP_INDEX, index);
327 }
328 
329 /* Lookup index from route map. */
330 static struct route_map_index *
route_map_index_lookup(struct route_map * map,enum route_map_type type,int pref)331 route_map_index_lookup (struct route_map *map, enum route_map_type type,
332 			int pref)
333 {
334   struct route_map_index *index;
335 
336   for (index = map->head; index; index = index->next)
337     if ((index->type == type || type == RMAP_ANY)
338 	&& index->pref == pref)
339       return index;
340   return NULL;
341 }
342 
343 /* Add new index to route map. */
344 static struct route_map_index *
route_map_index_add(struct route_map * map,enum route_map_type type,int pref)345 route_map_index_add (struct route_map *map, enum route_map_type type,
346 		     int pref)
347 {
348   struct route_map_index *index;
349   struct route_map_index *point;
350 
351   /* Allocate new route map inex. */
352   index = route_map_index_new ();
353   index->map = map;
354   index->type = type;
355   index->pref = pref;
356 
357   /* Compare preference. */
358   for (point = map->head; point; point = point->next)
359     if (point->pref >= pref)
360       break;
361 
362   if (map->head == NULL)
363     {
364       map->head = map->tail = index;
365     }
366   else if (point == NULL)
367     {
368       index->prev = map->tail;
369       map->tail->next = index;
370       map->tail = index;
371     }
372   else if (point == map->head)
373     {
374       index->next = map->head;
375       map->head->prev = index;
376       map->head = index;
377     }
378   else
379     {
380       index->next = point;
381       index->prev = point->prev;
382       if (point->prev)
383 	point->prev->next = index;
384       point->prev = index;
385     }
386 
387   /* Execute event hook. */
388   if (route_map_master.event_hook)
389     (*route_map_master.event_hook) (RMAP_EVENT_INDEX_ADDED,
390 				    map->name);
391 
392   return index;
393 }
394 
395 /* Get route map index. */
396 static struct route_map_index *
route_map_index_get(struct route_map * map,enum route_map_type type,int pref)397 route_map_index_get (struct route_map *map, enum route_map_type type,
398 		     int pref)
399 {
400   struct route_map_index *index;
401 
402   index = route_map_index_lookup (map, RMAP_ANY, pref);
403   if (index && index->type != type)
404     {
405       /* Delete index from route map. */
406       route_map_index_delete (index, 1);
407       index = NULL;
408     }
409   if (index == NULL)
410     index = route_map_index_add (map, type, pref);
411   return index;
412 }
413 
414 /* New route map rule */
415 static struct route_map_rule *
route_map_rule_new(void)416 route_map_rule_new (void)
417 {
418   struct route_map_rule *new;
419 
420   new = XCALLOC (MTYPE_ROUTE_MAP_RULE, sizeof (struct route_map_rule));
421   return new;
422 }
423 
424 /* Install rule command to the match list. */
425 void
route_map_install_match(struct route_map_rule_cmd * cmd)426 route_map_install_match (struct route_map_rule_cmd *cmd)
427 {
428   vector_set (route_match_vec, cmd);
429 }
430 
431 /* Install rule command to the set list. */
432 void
route_map_install_set(struct route_map_rule_cmd * cmd)433 route_map_install_set (struct route_map_rule_cmd *cmd)
434 {
435   vector_set (route_set_vec, cmd);
436 }
437 
438 /* Lookup rule command from match list. */
439 static struct route_map_rule_cmd *
route_map_lookup_match(const char * name)440 route_map_lookup_match (const char *name)
441 {
442   unsigned int i;
443   struct route_map_rule_cmd *rule;
444 
445   for (i = 0; i < vector_active (route_match_vec); i++)
446     if ((rule = vector_slot (route_match_vec, i)) != NULL)
447       if (strcmp (rule->str, name) == 0)
448 	return rule;
449   return NULL;
450 }
451 
452 /* Lookup rule command from set list. */
453 static struct route_map_rule_cmd *
route_map_lookup_set(const char * name)454 route_map_lookup_set (const char *name)
455 {
456   unsigned int i;
457   struct route_map_rule_cmd *rule;
458 
459   for (i = 0; i < vector_active (route_set_vec); i++)
460     if ((rule = vector_slot (route_set_vec, i)) != NULL)
461       if (strcmp (rule->str, name) == 0)
462 	return rule;
463   return NULL;
464 }
465 
466 /* Add match and set rule to rule list. */
467 static void
route_map_rule_add(struct route_map_rule_list * list,struct route_map_rule * rule)468 route_map_rule_add (struct route_map_rule_list *list,
469 		    struct route_map_rule *rule)
470 {
471   rule->next = NULL;
472   rule->prev = list->tail;
473   if (list->tail)
474     list->tail->next = rule;
475   else
476     list->head = rule;
477   list->tail = rule;
478 }
479 
480 /* Delete rule from rule list. */
481 static void
route_map_rule_delete(struct route_map_rule_list * list,struct route_map_rule * rule)482 route_map_rule_delete (struct route_map_rule_list *list,
483 		       struct route_map_rule *rule)
484 {
485   if (rule->cmd->func_free)
486     (*rule->cmd->func_free) (rule->value);
487 
488   if (rule->rule_str)
489     XFREE (MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str);
490 
491   if (rule->next)
492     rule->next->prev = rule->prev;
493   else
494     list->tail = rule->prev;
495   if (rule->prev)
496     rule->prev->next = rule->next;
497   else
498     list->head = rule->next;
499 
500   XFREE (MTYPE_ROUTE_MAP_RULE, rule);
501 }
502 
503 /* strcmp wrapper function which don't crush even argument is NULL. */
504 static int
rulecmp(const char * dst,const char * src)505 rulecmp (const char *dst, const char *src)
506 {
507   if (dst == NULL)
508     {
509       if (src ==  NULL)
510 	return 0;
511       else
512 	return 1;
513     }
514   else
515     {
516       if (src == NULL)
517 	return 1;
518       else
519 	return strcmp (dst, src);
520     }
521   return 1;
522 }
523 
524 /* Add match statement to route map. */
525 int
route_map_add_match(struct route_map_index * index,const char * match_name,const char * match_arg)526 route_map_add_match (struct route_map_index *index, const char *match_name,
527                      const char *match_arg)
528 {
529   struct route_map_rule *rule;
530   struct route_map_rule *next;
531   struct route_map_rule_cmd *cmd;
532   void *compile;
533   int replaced = 0;
534 
535   /* First lookup rule for add match statement. */
536   cmd = route_map_lookup_match (match_name);
537   if (cmd == NULL)
538     return RMAP_RULE_MISSING;
539 
540   /* Next call compile function for this match statement. */
541   if (cmd->func_compile)
542     {
543       compile= (*cmd->func_compile)(match_arg);
544       if (compile == NULL)
545 	return RMAP_COMPILE_ERROR;
546     }
547   else
548     compile = NULL;
549 
550   /* If argument is completely same ignore it. */
551   for (rule = index->match_list.head; rule; rule = next)
552     {
553       next = rule->next;
554       if (rule->cmd == cmd)
555 	{
556 	  route_map_rule_delete (&index->match_list, rule);
557 	  replaced = 1;
558 	}
559     }
560 
561   /* Add new route map match rule. */
562   rule = route_map_rule_new ();
563   rule->cmd = cmd;
564   rule->value = compile;
565   if (match_arg)
566     rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, match_arg);
567   else
568     rule->rule_str = NULL;
569 
570   /* Add new route match rule to linked list. */
571   route_map_rule_add (&index->match_list, rule);
572 
573   /* Execute event hook. */
574   if (route_map_master.event_hook)
575     (*route_map_master.event_hook) (replaced ?
576 				    RMAP_EVENT_MATCH_REPLACED:
577 				    RMAP_EVENT_MATCH_ADDED,
578 				    index->map->name);
579 
580   return 0;
581 }
582 
583 /* Delete specified route match rule. */
584 int
route_map_delete_match(struct route_map_index * index,const char * match_name,const char * match_arg)585 route_map_delete_match (struct route_map_index *index, const char *match_name,
586                         const char *match_arg)
587 {
588   struct route_map_rule *rule;
589   struct route_map_rule_cmd *cmd;
590 
591   cmd = route_map_lookup_match (match_name);
592   if (cmd == NULL)
593     return 1;
594 
595   for (rule = index->match_list.head; rule; rule = rule->next)
596     if (rule->cmd == cmd &&
597 	(rulecmp (rule->rule_str, match_arg) == 0 || match_arg == NULL))
598       {
599 	route_map_rule_delete (&index->match_list, rule);
600 	/* Execute event hook. */
601 	if (route_map_master.event_hook)
602 	  (*route_map_master.event_hook) (RMAP_EVENT_MATCH_DELETED,
603 					  index->map->name);
604 	return 0;
605       }
606   /* Can't find matched rule. */
607   return 1;
608 }
609 
610 /* Add route-map set statement to the route map. */
611 int
route_map_add_set(struct route_map_index * index,const char * set_name,const char * set_arg)612 route_map_add_set (struct route_map_index *index, const char *set_name,
613                    const char *set_arg)
614 {
615   struct route_map_rule *rule;
616   struct route_map_rule *next;
617   struct route_map_rule_cmd *cmd;
618   void *compile;
619   int replaced = 0;
620 
621   cmd = route_map_lookup_set (set_name);
622   if (cmd == NULL)
623     return RMAP_RULE_MISSING;
624 
625   /* Next call compile function for this match statement. */
626   if (cmd->func_compile)
627     {
628       compile= (*cmd->func_compile)(set_arg);
629       if (compile == NULL)
630 	return RMAP_COMPILE_ERROR;
631     }
632   else
633     compile = NULL;
634 
635  /* Add by WJL. if old set command of same kind exist, delete it first
636     to ensure only one set command of same kind exist under a
637     route_map_index. */
638   for (rule = index->set_list.head; rule; rule = next)
639     {
640       next = rule->next;
641       if (rule->cmd == cmd)
642 	{
643 	  route_map_rule_delete (&index->set_list, rule);
644 	  replaced = 1;
645 	}
646     }
647 
648   /* Add new route map match rule. */
649   rule = route_map_rule_new ();
650   rule->cmd = cmd;
651   rule->value = compile;
652   if (set_arg)
653     rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, set_arg);
654   else
655     rule->rule_str = NULL;
656 
657   /* Add new route match rule to linked list. */
658   route_map_rule_add (&index->set_list, rule);
659 
660   /* Execute event hook. */
661   if (route_map_master.event_hook)
662     (*route_map_master.event_hook) (replaced ?
663 				    RMAP_EVENT_SET_REPLACED:
664 				    RMAP_EVENT_SET_ADDED,
665 				    index->map->name);
666   return 0;
667 }
668 
669 /* Delete route map set rule. */
670 int
route_map_delete_set(struct route_map_index * index,const char * set_name,const char * set_arg)671 route_map_delete_set (struct route_map_index *index, const char *set_name,
672                       const char *set_arg)
673 {
674   struct route_map_rule *rule;
675   struct route_map_rule_cmd *cmd;
676 
677   cmd = route_map_lookup_set (set_name);
678   if (cmd == NULL)
679     return 1;
680 
681   for (rule = index->set_list.head; rule; rule = rule->next)
682     if ((rule->cmd == cmd) &&
683          (rulecmp (rule->rule_str, set_arg) == 0 || set_arg == NULL))
684       {
685         route_map_rule_delete (&index->set_list, rule);
686 	/* Execute event hook. */
687 	if (route_map_master.event_hook)
688 	  (*route_map_master.event_hook) (RMAP_EVENT_SET_DELETED,
689 					  index->map->name);
690         return 0;
691       }
692   /* Can't find matched rule. */
693   return 1;
694 }
695 
696 /* Apply route map's each index to the object.
697 
698    The matrix for a route-map looks like this:
699    (note, this includes the description for the "NEXT"
700    and "GOTO" frobs now
701 
702               Match   |   No Match
703                       |
704     permit    action  |     cont
705                       |
706     ------------------+---------------
707                       |
708     deny      deny    |     cont
709                       |
710 
711    action)
712       -Apply Set statements, accept route
713       -If Call statement is present jump to the specified route-map, if it
714          denies the route we finish.
715       -If NEXT is specified, goto NEXT statement
716       -If GOTO is specified, goto the first clause where pref > nextpref
717       -If nothing is specified, do as Cisco and finish
718    deny)
719       -Route is denied by route-map.
720    cont)
721       -Goto Next index
722 
723    If we get no matches after we've processed all updates, then the route
724    is dropped too.
725 
726    Some notes on the new "CALL", "NEXT" and "GOTO"
727      call WORD        - If this clause is matched, then the set statements
728                         are executed and then we jump to route-map 'WORD'. If
729                         this route-map denies the route, we finish, in other case we
730                         do whatever the exit policy (EXIT, NEXT or GOTO) tells.
731      on-match next    - If this clause is matched, then the set statements
732                         are executed and then we drop through to the next clause
733      on-match goto n  - If this clause is matched, then the set statments
734                         are executed and then we goto the nth clause, or the
735                         first clause greater than this. In order to ensure
736                         route-maps *always* exit, you cannot jump backwards.
737                         Sorry ;)
738 
739    We need to make sure our route-map processing matches the above
740 */
741 
742 static route_map_result_t
route_map_apply_match(struct route_map_rule_list * match_list,struct prefix * prefix,route_map_object_t type,void * object)743 route_map_apply_match (struct route_map_rule_list *match_list,
744                        struct prefix *prefix, route_map_object_t type,
745                        void *object)
746 {
747   route_map_result_t ret = RMAP_NOMATCH;
748   struct route_map_rule *match;
749 
750 
751   /* Check all match rule and if there is no match rule, go to the
752      set statement. */
753   if (!match_list->head)
754     ret = RMAP_MATCH;
755   else
756     {
757       for (match = match_list->head; match; match = match->next)
758         {
759           /* Try each match statement in turn, If any do not return
760              RMAP_MATCH, return, otherwise continue on to next match
761              statement. All match statements must match for end-result
762              to be a match. */
763           ret = (*match->cmd->func_apply) (match->value, prefix,
764                                            type, object);
765           if (ret != RMAP_MATCH)
766             return ret;
767         }
768     }
769   return ret;
770 }
771 
772 /* Apply route map to the object. */
773 route_map_result_t
route_map_apply(struct route_map * map,struct prefix * prefix,route_map_object_t type,void * object)774 route_map_apply (struct route_map *map, struct prefix *prefix,
775                  route_map_object_t type, void *object)
776 {
777   static int recursion = 0;
778   int ret = 0;
779   struct route_map_index *index;
780   struct route_map_rule *set;
781 
782   if (recursion > RMAP_RECURSION_LIMIT)
783     {
784       zlog (NULL, LOG_WARNING,
785             "route-map recursion limit (%d) reached, discarding route",
786             RMAP_RECURSION_LIMIT);
787       recursion = 0;
788       return RMAP_DENYMATCH;
789     }
790 
791   if (map == NULL)
792     return RMAP_DENYMATCH;
793 
794   for (index = map->head; index; index = index->next)
795     {
796       /* Apply this index. */
797       ret = route_map_apply_match (&index->match_list, prefix, type, object);
798 
799       /* Now we apply the matrix from above */
800       if (ret == RMAP_NOMATCH)
801         /* 'cont' from matrix - continue to next route-map sequence */
802         continue;
803       else if (ret == RMAP_MATCH)
804         {
805           if (index->type == RMAP_PERMIT)
806             /* 'action' */
807             {
808               /* permit+match must execute sets */
809               for (set = index->set_list.head; set; set = set->next)
810                 ret = (*set->cmd->func_apply) (set->value, prefix,
811                                                type, object);
812 
813               /* Call another route-map if available */
814               if (index->nextrm)
815                 {
816                   struct route_map *nextrm =
817                                     route_map_lookup_by_name (index->nextrm);
818 
819                   if (nextrm) /* Target route-map found, jump to it */
820                     {
821                       recursion++;
822                       ret = route_map_apply (nextrm, prefix, type, object);
823                       recursion--;
824                     }
825 
826                   /* If nextrm returned 'deny', finish. */
827                   if (ret == RMAP_DENYMATCH)
828                     return ret;
829                 }
830 
831               switch (index->exitpolicy)
832                 {
833                   case RMAP_EXIT:
834                     return ret;
835                   case RMAP_NEXT:
836                     continue;
837                   case RMAP_GOTO:
838                     {
839                       /* Find the next clause to jump to */
840                       struct route_map_index *next = index->next;
841                       int nextpref = index->nextpref;
842 
843                       while (next && next->pref < nextpref)
844                         {
845                           index = next;
846                           next = next->next;
847                         }
848                       if (next == NULL)
849                         {
850                           /* No clauses match! */
851                           return ret;
852                         }
853                     }
854                 }
855             }
856           else if (index->type == RMAP_DENY)
857             /* 'deny' */
858             {
859                 return RMAP_DENYMATCH;
860             }
861         }
862     }
863   /* Finally route-map does not match at all. */
864   return RMAP_DENYMATCH;
865 }
866 
867 void
route_map_add_hook(void (* func)(const char *))868 route_map_add_hook (void (*func) (const char *))
869 {
870   route_map_master.add_hook = func;
871 }
872 
873 void
route_map_delete_hook(void (* func)(const char *))874 route_map_delete_hook (void (*func) (const char *))
875 {
876   route_map_master.delete_hook = func;
877 }
878 
879 void
route_map_event_hook(void (* func)(route_map_event_t,const char *))880 route_map_event_hook (void (*func) (route_map_event_t, const char *))
881 {
882   route_map_master.event_hook = func;
883 }
884 
885 void
route_map_init(void)886 route_map_init (void)
887 {
888   /* Make vector for match and set. */
889   route_match_vec = vector_init (1);
890   route_set_vec = vector_init (1);
891 }
892 
893 void
route_map_finish(void)894 route_map_finish (void)
895 {
896   vector_free (route_match_vec);
897   route_match_vec = NULL;
898   vector_free (route_set_vec);
899   route_set_vec = NULL;
900   /* cleanup route_map */
901   while (route_map_master.head)
902     route_map_delete (route_map_master.head);
903 }
904 
905 /* VTY related functions. */
906 DEFUN (route_map,
907        route_map_cmd,
908        "route-map WORD (deny|permit) <1-65535>",
909        "Create route-map or enter route-map command mode\n"
910        "Route map tag\n"
911        "Route map denies set operations\n"
912        "Route map permits set operations\n"
913        "Sequence to insert to/delete from existing route-map entry\n")
914 {
915   int permit;
916   unsigned long pref;
917   struct route_map *map;
918   struct route_map_index *index;
919   char *endptr = NULL;
920 
921   /* Permit check. */
922   if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
923     permit = RMAP_PERMIT;
924   else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
925     permit = RMAP_DENY;
926   else
927     {
928       vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
929       return CMD_WARNING;
930     }
931 
932   /* Preference check. */
933   pref = strtoul (argv[2], &endptr, 10);
934   if (pref == ULONG_MAX || *endptr != '\0')
935     {
936       vty_out (vty, "the fourth field must be positive integer%s",
937 	       VTY_NEWLINE);
938       return CMD_WARNING;
939     }
940   if (pref == 0 || pref > 65535)
941     {
942       vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
943       return CMD_WARNING;
944     }
945 
946   /* Get route map. */
947   map = route_map_get (argv[0]);
948   index = route_map_index_get (map, permit, pref);
949 
950   vty->index = index;
951   vty->node = RMAP_NODE;
952   return CMD_SUCCESS;
953 }
954 
955 DEFUN (no_route_map_all,
956        no_route_map_all_cmd,
957        "no route-map WORD",
958        NO_STR
959        "Create route-map or enter route-map command mode\n"
960        "Route map tag\n")
961 {
962   struct route_map *map;
963 
964   map = route_map_lookup_by_name (argv[0]);
965   if (map == NULL)
966     {
967       vty_out (vty, "%% Could not find route-map %s%s",
968 	       argv[0], VTY_NEWLINE);
969       return CMD_WARNING;
970     }
971 
972   route_map_delete (map);
973 
974   return CMD_SUCCESS;
975 }
976 
977 DEFUN (no_route_map,
978        no_route_map_cmd,
979        "no route-map WORD (deny|permit) <1-65535>",
980        NO_STR
981        "Create route-map or enter route-map command mode\n"
982        "Route map tag\n"
983        "Route map denies set operations\n"
984        "Route map permits set operations\n"
985        "Sequence to insert to/delete from existing route-map entry\n")
986 {
987   int permit;
988   unsigned long pref;
989   struct route_map *map;
990   struct route_map_index *index;
991   char *endptr = NULL;
992 
993   /* Permit check. */
994   if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
995     permit = RMAP_PERMIT;
996   else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
997     permit = RMAP_DENY;
998   else
999     {
1000       vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
1001       return CMD_WARNING;
1002     }
1003 
1004   /* Preference. */
1005   pref = strtoul (argv[2], &endptr, 10);
1006   if (pref == ULONG_MAX || *endptr != '\0')
1007     {
1008       vty_out (vty, "the fourth field must be positive integer%s",
1009 	       VTY_NEWLINE);
1010       return CMD_WARNING;
1011     }
1012   if (pref == 0 || pref > 65535)
1013     {
1014       vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
1015       return CMD_WARNING;
1016     }
1017 
1018   /* Existence check. */
1019   map = route_map_lookup_by_name (argv[0]);
1020   if (map == NULL)
1021     {
1022       vty_out (vty, "%% Could not find route-map %s%s",
1023 	       argv[0], VTY_NEWLINE);
1024       return CMD_WARNING;
1025     }
1026 
1027   /* Lookup route map index. */
1028   index = route_map_index_lookup (map, permit, pref);
1029   if (index == NULL)
1030     {
1031       vty_out (vty, "%% Could not find route-map entry %s %s%s",
1032 	       argv[0], argv[2], VTY_NEWLINE);
1033       return CMD_WARNING;
1034     }
1035 
1036   /* Delete index from route map. */
1037   route_map_index_delete (index, 1);
1038 
1039   /* If this route rule is the last one, delete route map itself. */
1040   if (route_map_empty (map))
1041     route_map_delete (map);
1042 
1043   return CMD_SUCCESS;
1044 }
1045 
1046 DEFUN (rmap_onmatch_next,
1047        rmap_onmatch_next_cmd,
1048        "on-match next",
1049        "Exit policy on matches\n"
1050        "Next clause\n")
1051 {
1052   struct route_map_index *index;
1053 
1054   index = vty->index;
1055 
1056   if (index)
1057     index->exitpolicy = RMAP_NEXT;
1058 
1059   return CMD_SUCCESS;
1060 }
1061 
1062 DEFUN (no_rmap_onmatch_next,
1063        no_rmap_onmatch_next_cmd,
1064        "no on-match next",
1065        NO_STR
1066        "Exit policy on matches\n"
1067        "Next clause\n")
1068 {
1069   struct route_map_index *index;
1070 
1071   index = vty->index;
1072 
1073   if (index)
1074     index->exitpolicy = RMAP_EXIT;
1075 
1076   return CMD_SUCCESS;
1077 }
1078 
1079 DEFUN (rmap_onmatch_goto,
1080        rmap_onmatch_goto_cmd,
1081        "on-match goto <1-65535>",
1082        "Exit policy on matches\n"
1083        "Goto Clause number\n"
1084        "Number\n")
1085 {
1086   struct route_map_index *index = vty->index;
1087   int d = 0;
1088 
1089   if (index)
1090     {
1091       if (argc == 1 && argv[0])
1092         VTY_GET_INTEGER_RANGE("route-map index", d, argv[0], 1, 65536);
1093       else
1094         d = index->pref + 1;
1095 
1096       if (d <= index->pref)
1097 	{
1098 	  /* Can't allow you to do that, Dave */
1099 	  vty_out (vty, "can't jump backwards in route-maps%s",
1100 		   VTY_NEWLINE);
1101 	  return CMD_WARNING;
1102 	}
1103       else
1104 	{
1105 	  index->exitpolicy = RMAP_GOTO;
1106 	  index->nextpref = d;
1107 	}
1108     }
1109   return CMD_SUCCESS;
1110 }
1111 
1112 DEFUN (no_rmap_onmatch_goto,
1113        no_rmap_onmatch_goto_cmd,
1114        "no on-match goto",
1115        NO_STR
1116        "Exit policy on matches\n"
1117        "Goto Clause number\n")
1118 {
1119   struct route_map_index *index;
1120 
1121   index = vty->index;
1122 
1123   if (index)
1124     index->exitpolicy = RMAP_EXIT;
1125 
1126   return CMD_SUCCESS;
1127 }
1128 
1129 /* Cisco/GNU Zebra compatible ALIASes for on-match next */
1130 ALIAS (rmap_onmatch_goto,
1131        rmap_continue_cmd,
1132        "continue",
1133        "Continue on a different entry within the route-map\n")
1134 
1135 ALIAS (no_rmap_onmatch_goto,
1136        no_rmap_continue_cmd,
1137        "no continue",
1138        NO_STR
1139        "Continue on a different entry within the route-map\n")
1140 
1141 /* GNU Zebra compatible */
1142 ALIAS (rmap_onmatch_goto,
1143        rmap_continue_seq_cmd,
1144        "continue <1-65535>",
1145        "Continue on a different entry within the route-map\n"
1146        "Route-map entry sequence number\n")
1147 
1148 ALIAS (no_rmap_onmatch_goto,
1149        no_rmap_continue_seq,
1150        "no continue <1-65535>",
1151        NO_STR
1152        "Continue on a different entry within the route-map\n"
1153        "Route-map entry sequence number\n")
1154 
1155 DEFUN (rmap_show_name,
1156        rmap_show_name_cmd,
1157        "show route-map [WORD]",
1158        SHOW_STR
1159        "route-map information\n"
1160        "route-map name\n")
1161 {
1162     const char *name = NULL;
1163     if (argc)
1164       name = argv[0];
1165     return vty_show_route_map (vty, name);
1166 }
1167 
1168 ALIAS (rmap_onmatch_goto,
1169       rmap_continue_index_cmd,
1170       "continue <1-65536>",
1171       "Exit policy on matches\n"
1172       "Goto Clause number\n")
1173 
1174 DEFUN (rmap_call,
1175        rmap_call_cmd,
1176        "call WORD",
1177        "Jump to another Route-Map after match+set\n"
1178        "Target route-map name\n")
1179 {
1180   struct route_map_index *index;
1181 
1182   index = vty->index;
1183   if (index)
1184     {
1185       if (index->nextrm)
1186           XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
1187       index->nextrm = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[0]);
1188     }
1189   return CMD_SUCCESS;
1190 }
1191 
1192 DEFUN (no_rmap_call,
1193        no_rmap_call_cmd,
1194        "no call",
1195        NO_STR
1196        "Jump to another Route-Map after match+set\n")
1197 {
1198   struct route_map_index *index;
1199 
1200   index = vty->index;
1201 
1202   if (index->nextrm)
1203     {
1204       XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
1205       index->nextrm = NULL;
1206     }
1207 
1208   return CMD_SUCCESS;
1209 }
1210 
1211 DEFUN (rmap_description,
1212        rmap_description_cmd,
1213        "description .LINE",
1214        "Route-map comment\n"
1215        "Comment describing this route-map rule\n")
1216 {
1217   struct route_map_index *index;
1218 
1219   index = vty->index;
1220   if (index)
1221     {
1222       if (index->description)
1223 	XFREE (MTYPE_TMP, index->description);
1224       index->description = argv_concat (argv, argc, 0);
1225     }
1226   return CMD_SUCCESS;
1227 }
1228 
1229 DEFUN (no_rmap_description,
1230        no_rmap_description_cmd,
1231        "no description",
1232        NO_STR
1233        "Route-map comment\n")
1234 {
1235   struct route_map_index *index;
1236 
1237   index = vty->index;
1238   if (index)
1239     {
1240       if (index->description)
1241 	XFREE (MTYPE_TMP, index->description);
1242       index->description = NULL;
1243     }
1244   return CMD_SUCCESS;
1245 }
1246 
1247 /* Configuration write function. */
1248 static int
route_map_config_write(struct vty * vty)1249 route_map_config_write (struct vty *vty)
1250 {
1251   struct route_map *map;
1252   struct route_map_index *index;
1253   struct route_map_rule *rule;
1254   int first = 1;
1255   int write = 0;
1256 
1257   for (map = route_map_master.head; map; map = map->next)
1258     for (index = map->head; index; index = index->next)
1259       {
1260 	if (!first)
1261 	  vty_out (vty, "!%s", VTY_NEWLINE);
1262 	else
1263 	  first = 0;
1264 
1265 	vty_out (vty, "route-map %s %s %d%s",
1266 		 map->name,
1267 		 route_map_type_str (index->type),
1268 		 index->pref, VTY_NEWLINE);
1269 
1270 	if (index->description)
1271 	  vty_out (vty, " description %s%s", index->description, VTY_NEWLINE);
1272 
1273 	for (rule = index->match_list.head; rule; rule = rule->next)
1274 	  vty_out (vty, " match %s %s%s", rule->cmd->str,
1275 		   rule->rule_str ? rule->rule_str : "",
1276 		   VTY_NEWLINE);
1277 
1278 	for (rule = index->set_list.head; rule; rule = rule->next)
1279 	  vty_out (vty, " set %s %s%s", rule->cmd->str,
1280 		   rule->rule_str ? rule->rule_str : "",
1281 		   VTY_NEWLINE);
1282    if (index->nextrm)
1283      vty_out (vty, " call %s%s", index->nextrm, VTY_NEWLINE);
1284 	if (index->exitpolicy == RMAP_GOTO)
1285       vty_out (vty, " on-match goto %d%s", index->nextpref, VTY_NEWLINE);
1286 	if (index->exitpolicy == RMAP_NEXT)
1287 	  vty_out (vty," on-match next%s", VTY_NEWLINE);
1288 
1289 	write++;
1290       }
1291   return write;
1292 }
1293 
1294 /* Route map node structure. */
1295 static struct cmd_node rmap_node =
1296 {
1297   RMAP_NODE,
1298   "%s(config-route-map)# ",
1299   1
1300 };
1301 
1302 /* Common route map rules */
1303 
1304 void *
route_map_rule_tag_compile(const char * arg)1305 route_map_rule_tag_compile (const char *arg)
1306 {
1307   unsigned long int tmp;
1308   char *endptr;
1309   route_tag_t *tag;
1310 
1311   errno = 0;
1312   tmp = strtoul(arg, &endptr, 0);
1313   if (arg[0] == '\0' || *endptr != '\0' || errno || tmp > ROUTE_TAG_MAX)
1314     return NULL;
1315 
1316   tag = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*tag));
1317   *tag = tmp;
1318 
1319   return tag;
1320 }
1321 
1322 void
route_map_rule_tag_free(void * rule)1323 route_map_rule_tag_free (void *rule)
1324 {
1325   XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
1326 }
1327 
1328 /* Initialization of route map vector. */
1329 void
route_map_init_vty(void)1330 route_map_init_vty (void)
1331 {
1332   /* Install route map top node. */
1333   install_node (&rmap_node, route_map_config_write);
1334 
1335   /* Install route map commands. */
1336   install_default (RMAP_NODE);
1337   install_element (CONFIG_NODE, &route_map_cmd);
1338   install_element (CONFIG_NODE, &no_route_map_cmd);
1339   install_element (CONFIG_NODE, &no_route_map_all_cmd);
1340 
1341   /* Install the on-match stuff */
1342   install_element (RMAP_NODE, &route_map_cmd);
1343   install_element (RMAP_NODE, &rmap_onmatch_next_cmd);
1344   install_element (RMAP_NODE, &no_rmap_onmatch_next_cmd);
1345   install_element (RMAP_NODE, &rmap_onmatch_goto_cmd);
1346   install_element (RMAP_NODE, &no_rmap_onmatch_goto_cmd);
1347 
1348   /* Install the continue stuff (ALIAS of on-match). */
1349   install_element (RMAP_NODE, &rmap_continue_cmd);
1350   install_element (RMAP_NODE, &no_rmap_continue_cmd);
1351   install_element (RMAP_NODE, &rmap_continue_index_cmd);
1352 
1353   /* Install the call stuff. */
1354   install_element (RMAP_NODE, &rmap_call_cmd);
1355   install_element (RMAP_NODE, &no_rmap_call_cmd);
1356 
1357   /* Install description commands. */
1358   install_element (RMAP_NODE, &rmap_description_cmd);
1359   install_element (RMAP_NODE, &no_rmap_description_cmd);
1360 
1361   /* Install show command */
1362   install_element (ENABLE_NODE, &rmap_show_name_cmd);
1363 }
1364