zebra: Add route-map support to ip import-table

Added the ability to supply a route-map to the ip import-table command,
which greatly improves filtering between the kernel prefixes in a
non-default table that are imported into the zebra rib.

Ticket:CM-8168
Signed-off-by: Donald Slice
Reviewed By: Donald Sharp
This commit is contained in:
Don Slice 2016-05-11 08:47:02 -07:00 committed by Donald Sharp
parent 5c81b96aca
commit 8902474bd3
9 changed files with 266 additions and 67 deletions

View File

@ -36,6 +36,7 @@
#include "zebra/zserv.h"
#include "zebra/zebra_ns.h"
#include "zebra/zebra_vrf.h"
#include "zebra/zebra_routemap.h"
#include "zebra/redistribute.h"
#include "zebra/debug.h"
#include "zebra/router-id.h"
@ -559,52 +560,64 @@ zebra_interface_vrf_update_add (struct interface *ifp, vrf_id_t old_vrf_id)
}
int
zebra_add_import_table_entry (struct route_node *rn, struct rib *rib)
zebra_add_import_table_entry (struct route_node *rn, struct rib *rib, const char *rmap_name)
{
struct rib *newrib;
struct prefix_ipv4 p4;
struct nexthop *nhop;
struct in_addr *gate;
route_map_result_t ret = RMAP_MATCH;
if (rn->p.family == AF_INET)
if (rmap_name)
ret = zebra_import_table_route_map_check (AFI_IP, rib->type, &rn->p, rib->nexthop, rib->vrf_id,
rib->tag, rmap_name);
if (ret == RMAP_MATCH)
{
p4.family = AF_INET;
p4.prefixlen = rn->p.prefixlen;
p4.prefix = rn->p.u.prefix4;
if (rn->p.family == AF_INET)
{
p4.family = AF_INET;
p4.prefixlen = rn->p.prefixlen;
p4.prefix = rn->p.u.prefix4;
if (rib->nexthop_num == 1)
{
nhop = rib->nexthop;
if (nhop->type == NEXTHOP_TYPE_IFINDEX)
gate = NULL;
else
gate = &nhop->gate.ipv4;
if (rib->nexthop_num == 1)
{
nhop = rib->nexthop;
if (nhop->type == NEXTHOP_TYPE_IFINDEX)
gate = NULL;
else
gate = &nhop->gate.ipv4;
rib_add_ipv4(ZEBRA_ROUTE_TABLE, rib->table, 0, &p4,
gate, &nhop->src.ipv4,
nhop->ifindex, rib->vrf_id, zebrad.rtm_table_default,
rib->metric,
zebra_import_table_distance[AFI_IP][rib->table],
SAFI_UNICAST);
}
else if (rib->nexthop_num > 1)
{
newrib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
newrib->type = ZEBRA_ROUTE_TABLE;
newrib->distance = zebra_import_table_distance[AFI_IP][rib->table];
newrib->flags = rib->flags;
newrib->metric = rib->metric;
newrib->table = zebrad.rtm_table_default;
newrib->nexthop_num = 0;
newrib->uptime = time(NULL);
newrib->instance = rib->table;
rib_add_ipv4(ZEBRA_ROUTE_TABLE, rib->table, 0, &p4,
gate, &nhop->src.ipv4,
nhop->ifindex, rib->vrf_id, zebrad.rtm_table_default,
rib->metric,
zebra_import_table_distance[AFI_IP][rib->table],
SAFI_UNICAST);
}
else if (rib->nexthop_num > 1)
{
newrib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
newrib->type = ZEBRA_ROUTE_TABLE;
newrib->distance = zebra_import_table_distance[AFI_IP][rib->table];
newrib->flags = rib->flags;
newrib->metric = rib->metric;
newrib->table = zebrad.rtm_table_default;
newrib->nexthop_num = 0;
newrib->uptime = time(NULL);
newrib->instance = rib->table;
/* Assuming these routes are never recursive */
for (nhop = rib->nexthop; nhop; nhop = nhop->next)
rib_copy_nexthops(newrib, nhop);
/* Assuming these routes are never recursive */
for (nhop = rib->nexthop; nhop; nhop = nhop->next)
rib_copy_nexthops(newrib, nhop);
rib_add_ipv4_multipath(&p4, newrib, SAFI_UNICAST);
}
rib_add_ipv4_multipath(&p4, newrib, SAFI_UNICAST);
}
}
}
else
{
zebra_del_import_table_entry (rn, rib);
}
/* DD: Add IPv6 code */
return 0;
@ -631,7 +644,7 @@ zebra_del_import_table_entry (struct route_node *rn, struct rib *rib)
/* Assuming no one calls this with the main routing table */
int
zebra_import_table (afi_t afi, u_int32_t table_id, u_int32_t distance, int add)
zebra_import_table (afi_t afi, u_int32_t table_id, u_int32_t distance, const char *rmap_name, int add)
{
struct route_table *table;
struct rib *rib;
@ -657,6 +670,15 @@ zebra_import_table (afi_t afi, u_int32_t table_id, u_int32_t distance, int add)
if (add)
{
if (rmap_name)
zebra_add_import_table_route_map (afi, rmap_name, table_id);
else
{
rmap_name = zebra_get_import_table_route_map (afi, table_id);
if (rmap_name)
zebra_del_import_table_route_map (afi, table_id);
}
SET_FLAG(zebra_import_table_used[table_id], afi);
zebra_import_table_distance[afi][table_id] = distance;
}
@ -664,6 +686,10 @@ zebra_import_table (afi_t afi, u_int32_t table_id, u_int32_t distance, int add)
{
UNSET_FLAG(zebra_import_table_used[table_id], (u_char)afi);
zebra_import_table_distance[afi][table_id] = ZEBRA_TABLE_DISTANCE_DEFAULT;
rmap_name = zebra_get_import_table_route_map (afi, table_id);
if (rmap_name)
zebra_del_import_table_route_map (afi, table_id);
}
for (rn = route_top(table); rn; rn = route_next(rn))
@ -688,7 +714,7 @@ zebra_import_table (afi_t afi, u_int32_t table_id, u_int32_t distance, int add)
((afi == AFI_IP6) && (rn->p.family == AF_INET6)))
{
if (add)
zebra_add_import_table_entry (rn, rib);
zebra_add_import_table_entry (rn, rib, rmap_name);
else
zebra_del_import_table_entry (rn, rib);
}
@ -703,6 +729,7 @@ zebra_import_table_config (struct vty *vty)
afi_t afi;
int write = 0;
char afi_str[AFI_MAX][6] = {"", "ip", "ipv6"};
const char *rmap_name;
for (afi = AFI_IP; afi < AFI_MAX; afi++)
{
@ -712,14 +739,19 @@ zebra_import_table_config (struct vty *vty)
{
if (zebra_import_table_distance[afi][i] != ZEBRA_TABLE_DISTANCE_DEFAULT)
{
vty_out(vty, "%s import-table %d distance %d%s", afi_str[afi],
i, zebra_import_table_distance[afi][i], VTY_NEWLINE);
vty_out(vty, "%s import-table %d distance %d", afi_str[afi],
i, zebra_import_table_distance[afi][i]);
}
else
{
vty_out(vty, "%s import-table %d%s", afi_str[afi], i,
VTY_NEWLINE);
vty_out(vty, "%s import-table %d", afi_str[afi], i);
}
rmap_name = zebra_get_import_table_route_map (afi, i);
if (rmap_name)
vty_out(vty, " route-map %s", rmap_name);
vty_out(vty, "%s", VTY_NEWLINE);
write = 1;
}
}
@ -727,3 +759,53 @@ zebra_import_table_config (struct vty *vty)
return write;
}
void
zebra_import_table_rm_update ()
{
afi_t afi;
int i;
struct route_table *table;
struct rib *rib;
struct route_node *rn;
const char *rmap_name;
for (afi = AFI_IP; afi < AFI_MAX; afi++)
{
for (i = 1; i < ZEBRA_KERNEL_TABLE_MAX; i++)
{
if (is_zebra_import_table_enabled(afi, i))
{
rmap_name = zebra_get_import_table_route_map (afi, i);
if (!rmap_name)
return;
table = zebra_vrf_other_route_table(afi, i, VRF_DEFAULT);
for (rn = route_top(table); rn; rn = route_next(rn))
{
/* For each entry in the non-default routing table,
* add the entry in the main table
*/
if (!rn->info)
continue;
RNODE_FOREACH_RIB (rn, rib)
{
if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
continue;
break;
}
if (!rib)
continue;
if (((afi == AFI_IP) && (rn->p.family == AF_INET)) ||
((afi == AFI_IP6) && (rn->p.family == AF_INET6)))
zebra_add_import_table_entry (rn, rib, rmap_name);
}
}
}
}
return;
}

