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