From 7514fb7739f74311830e9ddd1381d0d228224f61 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 2 May 2007 16:05:35 +0000 Subject: [zebra] Routemap support on received routes, with 'set src' command (linux) 2007-05-01 David L Stevens * (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 --- doc/ChangeLog | 5 ++ doc/main.texi | 53 +++++++++++++++++ lib/ChangeLog | 13 +++++ lib/command.h | 1 + lib/log.c | 14 +++++ lib/routemap.c | 22 ++++--- lib/routemap.h | 3 +- lib/zebra.h | 3 + vtysh/ChangeLog | 7 +++ vtysh/extract.pl.in | 6 +- vtysh/vtysh.h | 2 +- zebra/ChangeLog | 36 ++++++++++++ zebra/Makefile.am | 2 +- zebra/connected.c | 4 +- zebra/kernel_socket.c | 2 +- zebra/main.c | 2 + zebra/rib.h | 33 +++++------ zebra/rt_netlink.c | 84 ++++++++++++++++++++++----- zebra/rtread_getmsg.c | 2 +- zebra/rtread_proc.c | 2 +- zebra/zebra_rib.c | 57 ++++++++++++++---- zebra/zebra_vty.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++ zebra/zserv.c | 5 +- zebra/zserv.h | 1 + 24 files changed, 453 insertions(+), 64 deletions(-) diff --git a/doc/ChangeLog b/doc/ChangeLog index 586852c6..b8c81e74 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,8 @@ +2007-05-01 David L Stevens + + * main.texi: added route-map, prefix-list, ip protocol + and set src documentation + 2007-04-30 Andrew J. Schorr * ospfd.texi: Add a paragraph to the description of the OSPFv2 diff --git a/doc/main.texi b/doc/main.texi index b76a636b..9966b356 100644 --- a/doc/main.texi +++ b/doc/main.texi @@ -10,6 +10,7 @@ different routing protocols. * 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 @@ and later). After setting @var{tableno} with this command, 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 @@ C* 203.181.89.240/28 eth0 @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 f8fdd11e..3787b68c 100644 --- a/lib/ChangeLog +++ b/lib/ChangeLog @@ -1,3 +1,16 @@ +2007-05-01 David L Stevens + + * (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 * log.c: (quagga_timestamp) Optimize the subsecond timestamp generation. diff --git a/lib/command.h b/lib/command.h index ce18731e..a7253788 100644 --- a/lib/command.h +++ b/lib/command.h @@ -99,6 +99,7 @@ enum node_type 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 21bf3f2f..cbf76af9 100644 --- a/lib/log.c +++ b/lib/log.c @@ -886,3 +886,17 @@ zserv_command_string (unsigned int command) } 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; inext) + 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]); + const 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/lib/zebra.h b/lib/zebra.h index 2e2f8cda..85537399 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -444,6 +444,9 @@ extern const char *zebra_route_string(unsigned int route_type); 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 4ca5df94..a582b959 100644 --- a/vtysh/ChangeLog +++ b/vtysh/ChangeLog @@ -1,3 +1,10 @@ +2007-05-01 David L Stevens + + * 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 * vtysh.c: (vtysh_log_timestamp_precision, 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/vtysh/vtysh.h b/vtysh/vtysh.h index dd2bcbd0..3ed0dd32 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 11e406d4..c08bbe4e 100644 --- a/zebra/ChangeLog +++ b/zebra/ChangeLog @@ -1,3 +1,39 @@ +2007-05-01 David L Stevens + + * (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 * ioctl{_solaris,}.c: (if_get_mtu) Fix missing ; in last commit. 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 74e10ac6..53aa2543 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -187,8 +187,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 52812367..b7c7ccc1 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -775,7 +775,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 ed45bd13..7d895799 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 @@ 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 e2f1f9d9..3b602c45 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -725,6 +725,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h) void *dest; void *gate; + void *src; rtm = NLMSG_DATA (h); @@ -764,6 +765,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]); @@ -773,6 +775,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]); @@ -787,7 +792,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) @@ -834,6 +839,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) int table; void *dest; void *gate; + void *src; rtm = NLMSG_DATA (h); @@ -890,6 +896,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]); @@ -902,6 +909,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; @@ -920,7 +930,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); } @@ -1489,7 +1499,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", @@ -1519,6 +1531,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, " @@ -1547,6 +1564,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): " @@ -1571,8 +1591,19 @@ 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_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 @@ 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); @@ -1640,6 +1672,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", @@ -1662,10 +1697,20 @@ 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 + 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 @@ 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", @@ -1723,10 +1771,18 @@ 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 + 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 @@ 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 02c73d12..693b3331 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); @@ -249,7 +253,7 @@ 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) + 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); @@ -1563,7 +1600,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_vty.c b/zebra/zebra_vty.c index 68e6f920..1487745b 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -21,6 +21,7 @@ #include +#include "memory.h" #include "if.h" #include "prefix.h" #include "command.h" @@ -474,6 +475,59 @@ 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 */ + +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 @@ 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 +631,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 +739,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"); @@ -1805,6 +1909,34 @@ DEFUN (show_ipv6_route_prefix, 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