View File

@ -51,17 +51,20 @@ extern void zebra_interface_address_delete_update (struct interface *,
struct connected *c);
extern void zebra_interface_vrf_update_del (struct interface *, vrf_id_t new_vrf_id);
extern void zebra_interface_vrf_update_add (struct interface *, vrf_id_t old_vrf_id);
extern int zebra_import_table (afi_t afi, u_int32_t table_id,
u_int32_t metric, int add);
u_int32_t distance, const char *rmap_name, int add);
extern int zebra_add_import_table_entry (struct route_node *rn,
struct rib *rib);
struct rib *rib, const char *rmap_name);
extern int zebra_del_import_table_entry (struct route_node *rn,
struct rib *rib);
extern int is_zebra_import_table_enabled(afi_t, u_int32_t table_id);
extern int zebra_import_table_config(struct vty *);
extern void zebra_import_table_rm_update(void);
extern int is_default (struct prefix *);
#endif /* _ZEBRA_REDISTRIBUTE_H */

View File

@ -65,11 +65,11 @@ void zebra_interface_vrf_update_del (struct interface *a, vrf_id_t new_vrf_id)
void zebra_interface_vrf_update_add (struct interface *a, vrf_id_t old_vrf_id)
{ return; }
int zebra_import_table (afi_t afi, u_int32_t table_id, u_int32_t metric,
int add)
int zebra_import_table (afi_t afi, u_int32_t table_id, u_int32_t distance,
const char *rmap_name, int add)
{ return 0; }
int zebra_add_import_table_entry (struct route_node *rn, struct rib *rib)
int zebra_add_import_table_entry (struct route_node *rn, struct rib *rib, const char *rmap_name)
{ return 0; }
int zebra_del_import_table_entry (struct route_node *rn, struct rib *rib)
@ -80,3 +80,6 @@ int is_zebra_import_table_enabled(afi_t afi, u_int32_t table_id)
int zebra_import_table_config(struct vty *vty)
{ return 0; }
void zebra_import_table_rm_update()
{ return; }

