Import Upstream version 1.2.2
[quagga-debian.git] / zebra / zebra_routemap.c
1 /* zebra routemap.
2  * Copyright (C) 2006 IBM Corporation
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
22 #include <zebra.h>
23
24 #include "memory.h"
25 #include "prefix.h"
26 #include "rib.h"
27 #include "routemap.h"
28 #include "command.h"
29 #include "filter.h"
30 #include "plist.h"
31 #include "vrf.h"
32 #include "nexthop.h"
33
34 #include "zebra/zserv.h"
35
36 /* Add zebra route map rule */
37 static int
38 zebra_route_match_add(struct vty *vty, struct route_map_index *index,
39                       const char *command, const char *arg)
40 {
41   int ret;
42
43   ret = route_map_add_match (index, command, arg);
44   if (ret)
45     {
46       switch (ret)
47         {
48         case RMAP_RULE_MISSING:
49           vty_out (vty, "%% Zebra Can't find rule.%s", VTY_NEWLINE);
50           return CMD_WARNING;
51         case RMAP_COMPILE_ERROR:
52           vty_out (vty, "%% Zebra Argument is malformed.%s", VTY_NEWLINE);
53           return CMD_WARNING;
54         }
55     }
56   return CMD_SUCCESS;
57 }
58
59 /* Delete zebra route map rule. */
60 static int
61 zebra_route_match_delete (struct vty *vty, struct route_map_index *index,
62                         const char *command, const char *arg)
63 {
64   int ret;
65
66   ret = route_map_delete_match (index, command, arg);
67   if (ret)
68     {
69       switch (ret)
70         {
71         case RMAP_RULE_MISSING:
72           vty_out (vty, "%% Zebra Can't find rule.%s", VTY_NEWLINE);
73           return CMD_WARNING;
74         case RMAP_COMPILE_ERROR:
75           vty_out (vty, "%% Zebra Argument is malformed.%s", VTY_NEWLINE);
76           return CMD_WARNING;
77         }
78     }
79   return CMD_SUCCESS;
80 }
81
82 /* Add zebra route map rule. */
83 static int
84 zebra_route_set_add (struct vty *vty, struct route_map_index *index,
85                    const char *command, const char *arg)
86 {
87   int ret;
88
89   ret = route_map_add_set (index, command, arg);
90   if (ret)
91     {
92       switch (ret)
93         {
94         case RMAP_RULE_MISSING:
95           vty_out (vty, "%% Zebra Can't find rule.%s", VTY_NEWLINE);
96           return CMD_WARNING;
97         case RMAP_COMPILE_ERROR:
98           vty_out (vty, "%% Zebra Argument is malformed.%s", VTY_NEWLINE);
99           return CMD_WARNING;
100         }
101     }
102   return CMD_SUCCESS;
103 }
104
105 /* Delete zebra route map rule. */
106 static int
107 zebra_route_set_delete (struct vty *vty, struct route_map_index *index,
108                       const char *command, const char *arg)
109 {
110   int ret;
111
112   ret = route_map_delete_set (index, command, arg);
113   if (ret)
114     {
115       switch (ret)
116         {
117         case RMAP_RULE_MISSING:
118           vty_out (vty, "%% Zebra Can't find rule.%s", VTY_NEWLINE);
119           return CMD_WARNING;
120         case RMAP_COMPILE_ERROR:
121           vty_out (vty, "%% Zebra Argument is malformed.%s", VTY_NEWLINE);
122           return CMD_WARNING;
123         }
124     }
125   return CMD_SUCCESS;
126 }
127
128
129 /* `match interface IFNAME' */
130 /* Match function return 1 if match is success else return zero. */
131 static route_map_result_t
132 route_match_interface (void *rule, struct prefix *prefix,
133                        route_map_object_t type, void *object)
134 {
135   struct nexthop_vrfid *nh_vrf;
136   struct nexthop *nexthop;
137   char *ifname = rule;
138   ifindex_t ifindex;
139
140   if (type == RMAP_ZEBRA)
141     {
142       if (strcasecmp(ifname, "any") == 0)
143         return RMAP_MATCH;
144       nh_vrf = object;
145       if (!nh_vrf)
146         return RMAP_NOMATCH;
147       ifindex = ifname2ifindex_vrf (ifname, nh_vrf->vrf_id);
148       if (ifindex == 0)
149         return RMAP_NOMATCH;
150       nexthop = nh_vrf->nexthop;
151       if (!nexthop)
152         return RMAP_NOMATCH;
153       if (nexthop->ifindex == ifindex)
154         return RMAP_MATCH;
155     }
156   return RMAP_NOMATCH;
157 }
158
159 /* Route map `match interface' match statement. `arg' is IFNAME value */
160 static void *
161 route_match_interface_compile (const char *arg)
162 {
163   return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
164 }
165
166 /* Free route map's compiled `match interface' value. */
167 static void
168 route_match_interface_free (void *rule)
169 {
170   XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
171 }
172
173 /* Route map commands for interface matching */
174 struct route_map_rule_cmd route_match_interface_cmd =
175 {
176    "interface",
177    route_match_interface,
178    route_match_interface_compile,
179    route_match_interface_free
180 };
181
182 DEFUN (match_interface,
183        match_interface_cmd,
184        "match interface WORD",
185        MATCH_STR
186        "match first hop interface of route\n"
187        "Interface name\n")
188 {
189   return zebra_route_match_add (vty, vty->index, "interface", argv[0]);
190 }
191
192 DEFUN (no_match_interface,
193        no_match_interface_cmd,
194        "no match interface",
195        NO_STR
196        MATCH_STR
197        "Match first hop interface of route\n")
198 {
199   if (argc == 0)
200     return zebra_route_match_delete (vty, vty->index, "interface", NULL);
201
202   return zebra_route_match_delete (vty, vty->index, "interface", argv[0]);
203 }
204
205 ALIAS (no_match_interface,
206        no_match_interface_val_cmd,
207        "no match interface WORD",
208        NO_STR
209        MATCH_STR
210        "Match first hop interface of route\n"
211        "Interface name\n")
212
213 DEFUN (match_ip_next_hop,
214        match_ip_next_hop_cmd,
215        "match ip next-hop (<1-199>|<1300-2699>|WORD)",
216        MATCH_STR
217        IP_STR
218        "Match next-hop address of route\n"
219        "IP access-list number\n"
220        "IP access-list number (expanded range)\n"
221        "IP Access-list name\n")
222 {
223   return zebra_route_match_add (vty, vty->index, "ip next-hop", argv[0]);
224 }
225
226 DEFUN (no_match_ip_next_hop,
227        no_match_ip_next_hop_cmd,
228        "no match ip next-hop",
229        NO_STR
230        MATCH_STR
231        IP_STR
232        "Match next-hop address of route\n")
233 {
234   if (argc == 0)
235     return zebra_route_match_delete (vty, vty->index, "ip next-hop", NULL);
236
237   return zebra_route_match_delete (vty, vty->index, "ip next-hop", argv[0]);
238 }
239
240 ALIAS (no_match_ip_next_hop,
241        no_match_ip_next_hop_val_cmd,
242        "no match ip next-hop (<1-199>|<1300-2699>|WORD)",
243        NO_STR
244        MATCH_STR
245        IP_STR
246        "Match next-hop address of route\n"
247        "IP access-list number\n"
248        "IP access-list number (expanded range)\n"
249        "IP Access-list name\n")
250
251 DEFUN (match_ip_next_hop_prefix_list,
252        match_ip_next_hop_prefix_list_cmd,
253        "match ip next-hop prefix-list WORD",
254        MATCH_STR
255        IP_STR
256        "Match next-hop address of route\n"
257        "Match entries of prefix-lists\n"
258        "IP prefix-list name\n")
259 {
260   return zebra_route_match_add (vty, vty->index, "ip next-hop prefix-list", argv[0]);
261 }
262
263 DEFUN (no_match_ip_next_hop_prefix_list,
264        no_match_ip_next_hop_prefix_list_cmd,
265        "no match ip next-hop prefix-list",
266        NO_STR
267        MATCH_STR
268        IP_STR
269        "Match next-hop address of route\n"
270        "Match entries of prefix-lists\n")
271 {
272   if (argc == 0)
273     return zebra_route_match_delete (vty, vty->index, "ip next-hop prefix-list", NULL);
274
275   return zebra_route_match_delete (vty, vty->index, "ip next-hop prefix-list", argv[0]);
276 }
277
278 ALIAS (no_match_ip_next_hop_prefix_list,
279        no_match_ip_next_hop_prefix_list_val_cmd,
280        "no match ip next-hop prefix-list WORD",
281        NO_STR
282        MATCH_STR
283        IP_STR
284        "Match next-hop address of route\n"
285        "Match entries of prefix-lists\n"
286        "IP prefix-list name\n")
287
288 DEFUN (match_ip_address,
289        match_ip_address_cmd,
290        "match ip address (<1-199>|<1300-2699>|WORD)",
291        MATCH_STR
292        IP_STR
293        "Match address of route\n"
294        "IP access-list number\n"
295        "IP access-list number (expanded range)\n"
296        "IP Access-list name\n")
297
298 {
299   return zebra_route_match_add (vty, vty->index, "ip address", argv[0]);
300 }
301
302 DEFUN (no_match_ip_address, 
303        no_match_ip_address_cmd,
304        "no match ip address",
305        NO_STR
306        MATCH_STR
307        IP_STR
308        "Match address of route\n")
309 {
310   if (argc == 0)
311     return zebra_route_match_delete (vty, vty->index, "ip address", NULL);
312
313   return zebra_route_match_delete (vty, vty->index, "ip address", argv[0]);
314 }
315
316 ALIAS (no_match_ip_address,
317        no_match_ip_address_val_cmd,
318        "no match ip address (<1-199>|<1300-2699>|WORD)",
319        NO_STR
320        MATCH_STR
321        IP_STR
322        "Match address of route\n"
323        "IP access-list number\n"
324        "IP access-list number (expanded range)\n"
325        "IP Access-list name\n")
326
327 DEFUN (match_ip_address_prefix_list, 
328        match_ip_address_prefix_list_cmd,
329        "match ip address prefix-list WORD",
330        MATCH_STR
331        IP_STR
332        "Match address of route\n"
333        "Match entries of prefix-lists\n"
334        "IP prefix-list name\n")
335 {
336   return zebra_route_match_add (vty, vty->index, "ip address prefix-list", argv[0]);
337 }
338
339 DEFUN (no_match_ip_address_prefix_list,
340        no_match_ip_address_prefix_list_cmd,
341        "no match ip address prefix-list",
342        NO_STR
343        MATCH_STR
344        IP_STR
345        "Match address of route\n"
346        "Match entries of prefix-lists\n")
347 {
348   if (argc == 0)
349     return zebra_route_match_delete (vty, vty->index, "ip address prefix-list", NULL);
350
351   return zebra_route_match_delete (vty, vty->index, "ip address prefix-list", argv[0]);
352 }
353
354 ALIAS (no_match_ip_address_prefix_list,
355        no_match_ip_address_prefix_list_val_cmd,
356        "no match ip address prefix-list WORD",
357        NO_STR
358        MATCH_STR
359        IP_STR
360        "Match address of route\n"
361        "Match entries of prefix-lists\n"
362        "IP prefix-list name\n")
363
364 /* set functions */
365
366 DEFUN (set_src,
367        set_src_cmd,
368        "set src A.B.C.D",
369        SET_STR
370        "src address for route\n"
371        "src address\n")
372 {
373   struct in_addr src;
374   struct interface *pif = NULL;
375   vrf_iter_t iter;
376
377   if (inet_pton(AF_INET, argv[0], &src) <= 0)
378     {
379       vty_out (vty, "%% not a local address%s", VTY_NEWLINE);
380       return CMD_WARNING;
381     }
382
383   for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter))
384     if ((pif = if_lookup_exact_address_vrf (src, vrf_iter2id (iter))) != NULL)
385       break;
386
387   if (!pif)
388     {
389       vty_out (vty, "%% not a local address%s", VTY_NEWLINE);
390       return CMD_WARNING;
391     }
392
393   return zebra_route_set_add (vty, vty->index, "src", argv[0]);
394 }
395
396 DEFUN (no_set_src,
397        no_set_src_cmd,
398        "no set src",
399        NO_STR
400        SET_STR
401        "Source address for route\n")
402 {
403   if (argc == 0)
404     return zebra_route_set_delete (vty, vty->index, "src", NULL);
405
406   return zebra_route_set_delete (vty, vty->index, "src", argv[0]);
407 }
408
409 ALIAS (no_set_src,
410        no_set_src_val_cmd,
411        "no set src (A.B.C.D)",
412        NO_STR
413        SET_STR
414        "src address for route\n"
415        "src address\n")
416
417 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXX*/
418
419 /* `match ip next-hop IP_ACCESS_LIST' */
420
421 /* Match function return 1 if match is success else return zero. */
422 static route_map_result_t
423 route_match_ip_next_hop (void *rule, struct prefix *prefix,
424                         route_map_object_t type, void *object)
425 {
426   struct access_list *alist;
427   struct nexthop *nexthop;
428   struct nexthop_vrfid *nh_vrf;
429   struct prefix_ipv4 p;
430
431   if (type == RMAP_ZEBRA)
432     {
433       nh_vrf = object;
434       nexthop = nh_vrf->nexthop;
435       switch (nexthop->type) {
436       case NEXTHOP_TYPE_IFINDEX:
437       case NEXTHOP_TYPE_IFNAME:
438         /* Interface routes can't match ip next-hop */
439         return RMAP_NOMATCH;
440       case NEXTHOP_TYPE_IPV4_IFINDEX:
441       case NEXTHOP_TYPE_IPV4_IFNAME:
442       case NEXTHOP_TYPE_IPV4:
443         p.family = AF_INET;
444         p.prefix = nexthop->gate.ipv4;
445         p.prefixlen = IPV4_MAX_BITLEN;
446         break;
447       default:
448         return RMAP_NOMATCH;
449       }
450       alist = access_list_lookup (AFI_IP, (char *) rule);
451       if (alist == NULL)
452         return RMAP_NOMATCH;
453
454       return (access_list_apply (alist, &p) == FILTER_DENY ?
455               RMAP_NOMATCH : RMAP_MATCH);
456     }
457   return RMAP_NOMATCH;
458 }
459
460 /* Route map `ip next-hop' match statement.  `arg' should be
461    access-list name. */
462 static void *
463 route_match_ip_next_hop_compile (const char *arg)
464 {
465   return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
466 }
467
468 /* Free route map's compiled `. */
469 static void
470 route_match_ip_next_hop_free (void *rule)
471 {
472   XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
473 }
474
475 /* Route map commands for ip next-hop matching. */
476 static struct route_map_rule_cmd route_match_ip_next_hop_cmd =
477 {
478   "ip next-hop",
479   route_match_ip_next_hop,
480   route_match_ip_next_hop_compile,
481   route_match_ip_next_hop_free
482 };
483
484 /* `match ip next-hop prefix-list PREFIX_LIST' */
485
486 static route_map_result_t
487 route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix,
488                                     route_map_object_t type, void *object)
489 {
490   struct prefix_list *plist;
491   struct nexthop *nexthop;
492   struct nexthop_vrfid *nh_vrf;
493   struct prefix_ipv4 p;
494
495   if (type == RMAP_ZEBRA)
496     {
497       nh_vrf = object;
498       nexthop = nh_vrf->nexthop;
499       switch (nexthop->type) {
500       case NEXTHOP_TYPE_IFINDEX:
501       case NEXTHOP_TYPE_IFNAME:
502         /* Interface routes can't match ip next-hop */
503         return RMAP_NOMATCH;
504       case NEXTHOP_TYPE_IPV4_IFINDEX:
505       case NEXTHOP_TYPE_IPV4_IFNAME:
506       case NEXTHOP_TYPE_IPV4:
507         p.family = AF_INET;
508         p.prefix = nexthop->gate.ipv4;
509         p.prefixlen = IPV4_MAX_BITLEN;
510         break;
511       default:
512         return RMAP_NOMATCH;
513       }
514       plist = prefix_list_lookup (AFI_IP, (char *) rule);
515       if (plist == NULL)
516         return RMAP_NOMATCH;
517
518       return (prefix_list_apply (plist, &p) == PREFIX_DENY ?
519               RMAP_NOMATCH : RMAP_MATCH);
520     }
521   return RMAP_NOMATCH;
522 }
523
524 static void *
525 route_match_ip_next_hop_prefix_list_compile (const char *arg)
526 {
527   return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
528 }
529
530 static void
531 route_match_ip_next_hop_prefix_list_free (void *rule)
532 {
533   XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
534 }
535
536 static struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd =
537 {
538   "ip next-hop prefix-list",
539   route_match_ip_next_hop_prefix_list,
540   route_match_ip_next_hop_prefix_list_compile,
541   route_match_ip_next_hop_prefix_list_free
542 };
543
544 /* `match ip address IP_ACCESS_LIST' */
545
546 /* Match function should return 1 if match is success else return
547    zero. */
548 static route_map_result_t
549 route_match_ip_address (void *rule, struct prefix *prefix, 
550                         route_map_object_t type, void *object)
551 {
552   struct access_list *alist;
553
554   if (type == RMAP_ZEBRA)
555     {
556       alist = access_list_lookup (AFI_IP, (char *) rule);
557       if (alist == NULL)
558         return RMAP_NOMATCH;
559     
560       return (access_list_apply (alist, prefix) == FILTER_DENY ?
561               RMAP_NOMATCH : RMAP_MATCH);
562     }
563   return RMAP_NOMATCH;
564 }
565
566 /* Route map `ip address' match statement.  `arg' should be
567    access-list name. */
568 static void *
569 route_match_ip_address_compile (const char *arg)
570 {
571   return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
572 }
573
574 /* Free route map's compiled `ip address' value. */
575 static void
576 route_match_ip_address_free (void *rule)
577 {
578   XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
579 }
580
581 /* Route map commands for ip address matching. */
582 static struct route_map_rule_cmd route_match_ip_address_cmd =
583 {
584   "ip address",
585   route_match_ip_address,
586   route_match_ip_address_compile,
587   route_match_ip_address_free
588 };
589
590 /* `match ip address prefix-list PREFIX_LIST' */
591
592 static route_map_result_t
593 route_match_ip_address_prefix_list (void *rule, struct prefix *prefix, 
594                                     route_map_object_t type, void *object)
595 {
596   struct prefix_list *plist;
597
598   if (type == RMAP_ZEBRA)
599     {
600       plist = prefix_list_lookup (AFI_IP, (char *) rule);
601       if (plist == NULL)
602         return RMAP_NOMATCH;
603     
604       return (prefix_list_apply (plist, prefix) == PREFIX_DENY ?
605               RMAP_NOMATCH : RMAP_MATCH);
606     }
607   return RMAP_NOMATCH;
608 }
609
610 static void *
611 route_match_ip_address_prefix_list_compile (const char *arg)
612 {
613   return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
614 }
615
616 static void
617 route_match_ip_address_prefix_list_free (void *rule)
618 {
619   XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
620 }
621
622 static struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd =
623 {
624   "ip address prefix-list",
625   route_match_ip_address_prefix_list,
626   route_match_ip_address_prefix_list_compile,
627   route_match_ip_address_prefix_list_free
628 };
629
630
631 /* `set src A.B.C.D' */
632
633 /* Set src. */
634 static route_map_result_t
635 route_set_src (void *rule, struct prefix *prefix, 
636                   route_map_object_t type, void *object)
637 {
638   if (type == RMAP_ZEBRA)
639     {
640       struct nexthop_vrfid *nh_vrf;
641
642       nh_vrf = object;
643       nh_vrf->nexthop->src = *(union g_addr *)rule;
644     }
645   return RMAP_OKAY;
646 }
647
648 /* set src compilation. */
649 static void *
650 route_set_src_compile (const char *arg)
651 {
652   union g_addr src, *psrc;
653
654   if (inet_pton(AF_INET, arg, &src.ipv4) != 1
655 #ifdef HAVE_IPV6
656       && inet_pton(AF_INET6, arg, &src.ipv6) != 1
657 #endif /* HAVE_IPV6 */
658      )
659     return NULL;
660
661   psrc = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (union g_addr));
662   *psrc = src;
663
664   return psrc;
665 }
666
667 /* Free route map's compiled `set src' value. */
668 static void
669 route_set_src_free (void *rule)
670 {
671   XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
672 }
673
674 /* Set src rule structure. */
675 static struct route_map_rule_cmd route_set_src_cmd = 
676 {
677   "src",
678   route_set_src,
679   route_set_src_compile,
680   route_set_src_free,
681 };
682
683 void
684 zebra_route_map_init ()
685 {
686   route_map_init ();
687   route_map_init_vty ();
688
689   route_map_install_match (&route_match_interface_cmd);
690   route_map_install_match (&route_match_ip_next_hop_cmd);
691   route_map_install_match (&route_match_ip_next_hop_prefix_list_cmd);
692   route_map_install_match (&route_match_ip_address_cmd);
693   route_map_install_match (&route_match_ip_address_prefix_list_cmd);
694 /* */
695   route_map_install_set (&route_set_src_cmd);
696 /* */
697   install_element (RMAP_NODE, &match_interface_cmd);
698   install_element (RMAP_NODE, &no_match_interface_cmd); 
699   install_element (RMAP_NODE, &no_match_interface_val_cmd); 
700   install_element (RMAP_NODE, &match_ip_next_hop_cmd); 
701   install_element (RMAP_NODE, &no_match_ip_next_hop_cmd); 
702   install_element (RMAP_NODE, &no_match_ip_next_hop_val_cmd); 
703   install_element (RMAP_NODE, &match_ip_next_hop_prefix_list_cmd); 
704   install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd); 
705   install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_val_cmd); 
706   install_element (RMAP_NODE, &match_ip_address_cmd); 
707   install_element (RMAP_NODE, &no_match_ip_address_cmd); 
708   install_element (RMAP_NODE, &no_match_ip_address_val_cmd); 
709   install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd); 
710   install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd); 
711   install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd);
712 /* */
713   install_element (RMAP_NODE, &set_src_cmd);
714   install_element (RMAP_NODE, &no_set_src_cmd);
715 }