summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Stevens <dlstevens@us.ibm.com>2007-04-09 18:36:39 -0500
committerJeffrey C. Ollie <jeff@ocjtech.us>2007-04-09 18:36:39 -0500
commit2a77721a1fe3e256a11d0d8c6a152cb114ba6baf (patch)
treeefb6d8311d76b82fc1f52661daca94bf5dbc7aea
parentc15deb1b7428a2baedfb615b1a41fe28d48c598c (diff)
downloadquagga-zrm.patch.tar.bz2
quagga-zrm.patch.tar.xz
route-map, prefix list, and source setting support for zebrazrm.patch
The following patch: 1) adds "route-map" support to zebra 2) fixes "show route-map" (with no name arg) 3) adds "prefix-list" support zebra 4) adds a "set src" route-map command to allow specifying a source address for matched routes 5) adds "ip protocol" command to zebra to execute route-maps by protocol (or "any") 6) supports "interface", "nexthop" and "ip address" matching for zebra route-map's
-rw-r--r--lib/routemap.c22
-rw-r--r--lib/routemap.h3
-rwxr-xr-xvtysh/extract.pl.in6
-rw-r--r--zebra/Makefile.am2
-rw-r--r--zebra/connected.c4
-rw-r--r--zebra/kernel_socket.c2
-rw-r--r--zebra/main.c1
-rw-r--r--zebra/rib.h33
-rw-r--r--zebra/rt_netlink.c90
-rw-r--r--zebra/rtread_getmsg.c2
-rw-r--r--zebra/rtread_proc.c2
-rw-r--r--zebra/zebra_rib.c59
-rw-r--r--zebra/zebra_routemap.c709
-rw-r--r--zebra/zebra_vty.c128
-rw-r--r--zebra/zserv.c5
15 files changed, 1001 insertions, 67 deletions
diff --git a/lib/routemap.c b/lib/routemap.c
index 55cc33c7..f379a4c7 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -268,6 +268,11 @@ vty_show_route_map (struct vty *vty, const char *name)
return CMD_WARNING;
}
}
+ else
+ {
+ for (map = route_map_master.head; map; map = map->next)
+ vty_show_route_map_entry (vty, map);
+ }
return CMD_SUCCESS;
}
@@ -1135,23 +1140,17 @@ ALIAS (no_rmap_onmatch_goto,
"Continue on a different entry within the route-map\n"
"Route-map entry sequence number\n")
-DEFUN (rmap_show,
- rmap_show_cmd,
- "show route-map",
- SHOW_STR
- "route-map information\n")
-{
- return vty_show_route_map (vty, NULL);
-}
-
DEFUN (rmap_show_name,
rmap_show_name_cmd,
- "show route-map WORD",
+ "show route-map [WORD]",
SHOW_STR
"route-map information\n"
"route-map name\n")
{
- return vty_show_route_map (vty, argv[0]);
+ char *name = NULL;
+ if (argc)
+ name = argv[0];
+ return vty_show_route_map (vty, name);
}
ALIAS (rmap_onmatch_goto,
@@ -1322,6 +1321,5 @@ route_map_init_vty (void)
install_element (RMAP_NODE, &no_rmap_description_cmd);
/* Install show command */
- install_element (ENABLE_NODE, &rmap_show_cmd);
install_element (ENABLE_NODE, &rmap_show_name_cmd);
}
diff --git a/lib/routemap.h b/lib/routemap.h
index c9cf4410..321e1927 100644
--- a/lib/routemap.h
+++ b/lib/routemap.h
@@ -45,7 +45,8 @@ typedef enum
RMAP_RIPNG,
RMAP_OSPF,
RMAP_OSPF6,
- RMAP_BGP
+ RMAP_BGP,
+ RMAP_ZEBRA
} route_map_object_t;
typedef enum
diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in
index 98a9ddde..723fe8d6 100755
--- a/vtysh/extract.pl.in
+++ b/vtysh/extract.pl.in
@@ -94,16 +94,16 @@ foreach (@ARGV) {
$protocol = "VTYSH_RIPD";
}
if ($file =~ /routemap.c/) {
- $protocol = "VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD";
+ $protocol = "VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA";
}
if ($file =~ /filter.c/) {
$protocol = "VTYSH_ALL";
}
if ($file =~ /plist.c/) {
if ($defun_array[1] =~ m/ipv6/) {
- $protocol = "VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD";
+ $protocol = "VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA";
} else {
- $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD";
+ $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD|VTYSH_ZEBRA";
}
}
if ($file =~ /distribute.c/) {
diff --git a/zebra/Makefile.am b/zebra/Makefile.am
index 7527562a..5d8db411 100644
--- a/zebra/Makefile.am
+++ b/zebra/Makefile.am
@@ -24,7 +24,7 @@ sbin_PROGRAMS = zebra
noinst_PROGRAMS = testzebra
zebra_SOURCES = \
- zserv.c main.c interface.c connected.c zebra_rib.c \
+ 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
diff --git a/zebra/connected.c b/zebra/connected.c
index 44002e76..9c2bc739 100644
--- a/zebra/connected.c
+++ b/zebra/connected.c
@@ -200,8 +200,8 @@ connected_up_ipv4 (struct interface *ifp, struct connected *ifc)
if (prefix_ipv4_any (&p))
return;
- rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, RT_TABLE_MAIN,
- ifp->metric, 0);
+ rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, NULL, ifp->ifindex,
+ RT_TABLE_MAIN, ifp->metric, 0);
rib_update ();
}
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
index bd4d9c4b..d3e19e67 100644
--- a/zebra/kernel_socket.c
+++ b/zebra/kernel_socket.c
@@ -764,7 +764,7 @@ rtm_read (struct rt_msghdr *rtm)
|| rtm->rtm_type == RTM_ADD
|| rtm->rtm_type == RTM_CHANGE)
rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags,
- &p, &gate.sin.sin_addr, 0, 0, 0, 0);
+ &p, &gate.sin.sin_addr, NULL, 0, 0, 0, 0);
else
rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags,
&p, &gate.sin.sin_addr, 0, 0);
diff --git a/zebra/main.c b/zebra/main.c
index dbe1b537..92d783d7 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -318,6 +318,7 @@ main (int argc, char **argv)
router_id_init();
zebra_vty_init ();
access_list_init ();
+ prefix_list_init ();
rtadv_init ();
#ifdef HAVE_IRDP
irdp_init();
diff --git a/zebra/rib.h b/zebra/rib.h
index 04fbbecf..7b2bd426 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -28,6 +28,14 @@
#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
{
/* Status Flags for the *route_node*, but kept in the head RIB.. */
@@ -167,24 +175,13 @@ struct nexthop
#define NEXTHOP_FLAG_RECURSIVE (1 << 2) /* Recursive nexthop. */
/* Nexthop address or interface name. */
- union
- {
- struct in_addr ipv4;
-#ifdef HAVE_IPV6
- struct in6_addr ipv6;
-#endif /* HAVE_IPV6*/
- } gate;
+ union g_addr gate;
/* Recursive lookup nexthop. */
u_char rtype;
unsigned int rifindex;
- union
- {
- struct in_addr ipv4;
-#ifdef HAVE_IPV6
- struct in6_addr ipv6;
-#endif /* HAVE_IPV6 */
- } rgate;
+ union g_addr rgate;
+ union g_addr src;
};
/* Routing table instance. */
@@ -212,7 +209,8 @@ struct vrf
extern struct nexthop *nexthop_ifindex_add (struct rib *, unsigned int);
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 *);
+extern struct nexthop *nexthop_ipv4_add (struct rib *, struct in_addr *,
+ struct in_addr *);
#ifdef HAVE_IPV6
extern struct nexthop *nexthop_ipv6_add (struct rib *, struct in6_addr *);
#endif /* HAVE_IPV6 */
@@ -225,8 +223,9 @@ extern struct route_table *vrf_static_table (afi_t afi, safi_t safi, u_int32_t i
* All rib_add_ipv[46]* functions will not just add prefix into RIB, but
* also implicitly withdraw equal prefix of same type. */
extern int rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p,
- struct in_addr *gate, unsigned int ifindex,
- u_int32_t vrf_id, u_int32_t, u_char);
+ struct in_addr *gate, struct in_addr *src,
+ unsigned int ifindex, u_int32_t vrf_id,
+ u_int32_t, u_char);
extern int rib_add_ipv4_multipath (struct prefix_ipv4 *, struct rib *);
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 216625e9..1bb2e476 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -737,6 +737,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
void *dest;
void *gate;
+ void *src;
rtm = NLMSG_DATA (h);
@@ -776,6 +777,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
metric = 0;
dest = NULL;
gate = NULL;
+ src = NULL;
if (tb[RTA_OIF])
index = *(int *) RTA_DATA (tb[RTA_OIF]);
@@ -785,6 +787,9 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
else
dest = anyaddr;
+ if (tb[RTA_PREFSRC])
+ src = RTA_DATA (tb[RTA_PREFSRC]);
+
/* Multipath treatment is needed. */
if (tb[RTA_GATEWAY])
gate = RTA_DATA (tb[RTA_GATEWAY]);
@@ -799,7 +804,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
memcpy (&p.prefix, dest, 4);
p.prefixlen = rtm->rtm_dst_len;
- rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table, metric, 0);
+ rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, table, metric, 0);
}
#ifdef HAVE_IPV6
if (rtm->rtm_family == AF_INET6)
@@ -846,6 +851,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
int table;
void *dest;
void *gate;
+ void *src;
rtm = NLMSG_DATA (h);
@@ -902,6 +908,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
index = 0;
dest = NULL;
gate = NULL;
+ src = NULL;
if (tb[RTA_OIF])
index = *(int *) RTA_DATA (tb[RTA_OIF]);
@@ -914,6 +921,9 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
if (tb[RTA_GATEWAY])
gate = RTA_DATA (tb[RTA_GATEWAY]);
+ if (tb[RTA_PREFSRC])
+ src = RTA_DATA (tb[RTA_PREFSRC]);
+
if (rtm->rtm_family == AF_INET)
{
struct prefix_ipv4 p;
@@ -932,7 +942,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
}
if (h->nlmsg_type == RTM_NEWROUTE)
- rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, 0, 0);
+ rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, 0, 0);
else
rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
}
@@ -1501,7 +1511,9 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
{
addattr_l (&req.n, sizeof req, RTA_GATEWAY,
&nexthop->rgate.ipv4, bytelen);
-
+ if (nexthop->src.ipv4.s_addr)
+ addattr_l(&req.n, sizeof req, RTA_PREFSRC,
+ &nexthop->src.ipv4, bytelen);
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("netlink_route_multipath() (recursive, "
"1 hop): nexthop via %s if %u",
@@ -1531,6 +1543,11 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
{
addattr32 (&req.n, sizeof req, RTA_OIF,
nexthop->rifindex);
+ if ((nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
+ || nexthop->rtype == NEXTHOP_TYPE_IFINDEX)
+ && nexthop->src.ipv4.s_addr)
+ addattr_l (&req.n, sizeof req, RTA_PREFSRC,
+ &nexthop->src.ipv4, bytelen);
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("netlink_route_multipath() (recursive, "
@@ -1559,6 +1576,9 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
{
addattr_l (&req.n, sizeof req, RTA_GATEWAY,
&nexthop->gate.ipv4, bytelen);
+ if (nexthop->src.ipv4.s_addr)
+ addattr_l (&req.n, sizeof req, RTA_PREFSRC,
+ &nexthop->src.ipv4, bytelen);
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("netlink_route_multipath() (single hop): "
@@ -1583,9 +1603,20 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
#endif /* HAVE_IPV6 */
if (nexthop->type == NEXTHOP_TYPE_IFINDEX
|| nexthop->type == NEXTHOP_TYPE_IFNAME
- || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
- || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
- || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
+ || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
+ {
+ addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
+
+ if (nexthop->src.ipv4.s_addr)
+ addattr_l (&req.n, sizeof req, RTA_PREFSRC,
+ &nexthop->src.ipv4, bytelen);
+
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("netlink_route_multipath() (single hop): "
+ "nexthop via if %u", nexthop->ifindex);
+ }
+ else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
+ || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
{
addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
@@ -1608,6 +1639,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
char buf[1024];
struct rtattr *rta = (void *) buf;
struct rtnexthop *rtnh;
+ union g_addr *src = NULL;
rta->rta_type = RTA_MULTIPATH;
rta->rta_len = RTA_LENGTH (0);
@@ -1652,6 +1684,9 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
&nexthop->rgate.ipv4, bytelen);
rtnh->rtnh_len += sizeof (struct rtattr) + 4;
+ if (nexthop->src.ipv4.s_addr)
+ src = &nexthop->src;
+
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("netlink_route_multipath() (recursive, "
"multihop): nexthop via %s if %u",
@@ -1674,11 +1709,21 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
}
#endif /* HAVE_IPV6 */
/* ifindex */
- if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
- || nexthop->rtype == NEXTHOP_TYPE_IFNAME
- || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
- || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
- || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
+ if (nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
+ || nexthop->rtype == NEXTHOP_TYPE_IFINDEX
+ || nexthop->rtype == NEXTHOP_TYPE_IFNAME)
+ {
+ rtnh->rtnh_ifindex = nexthop->rifindex;
+ if (nexthop->src.ipv4.s_addr)
+ src = &nexthop->src;
+
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("netlink_route_multipath() (recursive, "
+ "multihop): nexthop via if %u",
+ nexthop->rifindex);
+ }
+ else if (nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
+ || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
{
rtnh->rtnh_ifindex = nexthop->rifindex;
@@ -1713,6 +1758,9 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
&nexthop->gate.ipv4, bytelen);
rtnh->rtnh_len += sizeof (struct rtattr) + 4;
+ if (nexthop->src.ipv4.s_addr)
+ src = &nexthop->src;
+
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("netlink_route_multipath() (multihop): "
"nexthop via %s if %u",
@@ -1735,11 +1783,19 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
}
#endif /* HAVE_IPV6 */
/* ifindex */
- if (nexthop->type == NEXTHOP_TYPE_IFINDEX
- || nexthop->type == NEXTHOP_TYPE_IFNAME
- || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
- || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
- || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
+ if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
+ || nexthop->type == NEXTHOP_TYPE_IFINDEX
+ || nexthop->type == NEXTHOP_TYPE_IFNAME)
+ {
+ rtnh->rtnh_ifindex = nexthop->ifindex;
+ if (nexthop->src.ipv4.s_addr)
+ src = &nexthop->src;
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("netlink_route_multipath() (multihop): "
+ "nexthop via if %u", nexthop->ifindex);
+ }
+ else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
+ || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
{
rtnh->rtnh_ifindex = nexthop->ifindex;
@@ -1758,6 +1814,8 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
}
}
+ if (src)
+ addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src->ipv4, bytelen);
if (rta->rta_len > RTA_LENGTH (0))
addattr_l (&req.n, 1024, RTA_MULTIPATH, RTA_DATA (rta),
diff --git a/zebra/rtread_getmsg.c b/zebra/rtread_getmsg.c
index 1b0c8965..3e065c6f 100644
--- a/zebra/rtread_getmsg.c
+++ b/zebra/rtread_getmsg.c
@@ -90,7 +90,7 @@ handle_route_entry (mib2_ipRouteEntry_t *routeEntry)
gateway.s_addr = routeEntry->ipRouteNextHop;
rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &prefix,
- &gateway, 0, 0, 0, 0);
+ &gateway, NULL, 0, 0, 0, 0);
}
void
diff --git a/zebra/rtread_proc.c b/zebra/rtread_proc.c
index 93ec238f..1de435a4 100644
--- a/zebra/rtread_proc.c
+++ b/zebra/rtread_proc.c
@@ -96,7 +96,7 @@ proc_route_read (void)
p.prefixlen = ip_masklen (tmpmask);
sscanf (gate, "%lX", (unsigned long *)&gateway);
- rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gateway, 0, 0, 0, 0);
+ rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gateway, NULL, 0, 0, 0, 0);
}
fclose (fp);
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index acad065a..6ce0baed 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -32,6 +32,8 @@
#include "linklist.h"
#include "thread.h"
#include "workqueue.h"
+#include "prefix.h"
+#include "routemap.h"
#include "zebra/rib.h"
#include "zebra/rt.h"
@@ -233,7 +235,7 @@ nexthop_ifname_add (struct rib *rib, char *ifname)
}
struct nexthop *
-nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4)
+nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4, struct in_addr *src)
{
struct nexthop *nexthop;
@@ -241,6 +243,8 @@ nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4)
memset (nexthop, 0, sizeof (struct nexthop));
nexthop->type = NEXTHOP_TYPE_IPV4;
nexthop->gate.ipv4 = *ipv4;
+ if (src)
+ nexthop->src.ipv4 = *src;
nexthop_add (rib, nexthop);
@@ -248,8 +252,8 @@ nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4)
}
static struct nexthop *
-nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4,
- unsigned int ifindex)
+nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4,
+ struct in_addr *src, unsigned int ifindex)
{
struct nexthop *nexthop;
@@ -257,6 +261,8 @@ nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4,
memset (nexthop, 0, sizeof (struct nexthop));
nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
nexthop->gate.ipv4 = *ipv4;
+ if (src)
+ nexthop->src.ipv4 = *src;
nexthop->ifindex = ifindex;
nexthop_add (rib, nexthop);
@@ -685,12 +691,20 @@ rib_match_ipv6 (struct in6_addr *addr)
}
#endif /* HAVE_IPV6 */
+#define RIB_SYSTEM_ROUTE(R) \
+ ((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT)
+
static int
nexthop_active_check (struct route_node *rn, struct rib *rib,
struct nexthop *nexthop, int set)
{
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;
+ family = 0;
switch (nexthop->type)
{
case NEXTHOP_TYPE_IFINDEX:
@@ -700,8 +714,9 @@ nexthop_active_check (struct route_node *rn, struct rib *rib,
else
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
break;
- case NEXTHOP_TYPE_IFNAME:
case NEXTHOP_TYPE_IPV6_IFNAME:
+ family = AFI_IP6;
+ case NEXTHOP_TYPE_IFNAME:
ifp = if_lookup_by_name (nexthop->ifname);
if (ifp && if_is_up (ifp))
{
@@ -718,6 +733,7 @@ nexthop_active_check (struct route_node *rn, struct rib *rib,
break;
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX:
+ family = AFI_IP;
if (nexthop_active_ipv4 (rib, nexthop, set, rn))
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
else
@@ -725,12 +741,14 @@ nexthop_active_check (struct route_node *rn, struct rib *rib,
break;
#ifdef HAVE_IPV6
case NEXTHOP_TYPE_IPV6:
+ family = AFI_IP6;
if (nexthop_active_ipv6 (rib, nexthop, set, rn))
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
else
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
break;
case NEXTHOP_TYPE_IPV6_IFINDEX:
+ family = AFI_IP6;
if (IN6_IS_ADDR_LINKLOCAL (&nexthop->gate.ipv6))
{
ifp = if_lookup_by_index (nexthop->ifindex);
@@ -754,6 +772,26 @@ nexthop_active_check (struct route_node *rn, struct rib *rib,
default:
break;
}
+ if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+ return 0;
+
+ if (RIB_SYSTEM_ROUTE(rib) ||
+ (family == AFI_IP && rn->p.family != AF_INET) ||
+ (family == AFI_IP6 && rn->p.family != AF_INET6))
+ return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+
+ 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) {
+ ret = route_map_apply(rmap, &rn->p, RMAP_ZEBRA, nexthop);
+ }
+
+ if (ret == RMAP_DENYMATCH)
+ UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
}
@@ -782,8 +820,6 @@ nexthop_active_update (struct route_node *rn, struct rib *rib, int set)
}
-#define RIB_SYSTEM_ROUTE(R) \
- ((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT)
static void
rib_install_kernel (struct route_node *rn, struct rib *rib)
@@ -1231,7 +1267,8 @@ rib_delnode (struct route_node *rn, struct rib *rib)
int
rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p,
- struct in_addr *gate, unsigned int ifindex, u_int32_t vrf_id,
+ struct in_addr *gate, struct in_addr *src,
+ unsigned int ifindex, u_int32_t vrf_id,
u_int32_t metric, u_char distance)
{
struct rib *rib;
@@ -1300,9 +1337,9 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p,
if (gate)
{
if (ifindex)
- nexthop_ipv4_ifindex_add (rib, gate, ifindex);
+ nexthop_ipv4_ifindex_add (rib, gate, src, ifindex);
else
- nexthop_ipv4_add (rib, gate);
+ nexthop_ipv4_add (rib, gate, src);
}
else
nexthop_ifindex_add (rib, ifindex);
@@ -1539,7 +1576,7 @@ static_install_ipv4 (struct prefix *p, struct static_ipv4 *si)
switch (si->type)
{
case STATIC_IPV4_GATEWAY:
- nexthop_ipv4_add (rib, &si->gate.ipv4);
+ nexthop_ipv4_add (rib, &si->gate.ipv4, NULL);
break;
case STATIC_IPV4_IFNAME:
nexthop_ifname_add (rib, si->gate.ifname);
@@ -1562,7 +1599,7 @@ static_install_ipv4 (struct prefix *p, struct static_ipv4 *si)
switch (si->type)
{
case STATIC_IPV4_GATEWAY:
- nexthop_ipv4_add (rib, &si->gate.ipv4);
+ nexthop_ipv4_add (rib, &si->gate.ipv4, NULL);
break;
case STATIC_IPV4_IFNAME:
nexthop_ifname_add (rib, si->gate.ifname);
diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c
new file mode 100644
index 00000000..44367f8d
--- /dev/null
+++ b/zebra/zebra_routemap.c
@@ -0,0 +1,709 @@
+/* zebra routemap.
+ * Copyright (C) 2006 IBM Corporation
+ *
+ * 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 "memory.h"
+#include "prefix.h"
+#include "rib.h"
+#include "routemap.h"
+#include "command.h"
+#include "filter.h"
+#include "plist.h"
+
+#include "zebra/zserv.h"
+
+/* 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)
+{
+ int ret;
+
+ ret = route_map_add_match (index, command, arg);
+ if (ret)
+ {
+ switch (ret)
+ {
+ case RMAP_RULE_MISSING:
+ vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ case RMAP_COMPILE_ERROR:
+ vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+ 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)
+{
+ int ret;
+
+ ret = route_map_delete_match (index, command, arg);
+ if (ret)
+ {
+ switch (ret)
+ {
+ case RMAP_RULE_MISSING:
+ vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ case RMAP_COMPILE_ERROR:
+ vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+/* Add zebra route map rule. */
+static int
+zebra_route_set_add (struct vty *vty, struct route_map_index *index,
+ const char *command, const char *arg)
+{
+ int ret;
+
+ ret = route_map_add_set (index, command, arg);
+ if (ret)
+ {
+ switch (ret)
+ {
+ case RMAP_RULE_MISSING:
+ vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ case RMAP_COMPILE_ERROR:
+ vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+/* Delete zebra route map rule. */
+static int
+zebra_route_set_delete (struct vty *vty, struct route_map_index *index,
+ const char *command, const char *arg)
+{
+ int ret;
+
+ ret = route_map_delete_set (index, command, arg);
+ if (ret)
+ {
+ switch (ret)
+ {
+ case RMAP_RULE_MISSING:
+ vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ case RMAP_COMPILE_ERROR:
+ vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+
+/* `match interface IFNAME' */
+/* Match function return 1 if match is success else return zero. */
+static route_map_result_t
+route_match_interface (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct nexthop *nexthop;
+ char *ifname = rule;
+ unsigned int ifindex;
+
+ if (type == RMAP_ZEBRA)
+ {
+ if (strcasecmp(ifname, "any") == 0)
+ return RMAP_MATCH;
+ ifindex = ifname2ifindex(ifname);
+ if (ifindex == 0)
+ return RMAP_NOMATCH;
+ nexthop = object;
+ if (!nexthop)
+ return RMAP_NOMATCH;
+ if (nexthop->ifindex == ifindex)
+ return RMAP_MATCH;
+ }
+ return RMAP_NOMATCH;
+}
+
+/* Route map `match interface' match statement. `arg' is IFNAME value */
+static void *
+route_match_interface_compile (const char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+/* Free route map's compiled `match interface' value. */
+static void
+route_match_interface_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for interface matching */
+struct route_map_rule_cmd route_match_interface_cmd =
+{
+ "interface",
+ route_match_interface,
+ route_match_interface_compile,
+ route_match_interface_free
+};
+
+DEFUN (match_interface,
+ match_interface_cmd,
+ "match interface WORD",
+ MATCH_STR
+ "match first hop interface of route\n"
+ "Interface name\n")
+{
+ return zebra_route_match_add (vty, vty->index, "interface", argv[0]);
+}
+
+DEFUN (no_match_interface,
+ no_match_interface_cmd,
+ "no match interface",
+ NO_STR
+ MATCH_STR
+ "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", argv[0]);
+}
+
+ALIAS (no_match_interface,
+ no_match_interface_val_cmd,
+ "no match interface WORD",
+ NO_STR
+ MATCH_STR
+ "Match first hop interface of route\n"
+ "Interface name\n")
+
+DEFUN (match_ip_next_hop,
+ match_ip_next_hop_cmd,
+ "match ip next-hop (<1-199>|<1300-2699>|WORD)",
+ MATCH_STR
+ IP_STR
+ "Match next-hop address of route\n"
+ "IP access-list number\n"
+ "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]);
+}
+
+DEFUN (no_match_ip_next_hop,
+ no_match_ip_next_hop_cmd,
+ "no match ip next-hop",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "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", argv[0]);
+}
+
+ALIAS (no_match_ip_next_hop,
+ no_match_ip_next_hop_val_cmd,
+ "no match ip next-hop (<1-199>|<1300-2699>|WORD)",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match next-hop address of route\n"
+ "IP access-list number\n"
+ "IP access-list number (expanded range)\n"
+ "IP Access-list name\n")
+
+DEFUN (match_ip_next_hop_prefix_list,
+ match_ip_next_hop_prefix_list_cmd,
+ "match ip next-hop prefix-list WORD",
+ MATCH_STR
+ IP_STR
+ "Match next-hop address of route\n"
+ "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]);
+}
+
+DEFUN (no_match_ip_next_hop_prefix_list,
+ no_match_ip_next_hop_prefix_list_cmd,
+ "no match ip next-hop prefix-list",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match next-hop address of route\n"
+ "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", argv[0]);
+}
+
+ALIAS (no_match_ip_next_hop_prefix_list,
+ no_match_ip_next_hop_prefix_list_val_cmd,
+ "no match ip next-hop prefix-list WORD",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match next-hop address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+
+DEFUN (match_ip_address,
+ match_ip_address_cmd,
+ "match ip address (<1-199>|<1300-2699>|WORD)",
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "IP access-list number\n"
+ "IP access-list number (expanded range)\n"
+ "IP Access-list name\n")
+
+{
+ return zebra_route_match_add (vty, vty->index, "ip address", argv[0]);
+}
+
+DEFUN (no_match_ip_address,
+ no_match_ip_address_cmd,
+ "no match ip address",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "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", argv[0]);
+}
+
+ALIAS (no_match_ip_address,
+ no_match_ip_address_val_cmd,
+ "no match ip address (<1-199>|<1300-2699>|WORD)",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "IP access-list number\n"
+ "IP access-list number (expanded range)\n"
+ "IP Access-list name\n")
+
+DEFUN (match_ip_address_prefix_list,
+ match_ip_address_prefix_list_cmd,
+ "match ip address prefix-list WORD",
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "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]);
+}
+
+DEFUN (no_match_ip_address_prefix_list,
+ no_match_ip_address_prefix_list_cmd,
+ "no match ip address prefix-list",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "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", argv[0]);
+}
+
+ALIAS (no_match_ip_address_prefix_list,
+ no_match_ip_address_prefix_list_val_cmd,
+ "no match ip address prefix-list WORD",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+
+/* set functions */
+
+DEFUN (set_src,
+ set_src_cmd,
+ "set src A.B.C.D",
+ SET_STR
+ "src address for route\n"
+ "src address\n")
+{
+ struct in_addr src;
+ struct interface *pif;
+
+ if (inet_pton(AF_INET, argv[0], &src) <= 0)
+ {
+ vty_out (vty, "%% not a local address%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ pif = if_lookup_exact_address (src);
+ if (!pif)
+ {
+ vty_out (vty, "%% not a local address%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ return zebra_route_set_add (vty, vty->index, "src", argv[0]);
+}
+
+DEFUN (no_set_src,
+ no_set_src_cmd,
+ "no set src",
+ NO_STR
+ SET_STR
+ "Source address for route\n")
+{
+ if (argc == 0)
+ return zebra_route_set_delete (vty, vty->index, "src", NULL);
+
+ return zebra_route_set_delete (vty, vty->index, "src", argv[0]);
+}
+
+ALIAS (no_set_src,
+ no_set_src_val_cmd,
+ "no set src (A.B.C.D)",
+ NO_STR
+ SET_STR
+ "src address for route\n"
+ "src address\n")
+
+/*XXXXXXXXXXXXXXXXXXXXXXXXXXXX*/
+
+/* `match ip next-hop IP_ACCESS_LIST' */
+
+/* Match function return 1 if match is success else return zero. */
+static route_map_result_t
+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 prefix_ipv4 p;
+
+ if (type == RMAP_ZEBRA)
+ {
+ nexthop = object;
+ switch (nexthop->type) {
+ case NEXTHOP_TYPE_IFINDEX:
+ case NEXTHOP_TYPE_IFNAME:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ case NEXTHOP_TYPE_IPV4_IFNAME:
+ if (nexthop->rtype != NEXTHOP_TYPE_IPV4)
+ return RMAP_NOMATCH;
+ p.family = AF_INET;
+ p.prefix = nexthop->rgate.ipv4;
+ p.prefixlen = IPV4_MAX_BITLEN;
+ break;
+ case NEXTHOP_TYPE_IPV4:
+ p.family = AF_INET;
+ p.prefix = nexthop->gate.ipv4;
+ p.prefixlen = IPV4_MAX_BITLEN;
+ break;
+ default:
+ return RMAP_NOMATCH;
+ }
+ alist = access_list_lookup (AFI_IP, (char *) rule);
+ if (alist == NULL)
+ return RMAP_NOMATCH;
+
+ return (access_list_apply (alist, &p) == FILTER_DENY ?
+ RMAP_NOMATCH : RMAP_MATCH);
+ }
+ return RMAP_NOMATCH;
+}
+
+/* Route map `ip next-hop' match statement. `arg' should be
+ access-list name. */
+static void *
+route_match_ip_next_hop_compile (const char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+/* Free route map's compiled `. */
+static void
+route_match_ip_next_hop_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip next-hop matching. */
+static struct route_map_rule_cmd route_match_ip_next_hop_cmd =
+{
+ "ip next-hop",
+ route_match_ip_next_hop,
+ route_match_ip_next_hop_compile,
+ route_match_ip_next_hop_free
+};
+
+/* `match ip next-hop prefix-list PREFIX_LIST' */
+
+static route_map_result_t
+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 prefix_ipv4 p;
+
+ if (type == RMAP_ZEBRA)
+ {
+ nexthop = object;
+ switch (nexthop->type) {
+ case NEXTHOP_TYPE_IFINDEX:
+ case NEXTHOP_TYPE_IFNAME:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ case NEXTHOP_TYPE_IPV4_IFNAME:
+ if (nexthop->rtype != NEXTHOP_TYPE_IPV4)
+ return RMAP_NOMATCH;
+ p.family = AF_INET;
+ p.prefix = nexthop->rgate.ipv4;
+ p.prefixlen = IPV4_MAX_BITLEN;
+ break;
+ case NEXTHOP_TYPE_IPV4:
+ p.family = AF_INET;
+ p.prefix = nexthop->gate.ipv4;
+ p.prefixlen = IPV4_MAX_BITLEN;
+ break;
+ default:
+ return RMAP_NOMATCH;
+ }
+ plist = prefix_list_lookup (AFI_IP, (char *) rule);
+ if (plist == NULL)
+ return RMAP_NOMATCH;
+
+ return (prefix_list_apply (plist, &p) == PREFIX_DENY ?
+ RMAP_NOMATCH : RMAP_MATCH);
+ }
+ return RMAP_NOMATCH;
+}
+
+static void *
+route_match_ip_next_hop_prefix_list_compile (const char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+static void
+route_match_ip_next_hop_prefix_list_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+static struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd =
+{
+ "ip next-hop prefix-list",
+ route_match_ip_next_hop_prefix_list,
+ route_match_ip_next_hop_prefix_list_compile,
+ route_match_ip_next_hop_prefix_list_free
+};
+
+/* `match ip address IP_ACCESS_LIST' */
+
+/* Match function should return 1 if match is success else return
+ zero. */
+static route_map_result_t
+route_match_ip_address (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct access_list *alist;
+
+ if (type == RMAP_ZEBRA)
+ {
+ alist = access_list_lookup (AFI_IP, (char *) rule);
+ if (alist == NULL)
+ return RMAP_NOMATCH;
+
+ return (access_list_apply (alist, prefix) == FILTER_DENY ?
+ RMAP_NOMATCH : RMAP_MATCH);
+ }
+ return RMAP_NOMATCH;
+}
+
+/* Route map `ip address' match statement. `arg' should be
+ access-list name. */
+static void *
+route_match_ip_address_compile (const char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+/* Free route map's compiled `ip address' value. */
+static void
+route_match_ip_address_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip address matching. */
+static struct route_map_rule_cmd route_match_ip_address_cmd =
+{
+ "ip address",
+ route_match_ip_address,
+ route_match_ip_address_compile,
+ route_match_ip_address_free
+};
+
+/* `match ip address prefix-list PREFIX_LIST' */
+
+static route_map_result_t
+route_match_ip_address_prefix_list (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct prefix_list *plist;
+
+ if (type == RMAP_ZEBRA)
+ {
+ plist = prefix_list_lookup (AFI_IP, (char *) rule);
+ if (plist == NULL)
+ return RMAP_NOMATCH;
+
+ return (prefix_list_apply (plist, prefix) == PREFIX_DENY ?
+ RMAP_NOMATCH : RMAP_MATCH);
+ }
+ return RMAP_NOMATCH;
+}
+
+static void *
+route_match_ip_address_prefix_list_compile (const char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+static void
+route_match_ip_address_prefix_list_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+static struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd =
+{
+ "ip address prefix-list",
+ route_match_ip_address_prefix_list,
+ route_match_ip_address_prefix_list_compile,
+ route_match_ip_address_prefix_list_free
+};
+
+
+/* `set src A.B.C.D' */
+
+/* Set src. */
+static route_map_result_t
+route_set_src (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ if (type == RMAP_ZEBRA)
+ {
+ struct nexthop *nexthop;
+
+ nexthop = object;
+ nexthop->src = *(union g_addr *)rule;
+ }
+ return RMAP_OKAY;
+}
+
+/* set src compilation. */
+static void *
+route_set_src_compile (const char *arg)
+{
+ sa_family_t family;
+ union g_addr src, *psrc;
+
+ if (inet_pton(AF_INET, arg, &src.ipv4) > 0)
+ family = AF_INET;
+ else if (inet_pton(AF_INET6, arg, &src.ipv6) > 0)
+ family = AF_INET6;
+ else
+ return NULL;
+
+ psrc = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (union g_addr));
+ *psrc = src;
+
+ return psrc;
+}
+
+/* Free route map's compiled `set src' value. */
+static void
+route_set_src_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Set src rule structure. */
+static struct route_map_rule_cmd route_set_src_cmd =
+{
+ "src",
+ route_set_src,
+ route_set_src_compile,
+ route_set_src_free,
+};
+
+void
+zebra_route_map_init ()
+{
+ route_map_init ();
+ route_map_init_vty ();
+
+ 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_set (&route_set_src_cmd);
+/* */
+ install_element (RMAP_NODE, &match_interface_cmd);
+ install_element (RMAP_NODE, &no_match_interface_cmd);
+ install_element (RMAP_NODE, &no_match_interface_val_cmd);
+ install_element (RMAP_NODE, &match_ip_next_hop_cmd);
+ install_element (RMAP_NODE, &no_match_ip_next_hop_cmd);
+ install_element (RMAP_NODE, &no_match_ip_next_hop_val_cmd);
+ install_element (RMAP_NODE, &match_ip_next_hop_prefix_list_cmd);
+ install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd);
+ install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_val_cmd);
+ install_element (RMAP_NODE, &match_ip_address_cmd);
+ install_element (RMAP_NODE, &no_match_ip_address_cmd);
+ install_element (RMAP_NODE, &no_match_ip_address_val_cmd);
+ 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, &set_src_cmd);
+ install_element (RMAP_NODE, &no_set_src_cmd);
+}
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 68e6f920..89340880 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -21,6 +21,7 @@
#include <zebra.h>
+#include "memory.h"
#include "if.h"
#include "prefix.h"
#include "command.h"
@@ -474,6 +475,81 @@ DEFUN (no_ip_route_mask_flags_distance2,
return zebra_static_ipv4 (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3]);
}
+char *proto_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1]; /* "any" == ZEBRA_ROUTE_MAX */
+
+static struct proto_map {
+ const char *pr_name;
+ int pr_num;
+} proto_map[] = {
+ { "system", ZEBRA_ROUTE_SYSTEM },
+ { "kernel", ZEBRA_ROUTE_KERNEL },
+ { "connect", ZEBRA_ROUTE_CONNECT },
+ { "static", ZEBRA_ROUTE_STATIC },
+ { "rip", ZEBRA_ROUTE_RIP },
+ { "ripng", ZEBRA_ROUTE_RIPNG },
+ { "ospf", ZEBRA_ROUTE_OSPF },
+ { "ospf6", ZEBRA_ROUTE_OSPF6 },
+ { "isis", ZEBRA_ROUTE_ISIS },
+ { "bgp", ZEBRA_ROUTE_BGP },
+ { "hsls", ZEBRA_ROUTE_HSLS },
+ { "any", ZEBRA_ROUTE_MAX },
+ { 0, -1 },
+};
+
+static int
+proto_name2num(const char *s)
+{
+ struct proto_map *p;
+ for (p=proto_map; ; p++)
+ if (!p->pr_name || strcasecmp(s, p->pr_name) == 0)
+ return p->pr_num;
+}
+
+DEFUN (ip_protocol,
+ ip_protocol_cmd,
+ "ip protocol PROTO route-map ROUTE-MAP",
+ NO_STR
+ "Apply route map to PROTO\n"
+ "Protocol name\n"
+ "Route map name\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;
+ }
+ 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;
+}
+
+DEFUN (no_ip_protocol,
+ no_ip_protocol_cmd,
+ "no ip protocol PROTO",
+ NO_STR
+ "Remove route map from PROTO\n"
+ "Protocol name\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;
+ }
+ 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;
+}
+
/* New RIB. Detailed information for IPv4 route. */
static void
vty_show_ip_route_detail (struct vty *vty, struct route_node *rn)
@@ -529,6 +605,8 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn)
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
{
+ char addrstr[32];
+
vty_out (vty, " %c",
CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' ');
@@ -575,6 +653,31 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn)
break;
}
}
+ switch (nexthop->type)
+ {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ case NEXTHOP_TYPE_IPV4_IFNAME:
+ if (nexthop->src.ipv4.s_addr)
+ {
+ if (inet_ntop(AF_INET, &nexthop->src.ipv4, addrstr,
+ sizeof addrstr))
+ vty_out (vty, ", src %s", addrstr);
+ }
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ case NEXTHOP_TYPE_IPV6_IFNAME:
+ if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, &in6addr_any))
+ {
+ if (inet_ntop(AF_INET6, &nexthop->src.ipv6, addrstr,
+ sizeof addrstr))
+ vty_out (vty, ", src %s", addrstr);
+ }
+ break;
+ default:
+ break;
+ }
vty_out (vty, "%s", VTY_NEWLINE);
}
vty_out (vty, "%s", VTY_NEWLINE);
@@ -658,6 +761,29 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib)
break;
}
}
+ switch (nexthop->type)
+ {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ case NEXTHOP_TYPE_IPV4_IFNAME:
+ if (nexthop->src.ipv4.s_addr)
+ {
+ if (inet_ntop(AF_INET, &nexthop->src.ipv4, buf, sizeof buf))
+ vty_out (vty, ", src %s", buf);
+ }
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ case NEXTHOP_TYPE_IPV6_IFNAME:
+ if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, &in6addr_any))
+ {
+ if (inet_ntop(AF_INET6, &nexthop->src.ipv6, buf, sizeof buf))
+ vty_out (vty, ", src %s", buf);
+ }
+ break;
+ default:
+ break;
+ }
if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE))
vty_out (vty, ", bh");
@@ -1883,6 +2009,8 @@ zebra_vty_init (void)
{
install_node (&ip_node, zebra_ip_config);
+ install_element (CONFIG_NODE, &ip_protocol_cmd);
+ install_element (CONFIG_NODE, &no_ip_protocol_cmd);
install_element (CONFIG_NODE, &ip_route_cmd);
install_element (CONFIG_NODE, &ip_route_flags_cmd);
install_element (CONFIG_NODE, &ip_route_flags2_cmd);
diff --git a/zebra/zserv.c b/zebra/zserv.c
index 1703d3f5..22a6bed2 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -781,7 +781,7 @@ zread_ipv4_add (struct zserv *client, u_short length)
break;
case ZEBRA_NEXTHOP_IPV4:
nexthop.s_addr = stream_get_ipv4 (s);
- nexthop_ipv4_add (rib, &nexthop);
+ nexthop_ipv4_add (rib, &nexthop, NULL);
break;
case ZEBRA_NEXTHOP_IPV6:
stream_forward_getp (s, IPV6_MAX_BYTELEN);
@@ -1733,4 +1733,7 @@ zebra_init (void)
install_element (CONFIG_NODE, &ipv6_forwarding_cmd);
install_element (CONFIG_NODE, &no_ipv6_forwarding_cmd);
#endif /* HAVE_IPV6 */
+
+ /* Route-map */
+ zebra_route_map_init ();
}