View File

@ -43,6 +43,7 @@
#include "zebra/zserv.h"
#include "zebra/zebra_vrf.h"
#include "zebra/redistribute.h"
#include "zebra/zebra_routemap.h"
#include "zebra/debug.h"
#include "zebra/zebra_fpm.h"
#include "zebra/zebra_rnh.h"
@ -2130,6 +2131,7 @@ rib_link (struct route_node *rn, struct rib *rib, int process)
rib_dest_t *dest;
char buf[INET6_ADDRSTRLEN];
afi_t afi;
const char *rmap_name;
assert (rib && rn);
@ -2160,7 +2162,10 @@ rib_link (struct route_node *rn, struct rib *rib, int process)
afi = (rn->p.family == AF_INET) ? AFI_IP :
(rn->p.family == AF_INET6) ? AFI_IP6 : AFI_MAX;
if (is_zebra_import_table_enabled (afi, rib->table))
zebra_add_import_table_entry(rn, rib);
{
rmap_name = zebra_get_import_table_route_map (afi, rib->table);
zebra_add_import_table_entry(rn, rib, rmap_name);
}
else
if (process)
rib_queue_add (rn);

View File

@ -46,6 +46,7 @@
#include "zebra/redistribute.h"
#include "zebra/debug.h"
#include "zebra/zebra_rnh.h"
#include "zebra/zebra_routemap.h"
#include "zebra/interface.h"
static void free_state(vrf_id_t vrf_id, struct rib *rib, struct route_node *rn);

View File

