summaryrefslogtreecommitdiffstats
path: root/zebra
diff options
context:
space:
mode:
Diffstat (limited to 'zebra')
-rw-r--r--zebra/Makefile.am8
-rw-r--r--zebra/connected.c33
-rw-r--r--zebra/connected.h1
-rw-r--r--zebra/debug.c30
-rw-r--r--zebra/debug.h3
-rw-r--r--zebra/if_ioctl.c1
-rw-r--r--zebra/if_ioctl_solaris.c1
-rw-r--r--zebra/if_netlink.c1
-rw-r--r--zebra/if_sysctl.c1
-rw-r--r--zebra/interface.c35
-rw-r--r--zebra/ioctl.c1
-rw-r--r--zebra/ioctl_solaris.c1
-rw-r--r--zebra/kernel_null.c1
-rw-r--r--zebra/kernel_socket.c1
-rw-r--r--zebra/redistribute.c50
-rw-r--r--zebra/redistribute_null.c1
-rw-r--r--zebra/rib.h122
-rw-r--r--zebra/rt_netlink.c109
-rw-r--r--zebra/rtadv.c83
-rw-r--r--zebra/rtread_getmsg.c1
-rw-r--r--zebra/rtread_netlink.c1
-rw-r--r--zebra/rtread_sysctl.c1
-rw-r--r--zebra/zebra_fpm_netlink.c1
-rw-r--r--zebra/zebra_rib.c669
-rw-r--r--zebra/zebra_rnh.c761
-rw-r--r--zebra/zebra_rnh.h54
-rw-r--r--zebra/zebra_rnh_null.c21
-rw-r--r--zebra/zebra_routemap.c953
-rw-r--r--zebra/zebra_vty.c1884
-rw-r--r--zebra/zserv.c562
-rw-r--r--zebra/zserv.h51
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 */