diff options
Diffstat (limited to 'zebra')
-rw-r--r-- | zebra/Makefile.am | 8 | ||||
-rw-r--r-- | zebra/connected.c | 33 | ||||
-rw-r--r-- | zebra/connected.h | 1 | ||||
-rw-r--r-- | zebra/debug.c | 30 | ||||
-rw-r--r-- | zebra/debug.h | 3 | ||||
-rw-r--r-- | zebra/if_ioctl.c | 1 | ||||
-rw-r--r-- | zebra/if_ioctl_solaris.c | 1 | ||||
-rw-r--r-- | zebra/if_netlink.c | 1 | ||||
-rw-r--r-- | zebra/if_sysctl.c | 1 | ||||
-rw-r--r-- | zebra/interface.c | 35 | ||||
-rw-r--r-- | zebra/ioctl.c | 1 | ||||
-rw-r--r-- | zebra/ioctl_solaris.c | 1 | ||||
-rw-r--r-- | zebra/kernel_null.c | 1 | ||||
-rw-r--r-- | zebra/kernel_socket.c | 1 | ||||
-rw-r--r-- | zebra/redistribute.c | 50 | ||||
-rw-r--r-- | zebra/redistribute_null.c | 1 | ||||
-rw-r--r-- | zebra/rib.h | 122 | ||||
-rw-r--r-- | zebra/rt_netlink.c | 109 | ||||
-rw-r--r-- | zebra/rtadv.c | 83 | ||||
-rw-r--r-- | zebra/rtread_getmsg.c | 1 | ||||
-rw-r--r-- | zebra/rtread_netlink.c | 1 | ||||
-rw-r--r-- | zebra/rtread_sysctl.c | 1 | ||||
-rw-r--r-- | zebra/zebra_fpm_netlink.c | 1 | ||||
-rw-r--r-- | zebra/zebra_rib.c | 669 | ||||
-rw-r--r-- | zebra/zebra_rnh.c | 761 | ||||
-rw-r--r-- | zebra/zebra_rnh.h | 54 | ||||
-rw-r--r-- | zebra/zebra_rnh_null.c | 21 | ||||
-rw-r--r-- | zebra/zebra_routemap.c | 953 | ||||
-rw-r--r-- | zebra/zebra_vty.c | 1884 | ||||
-rw-r--r-- | zebra/zserv.c | 562 | ||||
-rw-r--r-- | zebra/zserv.h | 51 |
31 files changed, 4803 insertions, 639 deletions
diff --git a/zebra/Makefile.am b/zebra/Makefile.am index 90ce7b97..0210b81e 100644 --- a/zebra/Makefile.am +++ b/zebra/Makefile.am @@ -30,17 +30,17 @@ zebra_SOURCES = \ zserv.c main.c interface.c connected.c zebra_rib.c zebra_routemap.c \ redistribute.c debug.c rtadv.c zebra_snmp.c zebra_vty.c \ irdp_main.c irdp_interface.c irdp_packet.c router-id.c zebra_fpm.c \ - $(othersrc) + $(othersrc) zebra_rnh.c testzebra_SOURCES = test_main.c zebra_rib.c interface.c connected.c debug.c \ - zebra_vty.c \ - kernel_null.c redistribute_null.c ioctl_null.c misc_null.c + zebra_vty.c zebra_routemap.c \ + kernel_null.c redistribute_null.c ioctl_null.c misc_null.c zebra_rnh_null.c noinst_HEADERS = \ connected.h ioctl.h rib.h rt.h zserv.h redistribute.h debug.h rtadv.h \ interface.h ipforward.h irdp.h router-id.h kernel_socket.h \ rt_netlink.h zebra_fpm.h zebra_fpm_private.h \ - ioctl_solaris.h + ioctl_solaris.h zebra_rnh.h zebra_LDADD = $(otherobj) ../lib/libzebra.la $(LIBCAP) diff --git a/zebra/connected.c b/zebra/connected.c index 84b0d1cb..f2f523fa 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -30,6 +30,7 @@ #include "table.h" #include "log.h" #include "memory.h" +#include "vty.h" #include "zebra/zserv.h" #include "zebra/redistribute.h" @@ -77,7 +78,15 @@ connected_announce (struct interface *ifp, struct connected *ifc) { if (!ifc) return; - + + if (!if_is_loopback(ifp) && ifc->address->family == AF_INET) + { + if (ifc->address->prefixlen == 32) + SET_FLAG (ifc->flags, ZEBRA_IFA_UNNUMBERED); + else + UNSET_FLAG (ifc->flags, ZEBRA_IFA_UNNUMBERED); + } + listnode_add (ifp->connected, ifc); /* Update interface address information to protocol daemon. */ @@ -209,6 +218,9 @@ connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, struct prefix_ipv4 *p; struct connected *ifc; + if (ipv4_martian(addr)) + return; + /* Make connected structure. */ ifc = connected_new (); ifc->ifp = ifp; @@ -370,6 +382,9 @@ connected_add_ipv6 (struct interface *ifp, int flags, struct in6_addr *addr, struct prefix_ipv6 *p; struct connected *ifc; + if (ipv6_martian(addr)) + return; + /* Make connected structure. */ ifc = connected_new (); ifc->ifp = ifp; @@ -464,4 +479,20 @@ connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address, rib_update (ifp->vrf_id); } + +int +connected_is_unnumbered (struct interface *ifp) +{ + struct connected *connected; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected)) + { + if (CHECK_FLAG (connected->conf, ZEBRA_IFC_REAL) && + connected->address->family == AF_INET) + return CHECK_FLAG(connected->flags, ZEBRA_IFA_UNNUMBERED); + } + return 0; +} + #endif /* HAVE_IPV6 */ diff --git a/zebra/connected.h b/zebra/connected.h index 9595ddb1..c589bd67 100644 --- a/zebra/connected.h +++ b/zebra/connected.h @@ -52,4 +52,5 @@ extern void connected_down_ipv6 (struct interface *ifp, struct connected *); #endif /* HAVE_IPV6 */ +extern int connected_is_unnumbered (struct interface *); #endif /*_ZEBRA_CONNECTED_H */ diff --git a/zebra/debug.c b/zebra/debug.c index 537c4766..fbeef52b 100644 --- a/zebra/debug.c +++ b/zebra/debug.c @@ -30,6 +30,7 @@ unsigned long zebra_debug_packet; unsigned long zebra_debug_kernel; unsigned long zebra_debug_rib; unsigned long zebra_debug_fpm; +unsigned long zebra_debug_nht; DEFUN (show_debugging_zebra, show_debugging_zebra_cmd, @@ -74,6 +75,8 @@ DEFUN (show_debugging_zebra, if (IS_ZEBRA_DEBUG_FPM) vty_out (vty, " Zebra FPM debugging is on%s", VTY_NEWLINE); + if (IS_ZEBRA_DEBUG_NHT) + vty_out (vty, " Zebra next-hop tracking debugging is on%s", VTY_NEWLINE); return CMD_SUCCESS; } @@ -89,6 +92,17 @@ DEFUN (debug_zebra_events, return CMD_WARNING; } +DEFUN (debug_zebra_nht, + debug_zebra_nht_cmd, + "debug zebra nht", + DEBUG_STR + "Zebra configuration\n" + "Debug option set for zebra next hop tracking\n") +{ + zebra_debug_nht = ZEBRA_DEBUG_NHT; + return CMD_WARNING; +} + DEFUN (debug_zebra_packet, debug_zebra_packet_cmd, "debug zebra packet", @@ -197,6 +211,18 @@ DEFUN (no_debug_zebra_events, return CMD_SUCCESS; } +DEFUN (no_debug_zebra_nht, + no_debug_zebra_nht_cmd, + "no debug zebra nht", + NO_STR + DEBUG_STR + "Zebra configuration\n" + "Debug option set for zebra next hop tracking\n") +{ + zebra_debug_nht = 0; + return CMD_SUCCESS; +} + DEFUN (no_debug_zebra_packet, no_debug_zebra_packet_cmd, "no debug zebra packet", @@ -353,6 +379,7 @@ zebra_debug_init (void) install_element (ENABLE_NODE, &show_debugging_zebra_cmd); install_element (ENABLE_NODE, &debug_zebra_events_cmd); + install_element (ENABLE_NODE, &debug_zebra_nht_cmd); install_element (ENABLE_NODE, &debug_zebra_packet_cmd); install_element (ENABLE_NODE, &debug_zebra_packet_direct_cmd); install_element (ENABLE_NODE, &debug_zebra_packet_detail_cmd); @@ -361,6 +388,7 @@ zebra_debug_init (void) install_element (ENABLE_NODE, &debug_zebra_rib_q_cmd); install_element (ENABLE_NODE, &debug_zebra_fpm_cmd); install_element (ENABLE_NODE, &no_debug_zebra_events_cmd); + install_element (ENABLE_NODE, &no_debug_zebra_nht_cmd); install_element (ENABLE_NODE, &no_debug_zebra_packet_cmd); install_element (ENABLE_NODE, &no_debug_zebra_kernel_cmd); install_element (ENABLE_NODE, &no_debug_zebra_rib_cmd); @@ -368,6 +396,7 @@ zebra_debug_init (void) install_element (ENABLE_NODE, &no_debug_zebra_fpm_cmd); install_element (CONFIG_NODE, &debug_zebra_events_cmd); + install_element (CONFIG_NODE, &debug_zebra_nht_cmd); install_element (CONFIG_NODE, &debug_zebra_packet_cmd); install_element (CONFIG_NODE, &debug_zebra_packet_direct_cmd); install_element (CONFIG_NODE, &debug_zebra_packet_detail_cmd); @@ -376,6 +405,7 @@ zebra_debug_init (void) install_element (CONFIG_NODE, &debug_zebra_rib_q_cmd); install_element (CONFIG_NODE, &debug_zebra_fpm_cmd); install_element (CONFIG_NODE, &no_debug_zebra_events_cmd); + install_element (CONFIG_NODE, &no_debug_zebra_nht_cmd); install_element (CONFIG_NODE, &no_debug_zebra_packet_cmd); install_element (CONFIG_NODE, &no_debug_zebra_kernel_cmd); install_element (CONFIG_NODE, &no_debug_zebra_rib_cmd); diff --git a/zebra/debug.h b/zebra/debug.h index d9231a22..0fb4dd9f 100644 --- a/zebra/debug.h +++ b/zebra/debug.h @@ -37,6 +37,7 @@ #define ZEBRA_DEBUG_RIB_Q 0x02 #define ZEBRA_DEBUG_FPM 0x01 +#define ZEBRA_DEBUG_NHT 0x01 /* Debug related macro. */ #define IS_ZEBRA_DEBUG_EVENT (zebra_debug_event & ZEBRA_DEBUG_EVENT) @@ -52,12 +53,14 @@ #define IS_ZEBRA_DEBUG_RIB_Q (zebra_debug_rib & ZEBRA_DEBUG_RIB_Q) #define IS_ZEBRA_DEBUG_FPM (zebra_debug_fpm & ZEBRA_DEBUG_FPM) +#define IS_ZEBRA_DEBUG_NHT (zebra_debug_nht & ZEBRA_DEBUG_NHT) extern unsigned long zebra_debug_event; extern unsigned long zebra_debug_packet; extern unsigned long zebra_debug_kernel; extern unsigned long zebra_debug_rib; extern unsigned long zebra_debug_fpm; +extern unsigned long zebra_debug_nht; extern void zebra_debug_init (void); diff --git a/zebra/if_ioctl.c b/zebra/if_ioctl.c index 8df877db..99328a1d 100644 --- a/zebra/if_ioctl.c +++ b/zebra/if_ioctl.c @@ -30,6 +30,7 @@ #include "memory.h" #include "log.h" #include "vrf.h" +#include "vty.h" #include "zebra/interface.h" #include "zebra/rib.h" diff --git a/zebra/if_ioctl_solaris.c b/zebra/if_ioctl_solaris.c index 50b4aca6..b399812e 100644 --- a/zebra/if_ioctl_solaris.c +++ b/zebra/if_ioctl_solaris.c @@ -31,6 +31,7 @@ #include "log.h" #include "privs.h" #include "vrf.h" +#include "vty.h" #include "zebra/interface.h" #include "zebra/ioctl_solaris.h" diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 245b7b25..2d062e01 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -21,6 +21,7 @@ */ #include <zebra.h> +#include <vty.h> #include "zebra/zserv.h" #include "rt_netlink.h" diff --git a/zebra/if_sysctl.c b/zebra/if_sysctl.c index bb48f618..8c4761bb 100644 --- a/zebra/if_sysctl.c +++ b/zebra/if_sysctl.c @@ -29,6 +29,7 @@ #include "memory.h" #include "ioctl.h" #include "log.h" +#include "vty.h" #include "interface.h" #include "vrf.h" diff --git a/zebra/interface.c b/zebra/interface.c index 8a9225ac..4ba92ba8 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -632,12 +632,30 @@ connected_dump_vty (struct vty *vty, struct connected *connected) if (CHECK_FLAG (connected->flags, ZEBRA_IFA_SECONDARY)) vty_out (vty, " secondary"); + if (CHECK_FLAG (connected->flags, ZEBRA_IFA_UNNUMBERED)) + vty_out (vty, " unnumbered"); + if (connected->label) vty_out (vty, " %s", connected->label); vty_out (vty, "%s", VTY_NEWLINE); } +/* Dump interface neighbor address information to vty. */ +static void +nbr_connected_dump_vty (struct vty *vty, struct nbr_connected *connected) +{ + struct prefix *p; + + /* Print interface address. */ + p = connected->address; + vty_out (vty, " %s ", prefix_family_str (p)); + prefix_vty_out (vty, p); + vty_out (vty, "/%d", p->prefixlen); + + vty_out (vty, "%s", VTY_NEWLINE); +} + #if defined (HAVE_RTADV) /* Dump interface ND information to vty. */ static void @@ -706,6 +724,7 @@ static void if_dump_vty (struct vty *vty, struct interface *ifp) { struct connected *connected; + struct nbr_connected *nbr_connected; struct listnode *node; struct route_node *rn; struct zebra_if *zebra_if; @@ -793,6 +812,10 @@ if_dump_vty (struct vty *vty, struct interface *ifp) #if defined (HAVE_RTADV) nd_dump_vty (vty, ifp); #endif /* HAVE_RTADV */ + if (listhead(ifp->nbr_connected)) + vty_out (vty, " Neighbor address(s):%s", VTY_NEWLINE); + for (ALL_LIST_ELEMENTS_RO (ifp->nbr_connected, node, nbr_connected)) + nbr_connected_dump_vty (vty, nbr_connected); #ifdef HAVE_PROC_NET_DEV /* Statistics print out using proc file system. */ @@ -1381,6 +1404,12 @@ ip_address_install (struct vty *vty, struct interface *ifp, return CMD_WARNING; } + if (ipv4_martian(&cp.prefix)) + { + vty_out (vty, "%% Invalid address%s", VTY_NEWLINE); + return CMD_WARNING; + } + ifc = connected_check (ifp, (struct prefix *) &cp); if (! ifc) { @@ -1565,6 +1594,12 @@ ipv6_address_install (struct vty *vty, struct interface *ifp, return CMD_WARNING; } + if (ipv6_martian(&cp.prefix)) + { + vty_out (vty, "%% Invalid address%s", VTY_NEWLINE); + return CMD_WARNING; + } + ifc = connected_check (ifp, (struct prefix *) &cp); if (! ifc) { diff --git a/zebra/ioctl.c b/zebra/ioctl.c index f7a7ff40..c3a1b603 100644 --- a/zebra/ioctl.c +++ b/zebra/ioctl.c @@ -28,6 +28,7 @@ #include "ioctl.h" #include "log.h" #include "privs.h" +#include "vty.h" #include "zebra/rib.h" #include "zebra/rt.h" diff --git a/zebra/ioctl_solaris.c b/zebra/ioctl_solaris.c index 12737cbf..b5bf1ccb 100644 --- a/zebra/ioctl_solaris.c +++ b/zebra/ioctl_solaris.c @@ -28,6 +28,7 @@ #include "ioctl.h" #include "log.h" #include "privs.h" +#include "vty.h" #include "zebra/rib.h" #include "zebra/rt.h" diff --git a/zebra/kernel_null.c b/zebra/kernel_null.c index 1a16a75a..3813e45a 100644 --- a/zebra/kernel_null.c +++ b/zebra/kernel_null.c @@ -23,6 +23,7 @@ #include <zebra.h> #include <log.h> +#include <vty.h> #include "zebra/zserv.h" #include "zebra/rt.h" diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 5e68c567..aee0cb55 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -34,6 +34,7 @@ #include "rib.h" #include "privs.h" #include "vrf.h" +#include "vty.h" #include "zebra/interface.h" #include "zebra/zserv.h" diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 57b515e1..dd45af66 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -159,7 +159,10 @@ zebra_redistribute (struct zserv *client, int type, vrf_id_t vrf_id) && newrib->type == type && newrib->distance != DISTANCE_INFINITY && zebra_check_addr (&rn->p)) - zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, &rn->p, newrib); + { + client->redist_v4_add_cnt++; + zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, &rn->p, newrib); + } } #ifdef HAVE_IPV6 @@ -171,7 +174,10 @@ zebra_redistribute (struct zserv *client, int type, vrf_id_t vrf_id) && newrib->type == type && newrib->distance != DISTANCE_INFINITY && zebra_check_addr (&rn->p)) - zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, &rn->p, newrib); + { + client->redist_v6_add_cnt++; + zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, &rn->p, newrib); + } #endif /* HAVE_IPV6 */ } @@ -188,11 +194,15 @@ redistribute_add (struct prefix *p, struct rib *rib) || vrf_bitmap_check (client->redist[rib->type], rib->vrf_id)) { if (p->family == AF_INET) - zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, p, rib); -#ifdef HAVE_IPV6 + { + client->redist_v4_add_cnt++; + zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, p, rib); + } if (p->family == AF_INET6) - zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, p, rib); -#endif /* HAVE_IPV6 */ + { + client->redist_v6_add_cnt++; + zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, p, rib); + } } } } @@ -281,7 +291,9 @@ zebra_interface_up_update (struct interface *ifp) zlog_debug ("MESSAGE: ZEBRA_INTERFACE_UP %s", ifp->name); for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) - zsend_interface_update (ZEBRA_INTERFACE_UP, client, ifp); + { + zsend_interface_update (ZEBRA_INTERFACE_UP, client, ifp); + } } /* Interface down information. */ @@ -295,7 +307,9 @@ zebra_interface_down_update (struct interface *ifp) zlog_debug ("MESSAGE: ZEBRA_INTERFACE_DOWN %s", ifp->name); for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) - zsend_interface_update (ZEBRA_INTERFACE_DOWN, client, ifp); + { + zsend_interface_update (ZEBRA_INTERFACE_DOWN, client, ifp); + } } /* Interface information update. */ @@ -310,7 +324,10 @@ zebra_interface_add_update (struct interface *ifp) for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) if (client->ifinfo) - zsend_interface_add (client, ifp); + { + client->ifadd_cnt++; + zsend_interface_add (client, ifp); + } } void @@ -324,7 +341,10 @@ zebra_interface_delete_update (struct interface *ifp) for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) if (client->ifinfo) - zsend_interface_delete (client, ifp); + { + client->ifdel_cnt++; + zsend_interface_delete (client, ifp); + } } /* Interface address addition. */ @@ -353,7 +373,10 @@ zebra_interface_address_add_update (struct interface *ifp, for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) if (client->ifinfo && CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) - zsend_interface_address (ZEBRA_INTERFACE_ADDRESS_ADD, client, ifp, ifc); + { + client->connected_rt_add_cnt++; + zsend_interface_address (ZEBRA_INTERFACE_ADDRESS_ADD, client, ifp, ifc); + } } /* Interface address deletion. */ @@ -379,5 +402,8 @@ zebra_interface_address_delete_update (struct interface *ifp, for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) if (client->ifinfo && CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) - zsend_interface_address (ZEBRA_INTERFACE_ADDRESS_DELETE, client, ifp, ifc); + { + client->connected_rt_del_cnt++; + zsend_interface_address (ZEBRA_INTERFACE_ADDRESS_DELETE, client, ifp, ifc); + } } diff --git a/zebra/redistribute_null.c b/zebra/redistribute_null.c index c68cec6a..7a39de46 100644 --- a/zebra/redistribute_null.c +++ b/zebra/redistribute_null.c @@ -20,6 +20,7 @@ */ #include <zebra.h> +#include <vty.h> #include "zebra/rib.h" #include "zebra/zserv.h" diff --git a/zebra/rib.h b/zebra/rib.h index 1dacc7f7..a916aa99 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -27,18 +27,10 @@ #include "prefix.h" #include "table.h" #include "queue.h" +#include "nexthop.h" #define DISTANCE_INFINITY 255 -/* Routing information base. */ - -union g_addr { - struct in_addr ipv4; -#ifdef HAVE_IPV6 - struct in6_addr ipv6; -#endif /* HAVE_IPV6 */ -}; - struct rib { /* Link list. */ @@ -73,6 +65,9 @@ struct rib /* Distance. */ u_char distance; + /* Tag */ + u_short tag; + /* Flags of this route. * This flag's definition is in lib/zebra.h ZEBRA_FLAG_* and is exposed * to clients via Zserv @@ -81,9 +76,10 @@ struct rib /* RIB internal status */ u_char status; -#define RIB_ENTRY_REMOVED (1 << 0) -#define RIB_ENTRY_CHANGED (1 << 1) -#define RIB_ENTRY_SELECTED_FIB (1 << 2) +#define RIB_ENTRY_REMOVED (1 << 0) + /* to simplify NHT logic when NHs change, instead of doing a NH by NH cmp */ +#define RIB_ENTRY_NEXTHOPS_CHANGED (1 << 1) +#define RIB_ENTRY_SELECTED_FIB (1 << 2) /* Nexthop information. */ u_char nexthop_num; @@ -186,6 +182,9 @@ struct static_route /* Administrative distance. */ u_char distance; + /* Tag */ + u_short tag; + /* Flag for this static route's type. */ u_char type; #define STATIC_IPV4_GATEWAY 1 @@ -207,50 +206,6 @@ struct static_route */ }; -enum nexthop_types_t -{ - NEXTHOP_TYPE_IFINDEX = 1, /* Directly connected. */ - NEXTHOP_TYPE_IFNAME, /* Interface route. */ - NEXTHOP_TYPE_IPV4, /* IPv4 nexthop. */ - NEXTHOP_TYPE_IPV4_IFINDEX, /* IPv4 nexthop with ifindex. */ - NEXTHOP_TYPE_IPV4_IFNAME, /* IPv4 nexthop with ifname. */ - NEXTHOP_TYPE_IPV6, /* IPv6 nexthop. */ - NEXTHOP_TYPE_IPV6_IFINDEX, /* IPv6 nexthop with ifindex. */ - NEXTHOP_TYPE_IPV6_IFNAME, /* IPv6 nexthop with ifname. */ - NEXTHOP_TYPE_BLACKHOLE, /* Null0 nexthop. */ -}; - -/* Nexthop structure. */ -struct nexthop -{ - struct nexthop *next; - struct nexthop *prev; - - /* Interface index. */ - char *ifname; - ifindex_t ifindex; - - enum nexthop_types_t type; - - u_char flags; -#define NEXTHOP_FLAG_ACTIVE (1 << 0) /* This nexthop is alive. */ -#define NEXTHOP_FLAG_FIB (1 << 1) /* FIB nexthop. */ -#define NEXTHOP_FLAG_RECURSIVE (1 << 2) /* Recursive nexthop. */ -#define NEXTHOP_FLAG_ONLINK (1 << 3) /* Nexthop should be installed onlink. */ - - /* Nexthop address */ - union g_addr gate; - union g_addr src; - - /* Nexthops obtained by recursive resolution. - * - * If the nexthop struct needs to be resolved recursively, - * NEXTHOP_FLAG_RECURSIVE will be set in flags and the nexthops - * obtained by recursive resolution will be added to `resolved'. - * Only one level of recursive resolution is currently supported. */ - struct nexthop *resolved; -}; - /* The following for loop allows to iterate over the nexthop * structure of routes. * @@ -297,15 +252,6 @@ struct nexthop : ((tnexthop) = (nexthop)->next)) \ : (((recursing) = 0),((tnexthop) = (tnexthop)->next))) -/* Structure holding nexthop & VRF identifier, - * used for applying the route-map. */ -struct nexthop_vrfid -{ - struct nexthop *nexthop; - vrf_id_t vrf_id; -}; - - #if defined (HAVE_RTADV) /* Structure which hold status of router advertisement. */ struct rtadv @@ -370,6 +316,9 @@ struct zebra_vrf #if defined (HAVE_RTADV) struct rtadv rtadv; #endif /* HAVE_RTADV */ + + /* Recursive Nexthop table */ + struct route_table *rnh_table[AFI_MAX]; }; /* @@ -425,15 +374,19 @@ extern void multicast_mode_ipv4_set (enum multicast_mode mode); extern enum multicast_mode multicast_mode_ipv4_get (void); extern const char *nexthop_type_to_str (enum nexthop_types_t nh_type); -extern struct nexthop *nexthop_ifindex_add (struct rib *, ifindex_t); -extern struct nexthop *nexthop_ifname_add (struct rib *, char *); -extern struct nexthop *nexthop_blackhole_add (struct rib *); -extern struct nexthop *nexthop_ipv4_add (struct rib *, struct in_addr *, - struct in_addr *); -extern struct nexthop *nexthop_ipv4_ifindex_add (struct rib *, - struct in_addr *, - struct in_addr *, - ifindex_t); +extern struct nexthop *rib_nexthop_ifindex_add (struct rib *, ifindex_t); +extern struct nexthop *rib_nexthop_ifname_add (struct rib *, char *); +extern struct nexthop *rib_nexthop_blackhole_add (struct rib *); +extern struct nexthop *rib_nexthop_ipv4_add (struct rib *, struct in_addr *, + struct in_addr *); +extern struct nexthop *rib_nexthop_ipv4_ifindex_add (struct rib *, + struct in_addr *, + struct in_addr *, + ifindex_t); + +extern void rib_nexthop_add (struct rib *rib, struct nexthop *nexthop); +extern void rib_copy_nexthops (struct rib *rib, struct nexthop *nexthop); + extern int nexthop_has_fib_child(struct nexthop *); extern void rib_lookup_and_dump (struct prefix_ipv4 *); extern void rib_lookup_and_pushup (struct prefix_ipv4 *); @@ -448,8 +401,11 @@ extern int rib_lookup_ipv4_route (struct prefix_ipv4 *, union sockunion *, #define ZEBRA_RIB_FOUND_CONNECTED 2 #define ZEBRA_RIB_NOTFOUND 3 -extern struct nexthop *nexthop_ipv6_add (struct rib *, struct in6_addr *); +extern struct nexthop *rib_nexthop_ipv6_add (struct rib *, struct in6_addr *); +extern struct nexthop *rib_nexthop_ipv6_ifindex_add (struct rib *rib, + struct in6_addr *ipv6, ifindex_t ifindex); +extern struct zebra_vrf *zebra_vrf_lookup (vrf_id_t vrf_id); extern struct zebra_vrf *zebra_vrf_alloc (vrf_id_t); extern struct route_table *zebra_vrf_table (afi_t, safi_t, vrf_id_t); extern struct route_table *zebra_vrf_static_table (afi_t, safi_t, vrf_id_t); @@ -469,7 +425,7 @@ extern int rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, vrf_id_t, safi_t safi); extern struct rib *rib_match_ipv4_safi (struct in_addr addr, safi_t safi, - int skip_bgp, struct route_node **rn_out, + struct route_node **rn_out, vrf_id_t); extern struct rib *rib_match_ipv4_multicast (struct in_addr addr, struct route_node **rn_out, @@ -484,14 +440,17 @@ extern void rib_close_table (struct route_table *); extern void rib_close (void); extern void rib_init (void); extern unsigned long rib_score_proto (u_char proto); +struct zebra_t; +extern void rib_queue_add (struct zebra_t *zebra, struct route_node *rn); + extern int static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, - const char *ifname, u_char flags, u_char distance, + const char *ifname, u_char flags, u_short tag, u_char distance, vrf_id_t vrf_id); extern int static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, - const char *ifname, u_char distance, vrf_id_t vrf_id); + const char *ifname, u_short tag, u_char distance, vrf_id_t vrf_id); extern int rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, @@ -511,12 +470,15 @@ extern struct route_table *rib_table_ipv6; extern int static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, - const char *ifname, u_char flags, u_char distance, + const char *ifname, u_char flags, u_short tag, u_char distance, vrf_id_t vrf_id); extern int +rib_add_ipv6_multipath (struct prefix_ipv6 *, struct rib *, safi_t); + +extern int static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, - const char *ifname, u_char distance, vrf_id_t vrf_id); + const char *ifname, u_short tag, u_char distance, vrf_id_t vrf_id); extern int rib_gc_dest (struct route_node *rn); extern struct route_table *rib_tables_iter_next (rib_tables_iter_t *iter); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index e4505de3..131b37a6 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -38,6 +38,8 @@ #include "thread.h" #include "privs.h" #include "vrf.h" +#include "nexthop.h" +#include "vty.h" #include "zebra/zserv.h" #include "zebra/rt.h" @@ -851,12 +853,12 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h, if (gate) { if (index) - nexthop_ipv4_ifindex_add (rib, gate, src, index); + rib_nexthop_ipv4_ifindex_add (rib, gate, src, index); else - nexthop_ipv4_add (rib, gate, src); + rib_nexthop_ipv4_add (rib, gate, src); } else - nexthop_ifindex_add (rib, index); + rib_nexthop_ifindex_add (rib, index); len -= NLMSG_ALIGN(rtnh->rtnh_len); rtnh = RTNH_NEXT(rtnh); @@ -907,6 +909,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, int len; struct rtmsg *rtm; struct rtattr *tb[RTA_MAX + 1]; + u_char zebra_flags = 0; char anyaddr[16] = { 0 }; @@ -964,6 +967,8 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE) return 0; + if (rtm->rtm_protocol == RTPROT_ZEBRA) + SET_FLAG(zebra_flags, ZEBRA_FLAG_SELFROUTE); if (rtm->rtm_src_len != 0) { @@ -1065,12 +1070,12 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, if (gate) { if (index) - nexthop_ipv4_ifindex_add (rib, gate, src, index); + rib_nexthop_ipv4_ifindex_add (rib, gate, src, index); else - nexthop_ipv4_add (rib, gate, src); + rib_nexthop_ipv4_add (rib, gate, src); } else - nexthop_ifindex_add (rib, index); + rib_nexthop_ifindex_add (rib, index); len -= NLMSG_ALIGN(rtnh->rtnh_len); rtnh = RTNH_NEXT(rtnh); @@ -1083,8 +1088,8 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, } } else - rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id, - SAFI_UNICAST); + rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, gate, + index, vrf_id, SAFI_UNICAST); } #ifdef HAVE_IPV6 @@ -1108,7 +1113,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id, table, 0, mtu, 0, SAFI_UNICAST); else - rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id, + rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, gate, index, vrf_id, SAFI_UNICAST); } #endif /* HAVE_IPV6 */ @@ -1470,7 +1475,8 @@ _netlink_route_build_singlepath( struct nexthop *nexthop, struct nlmsghdr *nlmsg, struct rtmsg *rtmsg, - size_t req_size) + size_t req_size, + int cmd) { if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK)) rtmsg->rtm_flags |= RTNH_F_ONLINK; @@ -1479,7 +1485,11 @@ _netlink_route_build_singlepath( { addattr_l (nlmsg, req_size, RTA_GATEWAY, &nexthop->gate.ipv4, bytelen); - if (nexthop->src.ipv4.s_addr) + + if (nexthop->rmap_src.ipv4.s_addr && (cmd == RTM_NEWROUTE)) + addattr_l (nlmsg, req_size, RTA_PREFSRC, + &nexthop->rmap_src.ipv4, bytelen); + else if (nexthop->src.ipv4.s_addr && (cmd == RTM_NEWROUTE)) addattr_l (nlmsg, req_size, RTA_PREFSRC, &nexthop->src.ipv4, bytelen); @@ -1512,7 +1522,10 @@ _netlink_route_build_singlepath( { addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex); - if (nexthop->src.ipv4.s_addr) + if (nexthop->rmap_src.ipv4.s_addr && (cmd == RTM_NEWROUTE)) + addattr_l (nlmsg, req_size, RTA_PREFSRC, + &nexthop->rmap_src.ipv4, bytelen); + else if (nexthop->src.ipv4.s_addr && (cmd == RTM_NEWROUTE)) addattr_l (nlmsg, req_size, RTA_PREFSRC, &nexthop->src.ipv4, bytelen); @@ -1573,8 +1586,10 @@ _netlink_route_build_multipath( &nexthop->gate.ipv4, bytelen); rtnh->rtnh_len += sizeof (struct rtattr) + bytelen; - if (nexthop->src.ipv4.s_addr) - *src = &nexthop->src; + if (nexthop->rmap_src.ipv4.s_addr) + *src = &nexthop->rmap_src; + else if (nexthop->src.ipv4.s_addr) + *src = &nexthop->src; if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (%s): " @@ -1606,8 +1621,12 @@ _netlink_route_build_multipath( || nexthop->type == NEXTHOP_TYPE_IFNAME) { rtnh->rtnh_ifindex = nexthop->ifindex; - if (nexthop->src.ipv4.s_addr) + + if (nexthop->rmap_src.ipv4.s_addr) + *src = &nexthop->rmap_src; + else if (nexthop->src.ipv4.s_addr) *src = &nexthop->src; + if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (%s): " "nexthop via if %u", routedesc, nexthop->ifindex); @@ -1670,6 +1689,8 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib) int discard; int family = PREFIX_FAMILY(p); const char *routedesc; + int setsrc = 0; + union g_addr src; struct { @@ -1708,6 +1729,10 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib) req.r.rtm_type = RTN_UNREACHABLE; else assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */ + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug ("%s: Adding discard route for family %s\n", + __FUNCTION__, family == AF_INET ? "IPv4" : "IPv6"); } else req.r.rtm_type = RTN_UNICAST; @@ -1773,7 +1798,23 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib) for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) { if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) - continue; + { + /* This only works for IPv4 now */ + if (!setsrc) + { + if (nexthop->rmap_src.ipv4.s_addr != 0) + { + src.ipv4 = nexthop->rmap_src.ipv4; + setsrc = 1; + } + else if (nexthop->src.ipv4.s_addr != 0) + { + src.ipv4 = nexthop->src.ipv4; + setsrc = 1; + } + } + continue; + } if ((cmd == RTM_NEWROUTE && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) @@ -1785,7 +1826,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib) _netlink_route_debug(cmd, p, nexthop, routedesc, family, zvrf); _netlink_route_build_singlepath(routedesc, bytelen, nexthop, &req.n, &req.r, - sizeof req); + sizeof req, cmd); if (cmd == RTM_NEWROUTE) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); @@ -1794,13 +1835,15 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib) break; } } + if (setsrc && (cmd == RTM_NEWROUTE)) + addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src.ipv4, bytelen); } else { char buf[NL_PKT_BUF_SIZE]; struct rtattr *rta = (void *) buf; struct rtnexthop *rtnh; - union g_addr *src = NULL; + union g_addr *src1 = NULL; rta->rta_type = RTA_MULTIPATH; rta->rta_len = RTA_LENGTH (0); @@ -1813,7 +1856,23 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib) break; if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) - continue; + { + /* This only works for IPv4 now */ + if (!setsrc) + { + if (nexthop->rmap_src.ipv4.s_addr != 0) + { + src.ipv4 = nexthop->rmap_src.ipv4; + setsrc = 1; + } + else if (nexthop->src.ipv4.s_addr != 0) + { + src.ipv4 = nexthop->src.ipv4; + setsrc = 1; + } + } + continue; + } if ((cmd == RTM_NEWROUTE && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) @@ -1826,15 +1885,21 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib) _netlink_route_debug(cmd, p, nexthop, routedesc, family, zvrf); _netlink_route_build_multipath(routedesc, bytelen, - nexthop, rta, rtnh, &src); + nexthop, rta, rtnh, &src1); rtnh = RTNH_NEXT (rtnh); if (cmd == RTM_NEWROUTE) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + + if (!setsrc && src1) + { + src.ipv4 = src1->ipv4; + setsrc = 1; + } } } - if (src) - addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src->ipv4, bytelen); + if (setsrc && (cmd == RTM_NEWROUTE)) + addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src.ipv4, bytelen); if (rta->rta_len > RTA_LENGTH (0)) addattr_l (&req.n, NL_PKT_BUF_SIZE, RTA_MULTIPATH, RTA_DATA (rta), diff --git a/zebra/rtadv.c b/zebra/rtadv.c index 9450f9a9..8660f733 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -402,14 +402,83 @@ rtadv_process_solicit (struct interface *ifp) } static void -rtadv_process_advert (void) +rtadv_process_advert (u_char *msg, unsigned int len, struct interface *ifp, + struct sockaddr_in6 *addr) { - zlog_info ("Router advertisement received"); + struct nd_router_advert *radvert; + char addr_str[INET6_ADDRSTRLEN]; + struct zebra_if *zif; + + zif = ifp->info; + + inet_ntop (AF_INET6, &addr->sin6_addr, addr_str, INET6_ADDRSTRLEN); + + zlog_info ("Router advertisement received on %s from : %s", ifp->name, addr_str); + + if (len < sizeof(struct nd_router_advert)) { + zlog_warn("received icmpv6 RA packet with invalid length (%d) from %s", + len, addr_str); + return; + } + if (!IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) { + zlog_warn("received icmpv6 RA packet with non-linklocal source address from %s", + addr_str); + return; + } + + radvert = (struct nd_router_advert *) msg; + + if ((radvert->nd_ra_curhoplimit && zif->rtadv.AdvCurHopLimit) && + (radvert->nd_ra_curhoplimit != zif->rtadv.AdvCurHopLimit)) + { + zlog_warn("our AdvCurHopLimit on %s doesn't agree with %s", + ifp->name, addr_str); + } + + if ((radvert->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) && + !zif->rtadv.AdvManagedFlag) + { + zlog_warn("our AdvManagedFlag on %s doesn't agree with %s", + ifp->name, addr_str); + } + + if ((radvert->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) && + !zif->rtadv.AdvOtherConfigFlag) + { + zlog_warn("our AdvOtherConfigFlag on %s doesn't agree with %s", + ifp->name, addr_str); + } + + if ((radvert->nd_ra_reachable && zif->rtadv.AdvReachableTime) && + (ntohl(radvert->nd_ra_reachable) != zif->rtadv.AdvReachableTime)) + { + zlog_warn("our AdvReachableTime on %s doesn't agree with %s", + ifp->name, addr_str); + } + + if ((radvert->nd_ra_retransmit && zif->rtadv.AdvRetransTimer) && + (ntohl(radvert->nd_ra_retransmit) != (unsigned int)zif->rtadv.AdvRetransTimer)) + { + zlog_warn("our AdvRetransTimer on %s doesn't agree with %s", + ifp->name, addr_str); + } + + /* Currently supporting only P2P links, so any new RA source address is + considered as the replacement of the previously learnt Link-Local address. + As per the RFC, lifetime zero is to be considered a delete */ + if (ntohs(radvert->nd_ra_router_lifetime)) + nbr_connected_replacement_add_ipv6(ifp, &addr->sin6_addr, 128); + else + nbr_connected_delete_ipv6(ifp, &addr->sin6_addr, 128); + + return; } + static void -rtadv_process_packet (u_char *buf, unsigned int len, ifindex_t ifindex, - int hoplimit, vrf_id_t vrf_id) +rtadv_process_packet (u_char *buf, unsigned int len, unsigned int ifindex, + int hoplimit, vrf_id_t vrf_id, + struct sockaddr_in6 *from) { struct icmp6_hdr *icmph; struct interface *ifp; @@ -460,7 +529,7 @@ rtadv_process_packet (u_char *buf, unsigned int len, ifindex_t ifindex, if (icmph->icmp6_type == ND_ROUTER_SOLICIT) rtadv_process_solicit (ifp); else if (icmph->icmp6_type == ND_ROUTER_ADVERT) - rtadv_process_advert (); + rtadv_process_advert (buf, len, ifp, from); return; } @@ -490,7 +559,7 @@ rtadv_read (struct thread *thread) return len; } - rtadv_process_packet (buf, (unsigned)len, ifindex, hoplimit, zvrf->vrf_id); + rtadv_process_packet (buf, (unsigned)len, ifindex, hoplimit, zvrf->vrf_id, &from); return 0; } @@ -1539,8 +1608,6 @@ rtadv_config_write (struct vty *vty, struct interface *ifp) { if (zif->rtadv.AdvSendAdvertisements) vty_out (vty, " no ipv6 nd suppress-ra%s", VTY_NEWLINE); - else - vty_out (vty, " ipv6 nd suppress-ra%s", VTY_NEWLINE); } diff --git a/zebra/rtread_getmsg.c b/zebra/rtread_getmsg.c index 89153941..e1ec6709 100644 --- a/zebra/rtread_getmsg.c +++ b/zebra/rtread_getmsg.c @@ -26,6 +26,7 @@ #include "log.h" #include "if.h" #include "vrf.h" +#include "vty.h" #include "zebra/rib.h" #include "zebra/zserv.h" diff --git a/zebra/rtread_netlink.c b/zebra/rtread_netlink.c index 1f658646..a9d9c86c 100644 --- a/zebra/rtread_netlink.c +++ b/zebra/rtread_netlink.c @@ -21,6 +21,7 @@ */ #include <zebra.h> +#include <vty.h> #include "zebra/zserv.h" #include "rt_netlink.h" diff --git a/zebra/rtread_sysctl.c b/zebra/rtread_sysctl.c index 385e1506..9108d2ca 100644 --- a/zebra/rtread_sysctl.c +++ b/zebra/rtread_sysctl.c @@ -25,6 +25,7 @@ #include "memory.h" #include "log.h" #include "vrf.h" +#include "vty.h" #include "zebra/zserv.h" #include "zebra/rt.h" diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c index 01730007..c53d282b 100644 --- a/zebra/zebra_fpm_netlink.c +++ b/zebra/zebra_fpm_netlink.c @@ -29,6 +29,7 @@ #include "rib.h" #include "rt_netlink.h" +#include "nexthop.h" #include "zebra_fpm_private.h" diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 1650dabf..53691c76 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -35,13 +35,16 @@ #include "prefix.h" #include "routemap.h" #include "vrf.h" +#include "nexthop.h" +#include "zebra/connected.h" #include "zebra/rib.h" #include "zebra/rt.h" #include "zebra/zserv.h" #include "zebra/redistribute.h" #include "zebra/debug.h" #include "zebra/zebra_fpm.h" +#include "zebra/zebra_rnh.h" /* Default rtm_table for all clients */ extern struct zebra_t zebrad; @@ -110,57 +113,38 @@ _rnode_zlog(const char *_func, struct route_node *rn, int priority, #define rnode_info(node, ...) \ _rnode_zlog(__func__, node, LOG_INFO, __VA_ARGS__) -/* - * nexthop_type_to_str - */ -const char * -nexthop_type_to_str (enum nexthop_types_t nh_type) -{ - static const char *desc[] = { - "none", - "Directly connected", - "Interface route", - "IPv4 nexthop", - "IPv4 nexthop with ifindex", - "IPv4 nexthop with ifname", - "IPv6 nexthop", - "IPv6 nexthop with ifindex", - "IPv6 nexthop with ifname", - "Null0 nexthop", - }; - - if (nh_type >= ZEBRA_NUM_OF (desc)) - return "<Invalid nh type>"; - - return desc[nh_type]; -} - -/* Add nexthop to the end of a nexthop list. */ -static void -_nexthop_add (struct nexthop **target, struct nexthop *nexthop) +/* Add nexthop to the end of a rib node's nexthop list */ +void +rib_nexthop_add (struct rib *rib, struct nexthop *nexthop) { - struct nexthop *last; - - for (last = *target; last && last->next; last = last->next) - ; - if (last) - last->next = nexthop; - else - *target = nexthop; - nexthop->prev = last; + nexthop_add(&rib->nexthop, nexthop); + rib->nexthop_num++; } -/* Add nexthop to the end of a rib node's nexthop list */ -static void -nexthop_add (struct rib *rib, struct nexthop *nexthop) +/** + * copy_nexthop - copy a nexthop to the rib structure. + */ +void +rib_copy_nexthops (struct rib *rib, struct nexthop *nh) { - _nexthop_add(&rib->nexthop, nexthop); - rib->nexthop_num++; + struct nexthop *nexthop; + + nexthop = nexthop_new(); + nexthop->flags = nh->flags; + nexthop->type = nh->type; + nexthop->ifindex = nh->ifindex; + if (nh->ifname) + nexthop->ifname = XSTRDUP(0, nh->ifname); + memcpy(&(nexthop->gate), &(nh->gate), sizeof(union g_addr)); + memcpy(&(nexthop->src), &(nh->src), sizeof(union g_addr)); + rib_nexthop_add(rib, nexthop); + if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) + copy_nexthops(&nexthop->resolved, nh->resolved); } /* Delete specified nexthop from the list. */ static void -nexthop_delete (struct rib *rib, struct nexthop *nexthop) +rib_nexthop_delete (struct rib *rib, struct nexthop *nexthop) { if (nexthop->next) nexthop->next->prev = nexthop->prev; @@ -171,150 +155,130 @@ nexthop_delete (struct rib *rib, struct nexthop *nexthop) rib->nexthop_num--; } -static void nexthops_free(struct nexthop *nexthop); - -/* Free nexthop. */ -static void -nexthop_free (struct nexthop *nexthop) -{ - if (nexthop->ifname) - XFREE (0, nexthop->ifname); - if (nexthop->resolved) - nexthops_free(nexthop->resolved); - XFREE (MTYPE_NEXTHOP, nexthop); -} - -/* Frees a list of nexthops */ -static void -nexthops_free (struct nexthop *nexthop) -{ - struct nexthop *nh, *next; - - for (nh = nexthop; nh; nh = next) - { - next = nh->next; - nexthop_free (nh); - } -} - struct nexthop * -nexthop_ifindex_add (struct rib *rib, ifindex_t ifindex) +rib_nexthop_ifindex_add (struct rib *rib, ifindex_t ifindex) { struct nexthop *nexthop; - nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + nexthop = nexthop_new (); nexthop->type = NEXTHOP_TYPE_IFINDEX; nexthop->ifindex = ifindex; - nexthop_add (rib, nexthop); + rib_nexthop_add (rib, nexthop); return nexthop; } struct nexthop * -nexthop_ifname_add (struct rib *rib, char *ifname) +rib_nexthop_ifname_add (struct rib *rib, char *ifname) { struct nexthop *nexthop; - nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + nexthop = nexthop_new (); nexthop->type = NEXTHOP_TYPE_IFNAME; nexthop->ifname = XSTRDUP (0, ifname); - nexthop_add (rib, nexthop); + rib_nexthop_add (rib, nexthop); return nexthop; } struct nexthop * -nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4, struct in_addr *src) +rib_nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4, struct in_addr *src) { struct nexthop *nexthop; - nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + nexthop = nexthop_new (); nexthop->type = NEXTHOP_TYPE_IPV4; nexthop->gate.ipv4 = *ipv4; if (src) nexthop->src.ipv4 = *src; - nexthop_add (rib, nexthop); + rib_nexthop_add (rib, nexthop); return nexthop; } struct nexthop * -nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4, - struct in_addr *src, ifindex_t ifindex) +rib_nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4, + struct in_addr *src, ifindex_t ifindex) { struct nexthop *nexthop; - nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + nexthop = nexthop_new (); nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX; nexthop->gate.ipv4 = *ipv4; if (src) nexthop->src.ipv4 = *src; nexthop->ifindex = ifindex; - nexthop_add (rib, nexthop); + rib_nexthop_add (rib, nexthop); return nexthop; } struct nexthop * -nexthop_ipv6_add (struct rib *rib, struct in6_addr *ipv6) +rib_nexthop_ipv6_add (struct rib *rib, struct in6_addr *ipv6) { struct nexthop *nexthop; - nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + nexthop = nexthop_new (); nexthop->type = NEXTHOP_TYPE_IPV6; nexthop->gate.ipv6 = *ipv6; - nexthop_add (rib, nexthop); + rib_nexthop_add (rib, nexthop); return nexthop; } static struct nexthop * -nexthop_ipv6_ifname_add (struct rib *rib, struct in6_addr *ipv6, - char *ifname) +rib_nexthop_ipv6_ifname_add (struct rib *rib, struct in6_addr *ipv6, + char *ifname) { struct nexthop *nexthop; - nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + nexthop = nexthop_new (); nexthop->type = NEXTHOP_TYPE_IPV6_IFNAME; nexthop->gate.ipv6 = *ipv6; nexthop->ifname = XSTRDUP (0, ifname); - nexthop_add (rib, nexthop); + rib_nexthop_add (rib, nexthop); return nexthop; } -static struct nexthop * -nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_addr *ipv6, - ifindex_t ifindex) +struct nexthop * +rib_nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_addr *ipv6, + ifindex_t ifindex) { struct nexthop *nexthop; + struct interface *ifp; - nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + nexthop = nexthop_new (); nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX; nexthop->gate.ipv6 = *ipv6; nexthop->ifindex = ifindex; + ifp = if_lookup_by_index (nexthop->ifindex); + if (connected_is_unnumbered(ifp)) + { + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK); + } - nexthop_add (rib, nexthop); + rib_nexthop_add (rib, nexthop); return nexthop; } struct nexthop * -nexthop_blackhole_add (struct rib *rib) +rib_nexthop_blackhole_add (struct rib *rib) { struct nexthop *nexthop; - nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + nexthop = nexthop_new (); nexthop->type = NEXTHOP_TYPE_BLACKHOLE; SET_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE); - nexthop_add (rib, nexthop); + rib_nexthop_add (rib, nexthop); return nexthop; } @@ -348,8 +312,9 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, struct route_node *rn; struct rib *match; int resolved; - struct nexthop *newhop; + struct nexthop *newhop, *tnewhop; struct nexthop *resolved_hop; + int recursing = 0; if (nexthop->type == NEXTHOP_TYPE_IPV4) nexthop->ifindex = 0; @@ -357,11 +322,18 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, if (set) { UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); + zebra_deregister_rnh_static_nexthops (nexthop->resolved, top); nexthops_free(nexthop->resolved); nexthop->resolved = NULL; rib->nexthop_mtu = 0; } + /* Skip nexthops that have been filtered out due to route-map */ + /* The nexthops are specific to this route and so the same */ + /* nexthop for a different route may not have this flag set */ + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FILTERED)) + return 0; + /* Make lookup prefix. */ memset (&p, 0, sizeof (struct prefix_ipv4)); p.family = AF_INET; @@ -393,8 +365,7 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, /* If there is no selected route or matched route is EGP, go up tree. */ - if (! match - || match->type == ZEBRA_ROUTE_BGP) + if (! match) { do { rn = rn->parent; @@ -429,6 +400,7 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, if (set) { SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); + SET_FLAG(rib->status, RIB_ENTRY_NEXTHOPS_CHANGED); resolved_hop = XCALLOC(MTYPE_NEXTHOP, sizeof (struct nexthop)); SET_FLAG (resolved_hop->flags, NEXTHOP_FLAG_ACTIVE); @@ -455,7 +427,7 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, resolved_hop->ifindex = newhop->ifindex; } - _nexthop_add(&nexthop->resolved, resolved_hop); + nexthop_add(&nexthop->resolved, resolved_hop); } resolved = 1; } @@ -463,6 +435,57 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, rib->nexthop_mtu = match->mtu; return resolved; } + else if (rib->type == ZEBRA_ROUTE_STATIC) + { + resolved = 0; + for (ALL_NEXTHOPS_RO(match->nexthop, newhop, tnewhop, recursing)) + if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)) + { + if (set) + { + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); + + resolved_hop = XCALLOC(MTYPE_NEXTHOP, sizeof (struct nexthop)); + SET_FLAG (resolved_hop->flags, NEXTHOP_FLAG_ACTIVE); + /* If the resolving route specifies a gateway, use it */ + if (newhop->type == NEXTHOP_TYPE_IPV4 + || newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX + || newhop->type == NEXTHOP_TYPE_IPV4_IFNAME) + { + resolved_hop->type = newhop->type; + resolved_hop->gate.ipv4 = newhop->gate.ipv4; + + if (newhop->ifindex) + { + resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX; + resolved_hop->ifindex = newhop->ifindex; + } + } + + /* If the resolving route is an interface route, + * it means the gateway we are looking up is connected + * to that interface. (The actual network is _not_ onlink). + * Therefore, the resolved route should have the original + * gateway as nexthop as it is directly connected. + * + * On Linux, we have to set the onlink netlink flag because + * otherwise, the kernel won't accept the route. + */ + if (newhop->type == NEXTHOP_TYPE_IFINDEX + || newhop->type == NEXTHOP_TYPE_IFNAME) + { + resolved_hop->flags |= NEXTHOP_FLAG_ONLINK; + resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX; + resolved_hop->gate.ipv4 = nexthop->gate.ipv4; + resolved_hop->ifindex = newhop->ifindex; + } + + nexthop_add(&nexthop->resolved, resolved_hop); + } + resolved = 1; + } + return resolved; + } else { return 0; @@ -483,8 +506,10 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, struct route_node *rn; struct rib *match; int resolved; - struct nexthop *newhop; + struct nexthop *newhop, *tnewhop; + int recursing = 0; struct nexthop *resolved_hop; + struct interface *ifp; if (nexthop->type == NEXTHOP_TYPE_IPV6) nexthop->ifindex = 0; @@ -492,10 +517,36 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, if (set) { UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); + zebra_deregister_rnh_static_nexthops (nexthop->resolved, top); nexthops_free(nexthop->resolved); nexthop->resolved = NULL; } + /* Skip nexthops that have been filtered out due to route-map */ + /* The nexthops are specific to this route and so the same */ + /* nexthop for a different route may not have this flag set */ + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FILTERED)) + return 0; + + /* + * Check to see if we should trust the passed in information + * for UNNUMBERED interfaces as that we won't find the GW + * address in the routing table. + */ + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) + { + ifp = if_lookup_by_index (nexthop->ifindex); + if (ifp && connected_is_unnumbered(ifp)) + { + if (if_is_operative(ifp)) + return 1; + else + return 0; + } + else + return 0; + } + /* Make lookup prefix. */ memset (&p, 0, sizeof (struct prefix_ipv6)); p.family = AF_INET6; @@ -527,8 +578,7 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, /* If there is no selected route or matched route is EGP, go up tree. */ - if (! match - || match->type == ZEBRA_ROUTE_BGP) + if (! match) { do { rn = rn->parent; @@ -564,6 +614,7 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, if (set) { SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); + SET_FLAG(rib->status, RIB_ENTRY_NEXTHOPS_CHANGED); resolved_hop = XCALLOC(MTYPE_NEXTHOP, sizeof (struct nexthop)); SET_FLAG (resolved_hop->flags, NEXTHOP_FLAG_ACTIVE); @@ -592,7 +643,50 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, resolved_hop->ifindex = newhop->ifindex; } - _nexthop_add(&nexthop->resolved, resolved_hop); + nexthop_add(&nexthop->resolved, resolved_hop); + } + resolved = 1; + } + return resolved; + } + else if (rib->type == ZEBRA_ROUTE_STATIC) + { + resolved = 0; + for (ALL_NEXTHOPS_RO(match->nexthop, newhop, tnewhop, recursing)) + if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)) + { + if (set) + { + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); + + resolved_hop = XCALLOC(MTYPE_NEXTHOP, sizeof (struct nexthop)); + SET_FLAG (resolved_hop->flags, NEXTHOP_FLAG_ACTIVE); + /* See nexthop_active_ipv4 for a description how the + * resolved nexthop is constructed. */ + if (newhop->type == NEXTHOP_TYPE_IPV6 + || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX + || newhop->type == NEXTHOP_TYPE_IPV6_IFNAME) + { + resolved_hop->type = newhop->type; + resolved_hop->gate.ipv6 = newhop->gate.ipv6; + + if (newhop->ifindex) + { + resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX; + resolved_hop->ifindex = newhop->ifindex; + } + } + + if (newhop->type == NEXTHOP_TYPE_IFINDEX + || newhop->type == NEXTHOP_TYPE_IFNAME) + { + resolved_hop->flags |= NEXTHOP_FLAG_ONLINK; + resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX; + resolved_hop->gate.ipv6 = nexthop->gate.ipv6; + resolved_hop->ifindex = newhop->ifindex; + } + + nexthop_add(&nexthop->resolved, resolved_hop); } resolved = 1; } @@ -608,7 +702,7 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, } struct rib * -rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp, +rib_match_ipv4_safi (struct in_addr addr, safi_t safi, struct route_node **rn_out, vrf_id_t vrf_id) { struct route_table *table; @@ -639,7 +733,7 @@ rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp, /* If there is no selected route or matched route is EGP, go up tree. */ - if (!match || (skip_bgp && (match->type == ZEBRA_ROUTE_BGP))) + if (! match) { do { rn = rn->parent; @@ -676,29 +770,22 @@ rib_match_ipv4_multicast (struct in_addr addr, struct route_node **rn_out, { struct rib *rib = NULL, *mrib = NULL, *urib = NULL; struct route_node *m_rn = NULL, *u_rn = NULL; - int skip_bgp = 0; /* bool */ switch (ipv4_multicast_mode) { case MCAST_MRIB_ONLY: - return rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, rn_out, - vrf_id); + return rib_match_ipv4_safi (addr, SAFI_MULTICAST, rn_out, vrf_id); case MCAST_URIB_ONLY: - return rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, rn_out, - vrf_id); + return rib_match_ipv4_safi (addr, SAFI_UNICAST, rn_out, vrf_id); case MCAST_NO_CONFIG: case MCAST_MIX_MRIB_FIRST: - rib = mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn, - vrf_id); + rib = mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, &m_rn, vrf_id); if (!mrib) - rib = urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, &u_rn, - vrf_id); + rib = urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, &u_rn, vrf_id); break; case MCAST_MIX_DISTANCE: - mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn, - vrf_id); - urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, &u_rn, - vrf_id); + mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, &m_rn, vrf_id); + urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, &u_rn, vrf_id); if (mrib && urib) rib = urib->distance < mrib->distance ? urib : mrib; else if (mrib) @@ -707,10 +794,8 @@ rib_match_ipv4_multicast (struct in_addr addr, struct route_node **rn_out, rib = urib; break; case MCAST_MIX_PFXLEN: - mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn, - vrf_id); - urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, &u_rn, - vrf_id); + mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, &m_rn, vrf_id); + urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, &u_rn, vrf_id); if (mrib && urib) rib = u_rn->p.prefixlen > m_rn->p.prefixlen ? urib : mrib; else if (mrib) @@ -782,7 +867,7 @@ rib_lookup_ipv4 (struct prefix_ipv4 *p, vrf_id_t vrf_id) break; } - if (! match || match->type == ZEBRA_ROUTE_BGP) + if (! match) return NULL; if (match->type == ZEBRA_ROUTE_CONNECT) @@ -910,8 +995,7 @@ rib_match_ipv6 (struct in6_addr *addr, vrf_id_t vrf_id) /* If there is no selected route or matched route is EGP, go up tree. */ - if (! match - || match->type == ZEBRA_ROUTE_BGP) + if (! match) { do { rn = rn->parent; @@ -956,9 +1040,8 @@ nexthop_active_check (struct route_node *rn, struct rib *rib, rib_table_info_t *info = rn->table->info; struct interface *ifp; route_map_result_t ret = RMAP_MATCH; - extern char *proto_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1]; - struct route_map *rmap; int family; + char buf[INET6_ADDRSTRLEN+1]; family = 0; switch (nexthop->type) @@ -1045,19 +1128,21 @@ nexthop_active_check (struct route_node *rn, struct rib *rib, if (!family) family = info->afi; - rmap = 0; - if (rib->type >= 0 && rib->type < ZEBRA_ROUTE_MAX && - proto_rm[family][rib->type]) - rmap = route_map_lookup_by_name (proto_rm[family][rib->type]); - if (!rmap && proto_rm[family][ZEBRA_ROUTE_MAX]) - rmap = route_map_lookup_by_name (proto_rm[family][ZEBRA_ROUTE_MAX]); - if (rmap) { - struct nexthop_vrfid nh_vrf = {nexthop, rib->vrf_id}; - ret = route_map_apply(rmap, &rn->p, RMAP_ZEBRA, &nh_vrf); - } + memset(&nexthop->rmap_src.ipv6, 0, sizeof(union g_addr)); + /* It'll get set if required inside */ + ret = zebra_route_map_check(family, rib->type, &rn->p, nexthop, rib->vrf_id); if (ret == RMAP_DENYMATCH) - UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + { + if (IS_ZEBRA_DEBUG_RIB) + { + inet_ntop (rn->p.family, &rn->p.u.prefix, buf, sizeof (buf)); + zlog_debug("%s: Filtering out %s with NH out %s due to route map", + __FUNCTION__, buf, nexthop->ifname); + } + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + } + return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); } @@ -1074,22 +1159,35 @@ static int nexthop_active_update (struct route_node *rn, struct rib *rib, int set) { struct nexthop *nexthop; - unsigned int prev_active, new_active; + union g_addr prev_src; + unsigned int prev_active, new_active, old_num_nh; ifindex_t prev_index; - + + old_num_nh = rib->nexthop_active_num; + rib->nexthop_active_num = 0; - UNSET_FLAG (rib->status, RIB_ENTRY_CHANGED); + UNSET_FLAG (rib->status, RIB_ENTRY_NEXTHOPS_CHANGED); for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) { + /* No protocol daemon provides src and so we're skipping tracking it */ + prev_src = nexthop->rmap_src; prev_active = CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); prev_index = nexthop->ifindex; if ((new_active = nexthop_active_check (rn, rib, nexthop, set))) rib->nexthop_active_num++; + /* Don't allow src setting on IPv6 addr for now */ if (prev_active != new_active || - prev_index != nexthop->ifindex) - SET_FLAG (rib->status, RIB_ENTRY_CHANGED); + prev_index != nexthop->ifindex || + ((nexthop->type >= NEXTHOP_TYPE_IFINDEX && + nexthop->type < NEXTHOP_TYPE_IPV6) && + prev_src.ipv4.s_addr != nexthop->rmap_src.ipv4.s_addr)) + SET_FLAG (rib->status, RIB_ENTRY_NEXTHOPS_CHANGED); } + + if (old_num_nh != rib->nexthop_active_num) + SET_FLAG (rib->status, RIB_ENTRY_NEXTHOPS_CHANGED); + return rib->nexthop_active_num; } @@ -1275,6 +1373,8 @@ rib_process (struct route_node *rn) RNODE_FOREACH_RIB (rn, rib) { + UNSET_FLAG(rib->status, RIB_ENTRY_NEXTHOPS_CHANGED); + /* Currently installed rib. */ if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) { @@ -1292,7 +1392,18 @@ rib_process (struct route_node *rn) continue; /* Skip unreachable nexthop. */ - if (! nexthop_active_update (rn, rib, 0)) + /* This first call to nexthop_active_update is merely to determine if + * there's any change to nexthops associated with this RIB entry. Now, + * rib_process() can be invoked due to an external event such as link + * down or due to next-hop-tracking evaluation. In the latter case, + * a decision has already been made that the NHs have changed. So, no + * need to invoke a potentially expensive call again. Further, since + * the change might be in a recursive NH which is not caught in + * the nexthop_active_update() code. Thus, we might miss changes to + * recursive NHs. + */ + if (!CHECK_FLAG(rib->status, RIB_ENTRY_NEXTHOPS_CHANGED) && + ! nexthop_active_update (rn, rib, 0)) continue; /* Infinit distance. */ @@ -1327,7 +1438,7 @@ rib_process (struct route_node *rn) /* Update kernel if FIB entry has changed */ if (old_fib != new_fib - || (new_fib && CHECK_FLAG (new_fib->status, RIB_ENTRY_CHANGED))) + || (new_fib && CHECK_FLAG (new_fib->status, RIB_ENTRY_NEXTHOPS_CHANGED))) { if (old_fib && old_fib != new_fib) { @@ -1365,7 +1476,7 @@ rib_process (struct route_node *rn) /* Redistribute SELECTED entry */ if (old_selected != new_selected - || (new_selected && CHECK_FLAG (new_selected->status, RIB_ENTRY_CHANGED))) + || (new_selected && CHECK_FLAG (new_selected->status, RIB_ENTRY_NEXTHOPS_CHANGED))) { if (old_selected) { @@ -1436,6 +1547,18 @@ process_subq (struct list * subq, u_char qindex) return 1; } +/* + * All meta queues have been processed. Trigger next-hop evaluation. + */ +static void +meta_queue_process_complete (struct work_queue *dummy) +{ + zebra_evaluate_rnh_table(0, AF_INET, 0); +#ifdef HAVE_IPV6 + zebra_evaluate_rnh_table(0, AF_INET6, 0); +#endif /* HAVE_IPV6 */ +} + /* Dispatch the meta queue by picking, processing and unlocking the next RN from * a non-empty sub-queue with lowest priority. wq is equal to zebra->ribq and data * is pointed to the meta queue structure. @@ -1507,7 +1630,7 @@ rib_meta_queue_add (struct meta_queue *mq, struct route_node *rn) } /* Add route_node to work queue and schedule processing */ -static void +void rib_queue_add (struct zebra_t *zebra, struct route_node *rn) { assert (zebra && rn); @@ -1588,6 +1711,7 @@ rib_queue_init (struct zebra_t *zebra) /* fill in the work queue spec */ zebra->ribq->spec.workfunc = &meta_queue_process; zebra->ribq->spec.errorfunc = NULL; + zebra->ribq->spec.completion_func = &meta_queue_process_complete; /* XXX: TODO: These should be runtime configurable via vty */ zebra->ribq->spec.max_retries = 3; zebra->ribq->spec.hold = rib_process_hold_time; @@ -1720,7 +1844,8 @@ rib_unlink (struct route_node *rn, struct rib *rib) } /* free RIB and nexthops */ - nexthops_free(rib->nexthop); + zebra_deregister_rnh_static_nexthops (rib->nexthop, rn); + nexthops_free (rib->nexthop); XFREE (MTYPE_RIB, rib); } @@ -1811,12 +1936,12 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, if (gate) { if (ifindex) - nexthop_ipv4_ifindex_add (rib, gate, src, ifindex); + rib_nexthop_ipv4_ifindex_add (rib, gate, src, ifindex); else - nexthop_ipv4_add (rib, gate, src); + rib_nexthop_ipv4_add (rib, gate, src); } else - nexthop_ifindex_add (rib, ifindex); + rib_nexthop_ifindex_add (rib, ifindex); /* If this route is kernel route, set FIB flag to the route. */ if (type == ZEBRA_ROUTE_KERNEL || type == ZEBRA_ROUTE_CONNECT) @@ -2009,6 +2134,7 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi) struct route_node *rn; struct rib *same; struct nexthop *nexthop; + int ret = 0; /* Lookup table. */ table = zebra_vrf_table (AFI_IP, safi, rib->vrf_id); @@ -2051,6 +2177,7 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi) /* Link new rib to node.*/ rib_addnode (rn, rib); + ret = 1; if (IS_ZEBRA_DEBUG_RIB) { zlog_debug ("%s: called rib_addnode (%p, %p) on new RIB entry", @@ -2068,10 +2195,11 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi) rib_dump (p, same); } rib_delnode (rn, same); + ret = -1; } route_unlock_node (rn); - return 0; + return ret; } /* XXX factor with rib_delete_ipv6 */ @@ -2178,14 +2306,19 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, kernel. */ if (! same) { - if (fib && type == ZEBRA_ROUTE_KERNEL) - { - /* Unset flags. */ - for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next) - UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); - - UNSET_FLAG (fib->status, RIB_ENTRY_SELECTED_FIB); - } + if (fib && type == ZEBRA_ROUTE_KERNEL && + CHECK_FLAG(flags, ZEBRA_FLAG_SELFROUTE)) + { + if (IS_ZEBRA_DEBUG_KERNEL) + { + zlog_debug ("Zebra route %s/%d was deleted by others from kernel", + inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), + p->prefixlen); + } + /* This means someone else, other than Zebra, has deleted + * a Zebra router from the kernel. We will add it back */ + rib_update_kernel(rn, NULL, fib); + } else { if (IS_ZEBRA_DEBUG_KERNEL) @@ -2222,6 +2355,7 @@ static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ro struct rib *rib; struct route_node *rn; struct route_table *table; + struct prefix nh_p; /* Lookup table. */ table = zebra_vrf_table (afi, safi, si->vrf_id); @@ -2241,28 +2375,40 @@ static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ro if (rib) { + /* if tag value changed , update old value in RIB */ + if (rib->tag != si->tag) + rib->tag = si->tag; + /* Same distance static route is there. Update it with new nexthop. */ route_unlock_node (rn); switch (si->type) { case STATIC_IPV4_GATEWAY: - nexthop_ipv4_add (rib, &si->addr.ipv4, NULL); + rib_nexthop_ipv4_add (rib, &si->addr.ipv4, NULL); + nh_p.family = AF_INET; + nh_p.prefixlen = IPV4_MAX_BITLEN; + nh_p.u.prefix4 = si->addr.ipv4; + zebra_register_rnh_static_nh(&nh_p, rn); break; case STATIC_IPV4_IFNAME: - nexthop_ifname_add (rib, si->ifname); + rib_nexthop_ifname_add (rib, si->ifname); break; case STATIC_IPV4_BLACKHOLE: - nexthop_blackhole_add (rib); + rib_nexthop_blackhole_add (rib); break; case STATIC_IPV6_GATEWAY: - nexthop_ipv6_add (rib, &si->addr.ipv6); + rib_nexthop_ipv6_add (rib, &si->addr.ipv6); + nh_p.family = AF_INET6; + nh_p.prefixlen = IPV6_MAX_BITLEN; + nh_p.u.prefix6 = si->addr.ipv6; + zebra_register_rnh_static_nh(&nh_p, rn); break; case STATIC_IPV6_IFNAME: - nexthop_ifname_add (rib, si->ifname); + rib_nexthop_ifname_add (rib, si->ifname); break; case STATIC_IPV6_GATEWAY_IFNAME: - nexthop_ipv6_ifname_add (rib, &si->addr.ipv6, si->ifname); + rib_nexthop_ipv6_ifname_add (rib, &si->addr.ipv6, si->ifname); break; } rib_queue_add (&zebrad, rn); @@ -2278,26 +2424,35 @@ static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ro rib->vrf_id = si->vrf_id; rib->table = zebrad.rtm_table_default; rib->nexthop_num = 0; + rib->tag = si->tag; switch (si->type) { case STATIC_IPV4_GATEWAY: - nexthop_ipv4_add (rib, &si->addr.ipv4, NULL); + rib_nexthop_ipv4_add (rib, &si->addr.ipv4, NULL); + nh_p.family = AF_INET; + nh_p.prefixlen = IPV4_MAX_BITLEN; + nh_p.u.prefix4 = si->addr.ipv4; + zebra_register_rnh_static_nh(&nh_p, rn); break; case STATIC_IPV4_IFNAME: - nexthop_ifname_add (rib, si->ifname); + rib_nexthop_ifname_add (rib, si->ifname); break; case STATIC_IPV4_BLACKHOLE: - nexthop_blackhole_add (rib); + rib_nexthop_blackhole_add (rib); break; case STATIC_IPV6_GATEWAY: - nexthop_ipv6_add (rib, &si->addr.ipv6); + rib_nexthop_ipv6_add (rib, &si->addr.ipv6); + nh_p.family = AF_INET6; + nh_p.prefixlen = IPV6_MAX_BITLEN; + nh_p.u.prefix6 = si->addr.ipv6; + zebra_register_rnh_static_nh(&nh_p, rn); break; case STATIC_IPV6_IFNAME: - nexthop_ifname_add (rib, si->ifname); + rib_nexthop_ifname_add (rib, si->ifname); break; case STATIC_IPV6_GATEWAY_IFNAME: - nexthop_ipv6_ifname_add (rib, &si->addr.ipv6, si->ifname); + rib_nexthop_ipv6_ifname_add (rib, &si->addr.ipv6, si->ifname); break; } @@ -2347,6 +2502,7 @@ static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ struct rib *rib; struct nexthop *nexthop; struct route_table *table; + struct prefix nh_p; /* Lookup table. */ table = zebra_vrf_table (afi, safi, si->vrf_id); @@ -2363,7 +2519,8 @@ static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) continue; - if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance) + if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance && + rib->tag == si->tag) break; } @@ -2392,7 +2549,21 @@ static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ { if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) rib_uninstall (rn, rib); - nexthop_delete (rib, nexthop); + + if (afi == AF_INET) + { + nh_p.family = AF_INET; + nh_p.prefixlen = IPV4_MAX_BITLEN; + nh_p.u.prefix4 = nexthop->gate.ipv4; + } + else + { + nh_p.family = AF_INET6; + nh_p.prefixlen = IPV6_MAX_BITLEN; + nh_p.u.prefix6 = nexthop->gate.ipv6; + } + rib_nexthop_delete (rib, nexthop); + zebra_deregister_rnh_static_nh(&nh_p, rn); nexthop_free (nexthop); rib_queue_add (&zebrad, rn); } @@ -2402,7 +2573,7 @@ static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ int static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, - const char *ifname, u_char flags, u_char distance, + const char *ifname, u_char flags, u_short tag, u_char distance, vrf_id_t vrf_id) { u_char type = 0; @@ -2435,7 +2606,8 @@ static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, && (! gate || IPV4_ADDR_SAME (gate, &si->addr.ipv4)) && (! ifname || strcmp (ifname, si->ifname) == 0)) { - if (distance == si->distance) + if (distance == si->distance && + tag == si->tag) { route_unlock_node (rn); return 0; @@ -2445,15 +2617,16 @@ static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, } } - /* Distance changed. */ + /* Distance or tag changed. */ if (update) - static_delete_ipv4_safi (safi, p, gate, ifname, update->distance, vrf_id); + static_delete_ipv4_safi (safi, p, gate, ifname, update->tag, update->distance, vrf_id); /* Make new static route structure. */ si = XCALLOC (MTYPE_STATIC_ROUTE, sizeof (struct static_route)); si->type = type; si->distance = distance; + si->tag = tag; si->flags = flags; si->vrf_id = vrf_id; @@ -2497,7 +2670,7 @@ static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, int static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, - const char *ifname, u_char distance, vrf_id_t vrf_id) + const char *ifname, u_short tag, u_char distance, vrf_id_t vrf_id) { u_char type = 0; struct route_node *rn; @@ -2526,7 +2699,8 @@ static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, for (si = rn->info; si; si = si->next) if (type == si->type && (! gate || IPV4_ADDR_SAME (gate, &si->addr.ipv4)) - && (! ifname || strcmp (ifname, si->ifname) == 0)) + && (! ifname || strcmp (ifname, si->ifname) == 0) + && (! tag || (tag == si->tag))) break; /* Can't find static route. */ @@ -2628,12 +2802,12 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, if (gate) { if (ifindex) - nexthop_ipv6_ifindex_add (rib, gate, ifindex); + rib_nexthop_ipv6_ifindex_add (rib, gate, ifindex); else - nexthop_ipv6_add (rib, gate); + rib_nexthop_ipv6_add (rib, gate); } else - nexthop_ifindex_add (rib, ifindex); + rib_nexthop_ifindex_add (rib, ifindex); /* If this route is kernel route, set FIB flag to the route. */ if (type == ZEBRA_ROUTE_KERNEL || type == ZEBRA_ROUTE_CONNECT) @@ -2665,6 +2839,86 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, return 0; } +int +rib_add_ipv6_multipath (struct prefix_ipv6 *p, struct rib *rib, safi_t safi) +{ + struct route_table *table; + struct route_node *rn; + struct rib *same = NULL; + struct nexthop *nexthop; + int ret = 0; + + if (!rib) + return 0; /* why are we getting called with NULL rib */ + + /* Lookup table. */ + table = zebra_vrf_table (AFI_IP6, safi, rib->vrf_id); + + if (! table) + return 0; + + /* Make sure mask is applied. */ + apply_mask_ipv6 (p); + + /* Set default distance by route type. */ + if (rib->distance == 0) + { + rib->distance = route_info[rib->type].distance; + + /* iBGP distance is 200. */ + if (rib->type == ZEBRA_ROUTE_BGP + && CHECK_FLAG (rib->flags, ZEBRA_FLAG_IBGP)) + rib->distance = 200; + } + + /* Lookup route node.*/ + rn = route_node_get (table, (struct prefix *) p); + + /* If same type of route are installed, treat it as a implicit + withdraw. */ + RNODE_FOREACH_RIB (rn, same) { + if (CHECK_FLAG (same->status, RIB_ENTRY_REMOVED)) { + continue; + } + if (same->type != rib->type) { + continue; + } + + if (same->table != rib->table) { + continue; + } + if (same->type != ZEBRA_ROUTE_CONNECT) { + break; + } + } + + /* If this route is kernel route, set FIB flag to the route. */ + if (rib->type == ZEBRA_ROUTE_KERNEL || rib->type == ZEBRA_ROUTE_CONNECT) { + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) { + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + } + } + + /* Link new rib to node.*/ + rib_addnode (rn, rib); + ret = 1; + /* Free implicit route.*/ + if (same) + { + if (IS_ZEBRA_DEBUG_RIB) + { + zlog_debug ("%s: calling rib_delnode (%p, %p) on existing RIB entry", + __func__, rn, same); + rib_dump ((struct prefix *)p, same); + } + rib_delnode (rn, same); + ret = -1; + } + + route_unlock_node (rn); + return ret; +} + /* XXX factor with rib_delete_ipv6 */ int rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, @@ -2757,14 +3011,19 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, kernel. */ if (! same) { - if (fib && type == ZEBRA_ROUTE_KERNEL) - { - /* Unset flags. */ - for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next) - UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); - - UNSET_FLAG (fib->status, RIB_ENTRY_SELECTED_FIB); - } + if (fib && type == ZEBRA_ROUTE_KERNEL && + CHECK_FLAG(flags, ZEBRA_FLAG_SELFROUTE)) + { + if (IS_ZEBRA_DEBUG_KERNEL) + { + zlog_debug ("Zebra route %s/%d was deleted by others from kernel", + inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), + p->prefixlen); + } + /* This means someone else, other than Zebra, has deleted a Zebra + * route from the kernel. We will add it back */ + rib_update_kernel(rn, NULL, fib); + } else { if (IS_ZEBRA_DEBUG_KERNEL) @@ -2794,12 +3053,11 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, return 0; } - /* Add static route into static route configuration. */ int static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, - const char *ifname, u_char flags, u_char distance, - vrf_id_t vrf_id) + const char *ifname, u_char flags, u_short tag, + u_char distance, vrf_id_t vrf_id) { struct route_node *rn; struct static_route *si; @@ -2827,6 +3085,7 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, for (si = rn->info; si; si = si->next) { if (type == si->type + && tag == si->tag && (! gate || IPV6_ADDR_SAME (gate, &si->addr.ipv6)) && (! ifname || strcmp (ifname, si->ifname) == 0)) { @@ -2841,13 +3100,14 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, } if (update) - static_delete_ipv6(p, type, gate, ifname, si->distance, vrf_id); + static_delete_ipv6(p, type, gate, ifname, tag, si->distance, vrf_id); /* Make new static route structure. */ si = XCALLOC (MTYPE_STATIC_ROUTE, sizeof (struct static_route)); si->type = type; si->distance = distance; + si->tag = tag; si->flags = flags; si->vrf_id = vrf_id; @@ -2894,7 +3154,7 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, /* Delete static route from static route configuration. */ int static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, - const char *ifname, u_char distance, vrf_id_t vrf_id) + const char *ifname, u_short tag, u_char distance, vrf_id_t vrf_id) { struct route_node *rn; struct static_route *si; @@ -2915,7 +3175,8 @@ static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, if (distance == si->distance && type == si->type && (! gate || IPV6_ADDR_SAME (gate, &si->addr.ipv6)) - && (! ifname || strcmp (ifname, si->ifname) == 0)) + && (! ifname || strcmp (ifname, si->ifname) == 0) + && (! tag || (tag == si->tag))) break; /* Can't find static route. */ @@ -3237,6 +3498,13 @@ rib_tables_iter_next (rib_tables_iter_t *iter) return table; } +/* Lookup VRF by identifier. */ +struct zebra_vrf * +zebra_vrf_lookup (vrf_id_t vrf_id) +{ + return vrf_info_lookup (vrf_id); +} + /* * Create a routing table for the specific AFI/SAFI in the given VRF. */ @@ -3279,6 +3547,9 @@ zebra_vrf_alloc (vrf_id_t vrf_id) zvrf->stable[AFI_IP][SAFI_MULTICAST] = route_table_init (); zvrf->stable[AFI_IP6][SAFI_MULTICAST] = route_table_init (); + zvrf->rnh_table[AFI_IP] = route_table_init(); + zvrf->rnh_table[AFI_IP6] = route_table_init(); + /* Set VRF ID */ zvrf->vrf_id = vrf_id; diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c new file mode 100644 index 00000000..5f68f64f --- /dev/null +++ b/zebra/zebra_rnh.c @@ -0,0 +1,761 @@ +/* Zebra next hop tracking code + * Copyright (C) 2013 Cumulus Networks, Inc. + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "prefix.h" +#include "table.h" +#include "memory.h" +#include "str.h" +#include "command.h" +#include "if.h" +#include "log.h" +#include "sockunion.h" +#include "linklist.h" +#include "thread.h" +#include "workqueue.h" +#include "prefix.h" +#include "routemap.h" +#include "stream.h" +#include "nexthop.h" + +#include "zebra/rib.h" +#include "zebra/rt.h" +#include "zebra/zserv.h" +#include "zebra/redistribute.h" +#include "zebra/debug.h" +#include "zebra/zebra_rnh.h" + +#define lookup_rnh_table(v, f) \ +({ \ + struct zebra_vrf *zvrf; \ + struct route_table *t = NULL; \ + zvrf = zebra_vrf_lookup(v); \ + if (zvrf) \ + t = zvrf->rnh_table[family2afi(f)]; \ + t; \ +}) + +/* Default rtm_table for all clients */ +extern struct zebra_t zebrad; + +static void rib_free_state(struct rib *rib, struct route_node *rn); +static void copy_state(struct rnh *rnh, struct rib *rib, struct route_node *rn); +static int compare_state(struct rib *r1, struct rib *r2); +static int send_client(struct rnh *rnh, struct zserv *client, vrf_id_t vrf_id); +static void print_rnh(struct route_node *rn, struct vty *vty); + +char * +rnh_str (struct rnh *rnh, char *buf, int size) +{ + prefix2str(&(rnh->node->p), buf, size); + return buf; +} + +struct rnh * +zebra_add_rnh (struct prefix *p, vrf_id_t vrfid) +{ + struct route_table *table; + struct route_node *rn; + struct rnh *rnh = NULL; + + if (IS_ZEBRA_DEBUG_NHT) + { + char buf[INET6_ADDRSTRLEN]; + prefix2str(p, buf, INET6_ADDRSTRLEN); + zlog_debug("add rnh %s in vrf %d", buf, vrfid); + } + table = lookup_rnh_table(vrfid, PREFIX_FAMILY(p)); + if (!table) + { + zlog_debug("add_rnh: rnh table not found\n"); + return NULL; + } + + /* Make it sure prefixlen is applied to the prefix. */ + apply_mask (p); + + /* Lookup (or add) route node.*/ + rn = route_node_get (table, p); + + if (!rn->info) + { + rnh = XCALLOC(MTYPE_RNH, sizeof(struct rnh)); + rnh->client_list = list_new(); + rnh->zebra_static_route_list = list_new(); + route_lock_node (rn); + rn->info = rnh; + rnh->node = rn; + } + + route_unlock_node (rn); + return (rn->info); +} + +struct rnh * +zebra_lookup_rnh (struct prefix *p, vrf_id_t vrfid) +{ + struct route_table *table; + struct route_node *rn; + + table = lookup_rnh_table(vrfid, PREFIX_FAMILY(p)); + if (!table) + return NULL; + + /* Make it sure prefixlen is applied to the prefix. */ + apply_mask (p); + + /* Lookup route node.*/ + rn = route_node_lookup (table, p); + if (!rn) + return NULL; + + route_unlock_node (rn); + return (rn->info); +} + +void +zebra_delete_rnh (struct rnh *rnh) +{ + struct route_node *rn; + + if (!rnh || !(rn = rnh->node)) + return; + + if (IS_ZEBRA_DEBUG_NHT) + { + char buf[INET6_ADDRSTRLEN]; + zlog_debug("delete rnh %s", rnh_str(rnh, buf, INET6_ADDRSTRLEN)); + } + + list_free(rnh->client_list); + list_free(rnh->zebra_static_route_list); + rib_free_state(rnh->state, rn); + XFREE(MTYPE_RNH, rn->info); + rn->info = NULL; + route_unlock_node (rn); + return; +} + +void +zebra_add_rnh_client (struct rnh *rnh, struct zserv *client, vrf_id_t vrf_id) +{ + if (IS_ZEBRA_DEBUG_NHT) + { + char buf[INET6_ADDRSTRLEN]; + zlog_debug("client %s registers rnh %s", + zebra_route_string(client->proto), + rnh_str(rnh, buf, INET6_ADDRSTRLEN)); + } + if (!listnode_lookup(rnh->client_list, client)) + { + listnode_add(rnh->client_list, client); + send_client(rnh, client, vrf_id); + } +} + +void +zebra_remove_rnh_client (struct rnh *rnh, struct zserv *client) +{ + if (IS_ZEBRA_DEBUG_NHT) + { + char buf[INET6_ADDRSTRLEN]; + zlog_debug("client %s unregisters rnh %s", + zebra_route_string(client->proto), + rnh_str(rnh, buf, INET6_ADDRSTRLEN)); + } + listnode_delete(rnh->client_list, client); + if (list_isempty(rnh->client_list) && + list_isempty(rnh->zebra_static_route_list)) + zebra_delete_rnh(rnh); +} + +void +zebra_register_rnh_static_nh(struct prefix *nh, struct route_node *static_rn) +{ + struct rnh *rnh; + + rnh = zebra_add_rnh(nh, 0); + if (rnh && !listnode_lookup(rnh->zebra_static_route_list, static_rn)) + { + listnode_add(rnh->zebra_static_route_list, static_rn); + } +} + +void +zebra_deregister_rnh_static_nh(struct prefix *nh, struct route_node *static_rn) +{ + struct rnh *rnh; + + rnh = zebra_lookup_rnh(nh, 0); + if (!rnh) + return; + + listnode_delete(rnh->zebra_static_route_list, static_rn); + + if (list_isempty(rnh->client_list) && + list_isempty(rnh->zebra_static_route_list)) + zebra_delete_rnh(rnh); +} + +void +zebra_deregister_rnh_static_nexthops (struct nexthop *nexthop, struct route_node *rn) +{ + struct nexthop *nh; + struct prefix nh_p; + + for (nh = nexthop; nh ; nh = nh->next) + { + if (nh->type == NEXTHOP_TYPE_IPV4) + { + nh_p.family = AF_INET; + nh_p.prefixlen = IPV4_MAX_BITLEN; + nh_p.u.prefix4 = nh->gate.ipv4; + } + else if (nh->type == NEXTHOP_TYPE_IPV6) + { + nh_p.family = AF_INET6; + nh_p.prefixlen = IPV6_MAX_BITLEN; + nh_p.u.prefix6 = nh->gate.ipv6; + } + zebra_deregister_rnh_static_nh(&nh_p, rn); + } +} + +static int +zebra_evaluate_rnh_nexthops(int family, struct rib *rib, struct route_node *prn, + int proto) +{ + int at_least_one = 0; + int rmap_family; /* Route map has diff AF family enum */ + struct nexthop *nexthop; + int ret; + + rmap_family = (family == AF_INET) ? AFI_IP : AFI_IP6; + + if (prn && rib) + { + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + { + ret = zebra_nht_route_map_check(rmap_family, proto, &prn->p, rib, + nexthop); + if (ret != RMAP_DENYMATCH) + { + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + at_least_one++; /* at least one valid NH */ + } + else + { + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + } + } + } + return (at_least_one); +} + +int +zebra_evaluate_rnh_table (vrf_id_t vrfid, int family, int force) +{ + struct route_table *ptable; + struct route_table *ntable; + struct route_node *prn; + struct route_node *nrn; + struct rnh *rnh; + struct zserv *client; + struct listnode *node; + struct rib *rib, *srib; + int state_changed = 0; + int at_least_one = 0; + char bufn[INET6_ADDRSTRLEN]; + char bufp[INET6_ADDRSTRLEN]; + char bufs[INET6_ADDRSTRLEN]; + struct route_node *static_rn; + struct nexthop *nexthop; + ntable = lookup_rnh_table(vrfid, family); + if (!ntable) + { + zlog_debug("evaluate_rnh_table: rnh table not found\n"); + return -1; + } + + ptable = zebra_vrf_table(family2afi(family), SAFI_UNICAST, vrfid); + if (!ptable) + { + zlog_debug("evaluate_rnh_table: prefix table not found\n"); + return -1; + } + + for (nrn = route_top (ntable); nrn; nrn = route_next (nrn)) + { + if (!nrn->info) + continue; + + rnh = nrn->info; + at_least_one = 0; + + prn = route_node_match(ptable, &nrn->p); + if (!prn) + rib = NULL; + else + { + RNODE_FOREACH_RIB(prn, rib) + { + if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) + continue; + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + { + if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) + { + if (rib->type == ZEBRA_ROUTE_CONNECT) + break; + } + else + break; + } + } + } + + state_changed = 0; + + if (compare_state(rib, rnh->state)) + { + if (rib) + UNSET_FLAG(rib->status, RIB_ENTRY_NEXTHOPS_CHANGED); + + copy_state(rnh, rib, nrn); + state_changed = 1; + } + + if (IS_ZEBRA_DEBUG_NHT && (state_changed || force)) + { + prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN); + if (prn) + prefix2str(&prn->p, bufp, INET6_ADDRSTRLEN); + else + strcpy(bufp, "null"); + + zlog_debug("%s: State changed for %s/%s", __FUNCTION__, bufn, bufp); + + } + + /* Notify registered clients */ + rib = rnh->state; + + if (state_changed || force) + { + for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) + { + if (prn && rib) + { + at_least_one = zebra_evaluate_rnh_nexthops(family, rib, prn, + client->proto); + if (at_least_one) + rnh->filtered[client->proto] = 0; + else + rnh->filtered[client->proto] = 1; + } + else if (state_changed) + rnh->filtered[client->proto] = 0; + + if (IS_ZEBRA_DEBUG_NHT && (state_changed || force)) + zlog_debug("%srnh %s resolved through route %s - sending " + "nexthop %s event to clients", + at_least_one ? "":"(filtered)", bufn, bufp, + rib ? "reachable" : "unreachable"); + + send_client(rnh, client, vrfid); /* Route-map passed */ + } + + /* Now evaluate static client */ + if (prn && rib) + { + at_least_one = zebra_evaluate_rnh_nexthops(family, rib, prn, + ZEBRA_ROUTE_STATIC); + if (at_least_one) + rnh->filtered[ZEBRA_ROUTE_STATIC] = 0; + else + rnh->filtered[ZEBRA_ROUTE_STATIC] = 1; + } + else if (state_changed) + rnh->filtered[ZEBRA_ROUTE_STATIC] = 0; + + for (ALL_LIST_ELEMENTS_RO(rnh->zebra_static_route_list, node, + static_rn)) + { + RNODE_FOREACH_RIB(static_rn, srib) + { + break; /* pick the first and only(?) rib for static */ + } + + if (!srib) + { + if (IS_ZEBRA_DEBUG_NHT) + { + prefix2str(&static_rn->p, bufs, INET6_ADDRSTRLEN); + zlog_debug("%s: Unable to find RIB for static route %s, skipping NH resolution", + __FUNCTION__, bufs); + continue; + } + } + + /* Mark the appropriate static route's NH as filtered */ + for (nexthop = srib->nexthop; nexthop; nexthop = nexthop->next) + { + switch (nexthop->type) + { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + /* Don't see a use case for *_IFNAME */ + if (nexthop->gate.ipv4.s_addr == nrn->p.u.prefix4.s_addr) + { + if (at_least_one) + UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FILTERED); + else + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FILTERED); + } + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + /* Don't see a use case for *_IFNAME */ + if (memcmp(&nexthop->gate.ipv6,&nrn->p.u.prefix6, 16) == 0) + { + if (at_least_one) + UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FILTERED); + else + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FILTERED); + } + break; + default: + break; + } + } + + if (IS_ZEBRA_DEBUG_NHT && (state_changed || force)) + zlog_debug("%srnh %s resolved through route %s - sending " + "nexthop %s event to zebra", + at_least_one ? "":"(filtered)", bufn, bufp, + rib ? "reachable" : "unreachable"); + + if (srib && (state_changed || force)) + { + SET_FLAG(srib->status, RIB_ENTRY_NEXTHOPS_CHANGED); + rib_queue_add(&zebrad, static_rn); + } + } + } + } + return 1; +} + +int +zebra_dispatch_rnh_table (vrf_id_t vrfid, int family, struct zserv *client) +{ + struct route_table *ntable; + struct route_node *nrn; + struct rnh *rnh; + + ntable = lookup_rnh_table(vrfid, family); + if (!ntable) + { + zlog_debug("dispatch_rnh_table: rnh table not found\n"); + return -1; + } + + for (nrn = route_top (ntable); nrn; nrn = route_next (nrn)) + { + if (!nrn->info) + continue; + + rnh = nrn->info; + if (IS_ZEBRA_DEBUG_NHT) + { + char bufn[INET6_ADDRSTRLEN]; + prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN); + zlog_debug("rnh %s - sending nexthop %s event to client %s", bufn, + rnh->state ? "reachable" : "unreachable", + zebra_route_string(client->proto)); + } + send_client(rnh, client, vrfid); + } + return 1; +} + +void +zebra_print_rnh_table (vrf_id_t vrfid, int af, struct vty *vty) +{ + struct route_table *table; + struct route_node *rn; + + table = lookup_rnh_table(vrfid, af); + if (!table) + { + zlog_debug("print_rnhs: rnh table not found\n"); + return; + } + + for (rn = route_top(table); rn; rn = route_next(rn)) + if (rn->info) + print_rnh(rn, vty); +} + +int +zebra_cleanup_rnh_client (vrf_id_t vrfid, int family, struct zserv *client) +{ + struct route_table *ntable; + struct route_node *nrn; + struct rnh *rnh; + + ntable = lookup_rnh_table(vrfid, family); + if (!ntable) + { + zlog_debug("cleanup_rnh_client: rnh table not found\n"); + return -1; + } + + for (nrn = route_top (ntable); nrn; nrn = route_next (nrn)) + { + if (!nrn->info) + continue; + + rnh = nrn->info; + if (IS_ZEBRA_DEBUG_NHT) + { + char bufn[INET6_ADDRSTRLEN]; + prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN); + zlog_debug("rnh %s - cleaning state for client %s", bufn, + zebra_route_string(client->proto)); + } + zebra_remove_rnh_client(rnh, client); + } + return 1; +} + +/** + * free_state - free up the rib structure associated with the rnh. + */ +static void +rib_free_state (struct rib *rib, struct route_node *rn) +{ + + if (!rib) + return; + + /* free RIB and nexthops */ + zebra_deregister_rnh_static_nexthops (rib->nexthop, rn); + nexthops_free(rib->nexthop); + XFREE (MTYPE_RIB, rib); +} + +static void +copy_state (struct rnh *rnh, struct rib *rib, struct route_node *rn) +{ + struct rib *state; + struct nexthop *nh; + + if (rnh->state) + { + rib_free_state(rnh->state, rn); + rnh->state = NULL; + } + + if (!rib) + return; + + state = XCALLOC (MTYPE_RIB, sizeof (struct rib)); + state->type = rib->type; + state->metric = rib->metric; + + for (nh = rib->nexthop; nh; nh = nh->next) + rib_copy_nexthops(state, nh); + rnh->state = state; +} + +static int +compare_state (struct rib *r1, struct rib *r2) +{ + + if (!r1 && !r2) + return 0; + + if ((!r1 && r2) || (r1 && !r2)) + return 1; + + if (r1->metric != r2->metric) + return 1; + + if (r1->nexthop_num != r2->nexthop_num) + return 1; + + if (CHECK_FLAG(r1->status, RIB_ENTRY_NEXTHOPS_CHANGED)) + return 1; + + return 0; +} + +static int +send_client (struct rnh *rnh, struct zserv *client, vrf_id_t vrf_id) +{ + struct stream *s; + struct rib *rib; + unsigned long nump; + u_char num; + struct nexthop *nexthop; + struct route_node *rn; + + rn = rnh->node; + rib = rnh->state; + + /* Get output stream. */ + s = client->obuf; + stream_reset (s); + + zserv_create_header (s, ZEBRA_NEXTHOP_UPDATE, vrf_id); + + stream_putw(s, rn->p.family); + stream_put_prefix (s, &rn->p); + + if (rib) + { + stream_putl (s, rib->metric); + num = 0; + nump = stream_get_endp(s); + stream_putc (s, 0); + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + if ((CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) || + CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) && + CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + { + stream_putc (s, nexthop->type); + switch (nexthop->type) + { + case ZEBRA_NEXTHOP_IPV4: + stream_put_in_addr (s, &nexthop->gate.ipv4); + break; + case ZEBRA_NEXTHOP_IFINDEX: + case ZEBRA_NEXTHOP_IFNAME: + stream_putl (s, nexthop->ifindex); + break; + case ZEBRA_NEXTHOP_IPV4_IFINDEX: + case ZEBRA_NEXTHOP_IPV4_IFNAME: + stream_put_in_addr (s, &nexthop->gate.ipv4); + stream_putl (s, nexthop->ifindex); + break; +#ifdef HAVE_IPV6 + case ZEBRA_NEXTHOP_IPV6: + stream_put (s, &nexthop->gate.ipv6, 16); + break; + case ZEBRA_NEXTHOP_IPV6_IFINDEX: + case ZEBRA_NEXTHOP_IPV6_IFNAME: + stream_put (s, &nexthop->gate.ipv6, 16); + stream_putl (s, nexthop->ifindex); + break; +#endif /* HAVE_IPV6 */ + default: + /* do nothing */ + break; + } + num++; + } + stream_putc_at (s, nump, num); + } + else + { + stream_putl (s, 0); + stream_putc (s, 0); + } + stream_putw_at (s, 0, stream_get_endp (s)); + + client->nh_last_upd_time = quagga_time(NULL); + client->last_write_cmd = ZEBRA_NEXTHOP_UPDATE; + return zebra_server_send_message(client); +} + +static void +print_nh (struct nexthop *nexthop, struct vty *vty) +{ + char buf[BUFSIZ]; + + switch (nexthop->type) + { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + vty_out (vty, " via %s", inet_ntoa (nexthop->gate.ipv4)); + if (nexthop->ifindex) + vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex)); + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + case NEXTHOP_TYPE_IPV6_IFNAME: + vty_out (vty, " %s", + inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ)); + if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME) + vty_out (vty, ", %s", nexthop->ifname); + else if (nexthop->ifindex) + vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex)); + break; + case NEXTHOP_TYPE_IFINDEX: + vty_out (vty, " is directly connected, %s", + ifindex2ifname (nexthop->ifindex)); + break; + case NEXTHOP_TYPE_IFNAME: + vty_out (vty, " is directly connected, %s", nexthop->ifname); + break; + case NEXTHOP_TYPE_BLACKHOLE: + vty_out (vty, " is directly connected, Null0"); + break; + default: + break; + } + vty_out(vty, "%s", VTY_NEWLINE); +} + +static void +print_rnh (struct route_node *rn, struct vty *vty) +{ + struct rnh *rnh; + struct nexthop *nexthop; + struct listnode *node; + struct zserv *client; + char buf[BUFSIZ]; + + rnh = rn->info; + vty_out(vty, "%s%s", inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ), + VTY_NEWLINE); + if (rnh->state) + { + vty_out(vty, " resolved via %s%s", + zebra_route_string(rnh->state->type), VTY_NEWLINE); + for (nexthop = rnh->state->nexthop; nexthop; nexthop = nexthop->next) + print_nh(nexthop, vty); + } + else + vty_out(vty, " unresolved%s%s", + CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED) ? "(Connected)" : "", + VTY_NEWLINE); + + vty_out(vty, " Client list:"); + for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) + vty_out(vty, " %s(fd %d)%s", zebra_route_string(client->proto), + client->sock, rnh->filtered[client->proto] ? "(filtered)" : ""); + if (!list_isempty(rnh->zebra_static_route_list)) + vty_out(vty, " zebra%s", rnh->filtered[ZEBRA_ROUTE_STATIC] ? "(filtered)" : ""); + vty_out(vty, "%s", VTY_NEWLINE); +} diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h new file mode 100644 index 00000000..77a913aa --- /dev/null +++ b/zebra/zebra_rnh.h @@ -0,0 +1,54 @@ +/* + * Zebra next hop tracking header + * Copyright (C) 2013 Cumulus Networks, Inc. + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_RNH_H +#define _ZEBRA_RNH_H + +#include "prefix.h" +#include "vty.h" + +/* Nexthop structure. */ +struct rnh +{ + u_char flags; +#define ZEBRA_NHT_CONNECTED 0x1 + struct rib *state; + struct list *client_list; + struct list *zebra_static_route_list; /* static routes dependent on this NH */ + struct route_node *node; + int filtered[ZEBRA_ROUTE_MAX]; /* if this has been filtered for client */ +}; + +extern struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid); +extern struct rnh *zebra_lookup_rnh(struct prefix *p, vrf_id_t vrfid); +extern void zebra_delete_rnh(struct rnh *rnh); +extern void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client, vrf_id_t vrf_id_t); +extern void zebra_register_rnh_static_nh(struct prefix *, struct route_node *); +extern void zebra_deregister_rnh_static_nh(struct prefix *, struct route_node *); +extern void zebra_deregister_rnh_static_nexthops (struct nexthop *, struct route_node *); +extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client); +extern int zebra_evaluate_rnh_table(vrf_id_t vrfid, int family, int force); +extern int zebra_dispatch_rnh_table(vrf_id_t vrfid, int family, struct zserv *cl); +extern void zebra_print_rnh_table(vrf_id_t vrfid, int family, struct vty *vty); +extern char *rnh_str(struct rnh *rnh, char *buf, int size); +extern int zebra_cleanup_rnh_client(vrf_id_t vrf, int family, struct zserv *client); +#endif /*_ZEBRA_RNH_H */ diff --git a/zebra/zebra_rnh_null.c b/zebra/zebra_rnh_null.c new file mode 100644 index 00000000..c30e3e4e --- /dev/null +++ b/zebra/zebra_rnh_null.c @@ -0,0 +1,21 @@ +#include <zebra.h> +#include <vty.h> + +#include "zebra/rib.h" +#include "zebra/zserv.h" +#include "zebra/zebra_rnh.h" + +int zebra_evaluate_rnh_table (vrf_id_t vrfid, int family, int force) +{ return 0; } + +void zebra_print_rnh_table (vrf_id_t vrfid, int family, struct vty *vty) +{} + +void zebra_register_rnh_static_nh(struct prefix *p, struct route_node *rn) +{} + +void zebra_deregister_rnh_static_nh(struct prefix *p, struct route_node *rn) +{} + +void zebra_deregister_rnh_static_nexthops (struct nexthop *nexthop, struct route_node *rn) +{} diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index da9cb130..5184589c 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -29,13 +29,34 @@ #include "filter.h" #include "plist.h" #include "vrf.h" +#include "nexthop.h" #include "zebra/zserv.h" +#include "zebra/debug.h" +#include "zebra/zebra_rnh.h" + +static u_int32_t zebra_rmap_update_timer = ZEBRA_RMAP_DEFAULT_UPDATE_TIMER; +static struct thread *zebra_t_rmap_update = NULL; +char *proto_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1]; /* "any" == ZEBRA_ROUTE_MAX */ +/* NH Tracking route map */ +char *nht_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1]; /* "any" == ZEBRA_ROUTE_MAX */ + +extern struct zebra_t zebrad; +struct nh_rmap_obj +{ + struct nexthop *nexthop; + vrf_id_t vrf_id; + u_int32_t source_protocol; + int metric; +}; + +static void zebra_route_map_set_delay_timer(u_int32_t value); /* Add zebra route map rule */ static int zebra_route_match_add(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg) + const char *command, const char *arg, + route_map_event_t type) { int ret; @@ -45,22 +66,42 @@ zebra_route_match_add(struct vty *vty, struct route_map_index *index, switch (ret) { case RMAP_RULE_MISSING: - vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + vty_out (vty, "%% Zebra Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: - vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + vty_out (vty, "%% Zebra Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } + + if (type != RMAP_EVENT_MATCH_ADDED) + { + route_map_upd8_dependency (type, arg, index->map->name); + } return CMD_SUCCESS; } /* Delete zebra route map rule. */ static int zebra_route_match_delete (struct vty *vty, struct route_map_index *index, - const char *command, const char *arg) + const char *command, const char *arg, + route_map_event_t type) { int ret; + char *dep_name = (char *)arg; + const char *tmpstr; + char *rmap_name = NULL; + + if (type != RMAP_EVENT_MATCH_DELETED) + { + /* ignore the mundane, the types without any dependency */ + if (arg == NULL) + { + if ((tmpstr = route_map_get_match_arg(index, command)) != NULL) + dep_name = XSTRDUP(MTYPE_ROUTE_MAP_RULE, tmpstr); + } + rmap_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, index->map->name); + } ret = route_map_delete_match (index, command, arg); if (ret) @@ -68,13 +109,22 @@ zebra_route_match_delete (struct vty *vty, struct route_map_index *index, switch (ret) { case RMAP_RULE_MISSING: - vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + vty_out (vty, "%% Zebra Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: - vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + vty_out (vty, "%% Zebra Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } + + if (type != RMAP_EVENT_MATCH_DELETED && dep_name) + route_map_upd8_dependency(type, dep_name, rmap_name); + + if (arg == NULL && dep_name) + XFREE(MTYPE_ROUTE_MAP_RULE, dep_name); + if (rmap_name) + XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name); + return CMD_SUCCESS; } @@ -91,10 +141,10 @@ zebra_route_set_add (struct vty *vty, struct route_map_index *index, switch (ret) { case RMAP_RULE_MISSING: - vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + vty_out (vty, "%% Zebra Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: - vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + vty_out (vty, "%% Zebra Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } @@ -114,10 +164,10 @@ zebra_route_set_delete (struct vty *vty, struct route_map_index *index, switch (ret) { case RMAP_RULE_MISSING: - vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + vty_out (vty, "%% Zebra Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: - vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + vty_out (vty, "%% Zebra Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } @@ -131,7 +181,7 @@ static route_map_result_t route_match_interface (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { - struct nexthop_vrfid *nh_vrf; + struct nh_rmap_obj *nh_data; struct nexthop *nexthop; char *ifname = rule; ifindex_t ifindex; @@ -140,13 +190,13 @@ route_match_interface (void *rule, struct prefix *prefix, { if (strcasecmp(ifname, "any") == 0) return RMAP_MATCH; - nh_vrf = object; - if (!nh_vrf) + nh_data = object; + if (!nh_data) return RMAP_NOMATCH; - ifindex = ifname2ifindex_vrf (ifname, nh_vrf->vrf_id); + ifindex = ifname2ifindex_vrf (ifname, nh_data->vrf_id); if (ifindex == 0) return RMAP_NOMATCH; - nexthop = nh_vrf->nexthop; + nexthop = nh_data->nexthop; if (!nexthop) return RMAP_NOMATCH; if (nexthop->ifindex == ifindex) @@ -185,7 +235,8 @@ DEFUN (match_interface, "match first hop interface of route\n" "Interface name\n") { - return zebra_route_match_add (vty, vty->index, "interface", argv[0]); + return zebra_route_match_add (vty, vty->index, "interface", argv[0], + RMAP_EVENT_MATCH_ADDED); } DEFUN (no_match_interface, @@ -196,9 +247,9 @@ DEFUN (no_match_interface, "Match first hop interface of route\n") { if (argc == 0) - return zebra_route_match_delete (vty, vty->index, "interface", NULL); + return zebra_route_match_delete (vty, vty->index, "interface", NULL, RMAP_EVENT_MATCH_DELETED); - return zebra_route_match_delete (vty, vty->index, "interface", argv[0]); + return zebra_route_match_delete (vty, vty->index, "interface", argv[0], RMAP_EVENT_MATCH_DELETED); } ALIAS (no_match_interface, @@ -219,7 +270,7 @@ DEFUN (match_ip_next_hop, "IP access-list number (expanded range)\n" "IP Access-list name\n") { - return zebra_route_match_add (vty, vty->index, "ip next-hop", argv[0]); + return zebra_route_match_add (vty, vty->index, "ip next-hop", argv[0], RMAP_EVENT_FILTER_ADDED); } DEFUN (no_match_ip_next_hop, @@ -231,9 +282,11 @@ DEFUN (no_match_ip_next_hop, "Match next-hop address of route\n") { if (argc == 0) - return zebra_route_match_delete (vty, vty->index, "ip next-hop", NULL); + return zebra_route_match_delete (vty, vty->index, "ip next-hop", NULL, + RMAP_EVENT_FILTER_DELETED); - return zebra_route_match_delete (vty, vty->index, "ip next-hop", argv[0]); + return zebra_route_match_delete (vty, vty->index, "ip next-hop", argv[0], + RMAP_EVENT_FILTER_DELETED); } ALIAS (no_match_ip_next_hop, @@ -256,7 +309,8 @@ DEFUN (match_ip_next_hop_prefix_list, "Match entries of prefix-lists\n" "IP prefix-list name\n") { - return zebra_route_match_add (vty, vty->index, "ip next-hop prefix-list", argv[0]); + return zebra_route_match_add (vty, vty->index, "ip next-hop prefix-list", + argv[0], RMAP_EVENT_PLIST_ADDED); } DEFUN (no_match_ip_next_hop_prefix_list, @@ -269,9 +323,13 @@ DEFUN (no_match_ip_next_hop_prefix_list, "Match entries of prefix-lists\n") { if (argc == 0) - return zebra_route_match_delete (vty, vty->index, "ip next-hop prefix-list", NULL); + return zebra_route_match_delete (vty, vty->index, + "ip next-hop prefix-list", NULL, + RMAP_EVENT_PLIST_DELETED); - return zebra_route_match_delete (vty, vty->index, "ip next-hop prefix-list", argv[0]); + return zebra_route_match_delete (vty, vty->index, + "ip next-hop prefix-list", argv[0], + RMAP_EVENT_PLIST_DELETED); } ALIAS (no_match_ip_next_hop_prefix_list, @@ -295,7 +353,8 @@ DEFUN (match_ip_address, "IP Access-list name\n") { - return zebra_route_match_add (vty, vty->index, "ip address", argv[0]); + return zebra_route_match_add (vty, vty->index, "ip address", argv[0], + RMAP_EVENT_FILTER_ADDED); } DEFUN (no_match_ip_address, @@ -307,9 +366,11 @@ DEFUN (no_match_ip_address, "Match address of route\n") { if (argc == 0) - return zebra_route_match_delete (vty, vty->index, "ip address", NULL); + return zebra_route_match_delete (vty, vty->index, "ip address", NULL, + RMAP_EVENT_FILTER_DELETED); - return zebra_route_match_delete (vty, vty->index, "ip address", argv[0]); + return zebra_route_match_delete (vty, vty->index, "ip address", argv[0], + RMAP_EVENT_FILTER_DELETED); } ALIAS (no_match_ip_address, @@ -332,7 +393,8 @@ DEFUN (match_ip_address_prefix_list, "Match entries of prefix-lists\n" "IP prefix-list name\n") { - return zebra_route_match_add (vty, vty->index, "ip address prefix-list", argv[0]); + return zebra_route_match_add (vty, vty->index, "ip address prefix-list", + argv[0], RMAP_EVENT_PLIST_ADDED); } DEFUN (no_match_ip_address_prefix_list, @@ -345,9 +407,13 @@ DEFUN (no_match_ip_address_prefix_list, "Match entries of prefix-lists\n") { if (argc == 0) - return zebra_route_match_delete (vty, vty->index, "ip address prefix-list", NULL); + return zebra_route_match_delete (vty, vty->index, + "ip address prefix-list", NULL, + RMAP_EVENT_PLIST_DELETED); - return zebra_route_match_delete (vty, vty->index, "ip address prefix-list", argv[0]); + return zebra_route_match_delete (vty, vty->index, + "ip address prefix-list", argv[0], + RMAP_EVENT_PLIST_DELETED); } ALIAS (no_match_ip_address_prefix_list, @@ -360,6 +426,129 @@ ALIAS (no_match_ip_address_prefix_list, "Match entries of prefix-lists\n" "IP prefix-list name\n") +DEFUN (match_ip_address_prefix_len, + match_ip_address_prefix_len_cmd, + "match ip address prefix-len NUMBER", + MATCH_STR + IP_STR + "Match prefix length of ip address\n" + "Match prefix length of ip address\n" + "Prefix length\n") +{ + return zebra_route_match_add (vty, vty->index, "ip address prefix-len", + argv[0], RMAP_EVENT_MATCH_ADDED); +} + +DEFUN (no_match_ip_address_prefix_len, + no_match_ip_address_prefix_len_cmd, + "no match ip address prefix-len", + NO_STR + MATCH_STR + IP_STR + "Match prefixlen of ip address of route\n" + "prefix length of ip address\n") +{ + if (argc == 0) + return zebra_route_match_delete (vty, vty->index, + "ip address prefix-len", NULL, + RMAP_EVENT_MATCH_DELETED); + + return zebra_route_match_delete (vty, vty->index, + "ip address prefix-len", argv[0], + RMAP_EVENT_MATCH_DELETED); +} + +ALIAS (no_match_ip_address_prefix_len, + no_match_ip_address_prefix_len_val_cmd, + "no match ip address prefix-len NUMBER", + NO_STR + MATCH_STR + IP_STR + "Match prefixlen of ip address of route\n" + "prefix length of ip address\n") + +DEFUN (match_ip_nexthop_prefix_len, + match_ip_nexthop_prefix_len_cmd, + "match ip next-hop prefix-len NUMBER", + MATCH_STR + IP_STR + "Match prefixlen of nexthop ip address\n" + "Match prefixlen of given nexthop\n" + "Prefix length\n") +{ + return zebra_route_match_add (vty, vty->index, "ip next-hop prefix-len", + argv[0], RMAP_EVENT_MATCH_ADDED); +} + +DEFUN (no_match_ip_nexthop_prefix_len, + no_match_ip_nexthop_prefix_len_cmd, + "no match ip next-hop prefix-len", + NO_STR + MATCH_STR + IP_STR + "Match prefixlen of nexthop ip address\n" + "Match prefix length of nexthop\n") +{ + if (argc == 0) + return zebra_route_match_delete (vty, vty->index, + "ip next-hop prefix-len", NULL, + RMAP_EVENT_MATCH_DELETED); + + return zebra_route_match_delete (vty, vty->index, + "ip next-hop prefix-len", argv[0], + RMAP_EVENT_MATCH_DELETED); +} + +ALIAS (no_match_ip_nexthop_prefix_len, + no_match_ip_nexthop_prefix_len_val_cmd, + "no match ip next-hop prefix-len NUMBER", + MATCH_STR + "Match prefixlen of ip address of route\n" + "prefix length of ip address\n") + +DEFUN (match_source_protocol, + match_source_protocol_cmd, + "match source-protocol (bgp|ospf|rip|ripng|isis|ospf6|connected|system|kernel|static)", + MATCH_STR + "Match protocol via which the route was learnt\n") +{ + int i; + + i = proto_name2num(argv[0]); + if (i < 0) + { + vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "", + VTY_NEWLINE); + return CMD_WARNING; + } + return zebra_route_match_add (vty, vty->index, "source-protocol", + argv[0], RMAP_EVENT_MATCH_ADDED); +} + +DEFUN (no_match_source_protocol, + no_match_source_protocol_cmd, + "no match source-protocol (bgp|ospf|rip|ripng|isis|ospf6|connected|system|kernel|static)", + NO_STR + MATCH_STR + "No match protocol via which the route was learnt\n") +{ + int i; + + if (argc >= 1) + { + i = proto_name2num(argv[0]); + if (i < 0) + { + vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "", + VTY_NEWLINE); + return CMD_WARNING; + } + } + return zebra_route_match_delete (vty, vty->index, + "source-protocol", argv[0] ? argv[0] : NULL, + RMAP_EVENT_MATCH_DELETED); +} + /* set functions */ DEFUN (set_src, @@ -413,6 +602,340 @@ ALIAS (no_set_src, "src address for route\n" "src address\n") +DEFUN (zebra_route_map_timer, + zebra_route_map_timer_cmd, + "zebra route-map delay-timer <0-600>", + "Time to wait before route-map updates are processed\n" + "0 means event-driven updates are disabled\n") +{ + u_int32_t rmap_delay_timer; + + VTY_GET_INTEGER_RANGE ("delay-timer", rmap_delay_timer, argv[0], 0, 600); + zebra_route_map_set_delay_timer(rmap_delay_timer); + + return (CMD_SUCCESS); +} + +DEFUN (no_zebra_route_map_timer, + no_zebra_route_map_timer_cmd, + "no zebra route-map delay-timer", + NO_STR + "Time to wait before route-map updates are processed\n" + "Reset delay-timer to default value, 30 secs\n") +{ + zebra_route_map_set_delay_timer(ZEBRA_RMAP_DEFAULT_UPDATE_TIMER); + + return (CMD_SUCCESS); +} + +DEFUN (ip_protocol, + ip_protocol_cmd, + "ip protocol " QUAGGA_IP_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP", + IP_STR + "Filter routing info exchanged between zebra and protocol\n" + QUAGGA_IP_PROTOCOL_MAP_HELP_STR_ZEBRA + "Route map name\n") +{ + int i; + + if (strcasecmp(argv[0], "any") == 0) + i = ZEBRA_ROUTE_MAX; + else + i = proto_name2num(argv[0]); + if (i < 0) + { + vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "", + VTY_NEWLINE); + return CMD_WARNING; + } + if (proto_rm[AFI_IP][i]) + { + if (strcmp(proto_rm[AFI_IP][i], argv[1]) == 0) + return CMD_SUCCESS; + + XFREE (MTYPE_ROUTE_MAP_NAME, proto_rm[AFI_IP][i]); + } + proto_rm[AFI_IP][i] = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[1]); + rib_update(VRF_DEFAULT); + return CMD_SUCCESS; +} + +DEFUN (no_ip_protocol, + no_ip_protocol_cmd, + "no ip protocol " QUAGGA_IP_PROTOCOL_MAP_STR_ZEBRA, + NO_STR + IP_STR + "Stop filtering routing info between zebra and protocol\n" + QUAGGA_IP_PROTOCOL_MAP_HELP_STR_ZEBRA + "Protocol from which to stop filtering routes\n") +{ + int i; + + if (strcasecmp(argv[0], "any") == 0) + i = ZEBRA_ROUTE_MAX; + else + i = proto_name2num(argv[0]); + if (i < 0) + { + vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "", + VTY_NEWLINE); + return CMD_WARNING; + } + if (!proto_rm[AFI_IP][i]) + return CMD_SUCCESS; + + if ((argc == 2 && strcmp(argv[1], proto_rm[AFI_IP][i]) == 0) || + (argc < 2)) + { + XFREE (MTYPE_ROUTE_MAP_NAME, proto_rm[AFI_IP][i]); + proto_rm[AFI_IP][i] = NULL; + rib_update(VRF_DEFAULT); + } + return CMD_SUCCESS; +} + +ALIAS (no_ip_protocol, + no_ip_protocol_val_cmd, + "no ip protocol " QUAGGA_IP_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP", + NO_STR + IP_STR + "Stop filtering routing info between zebra and protocol\n" + QUAGGA_IP_PROTOCOL_MAP_HELP_STR_ZEBRA + "route map name") + +DEFUN (show_ip_protocol, + show_ip_protocol_cmd, + "show ip protocol", + SHOW_STR + IP_STR + "IP protocol filtering status\n") +{ + int i; + + vty_out(vty, "Protocol : route-map %s", VTY_NEWLINE); + vty_out(vty, "------------------------%s", VTY_NEWLINE); + for (i=0;i<ZEBRA_ROUTE_MAX;i++) + { + if (proto_rm[AFI_IP][i]) + vty_out (vty, "%-10s : %-10s%s", zebra_route_string(i), + proto_rm[AFI_IP][i], + VTY_NEWLINE); + else + vty_out (vty, "%-10s : none%s", zebra_route_string(i), VTY_NEWLINE); + } + if (proto_rm[AFI_IP][i]) + vty_out (vty, "%-10s : %-10s%s", "any", proto_rm[AFI_IP][i], + VTY_NEWLINE); + else + vty_out (vty, "%-10s : none%s", "any", VTY_NEWLINE); + + return CMD_SUCCESS; +} + +DEFUN (ip_protocol_nht_rmap, + ip_protocol_nht_rmap_cmd, + "ip nht " QUAGGA_IP_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP", + IP_STR + "Filter Next Hop tracking route resolution\n" + QUAGGA_IP_PROTOCOL_MAP_HELP_STR_ZEBRA + "Route map name\n") +{ + int i; + + if (strcasecmp(argv[0], "any") == 0) + i = ZEBRA_ROUTE_MAX; + else + i = proto_name2num(argv[0]); + if (i < 0) + { + vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "", + VTY_NEWLINE); + return CMD_WARNING; + } + if (nht_rm[AFI_IP][i]) + { + if (strcmp(nht_rm[AFI_IP][i], argv[1]) == 0) + return CMD_SUCCESS; + + XFREE (MTYPE_ROUTE_MAP_NAME, nht_rm[AFI_IP][i]); + } + + nht_rm[AFI_IP][i] = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[1]); + zebra_evaluate_rnh_table(0, AF_INET, 1); + + return CMD_SUCCESS; +} + +DEFUN (no_ip_protocol_nht_rmap, + no_ip_protocol_nht_rmap_cmd, + "no ip nht " QUAGGA_IP_PROTOCOL_MAP_STR_ZEBRA, + NO_STR + IP_STR + "Filter Next Hop tracking route resolution\n" + QUAGGA_IP_PROTOCOL_MAP_HELP_STR_ZEBRA) +{ + int i; + + if (strcasecmp(argv[0], "any") == 0) + i = ZEBRA_ROUTE_MAX; + else + i = proto_name2num(argv[0]); + if (i < 0) + { + vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "", + VTY_NEWLINE); + return CMD_WARNING; + } + if (!nht_rm[AFI_IP][i]) + return CMD_SUCCESS; + + if ((argc == 2 && strcmp(argv[1], nht_rm[AFI_IP][i]) == 0) || + (argc < 2)) + { + XFREE (MTYPE_ROUTE_MAP_NAME, nht_rm[AFI_IP][i]); + nht_rm[AFI_IP][i] = NULL; + zebra_evaluate_rnh_table(0, AF_INET, 1); + } + return CMD_SUCCESS; +} + +ALIAS (no_ip_protocol_nht_rmap, + no_ip_protocol_nht_rmap_val_cmd, + "no ip nht " QUAGGA_IP_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP", + IP_STR + "Filter Next Hop tracking route resolution\n" + QUAGGA_IP_PROTOCOL_MAP_HELP_STR_ZEBRA + "Route map name\n") + +DEFUN (show_ip_protocol_nht, + show_ip_protocol_nht_cmd, + "show ip nht route-map", + SHOW_STR + IP_STR + "IP Next Hop tracking filtering status\n") +{ + int i; + + vty_out(vty, "Protocol : route-map %s", VTY_NEWLINE); + vty_out(vty, "------------------------%s", VTY_NEWLINE); + for (i=0;i<ZEBRA_ROUTE_MAX;i++) + { + if (nht_rm[AFI_IP][i]) + vty_out (vty, "%-10s : %-10s%s", zebra_route_string(i), + nht_rm[AFI_IP][i], + VTY_NEWLINE); + else + vty_out (vty, "%-10s : none%s", zebra_route_string(i), VTY_NEWLINE); + } + if (nht_rm[AFI_IP][i]) + vty_out (vty, "%-10s : %-10s%s", "any", nht_rm[AFI_IP][i], + VTY_NEWLINE); + else + vty_out (vty, "%-10s : none%s", "any", VTY_NEWLINE); + + return CMD_SUCCESS; +} + +DEFUN (ipv6_protocol_nht_rmap, + ipv6_protocol_nht_rmap_cmd, + "ipv6 nht " QUAGGA_IP6_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP", + IP6_STR + "Filter Next Hop tracking route resolution\n" + QUAGGA_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA + "Route map name\n") +{ + int i; + + if (strcasecmp(argv[0], "any") == 0) + i = ZEBRA_ROUTE_MAX; + else + i = proto_name2num(argv[0]); + if (i < 0) + { + vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "", + VTY_NEWLINE); + return CMD_WARNING; + } + if (nht_rm[AFI_IP6][i]) + XFREE (MTYPE_ROUTE_MAP_NAME, nht_rm[AFI_IP6][i]); + nht_rm[AFI_IP6][i] = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[1]); + zebra_evaluate_rnh_table(0, AF_INET6, 1); + + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_protocol_nht_rmap, + no_ipv6_protocol_nht_rmap_cmd, + "no ipv6 nht " QUAGGA_IP6_PROTOCOL_MAP_STR_ZEBRA, + NO_STR + IP6_STR + "Filter Next Hop tracking route resolution\n" + QUAGGA_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA) +{ + int i; + + if (strcasecmp(argv[0], "any") == 0) + i = ZEBRA_ROUTE_MAX; + else + i = proto_name2num(argv[0]); + if (i < 0) + { + vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "", + VTY_NEWLINE); + return CMD_WARNING; + } + if (nht_rm[AFI_IP6][i]) + XFREE (MTYPE_ROUTE_MAP_NAME, nht_rm[AFI_IP6][i]); + + if ((argc == 2 && strcmp(argv[1], nht_rm[AFI_IP6][i]) == 0) || + (argc < 2)) + { + XFREE (MTYPE_ROUTE_MAP_NAME, nht_rm[AFI_IP6][i]); + nht_rm[AFI_IP6][i] = NULL; + zebra_evaluate_rnh_table(0, AF_INET6, 1); + } + + return CMD_SUCCESS; +} + +ALIAS (no_ipv6_protocol_nht_rmap, + no_ipv6_protocol_nht_rmap_val_cmd, + "no ipv6 nht " QUAGGA_IP6_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP", + NO_STR + IP6_STR + "Filter Next Hop tracking route resolution\n" + QUAGGA_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA + "Route map name\n") + +DEFUN (show_ipv6_protocol_nht, + show_ipv6_protocol_nht_cmd, + "show ipv6 nht route-map", + SHOW_STR + IP6_STR + "IPv6 protocol Next Hop filtering status\n") +{ + int i; + + vty_out(vty, "Protocol : route-map %s", VTY_NEWLINE); + vty_out(vty, "------------------------%s", VTY_NEWLINE); + for (i=0;i<ZEBRA_ROUTE_MAX;i++) + { + if (nht_rm[AFI_IP6][i]) + vty_out (vty, "%-10s : %-10s%s", zebra_route_string(i), + nht_rm[AFI_IP6][i], + VTY_NEWLINE); + else + vty_out (vty, "%-10s : none%s", zebra_route_string(i), VTY_NEWLINE); + } + if (nht_rm[AFI_IP][i]) + vty_out (vty, "%-10s : %-10s%s", "any", nht_rm[AFI_IP6][i], + VTY_NEWLINE); + else + vty_out (vty, "%-10s : none%s", "any", VTY_NEWLINE); + + return CMD_SUCCESS; +} + /*XXXXXXXXXXXXXXXXXXXXXXXXXXXX*/ /* `match ip next-hop IP_ACCESS_LIST' */ @@ -423,13 +946,16 @@ route_match_ip_next_hop (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct access_list *alist; - struct nexthop *nexthop; + struct nh_rmap_obj *nh_data; struct prefix_ipv4 p; if (type == RMAP_ZEBRA) { - nexthop = object; - switch (nexthop->type) { + nh_data = object; + if (!nh_data) + return RMAP_DENYMATCH; + + switch (nh_data->nexthop->type) { case NEXTHOP_TYPE_IFINDEX: case NEXTHOP_TYPE_IFNAME: /* Interface routes can't match ip next-hop */ @@ -438,7 +964,7 @@ route_match_ip_next_hop (void *rule, struct prefix *prefix, case NEXTHOP_TYPE_IPV4_IFNAME: case NEXTHOP_TYPE_IPV4: p.family = AF_INET; - p.prefix = nexthop->gate.ipv4; + p.prefix = nh_data->nexthop->gate.ipv4; p.prefixlen = IPV4_MAX_BITLEN; break; default: @@ -485,13 +1011,16 @@ route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct prefix_list *plist; - struct nexthop *nexthop; + struct nh_rmap_obj *nh_data; struct prefix_ipv4 p; if (type == RMAP_ZEBRA) { - nexthop = object; - switch (nexthop->type) { + nh_data = (struct nh_rmap_obj *)object; + if (!nh_data) + return RMAP_DENYMATCH; + + switch (nh_data->nexthop->type) { case NEXTHOP_TYPE_IFINDEX: case NEXTHOP_TYPE_IFNAME: /* Interface routes can't match ip next-hop */ @@ -500,7 +1029,7 @@ route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix, case NEXTHOP_TYPE_IPV4_IFNAME: case NEXTHOP_TYPE_IPV4: p.family = AF_INET; - p.prefix = nexthop->gate.ipv4; + p.prefix = nh_data->nexthop->gate.ipv4; p.prefixlen = IPV4_MAX_BITLEN; break; default: @@ -623,6 +1152,154 @@ static struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = }; +/* `match ip address prefix-len PREFIXLEN' */ + +static route_map_result_t +route_match_ip_address_prefix_len (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + u_int32_t *prefixlen = (u_int32_t *)rule; + + if (type == RMAP_ZEBRA) + { + return ((prefix->prefixlen == *prefixlen) ? RMAP_MATCH : RMAP_NOMATCH); + } + return RMAP_NOMATCH; +} + +static void * +route_match_ip_address_prefix_len_compile (const char *arg) +{ + u_int32_t *prefix_len; + char *endptr = NULL; + unsigned long tmpval; + + /* prefix len value shoud be integer. */ + if (! all_digit (arg)) + return NULL; + + errno = 0; + tmpval = strtoul (arg, &endptr, 10); + if (*endptr != '\0' || errno || tmpval > UINT32_MAX) + return NULL; + + prefix_len = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); + + if (!prefix_len) + return prefix_len; + + *prefix_len = tmpval; + return prefix_len; +} + +static void +route_match_ip_address_prefix_len_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +static struct route_map_rule_cmd route_match_ip_address_prefix_len_cmd = +{ + "ip address prefix-len", + route_match_ip_address_prefix_len, + route_match_ip_address_prefix_len_compile, + route_match_ip_address_prefix_len_free +}; + + +/* `match ip nexthop prefix-len PREFIXLEN' */ + +static route_map_result_t +route_match_ip_nexthop_prefix_len (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + u_int32_t *prefixlen = (u_int32_t *)rule; + struct nh_rmap_obj *nh_data; + struct prefix_ipv4 p; + + if (type == RMAP_ZEBRA) + { + nh_data = (struct nh_rmap_obj *)object; + if (!nh_data || !nh_data->nexthop) + return RMAP_DENYMATCH; + + switch (nh_data->nexthop->type) { + case NEXTHOP_TYPE_IFINDEX: + case NEXTHOP_TYPE_IFNAME: + /* Interface routes can't match ip next-hop */ + return RMAP_NOMATCH; + case NEXTHOP_TYPE_IPV4_IFINDEX: + case NEXTHOP_TYPE_IPV4_IFNAME: + case NEXTHOP_TYPE_IPV4: + p.family = AF_INET; + p.prefix = nh_data->nexthop->gate.ipv4; + p.prefixlen = IPV4_MAX_BITLEN; + break; + default: + return RMAP_NOMATCH; + } + return ((p.prefixlen == *prefixlen) ? RMAP_MATCH : RMAP_NOMATCH); + } + return RMAP_NOMATCH; +} + +static struct route_map_rule_cmd route_match_ip_nexthop_prefix_len_cmd = +{ + "ip next-hop prefix-len", + route_match_ip_nexthop_prefix_len, + route_match_ip_address_prefix_len_compile, /* reuse */ + route_match_ip_address_prefix_len_free /* reuse */ +}; + +/* `match source-protocol PROTOCOL' */ + +static route_map_result_t +route_match_source_protocol (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + u_int32_t *rib_type = (u_int32_t *)rule; + struct nh_rmap_obj *nh_data; + + if (type == RMAP_ZEBRA) + { + nh_data = (struct nh_rmap_obj *)object; + if (!nh_data) + return RMAP_DENYMATCH; + + return ((nh_data->source_protocol == *rib_type) + ? RMAP_MATCH : RMAP_NOMATCH); + } + return RMAP_NOMATCH; +} + +static void * +route_match_source_protocol_compile (const char *arg) +{ + u_int32_t *rib_type; + int i; + + i = proto_name2num(arg); + rib_type = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); + + *rib_type = i; + + return rib_type; +} + +static void +route_match_source_protocol_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +static struct route_map_rule_cmd route_match_source_protocol_cmd = +{ + "source-protocol", + route_match_source_protocol, + route_match_source_protocol_compile, + route_match_source_protocol_free +}; + /* `set src A.B.C.D' */ /* Set src. */ @@ -630,12 +1307,12 @@ static route_map_result_t route_set_src (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { + struct nh_rmap_obj *nh_data; + if (type == RMAP_ZEBRA) { - struct nexthop *nexthop; - - nexthop = object; - nexthop->src = *(union g_addr *)rule; + nh_data = (struct nh_rmap_obj *)object; + nh_data->nexthop->rmap_src = *(union g_addr *)rule; } return RMAP_OKAY; } @@ -675,17 +1352,199 @@ static struct route_map_rule_cmd route_set_src_cmd = route_set_src_free, }; +static int +zebra_route_map_update_timer (struct thread *thread) +{ + zebra_t_rmap_update = NULL; + + if (IS_ZEBRA_DEBUG_EVENT) + zlog_debug("Event driven route-map update triggered"); + + rib_update(VRF_DEFAULT); + zebra_evaluate_rnh_table(0, AF_INET, 1); + zebra_evaluate_rnh_table(0, AF_INET6, 1); + + return (0); +} + +static void +zebra_route_map_set_delay_timer(u_int32_t value) +{ + zebra_rmap_update_timer = value; + if (!value && zebra_t_rmap_update) + { + /* Event driven route map updates is being disabled */ + /* But there's a pending timer. Fire it off now */ + thread_cancel(zebra_t_rmap_update); + zebra_route_map_update_timer(zebra_t_rmap_update); + } +} + +void +zebra_route_map_write_delay_timer (struct vty *vty) +{ + if (vty && (zebra_rmap_update_timer != ZEBRA_RMAP_DEFAULT_UPDATE_TIMER)) + vty_out (vty, "zebra route-map delay-timer %d%s", zebra_rmap_update_timer, + VTY_NEWLINE); + return; +} + +route_map_result_t +zebra_route_map_check (int family, int rib_type, struct prefix *p, + struct nexthop *nexthop, vrf_id_t vrf_id) +{ + struct route_map *rmap = NULL; + route_map_result_t ret = RMAP_MATCH; + struct nh_rmap_obj nh_obj; + + nh_obj.nexthop = nexthop; + nh_obj.vrf_id = vrf_id; + nh_obj.source_protocol = rib_type; + nh_obj.metric = 0; + + if (rib_type >= 0 && rib_type < ZEBRA_ROUTE_MAX) + rmap = route_map_lookup_by_name (proto_rm[family][rib_type]); + if (!rmap && proto_rm[family][ZEBRA_ROUTE_MAX]) + rmap = route_map_lookup_by_name (proto_rm[family][ZEBRA_ROUTE_MAX]); + if (rmap) { + ret = route_map_apply(rmap, p, RMAP_ZEBRA, &nh_obj); + } + + return (ret); +} + +route_map_result_t +zebra_nht_route_map_check (int family, int client_proto, struct prefix *p, + struct rib * rib, struct nexthop *nexthop) +{ + struct route_map *rmap = NULL; + route_map_result_t ret = RMAP_MATCH; + struct nh_rmap_obj nh_obj; + + nh_obj.nexthop = nexthop; + nh_obj.vrf_id = rib->vrf_id; + nh_obj.source_protocol = rib->type; + nh_obj.metric = rib->metric; + + if (client_proto >= 0 && client_proto < ZEBRA_ROUTE_MAX) + rmap = route_map_lookup_by_name (nht_rm[family][client_proto]); + if (!rmap && nht_rm[family][ZEBRA_ROUTE_MAX]) + rmap = route_map_lookup_by_name (nht_rm[family][ZEBRA_ROUTE_MAX]); + if (rmap) { + ret = route_map_apply(rmap, p, RMAP_ZEBRA, &nh_obj); + } + + return (ret); +} + +static void +zebra_route_map_mark_update (const char *rmap_name) +{ + /* rmap_update_timer of 0 means don't do route updates */ + if (zebra_rmap_update_timer && !zebra_t_rmap_update) + zebra_t_rmap_update = + thread_add_timer(zebrad.master, zebra_route_map_update_timer, NULL, + zebra_rmap_update_timer); +} + +static void +zebra_route_map_add (const char *rmap_name) +{ + zebra_route_map_mark_update(rmap_name); + route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED); +} + +static void +zebra_route_map_delete (const char *rmap_name) +{ + zebra_route_map_mark_update(rmap_name); + route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_DELETED); +} + +static void +zebra_route_map_event (route_map_event_t event, const char *rmap_name) +{ + zebra_route_map_mark_update(rmap_name); + route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED); +} + +/* ip protocol configuration write function */ +static int config_write_protocol(struct vty *vty) +{ + int i; + + for (i=0;i<ZEBRA_ROUTE_MAX;i++) + { + if (proto_rm[AFI_IP][i]) + vty_out (vty, "ip protocol %s route-map %s%s", zebra_route_string(i), + proto_rm[AFI_IP][i], VTY_NEWLINE); + + if (nht_rm[AFI_IP][i]) + vty_out (vty, "ip nht %s route-map %s%s", zebra_route_string(i), + nht_rm[AFI_IP][i], VTY_NEWLINE); + + if (nht_rm[AFI_IP6][i]) + vty_out (vty, "ipv6 nht %s route-map %s%s", zebra_route_string(i), + nht_rm[AFI_IP6][i], VTY_NEWLINE); + } + + if (proto_rm[AFI_IP][ZEBRA_ROUTE_MAX]) + vty_out (vty, "ip protocol %s route-map %s%s", "any", + proto_rm[AFI_IP][ZEBRA_ROUTE_MAX], VTY_NEWLINE); + + if (nht_rm[AFI_IP][ZEBRA_ROUTE_MAX]) + vty_out (vty, "ip nht %s route-map %s%s", "any", + nht_rm[AFI_IP][ZEBRA_ROUTE_MAX], VTY_NEWLINE); + + if (nht_rm[AFI_IP6][ZEBRA_ROUTE_MAX]) + vty_out (vty, "ipv6 nht %s route-map %s%s", "any", + nht_rm[AFI_IP6][ZEBRA_ROUTE_MAX], VTY_NEWLINE); + + if (zebra_rmap_update_timer != ZEBRA_RMAP_DEFAULT_UPDATE_TIMER) + vty_out (vty, "zebra route-map delay-timer %d%s", zebra_rmap_update_timer, + VTY_NEWLINE); + return 1; +} +/* table node for protocol filtering */ +static struct cmd_node protocol_node = { PROTOCOL_NODE, "", 1 }; + void zebra_route_map_init () { + install_node (&protocol_node, config_write_protocol); + install_element (CONFIG_NODE, &ip_protocol_cmd); + install_element (CONFIG_NODE, &no_ip_protocol_cmd); + install_element (CONFIG_NODE, &no_ip_protocol_val_cmd); + install_element (VIEW_NODE, &show_ip_protocol_cmd); + install_element (ENABLE_NODE, &show_ip_protocol_cmd); + install_element (CONFIG_NODE, &ip_protocol_nht_rmap_cmd); + install_element (CONFIG_NODE, &no_ip_protocol_nht_rmap_cmd); + install_element (CONFIG_NODE, &no_ip_protocol_nht_rmap_val_cmd); + install_element (VIEW_NODE, &show_ip_protocol_nht_cmd); + install_element (ENABLE_NODE, &show_ip_protocol_nht_cmd); + install_element (CONFIG_NODE, &ipv6_protocol_nht_rmap_cmd); + install_element (CONFIG_NODE, &no_ipv6_protocol_nht_rmap_cmd); + install_element (ENABLE_NODE, &no_ipv6_protocol_nht_rmap_val_cmd); + install_element (VIEW_NODE, &show_ipv6_protocol_nht_cmd); + install_element (ENABLE_NODE, &show_ipv6_protocol_nht_cmd); + install_element (CONFIG_NODE, &zebra_route_map_timer_cmd); + install_element (CONFIG_NODE, &no_zebra_route_map_timer_cmd); + route_map_init (); route_map_init_vty (); + route_map_add_hook (zebra_route_map_add); + route_map_delete_hook (zebra_route_map_delete); + route_map_event_hook (zebra_route_map_event); + route_map_install_match (&route_match_interface_cmd); route_map_install_match (&route_match_ip_next_hop_cmd); route_map_install_match (&route_match_ip_next_hop_prefix_list_cmd); route_map_install_match (&route_match_ip_address_cmd); route_map_install_match (&route_match_ip_address_prefix_list_cmd); + route_map_install_match (&route_match_ip_address_prefix_len_cmd); + route_map_install_match (&route_match_ip_nexthop_prefix_len_cmd); + route_map_install_match (&route_match_source_protocol_cmd); /* */ route_map_install_set (&route_set_src_cmd); /* */ @@ -704,7 +1563,15 @@ zebra_route_map_init () install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd); install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd); install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd); -/* */ + install_element (RMAP_NODE, &match_ip_nexthop_prefix_len_cmd); + install_element (RMAP_NODE, &no_match_ip_nexthop_prefix_len_cmd); + install_element (RMAP_NODE, &no_match_ip_nexthop_prefix_len_val_cmd); + install_element (RMAP_NODE, &match_ip_address_prefix_len_cmd); + install_element (RMAP_NODE, &no_match_ip_address_prefix_len_cmd); + install_element (RMAP_NODE, &no_match_ip_address_prefix_len_val_cmd); + install_element (RMAP_NODE, &match_source_protocol_cmd); + install_element (RMAP_NODE, &no_match_source_protocol_cmd); + /* */ install_element (RMAP_NODE, &set_src_cmd); install_element (RMAP_NODE, &no_set_src_cmd); } diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 21b92ea9..965ea89c 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -28,8 +28,10 @@ #include "table.h" #include "rib.h" #include "vrf.h" +#include "nexthop.h" #include "zebra/zserv.h" +#include "zebra/zebra_rnh.h" static int do_show_ip_route(struct vty *vty, safi_t safi, vrf_id_t vrf_id); static void vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, @@ -42,7 +44,8 @@ static int zebra_static_ipv4_safi (struct vty *vty, safi_t safi, int add_cmd, const char *dest_str, const char *mask_str, const char *gate_str, const char *flag_str, - const char *distance_str, const char *vrf_id_str) + const char *tag_str, const char *distance_str, + const char *vrf_id_str) { int ret; u_char distance; @@ -51,6 +54,7 @@ zebra_static_ipv4_safi (struct vty *vty, safi_t safi, int add_cmd, struct in_addr mask; const char *ifname; u_char flag = 0; + u_short tag = 0; vrf_id_t vrf_id = VRF_DEFAULT; ret = str2prefix (dest_str, &p); @@ -81,10 +85,18 @@ zebra_static_ipv4_safi (struct vty *vty, safi_t safi, int add_cmd, else distance = ZEBRA_STATIC_DISTANCE_DEFAULT; + /* tag */ + if (tag_str) + tag = atoi (tag_str); + /* VRF id */ if (vrf_id_str) VTY_GET_INTEGER ("VRF ID", vrf_id, vrf_id_str); + /* tag */ + if (tag_str) + tag = atoi(tag_str); + /* Null0 static route. */ if ((gate_str != NULL) && (strncasecmp (gate_str, "Null0", strlen (gate_str)) == 0)) { @@ -94,9 +106,9 @@ zebra_static_ipv4_safi (struct vty *vty, safi_t safi, int add_cmd, return CMD_WARNING; } if (add_cmd) - static_add_ipv4_safi (safi, &p, NULL, NULL, ZEBRA_FLAG_BLACKHOLE, distance, vrf_id); + static_add_ipv4_safi (safi, &p, NULL, NULL, ZEBRA_FLAG_BLACKHOLE, tag, distance, vrf_id); else - static_delete_ipv4_safi (safi, &p, NULL, NULL, distance, vrf_id); + static_delete_ipv4_safi (safi, &p, NULL, NULL, tag, distance, vrf_id); return CMD_SUCCESS; } @@ -120,9 +132,9 @@ zebra_static_ipv4_safi (struct vty *vty, safi_t safi, int add_cmd, if (gate_str == NULL) { if (add_cmd) - static_add_ipv4_safi (safi, &p, NULL, NULL, flag, distance, vrf_id); + static_add_ipv4_safi (safi, &p, NULL, NULL, flag, tag, distance, vrf_id); else - static_delete_ipv4_safi (safi, &p, NULL, NULL, distance, vrf_id); + static_delete_ipv4_safi (safi, &p, NULL, NULL, tag, distance, vrf_id); return CMD_SUCCESS; } @@ -136,23 +148,13 @@ zebra_static_ipv4_safi (struct vty *vty, safi_t safi, int add_cmd, ifname = gate_str; if (add_cmd) - static_add_ipv4_safi (safi, &p, ifname ? NULL : &gate, ifname, flag, distance, vrf_id); + static_add_ipv4_safi (safi, &p, ifname ? NULL : &gate, ifname, flag, tag, distance, vrf_id); else - static_delete_ipv4_safi (safi, &p, ifname ? NULL : &gate, ifname, distance, vrf_id); + static_delete_ipv4_safi (safi, &p, ifname ? NULL : &gate, ifname, tag, distance, vrf_id); return CMD_SUCCESS; } -static int -zebra_static_ipv4 (struct vty *vty, int add_cmd, const char *dest_str, - const char *mask_str, const char *gate_str, - const char *flag_str, const char *distance_str, - const char *vrf_id_str) -{ - return zebra_static_ipv4_safi (vty, SAFI_UNICAST, add_cmd, dest_str, mask_str, - gate_str, flag_str, distance_str, vrf_id_str); -} - /* Static unicast routes for multicast RPF lookup. */ DEFUN (ip_mroute_dist, ip_mroute_dist_cmd, @@ -166,7 +168,7 @@ DEFUN (ip_mroute_dist, { VTY_WARN_EXPERIMENTAL(); return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 1, argv[0], NULL, argv[1], - NULL, argc > 2 ? argv[2] : NULL, NULL); + NULL, NULL, argc > 2 ? argv[2] : NULL, NULL); } ALIAS (ip_mroute_dist, @@ -191,7 +193,7 @@ DEFUN (ip_mroute_dist_vrf, { VTY_WARN_EXPERIMENTAL(); return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 1, argv[0], NULL, argv[1], - NULL, argc > 3 ? argv[2] : NULL, + NULL, NULL, argc > 3 ? argv[2] : NULL, argc > 3 ? argv[3] : argv[2]); } @@ -217,7 +219,7 @@ DEFUN (no_ip_mroute_dist, { VTY_WARN_EXPERIMENTAL(); return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 0, argv[0], NULL, argv[1], - NULL, argc > 2 ? argv[2] : NULL, NULL); + NULL, NULL, argc > 2 ? argv[2] : NULL, NULL); } ALIAS (no_ip_mroute_dist, @@ -243,7 +245,7 @@ DEFUN (no_ip_mroute_dist_vrf, { VTY_WARN_EXPERIMENTAL(); return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 0, argv[0], NULL, argv[1], - NULL, argc > 3 ? argv[2] : NULL, + NULL, NULL, argc > 3 ? argv[2] : NULL, argc > 3 ? argv[3] : argv[2]); } @@ -467,8 +469,41 @@ DEFUN (ip_route, "IP gateway interface name\n" "Null interface\n") { - return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], NULL, NULL, - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1], + NULL, NULL, NULL, NULL); +} + +DEFUN (ip_route_tag, + ip_route_tag_cmd, + "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535>", + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Set tag for this route\n" + "Tag value\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, + argv[1], NULL, argv[2], NULL, NULL); +} + +DEFUN (ip_route_tag_vrf, + ip_route_tag_vrf_cmd, + "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Set tag for this route\n" + "Tag value\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, + argv[1], NULL, argv[2], NULL, argv[3]); } DEFUN (ip_route_flags, @@ -482,8 +517,44 @@ DEFUN (ip_route_flags, "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") { - return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], argv[2], NULL, - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1], + argv[2], NULL, NULL, NULL); +} + +DEFUN (ip_route_flags_tag, + ip_route_flags_tag_cmd, + "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535>", + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n") + +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1], + argv[2], argv[3], NULL, NULL); +} + +DEFUN (ip_route_flags_tag_vrf, + ip_route_flags_tag_vrf_cmd, + "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1], + argv[2], argv[3], NULL, argv[4]); } DEFUN (ip_route_flags2, @@ -495,8 +566,39 @@ DEFUN (ip_route_flags2, "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") { - return zebra_static_ipv4 (vty, 1, argv[0], NULL, NULL, argv[1], NULL, - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, + NULL, argv[1], NULL, NULL, NULL); +} + +DEFUN (ip_route_flags2_tag, + ip_route_flags2_tag_cmd, + "ip route A.B.C.D/M (reject|blackhole) tag <1-65535>", + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, NULL, + argv[1], argv[2], NULL, NULL); +} + +DEFUN (ip_route_flags2_tag_vrf, + ip_route_flags2_tag_vrf_cmd, + "ip route A.B.C.D/M (reject|blackhole) tag <1-65535>", + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, NULL, + argv[1], argv[2], NULL, argv[3]); } /* Mask as A.B.C.D format. */ @@ -511,8 +613,44 @@ DEFUN (ip_route_mask, "IP gateway interface name\n" "Null interface\n") { - return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], NULL, NULL, - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], + argv[2], NULL, NULL, NULL, NULL); +} + +DEFUN (ip_route_mask_tag, + ip_route_mask_tag_cmd, + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-65535>", + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Set tag for this route\n" + "Tag value\n") + +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2], + NULL, argv[3], NULL, NULL); +} + +DEFUN (ip_route_mask_tag_vrf, + ip_route_mask_tag_vrf_cmd, + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-65535>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Set tag for this route\n" + "Tag value\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2], + NULL, argv[3], NULL, argv[4]); } DEFUN (ip_route_mask_flags, @@ -527,8 +665,45 @@ DEFUN (ip_route_mask_flags, "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") { - return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL, - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], + argv[2], argv[3], NULL, NULL, NULL); +} + +DEFUN (ip_route_mask_flags_tag, + ip_route_mask_flags_tag_cmd, + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535>", + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], + argv[2], argv[3], argv[4], NULL, NULL); +} + +DEFUN (ip_route_mask_flags_tag_vrf, + ip_route_mask_flags_tag_vrf_cmd, + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], + argv[2], argv[3], argv[4], NULL, argv[5]); } DEFUN (ip_route_mask_flags2, @@ -541,8 +716,41 @@ DEFUN (ip_route_mask_flags2, "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") { - return zebra_static_ipv4 (vty, 1, argv[0], argv[1], NULL, argv[2], NULL, - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], + NULL, argv[2], NULL, NULL, NULL); +} + +DEFUN (ip_route_mask_flags2_tag, + ip_route_mask_flags2_tag_cmd, + "ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535>", + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], NULL, + argv[2], argv[3], NULL, NULL); +} + +DEFUN (ip_route_mask_flags2_tag_vrf, + ip_route_mask_flags2_tag_vrf_cmd, + "ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], NULL, + argv[2], argv[3], NULL, argv[4]); } /* Distance option value. */ @@ -557,8 +765,43 @@ DEFUN (ip_route_distance, "Null interface\n" "Distance value for this route\n") { - return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], NULL, argv[2], - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, + argv[1], NULL, NULL, argv[2], NULL); +} + +DEFUN (ip_route_tag_distance, + ip_route_tag_distance_cmd, + "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>", + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, + argv[1], NULL, argv[2], argv[3], NULL); +} + +DEFUN (ip_route_tag_distance_vrf, + ip_route_tag_distance_vrf_cmd, + "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, + argv[1], NULL, argv[2], argv[3], argv[4]); } DEFUN (ip_route_flags_distance, @@ -573,8 +816,45 @@ DEFUN (ip_route_flags_distance, "Silently discard pkts when matched\n" "Distance value for this route\n") { - return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], argv[2], argv[3], - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1], + argv[2], NULL, argv[3], NULL); +} + +DEFUN (ip_route_flags_tag_distance, + ip_route_flags_tag_distance_cmd, + "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>", + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1], + argv[2], argv[3], argv[4], NULL); +} + +DEFUN (ip_route_flags_tag_distance_vrf, + ip_route_flags_tag_distance_vrf_cmd, + "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1], + argv[2], argv[3], argv[4], argv[5]); } DEFUN (ip_route_flags_distance2, @@ -587,8 +867,41 @@ DEFUN (ip_route_flags_distance2, "Silently discard pkts when matched\n" "Distance value for this route\n") { - return zebra_static_ipv4 (vty, 1, argv[0], NULL, NULL, argv[1], argv[2], - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, + NULL, argv[1], NULL, argv[2], NULL); +} + +DEFUN (ip_route_flags_tag_distance2, + ip_route_flags_tag_distance2_cmd, + "ip route A.B.C.D/M (reject|blackhole) tag <1-65535> <1-255>", + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, + NULL, argv[1], argv[2], argv[3], NULL); +} + +DEFUN (ip_route_flags_tag_distance2_vrf, + ip_route_flags_tag_distance2_vrf_cmd, + "ip route A.B.C.D/M (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, + NULL, argv[1], argv[2], argv[3], argv[4]); } DEFUN (ip_route_mask_distance, @@ -603,8 +916,85 @@ DEFUN (ip_route_mask_distance, "Null interface\n" "Distance value for this route\n") { - return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3], - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2], + NULL, NULL, argv[3], NULL); +} + +DEFUN (ip_route_mask_tag_distance, + ip_route_mask_tag_distance_cmd, + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>", + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], + argv[2], NULL, argv[3], argv[4], NULL); +} + +DEFUN (ip_route_mask_tag_distance_vrf, + ip_route_mask_tag_distance_vrf_cmd, + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], + argv[2], NULL, argv[3], argv[4], argv[5]); +} + + +DEFUN (ip_route_mask_flags_tag_distance, + ip_route_mask_flags_tag_distance_cmd, + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>", + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5], NULL); +} + +DEFUN (ip_route_mask_flags_tag_distance_vrf, + ip_route_mask_flags_tag_distance_vrf_cmd, + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5], argv[6]); } DEFUN (ip_route_mask_flags_distance, @@ -620,8 +1010,8 @@ DEFUN (ip_route_mask_flags_distance, "Silently discard pkts when matched\n" "Distance value for this route\n") { - return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4], - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2], + argv[3], NULL, argv[4], NULL); } DEFUN (ip_route_mask_flags_distance2, @@ -635,8 +1025,43 @@ DEFUN (ip_route_mask_flags_distance2, "Silently discard pkts when matched\n" "Distance value for this route\n") { - return zebra_static_ipv4 (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3], - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], + NULL, argv[2], NULL, argv[3], NULL); +} + +DEFUN (ip_route_mask_flags_tag_distance2, + ip_route_mask_flags_tag_distance2_cmd, + "ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535> <1-255>", + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], NULL, + argv[2], argv[3], argv[4], NULL); +} + +DEFUN (ip_route_mask_flags_tag_distance2_vrf, + ip_route_mask_flags_tag_distance2_vrf_cmd, + "ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], NULL, + argv[2], argv[3], argv[4], argv[5]); } DEFUN (no_ip_route, @@ -650,8 +1075,43 @@ DEFUN (no_ip_route, "IP gateway interface name\n" "Null interface\n") { - return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], NULL, NULL, - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, + argv[1], NULL, NULL, NULL, NULL); +} + +DEFUN (no_ip_route_tag, + no_ip_route_tag_cmd, + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535>", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Tag of this route\n" + "Tag value\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1], + NULL, argv[2], NULL, NULL); +} + +DEFUN (no_ip_route_tag_vrf, + no_ip_route_tag_vrf_cmd, + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535>" VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Tag of this route\n" + "Tag value\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1], + NULL, argv[2], NULL, argv[3]); } ALIAS (no_ip_route, @@ -666,6 +1126,20 @@ ALIAS (no_ip_route, "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") +ALIAS (no_ip_route_tag, + no_ip_route_flags_tag_cmd, + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535>", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Tag of this route\n" + "Tag value\n") + DEFUN (no_ip_route_flags2, no_ip_route_flags2_cmd, "no ip route A.B.C.D/M (reject|blackhole)", @@ -676,8 +1150,41 @@ DEFUN (no_ip_route_flags2, "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") { - return zebra_static_ipv4 (vty, 0, argv[0], NULL, NULL, NULL, NULL, - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, + NULL, NULL, NULL, NULL, NULL); +} + +DEFUN (no_ip_route_flags2_tag, + no_ip_route_flags2_tag_cmd, + "no ip route A.B.C.D/M (reject|blackhole) tag <1-65535>", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Tag of this route\n" + "Tag value\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, NULL, + NULL, argv[1], NULL, NULL); +} + +DEFUN (no_ip_route_flags2_tag_vrf, + no_ip_route_flags2_tag_vrf_cmd, + "no ip route A.B.C.D/M (reject|blackhole) tag <1-65535>" VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Tag of this route\n" + "Tag value\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, NULL, + NULL, argv[1], NULL, argv[2]); } DEFUN (no_ip_route_mask, @@ -692,8 +1199,26 @@ DEFUN (no_ip_route_mask, "IP gateway interface name\n" "Null interface\n") { - return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], NULL, NULL, - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], + argv[2], NULL, NULL, NULL, NULL); +} + +DEFUN (no_ip_route_mask_tag, + no_ip_route_mask_tag_cmd, + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-65535>", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Tag of this route\n" + "Tag value\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], argv[2], + NULL, argv[3], NULL, NULL); } ALIAS (no_ip_route_mask, @@ -709,6 +1234,21 @@ ALIAS (no_ip_route_mask, "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") +ALIAS (no_ip_route_mask_tag, + no_ip_route_mask_flags_tag_cmd, + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535>", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Tag of this route\n" + "Tag value\n") + DEFUN (no_ip_route_mask_flags2, no_ip_route_mask_flags2_cmd, "no ip route A.B.C.D A.B.C.D (reject|blackhole)", @@ -720,8 +1260,43 @@ DEFUN (no_ip_route_mask_flags2, "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") { - return zebra_static_ipv4 (vty, 0, argv[0], argv[1], NULL, NULL, NULL, - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], + NULL, NULL, NULL, NULL, NULL); +} + +DEFUN (no_ip_route_mask_flags2_tag, + no_ip_route_mask_flags2_tag_cmd, + "no ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535>", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Tag of this route\n" + "Tag value\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], + NULL, NULL, argv[2], NULL, NULL); +} + +DEFUN (no_ip_route_mask_flags2_tag_vrf, + no_ip_route_mask_flags2_tag_vrf_cmd, + "no ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535>" VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Tag of this route\n" + "Tag value\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], + NULL, NULL, argv[2], NULL, argv[3]); } DEFUN (no_ip_route_distance, @@ -736,8 +1311,45 @@ DEFUN (no_ip_route_distance, "Null interface\n" "Distance value for this route\n") { - return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], NULL, argv[2], - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, + argv[1], NULL, NULL, argv[2], NULL); +} + +DEFUN (no_ip_route_tag_distance, + no_ip_route_tag_distance_cmd, + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Tag of this route\n" + "Tag value\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1], + NULL, argv[2], argv[3], NULL); +} + +DEFUN (no_ip_route_tag_distance_vrf, + no_ip_route_tag_distance_vrf_cmd, + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>" VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Tag of this route\n" + "Tag value\n" + "Distance value for this route\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1], + NULL, argv[2], argv[3], argv[4]); } DEFUN (no_ip_route_flags_distance, @@ -753,8 +1365,47 @@ DEFUN (no_ip_route_flags_distance, "Silently discard pkts when matched\n" "Distance value for this route\n") { - return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], argv[2], argv[3], - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, + argv[1], argv[2], NULL, argv[3], NULL); +} + +DEFUN (no_ip_route_flags_tag_distance, + no_ip_route_flags_tag_distance_cmd, + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Tag of this route\n" + "Tag value\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1], + argv[2], argv[3], argv[4], NULL); +} + +DEFUN (no_ip_route_flags_tag_distance_vrf, + no_ip_route_flags_tag_distance_vrf_cmd, + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Tag of this route\n" + "Tag value\n" + "Distance value for this route\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1], + argv[2], argv[3], argv[4], argv[5]); } DEFUN (no_ip_route_flags_distance2, @@ -768,8 +1419,43 @@ DEFUN (no_ip_route_flags_distance2, "Silently discard pkts when matched\n" "Distance value for this route\n") { - return zebra_static_ipv4 (vty, 0, argv[0], NULL, NULL, argv[1], argv[2], - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, NULL, + argv[1], NULL, argv[2], NULL); +} + +DEFUN (no_ip_route_flags_tag_distance2, + no_ip_route_flags_tag_distance2_cmd, + "no ip route A.B.C.D/M (reject|blackhole) tag <1-65535> <1-255>", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Tag of this route\n" + "Tag value\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, NULL, + argv[1], argv[2] , argv[3], NULL); +} + +DEFUN (no_ip_route_flags_tag_distance2_vrf, + no_ip_route_flags_tag_distance2_vrf_cmd, + "no ip route A.B.C.D/M (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Tag of this route\n" + "Tag value\n" + "Distance value for this route\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, NULL, + argv[1], argv[2] , argv[3], argv[4]); } DEFUN (no_ip_route_mask_distance, @@ -785,8 +1471,47 @@ DEFUN (no_ip_route_mask_distance, "Null interface\n" "Distance value for this route\n") { - return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3], - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], + argv[2], NULL, NULL, argv[3], NULL); +} + +DEFUN (no_ip_route_mask_tag_distance, + no_ip_route_mask_tag_distance_cmd, + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Tag of this route\n" + "Tag value\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], + argv[2], NULL, argv[3], argv[4], NULL); +} + +DEFUN (no_ip_route_mask_tag_distance_vrf, + no_ip_route_mask_tag_distance_vrf_cmd, + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>" VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Tag of this route\n" + "Tag value\n" + "Distance value for this route\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], + argv[2], NULL, argv[3], argv[4], argv[5]); } DEFUN (no_ip_route_mask_flags_distance, @@ -803,8 +1528,49 @@ DEFUN (no_ip_route_mask_flags_distance, "Silently discard pkts when matched\n" "Distance value for this route\n") { - return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4], - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], + argv[2], argv[3], NULL, argv[4], NULL); +} + +DEFUN (no_ip_route_mask_flags_tag_distance, + no_ip_route_mask_flags_tag_distance_cmd, + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Tag of this route\n" + "Tag value\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], argv[2], argv[3], + argv[4], argv[5], NULL); +} + +DEFUN (no_ip_route_mask_flags_tag_distance_vrf, + no_ip_route_mask_flags_tag_distance_vrf_cmd, + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Tag of this route\n" + "Tag value\n" + "Distance value for this route\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], argv[2], argv[3], + argv[4], argv[5], argv[6]); } DEFUN (no_ip_route_mask_flags_distance2, @@ -819,8 +1585,8 @@ DEFUN (no_ip_route_mask_flags_distance2, "Silently discard pkts when matched\n" "Distance value for this route\n") { - return zebra_static_ipv4 (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3], - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], + NULL, argv[2], NULL, argv[3], NULL); } DEFUN (ip_route_vrf, @@ -834,8 +1600,8 @@ DEFUN (ip_route_vrf, "Null interface\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], NULL, NULL, - argv[2]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, + argv[1], NULL, NULL, NULL, argv[2]); } DEFUN (ip_route_flags_vrf, @@ -850,8 +1616,8 @@ DEFUN (ip_route_flags_vrf, "Silently discard pkts when matched\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], argv[2], NULL, - argv[3]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, + argv[1], argv[2], NULL, NULL, argv[3]); } DEFUN (ip_route_flags2_vrf, @@ -864,8 +1630,8 @@ DEFUN (ip_route_flags2_vrf, "Silently discard pkts when matched\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 1, argv[0], NULL, NULL, argv[1], NULL, - argv[2]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, + NULL, argv[1], NULL, NULL, argv[2]); } /* Mask as A.B.C.D format. */ @@ -881,8 +1647,8 @@ DEFUN (ip_route_mask_vrf, "Null interface\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], NULL, NULL, - argv[3]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], + argv[2], NULL, NULL, NULL, argv[3]); } DEFUN (ip_route_mask_flags_vrf, @@ -898,8 +1664,8 @@ DEFUN (ip_route_mask_flags_vrf, "Silently discard pkts when matched\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL, - argv[4]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], + argv[2], argv[3], NULL, NULL, argv[4]); } DEFUN (ip_route_mask_flags2_vrf, @@ -913,8 +1679,8 @@ DEFUN (ip_route_mask_flags2_vrf, "Silently discard pkts when matched\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 1, argv[0], argv[1], NULL, argv[2], NULL, - argv[3]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], + NULL, argv[2], NULL, NULL, argv[3]); } /* Distance option value. */ @@ -930,8 +1696,8 @@ DEFUN (ip_route_distance_vrf, "Distance value for this route\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], NULL, argv[2], - argv[3]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, + argv[1], NULL, NULL, argv[2], argv[3]); } DEFUN (ip_route_flags_distance_vrf, @@ -947,8 +1713,8 @@ DEFUN (ip_route_flags_distance_vrf, "Distance value for this route\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], argv[2], argv[3], - argv[4]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, + argv[1], argv[2], NULL, argv[3], argv[4]); } DEFUN (ip_route_flags_distance2_vrf, @@ -962,8 +1728,8 @@ DEFUN (ip_route_flags_distance2_vrf, "Distance value for this route\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 1, argv[0], NULL, NULL, argv[1], argv[2], - argv[3]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, + NULL, argv[1], NULL, argv[2], argv[3]); } DEFUN (ip_route_mask_distance_vrf, @@ -979,8 +1745,8 @@ DEFUN (ip_route_mask_distance_vrf, "Distance value for this route\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3], - argv[4]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], + argv[2], NULL, NULL, argv[3], argv[4]); } DEFUN (ip_route_mask_flags_distance_vrf, @@ -997,8 +1763,8 @@ DEFUN (ip_route_mask_flags_distance_vrf, "Distance value for this route\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4], - argv[5]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], + argv[2], argv[3], NULL, argv[4], argv[5]); } DEFUN (ip_route_mask_flags_distance2_vrf, @@ -1013,8 +1779,8 @@ DEFUN (ip_route_mask_flags_distance2_vrf, "Distance value for this route\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3], - argv[4]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], + NULL, argv[2], NULL, argv[3], argv[4]); } DEFUN (no_ip_route_vrf, @@ -1029,8 +1795,9 @@ DEFUN (no_ip_route_vrf, "Null interface\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], NULL, NULL, - (argc > 3) ? argv[3] : argv[2]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], + NULL, argv[1], NULL, NULL, NULL, + (argc > 3) ? argv[3] : argv[2]); } ALIAS (no_ip_route_vrf, @@ -1057,8 +1824,8 @@ DEFUN (no_ip_route_flags2_vrf, "Silently discard pkts when matched\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 0, argv[0], NULL, NULL, NULL, NULL, - argv[2]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], + NULL, NULL, NULL, NULL, NULL, argv[2]); } DEFUN (no_ip_route_mask_vrf, @@ -1074,8 +1841,9 @@ DEFUN (no_ip_route_mask_vrf, "Null interface\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], NULL, NULL, - (argc > 4) ? argv[4] : argv[3]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], + argv[2], NULL, NULL, NULL, + (argc > 4) ? argv[4] : argv[3]); } ALIAS (no_ip_route_mask_vrf, @@ -1104,8 +1872,8 @@ DEFUN (no_ip_route_mask_flags2_vrf, "Silently discard pkts when matched\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 0, argv[0], argv[1], NULL, NULL, NULL, - argv[2]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], + NULL, NULL, NULL, NULL, argv[2]); } DEFUN (no_ip_route_distance_vrf, @@ -1121,8 +1889,8 @@ DEFUN (no_ip_route_distance_vrf, "Distance value for this route\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], NULL, argv[2], - argv[3]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, + argv[1], NULL, NULL, argv[2], argv[3]); } DEFUN (no_ip_route_flags_distance_vrf, @@ -1139,8 +1907,8 @@ DEFUN (no_ip_route_flags_distance_vrf, "Distance value for this route\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], argv[2], argv[3], - argv[4]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1], + argv[2], NULL, argv[3], argv[4]); } DEFUN (no_ip_route_flags_distance2_vrf, @@ -1155,8 +1923,8 @@ DEFUN (no_ip_route_flags_distance2_vrf, "Distance value for this route\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 0, argv[0], NULL, NULL, argv[1], argv[2], - argv[3]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, NULL, + argv[1], NULL, argv[2], argv[3]); } DEFUN (no_ip_route_mask_distance_vrf, @@ -1173,8 +1941,8 @@ DEFUN (no_ip_route_mask_distance_vrf, "Distance value for this route\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3], - argv[4]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], + argv[2], NULL, NULL, argv[3], argv[4]); } DEFUN (no_ip_route_mask_flags_distance_vrf, @@ -1192,8 +1960,8 @@ DEFUN (no_ip_route_mask_flags_distance_vrf, "Distance value for this route\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4], - argv[5]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], argv[2], + argv[3], NULL, argv[4], argv[5]); } DEFUN (no_ip_route_mask_flags_distance2_vrf, @@ -1209,63 +1977,49 @@ DEFUN (no_ip_route_mask_flags_distance2_vrf, "Distance value for this route\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3], - argv[4]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], NULL, + argv[2], NULL, argv[3], argv[4]); } -char *proto_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1]; /* "any" == ZEBRA_ROUTE_MAX */ - -DEFUN (ip_protocol, - ip_protocol_cmd, - "ip protocol PROTO route-map ROUTE-MAP", +DEFUN (no_ip_route_mask_flags_tag_distance2, + no_ip_route_mask_flags_tag_distance2_cmd, + "no ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535> <1-255>", NO_STR - "Apply route map to PROTO\n" - "Protocol name\n" - "Route map name\n") + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Tag of this route\n" + "Tag value\n" + "Distance value for this route\n") { - int i; - - if (strcasecmp(argv[0], "any") == 0) - i = ZEBRA_ROUTE_MAX; - else - i = proto_name2num(argv[0]); - if (i < 0) - { - vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "", - VTY_NEWLINE); - return CMD_WARNING; - } - if (proto_rm[AFI_IP][i]) - XFREE (MTYPE_ROUTE_MAP_NAME, proto_rm[AFI_IP][i]); - proto_rm[AFI_IP][i] = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[1]); - return CMD_SUCCESS; + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], NULL, + argv[2], argv[3], argv[4], NULL); } -DEFUN (no_ip_protocol, - no_ip_protocol_cmd, - "no ip protocol PROTO", +DEFUN (no_ip_route_mask_flags_tag_distance2_vrf, + no_ip_route_mask_flags_tag_distance2_vrf_cmd, + "no ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, NO_STR - "Remove route map from PROTO\n" - "Protocol name\n") + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Tag of this route\n" + "Tag value\n" + "Distance value for this route\n" + VRF_CMD_HELP_STR) { - int i; - - if (strcasecmp(argv[0], "any") == 0) - i = ZEBRA_ROUTE_MAX; - else - i = proto_name2num(argv[0]); - if (i < 0) - { - vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "", - VTY_NEWLINE); - return CMD_WARNING; - } - if (proto_rm[AFI_IP][i]) - XFREE (MTYPE_ROUTE_MAP_NAME, proto_rm[AFI_IP][i]); - proto_rm[AFI_IP][i] = NULL; - return CMD_SUCCESS; + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], NULL, + argv[2], argv[3], argv[4], argv[5]); } +extern char *proto_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1]; /* "any" == ZEBRA_ROUTE_MAX */ + /* New RIB. Detailed information for IPv4 route. */ static void vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast) @@ -1292,6 +2046,7 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast) vty_out (vty, ", distance %u, metric %u", rib->distance, rib->metric); if (rib->mtu) vty_out (vty, ", mtu %u", rib->mtu); + vty_out (vty, ", tag %d", rib->tag); vty_out (vty, ", vrf %u", rib->vrf_id); if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) vty_out (vty, ", best"); @@ -1609,6 +2364,81 @@ ALIAS (show_ip_route, "IP routing table\n" VRF_CMD_HELP_STR) +DEFUN (show_ip_nht, + show_ip_nht_cmd, + "show ip nht", + SHOW_STR + IP_STR + "IP nexthop tracking table\n") +{ + zebra_print_rnh_table(0, AF_INET, vty); + return CMD_SUCCESS; +} + +DEFUN (show_ipv6_nht, + show_ipv6_nht_cmd, + "show ipv6 nht", + SHOW_STR + IP_STR + "IPv6 nexthop tracking table\n") +{ + zebra_print_rnh_table(0, AF_INET6, vty); + return CMD_SUCCESS; +} + +DEFUN (show_ip_route_tag, + show_ip_route_tag_cmd, + "show ip route tag <1-65535>", + SHOW_STR + IP_STR + "IP routing table\n" + "Show only routes with tag\n" + "Tag value\n") +{ + struct route_table *table; + struct route_node *rn; + struct rib *rib; + int first = 1; + u_short tag = 0; + vrf_id_t vrf_id = VRF_DEFAULT; + + if (argv[0]) + tag = atoi(argv[0]); + + if (argc == 2) + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]); + + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); + if (! table) + return CMD_SUCCESS; + + /* Show all IPv4 routes with matching tag value. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + RNODE_FOREACH_RIB (rn, rib) + { + if (rib->tag != tag) + continue; + + if (first) + { + vty_out (vty, SHOW_ROUTE_V4_HEADER); + first = 0; + } + vty_show_ip_route (vty, rn, rib); + } + return CMD_SUCCESS; +} + +ALIAS (show_ip_route_tag, + show_ip_route_tag_vrf_cmd, + "show ip route tag <1-65535>" VRF_CMD_STR, + SHOW_STR + IP_STR + "IP routing table\n" + "Show only routes with tag\n" + "Tag value\n" + VRF_CMD_HELP_STR) + DEFUN (show_ip_route_prefix_longer, show_ip_route_prefix_longer_cmd, "show ip route A.B.C.D/M longer-prefixes", @@ -2443,6 +3273,9 @@ static_config_ipv4 (struct vty *vty, safi_t safi, const char *cmd) vty_out (vty, " %s", "blackhole"); } + if (si->tag) + vty_out (vty, " tag %d", si->tag); + if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT) vty_out (vty, " %d", si->distance); @@ -2457,42 +3290,12 @@ static_config_ipv4 (struct vty *vty, safi_t safi, const char *cmd) return write; } -DEFUN (show_ip_protocol, - show_ip_protocol_cmd, - "show ip protocol", - SHOW_STR - IP_STR - "IP protocol filtering status\n") -{ - int i; - - vty_out(vty, "Protocol : route-map %s", VTY_NEWLINE); - vty_out(vty, "------------------------%s", VTY_NEWLINE); - for (i=0;i<ZEBRA_ROUTE_MAX;i++) - { - if (proto_rm[AFI_IP][i]) - vty_out (vty, "%-10s : %-10s%s", zebra_route_string(i), - proto_rm[AFI_IP][i], - VTY_NEWLINE); - else - vty_out (vty, "%-10s : none%s", zebra_route_string(i), VTY_NEWLINE); - } - if (proto_rm[AFI_IP][i]) - vty_out (vty, "%-10s : %-10s%s", "any", proto_rm[AFI_IP][i], - VTY_NEWLINE); - else - vty_out (vty, "%-10s : none%s", "any", VTY_NEWLINE); - - return CMD_SUCCESS; -} - -#ifdef HAVE_IPV6 /* General fucntion for IPv6 static route. */ static int static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str, const char *gate_str, const char *ifname, - const char *flag_str, const char *distance_str, - const char *vrf_id_str) + const char *flag_str, const char *tag_str, + const char *distance_str, const char *vrf_id_str) { int ret; u_char distance; @@ -2502,6 +3305,7 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str, u_char type = 0; vrf_id_t vrf_id = VRF_DEFAULT; u_char flag = 0; + u_short tag = 0; ret = str2prefix (dest_str, &p); if (ret <= 0) @@ -2536,6 +3340,14 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str, else distance = ZEBRA_STATIC_DISTANCE_DEFAULT; + /* tag */ + if (tag_str) + tag = atoi (tag_str); + + /* tag */ + if (tag_str) + tag = atoi(tag_str); + /* When gateway is valid IPv6 addrees, then gate is treated as nexthop address other case gate is treated as interface name. */ ret = inet_pton (AF_INET6, gate_str, &gate_addr); @@ -2571,9 +3383,9 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str, VTY_GET_INTEGER ("VRF ID", vrf_id, vrf_id_str); if (add_cmd) - static_add_ipv6 (&p, type, gate, ifname, flag, distance, vrf_id); + static_add_ipv6 (&p, type, gate, ifname, flag, tag, distance, vrf_id); else - static_delete_ipv6 (&p, type, gate, ifname, distance, vrf_id); + static_delete_ipv6 (&p, type, gate, ifname, tag, distance, vrf_id); return CMD_SUCCESS; } @@ -2588,7 +3400,36 @@ DEFUN (ipv6_route, "IPv6 gateway interface name\n") { return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, NULL, - NULL); + NULL, NULL); +} + +DEFUN (ipv6_route_tag, + ipv6_route_tag_cmd, + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535>", + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n") +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, argv[2], NULL, NULL); +} + +DEFUN (ipv6_route_tag_vrf, + ipv6_route_tag_vrf_cmd, + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, argv[2], NULL, argv[3]); } DEFUN (ipv6_route_flags, @@ -2603,7 +3444,40 @@ DEFUN (ipv6_route_flags, "Silently discard pkts when matched\n") { return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], NULL, - NULL); + NULL, NULL); +} + +DEFUN (ipv6_route_flags_tag, + ipv6_route_flags_tag_cmd, + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-65535>", + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n") +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3], NULL, NULL); +} + +DEFUN (ipv6_route_flags_tag_vrf, + ipv6_route_flags_tag_vrf_cmd, + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-65535>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3], NULL, argv[4]); } DEFUN (ipv6_route_ifname, @@ -2616,7 +3490,36 @@ DEFUN (ipv6_route_ifname, "IPv6 gateway interface name\n") { return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, NULL, - NULL); + NULL, NULL); +} + +DEFUN (ipv6_route_ifname_tag, + ipv6_route_ifname_tag_cmd, + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535>", + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n") +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3], NULL, NULL); +} + +DEFUN (ipv6_route_ifname_tag_vrf, + ipv6_route_ifname_tag_vrf_cmd, + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3], NULL, argv[4]); } DEFUN (ipv6_route_ifname_flags, @@ -2631,7 +3534,40 @@ DEFUN (ipv6_route_ifname_flags, "Silently discard pkts when matched\n") { return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL, - NULL); + NULL, NULL); +} + +DEFUN (ipv6_route_ifname_flags_tag, + ipv6_route_ifname_flags_tag_cmd, + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-65535>", + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n") +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4], NULL, NULL); +} + +DEFUN (ipv6_route_ifname_flags_tag_vrf, + ipv6_route_ifname_flags_tag_vrf_cmd, + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-65535>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4], NULL, argv[5]); } DEFUN (ipv6_route_pref, @@ -2644,10 +3580,41 @@ DEFUN (ipv6_route_pref, "IPv6 gateway interface name\n" "Distance value for this prefix\n") { - return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, argv[2], + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, NULL, argv[2], NULL); } +DEFUN (ipv6_route_pref_tag, + ipv6_route_pref_tag_cmd, + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535> <1-255>", + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n") +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, argv[2], argv[3], NULL); +} + +DEFUN (ipv6_route_pref_tag_vrf, + ipv6_route_pref_tag_vrf_cmd, + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535> <1-255>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, argv[2], argv[3], argv[4]); +} + DEFUN (ipv6_route_flags_pref, ipv6_route_flags_pref_cmd, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) <1-255>", @@ -2660,10 +3627,45 @@ DEFUN (ipv6_route_flags_pref, "Silently discard pkts when matched\n" "Distance value for this prefix\n") { - return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3], + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], NULL, argv[3], NULL); } +DEFUN (ipv6_route_flags_pref_tag, + ipv6_route_flags_pref_tag_cmd, + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>", + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n") +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3], argv[4], NULL); +} + +DEFUN (ipv6_route_flags_pref_tag_vrf, + ipv6_route_flags_pref_tag_vrf_cmd, + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3], argv[4], argv[5]); +} + DEFUN (ipv6_route_ifname_pref, ipv6_route_ifname_pref_cmd, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>", @@ -2674,10 +3676,41 @@ DEFUN (ipv6_route_ifname_pref, "IPv6 gateway interface name\n" "Distance value for this prefix\n") { - return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3], + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, NULL, argv[3], NULL); } +DEFUN (ipv6_route_ifname_pref_tag, + ipv6_route_ifname_pref_tag_cmd, + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535> <1-255>", + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n") +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3], argv[4], NULL); +} + +DEFUN (ipv6_route_ifname_pref_tag_vrf, + ipv6_route_ifname_pref_tag_vrf_cmd, + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535> <1-255>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3], argv[4], argv[5]); +} + DEFUN (ipv6_route_ifname_flags_pref, ipv6_route_ifname_flags_pref_cmd, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) <1-255>", @@ -2690,10 +3723,45 @@ DEFUN (ipv6_route_ifname_flags_pref, "Silently discard pkts when matched\n" "Distance value for this prefix\n") { - return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4], + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL, argv[4], NULL); } +DEFUN (ipv6_route_ifname_flags_pref_tag, + ipv6_route_ifname_flags_pref_tag_cmd, + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-65535> <1-255>", + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n") +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], NULL); +} + +DEFUN (ipv6_route_ifname_flags_pref_tag_vrf, + ipv6_route_ifname_flags_pref_tag_vrf_cmd, + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]); +} + DEFUN (no_ipv6_route, no_ipv6_route_cmd, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE)", @@ -2704,10 +3772,41 @@ DEFUN (no_ipv6_route, "IPv6 gateway address\n" "IPv6 gateway interface name\n") { - return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, NULL, + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, NULL, NULL, NULL); } +DEFUN (no_ipv6_route_tag, + no_ipv6_route_tag_cmd, + "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535>", + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n") +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, argv[2], NULL, NULL); +} + +DEFUN (no_ipv6_route_tag_vrf, + no_ipv6_route_tag_vrf_cmd, + "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535>" VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, argv[2], NULL, argv[3]); +} + ALIAS (no_ipv6_route, no_ipv6_route_flags_cmd, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole)", @@ -2720,6 +3819,20 @@ ALIAS (no_ipv6_route, "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") +ALIAS (no_ipv6_route_tag, + no_ipv6_route_flags_tag_cmd, + "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-65535>", + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n") + DEFUN (no_ipv6_route_ifname, no_ipv6_route_ifname_cmd, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE", @@ -2730,10 +3843,41 @@ DEFUN (no_ipv6_route_ifname, "IPv6 gateway address\n" "IPv6 gateway interface name\n") { - return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, NULL, + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, NULL, NULL, NULL); } +DEFUN (no_ipv6_route_ifname_tag, + no_ipv6_route_ifname_tag_cmd, + "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535>", + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n") +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3], NULL, NULL); +} + +DEFUN (no_ipv6_route_ifname_tag_vrf, + no_ipv6_route_ifname_tag_vrf_cmd, + "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535>" VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3], NULL, argv[4]); +} + ALIAS (no_ipv6_route_ifname, no_ipv6_route_ifname_flags_cmd, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole)", @@ -2746,6 +3890,20 @@ ALIAS (no_ipv6_route_ifname, "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") +ALIAS (no_ipv6_route_ifname_tag, + no_ipv6_route_ifname_flags_tag_cmd, + "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-65535>", + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n") + DEFUN (no_ipv6_route_pref, no_ipv6_route_pref_cmd, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) <1-255>", @@ -2757,10 +3915,43 @@ DEFUN (no_ipv6_route_pref, "IPv6 gateway interface name\n" "Distance value for this prefix\n") { - return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, argv[2], + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, NULL, argv[2], NULL); } +DEFUN (no_ipv6_route_pref_tag, + no_ipv6_route_pref_tag_cmd, + "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535> <1-255>", + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n") +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, argv[2], argv[3], NULL); +} + +DEFUN (no_ipv6_route_pref_tag_vrf, + no_ipv6_route_pref_tag_vrf_cmd, + "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535> <1-255>" VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, argv[2], argv[3], argv[4]); +} + DEFUN (no_ipv6_route_flags_pref, no_ipv6_route_flags_pref_cmd, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) <1-255>", @@ -2775,10 +3966,49 @@ DEFUN (no_ipv6_route_flags_pref, "Distance value for this prefix\n") { /* We do not care about argv[2] */ - return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3], + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2], NULL, argv[3], NULL); } +DEFUN (no_ipv6_route_flags_pref_tag, + no_ipv6_route_flags_pref_tag_cmd, + "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>", + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n") +{ + /* We do not care about argv[2] */ + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3], argv[4], NULL); +} + +DEFUN (no_ipv6_route_flags_pref_tag_vrf, + no_ipv6_route_flags_pref_tag_vrf_cmd, + "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" + VRF_CMD_HELP_STR) +{ + /* We do not care about argv[2] */ + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3], argv[4], argv[5]); +} + DEFUN (no_ipv6_route_ifname_pref, no_ipv6_route_ifname_pref_cmd, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>", @@ -2790,10 +4020,43 @@ DEFUN (no_ipv6_route_ifname_pref, "IPv6 gateway interface name\n" "Distance value for this prefix\n") { - return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3], + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, NULL, argv[3], NULL); } +DEFUN (no_ipv6_route_ifname_pref_tag, + no_ipv6_route_ifname_pref_tag_cmd, + "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535> <1-255>", + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n") +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3], argv[4], NULL); +} + +DEFUN (no_ipv6_route_ifname_pref_tag_vrf, + no_ipv6_route_ifname_pref_tag_vrf_cmd, + "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535> <1-255>" VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3], argv[4], argv[5]); +} + DEFUN (no_ipv6_route_ifname_flags_pref, no_ipv6_route_ifname_flags_pref_cmd, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) <1-255>", @@ -2807,10 +4070,47 @@ DEFUN (no_ipv6_route_ifname_flags_pref, "Silently discard pkts when matched\n" "Distance value for this prefix\n") { - return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4], + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3], NULL, argv[4], NULL); } +DEFUN (no_ipv6_route_ifname_flags_pref_tag, + no_ipv6_route_ifname_flags_pref_tag_cmd, + "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-65535> <1-255>", + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n") +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], NULL); +} + +DEFUN (no_ipv6_route_ifname_flags_pref_tag_vrf, + no_ipv6_route_ifname_flags_pref_tag_vrf_cmd, + "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]); +} + DEFUN (ipv6_route_vrf, ipv6_route_vrf_cmd, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) " VRF_CMD_STR, @@ -2821,7 +4121,7 @@ DEFUN (ipv6_route_vrf, "IPv6 gateway interface name\n" VRF_CMD_HELP_STR) { - return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, NULL, + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, NULL, NULL, argv[2]); } @@ -2837,7 +4137,7 @@ DEFUN (ipv6_route_flags_vrf, "Silently discard pkts when matched\n" VRF_CMD_HELP_STR) { - return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], NULL, + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], NULL, NULL, argv[3]); } @@ -2851,7 +4151,7 @@ DEFUN (ipv6_route_ifname_vrf, "IPv6 gateway interface name\n" VRF_CMD_HELP_STR) { - return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, NULL, + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, NULL, NULL, argv[3]); } @@ -2867,7 +4167,7 @@ DEFUN (ipv6_route_ifname_flags_vrf, "Silently discard pkts when matched\n" VRF_CMD_HELP_STR) { - return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL, + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL, NULL, argv[4]); } @@ -2882,7 +4182,7 @@ DEFUN (ipv6_route_pref_vrf, "Distance value for this prefix\n" VRF_CMD_HELP_STR) { - return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, argv[2], + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, NULL, argv[2], argv[3]); } @@ -2899,7 +4199,7 @@ DEFUN (ipv6_route_flags_pref_vrf, "Distance value for this prefix\n" VRF_CMD_HELP_STR) { - return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3], + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], NULL, argv[3], argv[4]); } @@ -2914,7 +4214,7 @@ DEFUN (ipv6_route_ifname_pref_vrf, "Distance value for this prefix\n" VRF_CMD_HELP_STR) { - return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3], + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, NULL, argv[3], argv[4]); } @@ -2931,7 +4231,7 @@ DEFUN (ipv6_route_ifname_flags_pref_vrf, "Distance value for this prefix\n" VRF_CMD_HELP_STR) { - return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4], + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL, argv[4], argv[5]); } @@ -2946,7 +4246,7 @@ DEFUN (no_ipv6_route_vrf, "IPv6 gateway interface name\n" VRF_CMD_HELP_STR) { - return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, NULL, + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, NULL, NULL, (argc > 3) ? argv[3] : argv[2]); } @@ -2974,7 +4274,7 @@ DEFUN (no_ipv6_route_ifname_vrf, "IPv6 gateway interface name\n" VRF_CMD_HELP_STR) { - return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, NULL, + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, NULL, NULL, (argc > 4) ? argv[4] : argv[3]); } @@ -3003,7 +4303,7 @@ DEFUN (no_ipv6_route_pref_vrf, "Distance value for this prefix\n" VRF_CMD_HELP_STR) { - return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, argv[2], + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, NULL, argv[2], argv[3]); } @@ -3022,7 +4322,7 @@ DEFUN (no_ipv6_route_flags_pref_vrf, VRF_CMD_HELP_STR) { /* We do not care about argv[2] */ - return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3], + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2], NULL, argv[3], argv[4]); } @@ -3038,7 +4338,7 @@ DEFUN (no_ipv6_route_ifname_pref_vrf, "Distance value for this prefix\n" VRF_CMD_HELP_STR) { - return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3], + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, NULL, argv[3], argv[4]); } @@ -3056,7 +4356,7 @@ DEFUN (no_ipv6_route_ifname_flags_pref_vrf, "Distance value for this prefix\n" VRF_CMD_HELP_STR) { - return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4], + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3], NULL, argv[4], argv[5]); } @@ -3102,6 +4402,59 @@ ALIAS (show_ipv6_route, "IPv6 routing table\n" VRF_CMD_HELP_STR) +DEFUN (show_ipv6_route_tag, + show_ipv6_route_tag_cmd, + "show ipv6 route tag <1-65535>", + SHOW_STR + IP_STR + "IPv6 routing table\n" + "Show only routes with tag\n" + "Tag value\n") +{ + struct route_table *table; + struct route_node *rn; + struct rib *rib; + int first = 1; + u_short tag = 0; + vrf_id_t vrf_id = VRF_DEFAULT; + + if (argv[0]) + tag = atoi(argv[0]); + + if (argc == 2) + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]); + + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); + if (! table) + return CMD_SUCCESS; + + /* Show all IPv6 routes with matching tag value. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + RNODE_FOREACH_RIB (rn, rib) + { + if (rib->tag != tag) + continue; + + if (first) + { + vty_out (vty, SHOW_ROUTE_V6_HEADER); + first = 0; + } + vty_show_ip_route (vty, rn, rib); + } + return CMD_SUCCESS; +} + +ALIAS (show_ipv6_route_tag, + show_ipv6_route_tag_vrf_cmd, + "show ipv6 route tag <1-65535>" VRF_CMD_STR, + SHOW_STR + IP_STR + "IPv6 routing table\n" + "Show only routes with tag\n" + "Tag value\n" + VRF_CMD_HELP_STR) + DEFUN (show_ipv6_route_prefix_longer, show_ipv6_route_prefix_longer_cmd, "show ipv6 route X:X::X:X/M longer-prefixes", @@ -3773,6 +5126,9 @@ static_config_ipv6 (struct vty *vty) if (CHECK_FLAG(si->flags, ZEBRA_FLAG_BLACKHOLE)) vty_out (vty, " %s", "blackhole"); + if (si->tag) + vty_out (vty, " tag %d", si->tag); + if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT) vty_out (vty, " %d", si->distance); @@ -3786,7 +5142,6 @@ static_config_ipv6 (struct vty *vty) } return write; } -#endif /* HAVE_IPV6 */ /* Static ip route configuration write function. */ static int @@ -3828,7 +5183,7 @@ static int config_write_vty(struct vty *vty) proto_rm[AFI_IP][ZEBRA_ROUTE_MAX], VTY_NEWLINE); return 1; -} +} /* table node for protocol filtering */ static struct cmd_node protocol_node = { PROTOCOL_NODE, "", 1 }; @@ -3850,35 +5205,82 @@ zebra_vty_init (void) install_element (CONFIG_NODE, &ip_multicast_mode_cmd); install_element (CONFIG_NODE, &no_ip_multicast_mode_cmd); install_element (CONFIG_NODE, &no_ip_multicast_mode_noarg_cmd); - install_element (CONFIG_NODE, &ip_protocol_cmd); - install_element (CONFIG_NODE, &no_ip_protocol_cmd); - install_element (VIEW_NODE, &show_ip_protocol_cmd); - install_element (ENABLE_NODE, &show_ip_protocol_cmd); + install_element (CONFIG_NODE, &ip_route_cmd); + install_element (CONFIG_NODE, &ip_route_tag_cmd); + install_element (CONFIG_NODE, &ip_route_tag_vrf_cmd); install_element (CONFIG_NODE, &ip_route_flags_cmd); + install_element (CONFIG_NODE, &ip_route_flags_tag_cmd); + install_element (CONFIG_NODE, &ip_route_flags_tag_vrf_cmd); install_element (CONFIG_NODE, &ip_route_flags2_cmd); + install_element (CONFIG_NODE, &ip_route_flags2_tag_cmd); + install_element (CONFIG_NODE, &ip_route_flags2_tag_vrf_cmd); install_element (CONFIG_NODE, &ip_route_mask_cmd); + install_element (CONFIG_NODE, &ip_route_mask_tag_cmd); + install_element (CONFIG_NODE, &ip_route_mask_tag_vrf_cmd); install_element (CONFIG_NODE, &ip_route_mask_flags_cmd); + install_element (CONFIG_NODE, &ip_route_mask_flags_tag_cmd); + install_element (CONFIG_NODE, &ip_route_mask_flags_tag_vrf_cmd); install_element (CONFIG_NODE, &ip_route_mask_flags2_cmd); + install_element (CONFIG_NODE, &ip_route_mask_flags2_tag_cmd); + install_element (CONFIG_NODE, &ip_route_mask_flags2_tag_vrf_cmd); install_element (CONFIG_NODE, &no_ip_route_cmd); + install_element (CONFIG_NODE, &no_ip_route_tag_cmd); + install_element (CONFIG_NODE, &no_ip_route_tag_vrf_cmd); install_element (CONFIG_NODE, &no_ip_route_flags_cmd); + install_element (CONFIG_NODE, &no_ip_route_flags_tag_cmd); install_element (CONFIG_NODE, &no_ip_route_flags2_cmd); + install_element (CONFIG_NODE, &no_ip_route_flags2_tag_cmd); + install_element (CONFIG_NODE, &no_ip_route_flags2_tag_vrf_cmd); install_element (CONFIG_NODE, &no_ip_route_mask_cmd); + install_element (CONFIG_NODE, &no_ip_route_mask_tag_cmd); install_element (CONFIG_NODE, &no_ip_route_mask_flags_cmd); + install_element (CONFIG_NODE, &no_ip_route_mask_flags_tag_cmd); install_element (CONFIG_NODE, &no_ip_route_mask_flags2_cmd); + install_element (CONFIG_NODE, &no_ip_route_mask_flags2_tag_cmd); + install_element (CONFIG_NODE, &no_ip_route_mask_flags2_tag_vrf_cmd); install_element (CONFIG_NODE, &ip_route_distance_cmd); + install_element (CONFIG_NODE, &ip_route_tag_distance_cmd); + install_element (CONFIG_NODE, &ip_route_tag_distance_vrf_cmd); install_element (CONFIG_NODE, &ip_route_flags_distance_cmd); + install_element (CONFIG_NODE, &ip_route_flags_tag_distance_cmd); + install_element (CONFIG_NODE, &ip_route_flags_tag_distance_vrf_cmd); install_element (CONFIG_NODE, &ip_route_flags_distance2_cmd); + install_element (CONFIG_NODE, &ip_route_flags_tag_distance2_cmd); + install_element (CONFIG_NODE, &ip_route_flags_tag_distance2_vrf_cmd); install_element (CONFIG_NODE, &ip_route_mask_distance_cmd); + install_element (CONFIG_NODE, &ip_route_mask_tag_distance_cmd); + install_element (CONFIG_NODE, &ip_route_mask_tag_distance_vrf_cmd); install_element (CONFIG_NODE, &ip_route_mask_flags_distance_cmd); + install_element (CONFIG_NODE, &ip_route_mask_flags_tag_distance_cmd); + install_element (CONFIG_NODE, &ip_route_mask_flags_tag_distance_vrf_cmd); install_element (CONFIG_NODE, &ip_route_mask_flags_distance2_cmd); + install_element (CONFIG_NODE, &ip_route_mask_flags_tag_distance2_cmd); + install_element (CONFIG_NODE, &ip_route_mask_flags_tag_distance2_vrf_cmd); install_element (CONFIG_NODE, &no_ip_route_distance_cmd); + install_element (CONFIG_NODE, &no_ip_route_tag_distance_cmd); + install_element (CONFIG_NODE, &no_ip_route_tag_distance_vrf_cmd); install_element (CONFIG_NODE, &no_ip_route_flags_distance_cmd); + install_element (CONFIG_NODE, &no_ip_route_flags_tag_distance_cmd); + install_element (CONFIG_NODE, &no_ip_route_flags_tag_distance_vrf_cmd); install_element (CONFIG_NODE, &no_ip_route_flags_distance2_cmd); + install_element (CONFIG_NODE, &no_ip_route_flags_tag_distance2_cmd); + install_element (CONFIG_NODE, &no_ip_route_flags_tag_distance2_vrf_cmd); + install_element (CONFIG_NODE, &no_ip_route_mask_distance_cmd); + install_element (CONFIG_NODE, &no_ip_route_mask_tag_distance_cmd); + install_element (CONFIG_NODE, &no_ip_route_mask_tag_distance_vrf_cmd); install_element (CONFIG_NODE, &no_ip_route_mask_flags_distance_cmd); + install_element (CONFIG_NODE, &no_ip_route_mask_flags_tag_distance_cmd); + install_element (CONFIG_NODE, &no_ip_route_mask_flags_tag_distance_vrf_cmd); install_element (CONFIG_NODE, &no_ip_route_mask_flags_distance2_cmd); + install_element (CONFIG_NODE, &no_ip_route_mask_flags_tag_distance2_cmd); + install_element (CONFIG_NODE, &no_ip_route_mask_flags_tag_distance2_vrf_cmd); install_element (VIEW_NODE, &show_ip_route_cmd); + install_element (VIEW_NODE, &show_ip_route_tag_cmd); + install_element (VIEW_NODE, &show_ip_route_tag_vrf_cmd); + install_element (VIEW_NODE, &show_ip_nht_cmd); + install_element (VIEW_NODE, &show_ipv6_nht_cmd); install_element (VIEW_NODE, &show_ip_route_addr_cmd); install_element (VIEW_NODE, &show_ip_route_prefix_cmd); install_element (VIEW_NODE, &show_ip_route_prefix_longer_cmd); @@ -3887,6 +5289,10 @@ zebra_vty_init (void) install_element (VIEW_NODE, &show_ip_route_summary_cmd); install_element (VIEW_NODE, &show_ip_route_summary_prefix_cmd); install_element (ENABLE_NODE, &show_ip_route_cmd); + install_element (ENABLE_NODE, &show_ip_route_tag_cmd); + install_element (ENABLE_NODE, &show_ip_route_tag_vrf_cmd); + install_element (ENABLE_NODE, &show_ip_nht_cmd); + install_element (ENABLE_NODE, &show_ipv6_nht_cmd); install_element (ENABLE_NODE, &show_ip_route_addr_cmd); install_element (ENABLE_NODE, &show_ip_route_prefix_cmd); install_element (ENABLE_NODE, &show_ip_route_prefix_longer_cmd); @@ -3991,7 +5397,39 @@ zebra_vty_init (void) install_element (CONFIG_NODE, &no_ipv6_route_flags_pref_cmd); install_element (CONFIG_NODE, &no_ipv6_route_ifname_pref_cmd); install_element (CONFIG_NODE, &no_ipv6_route_ifname_flags_pref_cmd); + install_element (CONFIG_NODE, &ipv6_route_tag_cmd); + install_element (CONFIG_NODE, &ipv6_route_tag_vrf_cmd); + install_element (CONFIG_NODE, &ipv6_route_flags_tag_cmd); + install_element (CONFIG_NODE, &ipv6_route_flags_tag_vrf_cmd); + install_element (CONFIG_NODE, &ipv6_route_ifname_tag_cmd); + install_element (CONFIG_NODE, &ipv6_route_ifname_tag_vrf_cmd); + install_element (CONFIG_NODE, &ipv6_route_ifname_flags_tag_cmd); + install_element (CONFIG_NODE, &ipv6_route_ifname_flags_tag_vrf_cmd); + install_element (CONFIG_NODE, &ipv6_route_pref_tag_cmd); + install_element (CONFIG_NODE, &ipv6_route_pref_tag_vrf_cmd); + install_element (CONFIG_NODE, &ipv6_route_flags_pref_tag_cmd); + install_element (CONFIG_NODE, &ipv6_route_flags_pref_tag_vrf_cmd); + install_element (CONFIG_NODE, &ipv6_route_ifname_pref_tag_cmd); + install_element (CONFIG_NODE, &ipv6_route_ifname_pref_tag_vrf_cmd); + install_element (CONFIG_NODE, &ipv6_route_ifname_flags_pref_tag_cmd); + install_element (CONFIG_NODE, &ipv6_route_ifname_flags_pref_tag_vrf_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_tag_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_tag_vrf_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_flags_tag_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_ifname_tag_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_ifname_tag_vrf_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_ifname_flags_tag_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_pref_tag_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_pref_tag_vrf_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_flags_pref_tag_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_flags_pref_tag_vrf_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_ifname_pref_tag_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_ifname_pref_tag_vrf_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_ifname_flags_pref_tag_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_ifname_flags_pref_tag_vrf_cmd); install_element (VIEW_NODE, &show_ipv6_route_cmd); + install_element (VIEW_NODE, &show_ipv6_route_tag_cmd); + install_element (VIEW_NODE, &show_ipv6_route_tag_vrf_cmd); install_element (VIEW_NODE, &show_ipv6_route_summary_cmd); install_element (VIEW_NODE, &show_ipv6_route_summary_prefix_cmd); install_element (VIEW_NODE, &show_ipv6_route_protocol_cmd); @@ -3999,6 +5437,8 @@ zebra_vty_init (void) install_element (VIEW_NODE, &show_ipv6_route_prefix_cmd); install_element (VIEW_NODE, &show_ipv6_route_prefix_longer_cmd); install_element (ENABLE_NODE, &show_ipv6_route_cmd); + install_element (ENABLE_NODE, &show_ipv6_route_tag_cmd); + install_element (ENABLE_NODE, &show_ipv6_route_tag_vrf_cmd); install_element (ENABLE_NODE, &show_ipv6_route_protocol_cmd); install_element (ENABLE_NODE, &show_ipv6_route_addr_cmd); install_element (ENABLE_NODE, &show_ipv6_route_prefix_cmd); diff --git a/zebra/zserv.c b/zebra/zserv.c index e624ef2f..0f8562e2 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -37,12 +37,14 @@ #include "network.h" #include "buffer.h" #include "vrf.h" +#include "nexthop.h" #include "zebra/zserv.h" #include "zebra/router-id.h" #include "zebra/redistribute.h" #include "zebra/debug.h" #include "zebra/ipforward.h" +#include "zebra/zebra_rnh.h" /* Event list of zebra. */ enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE }; @@ -99,14 +101,19 @@ zserv_flush_data(struct thread *thread) case BUFFER_EMPTY: break; } + + client->last_write_time = quagga_time(NULL); return 0; } -static int +int zebra_server_send_message(struct zserv *client) { if (client->t_suicide) return -1; + + stream_set_getp(client->obuf, 0); + client->last_write_cmd = stream_getw_from(client->obuf, 4); switch (buffer_write(client->wb, client->sock, STREAM_DATA(client->obuf), stream_get_endp(client->obuf))) { @@ -128,10 +135,12 @@ zebra_server_send_message(struct zserv *client) zserv_flush_data, client, client->sock); break; } + + client->last_write_time = quagga_time(NULL); return 0; } -static void +void zserv_create_header (struct stream *s, uint16_t cmd, vrf_id_t vrf_id) { /* length placeholder, caller can update */ @@ -189,6 +198,7 @@ zsend_interface_add (struct zserv *client, struct interface *ifp) zserv_create_header (s, ZEBRA_INTERFACE_ADD, ifp->vrf_id); zserv_encode_interface (s, ifp); + client->ifadd_cnt++; return zebra_server_send_message(client); } @@ -208,6 +218,7 @@ zsend_interface_delete (struct zserv *client, struct interface *ifp) zserv_create_header (s, ZEBRA_INTERFACE_DELETE, ifp->vrf_id); zserv_encode_interface (s, ifp); + client->ifdel_cnt++; return zebra_server_send_message (client); } @@ -293,9 +304,147 @@ zsend_interface_address (int cmd, struct zserv *client, /* Write packet size. */ stream_putw_at (s, 0, stream_get_endp (s)); + client->connected_rt_add_cnt++; + return zebra_server_send_message(client); +} + +static int +zsend_interface_nbr_address (int cmd, struct zserv *client, + struct interface *ifp, struct nbr_connected *ifc) +{ + int blen; + struct stream *s; + struct prefix *p; + + /* Check this client need interface information. */ + if (! client->ifinfo) + return 0; + + s = client->obuf; + stream_reset (s); + + zserv_create_header (s, cmd, ifp->vrf_id); + stream_putl (s, ifp->ifindex); + + /* Prefix information. */ + p = ifc->address; + stream_putc (s, p->family); + blen = prefix_blen (p); + stream_put (s, &p->u.prefix, blen); + + /* + * XXX gnu version does not send prefixlen for ZEBRA_INTERFACE_ADDRESS_DELETE + * but zebra_interface_address_delete_read() in the gnu version + * expects to find it + */ + stream_putc (s, p->prefixlen); + + /* Write packet size. */ + stream_putw_at (s, 0, stream_get_endp (s)); + return zebra_server_send_message(client); } +/* Interface address addition. */ +static void +zebra_interface_nbr_address_add_update (struct interface *ifp, + struct nbr_connected *ifc) +{ + struct listnode *node, *nnode; + struct zserv *client; + struct prefix *p; + + if (IS_ZEBRA_DEBUG_EVENT) + { + char buf[INET6_ADDRSTRLEN]; + + p = ifc->address; + zlog_debug ("MESSAGE: ZEBRA_INTERFACE_NBR_ADDRESS_ADD %s/%d on %s", + inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN), + p->prefixlen, ifc->ifp->name); + } + + for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) + if (client->ifinfo) + zsend_interface_nbr_address (ZEBRA_INTERFACE_NBR_ADDRESS_ADD, client, ifp, ifc); +} + +/* Interface address deletion. */ +static void +zebra_interface_nbr_address_delete_update (struct interface *ifp, + struct nbr_connected *ifc) +{ + struct listnode *node, *nnode; + struct zserv *client; + struct prefix *p; + + if (IS_ZEBRA_DEBUG_EVENT) + { + char buf[INET6_ADDRSTRLEN]; + + p = ifc->address; + zlog_debug ("MESSAGE: ZEBRA_INTERFACE_NBR_ADDRESS_DELETE %s/%d on %s", + inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN), + p->prefixlen, ifc->ifp->name); + } + + for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) + if (client->ifinfo) + zsend_interface_nbr_address (ZEBRA_INTERFACE_NBR_ADDRESS_DELETE, client, ifp, ifc); +} + +/* Add new nbr connected IPv6 address if none exists already, or replace the + existing one if an ifc entry is found on the interface. */ +void +nbr_connected_replacement_add_ipv6 (struct interface *ifp, struct in6_addr *address, + u_char prefixlen) +{ + struct nbr_connected *ifc; + struct prefix p; + + p.family = AF_INET6; + IPV6_ADDR_COPY (&p.u.prefix, address); + p.prefixlen = prefixlen; + + if (nbr_connected_check(ifp, &p)) + return; + + if (!(ifc = listnode_head(ifp->nbr_connected))) + { + /* new addition */ + ifc = nbr_connected_new (); + ifc->address = prefix_new(); + ifc->ifp = ifp; + listnode_add (ifp->nbr_connected, ifc); + } + + prefix_copy(ifc->address, &p); + + zebra_interface_nbr_address_add_update (ifp, ifc); +} + +void +nbr_connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address, + u_char prefixlen) +{ + struct nbr_connected *ifc; + struct prefix p; + + p.family = AF_INET6; + IPV6_ADDR_COPY (&p.u.prefix, address); + p.prefixlen = prefixlen; + + ifc = nbr_connected_check(ifp, &p); + if (!ifc) + return; + + listnode_delete (ifp->nbr_connected, ifc); + + zebra_interface_nbr_address_delete_update (ifp, ifc); + + nbr_connected_free (ifc); +} + /* * The cmd passed to zsend_interface_update may be ZEBRA_INTERFACE_UP or * ZEBRA_INTERFACE_DOWN. @@ -321,6 +470,11 @@ zsend_interface_update (int cmd, struct zserv *client, struct interface *ifp) zserv_create_header (s, cmd, ifp->vrf_id); zserv_encode_interface (s, ifp); + if (cmd == ZEBRA_INTERFACE_UP) + client->ifup_cnt++; + else + client->ifdown_cnt++; + return zebra_server_send_message(client); } @@ -453,6 +607,12 @@ zsend_route_multipath (int cmd, struct zserv *client, struct prefix *p, stream_putl (s, rib->metric); SET_FLAG (zapi_flags, ZAPI_MESSAGE_MTU); stream_putl (s, rib->mtu); + /* tag */ + if (rib->tag) + { + SET_FLAG(zapi_flags, ZAPI_MESSAGE_TAG); + stream_putw(s, rib->tag); + } } /* write real message flags value */ @@ -532,7 +692,7 @@ zsend_ipv6_nexthop_lookup (struct zserv *client, struct in6_addr *addr, } stream_putw_at (s, 0, stream_get_endp (s)); - + return zebra_server_send_message(client); } #endif /* HAVE_IPV6 */ @@ -548,7 +708,7 @@ zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr, struct nexthop *nexthop; /* Lookup nexthop - eBGP excluded */ - rib = rib_match_ipv4_safi (addr, SAFI_UNICAST, 1, NULL, vrf_id); + rib = rib_match_ipv4_safi (addr, SAFI_UNICAST, NULL, vrf_id); /* Get output stream. */ s = client->obuf; @@ -677,6 +837,75 @@ zsend_ipv4_nexthop_lookup_mrib (struct zserv *client, struct in_addr addr, return zebra_server_send_message(client); } +/* Nexthop register */ +static int +zserv_nexthop_register (struct zserv *client, int sock, u_short length, vrf_id_t vrf_id) +{ + struct rnh *rnh; + struct stream *s; + struct prefix p; + u_short l = 0; + u_char connected; + + if (IS_ZEBRA_DEBUG_NHT) + zlog_debug("nexthop_register msg from client %s: length=%d\n", + zebra_route_string(client->proto), length); + + s = client->ibuf; + + while (l < length) + { + connected = stream_getc(s); + p.family = stream_getw(s); + p.prefixlen = stream_getc(s); + l += 4; + stream_get(&p.u.prefix, s, PSIZE(p.prefixlen)); + l += PSIZE(p.prefixlen); + rnh = zebra_add_rnh(&p, 0); + if (connected) + SET_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED); + + client->nh_reg_time = quagga_time(NULL); + zebra_add_rnh_client(rnh, client, vrf_id); + } + zebra_evaluate_rnh_table(0, AF_INET, 0); + zebra_evaluate_rnh_table(0, AF_INET6, 0); + return 0; +} + +/* Nexthop register */ +static int +zserv_nexthop_unregister (struct zserv *client, int sock, u_short length) +{ + struct rnh *rnh; + struct stream *s; + struct prefix p; + u_short l = 0; + + if (IS_ZEBRA_DEBUG_NHT) + zlog_debug("nexthop_unregister msg from client %s: length=%d\n", + zebra_route_string(client->proto), length); + + s = client->ibuf; + + while (l < length) + { + (void)stream_getc(s); + p.family = stream_getw(s); + p.prefixlen = stream_getc(s); + l += 4; + stream_get(&p.u.prefix, s, PSIZE(p.prefixlen)); + l += PSIZE(p.prefixlen); + rnh = zebra_lookup_rnh(&p, 0); + if (rnh) + { + client->nh_dereg_time = quagga_time(NULL); + zebra_remove_rnh_client(rnh, client); + } + } + return 0; +} + static int zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p, vrf_id_t vrf_id) @@ -736,7 +965,7 @@ zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p, } stream_putw_at (s, 0, stream_get_endp (s)); - + return zebra_server_send_message(client); } @@ -779,6 +1008,7 @@ zread_interface_add (struct zserv *client, u_short length, vrf_id_t vrf_id) struct listnode *cnode, *cnnode; struct interface *ifp; struct connected *c; + struct nbr_connected *nc; /* Interface information is needed. */ vrf_bitmap_set (client->ifinfo, vrf_id); @@ -799,6 +1029,13 @@ zread_interface_add (struct zserv *client, u_short length, vrf_id_t vrf_id) ifp, c) < 0)) return -1; } + for (ALL_LIST_ELEMENTS (ifp->nbr_connected, cnode, cnnode, nc)) + { + if (zsend_interface_nbr_address (ZEBRA_INTERFACE_NBR_ADDRESS_ADD, client, + ifp, nc) < 0) + return -1; + } + } return 0; } @@ -830,7 +1067,7 @@ zread_ipv4_add (struct zserv *client, u_short length, vrf_id_t vrf_id) ifindex_t ifindex; u_char ifname_len; safi_t safi; - + int ret; /* Get input stream. */ s = client->ibuf; @@ -867,7 +1104,7 @@ zread_ipv4_add (struct zserv *client, u_short length, vrf_id_t vrf_id) { case ZEBRA_NEXTHOP_IFINDEX: ifindex = stream_getl (s); - nexthop_ifindex_add (rib, ifindex); + rib_nexthop_ifindex_add (rib, ifindex); break; case ZEBRA_NEXTHOP_IFNAME: ifname_len = stream_getc (s); @@ -875,18 +1112,18 @@ zread_ipv4_add (struct zserv *client, u_short length, vrf_id_t vrf_id) break; case ZEBRA_NEXTHOP_IPV4: nexthop.s_addr = stream_get_ipv4 (s); - nexthop_ipv4_add (rib, &nexthop, NULL); + rib_nexthop_ipv4_add (rib, &nexthop, NULL); break; case ZEBRA_NEXTHOP_IPV4_IFINDEX: nexthop.s_addr = stream_get_ipv4 (s); ifindex = stream_getl (s); - nexthop_ipv4_ifindex_add (rib, &nexthop, NULL, ifindex); + rib_nexthop_ipv4_ifindex_add (rib, &nexthop, NULL, ifindex); break; case ZEBRA_NEXTHOP_IPV6: stream_forward_getp (s, IPV6_MAX_BYTELEN); break; case ZEBRA_NEXTHOP_BLACKHOLE: - nexthop_blackhole_add (rib); + rib_nexthop_blackhole_add (rib); break; } } @@ -902,10 +1139,19 @@ zread_ipv4_add (struct zserv *client, u_short length, vrf_id_t vrf_id) if (CHECK_FLAG (message, ZAPI_MESSAGE_MTU)) rib->mtu = stream_getl (s); + /* Tag */ + if (CHECK_FLAG (message, ZAPI_MESSAGE_TAG)) + rib->tag = stream_getw (s); /* Table */ rib->table=zebrad.rtm_table_default; - rib_add_ipv4_multipath (&p, rib, safi); + ret = rib_add_ipv4_multipath (&p, rib, safi); + + /* Stats */ + if (ret > 0) + client->v4_route_add_cnt++; + else if (ret < 0) + client->v4_route_upd8_cnt++; return 0; } @@ -986,8 +1232,15 @@ zread_ipv4_delete (struct zserv *client, u_short length, vrf_id_t vrf_id) else api.metric = 0; + /* tag */ + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG)) + api.tag = stream_getw (s); + else + api.tag = 0; + rib_delete_ipv4 (api.type, api.flags, &p, nexthop_p, ifindex, vrf_id, api.safi); + client->v4_route_del_cnt++; return 0; } @@ -1040,34 +1293,51 @@ zread_ipv6_add (struct zserv *client, u_short length, vrf_id_t vrf_id) { int i; struct stream *s; - struct zapi_ipv6 api; struct in6_addr nexthop; - unsigned long ifindex; + struct rib *rib; + u_char message; + u_char gateway_num; + u_char nexthop_type; struct prefix_ipv6 p; - + safi_t safi; + static struct in6_addr nexthops[MULTIPATH_NUM]; + static unsigned int ifindices[MULTIPATH_NUM]; + int ret; + + /* Get input stream. */ s = client->ibuf; - ifindex = 0; + memset (&nexthop, 0, sizeof (struct in6_addr)); + /* Allocate new rib. */ + rib = XCALLOC (MTYPE_RIB, sizeof (struct rib)); + /* Type, flags, message. */ - api.type = stream_getc (s); - api.flags = stream_getc (s); - api.message = stream_getc (s); - api.safi = stream_getw (s); + rib->type = stream_getc (s); + rib->flags = stream_getc (s); + message = stream_getc (s); + safi = stream_getw (s); + rib->uptime = time (NULL); - /* IPv4 prefix. */ + /* IPv6 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv6)); p.family = AF_INET6; p.prefixlen = stream_getc (s); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); - /* Nexthop, ifindex, distance, metric. */ - if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) + /* We need to give nh-addr, nh-ifindex with the same next-hop object + * to the rib to ensure that IPv6 multipathing works; need to coalesce + * these. Clients should send the same number of paired set of + * next-hop-addr/next-hop-ifindices. */ + if (CHECK_FLAG (message, ZAPI_MESSAGE_NEXTHOP)) { - u_char nexthop_type; + int nh_count = 0; + int if_count = 0; + int max_nh_if = 0; + unsigned int ifindex; - api.nexthop_num = stream_getc (s); - for (i = 0; i < api.nexthop_num; i++) + gateway_num = stream_getc (s); + for (i = 0; i < gateway_num; i++) { nexthop_type = stream_getc (s); @@ -1075,37 +1345,64 @@ zread_ipv6_add (struct zserv *client, u_short length, vrf_id_t vrf_id) { case ZEBRA_NEXTHOP_IPV6: stream_get (&nexthop, s, 16); + if (nh_count < MULTIPATH_NUM) { + nexthops[nh_count++] = nexthop; + } break; case ZEBRA_NEXTHOP_IFINDEX: ifindex = stream_getl (s); + if (if_count < MULTIPATH_NUM) { + ifindices[if_count++] = ifindex; + } break; + case ZEBRA_NEXTHOP_BLACKHOLE: + rib_nexthop_blackhole_add (rib); + break; + } + } + + max_nh_if = (nh_count > if_count) ? nh_count : if_count; + for (i = 0; i < max_nh_if; i++) + { + if ((i < nh_count) && !IN6_IS_ADDR_UNSPECIFIED (&nexthops[i])) + { + if ((i < if_count) && ifindices[i]) + rib_nexthop_ipv6_ifindex_add (rib, &nexthops[i], ifindices[i]); + else + rib_nexthop_ipv6_add (rib, &nexthops[i]); + } + else + { + if ((i < if_count) && ifindices[i]) + rib_nexthop_ifindex_add (rib, ifindices[i]); } } } - if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) - api.distance = stream_getc (s); - else - api.distance = 0; + /* Distance. */ + if (CHECK_FLAG (message, ZAPI_MESSAGE_DISTANCE)) + rib->distance = stream_getc (s); - if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) - api.metric = stream_getl (s); - else - api.metric = 0; + /* Metric. */ + if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC)) + rib->metric = stream_getl (s); + + if (CHECK_FLAG (message, ZAPI_MESSAGE_MTU)) + rib->mtu = stream_getl (s); + + /* Tag */ + if (CHECK_FLAG (message, ZAPI_MESSAGE_TAG)) + rib->tag = stream_getw (s); + + /* Table */ + rib->table=zebrad.rtm_table_default; + ret = rib_add_ipv6_multipath (&p, rib, safi); + /* Stats */ + if (ret > 0) + client->v6_route_add_cnt++; + else if (ret < 0) + client->v6_route_upd8_cnt++; - if (CHECK_FLAG (api.message, ZAPI_MESSAGE_MTU)) - api.mtu = stream_getl (s); - else - api.mtu = 0; - - if (IN6_IS_ADDR_UNSPECIFIED (&nexthop)) - rib_add_ipv6 (api.type, api.flags, &p, NULL, ifindex, - vrf_id, zebrad.rtm_table_default, api.metric, - api.mtu, api.distance, api.safi); - else - rib_add_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, - vrf_id, zebrad.rtm_table_default, api.metric, - api.mtu, api.distance, api.safi); return 0; } @@ -1158,21 +1455,32 @@ zread_ipv6_delete (struct zserv *client, u_short length, vrf_id_t vrf_id) } } + /* Distance. */ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) api.distance = stream_getc (s); else api.distance = 0; + + /* Metric. */ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) api.metric = stream_getl (s); else api.metric = 0; + /* tag */ + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG)) + api.tag = stream_getw (s); + else + api.tag = 0; + if (IN6_IS_ADDR_UNSPECIFIED (&nexthop)) rib_delete_ipv6 (api.type, api.flags, &p, NULL, ifindex, vrf_id, api.safi); else rib_delete_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, vrf_id, api.safi); + + client->v6_route_del_cnt++; return 0; } @@ -1236,6 +1544,7 @@ zread_hello (struct zserv *client) client->sock); route_type_oaths[proto] = client->sock; + client->proto = proto; } } @@ -1276,6 +1585,9 @@ zebra_score_rib (int client_sock) static void zebra_client_close (struct zserv *client) { + zebra_cleanup_rnh_client(0, AF_INET, client); + zebra_cleanup_rnh_client(0, AF_INET6, client); + /* Close file descriptor. */ if (client->sock) { @@ -1329,6 +1641,7 @@ zebra_client_create (int sock) client->redist_default = vrf_bitmap_init (); client->ifinfo = vrf_bitmap_init (); client->ridinfo = vrf_bitmap_init (); + client->connect_time = quagga_time(NULL); /* Add this client to linked list. */ listnode_add (zebrad.client_list, client); @@ -1444,6 +1757,9 @@ zebra_client_read (struct thread *thread) zlog_debug ("zebra message received [%s] %d in VRF %u", zserv_command_string (command), length, vrf_id); + client->last_read_time = quagga_time(NULL); + client->last_read_cmd = command; + switch (command) { case ZEBRA_ROUTER_ID_ADD: @@ -1503,6 +1819,11 @@ zebra_client_read (struct thread *thread) break; case ZEBRA_VRF_UNREGISTER: zread_vrf_unregister (client, length, vrf_id); + case ZEBRA_NEXTHOP_REGISTER: + zserv_nexthop_register(client, sock, length, vrf_id); + break; + case ZEBRA_NEXTHOP_UNREGISTER: + zserv_nexthop_unregister(client, sock, length); break; default: zlog_info ("Zebra received unknown command %d", command); @@ -1701,6 +2022,127 @@ zebra_event (enum event event, int sock, struct zserv *client) } } +#define ZEBRA_TIME_BUF 32 +static char * +zserv_time_buf(time_t *time1, char *buf, int buflen) +{ + struct tm *tm; + time_t now; + + assert (buf != NULL); + assert (buflen >= ZEBRA_TIME_BUF); + assert (time1 != NULL); + + if (!*time1) + { + snprintf(buf, buflen, "never "); + return (buf); + } + + now = quagga_time(NULL); + now -= *time1; + tm = gmtime(&now); + + /* Making formatted timer strings. */ +#define ONE_DAY_SECOND 60*60*24 +#define ONE_WEEK_SECOND 60*60*24*7 + + if (now < ONE_DAY_SECOND) + snprintf (buf, buflen, "%02d:%02d:%02d", + tm->tm_hour, tm->tm_min, tm->tm_sec); + else if (now < ONE_WEEK_SECOND) + snprintf (buf, buflen, "%dd%02dh%02dm", + tm->tm_yday, tm->tm_hour, tm->tm_min); + else + snprintf (buf, buflen, "%02dw%dd%02dh", + tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); + return buf; +} + +static void +zebra_show_client_detail (struct vty *vty, struct zserv *client) +{ + char cbuf[ZEBRA_TIME_BUF], rbuf[ZEBRA_TIME_BUF]; + char wbuf[ZEBRA_TIME_BUF], nhbuf[ZEBRA_TIME_BUF], mbuf[ZEBRA_TIME_BUF]; + + vty_out (vty, "Client: %s %s", + zebra_route_string(client->proto), VTY_NEWLINE); + vty_out (vty, "------------------------ %s", VTY_NEWLINE); + vty_out (vty, "FD: %d %s", client->sock, VTY_NEWLINE); + vty_out (vty, "Route Table ID: %d %s", client->rtm_table, VTY_NEWLINE); + + vty_out (vty, "Connect Time: %s %s", + zserv_time_buf(&client->connect_time, cbuf, ZEBRA_TIME_BUF), + VTY_NEWLINE); + if (client->nh_reg_time) + { + vty_out (vty, "Nexthop Registry Time: %s %s", + zserv_time_buf(&client->nh_reg_time, nhbuf, ZEBRA_TIME_BUF), + VTY_NEWLINE); + if (client->nh_last_upd_time) + vty_out (vty, "Nexthop Last Update Time: %s %s", + zserv_time_buf(&client->nh_last_upd_time, mbuf, ZEBRA_TIME_BUF), + VTY_NEWLINE); + else + vty_out (vty, "No Nexthop Update sent%s", VTY_NEWLINE); + } + else + vty_out (vty, "Not registered for Nexthop Updates%s", VTY_NEWLINE); + + vty_out (vty, "Last Msg Rx Time: %s %s", + zserv_time_buf(&client->last_read_time, rbuf, ZEBRA_TIME_BUF), + VTY_NEWLINE); + vty_out (vty, "Last Msg Tx Time: %s %s", + zserv_time_buf(&client->last_write_time, wbuf, ZEBRA_TIME_BUF), + VTY_NEWLINE); + if (client->last_read_time) + vty_out (vty, "Last Rcvd Cmd: %s %s", + zserv_command_string(client->last_read_cmd), VTY_NEWLINE); + if (client->last_write_time) + vty_out (vty, "Last Sent Cmd: %s %s", + zserv_command_string(client->last_write_cmd), VTY_NEWLINE); + vty_out (vty, "%s", VTY_NEWLINE); + + vty_out (vty, "Type Add Update Del %s", VTY_NEWLINE); + vty_out (vty, "================================================== %s", VTY_NEWLINE); + vty_out (vty, "IPv4 %-12d%-12d%-12d%s", client->v4_route_add_cnt, + client->v4_route_upd8_cnt, client->v4_route_del_cnt, VTY_NEWLINE); + vty_out (vty, "IPv6 %-12d%-12d%-12d%s", client->v6_route_add_cnt, + client->v6_route_upd8_cnt, client->v6_route_del_cnt, VTY_NEWLINE); + vty_out (vty, "Redist:v4 %-12d%-12d%-12d%s", client->redist_v4_add_cnt, 0, + client->redist_v4_del_cnt, VTY_NEWLINE); + vty_out (vty, "Redist:v6 %-12d%-12d%-12d%s", client->redist_v6_add_cnt, 0, + client->redist_v6_del_cnt, VTY_NEWLINE); + vty_out (vty, "Connected %-12d%-12d%-12d%s", client->ifadd_cnt, 0, + client->ifdel_cnt, VTY_NEWLINE); + vty_out (vty, "Interface Up Notifications: %d%s", client->ifup_cnt, + VTY_NEWLINE); + vty_out (vty, "Interface Down Notifications: %d%s", client->ifdown_cnt, + VTY_NEWLINE); + + vty_out (vty, "%s", VTY_NEWLINE); + return; +} + +static void +zebra_show_client_brief (struct vty *vty, struct zserv *client) +{ + char cbuf[ZEBRA_TIME_BUF], rbuf[ZEBRA_TIME_BUF]; + char wbuf[ZEBRA_TIME_BUF]; + + vty_out (vty, "%-8s%12s %12s%12s%8d/%-8d%8d/%-8d%s", + zebra_route_string(client->proto), + zserv_time_buf(&client->connect_time, cbuf, ZEBRA_TIME_BUF), + zserv_time_buf(&client->last_read_time, rbuf, ZEBRA_TIME_BUF), + zserv_time_buf(&client->last_write_time, wbuf, ZEBRA_TIME_BUF), + client->v4_route_add_cnt+client->v4_route_upd8_cnt, + client->v4_route_del_cnt, + client->v6_route_add_cnt+client->v6_route_upd8_cnt, + client->v6_route_del_cnt, VTY_NEWLINE); + +} + + /* Display default rtm_table for all clients. */ DEFUN (show_table, show_table_cmd, @@ -1778,8 +2220,31 @@ DEFUN (show_zebra_client, struct zserv *client; for (ALL_LIST_ELEMENTS_RO (zebrad.client_list, node, client)) - vty_out (vty, "Client fd %d%s", client->sock, VTY_NEWLINE); - + zebra_show_client_detail(vty, client); + + return CMD_SUCCESS; +} + +/* This command is for debugging purpose. */ +DEFUN (show_zebra_client_summary, + show_zebra_client_summary_cmd, + "show zebra client summary", + SHOW_STR + "Zebra information brief" + "Client information brief") +{ + struct listnode *node; + struct zserv *client; + + vty_out (vty, "Name Connect Time Last Read Last Write IPv4 Routes IPv6 Routes %s", + VTY_NEWLINE); + vty_out (vty,"--------------------------------------------------------------------------------%s", + VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO (zebrad.client_list, node, client)) + zebra_show_client_brief(vty, client); + + vty_out (vty, "Routes column shows (added+updated)/deleted%s", VTY_NEWLINE); return CMD_SUCCESS; } @@ -1938,6 +2403,7 @@ zebra_init (void) install_element (CONFIG_NODE, &ip_forwarding_cmd); install_element (CONFIG_NODE, &no_ip_forwarding_cmd); install_element (ENABLE_NODE, &show_zebra_client_cmd); + install_element (ENABLE_NODE, &show_zebra_client_summary_cmd); #ifdef HAVE_NETLINK install_element (VIEW_NODE, &show_table_cmd); diff --git a/zebra/zserv.h b/zebra/zserv.h index fc01f961..3f8af08e 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -26,6 +26,7 @@ #include "if.h" #include "workqueue.h" #include "vrf.h" +#include "routemap.h" /* Default port information. */ #define ZEBRA_VTY_PORT 2601 @@ -33,6 +34,8 @@ /* Default configuration filename. */ #define DEFAULT_CONFIG_FILE "zebra.conf" +#define ZEBRA_RMAP_DEFAULT_UPDATE_TIMER 5 /* disabled by default */ + /* Client structure. */ struct zserv { @@ -67,6 +70,37 @@ struct zserv /* Router-id information. */ vrf_bitmap_t ridinfo; + + /* client's protocol */ + u_char proto; + + /* Statistics */ + u_int32_t redist_v4_add_cnt; + u_int32_t redist_v4_del_cnt; + u_int32_t redist_v6_add_cnt; + u_int32_t redist_v6_del_cnt; + u_int32_t v4_route_add_cnt; + u_int32_t v4_route_upd8_cnt; + u_int32_t v4_route_del_cnt; + u_int32_t v6_route_add_cnt; + u_int32_t v6_route_del_cnt; + u_int32_t v6_route_upd8_cnt; + u_int32_t connected_rt_add_cnt; + u_int32_t connected_rt_del_cnt; + u_int32_t ifup_cnt; + u_int32_t ifdown_cnt; + u_int32_t ifadd_cnt; + u_int32_t ifdel_cnt; + + time_t connect_time; + time_t last_read_time; + time_t last_write_time; + time_t nh_reg_time; + time_t nh_dereg_time; + time_t nh_last_upd_time; + + int last_read_cmd; + int last_write_cmd; }; /* Zebra instance */ @@ -105,6 +139,9 @@ extern int zsend_interface_add (struct zserv *, struct interface *); extern int zsend_interface_delete (struct zserv *, struct interface *); extern int zsend_interface_address (int, struct zserv *, struct interface *, struct connected *); +extern void nbr_connected_replacement_add_ipv6 (struct interface *, + struct in6_addr *, u_char); +extern void nbr_connected_delete_ipv6 (struct interface *, struct in6_addr *, u_char); extern int zsend_interface_update (int, struct zserv *, struct interface *); extern int zsend_route_multipath (int, struct zserv *, struct prefix *, struct rib *); @@ -113,4 +150,18 @@ extern int zsend_router_id_update (struct zserv *, struct prefix *, extern pid_t pid; +extern void zserv_create_header(struct stream *s, uint16_t cmd, vrf_id_t); +extern int zebra_server_send_message(struct zserv *client); + +extern void zebra_route_map_write_delay_timer(struct vty *); +extern route_map_result_t zebra_route_map_check (int family, int rib_type, + struct prefix *p, + struct nexthop *nexthop, + vrf_id_t vrf_id); +extern route_map_result_t zebra_nht_route_map_check (int family, + int client_proto, + struct prefix *p, + struct rib *, + struct nexthop *nexthop); + #endif /* _ZEBRA_ZEBRA_H */ |