@ -32,6 +32,7 @@
#include "vrf.h"
#include "zebra/zserv.h"
#include "zebra/redistribute.h"
#include "zebra/debug.h"
#include "zebra/zebra_rnh.h"
#include "zebra/zebra_routemap.h"
@ -41,6 +42,7 @@ static struct thread *zebra_t_rmap_update = NULL;
char *proto_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1]; /* "any" == ZEBRA_ROUTE_MAX */
/* NH Tracking route map */
char *nht_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1]; /* "any" == ZEBRA_ROUTE_MAX */
char *zebra_import_table_routemap[AFI_MAX][ZEBRA_KERNEL_TABLE_MAX];
struct nh_rmap_obj
{
@ -1610,6 +1612,7 @@ zebra_route_map_update_timer (struct thread *thread)
zlog_debug ("%u: Routemap update-timer fired, scheduling RIB processing",
VRF_DEFAULT);
zebra_import_table_rm_update ();
rib_update(VRF_DEFAULT, RIB_UPDATE_RMAP_CHANGE);
zebra_evaluate_rnh(0, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL);
zebra_evaluate_rnh(0, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL);
@ -1664,6 +1667,47 @@ zebra_route_map_check (int family, int rib_type, struct prefix *p,
return (ret);
}
char *
zebra_get_import_table_route_map (afi_t afi, uint32_t table)
{
return zebra_import_table_routemap[afi][table];
}
void
zebra_add_import_table_route_map (afi_t afi, const char *rmap_name, uint32_t table)
{
zebra_import_table_routemap[afi][table] = XSTRDUP (MTYPE_ROUTE_MAP_NAME, rmap_name);
}
void
zebra_del_import_table_route_map (afi_t afi, uint32_t table)
{
XFREE (MTYPE_ROUTE_MAP_NAME, zebra_import_table_routemap[afi][table]);
}
route_map_result_t
zebra_import_table_route_map_check (int family, int rib_type, struct prefix *p,
struct nexthop *nexthop, vrf_id_t vrf_id, u_short tag, const char *rmap_name)
{
struct route_map *rmap = NULL;
route_map_result_t ret = RMAP_DENYMATCH;
struct nh_rmap_obj nh_obj;
nh_obj.nexthop = nexthop;
nh_obj.vrf_id = vrf_id;
nh_obj.source_protocol = rib_type;
nh_obj.metric = 0;
nh_obj.tag = tag;
if (rib_type >= 0 && rib_type < ZEBRA_ROUTE_MAX)
rmap = route_map_lookup_by_name (rmap_name);
if (rmap) {
ret = route_map_apply(rmap, p, RMAP_ZEBRA, &nh_obj);
}
return (ret);
}
route_map_result_t
zebra_nht_route_map_check (int family, int client_proto, struct prefix *p,
struct rib * rib, struct nexthop *nexthop)

View File

@ -24,5 +24,28 @@
#define __ZEBRA_ROUTEMAP_H__
extern void zebra_routemap_config_write_protocol(struct vty *vty);
extern char *zebra_get_import_table_route_map (afi_t afi, uint32_t table);
extern void zebra_add_import_table_route_map (afi_t afi, const char *rmap_name, uint32_t table);
extern void zebra_del_import_table_route_map (afi_t afi, uint32_t table);
extern void zebra_route_map_write_delay_timer(struct vty *);
extern route_map_result_t zebra_import_table_route_map_check (int family, int rib_type,
struct prefix *p,
struct nexthop *nexthop,
vrf_id_t vrf_id,
u_short tag,
const char *rmap_name);
extern route_map_result_t zebra_route_map_check (int family, int rib_type,
struct prefix *p,
struct nexthop *nexthop,
vrf_id_t vrf_id,
u_short tag);
extern route_map_result_t zebra_nht_route_map_check (int family,
int client_proto,
struct prefix *p,
struct rib *,
struct nexthop *nexthop);
#endif

View File

@ -5646,13 +5646,9 @@ DEFUN (ip_zebra_import_table_distance,
return CMD_WARNING;
}
if (is_zebra_import_table_enabled(AFI_IP, table_id))
return CMD_SUCCESS;
if (argc > 1)
VTY_GET_INTEGER_RANGE("distance", distance, argv[1], 1, 255);
return (zebra_import_table(AFI_IP, table_id, distance, 1));
return (zebra_import_table(AFI_IP, table_id, distance, NULL, 1));
}
@ -5663,9 +5659,61 @@ ALIAS (ip_zebra_import_table_distance,
"import routes from non-main kernel table\n"
"kernel routing table id\n")
DEFUN (ip_zebra_import_table_distance_routemap,
ip_zebra_import_table_distance_routemap_cmd,
"ip import-table <1-252> distance <1-255> route-map WORD",
IP_STR
"import routes from non-main kernel table\n"
"kernel routing table id\n"
"Distance for imported routes\n"
"Default distance value\n"
"route-map for filtering\n"
"route-map name\n")
{
u_int32_t table_id = 0;
int distance = ZEBRA_TABLE_DISTANCE_DEFAULT;
const char *rmap_name;
if (argc)
VTY_GET_INTEGER("table", table_id, argv[0]);
if (!is_zebra_valid_kernel_table(table_id))
{
vty_out(vty, "Invalid routing table ID, %d. Must be in range 1-252%s",
table_id, VTY_NEWLINE);
return CMD_WARNING;
}
if (is_zebra_main_routing_table(table_id))
{
vty_out(vty, "Invalid routing table ID, %d. Must be non-default table%s",
table_id, VTY_NEWLINE);
return CMD_WARNING;
}
if (argc > 2)
{
VTY_GET_INTEGER_RANGE("distance", distance, argv[1], 1, 255);
rmap_name = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[2]);
}
else
rmap_name = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[1]);
return (zebra_import_table(AFI_IP, table_id, distance, rmap_name, 1));
}
ALIAS (ip_zebra_import_table_distance_routemap,
ip_zebra_import_table_routemap_cmd,
"ip import-table <1-252> route-map WORD",
IP_STR
"import routes from non-main kernel table\n"
"kernel routing table id\n"
"route-map for filtering\n"
"route-map name\n")
DEFUN (no_ip_zebra_import_table,
no_ip_zebra_import_table_cmd,
"no ip import-table <1-252>",
"no ip import-table <1-252> {route-map NAME}",
NO_STR
IP_STR
"import routes from non-main kernel table\n"
@ -5693,12 +5741,12 @@ DEFUN (no_ip_zebra_import_table,
if (!is_zebra_import_table_enabled(AFI_IP, table_id))
return CMD_SUCCESS;
return (zebra_import_table(AFI_IP, table_id, 0, 0));
return (zebra_import_table(AFI_IP, table_id, 0, NULL, 0));
}
ALIAS (no_ip_zebra_import_table,
no_ip_zebra_import_table_distance_cmd,
"no ip import-table <1-252> distance <1-255>",
"no ip import-table <1-252> distance <1-255> {route-map NAME}",
IP_STR
"import routes from non-main kernel table to main table"
"kernel routing table id\n"
@ -5786,6 +5834,8 @@ zebra_vty_init (void)
install_element (CONFIG_NODE, &no_ip_route_mask_flags_tag_distance2_cmd);
install_element (CONFIG_NODE, &ip_zebra_import_table_cmd);
install_element (CONFIG_NODE, &ip_zebra_import_table_distance_cmd);
install_element (CONFIG_NODE, &ip_zebra_import_table_routemap_cmd);
install_element (CONFIG_NODE, &ip_zebra_import_table_distance_routemap_cmd);
install_element (CONFIG_NODE, &no_ip_zebra_import_table_cmd);
install_element (CONFIG_NODE, &no_ip_zebra_import_table_distance_cmd);

View File

@ -171,16 +171,4 @@ extern void zserv_create_header(struct stream *s, uint16_t cmd, vrf_id_t vrf_id)
extern void zserv_nexthop_num_warn(const char *, const struct prefix *, const u_char);
extern int zebra_server_send_message(struct zserv *client);
extern void zebra_route_map_write_delay_timer(struct vty *);
extern route_map_result_t zebra_route_map_check (int family, int rib_type,
struct prefix *p,
struct nexthop *nexthop,
vrf_id_t vrf_id,
u_short tag);
extern route_map_result_t zebra_nht_route_map_check (int family,
int client_proto,
struct prefix *p,
struct rib *,
struct nexthop *nexthop);
#endif /* _ZEBRA_ZEBRA_H */