[zebra] Routemap support on received routes, with 'set src' command (linux)
2007-05-01 David L Stevens <dlstevens@us.ibm.com>
* (general) These changes collectively add route-map and
prefix-list support to zebra and fix a bug in "show
route-map" (with no argument).
* doc/main.texi: added route-map, prefix-list, ip protocol
and set src documentation
* lib/command.h: added PROTOCOL_NODE type
* lib/log.c: (proto_name2num) new function, protocol name to
number translation.
* lib/routemap.c: (vty_show_route_map) fixed "show route-map"
without route-map name
* lib/routemap.h: added RMAP_ZEBRA type
* lib/zebra.h: added proto_name2num() prototype
* vtysh/extract.pl.in: added VTYSH_ZEBRA flag for route-map and
plist
* vtysh/Makefile.am: added zebra_routemap.c
* vtysh/vtysh.h: added VTYSH_ZEBRA flag to VTYSH_RMAP
* zebra/connected.c: (connected_up_ipv4) added src preference argument
to rib_add_ipv4()
* zebra/kernel_socket.c: (rtm_read) ditto
* zebra/main.c: added prefix list initialization
* zebra/Makefile.am: added zebra_routemap.c source file
* zebra/rib.h: added generic address union "g_addr" and use in
existing places that had an explicit union.
Added "src" to struct nexthop.
Added preferred src arg to nexthop_ipv4_add and rib_add_ipv4.
* zebra/rt_netlink.c: (netlink_routing_table) set preferred source on
netlink messages.
(netlink_route_change) ditto
(netlink_route_multipath) ditto.
* zebra/rtread_getmsg.c: (handle_route_entry) added (NULL) src to
rib_add_ipv4() call.
* zebra/rtread_proc.c: (proc_route_read) ditto
* zebra/zebra_rib.c: (nexthop_ipv4_add) add src argument.
(nexthop_ipv4_ifindex_add) ditto
(rib_add_ipv4) ditto
(nexthop_active_check) Add route-map processing.
* zebra/zebra_routemap.c: new file for zebra route-map commands.
* zebra/zebra_vty.c: (ip_protocol_cmd) Apply route-map to protocol
(vty_show_ip_route_detail) added "src" printing
(vty_show_ip_route) ditto
(show_ip_protocol_cmd) new command, list routemaps.
(config_write_protocol) write out routemap protocl config.
(zebra_vty_init) Install the new routemap protocol commands.
* zebra/zserv.c: (zread_ipv4_add) added (NULL) src arg
(zebra_init) init zebra route-maps.
* zebra/zserv.h: add zebra_route_map_init
diff --git a/doc/ChangeLog b/doc/ChangeLog
index 586852c..b8c81e7 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,3 +1,8 @@
+2007-05-01 David L Stevens <dlstevens@us.ibm.com>
+
+ * main.texi: added route-map, prefix-list, ip protocol
+ and set src documentation
+
2007-04-30 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
* ospfd.texi: Add a paragraph to the description of the OSPFv2
diff --git a/doc/main.texi b/doc/main.texi
index b76a636..9966b35 100644
--- a/doc/main.texi
+++ b/doc/main.texi
@@ -10,6 +10,7 @@
* Invoking zebra:: Running the program
* Interface Commands:: Commands for zebra interfaces
* Static Route Commands:: Commands for adding static routes
+* zebra Route Filtering:: Commands for zebra route filtering
* zebra Terminal Mode Commands:: Commands for zebra's VTY
@end menu
@@ -183,6 +184,49 @@
static routes defined after this are added to the specified table.
@end deffn
+@node zebra Route Filtering
+@section zebra Route Filtering
+Zebra supports @command{prefix-list} and @command{route-map} to match
+routes received from other quagga components. The
+@command{permit}/@command{deny} facilities provided by these commands
+can be used to filter which routes zebra will install in the kernel.
+
+@deffn Command {ip protocol @var{protocol} route-map @var{routemap}} {}
+Apply a route-map filter to routes for the specified protocol. @var{protocol}
+can be @b{any} or one of
+@b{system},
+@b{kernel},
+@b{connected},
+@b{static},
+@b{rip},
+@b{ripng},
+@b{ospf},
+@b{ospf6},
+@b{isis},
+@b{bgp},
+@b{hsls}.
+@end deffn
+
+@deffn {Route Map} {set src @var{address}}
+Within a route-map, set the preferred source address for matching routes
+when installing in the kernel.
+@end deffn
+
+@example
+The following creates a prefix-list that matches all addresses, a route-map
+that sets the preferred source address, and applies the route-map to all
+@command{rip} routes.
+
+@group
+ip prefix-list ANY permit 0.0.0.0/0 le 32
+route-map RM1 permit 10
+ match ip address prefix-list ANY
+ set src 10.0.0.1
+
+ip protocol rip route-map RM1
+@end group
+@end example
+
@node zebra Terminal Mode Commands
@section zebra Terminal Mode Commands
@@ -209,6 +253,15 @@
@deffn Command {show interface} {}
@end deffn
+@deffn Command {show ip prefix-list [@var{name}]} {}
+@end deffn
+
+@deffn Command {show route-map [@var{name}]} {}
+@end deffn
+
+@deffn Command {show ip protocol} {}
+@end deffn
+
@deffn Command {show ipforward} {}
Display whether the host's IP forwarding function is enabled or not.
Almost any UNIX kernel can be configured with IP forwarding disabled.
diff --git a/lib/ChangeLog b/lib/ChangeLog
index f8fdd11..3787b68 100644
--- a/lib/ChangeLog
+++ b/lib/ChangeLog
@@ -1,3 +1,16 @@
+2007-05-01 David L Stevens <dlstevens@us.ibm.com>
+
+ * (general) These changes collectively add route-map and
+ prefix-list support to zebra and fix a bug in "show
+ route-map" (with no argument).
+ * command.h: added PROTOCOL_NODE type
+ * log.c: (proto_name2num) new function, protocol name to
+ number translation.
+ * routemap.c: (vty_show_route_map) fixed "show route-map"
+ without route-map name
+ * routemap.h: added RMAP_ZEBRA type
+ * zebra.h: added proto_name2num() prototype
+
2007-04-29 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
* log.c: (quagga_timestamp) Optimize the subsecond timestamp generation.
diff --git a/lib/command.h b/lib/command.h
index ce18731..a725378 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -99,6 +99,7 @@
SMUX_NODE, /* SNMP configuration node. */
DUMP_NODE, /* Packet dump node. */
FORWARDING_NODE, /* IP forwarding node. */
+ PROTOCOL_NODE, /* protocol filtering node */
VTY_NODE /* Vty node. */
};
diff --git a/lib/log.c b/lib/log.c
index 21bf3f2..cbf76af 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -886,3 +886,17 @@
}
return command_types[command].string;
}
+
+#define RTSIZE (sizeof(route_types)/sizeof(route_types[0]))
+
+int
+proto_name2num(const char *s)
+{
+ unsigned i;
+
+ for (i=0; i<RTSIZE; ++i)
+ if (strcasecmp(s, route_types[i].string) == 0)
+ return route_types[i].type;
+ return -1;
+}
+#undef RTSIZE
diff --git a/lib/routemap.c b/lib/routemap.c
index 55cc33c..58ed09a 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -268,6 +268,11 @@
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 @@
"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]);
+ const char *name = NULL;
+ if (argc)
+ name = argv[0];
+ return vty_show_route_map (vty, name);
}
ALIAS (rmap_onmatch_goto,
@@ -1322,6 +1321,5 @@
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 c9cf441..321e192 100644
--- a/lib/routemap.h
+++ b/lib/routemap.h
@@ -45,7 +45,8 @@
RMAP_RIPNG,
RMAP_OSPF,
RMAP_OSPF6,
- RMAP_BGP
+ RMAP_BGP,
+ RMAP_ZEBRA
} route_map_object_t;
typedef enum
diff --git a/lib/zebra.h b/lib/zebra.h
index 2e2f8cd..8553739 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -444,6 +444,9 @@
extern char zebra_route_char(unsigned int route_type);
/* Map a zserv command type to the same string,
* e.g. ZEBRA_INTERFACE_ADD -> "ZEBRA_INTERFACE_ADD" */
+/* Map a protocol name to its number. e.g. ZEBRA_ROUTE_BGP->9*/
+extern int proto_name2num(const char *s);
+
extern const char *zserv_command_string (unsigned int command);
/* Zebra's family types. */
diff --git a/vtysh/ChangeLog b/vtysh/ChangeLog
index 4ca5df9..a582b95 100644
--- a/vtysh/ChangeLog
+++ b/vtysh/ChangeLog
@@ -1,3 +1,10 @@
+2007-05-01 David L Stevens <dlstevens@us.ibm.com>
+
+ * vtysh/extract.pl.in: added VTYSH_ZEBRA flag for route-map and
+ plist
+ * vtysh/Makefile.am: added zebra_routemap.c
+ * vtysh/vtysh.h: added VTYSH_ZEBRA flag to VTYSH_RMAP
+
2007-04-28 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
* vtysh.c: (vtysh_log_timestamp_precision,
diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in
index 98a9ddd..723fe8d 100755
--- a/vtysh/extract.pl.in
+++ b/vtysh/extract.pl.in
@@ -94,16 +94,16 @@
$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/vtysh/vtysh.h b/vtysh/vtysh.h
index dd2bcbd..3ed0dd3 100644
--- a/vtysh/vtysh.h
+++ b/vtysh/vtysh.h
@@ -30,7 +30,7 @@
#define VTYSH_BGPD 0x20
#define VTYSH_ISISD 0x40
#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD
-#define VTYSH_RMAP VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD
+#define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD
#define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD
/* vtysh local configuration file. */
diff --git a/zebra/ChangeLog b/zebra/ChangeLog
index 11e406d..c08bbe4 100644
--- a/zebra/ChangeLog
+++ b/zebra/ChangeLog
@@ -1,3 +1,39 @@
+2007-05-01 David L Stevens <dlstevens@us.ibm.com>
+
+ * (general) These changes collectively add route-map and
+ prefix-list support to zebra and fix a bug in "show
+ route-map" (with no argument).
+ * connected.c: (connected_up_ipv4) added src preference argument
+ to rib_add_ipv4()
+ * kernel_socket.c: (rtm_read) ditto
+ * main.c: added prefix list initialization
+ * Makefile.am: added zebra_routemap.c source file
+ * rib.h: added generic address union "g_addr" and use in
+ existing places that had an explicit union.
+ Added "src" to struct nexthop.
+ Added preferred src arg to nexthop_ipv4_add and rib_add_ipv4.
+ * rt_netlink.c: (netlink_routing_table) set preferred source on
+ netlink messages.
+ (netlink_route_change) ditto
+ (netlink_route_multipath) ditto.
+ * rtread_getmsg.c: (handle_route_entry) added (NULL) src to
+ rib_add_ipv4() call.
+ * rtread_proc.c: (proc_route_read) ditto
+ * zebra_rib.c: (nexthop_ipv4_add) add src argument.
+ (nexthop_ipv4_ifindex_add) ditto
+ (rib_add_ipv4) ditto
+ (nexthop_active_check) Add route-map processing.
+ * zebra_routemap.c: new file for zebra route-map commands.
+ * zebra_vty.c: (ip_protocol_cmd) Apply route-map to protocol
+ (vty_show_ip_route_detail) added "src" printing
+ (vty_show_ip_route) ditto
+ (show_ip_protocol_cmd) new command, list routemaps.
+ (config_write_protocol) write out routemap protocl config.
+ (zebra_vty_init) Install the new routemap protocol commands.
+ * zserv.c: (zread_ipv4_add) added (NULL) src arg
+ (zebra_init) init zebra route-maps.
+ * zserv.h: add zebra_route_map_init
+
2007-04-29 Paul Jakma <paul.jakma@sun.com>
* ioctl{_solaris,}.c: (if_get_mtu) Fix missing ; in last commit.
diff --git a/zebra/Makefile.am b/zebra/Makefile.am
index 7527562..5d8db41 100644
--- a/zebra/Makefile.am
+++ b/zebra/Makefile.am
@@ -24,7 +24,7 @@
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 74e10ac..53aa254 100644
--- a/zebra/connected.c
+++ b/zebra/connected.c
@@ -187,8 +187,8 @@
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 5281236..b7c7ccc 100644
--- a/zebra/kernel_socket.c
+++ b/zebra/kernel_socket.c
@@ -775,7 +775,7 @@
|| 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 ed45bd1..7d89579 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -29,6 +29,7 @@
#include "memory.h"
#include "prefix.h"
#include "log.h"
+#include "plist.h"
#include "privs.h"
#include "sigevent.h"
@@ -324,6 +325,7 @@
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 04fbbec..7b2bd42 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 @@
#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 @@
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 @@
* 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 e2f1f9d..3b602c4 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -725,6 +725,7 @@
void *dest;
void *gate;
+ void *src;
rtm = NLMSG_DATA (h);
@@ -764,6 +765,7 @@
metric = 0;
dest = NULL;
gate = NULL;
+ src = NULL;
if (tb[RTA_OIF])
index = *(int *) RTA_DATA (tb[RTA_OIF]);
@@ -773,6 +775,9 @@
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]);
@@ -787,7 +792,7 @@
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)
@@ -834,6 +839,7 @@
int table;
void *dest;
void *gate;
+ void *src;
rtm = NLMSG_DATA (h);
@@ -890,6 +896,7 @@
index = 0;
dest = NULL;
gate = NULL;
+ src = NULL;
if (tb[RTA_OIF])
index = *(int *) RTA_DATA (tb[RTA_OIF]);
@@ -902,6 +909,9 @@
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;
@@ -920,7 +930,7 @@
}
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);
}
@@ -1489,7 +1499,9 @@
{
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",
@@ -1519,6 +1531,11 @@
{
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, "
@@ -1547,6 +1564,9 @@
{
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): "
@@ -1571,8 +1591,19 @@
#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_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);
@@ -1596,6 +1627,7 @@
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);
@@ -1640,6 +1672,9 @@
&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",
@@ -1662,10 +1697,20 @@
}
#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
+ 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;
@@ -1701,6 +1746,9 @@
&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",
@@ -1723,10 +1771,18 @@
}
#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
+ 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;
@@ -1746,6 +1802,8 @@
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 1b0c896..3e065c6 100644
--- a/zebra/rtread_getmsg.c
+++ b/zebra/rtread_getmsg.c
@@ -90,7 +90,7 @@
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 93ec238..1de435a 100644
--- a/zebra/rtread_proc.c
+++ b/zebra/rtread_proc.c
@@ -96,7 +96,7 @@
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 02c73d1..693b333 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 @@
}
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 @@
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);
@@ -249,7 +253,7 @@
static struct nexthop *
nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4,
- unsigned int ifindex)
+ struct in_addr *src, unsigned int ifindex)
{
struct nexthop *nexthop;
@@ -257,6 +261,8 @@
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 @@
}
#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 @@
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 @@
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 @@
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 @@
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 @@
}
-#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 @@
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 @@
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 @@
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);
@@ -1563,7 +1600,7 @@
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_vty.c b/zebra/zebra_vty.c
index 68e6f92..1487745 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,59 @@
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 */
+
+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;
+
+ 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;
+}
+
+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;
+
+ 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;
+}
+
/* New RIB. Detailed information for IPv4 route. */
static void
vty_show_ip_route_detail (struct vty *vty, struct route_node *rn)
@@ -529,6 +583,8 @@
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
{
+ char addrstr[32];
+
vty_out (vty, " %c",
CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' ');
@@ -575,6 +631,31 @@
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 +739,29 @@
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");
@@ -1805,6 +1909,34 @@
return CMD_SUCCESS;
}
+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;
+}
/* Write IPv6 static route configuration. */
static int
@@ -1874,6 +2006,27 @@
return write;
}
+/* 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 (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);
+
+ return 1;
+}
+
+/* table node for protocol filtering */
+struct cmd_node protocol_node = { PROTOCOL_NODE, "", 1 };
+
/* IP node for static routes. */
struct cmd_node ip_node = { IP_NODE, "", 1 };
@@ -1882,7 +2035,12 @@
zebra_vty_init (void)
{
install_node (&ip_node, zebra_ip_config);
+ install_node (&protocol_node, config_write_protocol);
+ 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_flags_cmd);
install_element (CONFIG_NODE, &ip_route_flags2_cmd);
diff --git a/zebra/zserv.c b/zebra/zserv.c
index 1703d3f..22a6bed 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -781,7 +781,7 @@
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 @@
install_element (CONFIG_NODE, &ipv6_forwarding_cmd);
install_element (CONFIG_NODE, &no_ipv6_forwarding_cmd);
#endif /* HAVE_IPV6 */
+
+ /* Route-map */
+ zebra_route_map_init ();
}
diff --git a/zebra/zserv.h b/zebra/zserv.h
index 9a570fb..68c26f2 100644
--- a/zebra/zserv.h
+++ b/zebra/zserv.h
@@ -93,6 +93,7 @@
extern void interface_list (void);
extern void kernel_init (void);
extern void route_read (void);
+extern void zebra_route_map_init (void);
extern void zebra_snmp_init (void);
extern void zebra_vty_init (void);