From 7a4bb9c54e529225cfc59926cf3bd5f858be0155 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 19 May 2015 18:03:42 -0700 Subject: [PATCH] zebra-redistribute-table.patch Zebra: Redistribute routes from non-main kernel table to main. This can be the basis for many interesting features such as variations of redistribute ARP, using zebra as the RIB in the presence of multiple routing protocol stacks etc. The code only supports IPv4 for now, but the infrastructure is in place for IPv6. Usage: There is a new route type introduced by this model: TABLE. Routes imported from alternate kernel tables will have their protocol type set to TABLE. Routes from alternate kernel tables MUST be first imported into the main table via "ip import-table ". They can then be redistributed via a routing protocol via the "redistribute table" command. Each imported table can an optional administrative distance specified. In Zebra, a route with a lower distance is chosen over routes with a higher distance. So, distance is how the user can choose to prioritize routes from a particular table over routes from other tables or routes learnt another way in zebra. Route maps for imported tables are specified via "ip protocol" command in zebra. Route maps for redistributed routes within a routing protocol are subject to the route map options supported by the protocol. The "match source-protocol" option in route maps can match against "table" to filter routes learnt from alternate kernel routing tables. Signed-off-by: Dinesh G Dutt --- bgpd/bgp_vty.c | 103 ++++++++++++++------- lib/log.c | 4 + lib/route_types.txt | 2 + lib/zebra.h | 1 + zebra/main.c | 2 +- zebra/redistribute.c | 190 ++++++++++++++++++++++++++++++++++++++ zebra/redistribute.h | 12 +++ zebra/redistribute_null.c | 17 ++++ zebra/rib.h | 10 +- zebra/rt_netlink.c | 13 +-- zebra/zebra_rib.c | 163 ++++++++++++++++++++++++++++---- zebra/zebra_vty.c | 96 +++++++++++++++++++ 12 files changed, 552 insertions(+), 61 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 3c625755cd..a7b5a90ba7 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -9749,21 +9749,28 @@ DEFUN (bgp_redistribute_ipv4_metric_rmap, DEFUN (bgp_redistribute_ipv4_ospf, bgp_redistribute_ipv4_ospf_cmd, - "redistribute ospf <1-65535>", + "redistribute (ospf|table) <1-65535>", "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" "Instance ID\n") { u_short instance; + u_short protocol; - VTY_GET_INTEGER ("Instance ID", instance, argv[0]); - bgp_redist_add(vty->index, AFI_IP, ZEBRA_ROUTE_OSPF, instance); - return bgp_redistribute_set (ZEBRA_ROUTE_OSPF, instance); + VTY_GET_INTEGER ("Instance ID", instance, argv[1]); + + if (strncmp(argv[0], "o", 1) == 0) + protocol = ZEBRA_ROUTE_OSPF; + else + protocol = ZEBRA_ROUTE_TABLE; + + bgp_redist_add(vty->index, AFI_IP, protocol, instance); + return bgp_redistribute_set (protocol, instance); } DEFUN (bgp_redistribute_ipv4_ospf_rmap, bgp_redistribute_ipv4_ospf_rmap_cmd, - "redistribute ospf <1-65535> route-map WORD", + "redistribute (ospf|table) <1-65535> route-map WORD", "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" "Instance ID\n" @@ -9772,16 +9779,22 @@ DEFUN (bgp_redistribute_ipv4_ospf_rmap, { struct bgp_redist *red; u_short instance; + int protocol; - VTY_GET_INTEGER ("Instance ID", instance, argv[0]); - red = bgp_redist_add(vty->index, AFI_IP, ZEBRA_ROUTE_OSPF, instance); - bgp_redistribute_rmap_set (red, argv[1]); - return bgp_redistribute_set (ZEBRA_ROUTE_OSPF, instance); + if (strncmp(argv[0], "o", 1) == 0) + protocol = ZEBRA_ROUTE_OSPF; + else + protocol = ZEBRA_ROUTE_TABLE; + + VTY_GET_INTEGER ("Instance ID", instance, argv[1]); + red = bgp_redist_add(vty->index, AFI_IP, protocol, instance); + bgp_redistribute_rmap_set (red, argv[2]); + return bgp_redistribute_set (protocol, instance); } DEFUN (bgp_redistribute_ipv4_ospf_metric, bgp_redistribute_ipv4_ospf_metric_cmd, - "redistribute ospf <1-65535> metric <0-4294967295>", + "redistribute (ospf|table) <1-65535> metric <0-4294967295>", "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" "Instance ID\n" @@ -9791,18 +9804,24 @@ DEFUN (bgp_redistribute_ipv4_ospf_metric, u_int32_t metric; struct bgp_redist *red; u_short instance; + int protocol; - VTY_GET_INTEGER ("Instance ID", instance, argv[0]); - VTY_GET_INTEGER ("metric", metric, argv[1]); + if (strncmp(argv[0], "o", 1) == 0) + protocol = ZEBRA_ROUTE_OSPF; + else + protocol = ZEBRA_ROUTE_TABLE; - red = bgp_redist_add(vty->index, AFI_IP, ZEBRA_ROUTE_OSPF, instance); + VTY_GET_INTEGER ("Instance ID", instance, argv[1]); + VTY_GET_INTEGER ("metric", metric, argv[2]); + + red = bgp_redist_add(vty->index, AFI_IP, protocol, instance); bgp_redistribute_metric_set (red, metric); - return bgp_redistribute_set (ZEBRA_ROUTE_OSPF, instance); + return bgp_redistribute_set (protocol, instance); } DEFUN (bgp_redistribute_ipv4_ospf_rmap_metric, bgp_redistribute_ipv4_ospf_rmap_metric_cmd, - "redistribute ospf <1-65535> route-map WORD metric <0-4294967295>", + "redistribute (ospf|table) <1-65535> route-map WORD metric <0-4294967295>", "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" "Instance ID\n" @@ -9814,19 +9833,25 @@ DEFUN (bgp_redistribute_ipv4_ospf_rmap_metric, u_int32_t metric; struct bgp_redist *red; u_short instance; + int protocol; - VTY_GET_INTEGER ("Instance ID", instance, argv[0]); - VTY_GET_INTEGER ("metric", metric, argv[2]); + if (strncmp(argv[0], "o", 1) == 0) + protocol = ZEBRA_ROUTE_OSPF; + else + protocol = ZEBRA_ROUTE_TABLE; - red = bgp_redist_add(vty->index, AFI_IP, ZEBRA_ROUTE_OSPF, instance); - bgp_redistribute_rmap_set (red, argv[1]); + VTY_GET_INTEGER ("Instance ID", instance, argv[1]); + VTY_GET_INTEGER ("metric", metric, argv[3]); + + red = bgp_redist_add(vty->index, AFI_IP, protocol, instance); + bgp_redistribute_rmap_set (red, argv[2]); bgp_redistribute_metric_set (red, metric); - return bgp_redistribute_set (ZEBRA_ROUTE_OSPF, instance); + return bgp_redistribute_set (protocol, instance); } DEFUN (bgp_redistribute_ipv4_ospf_metric_rmap, bgp_redistribute_ipv4_ospf_metric_rmap_cmd, - "redistribute ospf <1-65535> metric <0-4294967295> route-map WORD", + "redistribute (ospf|table) <1-65535> metric <0-4294967295> route-map WORD", "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" "Instance ID\n" @@ -9838,33 +9863,45 @@ DEFUN (bgp_redistribute_ipv4_ospf_metric_rmap, u_int32_t metric; struct bgp_redist *red; u_short instance; + int protocol; - VTY_GET_INTEGER ("Instance ID", instance, argv[0]); - VTY_GET_INTEGER ("metric", metric, argv[1]); + if (strncmp(argv[0], "o", 1) == 0) + protocol = ZEBRA_ROUTE_OSPF; + else + protocol = ZEBRA_ROUTE_TABLE; - red = bgp_redist_add(vty->index, AFI_IP, ZEBRA_ROUTE_OSPF, instance); + VTY_GET_INTEGER ("Instance ID", instance, argv[1]); + VTY_GET_INTEGER ("metric", metric, argv[2]); + + red = bgp_redist_add(vty->index, AFI_IP, protocol, instance); bgp_redistribute_metric_set (red, metric); - bgp_redistribute_rmap_set (red, argv[2]); - return bgp_redistribute_set (ZEBRA_ROUTE_OSPF, instance); + bgp_redistribute_rmap_set (red, argv[3]); + return bgp_redistribute_set (protocol, instance); } DEFUN (no_bgp_redistribute_ipv4_ospf, no_bgp_redistribute_ipv4_ospf_cmd, - "no redistribute ospf <1-65535>", + "no redistribute (ospf|table) <1-65535>", NO_STR "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" "Instance ID\n") { u_short instance; + int protocol; + + if (strncmp(argv[0], "o", 1) == 0) + protocol = ZEBRA_ROUTE_OSPF; + else + protocol = ZEBRA_ROUTE_TABLE; - VTY_GET_INTEGER ("Instance ID", instance, argv[0]); - return bgp_redistribute_unset (vty->index, AFI_IP, ZEBRA_ROUTE_OSPF, instance); + VTY_GET_INTEGER ("Instance ID", instance, argv[1]); + return bgp_redistribute_unset (vty->index, AFI_IP, protocol, instance); } ALIAS (no_bgp_redistribute_ipv4_ospf, no_bgp_redistribute_ipv4_ospf_rmap_cmd, - "no redistribute ospf <1-65535> route-map WORD", + "no redistribute (ospf|table) <1-65535> route-map WORD", NO_STR "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" @@ -9874,7 +9911,7 @@ ALIAS (no_bgp_redistribute_ipv4_ospf, ALIAS (no_bgp_redistribute_ipv4_ospf, no_bgp_redistribute_ipv4_ospf_metric_cmd, - "no redistribute ospf <1-65535> metric <0-4294967295>", + "no redistribute (ospf|table) <1-65535> metric <0-4294967295>", NO_STR "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" @@ -9884,7 +9921,7 @@ ALIAS (no_bgp_redistribute_ipv4_ospf, ALIAS (no_bgp_redistribute_ipv4_ospf, no_bgp_redistribute_ipv4_ospf_rmap_metric_cmd, - "no redistribute ospf <1-65535> route-map WORD metric <0-4294967295>", + "no redistribute (ospf|table) <1-65535> route-map WORD metric <0-4294967295>", NO_STR "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" @@ -9896,7 +9933,7 @@ ALIAS (no_bgp_redistribute_ipv4_ospf, ALIAS (no_bgp_redistribute_ipv4_ospf, no_bgp_redistribute_ipv4_ospf_metric_rmap_cmd, - "no redistribute ospf <1-65535> metric <0-4294967295> route-map WORD", + "no redistribute (ospf|table) <1-65535> metric <0-4294967295> route-map WORD", NO_STR "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" diff --git a/lib/log.c b/lib/log.c index cdca478acd..4acc0cab83 100644 --- a/lib/log.c +++ b/lib/log.c @@ -923,6 +923,8 @@ proto_redistnum(int afi, const char *s) return ZEBRA_ROUTE_BGP; else if (strncmp (s, "ba", 2) == 0) return ZEBRA_ROUTE_BABEL; + else if (strncmp (s, "t", 1) == 0) + return ZEBRA_ROUTE_TABLE; } if (afi == AFI_IP6) { @@ -942,6 +944,8 @@ proto_redistnum(int afi, const char *s) return ZEBRA_ROUTE_BGP; else if (strncmp (s, "ba", 2) == 0) return ZEBRA_ROUTE_BABEL; + else if (strncmp (s, "t", 1) == 0) + return ZEBRA_ROUTE_TABLE; } return -1; } diff --git a/lib/route_types.txt b/lib/route_types.txt index cebf01fca1..d6d8670edb 100644 --- a/lib/route_types.txt +++ b/lib/route_types.txt @@ -59,6 +59,7 @@ ZEBRA_ROUTE_BGP, bgp, bgpd, 'B', 1, 1, "BGP" ZEBRA_ROUTE_HSLS, hsls, hslsd, 'H', 0, 0, "HSLS" ZEBRA_ROUTE_OLSR, olsr, olsrd, 'o', 0, 0, "OLSR" ZEBRA_ROUTE_BABEL, babel, babeld, 'A', 1, 1, "Babel" +ZEBRA_ROUTE_TABLE, table, zebra, 'T', 1, 1, "Table" ## help strings ZEBRA_ROUTE_SYSTEM, "Reserved route type, for internal use only" @@ -74,3 +75,4 @@ ZEBRA_ROUTE_BGP, "Border Gateway Protocol (BGP)" ZEBRA_ROUTE_HSLS, "Hazy-Sighted Link State Protocol (HSLS)" ZEBRA_ROUTE_OLSR, "Optimised Link State Routing (OLSR)" ZEBRA_ROUTE_BABEL, "Babel routing protocol (Babel)" +ZEBRA_ROUTE_TABLE, "Non-main Kernel Routing Table" diff --git a/lib/zebra.h b/lib/zebra.h index 6e73ee3dbf..8b0248a3b6 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -528,6 +528,7 @@ extern const char *zserv_command_string (unsigned int command); #define ZEBRA_ISIS_DISTANCE_DEFAULT 115 #define ZEBRA_IBGP_DISTANCE_DEFAULT 200 #define ZEBRA_EBGP_DISTANCE_DEFAULT 20 +#define ZEBRA_TABLE_DISTANCE_DEFAULT 150 /* Flag manipulation macros. */ #define CHECK_FLAG(V,F) ((V) & (F)) diff --git a/zebra/main.c b/zebra/main.c index 6cff6d45d8..1977e4e3a5 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -374,7 +374,7 @@ main (int argc, char **argv) return(0); /* Clean up rib. */ - rib_weed_tables (); + /* rib_weed_tables (); */ /* Exit when zebra is working in batch mode. */ if (batch_mode) diff --git a/zebra/redistribute.c b/zebra/redistribute.c index b67430d1ae..701b83493f 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -43,6 +43,25 @@ /* master zebra server structure */ extern struct zebra_t zebrad; +/* array holding redistribute info about table redistribution */ +/* bit AFI is set if that AFI is redistributing routes from this table */ +static u_char zebra_import_table_used[ZEBRA_KERNEL_TABLE_MAX]; +static u_int32_t zebra_import_table_distance[AFI_MAX][ZEBRA_KERNEL_TABLE_MAX]; + +int +is_zebra_import_table_enabled(afi_t afi, u_int32_t table_id) +{ + if (is_zebra_valid_kernel_table(table_id)) + { + if (CHECK_FLAG(zebra_import_table_used[table_id], (u_char)afi)) + return 1; + else + return 0; + } + + return 0; +} + int zebra_check_addr (struct prefix *p) { @@ -461,3 +480,174 @@ zebra_interface_bfd_update (struct interface *ifp, struct prefix *p) zsend_interface_bfd_update (ZEBRA_INTERFACE_BFD_DEST_DOWN, client, ifp, p); } } + +int +zebra_add_import_table_entry (struct route_node *rn, struct rib *rib) +{ + struct rib *newrib; + struct prefix_ipv4 p4; + struct nexthop *nhop; + struct in_addr *gate; + + 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) || + (nhop->type == NEXTHOP_TYPE_IFNAME)) + gate = NULL; + else + gate = &nhop->gate.ipv4; + + rib_add_ipv4(ZEBRA_ROUTE_TABLE, rib->table, 0, &p4, + gate, &nhop->src.ipv4, + nhop->ifindex, 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) + copy_nexthops(newrib, nhop); + + rib_add_ipv4_multipath(&p4, newrib, SAFI_UNICAST); + } + } + /* DD: Add IPv6 code */ + return 0; +} + +int +zebra_del_import_table_entry (struct route_node *rn, struct rib *rib) +{ + struct prefix_ipv4 p4; + + if (rn->p.family == AF_INET) + { + p4.family = AF_INET; + p4.prefixlen = rn->p.prefixlen; + p4.prefix = rn->p.u.prefix4; + + rib_delete_ipv4(ZEBRA_ROUTE_TABLE, rib->table, rib->flags, &p4, NULL, + 0, zebrad.rtm_table_default, SAFI_UNICAST); + } + /* DD: Add IPv6 code */ + + return 0; +} + +/* 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) +{ + struct route_table *table; + struct rib *rib; + struct route_node *rn; + + if (!is_zebra_valid_kernel_table(table_id) || + ((table_id == RT_TABLE_MAIN) || (table_id == zebrad.rtm_table_default))) + return (-1); + + if (afi >= AFI_MAX) + return (-1); + + table = vrf_other_route_table(afi, table_id, 0); + if (table == NULL) + { + return 0; + } + else if (IS_ZEBRA_DEBUG_RIB) + { + zlog_debug ("%s routes from table %d", + add ? "Importing" : "Unimporting", table_id); + } + + if (add) + { + SET_FLAG(zebra_import_table_used[table_id], afi); + zebra_import_table_distance[afi][table_id] = distance; + } + else + { + UNSET_FLAG(zebra_import_table_used[table_id], (u_char)afi); + zebra_import_table_distance[afi][table_id] = ZEBRA_TABLE_DISTANCE_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)) + { + if (add) + zebra_add_import_table_entry (rn, rib); + else + zebra_del_import_table_entry (rn, rib); + } + } + return 0; +} + +int +zebra_import_table_config (struct vty *vty) +{ + int i; + afi_t afi; + int write = 0; + char afi_str[AFI_MAX][6] = {"", "ip", "ipv6"}; + + 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)) + { + 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); + } + else + { + vty_out(vty, "%s import-table %d%s", afi_str[afi], i, + VTY_NEWLINE); + } + write = 1; + } + } + } + + return write; +} diff --git a/zebra/redistribute.h b/zebra/redistribute.h index 8ed39fce28..aef944ca22 100644 --- a/zebra/redistribute.h +++ b/zebra/redistribute.h @@ -25,6 +25,7 @@ #include "table.h" #include "zserv.h" +#include "vty.h" extern void zebra_redistribute_add (int, struct zserv *, int); extern void zebra_redistribute_delete (int, struct zserv *, int); @@ -48,5 +49,16 @@ extern void zebra_interface_address_delete_update (struct interface *, extern void zebra_interface_bfd_update (struct interface *, struct prefix *); extern int zebra_check_addr (struct prefix *); +extern int zebra_import_table (afi_t afi, u_int32_t table_id, + u_int32_t metric, int add); + +extern int zebra_add_import_table_entry (struct route_node *rn, + struct rib *rib); +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 *); + #endif /* _ZEBRA_REDISTRIBUTE_H */ diff --git a/zebra/redistribute_null.c b/zebra/redistribute_null.c index 2c31a85b3b..c40938c4d9 100644 --- a/zebra/redistribute_null.c +++ b/zebra/redistribute_null.c @@ -55,3 +55,20 @@ void zebra_interface_address_delete_update (struct interface *a, #endif void zebra_interface_bfd_update (struct interface *a, struct prefix *b) { return; } + + +int zebra_import_table (afi_t afi, u_int32_t table_id, u_int32_t metric, + int add) +{ return 0; } + +int zebra_add_import_table_entry (struct route_node *rn, struct rib *rib) +{ return 0; } + +int zebra_del_import_table_entry (struct route_node *rn, struct rib *rib) +{ return 0; } + +int is_zebra_import_table_enabled(afi_t afi, u_int32_t table_id) +{ return 0; } + +int zebra_import_table_config(struct vty *vty) +{ return 0; } diff --git a/zebra/rib.h b/zebra/rib.h index e3c606f42c..58d3315a9e 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -29,6 +29,7 @@ #include "nexthop.h" #define DISTANCE_INFINITY 255 +#define ZEBRA_KERNEL_TABLE_MAX 252 /* support for no more than this rt tables */ struct rib { @@ -52,7 +53,7 @@ struct rib u_short instance; /* Which routing table */ - int table; + int table; /* Metric */ u_int32_t metric; @@ -299,6 +300,9 @@ struct vrf /* Recursive Nexthop table */ struct route_table *rnh_table[AFI_MAX]; + + /* Routing tables off of main table for redistribute table */ + struct route_table *other_table[AFI_MAX][ZEBRA_KERNEL_TABLE_MAX]; }; /* @@ -382,6 +386,10 @@ rib_bogus_ipv6 (int type, struct prefix_ipv6 *p, extern struct vrf *vrf_lookup (u_int32_t); extern struct route_table *vrf_table (afi_t afi, safi_t safi, u_int32_t id); extern struct route_table *vrf_static_table (afi_t afi, safi_t safi, u_int32_t id); +extern struct route_table *vrf_other_route_table (afi_t afi, u_int32_t table_id, + u_int32_t vrf_id); +extern int is_zebra_valid_kernel_table(u_int32_t table_id); +extern int is_zebra_main_routing_table(u_int32_t table_id); /* NOTE: * All rib_add_ipv[46]* functions will not just add prefix into RIB, but diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 1fa4593f4b..3410e4e1ea 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -225,7 +225,6 @@ netlink_request (int family, int type, struct nlsock *nl) struct rtgenmsg g; } req; - /* Check netlink socket. */ if (nl->sock < 0) { @@ -254,7 +253,7 @@ netlink_request (int family, int type, struct nlsock *nl) } ret = sendto (nl->sock, (void *) &req, sizeof req, 0, - (struct sockaddr *) &snl, sizeof snl); + (struct sockaddr *) &snl, sizeof snl); save_errno = errno; if (zserv_privs.change (ZPRIVS_LOWER)) @@ -686,10 +685,8 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h) return 0; table = rtm->rtm_table; -#if 0 /* we weed them out later in rib_weed_tables () */ - if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default) - return 0; -#endif + if (!is_zebra_valid_kernel_table(table) && !is_zebra_main_routing_table(table)) + return 0; len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg)); if (len < 0) @@ -875,10 +872,8 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) } table = rtm->rtm_table; - if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default) - { + if (!is_zebra_valid_kernel_table(table) && !is_zebra_main_routing_table(table)) return 0; - } len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg)); if (len < 0) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index f55302e135..77ff7775d0 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -181,6 +181,49 @@ vrf_static_table (afi_t afi, safi_t safi, u_int32_t id) return vrf->stable[afi][safi]; } +struct route_table * +vrf_other_route_table (afi_t afi, u_int32_t table_id, u_int32_t vrf_id) +{ + struct vrf *vrf; + + vrf = vrf_lookup (vrf_id); + if (! vrf) + return NULL; + + if(afi >= AFI_MAX) + return NULL; + + if (table_id >= ZEBRA_KERNEL_TABLE_MAX) + return NULL; + + if (vrf->other_table[afi][table_id] == NULL) + { + vrf->other_table[afi][table_id] = route_table_init(); + } + + return (vrf->other_table[afi][table_id]); +} + +int +is_zebra_valid_kernel_table(u_int32_t table_id) +{ + if ((table_id > ZEBRA_KERNEL_TABLE_MAX) || + (table_id == RT_TABLE_UNSPEC) || + (table_id == RT_TABLE_LOCAL) || + (table_id == RT_TABLE_COMPAT)) + return 0; + else + return 1; +} + +int +is_zebra_main_routing_table(u_int32_t table_id) +{ + if ((table_id == RT_TABLE_MAIN) || (table_id == zebrad.rtm_table_default)) + return 1; + return 0; +} + /* Add nexthop to the end of a nexthop list. */ void _nexthop_add (struct nexthop **target, struct nexthop *nexthop) @@ -1127,7 +1170,12 @@ nexthop_active_check (struct route_node *rn, struct rib *rib, int family; char buf[INET6_ADDRSTRLEN+1]; - family = 0; + if (rn->p.family == AF_INET) + family = AFI_IP; + else if (rn->p.family == AF_INET6) + family = AFI_IP6; + else + family = 0; switch (nexthop->type) { case NEXTHOP_TYPE_IFINDEX: @@ -1734,6 +1782,7 @@ static const u_char meta_queue_map[ZEBRA_ROUTE_MAX] = { [ZEBRA_ROUTE_BGP] = 3, [ZEBRA_ROUTE_HSLS] = 4, [ZEBRA_ROUTE_BABEL] = 2, + [ZEBRA_ROUTE_TABLE] = 1, }; /* Look into the RN and queue it into one or more priority queues, @@ -1916,6 +1965,7 @@ rib_link (struct route_node *rn, struct rib *rib) struct rib *head; rib_dest_t *dest; char buf[INET6_ADDRSTRLEN]; + afi_t afi; assert (rib && rn); @@ -1948,7 +1998,22 @@ rib_link (struct route_node *rn, struct rib *rib) } rib->next = head; dest->routes = rib; - rib_queue_add (&zebrad, rn); + + /* Further processing only if entry is in main table */ + if ((rib->table == RT_TABLE_MAIN) || (rib->table == zebrad.rtm_table_default)) + rib_queue_add (&zebrad, rn); + else + { + if (IS_ZEBRA_DEBUG_RIB) + { + zlog_debug ("%s: %s/%d: Skipping further RIB processing of non-main table", + __func__, buf, rn->p.prefixlen); + } + 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); + } } static void @@ -2017,6 +2082,8 @@ rib_unlink (struct route_node *rn, struct rib *rib) static void rib_delnode (struct route_node *rn, struct rib *rib) { + afi_t afi; + if (IS_ZEBRA_DEBUG_RIB) { char buf[INET6_ADDRSTRLEN]; @@ -2025,13 +2092,24 @@ rib_delnode (struct route_node *rn, struct rib *rib) buf, rn->p.prefixlen, rn, rib); } SET_FLAG (rib->status, RIB_ENTRY_REMOVED); - rib_queue_add (&zebrad, rn); + + if ((rib->table == RT_TABLE_MAIN) || (rib->table == zebrad.rtm_table_default)) + rib_queue_add (&zebrad, rn); + else + { + 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_del_import_table_entry(rn, rib); + /* Just clean up if non main table */ + rib_unlink(rn, rib); + } } int rib_add_ipv4 (int type, u_short instance, int flags, struct prefix_ipv4 *p, struct in_addr *gate, struct in_addr *src, - unsigned int ifindex, u_int32_t vrf_id, + unsigned int ifindex, u_int32_t table_id, u_int32_t metric, u_char distance, safi_t safi) { struct rib *rib; @@ -2041,7 +2119,14 @@ rib_add_ipv4 (int type, u_short instance, int flags, struct prefix_ipv4 *p, struct nexthop *nexthop; /* Lookup table. */ - table = vrf_table (AFI_IP, safi, 0); + if ((table_id == RT_TABLE_MAIN) || (table_id == zebrad.rtm_table_default)) + { + table = vrf_table (AFI_IP, safi, 0); + } + else + { + table = vrf_other_route_table (AFI_IP, table_id, 0); + } if (! table) return 0; @@ -2075,6 +2160,7 @@ rib_add_ipv4 (int type, u_short instance, int flags, struct prefix_ipv4 *p, continue; if (rib->instance != instance) continue; + if (rib->type != ZEBRA_ROUTE_CONNECT) { same = rib; @@ -2098,7 +2184,7 @@ rib_add_ipv4 (int type, u_short instance, int flags, struct prefix_ipv4 *p, rib->distance = distance; rib->flags = flags; rib->metric = metric; - rib->table = vrf_id; + rib->table = table_id; rib->nexthop_num = 0; rib->uptime = time (NULL); @@ -2120,7 +2206,11 @@ rib_add_ipv4 (int type, u_short instance, int flags, struct prefix_ipv4 *p, /* Link new rib to node.*/ if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%s: calling rib_addnode (%p, %p)", __func__, rn, rib); + { + zlog_debug ("%s: called rib_addnode (%p, %p) on new RIB entry", + __func__, rn, rib); + rib_dump ((struct prefix *)p, rib); + } rib_addnode (rn, rib); /* Free implicit route.*/ @@ -2306,7 +2396,14 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi) int ret = 0; /* Lookup table. */ - table = vrf_table (AFI_IP, safi, 0); + if ((rib->table == zebrad.rtm_table_default) || (rib->table == RT_TABLE_MAIN)) + { + table = vrf_table (AFI_IP, safi, 0); + } + else + { + table = vrf_other_route_table (AFI_IP, rib->table, 0); + } if (! table) return 0; @@ -2375,7 +2472,8 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi) /* XXX factor with rib_delete_ipv6 */ int rib_delete_ipv4 (int type, u_short instance, int flags, struct prefix_ipv4 *p, - struct in_addr *gate, unsigned int ifindex, u_int32_t vrf_id, safi_t safi) + struct in_addr *gate, unsigned int ifindex, + u_int32_t table_id, safi_t safi) { struct route_table *table; struct route_node *rn; @@ -2388,7 +2486,14 @@ rib_delete_ipv4 (int type, u_short instance, int flags, struct prefix_ipv4 *p, char buf2[INET_ADDRSTRLEN]; /* Lookup table. */ - table = vrf_table (AFI_IP, safi, 0); + if ((table_id == RT_TABLE_MAIN) || (table_id == zebrad.rtm_table_default)) + { + table = vrf_table (AFI_IP, safi, 0); + } + else + { + table = vrf_other_route_table(AFI_IP, table_id, 0); + } if (! table) return 0; @@ -2885,7 +2990,7 @@ rib_bogus_ipv6 (int type, struct prefix_ipv6 *p, int rib_add_ipv6 (int type, u_short instance, int flags, struct prefix_ipv6 *p, - struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id, + struct in6_addr *gate, unsigned int ifindex, u_int32_t table_id, u_int32_t metric, u_char distance, safi_t safi) { struct rib *rib; @@ -2895,7 +3000,14 @@ rib_add_ipv6 (int type, u_short instance, int flags, struct prefix_ipv6 *p, struct nexthop *nexthop; /* Lookup table. */ - table = vrf_table (AFI_IP6, safi, 0); + if ((table_id == RT_TABLE_MAIN) || (table_id == zebrad.rtm_table_default)) + { + table = vrf_table (AFI_IP6, safi, 0); + } + else + { + table = vrf_other_route_table(AFI_IP6, table_id, 0); + } if (! table) return 0; @@ -2949,7 +3061,7 @@ rib_add_ipv6 (int type, u_short instance, int flags, struct prefix_ipv6 *p, rib->distance = distance; rib->flags = flags; rib->metric = metric; - rib->table = vrf_id; + rib->table = table_id; rib->nexthop_num = 0; rib->uptime = time (NULL); @@ -3003,12 +3115,22 @@ rib_add_ipv6_multipath (struct prefix_ipv6 *p, struct rib *rib, safi_t safi, struct rib *same = NULL; struct nexthop *nexthop; int ret = 0; + int table_id = 0; - if (!rib) + if (rib) + table_id = rib->table; + else return 0; /* why are we getting called with NULL rib */ /* Lookup table. */ - table = vrf_table (AFI_IP6, safi, 0); + if ((table_id == RT_TABLE_MAIN) || (table_id == zebrad.rtm_table_default)) + { + table = vrf_table (AFI_IP6, safi, 0); + } + else + { + table = vrf_other_route_table(AFI_IP6, table_id, 0); + } if (! table) return 0; @@ -3088,7 +3210,7 @@ rib_add_ipv6_multipath (struct prefix_ipv6 *p, struct rib *rib, safi_t safi, /* XXX factor with rib_delete_ipv6 */ int rib_delete_ipv6 (int type, u_short instance, int flags, struct prefix_ipv6 *p, - struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id, safi_t safi) + struct in6_addr *gate, unsigned int ifindex, u_int32_t table_id, safi_t safi) { struct route_table *table; struct route_node *rn; @@ -3104,7 +3226,14 @@ rib_delete_ipv6 (int type, u_short instance, int flags, struct prefix_ipv6 *p, apply_mask_ipv6 (p); /* Lookup table. */ - table = vrf_table (AFI_IP6, safi, 0); + if ((table_id == RT_TABLE_MAIN) || (table_id == zebrad.rtm_table_default)) + { + table = vrf_table (AFI_IP6, safi, 0); + } + else + { + table = vrf_other_route_table(AFI_IP6, table_id, 0); + } if (! table) return 0; diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index a44d196185..97bf5cc97b 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -31,6 +31,7 @@ #include "zebra/zserv.h" #include "zebra/zebra_rnh.h" +#include "zebra/redistribute.h" /* General fucntion for static route. */ static int @@ -916,6 +917,7 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn) || rib->type == ZEBRA_ROUTE_OSPF || rib->type == ZEBRA_ROUTE_BABEL || rib->type == ZEBRA_ROUTE_ISIS + || rib->type == ZEBRA_ROUTE_TABLE || rib->type == ZEBRA_ROUTE_BGP) { time_t uptime; @@ -1113,6 +1115,7 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib) || rib->type == ZEBRA_ROUTE_OSPF || rib->type == ZEBRA_ROUTE_BABEL || rib->type == ZEBRA_ROUTE_ISIS + || rib->type == ZEBRA_ROUTE_TABLE || rib->type == ZEBRA_ROUTE_BGP) { time_t uptime; @@ -2878,9 +2881,98 @@ zebra_ip_config (struct vty *vty) write += static_config_ipv6 (vty); #endif /* HAVE_IPV6 */ + write += zebra_import_table_config (vty); return write; } +DEFUN (ip_zebra_import_table_distance, + ip_zebra_import_table_distance_cmd, + "ip import-table <1-252> distance <1-255>", + IP_STR + "import routes from non-main kernel table\n" + "kernel routing table id\n" + "Distance for imported routes\n" + "Default distance value\n") +{ + u_int32_t table_id = 0; + int distance = ZEBRA_TABLE_DISTANCE_DEFAULT; + char *route_map_name = NULL; + + 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 (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)); + +} + +ALIAS (ip_zebra_import_table_distance, + ip_zebra_import_table_cmd, + "ip import-table <1-252>", + IP_STR + "import routes from non-main kernel table\n" + "kernel routing table id\n") + +DEFUN (no_ip_zebra_import_table, + no_ip_zebra_import_table_cmd, + "no ip import-table <1-252>", + NO_STR + IP_STR + "import routes from non-main kernel table\n" + "kernel routing table id\n") +{ + u_int32_t table_id = 0; + + 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. Must be in range 1-252%s", + 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 (!is_zebra_import_table_enabled(AFI_IP, table_id)) + return CMD_SUCCESS; + + return (zebra_import_table(AFI_IP, table_id, 0, 0)); +} + +ALIAS (no_ip_zebra_import_table, + no_ip_zebra_import_table_distance_cmd, + "no ip import-table <1-252> distance <1-255>", + IP_STR + "import routes from non-main kernel table to main table" + "kernel routing table id\n" + "distance to be used\n") + /* IP node for static routes. */ static struct cmd_node ip_node = { IP_NODE, "", 1 }; @@ -2938,6 +3030,10 @@ zebra_vty_init (void) install_element (CONFIG_NODE, &no_ip_route_mask_flags_tag_distance_cmd); install_element (CONFIG_NODE, &no_ip_route_mask_flags_distance2_cmd); install_element (CONFIG_NODE, &no_ip_route_mask_flags_tag_distance2_cmd); + install_element (CONFIG_NODE, &ip_zebra_import_table_cmd); + install_element (CONFIG_NODE, &ip_zebra_import_table_distance_cmd); + install_element (CONFIG_NODE, &no_ip_zebra_import_table_cmd); + install_element (CONFIG_NODE, &no_ip_zebra_import_table_distance_cmd); install_element (VIEW_NODE, &show_ip_route_cmd); install_element (VIEW_NODE, &show_ip_route_ospf_instance_cmd); -- 2.39.5