2023-02-08 13:17:09 +01:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Route map function.
|
2017-05-13 10:25:29 +02:00
|
|
|
* Copyright (C) 1998, 1999 Kunihiro Ishiguro
|
|
|
|
*/
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
#include <zebra.h>
|
|
|
|
|
|
|
|
#include "linklist.h"
|
|
|
|
#include "memory.h"
|
2021-08-02 20:38:26 +02:00
|
|
|
#include "command.h"
|
2002-12-13 21:15:29 +01:00
|
|
|
#include "vector.h"
|
|
|
|
#include "prefix.h"
|
2016-10-06 21:56:13 +02:00
|
|
|
#include "vty.h"
|
2002-12-13 21:15:29 +01:00
|
|
|
#include "routemap.h"
|
|
|
|
#include "command.h"
|
2004-09-13 Jose Luis Rubio <jrubio@dit.upm.es>
(at Technical University of Madrid as part of Euro6ix Project)
Enhanced Route Server functionality and Route-Maps:
* bgpd/bgpd.h: Modified 'struct peer' and 'struct bgp_filter' to
support rs-clients. A 'struct bgp_table *rib' has been added to the
first (to mantain a separated RIB for each rs-client) and two new
route-maps have been added to the last (for import/export policies).
Added the following #defines: RMAP_{IN|OUT|IMPORT|EXPORT|MAX},
PEER_RMAP_TYPE_{IMPORT|EXPORT} and BGP_CLEAR_SOFT_RSCLIENT.
* bgpd/bgpd.c: Modified the functions that create/delete/etc peers in
order to consider the new fields included in 'struct peer' for
supporting rs-clients, i.e. the import/export route-maps and the
'struct bgp_table'.
* bgpd/bgp_route.{ch}: Modified several functions related with
receiving/sending announces in order to support the new Route Server
capabilities.
Function 'bgp_process' has been reorganized, creating an auxiliar
function for best path selection ('bgp_best_selection').
Modified 'bgp_show' and 'bgp_show_route' for displaying information
about any RIB (and not only the main bgp RIB).
Added commands for displaying information about RS-clients RIBs:
'show bgp rsclient (A.B.C.D|X:X::X:X)', 'show bgp rsclient
(A.B.C.D|X:X::X:X) X:X::X:X/M', etc
* bgpd/bgp_table.{ch}: The structure 'struct bgp_table' now has two
new fields: type (which can take the values BGP_TABLE_{MAIN|RSCLIENT})
and 'void *owner' which points to 'struct bgp' or 'struct peer' which
owns the table.
When creating a new bgp_table by default 'type=BGP_TABLE_MAIN' is set.
* bgpd/bgp_vty.c: The commands 'neighbor ... route-server-client' and
'no neighbor ... route-server-client' now not only set/unset the flag
PEER_FLAG_RSERVER_CLIENT, but they create/destroy the 'struct
bgp_table' of the peer. Special actions are taken for peer_groups.
Command 'neighbor ... route-map WORD (in|out)' now also supports two
new kinds of route-map: 'import' and 'export'.
Added commands 'clear bgp * rsclient', etc. These commands allow a new
kind of soft_reconfig which affects only the RIB of the specified
RS-client.
Added commands 'show bgp rsclient summary', etc which display a
summary of the rs-clients configured for the corresponding address
family.
* bgpd/bgp_routemap.c: A new match statement is available,
'match peer (A.B.C.D|X:X::X:X)'. This statement can only be used in
import/export route-maps, and it matches when the peer who announces
(when used in an import route-map) or is going to receive (when used
in an export route-map) the route is the same than the one specified
in the statement.
For peer-groups the statement matches if the specified peer is member
of the peer-group.
A special version of the command, 'match peer local', matches with
routes originated by the Route Server (defined with 'network ...',
redistributed routes and default-originate).
* lib/routemap.{ch}: Added a new clause 'call NAME' for use in
route-maps. It jumps into the specified route-map and when it returns
the first route-map ends if the called RM returns DENY_MATCH, or
continues in other case.
2004-09-13 07:12:46 +02:00
|
|
|
#include "log.h"
|
2015-05-20 02:40:45 +02:00
|
|
|
#include "hash.h"
|
2017-05-08 03:06:07 +02:00
|
|
|
#include "libfrr.h"
|
2018-08-20 16:21:03 +02:00
|
|
|
#include "lib_errors.h"
|
2019-11-02 03:42:20 +01:00
|
|
|
#include "table.h"
|
2021-08-02 20:38:26 +02:00
|
|
|
#include "json.h"
|
2021-11-06 16:57:52 +01:00
|
|
|
#include "jhash.h"
|
2014-06-04 06:53:35 +02:00
|
|
|
|
2023-02-13 15:14:56 +01:00
|
|
|
#include "lib/routemap_clippy.c"
|
|
|
|
|
2015-05-29 05:48:31 +02:00
|
|
|
DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP, "Route map");
|
|
|
|
DEFINE_MTYPE(LIB, ROUTE_MAP_NAME, "Route map name");
|
|
|
|
DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_INDEX, "Route map index");
|
|
|
|
DEFINE_MTYPE(LIB, ROUTE_MAP_RULE, "Route map rule");
|
|
|
|
DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_RULE_STR, "Route map rule str");
|
|
|
|
DEFINE_MTYPE(LIB, ROUTE_MAP_COMPILED, "Route map compiled");
|
|
|
|
DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_DEP, "Route map dependency");
|
2019-05-15 09:09:08 +02:00
|
|
|
DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_DEP_DATA, "Route map dependency data");
|
2015-05-29 05:48:31 +02:00
|
|
|
|
2016-09-27 14:51:08 +02:00
|
|
|
DEFINE_QOBJ_TYPE(route_map_index);
|
|
|
|
DEFINE_QOBJ_TYPE(route_map);
|
|
|
|
|
2021-11-06 16:57:52 +01:00
|
|
|
static int rmap_cmd_name_cmp(const struct route_map_rule_cmd_proxy *a,
|
|
|
|
const struct route_map_rule_cmd_proxy *b)
|
|
|
|
{
|
|
|
|
return strcmp(a->cmd->str, b->cmd->str);
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t rmap_cmd_name_hash(const struct route_map_rule_cmd_proxy *item)
|
|
|
|
{
|
|
|
|
return jhash(item->cmd->str, strlen(item->cmd->str), 0xbfd69320);
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_HASH(rmap_cmd_name, struct route_map_rule_cmd_proxy, itm,
|
|
|
|
rmap_cmd_name_cmp, rmap_cmd_name_hash);
|
|
|
|
|
|
|
|
static struct rmap_cmd_name_head rmap_match_cmds[1] = {
|
|
|
|
INIT_HASH(rmap_match_cmds[0]),
|
|
|
|
};
|
|
|
|
static struct rmap_cmd_name_head rmap_set_cmds[1] = {
|
|
|
|
INIT_HASH(rmap_set_cmds[0]),
|
|
|
|
};
|
|
|
|
|
2019-11-02 03:42:20 +01:00
|
|
|
#define IPv4_PREFIX_LIST "ip address prefix-list"
|
|
|
|
#define IPv6_PREFIX_LIST "ipv6 address prefix-list"
|
|
|
|
|
2019-12-20 07:57:09 +01:00
|
|
|
#define IS_RULE_IPv4_PREFIX_LIST(S) \
|
|
|
|
(strncmp(S, IPv4_PREFIX_LIST, strlen(IPv4_PREFIX_LIST)) == 0)
|
|
|
|
#define IS_RULE_IPv6_PREFIX_LIST(S) \
|
|
|
|
(strncmp(S, IPv6_PREFIX_LIST, strlen(IPv6_PREFIX_LIST)) == 0)
|
|
|
|
|
2019-11-02 03:42:20 +01:00
|
|
|
struct route_map_pentry_dep {
|
|
|
|
struct prefix_list_entry *pentry;
|
|
|
|
const char *plist_name;
|
|
|
|
route_map_event_t event;
|
|
|
|
};
|
|
|
|
|
2019-12-20 07:57:09 +01:00
|
|
|
static void route_map_pfx_tbl_update(route_map_event_t event,
|
|
|
|
struct route_map_index *index, afi_t afi,
|
|
|
|
const char *plist_name);
|
|
|
|
static void route_map_pfx_table_add_default(afi_t afi,
|
|
|
|
struct route_map_index *index);
|
|
|
|
static void route_map_pfx_table_del_default(afi_t afi,
|
|
|
|
struct route_map_index *index);
|
|
|
|
static void route_map_add_plist_entries(afi_t afi,
|
|
|
|
struct route_map_index *index,
|
|
|
|
const char *plist_name,
|
|
|
|
struct prefix_list_entry *entry);
|
|
|
|
static void route_map_del_plist_entries(afi_t afi,
|
|
|
|
struct route_map_index *index,
|
|
|
|
const char *plist_name,
|
|
|
|
struct prefix_list_entry *entry);
|
|
|
|
|
|
|
|
static struct hash *route_map_get_dep_hash(route_map_event_t event);
|
2022-03-02 21:41:54 +01:00
|
|
|
static void route_map_free_map(struct route_map *map);
|
2019-11-02 03:42:20 +01:00
|
|
|
|
2019-09-30 15:17:33 +02:00
|
|
|
struct route_map_match_set_hooks rmap_match_set_hook;
|
2016-10-06 21:56:13 +02:00
|
|
|
|
|
|
|
/* match interface */
|
|
|
|
void route_map_match_interface_hook(int (*func)(
|
2020-10-30 08:38:41 +01:00
|
|
|
struct route_map_index *index, const char *command,
|
|
|
|
const char *arg, route_map_event_t type,
|
|
|
|
char *errmsg, size_t errmsg_len))
|
2016-10-06 21:56:13 +02:00
|
|
|
{
|
|
|
|
rmap_match_set_hook.match_interface = func;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no match interface */
|
|
|
|
void route_map_no_match_interface_hook(int (*func)(
|
2020-10-30 08:38:41 +01:00
|
|
|
struct route_map_index *index, const char *command,
|
|
|
|
const char *arg, route_map_event_t type,
|
|
|
|
char *errmsg, size_t errmsg_len))
|
2016-10-06 21:56:13 +02:00
|
|
|
{
|
|
|
|
rmap_match_set_hook.no_match_interface = func;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* match ip address */
|
|
|
|
void route_map_match_ip_address_hook(int (*func)(
|
2020-10-30 08:38:41 +01:00
|
|
|
struct route_map_index *index, const char *command,
|
|
|
|
const char *arg, route_map_event_t type,
|
|
|
|
char *errmsg, size_t errmsg_len))
|
2016-10-06 21:56:13 +02:00
|
|
|
{
|
|
|
|
rmap_match_set_hook.match_ip_address = func;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no match ip address */
|
|
|
|
void route_map_no_match_ip_address_hook(int (*func)(
|
2020-10-30 08:38:41 +01:00
|
|
|
struct route_map_index *index, const char *command,
|
|
|
|
const char *arg, route_map_event_t type,
|
|
|
|
char *errmsg, size_t errmsg_len))
|
2016-10-06 21:56:13 +02:00
|
|
|
{
|
|
|
|
rmap_match_set_hook.no_match_ip_address = func;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* match ip address prefix list */
|
|
|
|
void route_map_match_ip_address_prefix_list_hook(int (*func)(
|
2020-10-30 08:38:41 +01:00
|
|
|
struct route_map_index *index, const char *command,
|
|
|
|
const char *arg, route_map_event_t type,
|
|
|
|
char *errmsg, size_t errmsg_len))
|
2016-10-06 21:56:13 +02:00
|
|
|
{
|
|
|
|
rmap_match_set_hook.match_ip_address_prefix_list = func;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no match ip address prefix list */
|
|
|
|
void route_map_no_match_ip_address_prefix_list_hook(int (*func)(
|
2020-10-30 08:38:41 +01:00
|
|
|
struct route_map_index *index, const char *command,
|
|
|
|
const char *arg, route_map_event_t type,
|
|
|
|
char *errmsg, size_t errmsg_len))
|
2016-10-06 21:56:13 +02:00
|
|
|
{
|
|
|
|
rmap_match_set_hook.no_match_ip_address_prefix_list = func;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* match ip next hop */
|
|
|
|
void route_map_match_ip_next_hop_hook(int (*func)(
|
2020-10-30 08:38:41 +01:00
|
|
|
struct route_map_index *index, const char *command,
|
|
|
|
const char *arg, route_map_event_t type,
|
|
|
|
char *errmsg, size_t errmsg_len))
|
2016-10-06 21:56:13 +02:00
|
|
|
{
|
|
|
|
rmap_match_set_hook.match_ip_next_hop = func;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no match ip next hop */
|
|
|
|
void route_map_no_match_ip_next_hop_hook(int (*func)(
|
2020-10-30 08:38:41 +01:00
|
|
|
struct route_map_index *index, const char *command,
|
|
|
|
const char *arg, route_map_event_t type,
|
|
|
|
char *errmsg, size_t errmsg_len))
|
2016-10-06 21:56:13 +02:00
|
|
|
{
|
|
|
|
rmap_match_set_hook.no_match_ip_next_hop = func;
|
|
|
|
}
|
|
|
|
|
2021-11-22 20:26:33 +01:00
|
|
|
/* match ipv6 next-hop */
|
|
|
|
void route_map_match_ipv6_next_hop_hook(int (*func)(
|
|
|
|
struct route_map_index *index, const char *command, const char *arg,
|
|
|
|
route_map_event_t type, char *errmsg, size_t errmsg_len))
|
|
|
|
{
|
|
|
|
rmap_match_set_hook.match_ipv6_next_hop = func;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no match ipv6 next-hop */
|
|
|
|
void route_map_no_match_ipv6_next_hop_hook(int (*func)(
|
|
|
|
struct route_map_index *index, const char *command, const char *arg,
|
|
|
|
route_map_event_t type, char *errmsg, size_t errmsg_len))
|
|
|
|
{
|
|
|
|
rmap_match_set_hook.no_match_ipv6_next_hop = func;
|
|
|
|
}
|
|
|
|
|
2016-10-06 21:56:13 +02:00
|
|
|
/* match ip next hop prefix list */
|
|
|
|
void route_map_match_ip_next_hop_prefix_list_hook(int (*func)(
|
2020-10-30 08:38:41 +01:00
|
|
|
struct route_map_index *index, const char *command,
|
|
|
|
const char *arg, route_map_event_t type,
|
|
|
|
char *errmsg, size_t errmsg_len))
|
2016-10-06 21:56:13 +02:00
|
|
|
{
|
|
|
|
rmap_match_set_hook.match_ip_next_hop_prefix_list = func;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no match ip next hop prefix list */
|
|
|
|
void route_map_no_match_ip_next_hop_prefix_list_hook(int (*func)(
|
2020-10-30 08:38:41 +01:00
|
|
|
struct route_map_index *index, const char *command,
|
|
|
|
const char *arg, route_map_event_t type,
|
|
|
|
char *errmsg, size_t errmsg_len))
|
2016-10-06 21:56:13 +02:00
|
|
|
{
|
|
|
|
rmap_match_set_hook.no_match_ip_next_hop_prefix_list = func;
|
|
|
|
}
|
|
|
|
|
2019-06-22 08:30:44 +02:00
|
|
|
/* match ip next-hop type */
|
2018-09-28 10:51:50 +02:00
|
|
|
void route_map_match_ip_next_hop_type_hook(int (*func)(
|
2020-10-30 08:38:41 +01:00
|
|
|
struct route_map_index *index, const char *command,
|
|
|
|
const char *arg, route_map_event_t type,
|
|
|
|
char *errmsg, size_t errmsg_len))
|
2018-09-28 10:51:50 +02:00
|
|
|
{
|
|
|
|
rmap_match_set_hook.match_ip_next_hop_type = func;
|
|
|
|
}
|
|
|
|
|
2019-06-22 08:30:44 +02:00
|
|
|
/* no match ip next-hop type */
|
2018-09-28 10:51:50 +02:00
|
|
|
void route_map_no_match_ip_next_hop_type_hook(int (*func)(
|
2020-10-30 08:38:41 +01:00
|
|
|
struct route_map_index *index, const char *command,
|
|
|
|
const char *arg, route_map_event_t type,
|
|
|
|
char *errmsg, size_t errmsg_len))
|
2018-09-28 10:51:50 +02:00
|
|
|
{
|
|
|
|
rmap_match_set_hook.no_match_ip_next_hop_type = func;
|
|
|
|
}
|
|
|
|
|
2016-10-06 21:56:13 +02:00
|
|
|
/* match ipv6 address */
|
|
|
|
void route_map_match_ipv6_address_hook(int (*func)(
|
2020-10-30 08:38:41 +01:00
|
|
|
struct route_map_index *index, const char *command,
|
|
|
|
const char *arg, route_map_event_t type,
|
|
|
|
char *errmsg, size_t errmsg_len))
|
2016-10-06 21:56:13 +02:00
|
|
|
{
|
|
|
|
rmap_match_set_hook.match_ipv6_address = func;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no match ipv6 address */
|
|
|
|
void route_map_no_match_ipv6_address_hook(int (*func)(
|
2020-10-30 08:38:41 +01:00
|
|
|
struct route_map_index *index, const char *command,
|
|
|
|
const char *arg, route_map_event_t type,
|
|
|
|
char *errmsg, size_t errmsg_len))
|
2016-10-06 21:56:13 +02:00
|
|
|
{
|
|
|
|
rmap_match_set_hook.no_match_ipv6_address = func;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* match ipv6 address prefix list */
|
|
|
|
void route_map_match_ipv6_address_prefix_list_hook(int (*func)(
|
2020-10-30 08:38:41 +01:00
|
|
|
struct route_map_index *index, const char *command,
|
|
|
|
const char *arg, route_map_event_t type,
|
|
|
|
char *errmsg, size_t errmsg_len))
|
2016-10-06 21:56:13 +02:00
|
|
|
{
|
|
|
|
rmap_match_set_hook.match_ipv6_address_prefix_list = func;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no match ipv6 address prefix list */
|
|
|
|
void route_map_no_match_ipv6_address_prefix_list_hook(int (*func)(
|
2020-10-30 08:38:41 +01:00
|
|
|
struct route_map_index *index, const char *command,
|
|
|
|
const char *arg, route_map_event_t type,
|
|
|
|
char *errmsg, size_t errmsg_len))
|
2016-10-06 21:56:13 +02:00
|
|
|
{
|
|
|
|
rmap_match_set_hook.no_match_ipv6_address_prefix_list = func;
|
|
|
|
}
|
|
|
|
|
2018-09-28 10:51:50 +02:00
|
|
|
/* match ipv6 next-hop type */
|
|
|
|
void route_map_match_ipv6_next_hop_type_hook(int (*func)(
|
2020-10-30 08:38:41 +01:00
|
|
|
struct route_map_index *index, const char *command,
|
|
|
|
const char *arg, route_map_event_t type,
|
|
|
|
char *errmsg, size_t errmsg_len))
|
2018-09-28 10:51:50 +02:00
|
|
|
{
|
|
|
|
rmap_match_set_hook.match_ipv6_next_hop_type = func;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no match ipv6 next-hop type */
|
|
|
|
void route_map_no_match_ipv6_next_hop_type_hook(int (*func)(
|
2020-10-30 08:38:41 +01:00
|
|
|
struct route_map_index *index, const char *command,
|
|
|
|
const char *arg, route_map_event_t type,
|
|
|
|
char *errmsg, size_t errmsg_len))
|
2018-09-28 10:51:50 +02:00
|
|
|
{
|
|
|
|
rmap_match_set_hook.no_match_ipv6_next_hop_type = func;
|
|
|
|
}
|
|
|
|
|
2021-11-24 15:28:31 +01:00
|
|
|
/* match ipv6 next-hop prefix-list */
|
|
|
|
void route_map_match_ipv6_next_hop_prefix_list_hook(int (*func)(
|
|
|
|
struct route_map_index *index, const char *command, const char *arg,
|
|
|
|
route_map_event_t type, char *errmsg, size_t errmsg_len))
|
|
|
|
{
|
|
|
|
rmap_match_set_hook.match_ipv6_next_hop_prefix_list = func;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no match ipv6 next-hop prefix-list */
|
|
|
|
void route_map_no_match_ipv6_next_hop_prefix_list_hook(int (*func)(
|
|
|
|
struct route_map_index *index, const char *command, const char *arg,
|
|
|
|
route_map_event_t type, char *errmsg, size_t errmsg_len))
|
|
|
|
{
|
|
|
|
rmap_match_set_hook.no_match_ipv6_next_hop_prefix_list = func;
|
|
|
|
}
|
|
|
|
|
2016-10-06 21:56:13 +02:00
|
|
|
/* match metric */
|
|
|
|
void route_map_match_metric_hook(int (*func)(
|
2020-10-30 08:38:41 +01:00
|
|
|
struct route_map_index *index, const char *command,
|
|
|
|
const char *arg, route_map_event_t type,
|
|
|
|
char *errmsg, size_t errmsg_len))
|
2016-10-06 21:56:13 +02:00
|
|
|
{
|
|
|
|
rmap_match_set_hook.match_metric = func;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no match metric */
|
|
|
|
void route_map_no_match_metric_hook(int (*func)(
|
2020-10-30 08:38:41 +01:00
|
|
|
struct route_map_index *index, const char *command,
|
|
|
|
const char *arg, route_map_event_t type,
|
|
|
|
char *errmsg, size_t errmsg_len))
|
2016-10-06 21:56:13 +02:00
|
|
|
{
|
|
|
|
rmap_match_set_hook.no_match_metric = func;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* match tag */
|
2020-10-30 08:38:41 +01:00
|
|
|
void route_map_match_tag_hook(int (*func)(struct route_map_index *index,
|
2016-10-06 21:56:13 +02:00
|
|
|
const char *command, const char *arg,
|
2020-10-30 08:38:41 +01:00
|
|
|
route_map_event_t type,
|
|
|
|
char *errmsg, size_t errmsg_len))
|
2016-10-06 21:56:13 +02:00
|
|
|
{
|
|
|
|
rmap_match_set_hook.match_tag = func;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no match tag */
|
|
|
|
void route_map_no_match_tag_hook(int (*func)(
|
2020-10-30 08:38:41 +01:00
|
|
|
struct route_map_index *index, const char *command,
|
|
|
|
const char *arg, route_map_event_t type,
|
|
|
|
char *errmsg, size_t errmsg_len))
|
2016-10-06 21:56:13 +02:00
|
|
|
{
|
|
|
|
rmap_match_set_hook.no_match_tag = func;
|
|
|
|
}
|
|
|
|
|
2020-07-20 13:43:54 +02:00
|
|
|
/* set sr-te color */
|
2020-10-30 08:38:41 +01:00
|
|
|
void route_map_set_srte_color_hook(int (*func)(struct route_map_index *index,
|
2020-07-20 13:43:54 +02:00
|
|
|
const char *command,
|
2020-10-30 08:38:41 +01:00
|
|
|
const char *arg,
|
|
|
|
char *errmsg, size_t errmsg_len))
|
2020-07-20 13:43:54 +02:00
|
|
|
{
|
|
|
|
rmap_match_set_hook.set_srte_color = func;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no set sr-te color */
|
2020-10-30 08:38:41 +01:00
|
|
|
void route_map_no_set_srte_color_hook(int (*func)(struct route_map_index *index,
|
2020-07-20 13:43:54 +02:00
|
|
|
const char *command,
|
2020-10-30 08:38:41 +01:00
|
|
|
const char *arg,
|
|
|
|
char *errmsg, size_t errmsg_len))
|
2020-07-20 13:43:54 +02:00
|
|
|
{
|
|
|
|
rmap_match_set_hook.no_set_srte_color = func;
|
|
|
|
}
|
|
|
|
|
2016-10-06 21:56:13 +02:00
|
|
|
/* set ip nexthop */
|
2020-10-30 08:38:41 +01:00
|
|
|
void route_map_set_ip_nexthop_hook(int (*func)(struct route_map_index *index,
|
2016-10-06 21:56:13 +02:00
|
|
|
const char *command,
|
2020-10-30 08:38:41 +01:00
|
|
|
const char *arg,
|
|
|
|
char *errmsg, size_t errmsg_len))
|
2016-10-06 21:56:13 +02:00
|
|
|
{
|
|
|
|
rmap_match_set_hook.set_ip_nexthop = func;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no set ip nexthop */
|
2020-10-30 08:38:41 +01:00
|
|
|
void route_map_no_set_ip_nexthop_hook(int (*func)(struct route_map_index *index,
|
2016-10-06 21:56:13 +02:00
|
|
|
const char *command,
|
2020-10-30 08:38:41 +01:00
|
|
|
const char *arg,
|
|
|
|
char *errmsg,
|
|
|
|
size_t errmsg_len))
|
2016-10-06 21:56:13 +02:00
|
|
|
{
|
|
|
|
rmap_match_set_hook.no_set_ip_nexthop = func;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* set ipv6 nexthop local */
|
|
|
|
void route_map_set_ipv6_nexthop_local_hook(
|
2020-10-30 08:38:41 +01:00
|
|
|
int (*func)(struct route_map_index *index,
|
|
|
|
const char *command, const char *arg,
|
|
|
|
char *errmsg, size_t errmsg_len))
|
2016-10-06 21:56:13 +02:00
|
|
|
{
|
|
|
|
rmap_match_set_hook.set_ipv6_nexthop_local = func;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no set ipv6 nexthop local */
|
|
|
|
void route_map_no_set_ipv6_nexthop_local_hook(
|
2020-10-30 08:38:41 +01:00
|
|
|
int (*func)(struct route_map_index *index,
|
|
|
|
const char *command, const char *arg,
|
|
|
|
char *errmsg, size_t errmsg_len))
|
2016-10-06 21:56:13 +02:00
|
|
|
{
|
|
|
|
rmap_match_set_hook.no_set_ipv6_nexthop_local = func;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* set metric */
|
2020-10-30 08:38:41 +01:00
|
|
|
void route_map_set_metric_hook(int (*func)(struct route_map_index *index,
|
2016-10-06 21:56:13 +02:00
|
|
|
const char *command,
|
2020-10-30 08:38:41 +01:00
|
|
|
const char *arg,
|
|
|
|
char *errmsg, size_t errmsg_len))
|
2016-10-06 21:56:13 +02:00
|
|
|
{
|
|
|
|
rmap_match_set_hook.set_metric = func;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no set metric */
|
2020-10-30 08:38:41 +01:00
|
|
|
void route_map_no_set_metric_hook(int (*func)(struct route_map_index *index,
|
2016-10-06 21:56:13 +02:00
|
|
|
const char *command,
|
2020-10-30 08:38:41 +01:00
|
|
|
const char *arg,
|
|
|
|
char *errmsg, size_t errmsg_len))
|
2016-10-06 21:56:13 +02:00
|
|
|
{
|
|
|
|
rmap_match_set_hook.no_set_metric = func;
|
|
|
|
}
|
2023-04-06 06:55:13 +02:00
|
|
|
/* set min-metric */
|
|
|
|
void route_map_set_min_metric_hook(int (*func)(struct route_map_index *index,
|
|
|
|
const char *command,
|
|
|
|
const char *arg, char *errmsg,
|
|
|
|
size_t errmsg_len))
|
|
|
|
{
|
|
|
|
rmap_match_set_hook.set_min_metric = func;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no set min-metric */
|
|
|
|
void route_map_no_set_min_metric_hook(int (*func)(struct route_map_index *index,
|
|
|
|
const char *command,
|
|
|
|
const char *arg, char *errmsg,
|
|
|
|
size_t errmsg_len))
|
|
|
|
{
|
|
|
|
rmap_match_set_hook.no_set_min_metric = func;
|
|
|
|
}
|
|
|
|
/* set max-metric */
|
|
|
|
void route_map_set_max_metric_hook(int (*func)(struct route_map_index *index,
|
|
|
|
const char *command,
|
|
|
|
const char *arg, char *errmsg,
|
|
|
|
size_t errmsg_len))
|
|
|
|
{
|
|
|
|
rmap_match_set_hook.set_max_metric = func;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no set max-metric */
|
|
|
|
void route_map_no_set_max_metric_hook(int (*func)(struct route_map_index *index,
|
|
|
|
const char *command,
|
|
|
|
const char *arg, char *errmsg,
|
|
|
|
size_t errmsg_len))
|
|
|
|
{
|
|
|
|
rmap_match_set_hook.no_set_max_metric = func;
|
|
|
|
}
|
2016-10-06 21:56:13 +02:00
|
|
|
|
|
|
|
/* set tag */
|
2020-10-30 08:38:41 +01:00
|
|
|
void route_map_set_tag_hook(int (*func)(struct route_map_index *index,
|
|
|
|
const char *command, const char *arg,
|
|
|
|
char *errmsg, size_t errmsg_len))
|
2016-10-06 21:56:13 +02:00
|
|
|
{
|
|
|
|
rmap_match_set_hook.set_tag = func;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no set tag */
|
2020-10-30 08:38:41 +01:00
|
|
|
void route_map_no_set_tag_hook(int (*func)(struct route_map_index *index,
|
2016-10-06 21:56:13 +02:00
|
|
|
const char *command,
|
2020-10-30 08:38:41 +01:00
|
|
|
const char *arg,
|
|
|
|
char *errmsg, size_t errmsg_len))
|
2016-10-06 21:56:13 +02:00
|
|
|
{
|
|
|
|
rmap_match_set_hook.no_set_tag = func;
|
|
|
|
}
|
|
|
|
|
2020-10-30 08:38:41 +01:00
|
|
|
int generic_match_add(struct route_map_index *index,
|
2016-10-06 21:56:13 +02:00
|
|
|
const char *command, const char *arg,
|
2020-10-30 08:38:41 +01:00
|
|
|
route_map_event_t type,
|
|
|
|
char *errmsg, size_t errmsg_len)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
2019-08-27 14:04:43 +02:00
|
|
|
enum rmap_compile_rets ret;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-05-15 09:09:08 +02:00
|
|
|
ret = route_map_add_match(index, command, arg, type);
|
2017-08-25 14:31:03 +02:00
|
|
|
switch (ret) {
|
|
|
|
case RMAP_RULE_MISSING:
|
2020-10-30 08:38:41 +01:00
|
|
|
snprintf(errmsg, errmsg_len, "%% [%s] Can't find rule.",
|
|
|
|
frr_protonameinst);
|
2017-08-25 14:31:03 +02:00
|
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
case RMAP_COMPILE_ERROR:
|
2020-10-30 08:38:41 +01:00
|
|
|
snprintf(errmsg, errmsg_len,
|
|
|
|
"%% [%s] Argument form is unsupported or malformed.",
|
|
|
|
frr_protonameinst);
|
2017-08-25 14:31:03 +02:00
|
|
|
return CMD_WARNING_CONFIG_FAILED;
|
2019-08-27 12:45:54 +02:00
|
|
|
case RMAP_COMPILE_SUCCESS:
|
2019-08-27 14:04:43 +02:00
|
|
|
/*
|
|
|
|
* Nothing to do here move along
|
|
|
|
*/
|
|
|
|
break;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2016-10-06 21:56:13 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
return CMD_SUCCESS;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2020-10-30 08:38:41 +01:00
|
|
|
int generic_match_delete(struct route_map_index *index,
|
2016-10-06 21:56:13 +02:00
|
|
|
const char *command, const char *arg,
|
2020-10-30 08:38:41 +01:00
|
|
|
route_map_event_t type,
|
|
|
|
char *errmsg, size_t errmsg_len)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
2019-08-27 14:04:43 +02:00
|
|
|
enum rmap_compile_rets ret;
|
2017-08-25 14:31:03 +02:00
|
|
|
int retval = CMD_SUCCESS;
|
2002-12-13 21:15:29 +01:00
|
|
|
char *dep_name = NULL;
|
2016-10-06 21:56:13 +02:00
|
|
|
const char *tmpstr;
|
2002-12-13 21:15:29 +01:00
|
|
|
char *rmap_name = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
if (type != RMAP_EVENT_MATCH_DELETED) {
|
|
|
|
/* ignore the mundane, the types without any dependency */
|
2016-10-06 21:56:13 +02:00
|
|
|
if (arg == NULL) {
|
|
|
|
if ((tmpstr = route_map_get_match_arg(index, command))
|
2017-07-17 14:03:14 +02:00
|
|
|
!= NULL)
|
2016-10-06 21:56:13 +02:00
|
|
|
dep_name =
|
|
|
|
XSTRDUP(MTYPE_ROUTE_MAP_RULE, tmpstr);
|
2017-07-17 14:03:14 +02:00
|
|
|
} else {
|
2016-10-06 21:56:13 +02:00
|
|
|
dep_name = XSTRDUP(MTYPE_ROUTE_MAP_RULE, arg);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2016-10-06 21:56:13 +02:00
|
|
|
rmap_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, index->map->name);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2019-08-27 12:45:54 +02:00
|
|
|
ret = route_map_delete_match(index, command, dep_name, type);
|
2017-08-25 14:31:03 +02:00
|
|
|
switch (ret) {
|
|
|
|
case RMAP_RULE_MISSING:
|
2020-10-30 08:38:41 +01:00
|
|
|
snprintf(errmsg, errmsg_len, "%% [%s] Can't find rule.",
|
|
|
|
frr_protonameinst);
|
2017-08-25 14:31:03 +02:00
|
|
|
retval = CMD_WARNING_CONFIG_FAILED;
|
|
|
|
break;
|
|
|
|
case RMAP_COMPILE_ERROR:
|
2020-10-30 08:38:41 +01:00
|
|
|
snprintf(errmsg, errmsg_len,
|
|
|
|
"%% [%s] Argument form is unsupported or malformed.",
|
|
|
|
frr_protonameinst);
|
2017-08-25 14:31:03 +02:00
|
|
|
retval = CMD_WARNING_CONFIG_FAILED;
|
|
|
|
break;
|
|
|
|
case RMAP_COMPILE_SUCCESS:
|
2019-08-27 14:04:43 +02:00
|
|
|
/*
|
|
|
|
* Nothing to do here
|
|
|
|
*/
|
|
|
|
break;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2019-02-25 21:18:13 +01:00
|
|
|
XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
|
|
|
|
XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-08-25 14:31:03 +02:00
|
|
|
return retval;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2020-10-30 08:38:41 +01:00
|
|
|
int generic_set_add(struct route_map_index *index,
|
|
|
|
const char *command, const char *arg,
|
|
|
|
char *errmsg, size_t errmsg_len)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2019-08-27 14:04:43 +02:00
|
|
|
enum rmap_compile_rets ret;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-10-06 21:56:13 +02:00
|
|
|
ret = route_map_add_set(index, command, arg);
|
2017-08-25 14:31:03 +02:00
|
|
|
switch (ret) {
|
|
|
|
case RMAP_RULE_MISSING:
|
2020-10-30 08:38:41 +01:00
|
|
|
snprintf(errmsg, errmsg_len,
|
|
|
|
"%% [%s] Can't find rule.", frr_protonameinst);
|
2017-08-25 14:31:03 +02:00
|
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
case RMAP_COMPILE_ERROR:
|
2020-10-30 08:38:41 +01:00
|
|
|
snprintf(errmsg, errmsg_len,
|
|
|
|
"%% [%s] Argument form is unsupported or malformed.",
|
|
|
|
frr_protonameinst);
|
2017-08-25 14:31:03 +02:00
|
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
case RMAP_COMPILE_SUCCESS:
|
|
|
|
break;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2017-08-25 14:31:03 +02:00
|
|
|
|
2016-10-06 21:56:13 +02:00
|
|
|
return CMD_SUCCESS;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2020-10-30 08:38:41 +01:00
|
|
|
int generic_set_delete(struct route_map_index *index,
|
|
|
|
const char *command, const char *arg,
|
|
|
|
char *errmsg, size_t errmsg_len)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
2019-08-27 14:04:43 +02:00
|
|
|
enum rmap_compile_rets ret;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-10-06 21:56:13 +02:00
|
|
|
ret = route_map_delete_set(index, command, arg);
|
2017-08-25 14:31:03 +02:00
|
|
|
switch (ret) {
|
|
|
|
case RMAP_RULE_MISSING:
|
2020-10-30 08:38:41 +01:00
|
|
|
snprintf(errmsg, errmsg_len, "%% [%s] Can't find rule.",
|
|
|
|
frr_protonameinst);
|
2017-08-25 14:31:03 +02:00
|
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
case RMAP_COMPILE_ERROR:
|
2020-10-30 08:38:41 +01:00
|
|
|
snprintf(errmsg, errmsg_len,
|
|
|
|
"%% [%s] Argument form is unsupported or malformed.",
|
|
|
|
frr_protonameinst);
|
2017-08-25 14:31:03 +02:00
|
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
case RMAP_COMPILE_SUCCESS:
|
|
|
|
break;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2017-08-25 14:31:03 +02:00
|
|
|
|
2016-10-06 21:56:13 +02:00
|
|
|
return CMD_SUCCESS;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Master list of route map. */
|
2019-09-30 15:17:33 +02:00
|
|
|
struct route_map_list route_map_master = {NULL, NULL, NULL, NULL, NULL};
|
|
|
|
struct hash *route_map_master_hash = NULL;
|
2015-10-28 20:12:24 +01:00
|
|
|
|
2019-05-14 22:19:07 +02:00
|
|
|
static unsigned int route_map_hash_key_make(const void *p)
|
2015-10-28 20:12:24 +01:00
|
|
|
{
|
|
|
|
const struct route_map *map = p;
|
|
|
|
return string_hash_make(map->name);
|
|
|
|
}
|
|
|
|
|
2018-10-17 21:27:12 +02:00
|
|
|
static bool route_map_hash_cmp(const void *p1, const void *p2)
|
2015-10-28 20:12:24 +01:00
|
|
|
{
|
|
|
|
const struct route_map *map1 = p1;
|
|
|
|
const struct route_map *map2 = p2;
|
|
|
|
|
2022-03-02 21:41:54 +01:00
|
|
|
if (!strcmp(map1->name, map2->name))
|
|
|
|
return true;
|
2015-10-28 20:12:24 +01:00
|
|
|
|
2018-10-17 21:27:12 +02:00
|
|
|
return false;
|
2015-10-28 20:12:24 +01:00
|
|
|
}
|
2015-05-20 02:40:45 +02:00
|
|
|
|
|
|
|
enum route_map_upd8_type {
|
|
|
|
ROUTE_MAP_ADD = 1,
|
|
|
|
ROUTE_MAP_DEL,
|
|
|
|
};
|
|
|
|
|
|
|
|
/* all possible route-map dependency types */
|
|
|
|
enum route_map_dep_type {
|
|
|
|
ROUTE_MAP_DEP_RMAP = 1,
|
|
|
|
ROUTE_MAP_DEP_CLIST,
|
|
|
|
ROUTE_MAP_DEP_ECLIST,
|
2016-11-15 11:00:39 +01:00
|
|
|
ROUTE_MAP_DEP_LCLIST,
|
2015-05-20 02:40:45 +02:00
|
|
|
ROUTE_MAP_DEP_PLIST,
|
|
|
|
ROUTE_MAP_DEP_ASPATH,
|
|
|
|
ROUTE_MAP_DEP_FILTER,
|
|
|
|
ROUTE_MAP_DEP_MAX,
|
|
|
|
};
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-05-20 02:40:45 +02:00
|
|
|
struct route_map_dep {
|
|
|
|
char *dep_name;
|
|
|
|
struct hash *dep_rmap_hash;
|
|
|
|
struct hash *this_hash; /* ptr to the hash structure this is part of */
|
|
|
|
};
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2019-05-15 09:09:08 +02:00
|
|
|
struct route_map_dep_data {
|
|
|
|
/* Route-map name.
|
|
|
|
*/
|
|
|
|
char *rname;
|
|
|
|
/* Count of number of sequences of this
|
|
|
|
* route-map that depend on the same entity.
|
|
|
|
*/
|
|
|
|
uint16_t refcnt;
|
|
|
|
};
|
|
|
|
|
2015-05-20 02:40:45 +02:00
|
|
|
/* Hashes maintaining dependency between various sublists used by route maps */
|
2019-11-27 21:17:57 +01:00
|
|
|
static struct hash *route_map_dep_hash[ROUTE_MAP_DEP_MAX];
|
2015-05-20 02:40:45 +02:00
|
|
|
|
2019-05-14 22:19:07 +02:00
|
|
|
static unsigned int route_map_dep_hash_make_key(const void *p);
|
2015-05-20 02:40:45 +02:00
|
|
|
static void route_map_clear_all_references(char *rmap_name);
|
|
|
|
static void route_map_rule_delete(struct route_map_rule_list *,
|
|
|
|
struct route_map_rule *);
|
2023-02-13 15:06:56 +01:00
|
|
|
|
2023-02-13 15:14:56 +01:00
|
|
|
uint32_t rmap_debug;
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
/* New route map allocation. Please note route map's name must be
|
|
|
|
specified. */
|
2004-10-10 Paul Jakma <paul@dishone.st>
* version.h.in: (pid_output*) add const qualifier.
* command.h: Change DEFUN func to take const char *[] rather
than char **, to begin process of fixing compile warnings in lib/.
Nearly all other changes in this commit follow from this change.
* buffer.{c,h}: (buffer_write) pointer-arithmetic is gccism, take
const void * and cast an automatic const char *p to it.
(buffer_putstr) add const
* command.c: (zencrypt) const qualifier
(cmd_execute_command_real) ditto
(cmd_execute_command_strict) ditto
(config_log_file) ditto.
Fix leak of getcwd() returned string.
* memory.{c,h}: Add MTYPE_DISTRIBUTE_IFNAME for struct dist ifname.
* distribute.{c,h}: Update with const qualifier.
(distribute_free) use MTYPE_DISTRIBUTE_IFNAME
(distribute_lookup) Cast to char *, note that it's ok.
(distribute_hash_alloc) use MTYPE_DISTRIBUTE_IFNAME.
(distribute_get) Cast to char *, note that it's ok.
* filter.c: Update with const qualifier.
* if.{c,h}: ditto.
* if_rmap.{c,h}: ditto.
(if_rmap_lookup) Cast to char *, note that it's ok.
(if_rmap_get) ditto.
* log.{c,h}: Update with const qualifier.
* plist.{c,h}: ditto.
* routemap.{c,h}: ditto.
* smux.{c,h}: ditto. Fix some signed/unsigned comparisons.
* sockopt.c: (getsockopt_cmsg_data) add return for error case.
* vty.c: Update with const qualifier.
2004-10-10 13:56:56 +02:00
|
|
|
static struct route_map *route_map_new(const char *name)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
struct route_map *new;
|
|
|
|
|
|
|
|
new = XCALLOC(MTYPE_ROUTE_MAP, sizeof(struct route_map));
|
|
|
|
new->name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, name);
|
2016-09-27 14:51:08 +02:00
|
|
|
QOBJ_REG(new, route_map);
|
2002-12-13 21:15:29 +01:00
|
|
|
return new;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add new name to route_map. */
|
2004-10-10 Paul Jakma <paul@dishone.st>
* version.h.in: (pid_output*) add const qualifier.
* command.h: Change DEFUN func to take const char *[] rather
than char **, to begin process of fixing compile warnings in lib/.
Nearly all other changes in this commit follow from this change.
* buffer.{c,h}: (buffer_write) pointer-arithmetic is gccism, take
const void * and cast an automatic const char *p to it.
(buffer_putstr) add const
* command.c: (zencrypt) const qualifier
(cmd_execute_command_real) ditto
(cmd_execute_command_strict) ditto
(config_log_file) ditto.
Fix leak of getcwd() returned string.
* memory.{c,h}: Add MTYPE_DISTRIBUTE_IFNAME for struct dist ifname.
* distribute.{c,h}: Update with const qualifier.
(distribute_free) use MTYPE_DISTRIBUTE_IFNAME
(distribute_lookup) Cast to char *, note that it's ok.
(distribute_hash_alloc) use MTYPE_DISTRIBUTE_IFNAME.
(distribute_get) Cast to char *, note that it's ok.
* filter.c: Update with const qualifier.
* if.{c,h}: ditto.
* if_rmap.{c,h}: ditto.
(if_rmap_lookup) Cast to char *, note that it's ok.
(if_rmap_get) ditto.
* log.{c,h}: Update with const qualifier.
* plist.{c,h}: ditto.
* routemap.{c,h}: ditto.
* smux.{c,h}: ditto. Fix some signed/unsigned comparisons.
* sockopt.c: (getsockopt_cmsg_data) add return for error case.
* vty.c: Update with const qualifier.
2004-10-10 13:56:56 +02:00
|
|
|
static struct route_map *route_map_add(const char *name)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2022-03-02 21:41:54 +01:00
|
|
|
struct route_map *map, *exist;
|
2002-12-13 21:15:29 +01:00
|
|
|
struct route_map_list *list;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
map = route_map_new(name);
|
|
|
|
list = &route_map_master;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-03-02 21:41:54 +01:00
|
|
|
/*
|
|
|
|
* Add map to the hash
|
|
|
|
*
|
|
|
|
* If the map already exists in the hash, then we know that
|
|
|
|
* FRR is now in a sequence of delete/create.
|
|
|
|
* All FRR needs to do here is set the to_be_processed
|
|
|
|
* bit (to inherit from the old one
|
|
|
|
*/
|
|
|
|
exist = hash_release(route_map_master_hash, map);
|
|
|
|
if (exist) {
|
|
|
|
map->to_be_processed = exist->to_be_processed;
|
|
|
|
route_map_free_map(exist);
|
|
|
|
}
|
2015-10-28 20:12:24 +01:00
|
|
|
hash_get(route_map_master_hash, map, hash_alloc_intern);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-05-18 23:08:55 +02:00
|
|
|
/* Add new entry to the head of the list to match how it is added in the
|
|
|
|
* hash table. This is to ensure that if the same route-map has been
|
|
|
|
* created more than once and then marked for deletion (which can happen
|
|
|
|
* if prior deletions haven't completed as BGP hasn't yet done the
|
|
|
|
* route-map processing), the order of the entities is the same in both
|
|
|
|
* the list and the hash table. Otherwise, since there is nothing to
|
|
|
|
* distinguish between the two entries, the wrong entry could get freed.
|
|
|
|
* TODO: This needs to be re-examined to handle it better - e.g., revive
|
|
|
|
* a deleted entry if the route-map is created again.
|
|
|
|
*/
|
|
|
|
map->prev = NULL;
|
|
|
|
map->next = list->head;
|
|
|
|
if (list->head)
|
|
|
|
list->head->prev = map;
|
|
|
|
list->head = map;
|
|
|
|
if (!list->tail)
|
|
|
|
list->tail = map;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Execute hook. */
|
|
|
|
if (route_map_master.add_hook) {
|
2015-05-20 02:40:45 +02:00
|
|
|
(*route_map_master.add_hook)(name);
|
|
|
|
route_map_notify_dependencies(name, RMAP_EVENT_CALL_ADDED);
|
|
|
|
}
|
2019-05-10 00:34:52 +02:00
|
|
|
|
2019-11-02 03:42:20 +01:00
|
|
|
if (!map->ipv4_prefix_table)
|
|
|
|
map->ipv4_prefix_table = route_table_init();
|
|
|
|
|
|
|
|
if (!map->ipv6_prefix_table)
|
|
|
|
map->ipv6_prefix_table = route_table_init();
|
|
|
|
|
2023-02-17 21:02:14 +01:00
|
|
|
if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP)))
|
2019-05-10 00:34:52 +02:00
|
|
|
zlog_debug("Add route-map %s", name);
|
2002-12-13 21:15:29 +01:00
|
|
|
return map;
|
|
|
|
}
|
|
|
|
|
2015-05-20 02:40:45 +02:00
|
|
|
/* this is supposed to be called post processing by
|
|
|
|
* the delete hook function. Don't invoke delete_hook
|
|
|
|
* again in this routine.
|
|
|
|
*/
|
|
|
|
static void route_map_free_map(struct route_map *map)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
struct route_map_list *list;
|
|
|
|
struct route_map_index *index;
|
2015-05-20 02:40:45 +02:00
|
|
|
|
2017-02-08 15:14:23 +01:00
|
|
|
if (map == NULL)
|
|
|
|
return;
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
while ((index = map->head) != NULL)
|
|
|
|
route_map_index_delete(index, 0);
|
|
|
|
|
2023-02-17 21:02:14 +01:00
|
|
|
if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP)))
|
2019-05-10 00:34:52 +02:00
|
|
|
zlog_debug("Deleting route-map %s", map->name);
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
list = &route_map_master;
|
|
|
|
|
2017-02-08 15:14:23 +01:00
|
|
|
QOBJ_UNREG(map);
|
2016-09-27 14:51:08 +02:00
|
|
|
|
2017-02-08 15:14:23 +01:00
|
|
|
if (map->next)
|
|
|
|
map->next->prev = map->prev;
|
|
|
|
else
|
|
|
|
list->tail = map->prev;
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2017-02-08 15:14:23 +01:00
|
|
|
if (map->prev)
|
|
|
|
map->prev->next = map->next;
|
|
|
|
else
|
|
|
|
list->head = map->next;
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2023-02-21 21:41:29 +01:00
|
|
|
route_table_finish(map->ipv4_prefix_table);
|
|
|
|
route_table_finish(map->ipv6_prefix_table);
|
|
|
|
|
2017-02-08 15:14:23 +01:00
|
|
|
hash_release(route_map_master_hash, map);
|
|
|
|
XFREE(MTYPE_ROUTE_MAP_NAME, map->name);
|
|
|
|
XFREE(MTYPE_ROUTE_MAP, map);
|
2015-05-20 02:40:45 +02:00
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2015-05-20 02:40:45 +02:00
|
|
|
/* Route map delete from list. */
|
2019-09-30 15:17:33 +02:00
|
|
|
void route_map_delete(struct route_map *map)
|
2015-05-20 02:40:45 +02:00
|
|
|
{
|
|
|
|
struct route_map_index *index;
|
|
|
|
char *name;
|
|
|
|
|
|
|
|
while ((index = map->head) != NULL)
|
|
|
|
route_map_index_delete(index, 0);
|
|
|
|
|
|
|
|
name = map->name;
|
|
|
|
map->head = NULL;
|
|
|
|
|
|
|
|
/* Clear all dependencies */
|
|
|
|
route_map_clear_all_references(name);
|
2018-04-29 01:52:41 +02:00
|
|
|
map->deleted = true;
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Execute deletion hook. */
|
|
|
|
if (route_map_master.delete_hook) {
|
2015-05-20 02:40:45 +02:00
|
|
|
(*route_map_master.delete_hook)(name);
|
|
|
|
route_map_notify_dependencies(name, RMAP_EVENT_CALL_DELETED);
|
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2015-05-20 02:40:45 +02:00
|
|
|
if (!map->to_be_processed) {
|
|
|
|
route_map_free_map(map);
|
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Lookup route map by route map name string. */
|
2004-10-10 Paul Jakma <paul@dishone.st>
* version.h.in: (pid_output*) add const qualifier.
* command.h: Change DEFUN func to take const char *[] rather
than char **, to begin process of fixing compile warnings in lib/.
Nearly all other changes in this commit follow from this change.
* buffer.{c,h}: (buffer_write) pointer-arithmetic is gccism, take
const void * and cast an automatic const char *p to it.
(buffer_putstr) add const
* command.c: (zencrypt) const qualifier
(cmd_execute_command_real) ditto
(cmd_execute_command_strict) ditto
(config_log_file) ditto.
Fix leak of getcwd() returned string.
* memory.{c,h}: Add MTYPE_DISTRIBUTE_IFNAME for struct dist ifname.
* distribute.{c,h}: Update with const qualifier.
(distribute_free) use MTYPE_DISTRIBUTE_IFNAME
(distribute_lookup) Cast to char *, note that it's ok.
(distribute_hash_alloc) use MTYPE_DISTRIBUTE_IFNAME.
(distribute_get) Cast to char *, note that it's ok.
* filter.c: Update with const qualifier.
* if.{c,h}: ditto.
* if_rmap.{c,h}: ditto.
(if_rmap_lookup) Cast to char *, note that it's ok.
(if_rmap_get) ditto.
* log.{c,h}: Update with const qualifier.
* plist.{c,h}: ditto.
* routemap.{c,h}: ditto.
* smux.{c,h}: ditto. Fix some signed/unsigned comparisons.
* sockopt.c: (getsockopt_cmsg_data) add return for error case.
* vty.c: Update with const qualifier.
2004-10-10 13:56:56 +02:00
|
|
|
struct route_map *route_map_lookup_by_name(const char *name)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
struct route_map *map;
|
2015-10-28 20:12:24 +01:00
|
|
|
struct route_map tmp_map;
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2015-05-20 02:40:45 +02:00
|
|
|
if (!name)
|
|
|
|
return NULL;
|
|
|
|
|
2022-03-02 21:41:54 +01:00
|
|
|
// map.deleted is false via memset
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&tmp_map, 0, sizeof(tmp_map));
|
2015-10-28 20:12:24 +01:00
|
|
|
tmp_map.name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, name);
|
|
|
|
map = hash_lookup(route_map_master_hash, &tmp_map);
|
|
|
|
XFREE(MTYPE_ROUTE_MAP_NAME, tmp_map.name);
|
2022-03-02 21:41:54 +01:00
|
|
|
|
|
|
|
if (map && map->deleted)
|
|
|
|
return NULL;
|
|
|
|
|
2015-10-28 20:12:24 +01:00
|
|
|
return map;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2018-09-14 10:56:46 +02:00
|
|
|
/* Simple helper to warn if route-map does not exist. */
|
|
|
|
struct route_map *route_map_lookup_warn_noexist(struct vty *vty, const char *name)
|
|
|
|
{
|
|
|
|
struct route_map *route_map = route_map_lookup_by_name(name);
|
|
|
|
|
|
|
|
if (!route_map)
|
|
|
|
if (vty_shell_serv(vty))
|
|
|
|
vty_out(vty, "The route-map '%s' does not exist.\n", name);
|
|
|
|
|
|
|
|
return route_map;
|
|
|
|
}
|
|
|
|
|
2018-06-20 02:44:15 +02:00
|
|
|
int route_map_mark_updated(const char *name)
|
2015-05-20 02:40:45 +02:00
|
|
|
{
|
|
|
|
struct route_map *map;
|
|
|
|
int ret = -1;
|
2015-10-28 20:12:24 +01:00
|
|
|
struct route_map tmp_map;
|
2015-05-20 02:40:45 +02:00
|
|
|
|
2015-10-28 20:12:24 +01:00
|
|
|
if (!name)
|
|
|
|
return (ret);
|
|
|
|
|
|
|
|
map = route_map_lookup_by_name(name);
|
|
|
|
|
2018-04-29 01:52:41 +02:00
|
|
|
/* If we did not find the routemap with deleted=false try again
|
|
|
|
* with deleted=true
|
2015-05-20 02:40:45 +02:00
|
|
|
*/
|
2015-10-28 20:12:24 +01:00
|
|
|
if (!map) {
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&tmp_map, 0, sizeof(tmp_map));
|
2015-10-28 20:12:24 +01:00
|
|
|
tmp_map.name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, name);
|
2018-04-29 01:52:41 +02:00
|
|
|
tmp_map.deleted = true;
|
2015-10-28 20:12:24 +01:00
|
|
|
map = hash_lookup(route_map_master_hash, &tmp_map);
|
|
|
|
XFREE(MTYPE_ROUTE_MAP_NAME, tmp_map.name);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (map) {
|
2018-04-29 01:52:41 +02:00
|
|
|
map->to_be_processed = true;
|
2015-10-28 20:12:24 +01:00
|
|
|
ret = 0;
|
|
|
|
}
|
2015-05-20 02:40:45 +02:00
|
|
|
|
|
|
|
return (ret);
|
|
|
|
}
|
|
|
|
|
2022-09-06 16:21:43 +02:00
|
|
|
static void route_map_clear_updated(struct route_map *map)
|
2015-05-20 02:40:45 +02:00
|
|
|
{
|
|
|
|
if (map) {
|
2018-04-29 01:52:41 +02:00
|
|
|
map->to_be_processed = false;
|
2015-05-20 02:40:45 +02:00
|
|
|
if (map->deleted)
|
|
|
|
route_map_free_map(map);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Lookup route map. If there isn't route map create one and return
|
|
|
|
it. */
|
2019-09-30 15:17:33 +02:00
|
|
|
struct route_map *route_map_get(const char *name)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
struct route_map *map;
|
|
|
|
|
|
|
|
map = route_map_lookup_by_name(name);
|
|
|
|
if (map == NULL)
|
|
|
|
map = route_map_add(name);
|
2015-05-20 02:40:45 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
return map;
|
|
|
|
}
|
|
|
|
|
2018-06-20 03:18:33 +02:00
|
|
|
void route_map_walk_update_list(void (*route_map_update_fn)(char *name))
|
2015-05-20 02:40:45 +02:00
|
|
|
{
|
|
|
|
struct route_map *node;
|
|
|
|
struct route_map *nnode = NULL;
|
|
|
|
|
|
|
|
for (node = route_map_master.head; node; node = nnode) {
|
|
|
|
if (node->to_be_processed) {
|
|
|
|
/* DD: Should we add any thread yield code here */
|
2016-03-22 18:46:30 +01:00
|
|
|
route_map_update_fn(node->name);
|
2015-05-20 02:40:45 +02:00
|
|
|
nnode = node->next;
|
|
|
|
route_map_clear_updated(node);
|
2017-07-17 14:03:14 +02:00
|
|
|
} else
|
2015-05-20 02:40:45 +02:00
|
|
|
nnode = node->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Return route map's type string. */
|
|
|
|
static const char *route_map_type_str(enum route_map_type type)
|
|
|
|
{
|
|
|
|
switch (type) {
|
|
|
|
case RMAP_PERMIT:
|
|
|
|
return "permit";
|
|
|
|
case RMAP_DENY:
|
|
|
|
return "deny";
|
2019-05-09 05:00:52 +02:00
|
|
|
case RMAP_ANY:
|
2002-12-13 21:15:29 +01:00
|
|
|
return "";
|
|
|
|
}
|
2019-05-16 15:20:12 +02:00
|
|
|
|
|
|
|
return "";
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
lib: Introducing a 3rd state for route-map match cmd: RMAP_NOOP
Introducing a 3rd state for route_map_apply library function: RMAP_NOOP
Traditionally route map MATCH rule apis were designed to return
a binary response, consisting of either RMAP_MATCH or RMAP_NOMATCH.
(Route-map SET rule apis return RMAP_OKAY or RMAP_ERROR).
Depending on this response, the following statemachine decided the
course of action:
State1:
If match cmd returns RMAP_MATCH then, keep existing behaviour.
If routemap type is PERMIT, execute set cmds or call cmds if applicable,
otherwise PERMIT!
Else If routemap type is DENY, we DENYMATCH right away
State2:
If match cmd returns RMAP_NOMATCH, continue on to next route-map. If there
are no other rules or if all the rules return RMAP_NOMATCH, return DENYMATCH
We require a 3rd state because of the following situation:
The issue - what if, the rule api needs to abort or ignore a rule?:
"match evpn vni xx" route-map filter can be applied to incoming routes
regardless of whether the tunnel type is vxlan or mpls.
This rule should be N/A for mpls based evpn route, but applicable to only
vxlan based evpn route.
Also, this rule should be applicable for routes with VNI label only, and
not for routes without labels. For example, type 3 and type 4 EVPN routes
do not have labels, so, this match cmd should let them through.
Today, the filter produces either a match or nomatch response regardless of
whether it is mpls/vxlan, resulting in either permitting or denying the
route.. So an mpls evpn route may get filtered out incorrectly.
Eg: "route-map RM1 permit 10 ; match evpn vni 20" or
"route-map RM2 deny 20 ; match vni 20"
With the introduction of the 3rd state, we can abort this rule check safely.
How? The rules api can now return RMAP_NOOP to indicate
that it encountered an invalid check, and needs to abort just that rule,
but continue with other rules.
As a result we have a 3rd state:
State3:
If match cmd returned RMAP_NOOP
Then, proceed to other route-map, otherwise if there are no more
rules or if all the rules return RMAP_NOOP, then, return RMAP_PERMITMATCH.
Signed-off-by: Lakshman Krishnamoorthy <lkrishnamoor@vmware.com>
2019-06-19 23:04:36 +02:00
|
|
|
static const char *route_map_cmd_result_str(enum route_map_cmd_result_t res)
|
2019-05-10 00:34:52 +02:00
|
|
|
{
|
|
|
|
switch (res) {
|
|
|
|
case RMAP_MATCH:
|
|
|
|
return "match";
|
|
|
|
case RMAP_NOMATCH:
|
|
|
|
return "no match";
|
lib: Introducing a 3rd state for route-map match cmd: RMAP_NOOP
Introducing a 3rd state for route_map_apply library function: RMAP_NOOP
Traditionally route map MATCH rule apis were designed to return
a binary response, consisting of either RMAP_MATCH or RMAP_NOMATCH.
(Route-map SET rule apis return RMAP_OKAY or RMAP_ERROR).
Depending on this response, the following statemachine decided the
course of action:
State1:
If match cmd returns RMAP_MATCH then, keep existing behaviour.
If routemap type is PERMIT, execute set cmds or call cmds if applicable,
otherwise PERMIT!
Else If routemap type is DENY, we DENYMATCH right away
State2:
If match cmd returns RMAP_NOMATCH, continue on to next route-map. If there
are no other rules or if all the rules return RMAP_NOMATCH, return DENYMATCH
We require a 3rd state because of the following situation:
The issue - what if, the rule api needs to abort or ignore a rule?:
"match evpn vni xx" route-map filter can be applied to incoming routes
regardless of whether the tunnel type is vxlan or mpls.
This rule should be N/A for mpls based evpn route, but applicable to only
vxlan based evpn route.
Also, this rule should be applicable for routes with VNI label only, and
not for routes without labels. For example, type 3 and type 4 EVPN routes
do not have labels, so, this match cmd should let them through.
Today, the filter produces either a match or nomatch response regardless of
whether it is mpls/vxlan, resulting in either permitting or denying the
route.. So an mpls evpn route may get filtered out incorrectly.
Eg: "route-map RM1 permit 10 ; match evpn vni 20" or
"route-map RM2 deny 20 ; match vni 20"
With the introduction of the 3rd state, we can abort this rule check safely.
How? The rules api can now return RMAP_NOOP to indicate
that it encountered an invalid check, and needs to abort just that rule,
but continue with other rules.
As a result we have a 3rd state:
State3:
If match cmd returned RMAP_NOOP
Then, proceed to other route-map, otherwise if there are no more
rules or if all the rules return RMAP_NOOP, then, return RMAP_PERMITMATCH.
Signed-off-by: Lakshman Krishnamoorthy <lkrishnamoor@vmware.com>
2019-06-19 23:04:36 +02:00
|
|
|
case RMAP_NOOP:
|
|
|
|
return "noop";
|
2019-05-10 00:34:52 +02:00
|
|
|
case RMAP_ERROR:
|
|
|
|
return "error";
|
|
|
|
case RMAP_OKAY:
|
|
|
|
return "okay";
|
|
|
|
}
|
|
|
|
|
|
|
|
return "invalid";
|
|
|
|
}
|
|
|
|
|
lib: Introducing a 3rd state for route-map match cmd: RMAP_NOOP
Introducing a 3rd state for route_map_apply library function: RMAP_NOOP
Traditionally route map MATCH rule apis were designed to return
a binary response, consisting of either RMAP_MATCH or RMAP_NOMATCH.
(Route-map SET rule apis return RMAP_OKAY or RMAP_ERROR).
Depending on this response, the following statemachine decided the
course of action:
State1:
If match cmd returns RMAP_MATCH then, keep existing behaviour.
If routemap type is PERMIT, execute set cmds or call cmds if applicable,
otherwise PERMIT!
Else If routemap type is DENY, we DENYMATCH right away
State2:
If match cmd returns RMAP_NOMATCH, continue on to next route-map. If there
are no other rules or if all the rules return RMAP_NOMATCH, return DENYMATCH
We require a 3rd state because of the following situation:
The issue - what if, the rule api needs to abort or ignore a rule?:
"match evpn vni xx" route-map filter can be applied to incoming routes
regardless of whether the tunnel type is vxlan or mpls.
This rule should be N/A for mpls based evpn route, but applicable to only
vxlan based evpn route.
Also, this rule should be applicable for routes with VNI label only, and
not for routes without labels. For example, type 3 and type 4 EVPN routes
do not have labels, so, this match cmd should let them through.
Today, the filter produces either a match or nomatch response regardless of
whether it is mpls/vxlan, resulting in either permitting or denying the
route.. So an mpls evpn route may get filtered out incorrectly.
Eg: "route-map RM1 permit 10 ; match evpn vni 20" or
"route-map RM2 deny 20 ; match vni 20"
With the introduction of the 3rd state, we can abort this rule check safely.
How? The rules api can now return RMAP_NOOP to indicate
that it encountered an invalid check, and needs to abort just that rule,
but continue with other rules.
As a result we have a 3rd state:
State3:
If match cmd returned RMAP_NOOP
Then, proceed to other route-map, otherwise if there are no more
rules or if all the rules return RMAP_NOOP, then, return RMAP_PERMITMATCH.
Signed-off-by: Lakshman Krishnamoorthy <lkrishnamoor@vmware.com>
2019-06-19 23:04:36 +02:00
|
|
|
static const char *route_map_result_str(route_map_result_t res)
|
|
|
|
{
|
|
|
|
switch (res) {
|
|
|
|
case RMAP_DENYMATCH:
|
|
|
|
return "deny";
|
|
|
|
case RMAP_PERMITMATCH:
|
|
|
|
return "permit";
|
|
|
|
}
|
|
|
|
|
|
|
|
return "invalid";
|
|
|
|
}
|
|
|
|
|
2004-07-09 16:00:01 +02:00
|
|
|
/* show route-map */
|
2021-08-02 20:38:26 +02:00
|
|
|
static void vty_show_route_map_entry(struct vty *vty, struct route_map *map,
|
|
|
|
json_object *json)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
struct route_map_index *index;
|
|
|
|
struct route_map_rule *rule;
|
2021-08-02 20:38:26 +02:00
|
|
|
json_object *json_rmap = NULL;
|
|
|
|
json_object *json_rules = NULL;
|
|
|
|
|
|
|
|
if (json) {
|
|
|
|
json_rmap = json_object_new_object();
|
|
|
|
json_object_object_add(json, map->name, json_rmap);
|
|
|
|
|
|
|
|
json_rules = json_object_new_array();
|
|
|
|
json_object_int_add(json_rmap, "invoked",
|
|
|
|
map->applied - map->applied_clear);
|
|
|
|
json_object_boolean_add(json_rmap, "disabledOptimization",
|
|
|
|
map->optimization_disabled);
|
|
|
|
json_object_boolean_add(json_rmap, "processedChange",
|
|
|
|
map->to_be_processed);
|
|
|
|
json_object_object_add(json_rmap, "rules", json_rules);
|
2022-10-10 16:56:51 +02:00
|
|
|
json_object_int_add(json_rmap, "cpuTimeMS", map->cputime / 1000);
|
2021-08-02 20:38:26 +02:00
|
|
|
} else {
|
|
|
|
vty_out(vty,
|
|
|
|
"route-map: %s Invoked: %" PRIu64
|
2022-10-10 16:56:51 +02:00
|
|
|
" (%zu milliseconds total) Optimization: %s Processed Change: %s\n",
|
|
|
|
map->name, map->applied - map->applied_clear, map->cputime / 1000,
|
2021-08-02 20:38:26 +02:00
|
|
|
map->optimization_disabled ? "disabled" : "enabled",
|
|
|
|
map->to_be_processed ? "true" : "false");
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-07-09 16:00:01 +02:00
|
|
|
for (index = map->head; index; index = index->next) {
|
2021-08-02 20:38:26 +02:00
|
|
|
if (json) {
|
|
|
|
json_object *json_rule;
|
|
|
|
json_object *json_matches;
|
|
|
|
json_object *json_sets;
|
|
|
|
char action[BUFSIZ] = {};
|
|
|
|
|
|
|
|
json_rule = json_object_new_object();
|
|
|
|
json_object_array_add(json_rules, json_rule);
|
|
|
|
|
|
|
|
json_object_int_add(json_rule, "sequenceNumber",
|
|
|
|
index->pref);
|
|
|
|
json_object_string_add(json_rule, "type",
|
|
|
|
route_map_type_str(index->type));
|
|
|
|
json_object_int_add(json_rule, "invoked",
|
|
|
|
index->applied
|
|
|
|
- index->applied_clear);
|
2022-10-10 16:56:51 +02:00
|
|
|
json_object_int_add(json_rule, "cpuTimeMS", index->cputime / 1000);
|
2021-08-02 20:38:26 +02:00
|
|
|
|
|
|
|
/* Description */
|
|
|
|
if (index->description)
|
|
|
|
json_object_string_add(json_rule, "description",
|
|
|
|
index->description);
|
|
|
|
|
|
|
|
/* Match clauses */
|
|
|
|
json_matches = json_object_new_array();
|
|
|
|
json_object_object_add(json_rule, "matchClauses",
|
|
|
|
json_matches);
|
|
|
|
for (rule = index->match_list.head; rule;
|
|
|
|
rule = rule->next) {
|
|
|
|
char buf[BUFSIZ];
|
|
|
|
|
|
|
|
snprintf(buf, sizeof(buf), "%s %s",
|
|
|
|
rule->cmd->str, rule->rule_str);
|
|
|
|
json_array_string_add(json_matches, buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set clauses */
|
|
|
|
json_sets = json_object_new_array();
|
|
|
|
json_object_object_add(json_rule, "setClauses",
|
|
|
|
json_sets);
|
|
|
|
for (rule = index->set_list.head; rule;
|
|
|
|
rule = rule->next) {
|
|
|
|
char buf[BUFSIZ];
|
|
|
|
|
|
|
|
snprintf(buf, sizeof(buf), "%s %s",
|
|
|
|
rule->cmd->str, rule->rule_str);
|
|
|
|
json_array_string_add(json_sets, buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Call clause */
|
|
|
|
if (index->nextrm)
|
|
|
|
json_object_string_add(json_rule, "callClause",
|
|
|
|
index->nextrm);
|
|
|
|
|
|
|
|
/* Exit Policy */
|
|
|
|
if (index->exitpolicy == RMAP_GOTO)
|
|
|
|
snprintf(action, sizeof(action), "Goto %d",
|
|
|
|
index->nextpref);
|
|
|
|
else if (index->exitpolicy == RMAP_NEXT)
|
|
|
|
snprintf(action, sizeof(action),
|
|
|
|
"Continue to next entry");
|
|
|
|
else if (index->exitpolicy == RMAP_EXIT)
|
|
|
|
snprintf(action, sizeof(action),
|
|
|
|
"Exit routemap");
|
|
|
|
if (action[0] != '\0')
|
|
|
|
json_object_string_add(json_rule, "action",
|
|
|
|
action);
|
|
|
|
} else {
|
2022-10-10 16:56:51 +02:00
|
|
|
vty_out(vty,
|
|
|
|
" %s, sequence %d Invoked %" PRIu64 " (%zu milliseconds total)\n",
|
2021-08-02 20:38:26 +02:00
|
|
|
route_map_type_str(index->type), index->pref,
|
2022-10-10 16:56:51 +02:00
|
|
|
index->applied - index->applied_clear, index->cputime / 1000);
|
2021-08-02 20:38:26 +02:00
|
|
|
|
|
|
|
/* Description */
|
|
|
|
if (index->description)
|
|
|
|
vty_out(vty, " Description:\n %s\n",
|
|
|
|
index->description);
|
|
|
|
|
|
|
|
/* Match clauses */
|
|
|
|
vty_out(vty, " Match clauses:\n");
|
|
|
|
for (rule = index->match_list.head; rule;
|
|
|
|
rule = rule->next)
|
|
|
|
vty_out(vty, " %s %s\n", rule->cmd->str,
|
|
|
|
rule->rule_str);
|
|
|
|
|
|
|
|
/* Set clauses */
|
|
|
|
vty_out(vty, " Set clauses:\n");
|
|
|
|
for (rule = index->set_list.head; rule;
|
|
|
|
rule = rule->next)
|
|
|
|
vty_out(vty, " %s %s\n", rule->cmd->str,
|
|
|
|
rule->rule_str);
|
|
|
|
|
|
|
|
/* Call clause */
|
|
|
|
vty_out(vty, " Call clause:\n");
|
|
|
|
if (index->nextrm)
|
|
|
|
vty_out(vty, " Call %s\n", index->nextrm);
|
|
|
|
|
|
|
|
/* Exit Policy */
|
|
|
|
vty_out(vty, " Action:\n");
|
|
|
|
if (index->exitpolicy == RMAP_GOTO)
|
|
|
|
vty_out(vty, " Goto %d\n", index->nextpref);
|
|
|
|
else if (index->exitpolicy == RMAP_NEXT)
|
|
|
|
vty_out(vty, " Continue to next entry\n");
|
|
|
|
else if (index->exitpolicy == RMAP_EXIT)
|
|
|
|
vty_out(vty, " Exit routemap\n");
|
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2018-08-30 23:22:22 +02:00
|
|
|
static int sort_route_map(const void **map1, const void **map2)
|
|
|
|
{
|
|
|
|
const struct route_map *m1 = *map1;
|
|
|
|
const struct route_map *m2 = *map2;
|
|
|
|
|
|
|
|
return strcmp(m1->name, m2->name);
|
|
|
|
}
|
|
|
|
|
2021-08-02 20:38:26 +02:00
|
|
|
static int vty_show_route_map(struct vty *vty, const char *name, bool use_json)
|
2004-07-09 16:00:01 +02:00
|
|
|
{
|
|
|
|
struct route_map *map;
|
2021-08-02 20:38:26 +02:00
|
|
|
json_object *json = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2023-11-20 21:32:19 +01:00
|
|
|
if (use_json)
|
2021-08-02 20:38:26 +02:00
|
|
|
json = json_object_new_object();
|
2023-11-20 21:32:19 +01:00
|
|
|
else
|
2021-08-02 20:38:26 +02:00
|
|
|
vty_out(vty, "%s:\n", frr_protonameinst);
|
2018-09-25 21:02:51 +02:00
|
|
|
|
2004-07-09 16:00:01 +02:00
|
|
|
if (name) {
|
|
|
|
map = route_map_lookup_by_name(name);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-07-09 16:00:01 +02:00
|
|
|
if (map) {
|
2023-11-20 21:32:19 +01:00
|
|
|
vty_show_route_map_entry(vty, map, json);
|
2021-08-02 20:38:26 +02:00
|
|
|
} else if (!use_json) {
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "%s: 'route-map %s' not found\n",
|
|
|
|
frr_protonameinst, name);
|
2004-07-09 16:00:01 +02:00
|
|
|
}
|
2007-05-02 18:05:35 +02:00
|
|
|
} else {
|
2018-08-30 23:22:22 +02:00
|
|
|
|
|
|
|
struct list *maplist = list_new();
|
|
|
|
struct listnode *ln;
|
|
|
|
|
2007-05-02 18:05:35 +02:00
|
|
|
for (map = route_map_master.head; map; map = map->next)
|
2018-08-30 23:22:22 +02:00
|
|
|
listnode_add(maplist, map);
|
|
|
|
|
|
|
|
list_sort(maplist, sort_route_map);
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(maplist, ln, map))
|
2023-11-20 21:32:19 +01:00
|
|
|
vty_show_route_map_entry(vty, map, json);
|
2018-08-30 23:22:22 +02:00
|
|
|
|
2018-10-02 11:39:51 +02:00
|
|
|
list_delete(&maplist);
|
2007-05-02 18:05:35 +02:00
|
|
|
}
|
2021-08-02 20:38:26 +02:00
|
|
|
|
2021-11-17 12:05:12 +01:00
|
|
|
return vty_json(vty, json);
|
2004-07-09 16:00:01 +02:00
|
|
|
}
|
|
|
|
|
2018-12-20 16:56:21 +01:00
|
|
|
/* Unused route map details */
|
|
|
|
static int vty_show_unused_route_map(struct vty *vty)
|
|
|
|
{
|
|
|
|
struct list *maplist = list_new();
|
|
|
|
struct listnode *ln;
|
|
|
|
struct route_map *map;
|
|
|
|
|
|
|
|
for (map = route_map_master.head; map; map = map->next) {
|
|
|
|
/* If use_count is zero, No protocol is using this routemap.
|
|
|
|
* so adding to the list.
|
|
|
|
*/
|
|
|
|
if (!map->use_count)
|
|
|
|
listnode_add(maplist, map);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (maplist->count > 0) {
|
|
|
|
vty_out(vty, "\n%s:\n", frr_protonameinst);
|
|
|
|
list_sort(maplist, sort_route_map);
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(maplist, ln, map))
|
2021-08-02 20:38:26 +02:00
|
|
|
vty_show_route_map_entry(vty, map, NULL);
|
2018-12-20 16:56:21 +01:00
|
|
|
} else {
|
|
|
|
vty_out(vty, "\n%s: None\n", frr_protonameinst);
|
|
|
|
}
|
|
|
|
|
|
|
|
list_delete(&maplist);
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
2004-07-09 16:00:01 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* New route map allocation. Please note route map's name must be
|
|
|
|
specified. */
|
2005-05-06 Paul Jakma <paul@dishone.st>
* (general) extern and static'ification of functions in code and
header.
Cleanup any definitions with unspecified arguments.
Add casts for callback assignments where the callback is defined,
typically, as passing void *, but the function being assigned has
some other pointer type defined as its argument, as gcc complains
about casts from void * to X* via function arguments.
Fix some old K&R style function argument definitions.
Add noreturn gcc attribute to some functions, as appropriate.
Add unused gcc attribute to some functions (eg ones meant to help
while debugging)
Add guard defines to headers which were missing them.
* command.c: (install_node) add const qualifier, still doesnt shut
up the warning though, because of the double pointer.
(cmp_node) ditto
* keychain.c: (key_str2time) Add GET_LONG_RANGE() macro, derived
fromn vty.h ones to fix some of the (long) < 0 warnings.
* thread.c: (various) use thread_empty
(cpu_record_hash_key) should cast to uintptr_t, a stdint.h type
* vty.h: Add VTY_GET_IPV4_ADDRESS and VTY_GET_IPV4_PREFIX so they
removed from ospfd/ospf_vty.h
* zebra.h: Move definition of ZEBRA_PORT to here, to remove
dependence of lib on zebra/zserv.h
2005-05-06 23:25:49 +02:00
|
|
|
static struct route_map_index *route_map_index_new(void)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
struct route_map_index *new;
|
|
|
|
|
|
|
|
new = XCALLOC(MTYPE_ROUTE_MAP_INDEX, sizeof(struct route_map_index));
|
|
|
|
new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */
|
2019-10-15 04:29:19 +02:00
|
|
|
TAILQ_INIT(&new->rhclist);
|
2016-09-27 14:51:08 +02:00
|
|
|
QOBJ_REG(new, route_map_index);
|
2002-12-13 21:15:29 +01:00
|
|
|
return new;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Free route map index. */
|
2019-09-30 15:17:33 +02:00
|
|
|
void route_map_index_delete(struct route_map_index *index, int notify)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2020-02-19 14:35:28 +01:00
|
|
|
struct routemap_hook_context *rhc;
|
2002-12-13 21:15:29 +01:00
|
|
|
struct route_map_rule *rule;
|
|
|
|
|
2016-09-27 14:51:08 +02:00
|
|
|
QOBJ_UNREG(index);
|
|
|
|
|
2023-02-17 21:02:14 +01:00
|
|
|
if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP)))
|
2019-05-10 00:34:52 +02:00
|
|
|
zlog_debug("Deleting route-map %s sequence %d",
|
|
|
|
index->map->name, index->pref);
|
|
|
|
|
2020-07-06 16:39:27 +02:00
|
|
|
/* Free route map entry description. */
|
|
|
|
XFREE(MTYPE_TMP, index->description);
|
|
|
|
|
2019-10-15 04:29:19 +02:00
|
|
|
/* Free route map northbound hook contexts. */
|
2020-02-19 14:35:28 +01:00
|
|
|
while ((rhc = TAILQ_FIRST(&index->rhclist)) != NULL)
|
|
|
|
routemap_hook_context_free(rhc);
|
2019-10-15 04:29:19 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Free route match. */
|
2019-11-02 03:42:20 +01:00
|
|
|
while ((rule = index->match_list.head) != NULL) {
|
2019-11-02 03:43:10 +01:00
|
|
|
if (IS_RULE_IPv4_PREFIX_LIST(rule->cmd->str))
|
2019-12-20 07:57:09 +01:00
|
|
|
route_map_pfx_tbl_update(RMAP_EVENT_PLIST_DELETED,
|
|
|
|
index, AFI_IP, rule->rule_str);
|
2019-11-02 03:43:10 +01:00
|
|
|
else if (IS_RULE_IPv6_PREFIX_LIST(rule->cmd->str))
|
2019-12-20 07:57:09 +01:00
|
|
|
route_map_pfx_tbl_update(RMAP_EVENT_PLIST_DELETED,
|
|
|
|
index, AFI_IP6,
|
|
|
|
rule->rule_str);
|
2019-11-02 03:42:20 +01:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
route_map_rule_delete(&index->match_list, rule);
|
2019-11-02 03:42:20 +01:00
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
/* Free route set. */
|
|
|
|
while ((rule = index->set_list.head) != NULL)
|
|
|
|
route_map_rule_delete(&index->set_list, rule);
|
|
|
|
|
|
|
|
/* Remove index from route map list. */
|
|
|
|
if (index->next)
|
|
|
|
index->next->prev = index->prev;
|
|
|
|
else
|
|
|
|
index->map->tail = index->prev;
|
|
|
|
|
|
|
|
if (index->prev)
|
|
|
|
index->prev->next = index->next;
|
|
|
|
else
|
|
|
|
index->map->head = index->next;
|
|
|
|
|
2004-09-13 Jose Luis Rubio <jrubio@dit.upm.es>
(at Technical University of Madrid as part of Euro6ix Project)
Enhanced Route Server functionality and Route-Maps:
* bgpd/bgpd.h: Modified 'struct peer' and 'struct bgp_filter' to
support rs-clients. A 'struct bgp_table *rib' has been added to the
first (to mantain a separated RIB for each rs-client) and two new
route-maps have been added to the last (for import/export policies).
Added the following #defines: RMAP_{IN|OUT|IMPORT|EXPORT|MAX},
PEER_RMAP_TYPE_{IMPORT|EXPORT} and BGP_CLEAR_SOFT_RSCLIENT.
* bgpd/bgpd.c: Modified the functions that create/delete/etc peers in
order to consider the new fields included in 'struct peer' for
supporting rs-clients, i.e. the import/export route-maps and the
'struct bgp_table'.
* bgpd/bgp_route.{ch}: Modified several functions related with
receiving/sending announces in order to support the new Route Server
capabilities.
Function 'bgp_process' has been reorganized, creating an auxiliar
function for best path selection ('bgp_best_selection').
Modified 'bgp_show' and 'bgp_show_route' for displaying information
about any RIB (and not only the main bgp RIB).
Added commands for displaying information about RS-clients RIBs:
'show bgp rsclient (A.B.C.D|X:X::X:X)', 'show bgp rsclient
(A.B.C.D|X:X::X:X) X:X::X:X/M', etc
* bgpd/bgp_table.{ch}: The structure 'struct bgp_table' now has two
new fields: type (which can take the values BGP_TABLE_{MAIN|RSCLIENT})
and 'void *owner' which points to 'struct bgp' or 'struct peer' which
owns the table.
When creating a new bgp_table by default 'type=BGP_TABLE_MAIN' is set.
* bgpd/bgp_vty.c: The commands 'neighbor ... route-server-client' and
'no neighbor ... route-server-client' now not only set/unset the flag
PEER_FLAG_RSERVER_CLIENT, but they create/destroy the 'struct
bgp_table' of the peer. Special actions are taken for peer_groups.
Command 'neighbor ... route-map WORD (in|out)' now also supports two
new kinds of route-map: 'import' and 'export'.
Added commands 'clear bgp * rsclient', etc. These commands allow a new
kind of soft_reconfig which affects only the RIB of the specified
RS-client.
Added commands 'show bgp rsclient summary', etc which display a
summary of the rs-clients configured for the corresponding address
family.
* bgpd/bgp_routemap.c: A new match statement is available,
'match peer (A.B.C.D|X:X::X:X)'. This statement can only be used in
import/export route-maps, and it matches when the peer who announces
(when used in an import route-map) or is going to receive (when used
in an export route-map) the route is the same than the one specified
in the statement.
For peer-groups the statement matches if the specified peer is member
of the peer-group.
A special version of the command, 'match peer local', matches with
routes originated by the Route Server (defined with 'network ...',
redistributed routes and default-originate).
* lib/routemap.{ch}: Added a new clause 'call NAME' for use in
route-maps. It jumps into the specified route-map and when it returns
the first route-map ends if the called RM returns DENY_MATCH, or
continues in other case.
2004-09-13 07:12:46 +02:00
|
|
|
/* Free 'char *nextrm' if not NULL */
|
2019-02-25 21:18:13 +01:00
|
|
|
XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
|
2004-09-13 Jose Luis Rubio <jrubio@dit.upm.es>
(at Technical University of Madrid as part of Euro6ix Project)
Enhanced Route Server functionality and Route-Maps:
* bgpd/bgpd.h: Modified 'struct peer' and 'struct bgp_filter' to
support rs-clients. A 'struct bgp_table *rib' has been added to the
first (to mantain a separated RIB for each rs-client) and two new
route-maps have been added to the last (for import/export policies).
Added the following #defines: RMAP_{IN|OUT|IMPORT|EXPORT|MAX},
PEER_RMAP_TYPE_{IMPORT|EXPORT} and BGP_CLEAR_SOFT_RSCLIENT.
* bgpd/bgpd.c: Modified the functions that create/delete/etc peers in
order to consider the new fields included in 'struct peer' for
supporting rs-clients, i.e. the import/export route-maps and the
'struct bgp_table'.
* bgpd/bgp_route.{ch}: Modified several functions related with
receiving/sending announces in order to support the new Route Server
capabilities.
Function 'bgp_process' has been reorganized, creating an auxiliar
function for best path selection ('bgp_best_selection').
Modified 'bgp_show' and 'bgp_show_route' for displaying information
about any RIB (and not only the main bgp RIB).
Added commands for displaying information about RS-clients RIBs:
'show bgp rsclient (A.B.C.D|X:X::X:X)', 'show bgp rsclient
(A.B.C.D|X:X::X:X) X:X::X:X/M', etc
* bgpd/bgp_table.{ch}: The structure 'struct bgp_table' now has two
new fields: type (which can take the values BGP_TABLE_{MAIN|RSCLIENT})
and 'void *owner' which points to 'struct bgp' or 'struct peer' which
owns the table.
When creating a new bgp_table by default 'type=BGP_TABLE_MAIN' is set.
* bgpd/bgp_vty.c: The commands 'neighbor ... route-server-client' and
'no neighbor ... route-server-client' now not only set/unset the flag
PEER_FLAG_RSERVER_CLIENT, but they create/destroy the 'struct
bgp_table' of the peer. Special actions are taken for peer_groups.
Command 'neighbor ... route-map WORD (in|out)' now also supports two
new kinds of route-map: 'import' and 'export'.
Added commands 'clear bgp * rsclient', etc. These commands allow a new
kind of soft_reconfig which affects only the RIB of the specified
RS-client.
Added commands 'show bgp rsclient summary', etc which display a
summary of the rs-clients configured for the corresponding address
family.
* bgpd/bgp_routemap.c: A new match statement is available,
'match peer (A.B.C.D|X:X::X:X)'. This statement can only be used in
import/export route-maps, and it matches when the peer who announces
(when used in an import route-map) or is going to receive (when used
in an export route-map) the route is the same than the one specified
in the statement.
For peer-groups the statement matches if the specified peer is member
of the peer-group.
A special version of the command, 'match peer local', matches with
routes originated by the Route Server (defined with 'network ...',
redistributed routes and default-originate).
* lib/routemap.{ch}: Added a new clause 'call NAME' for use in
route-maps. It jumps into the specified route-map and when it returns
the first route-map ends if the called RM returns DENY_MATCH, or
continues in other case.
2004-09-13 07:12:46 +02:00
|
|
|
|
2019-12-20 07:57:09 +01:00
|
|
|
route_map_pfx_tbl_update(RMAP_EVENT_INDEX_DELETED, index, 0, NULL);
|
2019-11-02 03:42:20 +01:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Execute event hook. */
|
|
|
|
if (route_map_master.event_hook && notify) {
|
2019-05-09 05:19:55 +02:00
|
|
|
(*route_map_master.event_hook)(index->map->name);
|
2015-05-20 02:40:45 +02:00
|
|
|
route_map_notify_dependencies(index->map->name,
|
|
|
|
RMAP_EVENT_CALL_ADDED);
|
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
XFREE(MTYPE_ROUTE_MAP_INDEX, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Lookup index from route map. */
|
|
|
|
static struct route_map_index *route_map_index_lookup(struct route_map *map,
|
|
|
|
enum route_map_type type,
|
|
|
|
int pref)
|
|
|
|
{
|
|
|
|
struct route_map_index *index;
|
|
|
|
|
|
|
|
for (index = map->head; index; index = index->next)
|
|
|
|
if ((index->type == type || type == RMAP_ANY)
|
|
|
|
&& index->pref == pref)
|
|
|
|
return index;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add new index to route map. */
|
2005-05-06 Paul Jakma <paul@dishone.st>
* (general) extern and static'ification of functions in code and
header.
Cleanup any definitions with unspecified arguments.
Add casts for callback assignments where the callback is defined,
typically, as passing void *, but the function being assigned has
some other pointer type defined as its argument, as gcc complains
about casts from void * to X* via function arguments.
Fix some old K&R style function argument definitions.
Add noreturn gcc attribute to some functions, as appropriate.
Add unused gcc attribute to some functions (eg ones meant to help
while debugging)
Add guard defines to headers which were missing them.
* command.c: (install_node) add const qualifier, still doesnt shut
up the warning though, because of the double pointer.
(cmp_node) ditto
* keychain.c: (key_str2time) Add GET_LONG_RANGE() macro, derived
fromn vty.h ones to fix some of the (long) < 0 warnings.
* thread.c: (various) use thread_empty
(cpu_record_hash_key) should cast to uintptr_t, a stdint.h type
* vty.h: Add VTY_GET_IPV4_ADDRESS and VTY_GET_IPV4_PREFIX so they
removed from ospfd/ospf_vty.h
* zebra.h: Move definition of ZEBRA_PORT to here, to remove
dependence of lib on zebra/zserv.h
2005-05-06 23:25:49 +02:00
|
|
|
static struct route_map_index *
|
2002-12-13 21:15:29 +01:00
|
|
|
route_map_index_add(struct route_map *map, enum route_map_type type, int pref)
|
|
|
|
{
|
|
|
|
struct route_map_index *index;
|
|
|
|
struct route_map_index *point;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Allocate new route map inex. */
|
|
|
|
index = route_map_index_new();
|
|
|
|
index->map = map;
|
|
|
|
index->type = type;
|
|
|
|
index->pref = pref;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Compare preference. */
|
|
|
|
for (point = map->head; point; point = point->next)
|
|
|
|
if (point->pref >= pref)
|
|
|
|
break;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
if (map->head == NULL) {
|
|
|
|
map->head = map->tail = index;
|
|
|
|
} else if (point == NULL) {
|
|
|
|
index->prev = map->tail;
|
|
|
|
map->tail->next = index;
|
|
|
|
map->tail = index;
|
|
|
|
} else if (point == map->head) {
|
|
|
|
index->next = map->head;
|
|
|
|
map->head->prev = index;
|
|
|
|
map->head = index;
|
|
|
|
} else {
|
|
|
|
index->next = point;
|
|
|
|
index->prev = point->prev;
|
|
|
|
if (point->prev)
|
|
|
|
point->prev->next = index;
|
|
|
|
point->prev = index;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-12-20 07:57:09 +01:00
|
|
|
route_map_pfx_tbl_update(RMAP_EVENT_INDEX_ADDED, index, 0, NULL);
|
2019-11-02 03:42:20 +01:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Execute event hook. */
|
|
|
|
if (route_map_master.event_hook) {
|
2019-05-09 05:19:55 +02:00
|
|
|
(*route_map_master.event_hook)(map->name);
|
2015-05-20 02:40:45 +02:00
|
|
|
route_map_notify_dependencies(map->name, RMAP_EVENT_CALL_ADDED);
|
|
|
|
}
|
2019-05-10 00:34:52 +02:00
|
|
|
|
2023-02-17 21:02:14 +01:00
|
|
|
if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP)))
|
2019-05-10 00:34:52 +02:00
|
|
|
zlog_debug("Route-map %s add sequence %d, type: %s",
|
|
|
|
map->name, pref, route_map_type_str(type));
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get route map index. */
|
2019-09-30 15:17:33 +02:00
|
|
|
struct route_map_index *
|
2002-12-13 21:15:29 +01:00
|
|
|
route_map_index_get(struct route_map *map, enum route_map_type type, int pref)
|
|
|
|
{
|
|
|
|
struct route_map_index *index;
|
|
|
|
|
|
|
|
index = route_map_index_lookup(map, RMAP_ANY, pref);
|
|
|
|
if (index && index->type != type) {
|
|
|
|
/* Delete index from route map. */
|
|
|
|
route_map_index_delete(index, 1);
|
|
|
|
index = NULL;
|
|
|
|
}
|
|
|
|
if (index == NULL)
|
|
|
|
index = route_map_index_add(map, type, pref);
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* New route map rule */
|
2005-05-06 Paul Jakma <paul@dishone.st>
* (general) extern and static'ification of functions in code and
header.
Cleanup any definitions with unspecified arguments.
Add casts for callback assignments where the callback is defined,
typically, as passing void *, but the function being assigned has
some other pointer type defined as its argument, as gcc complains
about casts from void * to X* via function arguments.
Fix some old K&R style function argument definitions.
Add noreturn gcc attribute to some functions, as appropriate.
Add unused gcc attribute to some functions (eg ones meant to help
while debugging)
Add guard defines to headers which were missing them.
* command.c: (install_node) add const qualifier, still doesnt shut
up the warning though, because of the double pointer.
(cmp_node) ditto
* keychain.c: (key_str2time) Add GET_LONG_RANGE() macro, derived
fromn vty.h ones to fix some of the (long) < 0 warnings.
* thread.c: (various) use thread_empty
(cpu_record_hash_key) should cast to uintptr_t, a stdint.h type
* vty.h: Add VTY_GET_IPV4_ADDRESS and VTY_GET_IPV4_PREFIX so they
removed from ospfd/ospf_vty.h
* zebra.h: Move definition of ZEBRA_PORT to here, to remove
dependence of lib on zebra/zserv.h
2005-05-06 23:25:49 +02:00
|
|
|
static struct route_map_rule *route_map_rule_new(void)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
struct route_map_rule *new;
|
|
|
|
|
|
|
|
new = XCALLOC(MTYPE_ROUTE_MAP_RULE, sizeof(struct route_map_rule));
|
|
|
|
return new;
|
|
|
|
}
|
2014-06-04 06:53:35 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Install rule command to the match list. */
|
2021-11-06 16:57:52 +01:00
|
|
|
void _route_map_install_match(struct route_map_rule_cmd_proxy *proxy)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2021-11-06 16:57:52 +01:00
|
|
|
rmap_cmd_name_add(rmap_match_cmds, proxy);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Install rule command to the set list. */
|
2021-11-06 16:57:52 +01:00
|
|
|
void _route_map_install_set(struct route_map_rule_cmd_proxy *proxy)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2021-11-06 16:57:52 +01:00
|
|
|
rmap_cmd_name_add(rmap_set_cmds, proxy);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Lookup rule command from match list. */
|
2019-11-20 17:20:58 +01:00
|
|
|
static const struct route_map_rule_cmd *route_map_lookup_match(const char *name)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2021-11-06 16:57:52 +01:00
|
|
|
struct route_map_rule_cmd refcmd = {.str = name};
|
|
|
|
struct route_map_rule_cmd_proxy ref = {.cmd = &refcmd};
|
|
|
|
struct route_map_rule_cmd_proxy *res;
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2021-11-06 16:57:52 +01:00
|
|
|
res = rmap_cmd_name_find(rmap_match_cmds, &ref);
|
|
|
|
if (res)
|
|
|
|
return res->cmd;
|
2002-12-13 21:15:29 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Lookup rule command from set list. */
|
2019-11-20 17:20:58 +01:00
|
|
|
static const struct route_map_rule_cmd *route_map_lookup_set(const char *name)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2021-11-06 16:57:52 +01:00
|
|
|
struct route_map_rule_cmd refcmd = {.str = name};
|
|
|
|
struct route_map_rule_cmd_proxy ref = {.cmd = &refcmd};
|
|
|
|
struct route_map_rule_cmd_proxy *res;
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2021-11-06 16:57:52 +01:00
|
|
|
res = rmap_cmd_name_find(rmap_set_cmds, &ref);
|
|
|
|
if (res)
|
|
|
|
return res->cmd;
|
2002-12-13 21:15:29 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add match and set rule to rule list. */
|
|
|
|
static void route_map_rule_add(struct route_map_rule_list *list,
|
|
|
|
struct route_map_rule *rule)
|
|
|
|
{
|
|
|
|
rule->next = NULL;
|
|
|
|
rule->prev = list->tail;
|
|
|
|
if (list->tail)
|
|
|
|
list->tail->next = rule;
|
|
|
|
else
|
|
|
|
list->head = rule;
|
|
|
|
list->tail = rule;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Delete rule from rule list. */
|
|
|
|
static void route_map_rule_delete(struct route_map_rule_list *list,
|
|
|
|
struct route_map_rule *rule)
|
|
|
|
{
|
|
|
|
if (rule->cmd->func_free)
|
|
|
|
(*rule->cmd->func_free)(rule->value);
|
|
|
|
|
2019-02-25 21:18:13 +01:00
|
|
|
XFREE(MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
if (rule->next)
|
|
|
|
rule->next->prev = rule->prev;
|
|
|
|
else
|
|
|
|
list->tail = rule->prev;
|
|
|
|
if (rule->prev)
|
|
|
|
rule->prev->next = rule->next;
|
|
|
|
else
|
|
|
|
list->head = rule->next;
|
|
|
|
|
|
|
|
XFREE(MTYPE_ROUTE_MAP_RULE, rule);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* strcmp wrapper function which don't crush even argument is NULL. */
|
2004-10-11 13:28:44 +02:00
|
|
|
static int rulecmp(const char *dst, const char *src)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
if (dst == NULL) {
|
|
|
|
if (src == NULL)
|
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
if (src == NULL)
|
|
|
|
return 1;
|
2017-07-17 14:03:14 +02:00
|
|
|
else
|
2002-12-13 21:15:29 +01:00
|
|
|
return strcmp(dst, src);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-05-20 02:40:45 +02:00
|
|
|
/* Use this to return the already specified argument for this match. This is
|
|
|
|
* useful to get the specified argument with a route map match rule when the
|
|
|
|
* rule is being deleted and the argument is not provided.
|
|
|
|
*/
|
|
|
|
const char *route_map_get_match_arg(struct route_map_index *index,
|
|
|
|
const char *match_name)
|
|
|
|
{
|
|
|
|
struct route_map_rule *rule;
|
2019-11-20 17:20:58 +01:00
|
|
|
const struct route_map_rule_cmd *cmd;
|
2015-05-20 02:40:45 +02:00
|
|
|
|
|
|
|
/* First lookup rule for add match statement. */
|
|
|
|
cmd = route_map_lookup_match(match_name);
|
|
|
|
if (cmd == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
for (rule = index->match_list.head; rule; rule = rule->next)
|
|
|
|
if (rule->cmd == cmd && rule->rule_str != NULL)
|
|
|
|
return (rule->rule_str);
|
|
|
|
|
2020-02-09 13:21:56 +01:00
|
|
|
return NULL;
|
2015-05-20 02:40:45 +02:00
|
|
|
}
|
|
|
|
|
2019-05-15 09:09:08 +02:00
|
|
|
static route_map_event_t get_route_map_delete_event(route_map_event_t type)
|
|
|
|
{
|
|
|
|
switch (type) {
|
|
|
|
case RMAP_EVENT_CALL_ADDED:
|
|
|
|
return RMAP_EVENT_CALL_DELETED;
|
|
|
|
case RMAP_EVENT_PLIST_ADDED:
|
|
|
|
return RMAP_EVENT_PLIST_DELETED;
|
|
|
|
case RMAP_EVENT_CLIST_ADDED:
|
|
|
|
return RMAP_EVENT_CLIST_DELETED;
|
|
|
|
case RMAP_EVENT_ECLIST_ADDED:
|
|
|
|
return RMAP_EVENT_ECLIST_DELETED;
|
|
|
|
case RMAP_EVENT_LLIST_ADDED:
|
|
|
|
return RMAP_EVENT_LLIST_DELETED;
|
|
|
|
case RMAP_EVENT_ASLIST_ADDED:
|
|
|
|
return RMAP_EVENT_ASLIST_DELETED;
|
|
|
|
case RMAP_EVENT_FILTER_ADDED:
|
|
|
|
return RMAP_EVENT_FILTER_DELETED;
|
|
|
|
case RMAP_EVENT_SET_ADDED:
|
|
|
|
case RMAP_EVENT_SET_DELETED:
|
|
|
|
case RMAP_EVENT_SET_REPLACED:
|
|
|
|
case RMAP_EVENT_MATCH_ADDED:
|
|
|
|
case RMAP_EVENT_MATCH_DELETED:
|
|
|
|
case RMAP_EVENT_MATCH_REPLACED:
|
|
|
|
case RMAP_EVENT_INDEX_ADDED:
|
|
|
|
case RMAP_EVENT_INDEX_DELETED:
|
|
|
|
case RMAP_EVENT_CALL_DELETED:
|
|
|
|
case RMAP_EVENT_PLIST_DELETED:
|
|
|
|
case RMAP_EVENT_CLIST_DELETED:
|
|
|
|
case RMAP_EVENT_ECLIST_DELETED:
|
|
|
|
case RMAP_EVENT_LLIST_DELETED:
|
|
|
|
case RMAP_EVENT_ASLIST_DELETED:
|
|
|
|
case RMAP_EVENT_FILTER_DELETED:
|
|
|
|
/* This function returns the appropriate 'deleted' event type
|
|
|
|
* for every 'added' event type passed to this function.
|
|
|
|
* This is done only for named entities used in the
|
|
|
|
* route-map match commands.
|
|
|
|
* This function is not to be invoked for any of the other event
|
|
|
|
* types.
|
|
|
|
*/
|
|
|
|
assert(0);
|
|
|
|
}
|
2019-06-03 16:44:23 +02:00
|
|
|
|
|
|
|
assert(0);
|
|
|
|
/*
|
|
|
|
* Return to make c happy but if we get here something has gone
|
|
|
|
* terribly terribly wrong, so yes this return makes no sense.
|
|
|
|
*/
|
|
|
|
return RMAP_EVENT_CALL_ADDED;
|
2019-05-15 09:09:08 +02:00
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Add match statement to route map. */
|
2019-08-27 14:04:43 +02:00
|
|
|
enum rmap_compile_rets route_map_add_match(struct route_map_index *index,
|
|
|
|
const char *match_name,
|
|
|
|
const char *match_arg,
|
|
|
|
route_map_event_t type)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
struct route_map_rule *rule;
|
|
|
|
struct route_map_rule *next;
|
2019-11-20 17:20:58 +01:00
|
|
|
const struct route_map_rule_cmd *cmd;
|
2002-12-13 21:15:29 +01:00
|
|
|
void *compile;
|
2019-05-15 09:09:08 +02:00
|
|
|
int8_t delete_rmap_event_type = 0;
|
2019-08-27 12:45:54 +02:00
|
|
|
const char *rule_key;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* First lookup rule for add match statement. */
|
|
|
|
cmd = route_map_lookup_match(match_name);
|
|
|
|
if (cmd == NULL)
|
|
|
|
return RMAP_RULE_MISSING;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Next call compile function for this match statement. */
|
|
|
|
if (cmd->func_compile) {
|
|
|
|
compile = (*cmd->func_compile)(match_arg);
|
|
|
|
if (compile == NULL)
|
|
|
|
return RMAP_COMPILE_ERROR;
|
|
|
|
} else
|
|
|
|
compile = NULL;
|
2019-08-27 12:45:54 +02:00
|
|
|
/* use the compiled results if applicable */
|
|
|
|
if (compile && cmd->func_get_rmap_rule_key)
|
|
|
|
rule_key = (*cmd->func_get_rmap_rule_key)
|
|
|
|
(compile);
|
|
|
|
else
|
|
|
|
rule_key = match_arg;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* If argument is completely same ignore it. */
|
|
|
|
for (rule = index->match_list.head; rule; rule = next) {
|
|
|
|
next = rule->next;
|
|
|
|
if (rule->cmd == cmd) {
|
2019-05-08 11:58:27 +02:00
|
|
|
/* If the configured route-map match rule is exactly
|
|
|
|
* the same as the existing configuration then,
|
|
|
|
* ignore the duplicate configuration.
|
|
|
|
*/
|
2021-08-12 18:07:53 +02:00
|
|
|
if (rulecmp(match_arg, rule->rule_str) == 0) {
|
2019-05-08 11:58:27 +02:00
|
|
|
if (cmd->func_free)
|
|
|
|
(*cmd->func_free)(compile);
|
2019-05-15 09:09:08 +02:00
|
|
|
|
2019-08-27 12:45:54 +02:00
|
|
|
return RMAP_COMPILE_SUCCESS;
|
2019-05-15 09:09:08 +02:00
|
|
|
}
|
|
|
|
|
2019-11-02 03:42:20 +01:00
|
|
|
/* If IPv4 or IPv6 prefix-list match criteria
|
|
|
|
* has been delete to the route-map index, update
|
|
|
|
* the route-map's prefix table.
|
|
|
|
*/
|
2019-11-02 03:43:10 +01:00
|
|
|
if (IS_RULE_IPv4_PREFIX_LIST(match_name))
|
2019-11-02 03:42:20 +01:00
|
|
|
route_map_pfx_tbl_update(
|
2019-12-20 07:57:09 +01:00
|
|
|
RMAP_EVENT_PLIST_DELETED, index, AFI_IP,
|
|
|
|
rule->rule_str);
|
2019-11-02 03:43:10 +01:00
|
|
|
else if (IS_RULE_IPv6_PREFIX_LIST(match_name))
|
2019-11-02 03:42:20 +01:00
|
|
|
route_map_pfx_tbl_update(
|
2019-12-20 07:57:09 +01:00
|
|
|
RMAP_EVENT_PLIST_DELETED, index,
|
|
|
|
AFI_IP6, rule->rule_str);
|
2019-11-02 03:42:20 +01:00
|
|
|
|
2019-05-15 09:09:08 +02:00
|
|
|
/* Remove the dependency of the route-map on the rule
|
|
|
|
* that is being replaced.
|
|
|
|
*/
|
|
|
|
if (type >= RMAP_EVENT_CALL_ADDED) {
|
|
|
|
delete_rmap_event_type =
|
|
|
|
get_route_map_delete_event(type);
|
|
|
|
route_map_upd8_dependency(
|
|
|
|
delete_rmap_event_type,
|
2020-12-18 20:22:09 +01:00
|
|
|
rule->rule_str,
|
2019-05-15 09:09:08 +02:00
|
|
|
index->map->name);
|
2019-05-08 11:58:27 +02:00
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
route_map_rule_delete(&index->match_list, rule);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Add new route map match rule. */
|
|
|
|
rule = route_map_rule_new();
|
|
|
|
rule->cmd = cmd;
|
|
|
|
rule->value = compile;
|
|
|
|
if (match_arg)
|
|
|
|
rule->rule_str = XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR, match_arg);
|
|
|
|
else
|
|
|
|
rule->rule_str = NULL;
|
|
|
|
|
|
|
|
/* Add new route match rule to linked list. */
|
|
|
|
route_map_rule_add(&index->match_list, rule);
|
|
|
|
|
2019-11-02 03:42:20 +01:00
|
|
|
/* If IPv4 or IPv6 prefix-list match criteria
|
|
|
|
* has been added to the route-map index, update
|
|
|
|
* the route-map's prefix table.
|
|
|
|
*/
|
2019-11-02 03:43:10 +01:00
|
|
|
if (IS_RULE_IPv4_PREFIX_LIST(match_name)) {
|
2019-12-20 07:57:09 +01:00
|
|
|
route_map_pfx_tbl_update(RMAP_EVENT_PLIST_ADDED, index, AFI_IP,
|
2019-11-02 03:42:20 +01:00
|
|
|
match_arg);
|
2019-11-02 03:43:10 +01:00
|
|
|
} else if (IS_RULE_IPv6_PREFIX_LIST(match_name)) {
|
2019-12-20 07:57:09 +01:00
|
|
|
route_map_pfx_tbl_update(RMAP_EVENT_PLIST_ADDED, index, AFI_IP6,
|
2019-11-02 03:42:20 +01:00
|
|
|
match_arg);
|
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Execute event hook. */
|
|
|
|
if (route_map_master.event_hook) {
|
2019-05-09 05:19:55 +02:00
|
|
|
(*route_map_master.event_hook)(index->map->name);
|
2015-05-20 02:40:45 +02:00
|
|
|
route_map_notify_dependencies(index->map->name,
|
|
|
|
RMAP_EVENT_CALL_ADDED);
|
|
|
|
}
|
2019-08-27 12:45:54 +02:00
|
|
|
if (type != RMAP_EVENT_MATCH_ADDED)
|
|
|
|
route_map_upd8_dependency(type, rule_key, index->map->name);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2017-08-25 14:31:03 +02:00
|
|
|
return RMAP_COMPILE_SUCCESS;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Delete specified route match rule. */
|
2019-08-27 14:04:43 +02:00
|
|
|
enum rmap_compile_rets route_map_delete_match(struct route_map_index *index,
|
|
|
|
const char *match_name,
|
2019-08-27 12:45:54 +02:00
|
|
|
const char *match_arg,
|
|
|
|
route_map_event_t type)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
struct route_map_rule *rule;
|
2019-11-20 17:20:58 +01:00
|
|
|
const struct route_map_rule_cmd *cmd;
|
2019-08-27 12:45:54 +02:00
|
|
|
const char *rule_key;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
cmd = route_map_lookup_match(match_name);
|
|
|
|
if (cmd == NULL)
|
2019-08-27 13:45:02 +02:00
|
|
|
return RMAP_RULE_MISSING;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
for (rule = index->match_list.head; rule; rule = rule->next)
|
2017-07-22 14:52:33 +02:00
|
|
|
if (rule->cmd == cmd && (rulecmp(rule->rule_str, match_arg) == 0
|
|
|
|
|| match_arg == NULL)) {
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Execute event hook. */
|
|
|
|
if (route_map_master.event_hook) {
|
2019-05-09 05:19:55 +02:00
|
|
|
(*route_map_master.event_hook)(index->map->name);
|
2015-05-20 02:40:45 +02:00
|
|
|
route_map_notify_dependencies(
|
|
|
|
index->map->name,
|
|
|
|
RMAP_EVENT_CALL_ADDED);
|
|
|
|
}
|
2019-08-27 12:45:54 +02:00
|
|
|
if (cmd->func_get_rmap_rule_key)
|
|
|
|
rule_key = (*cmd->func_get_rmap_rule_key)
|
|
|
|
(rule->value);
|
|
|
|
else
|
|
|
|
rule_key = match_arg;
|
|
|
|
|
|
|
|
if (type != RMAP_EVENT_MATCH_DELETED && rule_key)
|
|
|
|
route_map_upd8_dependency(type, rule_key,
|
|
|
|
index->map->name);
|
|
|
|
|
|
|
|
route_map_rule_delete(&index->match_list, rule);
|
2019-11-02 03:42:20 +01:00
|
|
|
|
|
|
|
/* If IPv4 or IPv6 prefix-list match criteria
|
2020-05-14 16:09:42 +02:00
|
|
|
* has been delete from the route-map index, update
|
2019-11-02 03:42:20 +01:00
|
|
|
* the route-map's prefix table.
|
|
|
|
*/
|
2019-11-02 03:43:10 +01:00
|
|
|
if (IS_RULE_IPv4_PREFIX_LIST(match_name)) {
|
2019-11-02 03:42:20 +01:00
|
|
|
route_map_pfx_tbl_update(
|
2019-12-20 07:57:09 +01:00
|
|
|
RMAP_EVENT_PLIST_DELETED, index, AFI_IP,
|
|
|
|
match_arg);
|
2019-11-02 03:43:10 +01:00
|
|
|
} else if (IS_RULE_IPv6_PREFIX_LIST(match_name)) {
|
2019-11-02 03:42:20 +01:00
|
|
|
route_map_pfx_tbl_update(
|
2019-12-20 07:57:09 +01:00
|
|
|
RMAP_EVENT_PLIST_DELETED, index,
|
|
|
|
AFI_IP6, match_arg);
|
2019-11-02 03:42:20 +01:00
|
|
|
}
|
|
|
|
|
2019-08-27 13:45:02 +02:00
|
|
|
return RMAP_COMPILE_SUCCESS;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
/* Can't find matched rule. */
|
2019-08-27 13:45:02 +02:00
|
|
|
return RMAP_RULE_MISSING;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Add route-map set statement to the route map. */
|
2019-08-27 14:04:43 +02:00
|
|
|
enum rmap_compile_rets route_map_add_set(struct route_map_index *index,
|
|
|
|
const char *set_name,
|
|
|
|
const char *set_arg)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
struct route_map_rule *rule;
|
|
|
|
struct route_map_rule *next;
|
2019-11-20 17:20:58 +01:00
|
|
|
const struct route_map_rule_cmd *cmd;
|
2002-12-13 21:15:29 +01:00
|
|
|
void *compile;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
cmd = route_map_lookup_set(set_name);
|
|
|
|
if (cmd == NULL)
|
|
|
|
return RMAP_RULE_MISSING;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Next call compile function for this match statement. */
|
|
|
|
if (cmd->func_compile) {
|
|
|
|
compile = (*cmd->func_compile)(set_arg);
|
|
|
|
if (compile == NULL)
|
|
|
|
return RMAP_COMPILE_ERROR;
|
|
|
|
} else
|
|
|
|
compile = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Add by WJL. if old set command of same kind exist, delete it first
|
|
|
|
to ensure only one set command of same kind exist under a
|
|
|
|
route_map_index. */
|
|
|
|
for (rule = index->set_list.head; rule; rule = next) {
|
|
|
|
next = rule->next;
|
2019-05-16 15:20:12 +02:00
|
|
|
if (rule->cmd == cmd)
|
2002-12-13 21:15:29 +01:00
|
|
|
route_map_rule_delete(&index->set_list, rule);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Add new route map match rule. */
|
|
|
|
rule = route_map_rule_new();
|
|
|
|
rule->cmd = cmd;
|
|
|
|
rule->value = compile;
|
|
|
|
if (set_arg)
|
|
|
|
rule->rule_str = XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR, set_arg);
|
|
|
|
else
|
|
|
|
rule->rule_str = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Add new route match rule to linked list. */
|
|
|
|
route_map_rule_add(&index->set_list, rule);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Execute event hook. */
|
|
|
|
if (route_map_master.event_hook) {
|
2019-05-09 05:19:55 +02:00
|
|
|
(*route_map_master.event_hook)(index->map->name);
|
2015-05-20 02:40:45 +02:00
|
|
|
route_map_notify_dependencies(index->map->name,
|
2002-12-13 21:15:29 +01:00
|
|
|
RMAP_EVENT_CALL_ADDED);
|
|
|
|
}
|
2017-08-25 14:31:03 +02:00
|
|
|
return RMAP_COMPILE_SUCCESS;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Delete route map set rule. */
|
2019-08-27 14:04:43 +02:00
|
|
|
enum rmap_compile_rets route_map_delete_set(struct route_map_index *index,
|
|
|
|
const char *set_name,
|
|
|
|
const char *set_arg)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
struct route_map_rule *rule;
|
2019-11-20 17:20:58 +01:00
|
|
|
const struct route_map_rule_cmd *cmd;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
cmd = route_map_lookup_set(set_name);
|
|
|
|
if (cmd == NULL)
|
2019-08-27 13:45:02 +02:00
|
|
|
return RMAP_RULE_MISSING;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
for (rule = index->set_list.head; rule; rule = rule->next)
|
2017-07-22 14:52:33 +02:00
|
|
|
if ((rule->cmd == cmd) && (rulecmp(rule->rule_str, set_arg) == 0
|
|
|
|
|| set_arg == NULL)) {
|
2002-12-13 21:15:29 +01:00
|
|
|
route_map_rule_delete(&index->set_list, rule);
|
|
|
|
/* Execute event hook. */
|
|
|
|
if (route_map_master.event_hook) {
|
2019-05-09 05:19:55 +02:00
|
|
|
(*route_map_master.event_hook)(index->map->name);
|
2015-05-20 02:40:45 +02:00
|
|
|
route_map_notify_dependencies(
|
|
|
|
index->map->name,
|
|
|
|
RMAP_EVENT_CALL_ADDED);
|
|
|
|
}
|
2019-08-27 13:45:02 +02:00
|
|
|
return RMAP_COMPILE_SUCCESS;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
/* Can't find matched rule. */
|
2019-08-27 13:45:02 +02:00
|
|
|
return RMAP_RULE_MISSING;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
lib: Introducing a 3rd state for route-map match cmd: RMAP_NOOP
Introducing a 3rd state for route_map_apply library function: RMAP_NOOP
Traditionally route map MATCH rule apis were designed to return
a binary response, consisting of either RMAP_MATCH or RMAP_NOMATCH.
(Route-map SET rule apis return RMAP_OKAY or RMAP_ERROR).
Depending on this response, the following statemachine decided the
course of action:
State1:
If match cmd returns RMAP_MATCH then, keep existing behaviour.
If routemap type is PERMIT, execute set cmds or call cmds if applicable,
otherwise PERMIT!
Else If routemap type is DENY, we DENYMATCH right away
State2:
If match cmd returns RMAP_NOMATCH, continue on to next route-map. If there
are no other rules or if all the rules return RMAP_NOMATCH, return DENYMATCH
We require a 3rd state because of the following situation:
The issue - what if, the rule api needs to abort or ignore a rule?:
"match evpn vni xx" route-map filter can be applied to incoming routes
regardless of whether the tunnel type is vxlan or mpls.
This rule should be N/A for mpls based evpn route, but applicable to only
vxlan based evpn route.
Also, this rule should be applicable for routes with VNI label only, and
not for routes without labels. For example, type 3 and type 4 EVPN routes
do not have labels, so, this match cmd should let them through.
Today, the filter produces either a match or nomatch response regardless of
whether it is mpls/vxlan, resulting in either permitting or denying the
route.. So an mpls evpn route may get filtered out incorrectly.
Eg: "route-map RM1 permit 10 ; match evpn vni 20" or
"route-map RM2 deny 20 ; match vni 20"
With the introduction of the 3rd state, we can abort this rule check safely.
How? The rules api can now return RMAP_NOOP to indicate
that it encountered an invalid check, and needs to abort just that rule,
but continue with other rules.
As a result we have a 3rd state:
State3:
If match cmd returned RMAP_NOOP
Then, proceed to other route-map, otherwise if there are no more
rules or if all the rules return RMAP_NOOP, then, return RMAP_PERMITMATCH.
Signed-off-by: Lakshman Krishnamoorthy <lkrishnamoor@vmware.com>
2019-06-19 23:04:36 +02:00
|
|
|
static enum route_map_cmd_result_t
|
|
|
|
route_map_apply_match(struct route_map_rule_list *match_list,
|
2020-11-14 01:35:20 +01:00
|
|
|
const struct prefix *prefix, void *object)
|
lib: Introducing a 3rd state for route-map match cmd: RMAP_NOOP
Introducing a 3rd state for route_map_apply library function: RMAP_NOOP
Traditionally route map MATCH rule apis were designed to return
a binary response, consisting of either RMAP_MATCH or RMAP_NOMATCH.
(Route-map SET rule apis return RMAP_OKAY or RMAP_ERROR).
Depending on this response, the following statemachine decided the
course of action:
State1:
If match cmd returns RMAP_MATCH then, keep existing behaviour.
If routemap type is PERMIT, execute set cmds or call cmds if applicable,
otherwise PERMIT!
Else If routemap type is DENY, we DENYMATCH right away
State2:
If match cmd returns RMAP_NOMATCH, continue on to next route-map. If there
are no other rules or if all the rules return RMAP_NOMATCH, return DENYMATCH
We require a 3rd state because of the following situation:
The issue - what if, the rule api needs to abort or ignore a rule?:
"match evpn vni xx" route-map filter can be applied to incoming routes
regardless of whether the tunnel type is vxlan or mpls.
This rule should be N/A for mpls based evpn route, but applicable to only
vxlan based evpn route.
Also, this rule should be applicable for routes with VNI label only, and
not for routes without labels. For example, type 3 and type 4 EVPN routes
do not have labels, so, this match cmd should let them through.
Today, the filter produces either a match or nomatch response regardless of
whether it is mpls/vxlan, resulting in either permitting or denying the
route.. So an mpls evpn route may get filtered out incorrectly.
Eg: "route-map RM1 permit 10 ; match evpn vni 20" or
"route-map RM2 deny 20 ; match vni 20"
With the introduction of the 3rd state, we can abort this rule check safely.
How? The rules api can now return RMAP_NOOP to indicate
that it encountered an invalid check, and needs to abort just that rule,
but continue with other rules.
As a result we have a 3rd state:
State3:
If match cmd returned RMAP_NOOP
Then, proceed to other route-map, otherwise if there are no more
rules or if all the rules return RMAP_NOOP, then, return RMAP_PERMITMATCH.
Signed-off-by: Lakshman Krishnamoorthy <lkrishnamoor@vmware.com>
2019-06-19 23:04:36 +02:00
|
|
|
{
|
|
|
|
enum route_map_cmd_result_t ret = RMAP_NOMATCH;
|
|
|
|
struct route_map_rule *match;
|
|
|
|
bool is_matched = false;
|
|
|
|
|
|
|
|
|
|
|
|
/* Check all match rule and if there is no match rule, go to the
|
|
|
|
set statement. */
|
|
|
|
if (!match_list->head)
|
|
|
|
ret = RMAP_MATCH;
|
|
|
|
else {
|
|
|
|
for (match = match_list->head; match; match = match->next) {
|
|
|
|
/*
|
|
|
|
* Try each match statement. If any match does not
|
|
|
|
* return RMAP_MATCH or RMAP_NOOP, return.
|
|
|
|
* Otherwise continue on to next match statement.
|
|
|
|
* All match statements must MATCH for
|
|
|
|
* end-result to be a match.
|
|
|
|
* (Exception:If match stmts result in a mix of
|
|
|
|
* MATCH/NOOP, then also end-result is a match)
|
|
|
|
* If all result in NOOP, end-result is NOOP.
|
|
|
|
*/
|
|
|
|
ret = (*match->cmd->func_apply)(match->value, prefix,
|
2020-11-14 01:35:20 +01:00
|
|
|
object);
|
lib: Introducing a 3rd state for route-map match cmd: RMAP_NOOP
Introducing a 3rd state for route_map_apply library function: RMAP_NOOP
Traditionally route map MATCH rule apis were designed to return
a binary response, consisting of either RMAP_MATCH or RMAP_NOMATCH.
(Route-map SET rule apis return RMAP_OKAY or RMAP_ERROR).
Depending on this response, the following statemachine decided the
course of action:
State1:
If match cmd returns RMAP_MATCH then, keep existing behaviour.
If routemap type is PERMIT, execute set cmds or call cmds if applicable,
otherwise PERMIT!
Else If routemap type is DENY, we DENYMATCH right away
State2:
If match cmd returns RMAP_NOMATCH, continue on to next route-map. If there
are no other rules or if all the rules return RMAP_NOMATCH, return DENYMATCH
We require a 3rd state because of the following situation:
The issue - what if, the rule api needs to abort or ignore a rule?:
"match evpn vni xx" route-map filter can be applied to incoming routes
regardless of whether the tunnel type is vxlan or mpls.
This rule should be N/A for mpls based evpn route, but applicable to only
vxlan based evpn route.
Also, this rule should be applicable for routes with VNI label only, and
not for routes without labels. For example, type 3 and type 4 EVPN routes
do not have labels, so, this match cmd should let them through.
Today, the filter produces either a match or nomatch response regardless of
whether it is mpls/vxlan, resulting in either permitting or denying the
route.. So an mpls evpn route may get filtered out incorrectly.
Eg: "route-map RM1 permit 10 ; match evpn vni 20" or
"route-map RM2 deny 20 ; match vni 20"
With the introduction of the 3rd state, we can abort this rule check safely.
How? The rules api can now return RMAP_NOOP to indicate
that it encountered an invalid check, and needs to abort just that rule,
but continue with other rules.
As a result we have a 3rd state:
State3:
If match cmd returned RMAP_NOOP
Then, proceed to other route-map, otherwise if there are no more
rules or if all the rules return RMAP_NOOP, then, return RMAP_PERMITMATCH.
Signed-off-by: Lakshman Krishnamoorthy <lkrishnamoor@vmware.com>
2019-06-19 23:04:36 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If the consolidated result of func_apply is:
|
|
|
|
* -----------------------------------------------
|
|
|
|
* | MATCH | NOMATCH | NOOP | Final Result |
|
|
|
|
* ------------------------------------------------
|
|
|
|
* | yes | yes | yes | NOMATCH |
|
|
|
|
* | no | no | yes | NOOP |
|
|
|
|
* | yes | no | yes | MATCH |
|
|
|
|
* | no | yes | yes | NOMATCH |
|
|
|
|
* |-----------------------------------------------
|
|
|
|
*
|
|
|
|
* Traditionally, all rules within route-map
|
|
|
|
* should match for it to MATCH.
|
|
|
|
* If there are noops within the route-map rules,
|
|
|
|
* it follows the above matrix.
|
|
|
|
*
|
|
|
|
* Eg: route-map rm1 permit 10
|
|
|
|
* match rule1
|
|
|
|
* match rule2
|
|
|
|
* match rule3
|
|
|
|
* ....
|
|
|
|
* route-map rm1 permit 20
|
|
|
|
* match ruleX
|
|
|
|
* match ruleY
|
|
|
|
* ...
|
|
|
|
*/
|
|
|
|
|
|
|
|
switch (ret) {
|
|
|
|
case RMAP_MATCH:
|
|
|
|
is_matched = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RMAP_NOMATCH:
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
case RMAP_NOOP:
|
|
|
|
if (is_matched)
|
|
|
|
ret = RMAP_MATCH;
|
|
|
|
break;
|
|
|
|
|
2023-01-30 16:06:29 +01:00
|
|
|
case RMAP_OKAY:
|
|
|
|
case RMAP_ERROR:
|
lib: Introducing a 3rd state for route-map match cmd: RMAP_NOOP
Introducing a 3rd state for route_map_apply library function: RMAP_NOOP
Traditionally route map MATCH rule apis were designed to return
a binary response, consisting of either RMAP_MATCH or RMAP_NOMATCH.
(Route-map SET rule apis return RMAP_OKAY or RMAP_ERROR).
Depending on this response, the following statemachine decided the
course of action:
State1:
If match cmd returns RMAP_MATCH then, keep existing behaviour.
If routemap type is PERMIT, execute set cmds or call cmds if applicable,
otherwise PERMIT!
Else If routemap type is DENY, we DENYMATCH right away
State2:
If match cmd returns RMAP_NOMATCH, continue on to next route-map. If there
are no other rules or if all the rules return RMAP_NOMATCH, return DENYMATCH
We require a 3rd state because of the following situation:
The issue - what if, the rule api needs to abort or ignore a rule?:
"match evpn vni xx" route-map filter can be applied to incoming routes
regardless of whether the tunnel type is vxlan or mpls.
This rule should be N/A for mpls based evpn route, but applicable to only
vxlan based evpn route.
Also, this rule should be applicable for routes with VNI label only, and
not for routes without labels. For example, type 3 and type 4 EVPN routes
do not have labels, so, this match cmd should let them through.
Today, the filter produces either a match or nomatch response regardless of
whether it is mpls/vxlan, resulting in either permitting or denying the
route.. So an mpls evpn route may get filtered out incorrectly.
Eg: "route-map RM1 permit 10 ; match evpn vni 20" or
"route-map RM2 deny 20 ; match vni 20"
With the introduction of the 3rd state, we can abort this rule check safely.
How? The rules api can now return RMAP_NOOP to indicate
that it encountered an invalid check, and needs to abort just that rule,
but continue with other rules.
As a result we have a 3rd state:
State3:
If match cmd returned RMAP_NOOP
Then, proceed to other route-map, otherwise if there are no more
rules or if all the rules return RMAP_NOOP, then, return RMAP_PERMITMATCH.
Signed-off-by: Lakshman Krishnamoorthy <lkrishnamoor@vmware.com>
2019-06-19 23:04:36 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2019-12-20 07:57:09 +01:00
|
|
|
static struct list *route_map_get_index_list(struct route_node **rn,
|
|
|
|
const struct prefix *prefix,
|
|
|
|
struct route_table *table)
|
2019-11-02 03:43:10 +01:00
|
|
|
{
|
|
|
|
struct route_node *tmp_rn = NULL;
|
|
|
|
|
|
|
|
if (!(*rn)) {
|
|
|
|
*rn = route_node_match(table, prefix);
|
|
|
|
|
|
|
|
if (!(*rn))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if ((*rn)->info)
|
|
|
|
return (struct list *)((*rn)->info);
|
|
|
|
|
|
|
|
/* If rn->info is NULL, get the parent.
|
|
|
|
* Store the rn in tmp_rn and unlock it later.
|
|
|
|
*/
|
|
|
|
tmp_rn = *rn;
|
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
|
|
|
*rn = (*rn)->parent;
|
|
|
|
if (tmp_rn)
|
|
|
|
route_unlock_node(tmp_rn);
|
|
|
|
|
|
|
|
if (!(*rn))
|
|
|
|
break;
|
|
|
|
|
|
|
|
if ((*rn)->info) {
|
|
|
|
route_lock_node(*rn);
|
|
|
|
return (struct list *)((*rn)->info);
|
|
|
|
}
|
|
|
|
} while (!(*rn)->info);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This function returns the route-map index that best matches the prefix.
|
|
|
|
*/
|
2022-03-04 10:21:48 +01:00
|
|
|
static struct route_map_index *
|
|
|
|
route_map_get_index(struct route_map *map, const struct prefix *prefix,
|
|
|
|
void *object, enum route_map_cmd_result_t *match_ret)
|
2019-11-02 03:43:10 +01:00
|
|
|
{
|
2022-03-04 10:21:48 +01:00
|
|
|
enum route_map_cmd_result_t ret = RMAP_NOMATCH;
|
2019-11-02 03:43:10 +01:00
|
|
|
struct list *candidate_rmap_list = NULL;
|
|
|
|
struct route_node *rn = NULL;
|
|
|
|
struct listnode *ln = NULL, *nn = NULL;
|
|
|
|
struct route_map_index *index = NULL, *best_index = NULL;
|
|
|
|
struct route_map_index *head_index = NULL;
|
|
|
|
struct route_table *table = NULL;
|
2021-05-12 17:58:37 +02:00
|
|
|
|
lib: skip route-map optimization if !AF_INET(6)
Currently we unconditionally send a prefix through the optimized
route-map codepath if the v4 and v6 LPM tables have been allocated and
optimization has not been disabled.
However prefixes from address-families that are not IPv4/IPv6 unicast
always fail the optimized route-map index lookup, because they occur on
an LPM tree that is IPv4 or IPv6 specific.
e.g.
Even if you have an empty permit route-map clause, Type-3 EVPN routes
are always denied:
```
--config
route-map soo-foo permit 10
--logs
2023/02/17 19:38:42 BGP: [KZK58-6T4Y6] No best match sequence for pfx: [3]:[0]:[32]:[2.2.2.2] in route-map: soo-foo, result: no match
2023/02/17 19:38:42 BGP: [H5AW4-JFYQC] Route-map: soo-foo, prefix: [3]:[0]:[32]:[2.2.2.2], result: deny
```
There is some existing code that creates an AF_INET/AF_INET6 prefix
using the IP/prefix information from a Type-2/5 EVPN route, which
allowed only these two route-types to successfully attempt an LPM lookup
in the route-map optimization trees via the converted prefix.
This commit does 3 things:
1) Reverts to non-optimized route-map lookup for prefixes that are not
AF_INET or AF_INET6.
2) Cleans up the route-map code so that the AF check is part of the
index lookup + the EVPN RT-2/5 -> AF_INET/6 prefix conversion occurs
outside the index lookup.
3) Adds "debug route-map detail" logs to indicate when we attempt to
convert an AF_EVPN prefix into an AF_INET/6 prefix + when we fallback
to a non-optimized lookup.
Additional functionality for optimized lookups of prefixes from other
address-families can be added prior to the index lookup, similar to how
the existing EVPN conversion works today.
New behavior:
```
2023/02/17 21:44:27 BGP: [WYP1M-NE4SY] Converted EVPN prefix [5]:[0]:[32]:[192.0.2.7] into 192.0.2.7/32 for optimized route-map lookup
2023/02/17 21:44:27 BGP: [MT1SJ-WEJQ1] Best match route-map: soo-foo, sequence: 10 for pfx: 192.0.2.7/32, result: match
2023/02/17 21:44:27 BGP: [H5AW4-JFYQC] Route-map: soo-foo, prefix: 192.0.2.7/32, result: permit
2023/02/17 21:44:27 BGP: [WYP1M-NE4SY] Converted EVPN prefix [2]:[0]:[48]:[aa:bb:cc:00:22:22]:[32]:[20.0.0.2] into 20.0.0.2/32 for optimized route-map lookup
2023/02/17 21:44:27 BGP: [MT1SJ-WEJQ1] Best match route-map: soo-foo, sequence: 10 for pfx: 20.0.0.2/32, result: match
2023/02/17 21:44:27 BGP: [H5AW4-JFYQC] Route-map: soo-foo, prefix: 20.0.0.2/32, result: permit
2023/02/17 21:44:27 BGP: [KHG7H-RH4PN] Unable to convert EVPN prefix [3]:[0]:[32]:[2.2.2.2] into IPv4/IPv6 prefix. Falling back to non-optimized route-map lookup
2023/02/17 21:44:27 BGP: [MT1SJ-WEJQ1] Best match route-map: soo-foo, sequence: 10 for pfx: [3]:[0]:[32]:[2.2.2.2], result: match
2023/02/17 21:44:27 BGP: [H5AW4-JFYQC] Route-map: soo-foo, prefix: [3]:[0]:[32]:[2.2.2.2], result: permit
```
Signed-off-by: Trey Aspelund <taspelund@nvidia.com>
2023-02-17 22:47:09 +01:00
|
|
|
/* Route-map optimization relies on LPM lookups of the prefix to reduce
|
|
|
|
* the amount of route-map clauses a given prefix needs to be processed
|
|
|
|
* against. These LPM trees are IPv4/IPv6-specific and prefix->family
|
|
|
|
* must be AF_INET or AF_INET6 in order for the lookup to succeed. So if
|
|
|
|
* the AF doesn't line up with the LPM trees, skip the optimization.
|
2021-05-12 17:58:37 +02:00
|
|
|
*/
|
2023-02-21 21:41:29 +01:00
|
|
|
if (map->optimization_disabled) {
|
2023-02-17 21:02:14 +01:00
|
|
|
if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL)))
|
lib: skip route-map optimization if !AF_INET(6)
Currently we unconditionally send a prefix through the optimized
route-map codepath if the v4 and v6 LPM tables have been allocated and
optimization has not been disabled.
However prefixes from address-families that are not IPv4/IPv6 unicast
always fail the optimized route-map index lookup, because they occur on
an LPM tree that is IPv4 or IPv6 specific.
e.g.
Even if you have an empty permit route-map clause, Type-3 EVPN routes
are always denied:
```
--config
route-map soo-foo permit 10
--logs
2023/02/17 19:38:42 BGP: [KZK58-6T4Y6] No best match sequence for pfx: [3]:[0]:[32]:[2.2.2.2] in route-map: soo-foo, result: no match
2023/02/17 19:38:42 BGP: [H5AW4-JFYQC] Route-map: soo-foo, prefix: [3]:[0]:[32]:[2.2.2.2], result: deny
```
There is some existing code that creates an AF_INET/AF_INET6 prefix
using the IP/prefix information from a Type-2/5 EVPN route, which
allowed only these two route-types to successfully attempt an LPM lookup
in the route-map optimization trees via the converted prefix.
This commit does 3 things:
1) Reverts to non-optimized route-map lookup for prefixes that are not
AF_INET or AF_INET6.
2) Cleans up the route-map code so that the AF check is part of the
index lookup + the EVPN RT-2/5 -> AF_INET/6 prefix conversion occurs
outside the index lookup.
3) Adds "debug route-map detail" logs to indicate when we attempt to
convert an AF_EVPN prefix into an AF_INET/6 prefix + when we fallback
to a non-optimized lookup.
Additional functionality for optimized lookups of prefixes from other
address-families can be added prior to the index lookup, similar to how
the existing EVPN conversion works today.
New behavior:
```
2023/02/17 21:44:27 BGP: [WYP1M-NE4SY] Converted EVPN prefix [5]:[0]:[32]:[192.0.2.7] into 192.0.2.7/32 for optimized route-map lookup
2023/02/17 21:44:27 BGP: [MT1SJ-WEJQ1] Best match route-map: soo-foo, sequence: 10 for pfx: 192.0.2.7/32, result: match
2023/02/17 21:44:27 BGP: [H5AW4-JFYQC] Route-map: soo-foo, prefix: 192.0.2.7/32, result: permit
2023/02/17 21:44:27 BGP: [WYP1M-NE4SY] Converted EVPN prefix [2]:[0]:[48]:[aa:bb:cc:00:22:22]:[32]:[20.0.0.2] into 20.0.0.2/32 for optimized route-map lookup
2023/02/17 21:44:27 BGP: [MT1SJ-WEJQ1] Best match route-map: soo-foo, sequence: 10 for pfx: 20.0.0.2/32, result: match
2023/02/17 21:44:27 BGP: [H5AW4-JFYQC] Route-map: soo-foo, prefix: 20.0.0.2/32, result: permit
2023/02/17 21:44:27 BGP: [KHG7H-RH4PN] Unable to convert EVPN prefix [3]:[0]:[32]:[2.2.2.2] into IPv4/IPv6 prefix. Falling back to non-optimized route-map lookup
2023/02/17 21:44:27 BGP: [MT1SJ-WEJQ1] Best match route-map: soo-foo, sequence: 10 for pfx: [3]:[0]:[32]:[2.2.2.2], result: match
2023/02/17 21:44:27 BGP: [H5AW4-JFYQC] Route-map: soo-foo, prefix: [3]:[0]:[32]:[2.2.2.2], result: permit
```
Signed-off-by: Trey Aspelund <taspelund@nvidia.com>
2023-02-17 22:47:09 +01:00
|
|
|
zlog_debug(
|
|
|
|
"Skipping route-map optimization for route-map: %s, pfx: %pFX, family: %d",
|
|
|
|
map->name, prefix, prefix->family);
|
|
|
|
return map->head;
|
2021-05-12 17:58:37 +02:00
|
|
|
}
|
|
|
|
|
lib: skip route-map optimization if !AF_INET(6)
Currently we unconditionally send a prefix through the optimized
route-map codepath if the v4 and v6 LPM tables have been allocated and
optimization has not been disabled.
However prefixes from address-families that are not IPv4/IPv6 unicast
always fail the optimized route-map index lookup, because they occur on
an LPM tree that is IPv4 or IPv6 specific.
e.g.
Even if you have an empty permit route-map clause, Type-3 EVPN routes
are always denied:
```
--config
route-map soo-foo permit 10
--logs
2023/02/17 19:38:42 BGP: [KZK58-6T4Y6] No best match sequence for pfx: [3]:[0]:[32]:[2.2.2.2] in route-map: soo-foo, result: no match
2023/02/17 19:38:42 BGP: [H5AW4-JFYQC] Route-map: soo-foo, prefix: [3]:[0]:[32]:[2.2.2.2], result: deny
```
There is some existing code that creates an AF_INET/AF_INET6 prefix
using the IP/prefix information from a Type-2/5 EVPN route, which
allowed only these two route-types to successfully attempt an LPM lookup
in the route-map optimization trees via the converted prefix.
This commit does 3 things:
1) Reverts to non-optimized route-map lookup for prefixes that are not
AF_INET or AF_INET6.
2) Cleans up the route-map code so that the AF check is part of the
index lookup + the EVPN RT-2/5 -> AF_INET/6 prefix conversion occurs
outside the index lookup.
3) Adds "debug route-map detail" logs to indicate when we attempt to
convert an AF_EVPN prefix into an AF_INET/6 prefix + when we fallback
to a non-optimized lookup.
Additional functionality for optimized lookups of prefixes from other
address-families can be added prior to the index lookup, similar to how
the existing EVPN conversion works today.
New behavior:
```
2023/02/17 21:44:27 BGP: [WYP1M-NE4SY] Converted EVPN prefix [5]:[0]:[32]:[192.0.2.7] into 192.0.2.7/32 for optimized route-map lookup
2023/02/17 21:44:27 BGP: [MT1SJ-WEJQ1] Best match route-map: soo-foo, sequence: 10 for pfx: 192.0.2.7/32, result: match
2023/02/17 21:44:27 BGP: [H5AW4-JFYQC] Route-map: soo-foo, prefix: 192.0.2.7/32, result: permit
2023/02/17 21:44:27 BGP: [WYP1M-NE4SY] Converted EVPN prefix [2]:[0]:[48]:[aa:bb:cc:00:22:22]:[32]:[20.0.0.2] into 20.0.0.2/32 for optimized route-map lookup
2023/02/17 21:44:27 BGP: [MT1SJ-WEJQ1] Best match route-map: soo-foo, sequence: 10 for pfx: 20.0.0.2/32, result: match
2023/02/17 21:44:27 BGP: [H5AW4-JFYQC] Route-map: soo-foo, prefix: 20.0.0.2/32, result: permit
2023/02/17 21:44:27 BGP: [KHG7H-RH4PN] Unable to convert EVPN prefix [3]:[0]:[32]:[2.2.2.2] into IPv4/IPv6 prefix. Falling back to non-optimized route-map lookup
2023/02/17 21:44:27 BGP: [MT1SJ-WEJQ1] Best match route-map: soo-foo, sequence: 10 for pfx: [3]:[0]:[32]:[2.2.2.2], result: match
2023/02/17 21:44:27 BGP: [H5AW4-JFYQC] Route-map: soo-foo, prefix: [3]:[0]:[32]:[2.2.2.2], result: permit
```
Signed-off-by: Trey Aspelund <taspelund@nvidia.com>
2023-02-17 22:47:09 +01:00
|
|
|
if (prefix->family == AF_INET)
|
2019-11-02 03:43:10 +01:00
|
|
|
table = map->ipv4_prefix_table;
|
|
|
|
else
|
|
|
|
table = map->ipv6_prefix_table;
|
|
|
|
|
|
|
|
do {
|
2019-12-20 07:57:09 +01:00
|
|
|
candidate_rmap_list =
|
|
|
|
route_map_get_index_list(&rn, prefix, table);
|
2019-11-02 03:43:10 +01:00
|
|
|
if (!rn)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* If the index at the head of the list is of seq higher
|
|
|
|
* than that in best_index, ignore the list and get the
|
|
|
|
* parent node's list.
|
|
|
|
*/
|
2019-12-20 07:57:09 +01:00
|
|
|
head_index = (struct route_map_index *)(listgetdata(
|
|
|
|
listhead(candidate_rmap_list)));
|
|
|
|
if (best_index && head_index
|
|
|
|
&& (best_index->pref < head_index->pref)) {
|
2019-11-02 03:43:10 +01:00
|
|
|
route_unlock_node(rn);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS(candidate_rmap_list, ln, nn, index)) {
|
|
|
|
/* If the index is of seq higher than that in
|
|
|
|
* best_index, ignore the list and get the parent
|
|
|
|
* node's list.
|
|
|
|
*/
|
|
|
|
if (best_index && (best_index->pref < index->pref))
|
|
|
|
break;
|
|
|
|
|
2019-12-20 07:57:09 +01:00
|
|
|
ret = route_map_apply_match(&index->match_list, prefix,
|
2020-11-14 01:35:20 +01:00
|
|
|
object);
|
2019-11-02 03:43:10 +01:00
|
|
|
|
|
|
|
if (ret == RMAP_MATCH) {
|
|
|
|
*match_ret = ret;
|
|
|
|
best_index = index;
|
|
|
|
break;
|
|
|
|
} else if (ret == RMAP_NOOP) {
|
|
|
|
/*
|
|
|
|
* If match_ret is denymatch, even if we see
|
|
|
|
* more noops, we retain this return value and
|
|
|
|
* return this eventually if there are no
|
|
|
|
* matches.
|
2020-07-14 18:15:27 +02:00
|
|
|
* If a best match route-map index already
|
|
|
|
* exists, do not reset the match_ret.
|
2019-11-02 03:43:10 +01:00
|
|
|
*/
|
2020-07-14 18:15:27 +02:00
|
|
|
if (!best_index && (*match_ret != RMAP_NOMATCH))
|
2019-11-02 03:43:10 +01:00
|
|
|
*match_ret = ret;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* ret is RMAP_NOMATCH.
|
2020-07-14 18:15:27 +02:00
|
|
|
* If a best match route-map index already
|
|
|
|
* exists, do not reset the match_ret.
|
2019-11-02 03:43:10 +01:00
|
|
|
*/
|
2020-07-14 18:15:27 +02:00
|
|
|
if (!best_index)
|
|
|
|
*match_ret = ret;
|
2019-11-02 03:43:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
route_unlock_node(rn);
|
|
|
|
|
|
|
|
} while (rn);
|
|
|
|
|
|
|
|
return best_index;
|
|
|
|
}
|
|
|
|
|
2019-12-20 07:57:09 +01:00
|
|
|
static int route_map_candidate_list_cmp(struct route_map_index *idx1,
|
|
|
|
struct route_map_index *idx2)
|
2019-11-02 03:42:20 +01:00
|
|
|
{
|
2022-10-19 18:57:28 +02:00
|
|
|
return idx1->pref - idx2->pref;
|
2019-11-02 03:42:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This function adds the route-map index into the default route's
|
|
|
|
* route-node in the route-map's IPv4/IPv6 prefix-table.
|
|
|
|
*/
|
2019-12-20 07:57:09 +01:00
|
|
|
static void route_map_pfx_table_add_default(afi_t afi,
|
|
|
|
struct route_map_index *index)
|
2019-11-02 03:42:20 +01:00
|
|
|
{
|
|
|
|
struct route_node *rn = NULL;
|
|
|
|
struct list *rmap_candidate_list = NULL;
|
|
|
|
struct prefix p;
|
|
|
|
bool updated_rn = false;
|
|
|
|
struct route_table *table = NULL;
|
|
|
|
|
|
|
|
memset(&p, 0, sizeof(p));
|
|
|
|
p.family = afi2family(afi);
|
|
|
|
p.prefixlen = 0;
|
|
|
|
|
2023-02-21 21:41:29 +01:00
|
|
|
if (p.family == AF_INET)
|
2019-11-02 03:42:20 +01:00
|
|
|
table = index->map->ipv4_prefix_table;
|
2023-02-21 21:41:29 +01:00
|
|
|
else
|
2019-11-02 03:42:20 +01:00
|
|
|
table = index->map->ipv6_prefix_table;
|
|
|
|
|
|
|
|
/* Add default route to table */
|
|
|
|
rn = route_node_get(table, &p);
|
|
|
|
|
|
|
|
if (!rn)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!rn->info) {
|
|
|
|
rmap_candidate_list = list_new();
|
|
|
|
rmap_candidate_list->cmp =
|
|
|
|
(int (*)(void *, void *))route_map_candidate_list_cmp;
|
|
|
|
rn->info = rmap_candidate_list;
|
|
|
|
} else {
|
|
|
|
rmap_candidate_list = (struct list *)rn->info;
|
|
|
|
updated_rn = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
listnode_add_sort_nodup(rmap_candidate_list, index);
|
|
|
|
if (updated_rn)
|
|
|
|
route_unlock_node(rn);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This function removes the route-map index from the default route's
|
|
|
|
* route-node in the route-map's IPv4/IPv6 prefix-table.
|
|
|
|
*/
|
2019-12-20 07:57:09 +01:00
|
|
|
static void route_map_pfx_table_del_default(afi_t afi,
|
|
|
|
struct route_map_index *index)
|
2019-11-02 03:42:20 +01:00
|
|
|
{
|
|
|
|
struct route_node *rn = NULL;
|
|
|
|
struct list *rmap_candidate_list = NULL;
|
|
|
|
struct prefix p;
|
|
|
|
struct route_table *table = NULL;
|
|
|
|
|
|
|
|
memset(&p, 0, sizeof(p));
|
|
|
|
p.family = afi2family(afi);
|
|
|
|
p.prefixlen = 0;
|
|
|
|
|
|
|
|
if (p.family == AF_INET)
|
|
|
|
table = index->map->ipv4_prefix_table;
|
|
|
|
else
|
|
|
|
table = index->map->ipv6_prefix_table;
|
|
|
|
|
|
|
|
/* Remove RMAP index from default route in table */
|
|
|
|
rn = route_node_lookup(table, &p);
|
|
|
|
if (!rn || !rn->info)
|
|
|
|
return;
|
|
|
|
|
|
|
|
rmap_candidate_list = (struct list *)rn->info;
|
|
|
|
|
|
|
|
listnode_delete(rmap_candidate_list, index);
|
|
|
|
|
|
|
|
if (listcount(rmap_candidate_list) == 0) {
|
|
|
|
list_delete(&rmap_candidate_list);
|
|
|
|
rn->info = NULL;
|
|
|
|
route_unlock_node(rn);
|
|
|
|
}
|
|
|
|
route_unlock_node(rn);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This function adds the route-map index to the route-node for
|
|
|
|
* the prefix-entry in the route-map's IPv4/IPv6 prefix-table.
|
|
|
|
*/
|
2019-12-20 07:57:09 +01:00
|
|
|
static void route_map_pfx_table_add(struct route_table *table,
|
|
|
|
struct route_map_index *index,
|
|
|
|
struct prefix_list_entry *pentry)
|
2019-11-02 03:42:20 +01:00
|
|
|
{
|
|
|
|
struct route_node *rn = NULL;
|
|
|
|
struct list *rmap_candidate_list = NULL;
|
|
|
|
bool updated_rn = false;
|
|
|
|
|
|
|
|
rn = route_node_get(table, &pentry->prefix);
|
|
|
|
if (!rn)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!rn->info) {
|
|
|
|
rmap_candidate_list = list_new();
|
|
|
|
rmap_candidate_list->cmp =
|
|
|
|
(int (*)(void *, void *))route_map_candidate_list_cmp;
|
|
|
|
rn->info = rmap_candidate_list;
|
|
|
|
} else {
|
|
|
|
rmap_candidate_list = (struct list *)rn->info;
|
|
|
|
updated_rn = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
listnode_add_sort_nodup(rmap_candidate_list, index);
|
|
|
|
if (updated_rn)
|
|
|
|
route_unlock_node(rn);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This function removes the route-map index from the route-node for
|
|
|
|
* the prefix-entry in the route-map's IPv4/IPv6 prefix-table.
|
|
|
|
*/
|
2019-12-20 07:57:09 +01:00
|
|
|
static void route_map_pfx_table_del(struct route_table *table,
|
|
|
|
struct route_map_index *index,
|
|
|
|
struct prefix_list_entry *pentry)
|
2019-11-02 03:42:20 +01:00
|
|
|
{
|
|
|
|
struct route_node *rn = NULL;
|
|
|
|
struct list *rmap_candidate_list = NULL;
|
|
|
|
|
|
|
|
rn = route_node_lookup(table, &pentry->prefix);
|
|
|
|
if (!rn || !rn->info)
|
|
|
|
return;
|
|
|
|
|
|
|
|
rmap_candidate_list = (struct list *)rn->info;
|
|
|
|
|
|
|
|
listnode_delete(rmap_candidate_list, index);
|
|
|
|
|
|
|
|
if (listcount(rmap_candidate_list) == 0) {
|
|
|
|
list_delete(&rmap_candidate_list);
|
|
|
|
rn->info = NULL;
|
|
|
|
route_unlock_node(rn);
|
|
|
|
}
|
|
|
|
route_unlock_node(rn);
|
|
|
|
}
|
|
|
|
|
2020-05-14 16:09:42 +02:00
|
|
|
/* This function checks for the presence of an IPv4 prefix-list
|
|
|
|
* match rule in the given route-map index.
|
2019-11-02 03:42:20 +01:00
|
|
|
*/
|
2020-05-14 16:09:42 +02:00
|
|
|
static bool route_map_is_ip_pfx_list_rule_present(struct route_map_index *index)
|
2019-11-02 03:42:20 +01:00
|
|
|
{
|
|
|
|
struct route_map_rule_list *match_list = NULL;
|
|
|
|
struct route_map_rule *rule = NULL;
|
|
|
|
|
|
|
|
match_list = &index->match_list;
|
|
|
|
for (rule = match_list->head; rule; rule = rule->next)
|
2020-05-14 16:09:42 +02:00
|
|
|
if (IS_RULE_IPv4_PREFIX_LIST(rule->cmd->str))
|
2019-11-02 03:42:20 +01:00
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-05-14 16:09:42 +02:00
|
|
|
/* This function checks for the presence of an IPv6 prefix-list
|
|
|
|
* match rule in the given route-map index.
|
2019-11-02 03:42:20 +01:00
|
|
|
*/
|
2020-05-14 16:09:42 +02:00
|
|
|
static bool
|
|
|
|
route_map_is_ipv6_pfx_list_rule_present(struct route_map_index *index)
|
2019-11-02 03:42:20 +01:00
|
|
|
{
|
|
|
|
struct route_map_rule_list *match_list = NULL;
|
|
|
|
struct route_map_rule *rule = NULL;
|
|
|
|
|
|
|
|
match_list = &index->match_list;
|
|
|
|
for (rule = match_list->head; rule; rule = rule->next)
|
2020-05-14 16:09:42 +02:00
|
|
|
if (IS_RULE_IPv6_PREFIX_LIST(rule->cmd->str))
|
2019-11-02 03:42:20 +01:00
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This function does the following:
|
|
|
|
* 1) If plist_name is not present, search for a IPv4 or IPv6 prefix-list
|
|
|
|
* match clause (based on the afi passed to this foo) and get the
|
|
|
|
* prefix-list name.
|
|
|
|
* 2) Look up the prefix-list using the name.
|
|
|
|
* 3) If the prefix-list is not found then, add the index to the IPv4/IPv6
|
|
|
|
* default-route's node in the trie (based on the afi passed to this foo).
|
|
|
|
* 4) If the prefix-list is found then, remove the index from the IPv4/IPv6
|
|
|
|
* default-route's node in the trie (based on the afi passed to this foo).
|
|
|
|
* 5) If a prefix-entry is passed then, create a route-node for this entry and
|
|
|
|
* add this index to the route-node.
|
|
|
|
* 6) If prefix-entry is not passed then, for every prefix-entry in the
|
|
|
|
* prefix-list, create a route-node for this entry and
|
|
|
|
* add this index to the route-node.
|
|
|
|
*/
|
2019-12-20 07:57:09 +01:00
|
|
|
static void route_map_add_plist_entries(afi_t afi,
|
|
|
|
struct route_map_index *index,
|
|
|
|
const char *plist_name,
|
|
|
|
struct prefix_list_entry *entry)
|
2019-11-02 03:42:20 +01:00
|
|
|
{
|
|
|
|
struct route_map_rule_list *match_list = NULL;
|
|
|
|
struct route_map_rule *match = NULL;
|
|
|
|
struct prefix_list *plist = NULL;
|
|
|
|
struct prefix_list_entry *pentry = NULL;
|
|
|
|
bool plist_rule_is_present = false;
|
|
|
|
|
|
|
|
if (!plist_name) {
|
|
|
|
match_list = &index->match_list;
|
|
|
|
|
|
|
|
for (match = match_list->head; match; match = match->next) {
|
2019-11-02 03:43:10 +01:00
|
|
|
if (afi == AFI_IP) {
|
2019-12-20 07:57:09 +01:00
|
|
|
if (IS_RULE_IPv4_PREFIX_LIST(match->cmd->str)) {
|
2019-11-02 03:43:10 +01:00
|
|
|
plist_rule_is_present = true;
|
|
|
|
break;
|
2019-12-20 07:57:09 +01:00
|
|
|
}
|
2019-11-02 03:43:10 +01:00
|
|
|
} else {
|
2019-12-20 07:57:09 +01:00
|
|
|
if (IS_RULE_IPv6_PREFIX_LIST(match->cmd->str)) {
|
2019-11-02 03:43:10 +01:00
|
|
|
plist_rule_is_present = true;
|
|
|
|
break;
|
2019-12-20 07:57:09 +01:00
|
|
|
}
|
2019-11-02 03:42:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (plist_rule_is_present)
|
|
|
|
plist = prefix_list_lookup(afi, match->rule_str);
|
|
|
|
} else {
|
|
|
|
plist = prefix_list_lookup(afi, plist_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!plist) {
|
|
|
|
route_map_pfx_table_add_default(afi, index);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-05-22 00:04:15 +02:00
|
|
|
/* Default entry should be deleted only if the first entry of the
|
|
|
|
* prefix-list is created.
|
|
|
|
*/
|
|
|
|
if (entry) {
|
|
|
|
if (plist->count == 1)
|
|
|
|
route_map_pfx_table_del_default(afi, index);
|
|
|
|
} else {
|
|
|
|
route_map_pfx_table_del_default(afi, index);
|
|
|
|
}
|
2019-11-02 03:42:20 +01:00
|
|
|
|
|
|
|
if (entry) {
|
|
|
|
if (afi == AFI_IP) {
|
2019-12-20 07:57:09 +01:00
|
|
|
route_map_pfx_table_add(index->map->ipv4_prefix_table,
|
|
|
|
index, entry);
|
2019-11-02 03:42:20 +01:00
|
|
|
} else {
|
2019-12-20 07:57:09 +01:00
|
|
|
route_map_pfx_table_add(index->map->ipv6_prefix_table,
|
|
|
|
index, entry);
|
2019-11-02 03:42:20 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (pentry = plist->head; pentry; pentry = pentry->next) {
|
|
|
|
if (afi == AFI_IP) {
|
|
|
|
route_map_pfx_table_add(
|
2019-12-20 07:57:09 +01:00
|
|
|
index->map->ipv4_prefix_table, index,
|
|
|
|
pentry);
|
2019-11-02 03:42:20 +01:00
|
|
|
} else {
|
|
|
|
route_map_pfx_table_add(
|
2019-12-20 07:57:09 +01:00
|
|
|
index->map->ipv6_prefix_table, index,
|
|
|
|
pentry);
|
2019-11-02 03:42:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This function does the following:
|
|
|
|
* 1) If plist_name is not present, search for a IPv4 or IPv6 prefix-list
|
|
|
|
* match clause (based on the afi passed to this foo) and get the
|
|
|
|
* prefix-list name.
|
|
|
|
* 2) Look up the prefix-list using the name.
|
|
|
|
* 3) If the prefix-list is not found then, delete the index from the IPv4/IPv6
|
|
|
|
* default-route's node in the trie (based on the afi passed to this foo).
|
|
|
|
* 4) If a prefix-entry is passed then, remove this index from the route-node
|
|
|
|
* for the prefix in this prefix-entry.
|
|
|
|
* 5) If prefix-entry is not passed then, for every prefix-entry in the
|
|
|
|
* prefix-list, remove this index from the route-node
|
|
|
|
* for the prefix in this prefix-entry.
|
|
|
|
*/
|
2019-12-20 07:57:09 +01:00
|
|
|
static void route_map_del_plist_entries(afi_t afi,
|
|
|
|
struct route_map_index *index,
|
|
|
|
const char *plist_name,
|
|
|
|
struct prefix_list_entry *entry)
|
2019-11-02 03:42:20 +01:00
|
|
|
{
|
|
|
|
struct route_map_rule_list *match_list = NULL;
|
|
|
|
struct route_map_rule *match = NULL;
|
|
|
|
struct prefix_list *plist = NULL;
|
|
|
|
struct prefix_list_entry *pentry = NULL;
|
|
|
|
bool plist_rule_is_present = false;
|
|
|
|
|
|
|
|
if (!plist_name) {
|
|
|
|
match_list = &index->match_list;
|
|
|
|
|
|
|
|
for (match = match_list->head; match; match = match->next) {
|
2019-11-02 03:43:10 +01:00
|
|
|
if (afi == AFI_IP) {
|
2019-12-20 07:57:09 +01:00
|
|
|
if (IS_RULE_IPv4_PREFIX_LIST(match->cmd->str)) {
|
2019-11-02 03:43:10 +01:00
|
|
|
plist_rule_is_present = true;
|
|
|
|
break;
|
2019-12-20 07:57:09 +01:00
|
|
|
}
|
2019-11-02 03:43:10 +01:00
|
|
|
} else {
|
2019-12-20 07:57:09 +01:00
|
|
|
if (IS_RULE_IPv6_PREFIX_LIST(match->cmd->str)) {
|
2019-11-02 03:43:10 +01:00
|
|
|
plist_rule_is_present = true;
|
|
|
|
break;
|
2019-12-20 07:57:09 +01:00
|
|
|
}
|
2019-11-02 03:42:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (plist_rule_is_present)
|
|
|
|
plist = prefix_list_lookup(afi, match->rule_str);
|
|
|
|
} else {
|
|
|
|
plist = prefix_list_lookup(afi, plist_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!plist) {
|
|
|
|
route_map_pfx_table_del_default(afi, index);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (entry) {
|
|
|
|
if (afi == AFI_IP) {
|
2019-12-20 07:57:09 +01:00
|
|
|
route_map_pfx_table_del(index->map->ipv4_prefix_table,
|
|
|
|
index, entry);
|
2019-11-02 03:42:20 +01:00
|
|
|
} else {
|
2019-12-20 07:57:09 +01:00
|
|
|
route_map_pfx_table_del(index->map->ipv6_prefix_table,
|
|
|
|
index, entry);
|
2019-11-02 03:42:20 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (pentry = plist->head; pentry; pentry = pentry->next) {
|
|
|
|
if (afi == AFI_IP) {
|
|
|
|
route_map_pfx_table_del(
|
2019-12-20 07:57:09 +01:00
|
|
|
index->map->ipv4_prefix_table, index,
|
|
|
|
pentry);
|
2019-11-02 03:42:20 +01:00
|
|
|
} else {
|
|
|
|
route_map_pfx_table_del(
|
2019-12-20 07:57:09 +01:00
|
|
|
index->map->ipv6_prefix_table, index,
|
|
|
|
pentry);
|
2019-11-02 03:42:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This function handles the cases where a prefix-list is added/removed
|
|
|
|
* as a match command from a particular route-map index.
|
|
|
|
* It updates the prefix-table of the route-map accordingly.
|
|
|
|
*/
|
2019-12-20 07:57:09 +01:00
|
|
|
static void route_map_trie_update(afi_t afi, route_map_event_t event,
|
|
|
|
struct route_map_index *index,
|
|
|
|
const char *plist_name)
|
2019-11-02 03:42:20 +01:00
|
|
|
{
|
|
|
|
if (event == RMAP_EVENT_PLIST_ADDED) {
|
|
|
|
if (afi == AFI_IP) {
|
2020-05-14 16:09:42 +02:00
|
|
|
if (!route_map_is_ipv6_pfx_list_rule_present(index)) {
|
2019-12-20 07:57:09 +01:00
|
|
|
route_map_pfx_table_del_default(AFI_IP6, index);
|
2019-11-02 03:42:20 +01:00
|
|
|
route_map_add_plist_entries(afi, index,
|
|
|
|
plist_name, NULL);
|
|
|
|
} else {
|
|
|
|
route_map_del_plist_entries(AFI_IP6, index,
|
|
|
|
NULL, NULL);
|
|
|
|
}
|
|
|
|
} else {
|
2020-05-14 16:09:42 +02:00
|
|
|
if (!route_map_is_ip_pfx_list_rule_present(index)) {
|
2019-12-20 07:57:09 +01:00
|
|
|
route_map_pfx_table_del_default(AFI_IP, index);
|
2019-11-02 03:42:20 +01:00
|
|
|
route_map_add_plist_entries(afi, index,
|
|
|
|
plist_name, NULL);
|
|
|
|
} else {
|
2019-12-20 07:57:09 +01:00
|
|
|
route_map_del_plist_entries(AFI_IP, index, NULL,
|
|
|
|
NULL);
|
2019-11-02 03:42:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (event == RMAP_EVENT_PLIST_DELETED) {
|
|
|
|
if (afi == AFI_IP) {
|
2019-12-20 07:57:09 +01:00
|
|
|
route_map_del_plist_entries(afi, index, plist_name,
|
|
|
|
NULL);
|
2019-11-02 03:42:20 +01:00
|
|
|
|
2020-05-14 16:09:42 +02:00
|
|
|
/* If IPv6 prefix-list match rule is not present,
|
|
|
|
* add this index to the IPv4 default route's trie
|
|
|
|
* node.
|
|
|
|
* Also, add this index to the trie nodes created
|
|
|
|
* for each of the prefix-entries within the IPv6
|
|
|
|
* prefix-list, if the IPv6 prefix-list match rule
|
|
|
|
* is present. Else, add this index to the IPv6
|
|
|
|
* default route's trie node.
|
|
|
|
*/
|
|
|
|
if (!route_map_is_ipv6_pfx_list_rule_present(index))
|
2019-11-02 03:42:20 +01:00
|
|
|
route_map_pfx_table_add_default(afi, index);
|
|
|
|
|
2020-05-14 16:09:42 +02:00
|
|
|
route_map_add_plist_entries(AFI_IP6, index, NULL, NULL);
|
2019-11-02 03:42:20 +01:00
|
|
|
} else {
|
2019-12-20 07:57:09 +01:00
|
|
|
route_map_del_plist_entries(afi, index, plist_name,
|
|
|
|
NULL);
|
2019-11-02 03:42:20 +01:00
|
|
|
|
2020-05-14 16:09:42 +02:00
|
|
|
/* If IPv4 prefix-list match rule is not present,
|
|
|
|
* add this index to the IPv6 default route's trie
|
|
|
|
* node.
|
|
|
|
* Also, add this index to the trie nodes created
|
|
|
|
* for each of the prefix-entries within the IPv4
|
|
|
|
* prefix-list, if the IPv4 prefix-list match rule
|
|
|
|
* is present. Else, add this index to the IPv4
|
|
|
|
* default route's trie node.
|
|
|
|
*/
|
|
|
|
if (!route_map_is_ip_pfx_list_rule_present(index))
|
2019-11-02 03:42:20 +01:00
|
|
|
route_map_pfx_table_add_default(afi, index);
|
|
|
|
|
2020-05-14 16:09:42 +02:00
|
|
|
route_map_add_plist_entries(AFI_IP, index, NULL, NULL);
|
2019-11-02 03:42:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This function handles the cases where a route-map index and
|
|
|
|
* prefix-list is added/removed.
|
|
|
|
* It updates the prefix-table of the route-map accordingly.
|
|
|
|
*/
|
2019-12-20 07:57:09 +01:00
|
|
|
static void route_map_pfx_tbl_update(route_map_event_t event,
|
|
|
|
struct route_map_index *index, afi_t afi,
|
|
|
|
const char *plist_name)
|
2019-11-02 03:42:20 +01:00
|
|
|
{
|
|
|
|
if (!index)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (event == RMAP_EVENT_INDEX_ADDED) {
|
|
|
|
route_map_pfx_table_add_default(AFI_IP, index);
|
|
|
|
route_map_pfx_table_add_default(AFI_IP6, index);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (event == RMAP_EVENT_INDEX_DELETED) {
|
|
|
|
route_map_pfx_table_del_default(AFI_IP, index);
|
|
|
|
route_map_pfx_table_del_default(AFI_IP6, index);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Handle prefix-list match rule addition/deletion.
|
|
|
|
*/
|
2019-12-20 07:57:09 +01:00
|
|
|
route_map_trie_update(afi, event, index, plist_name);
|
2019-11-02 03:42:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This function handles the cases where a new prefix-entry is added to
|
|
|
|
* a prefix-list or, an existing prefix-entry is removed from the prefix-list.
|
|
|
|
* It updates the prefix-table of the route-map accordingly.
|
|
|
|
*/
|
2019-12-20 07:57:09 +01:00
|
|
|
static void route_map_pentry_update(route_map_event_t event,
|
|
|
|
const char *plist_name,
|
|
|
|
struct route_map_index *index,
|
|
|
|
struct prefix_list_entry *pentry)
|
2019-11-02 03:42:20 +01:00
|
|
|
{
|
|
|
|
struct prefix_list *plist = NULL;
|
|
|
|
afi_t afi;
|
|
|
|
unsigned char family = pentry->prefix.family;
|
|
|
|
|
|
|
|
if (family == AF_INET) {
|
|
|
|
afi = AFI_IP;
|
|
|
|
plist = prefix_list_lookup(AFI_IP, plist_name);
|
|
|
|
} else {
|
|
|
|
afi = AFI_IP6;
|
|
|
|
plist = prefix_list_lookup(AFI_IP6, plist_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (event == RMAP_EVENT_PLIST_ADDED) {
|
2020-05-14 16:09:42 +02:00
|
|
|
if (afi == AFI_IP) {
|
|
|
|
if (!route_map_is_ipv6_pfx_list_rule_present(index))
|
|
|
|
route_map_add_plist_entries(afi, index,
|
|
|
|
plist_name, pentry);
|
2019-11-02 03:42:20 +01:00
|
|
|
} else {
|
2020-05-14 16:09:42 +02:00
|
|
|
if (!route_map_is_ip_pfx_list_rule_present(index))
|
|
|
|
route_map_add_plist_entries(afi, index,
|
|
|
|
plist_name, pentry);
|
2019-11-02 03:42:20 +01:00
|
|
|
}
|
|
|
|
} else if (event == RMAP_EVENT_PLIST_DELETED) {
|
|
|
|
route_map_del_plist_entries(afi, index, plist_name, pentry);
|
|
|
|
|
|
|
|
if (plist->count == 1) {
|
|
|
|
if (afi == AFI_IP) {
|
2020-05-14 16:09:42 +02:00
|
|
|
if (!route_map_is_ipv6_pfx_list_rule_present(
|
|
|
|
index))
|
2019-11-02 03:42:20 +01:00
|
|
|
route_map_pfx_table_add_default(afi,
|
|
|
|
index);
|
|
|
|
} else {
|
2020-05-14 16:09:42 +02:00
|
|
|
if (!route_map_is_ip_pfx_list_rule_present(
|
|
|
|
index))
|
2019-11-02 03:42:20 +01:00
|
|
|
route_map_pfx_table_add_default(afi,
|
|
|
|
index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-02 17:11:25 +01:00
|
|
|
static void route_map_pentry_process_dependency(struct hash_bucket *bucket,
|
2019-12-20 07:57:09 +01:00
|
|
|
void *data)
|
2019-11-02 03:42:20 +01:00
|
|
|
{
|
|
|
|
char *rmap_name = NULL;
|
|
|
|
struct route_map *rmap = NULL;
|
|
|
|
struct route_map_index *index = NULL;
|
|
|
|
struct route_map_rule_list *match_list = NULL;
|
|
|
|
struct route_map_rule *match = NULL;
|
|
|
|
struct route_map_dep_data *dep_data = NULL;
|
|
|
|
struct route_map_pentry_dep *pentry_dep =
|
2019-12-20 07:57:09 +01:00
|
|
|
(struct route_map_pentry_dep *)data;
|
2019-11-02 03:42:20 +01:00
|
|
|
unsigned char family = pentry_dep->pentry->prefix.family;
|
|
|
|
|
2021-02-02 17:11:25 +01:00
|
|
|
dep_data = (struct route_map_dep_data *)bucket->data;
|
2019-11-02 03:42:20 +01:00
|
|
|
if (!dep_data)
|
|
|
|
return;
|
|
|
|
|
|
|
|
rmap_name = dep_data->rname;
|
|
|
|
rmap = route_map_lookup_by_name(rmap_name);
|
|
|
|
if (!rmap || !rmap->head)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (index = rmap->head; index; index = index->next) {
|
|
|
|
match_list = &index->match_list;
|
|
|
|
|
|
|
|
if (!match_list)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (match = match_list->head; match; match = match->next) {
|
|
|
|
if (strcmp(match->rule_str, pentry_dep->plist_name)
|
2019-12-20 07:57:09 +01:00
|
|
|
== 0) {
|
|
|
|
if (IS_RULE_IPv4_PREFIX_LIST(match->cmd->str)
|
|
|
|
&& family == AF_INET) {
|
2019-11-02 03:42:20 +01:00
|
|
|
route_map_pentry_update(
|
2019-12-20 07:57:09 +01:00
|
|
|
pentry_dep->event,
|
|
|
|
pentry_dep->plist_name, index,
|
|
|
|
pentry_dep->pentry);
|
2019-11-02 03:43:10 +01:00
|
|
|
} else if (IS_RULE_IPv6_PREFIX_LIST(
|
2019-12-20 07:57:09 +01:00
|
|
|
match->cmd->str)
|
|
|
|
&& family == AF_INET6) {
|
2019-11-02 03:42:20 +01:00
|
|
|
route_map_pentry_update(
|
2019-12-20 07:57:09 +01:00
|
|
|
pentry_dep->event,
|
|
|
|
pentry_dep->plist_name, index,
|
|
|
|
pentry_dep->pentry);
|
2019-11-02 03:42:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-20 07:57:09 +01:00
|
|
|
void route_map_notify_pentry_dependencies(const char *affected_name,
|
|
|
|
struct prefix_list_entry *pentry,
|
|
|
|
route_map_event_t event)
|
2019-11-02 03:42:20 +01:00
|
|
|
{
|
|
|
|
struct route_map_dep *dep = NULL;
|
|
|
|
struct hash *upd8_hash = NULL;
|
|
|
|
struct route_map_pentry_dep pentry_dep;
|
|
|
|
|
|
|
|
if (!affected_name || !pentry)
|
|
|
|
return;
|
|
|
|
|
|
|
|
upd8_hash = route_map_get_dep_hash(event);
|
|
|
|
if (!upd8_hash)
|
|
|
|
return;
|
|
|
|
|
|
|
|
dep = (struct route_map_dep *)hash_get(upd8_hash, (void *)affected_name,
|
|
|
|
NULL);
|
|
|
|
if (dep) {
|
|
|
|
if (!dep->this_hash)
|
|
|
|
dep->this_hash = upd8_hash;
|
|
|
|
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&pentry_dep, 0, sizeof(pentry_dep));
|
2019-11-02 03:42:20 +01:00
|
|
|
pentry_dep.pentry = pentry;
|
|
|
|
pentry_dep.plist_name = affected_name;
|
|
|
|
pentry_dep.event = event;
|
|
|
|
|
|
|
|
hash_iterate(dep->dep_rmap_hash,
|
|
|
|
route_map_pentry_process_dependency,
|
|
|
|
(void *)&pentry_dep);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-10-29 07:30:19 +01:00
|
|
|
/* Apply route map's each index to the object.
|
|
|
|
|
|
|
|
The matrix for a route-map looks like this:
|
|
|
|
(note, this includes the description for the "NEXT"
|
|
|
|
and "GOTO" frobs now
|
2017-07-17 14:03:14 +02:00
|
|
|
|
lib: Introducing a 3rd state for route-map match cmd: RMAP_NOOP
Introducing a 3rd state for route_map_apply library function: RMAP_NOOP
Traditionally route map MATCH rule apis were designed to return
a binary response, consisting of either RMAP_MATCH or RMAP_NOMATCH.
(Route-map SET rule apis return RMAP_OKAY or RMAP_ERROR).
Depending on this response, the following statemachine decided the
course of action:
State1:
If match cmd returns RMAP_MATCH then, keep existing behaviour.
If routemap type is PERMIT, execute set cmds or call cmds if applicable,
otherwise PERMIT!
Else If routemap type is DENY, we DENYMATCH right away
State2:
If match cmd returns RMAP_NOMATCH, continue on to next route-map. If there
are no other rules or if all the rules return RMAP_NOMATCH, return DENYMATCH
We require a 3rd state because of the following situation:
The issue - what if, the rule api needs to abort or ignore a rule?:
"match evpn vni xx" route-map filter can be applied to incoming routes
regardless of whether the tunnel type is vxlan or mpls.
This rule should be N/A for mpls based evpn route, but applicable to only
vxlan based evpn route.
Also, this rule should be applicable for routes with VNI label only, and
not for routes without labels. For example, type 3 and type 4 EVPN routes
do not have labels, so, this match cmd should let them through.
Today, the filter produces either a match or nomatch response regardless of
whether it is mpls/vxlan, resulting in either permitting or denying the
route.. So an mpls evpn route may get filtered out incorrectly.
Eg: "route-map RM1 permit 10 ; match evpn vni 20" or
"route-map RM2 deny 20 ; match vni 20"
With the introduction of the 3rd state, we can abort this rule check safely.
How? The rules api can now return RMAP_NOOP to indicate
that it encountered an invalid check, and needs to abort just that rule,
but continue with other rules.
As a result we have a 3rd state:
State3:
If match cmd returned RMAP_NOOP
Then, proceed to other route-map, otherwise if there are no more
rules or if all the rules return RMAP_NOOP, then, return RMAP_PERMITMATCH.
Signed-off-by: Lakshman Krishnamoorthy <lkrishnamoor@vmware.com>
2019-06-19 23:04:36 +02:00
|
|
|
| Match | No Match | No op
|
|
|
|
|-----------|--------------|-------
|
|
|
|
permit | action | cont | cont.
|
|
|
|
| | default:deny | default:permit
|
|
|
|
-------------------+-----------------------
|
|
|
|
| deny | cont | cont.
|
|
|
|
deny | | default:deny | default:permit
|
|
|
|
|-----------|--------------|--------
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-09-13 Jose Luis Rubio <jrubio@dit.upm.es>
(at Technical University of Madrid as part of Euro6ix Project)
Enhanced Route Server functionality and Route-Maps:
* bgpd/bgpd.h: Modified 'struct peer' and 'struct bgp_filter' to
support rs-clients. A 'struct bgp_table *rib' has been added to the
first (to mantain a separated RIB for each rs-client) and two new
route-maps have been added to the last (for import/export policies).
Added the following #defines: RMAP_{IN|OUT|IMPORT|EXPORT|MAX},
PEER_RMAP_TYPE_{IMPORT|EXPORT} and BGP_CLEAR_SOFT_RSCLIENT.
* bgpd/bgpd.c: Modified the functions that create/delete/etc peers in
order to consider the new fields included in 'struct peer' for
supporting rs-clients, i.e. the import/export route-maps and the
'struct bgp_table'.
* bgpd/bgp_route.{ch}: Modified several functions related with
receiving/sending announces in order to support the new Route Server
capabilities.
Function 'bgp_process' has been reorganized, creating an auxiliar
function for best path selection ('bgp_best_selection').
Modified 'bgp_show' and 'bgp_show_route' for displaying information
about any RIB (and not only the main bgp RIB).
Added commands for displaying information about RS-clients RIBs:
'show bgp rsclient (A.B.C.D|X:X::X:X)', 'show bgp rsclient
(A.B.C.D|X:X::X:X) X:X::X:X/M', etc
* bgpd/bgp_table.{ch}: The structure 'struct bgp_table' now has two
new fields: type (which can take the values BGP_TABLE_{MAIN|RSCLIENT})
and 'void *owner' which points to 'struct bgp' or 'struct peer' which
owns the table.
When creating a new bgp_table by default 'type=BGP_TABLE_MAIN' is set.
* bgpd/bgp_vty.c: The commands 'neighbor ... route-server-client' and
'no neighbor ... route-server-client' now not only set/unset the flag
PEER_FLAG_RSERVER_CLIENT, but they create/destroy the 'struct
bgp_table' of the peer. Special actions are taken for peer_groups.
Command 'neighbor ... route-map WORD (in|out)' now also supports two
new kinds of route-map: 'import' and 'export'.
Added commands 'clear bgp * rsclient', etc. These commands allow a new
kind of soft_reconfig which affects only the RIB of the specified
RS-client.
Added commands 'show bgp rsclient summary', etc which display a
summary of the rs-clients configured for the corresponding address
family.
* bgpd/bgp_routemap.c: A new match statement is available,
'match peer (A.B.C.D|X:X::X:X)'. This statement can only be used in
import/export route-maps, and it matches when the peer who announces
(when used in an import route-map) or is going to receive (when used
in an export route-map) the route is the same than the one specified
in the statement.
For peer-groups the statement matches if the specified peer is member
of the peer-group.
A special version of the command, 'match peer local', matches with
routes originated by the Route Server (defined with 'network ...',
redistributed routes and default-originate).
* lib/routemap.{ch}: Added a new clause 'call NAME' for use in
route-maps. It jumps into the specified route-map and when it returns
the first route-map ends if the called RM returns DENY_MATCH, or
continues in other case.
2004-09-13 07:12:46 +02:00
|
|
|
action)
|
|
|
|
-Apply Set statements, accept route
|
|
|
|
-If Call statement is present jump to the specified route-map, if it
|
|
|
|
denies the route we finish.
|
|
|
|
-If NEXT is specified, goto NEXT statement
|
|
|
|
-If GOTO is specified, goto the first clause where pref > nextpref
|
|
|
|
-If nothing is specified, do as Cisco and finish
|
|
|
|
deny)
|
|
|
|
-Route is denied by route-map.
|
|
|
|
cont)
|
|
|
|
-Goto Next index
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2003-10-29 07:30:19 +01:00
|
|
|
If we get no matches after we've processed all updates, then the route
|
|
|
|
is dropped too.
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-09-13 Jose Luis Rubio <jrubio@dit.upm.es>
(at Technical University of Madrid as part of Euro6ix Project)
Enhanced Route Server functionality and Route-Maps:
* bgpd/bgpd.h: Modified 'struct peer' and 'struct bgp_filter' to
support rs-clients. A 'struct bgp_table *rib' has been added to the
first (to mantain a separated RIB for each rs-client) and two new
route-maps have been added to the last (for import/export policies).
Added the following #defines: RMAP_{IN|OUT|IMPORT|EXPORT|MAX},
PEER_RMAP_TYPE_{IMPORT|EXPORT} and BGP_CLEAR_SOFT_RSCLIENT.
* bgpd/bgpd.c: Modified the functions that create/delete/etc peers in
order to consider the new fields included in 'struct peer' for
supporting rs-clients, i.e. the import/export route-maps and the
'struct bgp_table'.
* bgpd/bgp_route.{ch}: Modified several functions related with
receiving/sending announces in order to support the new Route Server
capabilities.
Function 'bgp_process' has been reorganized, creating an auxiliar
function for best path selection ('bgp_best_selection').
Modified 'bgp_show' and 'bgp_show_route' for displaying information
about any RIB (and not only the main bgp RIB).
Added commands for displaying information about RS-clients RIBs:
'show bgp rsclient (A.B.C.D|X:X::X:X)', 'show bgp rsclient
(A.B.C.D|X:X::X:X) X:X::X:X/M', etc
* bgpd/bgp_table.{ch}: The structure 'struct bgp_table' now has two
new fields: type (which can take the values BGP_TABLE_{MAIN|RSCLIENT})
and 'void *owner' which points to 'struct bgp' or 'struct peer' which
owns the table.
When creating a new bgp_table by default 'type=BGP_TABLE_MAIN' is set.
* bgpd/bgp_vty.c: The commands 'neighbor ... route-server-client' and
'no neighbor ... route-server-client' now not only set/unset the flag
PEER_FLAG_RSERVER_CLIENT, but they create/destroy the 'struct
bgp_table' of the peer. Special actions are taken for peer_groups.
Command 'neighbor ... route-map WORD (in|out)' now also supports two
new kinds of route-map: 'import' and 'export'.
Added commands 'clear bgp * rsclient', etc. These commands allow a new
kind of soft_reconfig which affects only the RIB of the specified
RS-client.
Added commands 'show bgp rsclient summary', etc which display a
summary of the rs-clients configured for the corresponding address
family.
* bgpd/bgp_routemap.c: A new match statement is available,
'match peer (A.B.C.D|X:X::X:X)'. This statement can only be used in
import/export route-maps, and it matches when the peer who announces
(when used in an import route-map) or is going to receive (when used
in an export route-map) the route is the same than the one specified
in the statement.
For peer-groups the statement matches if the specified peer is member
of the peer-group.
A special version of the command, 'match peer local', matches with
routes originated by the Route Server (defined with 'network ...',
redistributed routes and default-originate).
* lib/routemap.{ch}: Added a new clause 'call NAME' for use in
route-maps. It jumps into the specified route-map and when it returns
the first route-map ends if the called RM returns DENY_MATCH, or
continues in other case.
2004-09-13 07:12:46 +02:00
|
|
|
Some notes on the new "CALL", "NEXT" and "GOTO"
|
|
|
|
call WORD - If this clause is matched, then the set statements
|
|
|
|
are executed and then we jump to route-map 'WORD'. If
|
|
|
|
this route-map denies the route, we finish, in other
|
|
|
|
case we
|
|
|
|
do whatever the exit policy (EXIT, NEXT or GOTO) tells.
|
2003-10-29 07:30:19 +01:00
|
|
|
on-match next - If this clause is matched, then the set statements
|
|
|
|
are executed and then we drop through to the next clause
|
2021-10-05 23:33:14 +02:00
|
|
|
on-match goto n - If this clause is matched, then the set statements
|
2003-10-29 07:30:19 +01:00
|
|
|
are executed and then we goto the nth clause, or the
|
|
|
|
first clause greater than this. In order to ensure
|
|
|
|
route-maps *always* exit, you cannot jump backwards.
|
|
|
|
Sorry ;)
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2003-10-29 07:30:19 +01:00
|
|
|
We need to make sure our route-map processing matches the above
|
2002-12-13 21:15:29 +01:00
|
|
|
*/
|
2021-09-08 19:46:21 +02:00
|
|
|
route_map_result_t route_map_apply_ext(struct route_map *map,
|
|
|
|
const struct prefix *prefix,
|
2022-05-27 17:07:36 +02:00
|
|
|
void *match_object, void *set_object,
|
|
|
|
int *pref)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2004-09-13 Jose Luis Rubio <jrubio@dit.upm.es>
(at Technical University of Madrid as part of Euro6ix Project)
Enhanced Route Server functionality and Route-Maps:
* bgpd/bgpd.h: Modified 'struct peer' and 'struct bgp_filter' to
support rs-clients. A 'struct bgp_table *rib' has been added to the
first (to mantain a separated RIB for each rs-client) and two new
route-maps have been added to the last (for import/export policies).
Added the following #defines: RMAP_{IN|OUT|IMPORT|EXPORT|MAX},
PEER_RMAP_TYPE_{IMPORT|EXPORT} and BGP_CLEAR_SOFT_RSCLIENT.
* bgpd/bgpd.c: Modified the functions that create/delete/etc peers in
order to consider the new fields included in 'struct peer' for
supporting rs-clients, i.e. the import/export route-maps and the
'struct bgp_table'.
* bgpd/bgp_route.{ch}: Modified several functions related with
receiving/sending announces in order to support the new Route Server
capabilities.
Function 'bgp_process' has been reorganized, creating an auxiliar
function for best path selection ('bgp_best_selection').
Modified 'bgp_show' and 'bgp_show_route' for displaying information
about any RIB (and not only the main bgp RIB).
Added commands for displaying information about RS-clients RIBs:
'show bgp rsclient (A.B.C.D|X:X::X:X)', 'show bgp rsclient
(A.B.C.D|X:X::X:X) X:X::X:X/M', etc
* bgpd/bgp_table.{ch}: The structure 'struct bgp_table' now has two
new fields: type (which can take the values BGP_TABLE_{MAIN|RSCLIENT})
and 'void *owner' which points to 'struct bgp' or 'struct peer' which
owns the table.
When creating a new bgp_table by default 'type=BGP_TABLE_MAIN' is set.
* bgpd/bgp_vty.c: The commands 'neighbor ... route-server-client' and
'no neighbor ... route-server-client' now not only set/unset the flag
PEER_FLAG_RSERVER_CLIENT, but they create/destroy the 'struct
bgp_table' of the peer. Special actions are taken for peer_groups.
Command 'neighbor ... route-map WORD (in|out)' now also supports two
new kinds of route-map: 'import' and 'export'.
Added commands 'clear bgp * rsclient', etc. These commands allow a new
kind of soft_reconfig which affects only the RIB of the specified
RS-client.
Added commands 'show bgp rsclient summary', etc which display a
summary of the rs-clients configured for the corresponding address
family.
* bgpd/bgp_routemap.c: A new match statement is available,
'match peer (A.B.C.D|X:X::X:X)'. This statement can only be used in
import/export route-maps, and it matches when the peer who announces
(when used in an import route-map) or is going to receive (when used
in an export route-map) the route is the same than the one specified
in the statement.
For peer-groups the statement matches if the specified peer is member
of the peer-group.
A special version of the command, 'match peer local', matches with
routes originated by the Route Server (defined with 'network ...',
redistributed routes and default-originate).
* lib/routemap.{ch}: Added a new clause 'call NAME' for use in
route-maps. It jumps into the specified route-map and when it returns
the first route-map ends if the called RM returns DENY_MATCH, or
continues in other case.
2004-09-13 07:12:46 +02:00
|
|
|
static int recursion = 0;
|
lib: Introducing a 3rd state for route-map match cmd: RMAP_NOOP
Introducing a 3rd state for route_map_apply library function: RMAP_NOOP
Traditionally route map MATCH rule apis were designed to return
a binary response, consisting of either RMAP_MATCH or RMAP_NOMATCH.
(Route-map SET rule apis return RMAP_OKAY or RMAP_ERROR).
Depending on this response, the following statemachine decided the
course of action:
State1:
If match cmd returns RMAP_MATCH then, keep existing behaviour.
If routemap type is PERMIT, execute set cmds or call cmds if applicable,
otherwise PERMIT!
Else If routemap type is DENY, we DENYMATCH right away
State2:
If match cmd returns RMAP_NOMATCH, continue on to next route-map. If there
are no other rules or if all the rules return RMAP_NOMATCH, return DENYMATCH
We require a 3rd state because of the following situation:
The issue - what if, the rule api needs to abort or ignore a rule?:
"match evpn vni xx" route-map filter can be applied to incoming routes
regardless of whether the tunnel type is vxlan or mpls.
This rule should be N/A for mpls based evpn route, but applicable to only
vxlan based evpn route.
Also, this rule should be applicable for routes with VNI label only, and
not for routes without labels. For example, type 3 and type 4 EVPN routes
do not have labels, so, this match cmd should let them through.
Today, the filter produces either a match or nomatch response regardless of
whether it is mpls/vxlan, resulting in either permitting or denying the
route.. So an mpls evpn route may get filtered out incorrectly.
Eg: "route-map RM1 permit 10 ; match evpn vni 20" or
"route-map RM2 deny 20 ; match vni 20"
With the introduction of the 3rd state, we can abort this rule check safely.
How? The rules api can now return RMAP_NOOP to indicate
that it encountered an invalid check, and needs to abort just that rule,
but continue with other rules.
As a result we have a 3rd state:
State3:
If match cmd returned RMAP_NOOP
Then, proceed to other route-map, otherwise if there are no more
rules or if all the rules return RMAP_NOOP, then, return RMAP_PERMITMATCH.
Signed-off-by: Lakshman Krishnamoorthy <lkrishnamoor@vmware.com>
2019-06-19 23:04:36 +02:00
|
|
|
enum route_map_cmd_result_t match_ret = RMAP_NOMATCH;
|
|
|
|
route_map_result_t ret = RMAP_PERMITMATCH;
|
2019-11-02 03:43:10 +01:00
|
|
|
struct route_map_index *index = NULL;
|
|
|
|
struct route_map_rule *set = NULL;
|
|
|
|
bool skip_match_clause = false;
|
2022-10-10 16:56:51 +02:00
|
|
|
RUSAGE_T mbefore, mafter;
|
|
|
|
RUSAGE_T ibefore, iafter;
|
|
|
|
unsigned long cputime;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-09-13 Jose Luis Rubio <jrubio@dit.upm.es>
(at Technical University of Madrid as part of Euro6ix Project)
Enhanced Route Server functionality and Route-Maps:
* bgpd/bgpd.h: Modified 'struct peer' and 'struct bgp_filter' to
support rs-clients. A 'struct bgp_table *rib' has been added to the
first (to mantain a separated RIB for each rs-client) and two new
route-maps have been added to the last (for import/export policies).
Added the following #defines: RMAP_{IN|OUT|IMPORT|EXPORT|MAX},
PEER_RMAP_TYPE_{IMPORT|EXPORT} and BGP_CLEAR_SOFT_RSCLIENT.
* bgpd/bgpd.c: Modified the functions that create/delete/etc peers in
order to consider the new fields included in 'struct peer' for
supporting rs-clients, i.e. the import/export route-maps and the
'struct bgp_table'.
* bgpd/bgp_route.{ch}: Modified several functions related with
receiving/sending announces in order to support the new Route Server
capabilities.
Function 'bgp_process' has been reorganized, creating an auxiliar
function for best path selection ('bgp_best_selection').
Modified 'bgp_show' and 'bgp_show_route' for displaying information
about any RIB (and not only the main bgp RIB).
Added commands for displaying information about RS-clients RIBs:
'show bgp rsclient (A.B.C.D|X:X::X:X)', 'show bgp rsclient
(A.B.C.D|X:X::X:X) X:X::X:X/M', etc
* bgpd/bgp_table.{ch}: The structure 'struct bgp_table' now has two
new fields: type (which can take the values BGP_TABLE_{MAIN|RSCLIENT})
and 'void *owner' which points to 'struct bgp' or 'struct peer' which
owns the table.
When creating a new bgp_table by default 'type=BGP_TABLE_MAIN' is set.
* bgpd/bgp_vty.c: The commands 'neighbor ... route-server-client' and
'no neighbor ... route-server-client' now not only set/unset the flag
PEER_FLAG_RSERVER_CLIENT, but they create/destroy the 'struct
bgp_table' of the peer. Special actions are taken for peer_groups.
Command 'neighbor ... route-map WORD (in|out)' now also supports two
new kinds of route-map: 'import' and 'export'.
Added commands 'clear bgp * rsclient', etc. These commands allow a new
kind of soft_reconfig which affects only the RIB of the specified
RS-client.
Added commands 'show bgp rsclient summary', etc which display a
summary of the rs-clients configured for the corresponding address
family.
* bgpd/bgp_routemap.c: A new match statement is available,
'match peer (A.B.C.D|X:X::X:X)'. This statement can only be used in
import/export route-maps, and it matches when the peer who announces
(when used in an import route-map) or is going to receive (when used
in an export route-map) the route is the same than the one specified
in the statement.
For peer-groups the statement matches if the specified peer is member
of the peer-group.
A special version of the command, 'match peer local', matches with
routes originated by the Route Server (defined with 'network ...',
redistributed routes and default-originate).
* lib/routemap.{ch}: Added a new clause 'call NAME' for use in
route-maps. It jumps into the specified route-map and when it returns
the first route-map ends if the called RM returns DENY_MATCH, or
continues in other case.
2004-09-13 07:12:46 +02:00
|
|
|
if (recursion > RMAP_RECURSION_LIMIT) {
|
2023-06-30 15:56:51 +02:00
|
|
|
if (map)
|
|
|
|
map->applied++;
|
|
|
|
|
2018-08-20 16:21:03 +02:00
|
|
|
flog_warn(
|
2018-09-13 21:34:28 +02:00
|
|
|
EC_LIB_RMAP_RECURSION_LIMIT,
|
*: get rid of zlog(*, LOG_LEVEL, ...)
Result of running the following Coccinelle patch + fixups:
<<EOF
/* long-forms: zlog(NULL, <level>, ...)
* => zlog_level(...)
*/
@@
expression list args;
@@
- zlog(NULL, LOG_DEBUG, args)
+ zlog_debug(args)
@@
expression list args;
@@
- zlog(NULL, LOG_NOTICE, args)
+ zlog_notice(args)
@@
expression list args;
@@
- zlog(NULL, LOG_INFO, args)
+ zlog_info(args)
@@
expression list args;
@@
- zlog(NULL, LOG_WARNING, args)
+ zlog_warn(args)
@@
expression list args;
@@
- zlog(NULL, LOG_ERR, args)
+ zlog_err(args)
/* long-forms: zlog(base->log, <level>, ...)
* => zlog_level(...)
*/
@@
expression base;
expression list args;
@@
- zlog(base->log, LOG_DEBUG, args)
+ zlog_debug(args)
@@
expression base;
expression list args;
@@
- zlog(base->log, LOG_NOTICE, args)
+ zlog_notice(args)
@@
expression base;
expression list args;
@@
- zlog(base->log, LOG_INFO, args)
+ zlog_info(args)
@@
expression base;
expression list args;
@@
- zlog(base->log, LOG_WARNING, args)
+ zlog_warn(args)
@@
expression base;
expression list args;
@@
- zlog(base->log, LOG_ERR, args)
+ zlog_err(args)
EOF
Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
2016-11-13 04:19:14 +01:00
|
|
|
"route-map recursion limit (%d) reached, discarding route",
|
|
|
|
RMAP_RECURSION_LIMIT);
|
2004-09-13 Jose Luis Rubio <jrubio@dit.upm.es>
(at Technical University of Madrid as part of Euro6ix Project)
Enhanced Route Server functionality and Route-Maps:
* bgpd/bgpd.h: Modified 'struct peer' and 'struct bgp_filter' to
support rs-clients. A 'struct bgp_table *rib' has been added to the
first (to mantain a separated RIB for each rs-client) and two new
route-maps have been added to the last (for import/export policies).
Added the following #defines: RMAP_{IN|OUT|IMPORT|EXPORT|MAX},
PEER_RMAP_TYPE_{IMPORT|EXPORT} and BGP_CLEAR_SOFT_RSCLIENT.
* bgpd/bgpd.c: Modified the functions that create/delete/etc peers in
order to consider the new fields included in 'struct peer' for
supporting rs-clients, i.e. the import/export route-maps and the
'struct bgp_table'.
* bgpd/bgp_route.{ch}: Modified several functions related with
receiving/sending announces in order to support the new Route Server
capabilities.
Function 'bgp_process' has been reorganized, creating an auxiliar
function for best path selection ('bgp_best_selection').
Modified 'bgp_show' and 'bgp_show_route' for displaying information
about any RIB (and not only the main bgp RIB).
Added commands for displaying information about RS-clients RIBs:
'show bgp rsclient (A.B.C.D|X:X::X:X)', 'show bgp rsclient
(A.B.C.D|X:X::X:X) X:X::X:X/M', etc
* bgpd/bgp_table.{ch}: The structure 'struct bgp_table' now has two
new fields: type (which can take the values BGP_TABLE_{MAIN|RSCLIENT})
and 'void *owner' which points to 'struct bgp' or 'struct peer' which
owns the table.
When creating a new bgp_table by default 'type=BGP_TABLE_MAIN' is set.
* bgpd/bgp_vty.c: The commands 'neighbor ... route-server-client' and
'no neighbor ... route-server-client' now not only set/unset the flag
PEER_FLAG_RSERVER_CLIENT, but they create/destroy the 'struct
bgp_table' of the peer. Special actions are taken for peer_groups.
Command 'neighbor ... route-map WORD (in|out)' now also supports two
new kinds of route-map: 'import' and 'export'.
Added commands 'clear bgp * rsclient', etc. These commands allow a new
kind of soft_reconfig which affects only the RIB of the specified
RS-client.
Added commands 'show bgp rsclient summary', etc which display a
summary of the rs-clients configured for the corresponding address
family.
* bgpd/bgp_routemap.c: A new match statement is available,
'match peer (A.B.C.D|X:X::X:X)'. This statement can only be used in
import/export route-maps, and it matches when the peer who announces
(when used in an import route-map) or is going to receive (when used
in an export route-map) the route is the same than the one specified
in the statement.
For peer-groups the statement matches if the specified peer is member
of the peer-group.
A special version of the command, 'match peer local', matches with
routes originated by the Route Server (defined with 'network ...',
redistributed routes and default-originate).
* lib/routemap.{ch}: Added a new clause 'call NAME' for use in
route-maps. It jumps into the specified route-map and when it returns
the first route-map ends if the called RM returns DENY_MATCH, or
continues in other case.
2004-09-13 07:12:46 +02:00
|
|
|
recursion = 0;
|
|
|
|
return RMAP_DENYMATCH;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
lib: Introducing a 3rd state for route-map match cmd: RMAP_NOOP
Introducing a 3rd state for route_map_apply library function: RMAP_NOOP
Traditionally route map MATCH rule apis were designed to return
a binary response, consisting of either RMAP_MATCH or RMAP_NOMATCH.
(Route-map SET rule apis return RMAP_OKAY or RMAP_ERROR).
Depending on this response, the following statemachine decided the
course of action:
State1:
If match cmd returns RMAP_MATCH then, keep existing behaviour.
If routemap type is PERMIT, execute set cmds or call cmds if applicable,
otherwise PERMIT!
Else If routemap type is DENY, we DENYMATCH right away
State2:
If match cmd returns RMAP_NOMATCH, continue on to next route-map. If there
are no other rules or if all the rules return RMAP_NOMATCH, return DENYMATCH
We require a 3rd state because of the following situation:
The issue - what if, the rule api needs to abort or ignore a rule?:
"match evpn vni xx" route-map filter can be applied to incoming routes
regardless of whether the tunnel type is vxlan or mpls.
This rule should be N/A for mpls based evpn route, but applicable to only
vxlan based evpn route.
Also, this rule should be applicable for routes with VNI label only, and
not for routes without labels. For example, type 3 and type 4 EVPN routes
do not have labels, so, this match cmd should let them through.
Today, the filter produces either a match or nomatch response regardless of
whether it is mpls/vxlan, resulting in either permitting or denying the
route.. So an mpls evpn route may get filtered out incorrectly.
Eg: "route-map RM1 permit 10 ; match evpn vni 20" or
"route-map RM2 deny 20 ; match vni 20"
With the introduction of the 3rd state, we can abort this rule check safely.
How? The rules api can now return RMAP_NOOP to indicate
that it encountered an invalid check, and needs to abort just that rule,
but continue with other rules.
As a result we have a 3rd state:
State3:
If match cmd returned RMAP_NOOP
Then, proceed to other route-map, otherwise if there are no more
rules or if all the rules return RMAP_NOOP, then, return RMAP_PERMITMATCH.
Signed-off-by: Lakshman Krishnamoorthy <lkrishnamoor@vmware.com>
2019-06-19 23:04:36 +02:00
|
|
|
if (map == NULL || map->head == NULL) {
|
2023-06-30 15:56:51 +02:00
|
|
|
if (map)
|
|
|
|
map->applied++;
|
2019-05-10 00:34:52 +02:00
|
|
|
ret = RMAP_DENYMATCH;
|
|
|
|
goto route_map_apply_end;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-09-25 21:02:51 +02:00
|
|
|
map->applied++;
|
2019-11-02 03:43:10 +01:00
|
|
|
|
2022-10-10 16:56:51 +02:00
|
|
|
GETRUSAGE(&mbefore);
|
|
|
|
ibefore = mbefore;
|
|
|
|
|
lib: skip route-map optimization if !AF_INET(6)
Currently we unconditionally send a prefix through the optimized
route-map codepath if the v4 and v6 LPM tables have been allocated and
optimization has not been disabled.
However prefixes from address-families that are not IPv4/IPv6 unicast
always fail the optimized route-map index lookup, because they occur on
an LPM tree that is IPv4 or IPv6 specific.
e.g.
Even if you have an empty permit route-map clause, Type-3 EVPN routes
are always denied:
```
--config
route-map soo-foo permit 10
--logs
2023/02/17 19:38:42 BGP: [KZK58-6T4Y6] No best match sequence for pfx: [3]:[0]:[32]:[2.2.2.2] in route-map: soo-foo, result: no match
2023/02/17 19:38:42 BGP: [H5AW4-JFYQC] Route-map: soo-foo, prefix: [3]:[0]:[32]:[2.2.2.2], result: deny
```
There is some existing code that creates an AF_INET/AF_INET6 prefix
using the IP/prefix information from a Type-2/5 EVPN route, which
allowed only these two route-types to successfully attempt an LPM lookup
in the route-map optimization trees via the converted prefix.
This commit does 3 things:
1) Reverts to non-optimized route-map lookup for prefixes that are not
AF_INET or AF_INET6.
2) Cleans up the route-map code so that the AF check is part of the
index lookup + the EVPN RT-2/5 -> AF_INET/6 prefix conversion occurs
outside the index lookup.
3) Adds "debug route-map detail" logs to indicate when we attempt to
convert an AF_EVPN prefix into an AF_INET/6 prefix + when we fallback
to a non-optimized lookup.
Additional functionality for optimized lookups of prefixes from other
address-families can be added prior to the index lookup, similar to how
the existing EVPN conversion works today.
New behavior:
```
2023/02/17 21:44:27 BGP: [WYP1M-NE4SY] Converted EVPN prefix [5]:[0]:[32]:[192.0.2.7] into 192.0.2.7/32 for optimized route-map lookup
2023/02/17 21:44:27 BGP: [MT1SJ-WEJQ1] Best match route-map: soo-foo, sequence: 10 for pfx: 192.0.2.7/32, result: match
2023/02/17 21:44:27 BGP: [H5AW4-JFYQC] Route-map: soo-foo, prefix: 192.0.2.7/32, result: permit
2023/02/17 21:44:27 BGP: [WYP1M-NE4SY] Converted EVPN prefix [2]:[0]:[48]:[aa:bb:cc:00:22:22]:[32]:[20.0.0.2] into 20.0.0.2/32 for optimized route-map lookup
2023/02/17 21:44:27 BGP: [MT1SJ-WEJQ1] Best match route-map: soo-foo, sequence: 10 for pfx: 20.0.0.2/32, result: match
2023/02/17 21:44:27 BGP: [H5AW4-JFYQC] Route-map: soo-foo, prefix: 20.0.0.2/32, result: permit
2023/02/17 21:44:27 BGP: [KHG7H-RH4PN] Unable to convert EVPN prefix [3]:[0]:[32]:[2.2.2.2] into IPv4/IPv6 prefix. Falling back to non-optimized route-map lookup
2023/02/17 21:44:27 BGP: [MT1SJ-WEJQ1] Best match route-map: soo-foo, sequence: 10 for pfx: [3]:[0]:[32]:[2.2.2.2], result: match
2023/02/17 21:44:27 BGP: [H5AW4-JFYQC] Route-map: soo-foo, prefix: [3]:[0]:[32]:[2.2.2.2], result: permit
```
Signed-off-by: Trey Aspelund <taspelund@nvidia.com>
2023-02-17 22:47:09 +01:00
|
|
|
if (prefix->family == AF_EVPN) {
|
2024-02-15 11:07:43 +01:00
|
|
|
index = map->head;
|
|
|
|
} else {
|
|
|
|
skip_match_clause = true;
|
|
|
|
index = route_map_get_index(map, prefix, match_object,
|
|
|
|
&match_ret);
|
lib: skip route-map optimization if !AF_INET(6)
Currently we unconditionally send a prefix through the optimized
route-map codepath if the v4 and v6 LPM tables have been allocated and
optimization has not been disabled.
However prefixes from address-families that are not IPv4/IPv6 unicast
always fail the optimized route-map index lookup, because they occur on
an LPM tree that is IPv4 or IPv6 specific.
e.g.
Even if you have an empty permit route-map clause, Type-3 EVPN routes
are always denied:
```
--config
route-map soo-foo permit 10
--logs
2023/02/17 19:38:42 BGP: [KZK58-6T4Y6] No best match sequence for pfx: [3]:[0]:[32]:[2.2.2.2] in route-map: soo-foo, result: no match
2023/02/17 19:38:42 BGP: [H5AW4-JFYQC] Route-map: soo-foo, prefix: [3]:[0]:[32]:[2.2.2.2], result: deny
```
There is some existing code that creates an AF_INET/AF_INET6 prefix
using the IP/prefix information from a Type-2/5 EVPN route, which
allowed only these two route-types to successfully attempt an LPM lookup
in the route-map optimization trees via the converted prefix.
This commit does 3 things:
1) Reverts to non-optimized route-map lookup for prefixes that are not
AF_INET or AF_INET6.
2) Cleans up the route-map code so that the AF check is part of the
index lookup + the EVPN RT-2/5 -> AF_INET/6 prefix conversion occurs
outside the index lookup.
3) Adds "debug route-map detail" logs to indicate when we attempt to
convert an AF_EVPN prefix into an AF_INET/6 prefix + when we fallback
to a non-optimized lookup.
Additional functionality for optimized lookups of prefixes from other
address-families can be added prior to the index lookup, similar to how
the existing EVPN conversion works today.
New behavior:
```
2023/02/17 21:44:27 BGP: [WYP1M-NE4SY] Converted EVPN prefix [5]:[0]:[32]:[192.0.2.7] into 192.0.2.7/32 for optimized route-map lookup
2023/02/17 21:44:27 BGP: [MT1SJ-WEJQ1] Best match route-map: soo-foo, sequence: 10 for pfx: 192.0.2.7/32, result: match
2023/02/17 21:44:27 BGP: [H5AW4-JFYQC] Route-map: soo-foo, prefix: 192.0.2.7/32, result: permit
2023/02/17 21:44:27 BGP: [WYP1M-NE4SY] Converted EVPN prefix [2]:[0]:[48]:[aa:bb:cc:00:22:22]:[32]:[20.0.0.2] into 20.0.0.2/32 for optimized route-map lookup
2023/02/17 21:44:27 BGP: [MT1SJ-WEJQ1] Best match route-map: soo-foo, sequence: 10 for pfx: 20.0.0.2/32, result: match
2023/02/17 21:44:27 BGP: [H5AW4-JFYQC] Route-map: soo-foo, prefix: 20.0.0.2/32, result: permit
2023/02/17 21:44:27 BGP: [KHG7H-RH4PN] Unable to convert EVPN prefix [3]:[0]:[32]:[2.2.2.2] into IPv4/IPv6 prefix. Falling back to non-optimized route-map lookup
2023/02/17 21:44:27 BGP: [MT1SJ-WEJQ1] Best match route-map: soo-foo, sequence: 10 for pfx: [3]:[0]:[32]:[2.2.2.2], result: match
2023/02/17 21:44:27 BGP: [H5AW4-JFYQC] Route-map: soo-foo, prefix: [3]:[0]:[32]:[2.2.2.2], result: permit
```
Signed-off-by: Trey Aspelund <taspelund@nvidia.com>
2023-02-17 22:47:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (index) {
|
|
|
|
index->applied++;
|
2022-10-10 16:56:51 +02:00
|
|
|
|
|
|
|
GETRUSAGE(&iafter);
|
|
|
|
event_consumed_time(&iafter, &ibefore, &cputime);
|
|
|
|
index->cputime += cputime;
|
|
|
|
ibefore = iafter;
|
|
|
|
|
2023-02-17 21:02:14 +01:00
|
|
|
if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP)))
|
lib: skip route-map optimization if !AF_INET(6)
Currently we unconditionally send a prefix through the optimized
route-map codepath if the v4 and v6 LPM tables have been allocated and
optimization has not been disabled.
However prefixes from address-families that are not IPv4/IPv6 unicast
always fail the optimized route-map index lookup, because they occur on
an LPM tree that is IPv4 or IPv6 specific.
e.g.
Even if you have an empty permit route-map clause, Type-3 EVPN routes
are always denied:
```
--config
route-map soo-foo permit 10
--logs
2023/02/17 19:38:42 BGP: [KZK58-6T4Y6] No best match sequence for pfx: [3]:[0]:[32]:[2.2.2.2] in route-map: soo-foo, result: no match
2023/02/17 19:38:42 BGP: [H5AW4-JFYQC] Route-map: soo-foo, prefix: [3]:[0]:[32]:[2.2.2.2], result: deny
```
There is some existing code that creates an AF_INET/AF_INET6 prefix
using the IP/prefix information from a Type-2/5 EVPN route, which
allowed only these two route-types to successfully attempt an LPM lookup
in the route-map optimization trees via the converted prefix.
This commit does 3 things:
1) Reverts to non-optimized route-map lookup for prefixes that are not
AF_INET or AF_INET6.
2) Cleans up the route-map code so that the AF check is part of the
index lookup + the EVPN RT-2/5 -> AF_INET/6 prefix conversion occurs
outside the index lookup.
3) Adds "debug route-map detail" logs to indicate when we attempt to
convert an AF_EVPN prefix into an AF_INET/6 prefix + when we fallback
to a non-optimized lookup.
Additional functionality for optimized lookups of prefixes from other
address-families can be added prior to the index lookup, similar to how
the existing EVPN conversion works today.
New behavior:
```
2023/02/17 21:44:27 BGP: [WYP1M-NE4SY] Converted EVPN prefix [5]:[0]:[32]:[192.0.2.7] into 192.0.2.7/32 for optimized route-map lookup
2023/02/17 21:44:27 BGP: [MT1SJ-WEJQ1] Best match route-map: soo-foo, sequence: 10 for pfx: 192.0.2.7/32, result: match
2023/02/17 21:44:27 BGP: [H5AW4-JFYQC] Route-map: soo-foo, prefix: 192.0.2.7/32, result: permit
2023/02/17 21:44:27 BGP: [WYP1M-NE4SY] Converted EVPN prefix [2]:[0]:[48]:[aa:bb:cc:00:22:22]:[32]:[20.0.0.2] into 20.0.0.2/32 for optimized route-map lookup
2023/02/17 21:44:27 BGP: [MT1SJ-WEJQ1] Best match route-map: soo-foo, sequence: 10 for pfx: 20.0.0.2/32, result: match
2023/02/17 21:44:27 BGP: [H5AW4-JFYQC] Route-map: soo-foo, prefix: 20.0.0.2/32, result: permit
2023/02/17 21:44:27 BGP: [KHG7H-RH4PN] Unable to convert EVPN prefix [3]:[0]:[32]:[2.2.2.2] into IPv4/IPv6 prefix. Falling back to non-optimized route-map lookup
2023/02/17 21:44:27 BGP: [MT1SJ-WEJQ1] Best match route-map: soo-foo, sequence: 10 for pfx: [3]:[0]:[32]:[2.2.2.2], result: match
2023/02/17 21:44:27 BGP: [H5AW4-JFYQC] Route-map: soo-foo, prefix: [3]:[0]:[32]:[2.2.2.2], result: permit
```
Signed-off-by: Trey Aspelund <taspelund@nvidia.com>
2023-02-17 22:47:09 +01:00
|
|
|
zlog_debug(
|
|
|
|
"Best match route-map: %s, sequence: %d for pfx: %pFX, result: %s",
|
|
|
|
map->name, index->pref, prefix,
|
|
|
|
route_map_cmd_result_str(match_ret));
|
2019-11-02 03:43:10 +01:00
|
|
|
} else {
|
2023-02-17 21:02:14 +01:00
|
|
|
if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP)))
|
lib: skip route-map optimization if !AF_INET(6)
Currently we unconditionally send a prefix through the optimized
route-map codepath if the v4 and v6 LPM tables have been allocated and
optimization has not been disabled.
However prefixes from address-families that are not IPv4/IPv6 unicast
always fail the optimized route-map index lookup, because they occur on
an LPM tree that is IPv4 or IPv6 specific.
e.g.
Even if you have an empty permit route-map clause, Type-3 EVPN routes
are always denied:
```
--config
route-map soo-foo permit 10
--logs
2023/02/17 19:38:42 BGP: [KZK58-6T4Y6] No best match sequence for pfx: [3]:[0]:[32]:[2.2.2.2] in route-map: soo-foo, result: no match
2023/02/17 19:38:42 BGP: [H5AW4-JFYQC] Route-map: soo-foo, prefix: [3]:[0]:[32]:[2.2.2.2], result: deny
```
There is some existing code that creates an AF_INET/AF_INET6 prefix
using the IP/prefix information from a Type-2/5 EVPN route, which
allowed only these two route-types to successfully attempt an LPM lookup
in the route-map optimization trees via the converted prefix.
This commit does 3 things:
1) Reverts to non-optimized route-map lookup for prefixes that are not
AF_INET or AF_INET6.
2) Cleans up the route-map code so that the AF check is part of the
index lookup + the EVPN RT-2/5 -> AF_INET/6 prefix conversion occurs
outside the index lookup.
3) Adds "debug route-map detail" logs to indicate when we attempt to
convert an AF_EVPN prefix into an AF_INET/6 prefix + when we fallback
to a non-optimized lookup.
Additional functionality for optimized lookups of prefixes from other
address-families can be added prior to the index lookup, similar to how
the existing EVPN conversion works today.
New behavior:
```
2023/02/17 21:44:27 BGP: [WYP1M-NE4SY] Converted EVPN prefix [5]:[0]:[32]:[192.0.2.7] into 192.0.2.7/32 for optimized route-map lookup
2023/02/17 21:44:27 BGP: [MT1SJ-WEJQ1] Best match route-map: soo-foo, sequence: 10 for pfx: 192.0.2.7/32, result: match
2023/02/17 21:44:27 BGP: [H5AW4-JFYQC] Route-map: soo-foo, prefix: 192.0.2.7/32, result: permit
2023/02/17 21:44:27 BGP: [WYP1M-NE4SY] Converted EVPN prefix [2]:[0]:[48]:[aa:bb:cc:00:22:22]:[32]:[20.0.0.2] into 20.0.0.2/32 for optimized route-map lookup
2023/02/17 21:44:27 BGP: [MT1SJ-WEJQ1] Best match route-map: soo-foo, sequence: 10 for pfx: 20.0.0.2/32, result: match
2023/02/17 21:44:27 BGP: [H5AW4-JFYQC] Route-map: soo-foo, prefix: 20.0.0.2/32, result: permit
2023/02/17 21:44:27 BGP: [KHG7H-RH4PN] Unable to convert EVPN prefix [3]:[0]:[32]:[2.2.2.2] into IPv4/IPv6 prefix. Falling back to non-optimized route-map lookup
2023/02/17 21:44:27 BGP: [MT1SJ-WEJQ1] Best match route-map: soo-foo, sequence: 10 for pfx: [3]:[0]:[32]:[2.2.2.2], result: match
2023/02/17 21:44:27 BGP: [H5AW4-JFYQC] Route-map: soo-foo, prefix: [3]:[0]:[32]:[2.2.2.2], result: permit
```
Signed-off-by: Trey Aspelund <taspelund@nvidia.com>
2023-02-17 22:47:09 +01:00
|
|
|
zlog_debug(
|
|
|
|
"No best match sequence for pfx: %pFX in route-map: %s, result: %s",
|
|
|
|
prefix, map->name,
|
|
|
|
route_map_cmd_result_str(match_ret));
|
|
|
|
/*
|
|
|
|
* No index matches this prefix. Return deny unless,
|
|
|
|
* match_ret = RMAP_NOOP.
|
|
|
|
*/
|
|
|
|
if (match_ret == RMAP_NOOP)
|
|
|
|
ret = RMAP_PERMITMATCH;
|
|
|
|
else
|
|
|
|
ret = RMAP_DENYMATCH;
|
|
|
|
goto route_map_apply_end;
|
2019-11-02 03:43:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for (; index; index = index->next) {
|
2020-03-04 14:04:23 +01:00
|
|
|
if (!skip_match_clause) {
|
2020-08-04 00:15:29 +02:00
|
|
|
index->applied++;
|
2019-11-02 03:43:10 +01:00
|
|
|
/* Apply this index. */
|
|
|
|
match_ret = route_map_apply_match(&index->match_list,
|
2021-09-08 19:46:21 +02:00
|
|
|
prefix, match_object);
|
2023-02-17 21:02:14 +01:00
|
|
|
if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP))) {
|
2019-11-02 03:43:10 +01:00
|
|
|
zlog_debug(
|
2020-10-18 13:33:54 +02:00
|
|
|
"Route-map: %s, sequence: %d, prefix: %pFX, result: %s",
|
|
|
|
map->name, index->pref, prefix,
|
2019-11-02 03:43:10 +01:00
|
|
|
route_map_cmd_result_str(match_ret));
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
skip_match_clause = false;
|
|
|
|
|
2019-05-10 00:34:52 +02:00
|
|
|
|
2003-10-29 07:30:19 +01:00
|
|
|
/* Now we apply the matrix from above */
|
lib: Introducing a 3rd state for route-map match cmd: RMAP_NOOP
Introducing a 3rd state for route_map_apply library function: RMAP_NOOP
Traditionally route map MATCH rule apis were designed to return
a binary response, consisting of either RMAP_MATCH or RMAP_NOMATCH.
(Route-map SET rule apis return RMAP_OKAY or RMAP_ERROR).
Depending on this response, the following statemachine decided the
course of action:
State1:
If match cmd returns RMAP_MATCH then, keep existing behaviour.
If routemap type is PERMIT, execute set cmds or call cmds if applicable,
otherwise PERMIT!
Else If routemap type is DENY, we DENYMATCH right away
State2:
If match cmd returns RMAP_NOMATCH, continue on to next route-map. If there
are no other rules or if all the rules return RMAP_NOMATCH, return DENYMATCH
We require a 3rd state because of the following situation:
The issue - what if, the rule api needs to abort or ignore a rule?:
"match evpn vni xx" route-map filter can be applied to incoming routes
regardless of whether the tunnel type is vxlan or mpls.
This rule should be N/A for mpls based evpn route, but applicable to only
vxlan based evpn route.
Also, this rule should be applicable for routes with VNI label only, and
not for routes without labels. For example, type 3 and type 4 EVPN routes
do not have labels, so, this match cmd should let them through.
Today, the filter produces either a match or nomatch response regardless of
whether it is mpls/vxlan, resulting in either permitting or denying the
route.. So an mpls evpn route may get filtered out incorrectly.
Eg: "route-map RM1 permit 10 ; match evpn vni 20" or
"route-map RM2 deny 20 ; match vni 20"
With the introduction of the 3rd state, we can abort this rule check safely.
How? The rules api can now return RMAP_NOOP to indicate
that it encountered an invalid check, and needs to abort just that rule,
but continue with other rules.
As a result we have a 3rd state:
State3:
If match cmd returned RMAP_NOOP
Then, proceed to other route-map, otherwise if there are no more
rules or if all the rules return RMAP_NOOP, then, return RMAP_PERMITMATCH.
Signed-off-by: Lakshman Krishnamoorthy <lkrishnamoor@vmware.com>
2019-06-19 23:04:36 +02:00
|
|
|
if (match_ret == RMAP_NOOP)
|
|
|
|
/*
|
|
|
|
* Do not change the return value. Retain the previous
|
|
|
|
* return value. Previous values can be:
|
|
|
|
* 1)permitmatch (if a nomatch was never
|
|
|
|
* seen before in this route-map.)
|
|
|
|
* 2)denymatch (if a nomatch was seen earlier in one
|
|
|
|
* of the previous sequences)
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 'cont' from matrix - continue to next route-map
|
|
|
|
* sequence
|
|
|
|
*/
|
2003-10-29 07:30:19 +01:00
|
|
|
continue;
|
lib: Introducing a 3rd state for route-map match cmd: RMAP_NOOP
Introducing a 3rd state for route_map_apply library function: RMAP_NOOP
Traditionally route map MATCH rule apis were designed to return
a binary response, consisting of either RMAP_MATCH or RMAP_NOMATCH.
(Route-map SET rule apis return RMAP_OKAY or RMAP_ERROR).
Depending on this response, the following statemachine decided the
course of action:
State1:
If match cmd returns RMAP_MATCH then, keep existing behaviour.
If routemap type is PERMIT, execute set cmds or call cmds if applicable,
otherwise PERMIT!
Else If routemap type is DENY, we DENYMATCH right away
State2:
If match cmd returns RMAP_NOMATCH, continue on to next route-map. If there
are no other rules or if all the rules return RMAP_NOMATCH, return DENYMATCH
We require a 3rd state because of the following situation:
The issue - what if, the rule api needs to abort or ignore a rule?:
"match evpn vni xx" route-map filter can be applied to incoming routes
regardless of whether the tunnel type is vxlan or mpls.
This rule should be N/A for mpls based evpn route, but applicable to only
vxlan based evpn route.
Also, this rule should be applicable for routes with VNI label only, and
not for routes without labels. For example, type 3 and type 4 EVPN routes
do not have labels, so, this match cmd should let them through.
Today, the filter produces either a match or nomatch response regardless of
whether it is mpls/vxlan, resulting in either permitting or denying the
route.. So an mpls evpn route may get filtered out incorrectly.
Eg: "route-map RM1 permit 10 ; match evpn vni 20" or
"route-map RM2 deny 20 ; match vni 20"
With the introduction of the 3rd state, we can abort this rule check safely.
How? The rules api can now return RMAP_NOOP to indicate
that it encountered an invalid check, and needs to abort just that rule,
but continue with other rules.
As a result we have a 3rd state:
State3:
If match cmd returned RMAP_NOOP
Then, proceed to other route-map, otherwise if there are no more
rules or if all the rules return RMAP_NOOP, then, return RMAP_PERMITMATCH.
Signed-off-by: Lakshman Krishnamoorthy <lkrishnamoor@vmware.com>
2019-06-19 23:04:36 +02:00
|
|
|
else if (match_ret == RMAP_NOMATCH) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The return value is now changed to denymatch.
|
|
|
|
* So from here on out, even if we see more noops,
|
|
|
|
* we retain this return value and return this
|
|
|
|
* eventually if there are no matches.
|
|
|
|
*/
|
|
|
|
ret = RMAP_DENYMATCH;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 'cont' from matrix - continue to next route-map
|
|
|
|
* sequence
|
|
|
|
*/
|
|
|
|
continue;
|
|
|
|
} else if (match_ret == RMAP_MATCH) {
|
2003-10-29 07:30:19 +01:00
|
|
|
if (index->type == RMAP_PERMIT)
|
|
|
|
/* 'action' */
|
|
|
|
{
|
lib: Introducing a 3rd state for route-map match cmd: RMAP_NOOP
Introducing a 3rd state for route_map_apply library function: RMAP_NOOP
Traditionally route map MATCH rule apis were designed to return
a binary response, consisting of either RMAP_MATCH or RMAP_NOMATCH.
(Route-map SET rule apis return RMAP_OKAY or RMAP_ERROR).
Depending on this response, the following statemachine decided the
course of action:
State1:
If match cmd returns RMAP_MATCH then, keep existing behaviour.
If routemap type is PERMIT, execute set cmds or call cmds if applicable,
otherwise PERMIT!
Else If routemap type is DENY, we DENYMATCH right away
State2:
If match cmd returns RMAP_NOMATCH, continue on to next route-map. If there
are no other rules or if all the rules return RMAP_NOMATCH, return DENYMATCH
We require a 3rd state because of the following situation:
The issue - what if, the rule api needs to abort or ignore a rule?:
"match evpn vni xx" route-map filter can be applied to incoming routes
regardless of whether the tunnel type is vxlan or mpls.
This rule should be N/A for mpls based evpn route, but applicable to only
vxlan based evpn route.
Also, this rule should be applicable for routes with VNI label only, and
not for routes without labels. For example, type 3 and type 4 EVPN routes
do not have labels, so, this match cmd should let them through.
Today, the filter produces either a match or nomatch response regardless of
whether it is mpls/vxlan, resulting in either permitting or denying the
route.. So an mpls evpn route may get filtered out incorrectly.
Eg: "route-map RM1 permit 10 ; match evpn vni 20" or
"route-map RM2 deny 20 ; match vni 20"
With the introduction of the 3rd state, we can abort this rule check safely.
How? The rules api can now return RMAP_NOOP to indicate
that it encountered an invalid check, and needs to abort just that rule,
but continue with other rules.
As a result we have a 3rd state:
State3:
If match cmd returned RMAP_NOOP
Then, proceed to other route-map, otherwise if there are no more
rules or if all the rules return RMAP_NOOP, then, return RMAP_PERMITMATCH.
Signed-off-by: Lakshman Krishnamoorthy <lkrishnamoor@vmware.com>
2019-06-19 23:04:36 +02:00
|
|
|
/* Match succeeded, rmap is of type permit */
|
|
|
|
ret = RMAP_PERMITMATCH;
|
|
|
|
|
2003-10-29 07:30:19 +01:00
|
|
|
/* permit+match must execute sets */
|
|
|
|
for (set = index->set_list.head; set;
|
|
|
|
set = set->next)
|
lib: Introducing a 3rd state for route-map match cmd: RMAP_NOOP
Introducing a 3rd state for route_map_apply library function: RMAP_NOOP
Traditionally route map MATCH rule apis were designed to return
a binary response, consisting of either RMAP_MATCH or RMAP_NOMATCH.
(Route-map SET rule apis return RMAP_OKAY or RMAP_ERROR).
Depending on this response, the following statemachine decided the
course of action:
State1:
If match cmd returns RMAP_MATCH then, keep existing behaviour.
If routemap type is PERMIT, execute set cmds or call cmds if applicable,
otherwise PERMIT!
Else If routemap type is DENY, we DENYMATCH right away
State2:
If match cmd returns RMAP_NOMATCH, continue on to next route-map. If there
are no other rules or if all the rules return RMAP_NOMATCH, return DENYMATCH
We require a 3rd state because of the following situation:
The issue - what if, the rule api needs to abort or ignore a rule?:
"match evpn vni xx" route-map filter can be applied to incoming routes
regardless of whether the tunnel type is vxlan or mpls.
This rule should be N/A for mpls based evpn route, but applicable to only
vxlan based evpn route.
Also, this rule should be applicable for routes with VNI label only, and
not for routes without labels. For example, type 3 and type 4 EVPN routes
do not have labels, so, this match cmd should let them through.
Today, the filter produces either a match or nomatch response regardless of
whether it is mpls/vxlan, resulting in either permitting or denying the
route.. So an mpls evpn route may get filtered out incorrectly.
Eg: "route-map RM1 permit 10 ; match evpn vni 20" or
"route-map RM2 deny 20 ; match vni 20"
With the introduction of the 3rd state, we can abort this rule check safely.
How? The rules api can now return RMAP_NOOP to indicate
that it encountered an invalid check, and needs to abort just that rule,
but continue with other rules.
As a result we have a 3rd state:
State3:
If match cmd returned RMAP_NOOP
Then, proceed to other route-map, otherwise if there are no more
rules or if all the rules return RMAP_NOOP, then, return RMAP_PERMITMATCH.
Signed-off-by: Lakshman Krishnamoorthy <lkrishnamoor@vmware.com>
2019-06-19 23:04:36 +02:00
|
|
|
/*
|
|
|
|
* set cmds return RMAP_OKAY or
|
|
|
|
* RMAP_ERROR. We do not care if
|
|
|
|
* set succeeded or not. So, ignore
|
|
|
|
* return code.
|
|
|
|
*/
|
2020-11-14 01:35:20 +01:00
|
|
|
(void)(*set->cmd->func_apply)(
|
2021-09-08 19:46:21 +02:00
|
|
|
set->value, prefix, set_object);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-09-13 Jose Luis Rubio <jrubio@dit.upm.es>
(at Technical University of Madrid as part of Euro6ix Project)
Enhanced Route Server functionality and Route-Maps:
* bgpd/bgpd.h: Modified 'struct peer' and 'struct bgp_filter' to
support rs-clients. A 'struct bgp_table *rib' has been added to the
first (to mantain a separated RIB for each rs-client) and two new
route-maps have been added to the last (for import/export policies).
Added the following #defines: RMAP_{IN|OUT|IMPORT|EXPORT|MAX},
PEER_RMAP_TYPE_{IMPORT|EXPORT} and BGP_CLEAR_SOFT_RSCLIENT.
* bgpd/bgpd.c: Modified the functions that create/delete/etc peers in
order to consider the new fields included in 'struct peer' for
supporting rs-clients, i.e. the import/export route-maps and the
'struct bgp_table'.
* bgpd/bgp_route.{ch}: Modified several functions related with
receiving/sending announces in order to support the new Route Server
capabilities.
Function 'bgp_process' has been reorganized, creating an auxiliar
function for best path selection ('bgp_best_selection').
Modified 'bgp_show' and 'bgp_show_route' for displaying information
about any RIB (and not only the main bgp RIB).
Added commands for displaying information about RS-clients RIBs:
'show bgp rsclient (A.B.C.D|X:X::X:X)', 'show bgp rsclient
(A.B.C.D|X:X::X:X) X:X::X:X/M', etc
* bgpd/bgp_table.{ch}: The structure 'struct bgp_table' now has two
new fields: type (which can take the values BGP_TABLE_{MAIN|RSCLIENT})
and 'void *owner' which points to 'struct bgp' or 'struct peer' which
owns the table.
When creating a new bgp_table by default 'type=BGP_TABLE_MAIN' is set.
* bgpd/bgp_vty.c: The commands 'neighbor ... route-server-client' and
'no neighbor ... route-server-client' now not only set/unset the flag
PEER_FLAG_RSERVER_CLIENT, but they create/destroy the 'struct
bgp_table' of the peer. Special actions are taken for peer_groups.
Command 'neighbor ... route-map WORD (in|out)' now also supports two
new kinds of route-map: 'import' and 'export'.
Added commands 'clear bgp * rsclient', etc. These commands allow a new
kind of soft_reconfig which affects only the RIB of the specified
RS-client.
Added commands 'show bgp rsclient summary', etc which display a
summary of the rs-clients configured for the corresponding address
family.
* bgpd/bgp_routemap.c: A new match statement is available,
'match peer (A.B.C.D|X:X::X:X)'. This statement can only be used in
import/export route-maps, and it matches when the peer who announces
(when used in an import route-map) or is going to receive (when used
in an export route-map) the route is the same than the one specified
in the statement.
For peer-groups the statement matches if the specified peer is member
of the peer-group.
A special version of the command, 'match peer local', matches with
routes originated by the Route Server (defined with 'network ...',
redistributed routes and default-originate).
* lib/routemap.{ch}: Added a new clause 'call NAME' for use in
route-maps. It jumps into the specified route-map and when it returns
the first route-map ends if the called RM returns DENY_MATCH, or
continues in other case.
2004-09-13 07:12:46 +02:00
|
|
|
/* Call another route-map if available */
|
|
|
|
if (index->nextrm) {
|
|
|
|
struct route_map *nextrm =
|
|
|
|
route_map_lookup_by_name(
|
|
|
|
index->nextrm);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-09-13 Jose Luis Rubio <jrubio@dit.upm.es>
(at Technical University of Madrid as part of Euro6ix Project)
Enhanced Route Server functionality and Route-Maps:
* bgpd/bgpd.h: Modified 'struct peer' and 'struct bgp_filter' to
support rs-clients. A 'struct bgp_table *rib' has been added to the
first (to mantain a separated RIB for each rs-client) and two new
route-maps have been added to the last (for import/export policies).
Added the following #defines: RMAP_{IN|OUT|IMPORT|EXPORT|MAX},
PEER_RMAP_TYPE_{IMPORT|EXPORT} and BGP_CLEAR_SOFT_RSCLIENT.
* bgpd/bgpd.c: Modified the functions that create/delete/etc peers in
order to consider the new fields included in 'struct peer' for
supporting rs-clients, i.e. the import/export route-maps and the
'struct bgp_table'.
* bgpd/bgp_route.{ch}: Modified several functions related with
receiving/sending announces in order to support the new Route Server
capabilities.
Function 'bgp_process' has been reorganized, creating an auxiliar
function for best path selection ('bgp_best_selection').
Modified 'bgp_show' and 'bgp_show_route' for displaying information
about any RIB (and not only the main bgp RIB).
Added commands for displaying information about RS-clients RIBs:
'show bgp rsclient (A.B.C.D|X:X::X:X)', 'show bgp rsclient
(A.B.C.D|X:X::X:X) X:X::X:X/M', etc
* bgpd/bgp_table.{ch}: The structure 'struct bgp_table' now has two
new fields: type (which can take the values BGP_TABLE_{MAIN|RSCLIENT})
and 'void *owner' which points to 'struct bgp' or 'struct peer' which
owns the table.
When creating a new bgp_table by default 'type=BGP_TABLE_MAIN' is set.
* bgpd/bgp_vty.c: The commands 'neighbor ... route-server-client' and
'no neighbor ... route-server-client' now not only set/unset the flag
PEER_FLAG_RSERVER_CLIENT, but they create/destroy the 'struct
bgp_table' of the peer. Special actions are taken for peer_groups.
Command 'neighbor ... route-map WORD (in|out)' now also supports two
new kinds of route-map: 'import' and 'export'.
Added commands 'clear bgp * rsclient', etc. These commands allow a new
kind of soft_reconfig which affects only the RIB of the specified
RS-client.
Added commands 'show bgp rsclient summary', etc which display a
summary of the rs-clients configured for the corresponding address
family.
* bgpd/bgp_routemap.c: A new match statement is available,
'match peer (A.B.C.D|X:X::X:X)'. This statement can only be used in
import/export route-maps, and it matches when the peer who announces
(when used in an import route-map) or is going to receive (when used
in an export route-map) the route is the same than the one specified
in the statement.
For peer-groups the statement matches if the specified peer is member
of the peer-group.
A special version of the command, 'match peer local', matches with
routes originated by the Route Server (defined with 'network ...',
redistributed routes and default-originate).
* lib/routemap.{ch}: Added a new clause 'call NAME' for use in
route-maps. It jumps into the specified route-map and when it returns
the first route-map ends if the called RM returns DENY_MATCH, or
continues in other case.
2004-09-13 07:12:46 +02:00
|
|
|
if (nextrm) /* Target route-map found,
|
|
|
|
jump to it */
|
|
|
|
{
|
|
|
|
recursion++;
|
2021-09-08 19:46:21 +02:00
|
|
|
ret = route_map_apply_ext(
|
|
|
|
nextrm, prefix,
|
|
|
|
match_object,
|
2022-05-27 17:07:36 +02:00
|
|
|
set_object, NULL);
|
2004-09-13 Jose Luis Rubio <jrubio@dit.upm.es>
(at Technical University of Madrid as part of Euro6ix Project)
Enhanced Route Server functionality and Route-Maps:
* bgpd/bgpd.h: Modified 'struct peer' and 'struct bgp_filter' to
support rs-clients. A 'struct bgp_table *rib' has been added to the
first (to mantain a separated RIB for each rs-client) and two new
route-maps have been added to the last (for import/export policies).
Added the following #defines: RMAP_{IN|OUT|IMPORT|EXPORT|MAX},
PEER_RMAP_TYPE_{IMPORT|EXPORT} and BGP_CLEAR_SOFT_RSCLIENT.
* bgpd/bgpd.c: Modified the functions that create/delete/etc peers in
order to consider the new fields included in 'struct peer' for
supporting rs-clients, i.e. the import/export route-maps and the
'struct bgp_table'.
* bgpd/bgp_route.{ch}: Modified several functions related with
receiving/sending announces in order to support the new Route Server
capabilities.
Function 'bgp_process' has been reorganized, creating an auxiliar
function for best path selection ('bgp_best_selection').
Modified 'bgp_show' and 'bgp_show_route' for displaying information
about any RIB (and not only the main bgp RIB).
Added commands for displaying information about RS-clients RIBs:
'show bgp rsclient (A.B.C.D|X:X::X:X)', 'show bgp rsclient
(A.B.C.D|X:X::X:X) X:X::X:X/M', etc
* bgpd/bgp_table.{ch}: The structure 'struct bgp_table' now has two
new fields: type (which can take the values BGP_TABLE_{MAIN|RSCLIENT})
and 'void *owner' which points to 'struct bgp' or 'struct peer' which
owns the table.
When creating a new bgp_table by default 'type=BGP_TABLE_MAIN' is set.
* bgpd/bgp_vty.c: The commands 'neighbor ... route-server-client' and
'no neighbor ... route-server-client' now not only set/unset the flag
PEER_FLAG_RSERVER_CLIENT, but they create/destroy the 'struct
bgp_table' of the peer. Special actions are taken for peer_groups.
Command 'neighbor ... route-map WORD (in|out)' now also supports two
new kinds of route-map: 'import' and 'export'.
Added commands 'clear bgp * rsclient', etc. These commands allow a new
kind of soft_reconfig which affects only the RIB of the specified
RS-client.
Added commands 'show bgp rsclient summary', etc which display a
summary of the rs-clients configured for the corresponding address
family.
* bgpd/bgp_routemap.c: A new match statement is available,
'match peer (A.B.C.D|X:X::X:X)'. This statement can only be used in
import/export route-maps, and it matches when the peer who announces
(when used in an import route-map) or is going to receive (when used
in an export route-map) the route is the same than the one specified
in the statement.
For peer-groups the statement matches if the specified peer is member
of the peer-group.
A special version of the command, 'match peer local', matches with
routes originated by the Route Server (defined with 'network ...',
redistributed routes and default-originate).
* lib/routemap.{ch}: Added a new clause 'call NAME' for use in
route-maps. It jumps into the specified route-map and when it returns
the first route-map ends if the called RM returns DENY_MATCH, or
continues in other case.
2004-09-13 07:12:46 +02:00
|
|
|
recursion--;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-09-13 Jose Luis Rubio <jrubio@dit.upm.es>
(at Technical University of Madrid as part of Euro6ix Project)
Enhanced Route Server functionality and Route-Maps:
* bgpd/bgpd.h: Modified 'struct peer' and 'struct bgp_filter' to
support rs-clients. A 'struct bgp_table *rib' has been added to the
first (to mantain a separated RIB for each rs-client) and two new
route-maps have been added to the last (for import/export policies).
Added the following #defines: RMAP_{IN|OUT|IMPORT|EXPORT|MAX},
PEER_RMAP_TYPE_{IMPORT|EXPORT} and BGP_CLEAR_SOFT_RSCLIENT.
* bgpd/bgpd.c: Modified the functions that create/delete/etc peers in
order to consider the new fields included in 'struct peer' for
supporting rs-clients, i.e. the import/export route-maps and the
'struct bgp_table'.
* bgpd/bgp_route.{ch}: Modified several functions related with
receiving/sending announces in order to support the new Route Server
capabilities.
Function 'bgp_process' has been reorganized, creating an auxiliar
function for best path selection ('bgp_best_selection').
Modified 'bgp_show' and 'bgp_show_route' for displaying information
about any RIB (and not only the main bgp RIB).
Added commands for displaying information about RS-clients RIBs:
'show bgp rsclient (A.B.C.D|X:X::X:X)', 'show bgp rsclient
(A.B.C.D|X:X::X:X) X:X::X:X/M', etc
* bgpd/bgp_table.{ch}: The structure 'struct bgp_table' now has two
new fields: type (which can take the values BGP_TABLE_{MAIN|RSCLIENT})
and 'void *owner' which points to 'struct bgp' or 'struct peer' which
owns the table.
When creating a new bgp_table by default 'type=BGP_TABLE_MAIN' is set.
* bgpd/bgp_vty.c: The commands 'neighbor ... route-server-client' and
'no neighbor ... route-server-client' now not only set/unset the flag
PEER_FLAG_RSERVER_CLIENT, but they create/destroy the 'struct
bgp_table' of the peer. Special actions are taken for peer_groups.
Command 'neighbor ... route-map WORD (in|out)' now also supports two
new kinds of route-map: 'import' and 'export'.
Added commands 'clear bgp * rsclient', etc. These commands allow a new
kind of soft_reconfig which affects only the RIB of the specified
RS-client.
Added commands 'show bgp rsclient summary', etc which display a
summary of the rs-clients configured for the corresponding address
family.
* bgpd/bgp_routemap.c: A new match statement is available,
'match peer (A.B.C.D|X:X::X:X)'. This statement can only be used in
import/export route-maps, and it matches when the peer who announces
(when used in an import route-map) or is going to receive (when used
in an export route-map) the route is the same than the one specified
in the statement.
For peer-groups the statement matches if the specified peer is member
of the peer-group.
A special version of the command, 'match peer local', matches with
routes originated by the Route Server (defined with 'network ...',
redistributed routes and default-originate).
* lib/routemap.{ch}: Added a new clause 'call NAME' for use in
route-maps. It jumps into the specified route-map and when it returns
the first route-map ends if the called RM returns DENY_MATCH, or
continues in other case.
2004-09-13 07:12:46 +02:00
|
|
|
/* If nextrm returned 'deny', finish. */
|
|
|
|
if (ret == RMAP_DENYMATCH)
|
2019-05-10 00:34:52 +02:00
|
|
|
goto route_map_apply_end;
|
2004-09-13 Jose Luis Rubio <jrubio@dit.upm.es>
(at Technical University of Madrid as part of Euro6ix Project)
Enhanced Route Server functionality and Route-Maps:
* bgpd/bgpd.h: Modified 'struct peer' and 'struct bgp_filter' to
support rs-clients. A 'struct bgp_table *rib' has been added to the
first (to mantain a separated RIB for each rs-client) and two new
route-maps have been added to the last (for import/export policies).
Added the following #defines: RMAP_{IN|OUT|IMPORT|EXPORT|MAX},
PEER_RMAP_TYPE_{IMPORT|EXPORT} and BGP_CLEAR_SOFT_RSCLIENT.
* bgpd/bgpd.c: Modified the functions that create/delete/etc peers in
order to consider the new fields included in 'struct peer' for
supporting rs-clients, i.e. the import/export route-maps and the
'struct bgp_table'.
* bgpd/bgp_route.{ch}: Modified several functions related with
receiving/sending announces in order to support the new Route Server
capabilities.
Function 'bgp_process' has been reorganized, creating an auxiliar
function for best path selection ('bgp_best_selection').
Modified 'bgp_show' and 'bgp_show_route' for displaying information
about any RIB (and not only the main bgp RIB).
Added commands for displaying information about RS-clients RIBs:
'show bgp rsclient (A.B.C.D|X:X::X:X)', 'show bgp rsclient
(A.B.C.D|X:X::X:X) X:X::X:X/M', etc
* bgpd/bgp_table.{ch}: The structure 'struct bgp_table' now has two
new fields: type (which can take the values BGP_TABLE_{MAIN|RSCLIENT})
and 'void *owner' which points to 'struct bgp' or 'struct peer' which
owns the table.
When creating a new bgp_table by default 'type=BGP_TABLE_MAIN' is set.
* bgpd/bgp_vty.c: The commands 'neighbor ... route-server-client' and
'no neighbor ... route-server-client' now not only set/unset the flag
PEER_FLAG_RSERVER_CLIENT, but they create/destroy the 'struct
bgp_table' of the peer. Special actions are taken for peer_groups.
Command 'neighbor ... route-map WORD (in|out)' now also supports two
new kinds of route-map: 'import' and 'export'.
Added commands 'clear bgp * rsclient', etc. These commands allow a new
kind of soft_reconfig which affects only the RIB of the specified
RS-client.
Added commands 'show bgp rsclient summary', etc which display a
summary of the rs-clients configured for the corresponding address
family.
* bgpd/bgp_routemap.c: A new match statement is available,
'match peer (A.B.C.D|X:X::X:X)'. This statement can only be used in
import/export route-maps, and it matches when the peer who announces
(when used in an import route-map) or is going to receive (when used
in an export route-map) the route is the same than the one specified
in the statement.
For peer-groups the statement matches if the specified peer is member
of the peer-group.
A special version of the command, 'match peer local', matches with
routes originated by the Route Server (defined with 'network ...',
redistributed routes and default-originate).
* lib/routemap.{ch}: Added a new clause 'call NAME' for use in
route-maps. It jumps into the specified route-map and when it returns
the first route-map ends if the called RM returns DENY_MATCH, or
continues in other case.
2004-09-13 07:12:46 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2003-10-29 07:30:19 +01:00
|
|
|
switch (index->exitpolicy) {
|
|
|
|
case RMAP_EXIT:
|
2019-05-10 00:34:52 +02:00
|
|
|
goto route_map_apply_end;
|
2003-10-29 07:30:19 +01:00
|
|
|
case RMAP_NEXT:
|
|
|
|
continue;
|
|
|
|
case RMAP_GOTO: {
|
|
|
|
/* Find the next clause to jump to */
|
|
|
|
struct route_map_index *next =
|
|
|
|
index->next;
|
2004-09-13 Jose Luis Rubio <jrubio@dit.upm.es>
(at Technical University of Madrid as part of Euro6ix Project)
Enhanced Route Server functionality and Route-Maps:
* bgpd/bgpd.h: Modified 'struct peer' and 'struct bgp_filter' to
support rs-clients. A 'struct bgp_table *rib' has been added to the
first (to mantain a separated RIB for each rs-client) and two new
route-maps have been added to the last (for import/export policies).
Added the following #defines: RMAP_{IN|OUT|IMPORT|EXPORT|MAX},
PEER_RMAP_TYPE_{IMPORT|EXPORT} and BGP_CLEAR_SOFT_RSCLIENT.
* bgpd/bgpd.c: Modified the functions that create/delete/etc peers in
order to consider the new fields included in 'struct peer' for
supporting rs-clients, i.e. the import/export route-maps and the
'struct bgp_table'.
* bgpd/bgp_route.{ch}: Modified several functions related with
receiving/sending announces in order to support the new Route Server
capabilities.
Function 'bgp_process' has been reorganized, creating an auxiliar
function for best path selection ('bgp_best_selection').
Modified 'bgp_show' and 'bgp_show_route' for displaying information
about any RIB (and not only the main bgp RIB).
Added commands for displaying information about RS-clients RIBs:
'show bgp rsclient (A.B.C.D|X:X::X:X)', 'show bgp rsclient
(A.B.C.D|X:X::X:X) X:X::X:X/M', etc
* bgpd/bgp_table.{ch}: The structure 'struct bgp_table' now has two
new fields: type (which can take the values BGP_TABLE_{MAIN|RSCLIENT})
and 'void *owner' which points to 'struct bgp' or 'struct peer' which
owns the table.
When creating a new bgp_table by default 'type=BGP_TABLE_MAIN' is set.
* bgpd/bgp_vty.c: The commands 'neighbor ... route-server-client' and
'no neighbor ... route-server-client' now not only set/unset the flag
PEER_FLAG_RSERVER_CLIENT, but they create/destroy the 'struct
bgp_table' of the peer. Special actions are taken for peer_groups.
Command 'neighbor ... route-map WORD (in|out)' now also supports two
new kinds of route-map: 'import' and 'export'.
Added commands 'clear bgp * rsclient', etc. These commands allow a new
kind of soft_reconfig which affects only the RIB of the specified
RS-client.
Added commands 'show bgp rsclient summary', etc which display a
summary of the rs-clients configured for the corresponding address
family.
* bgpd/bgp_routemap.c: A new match statement is available,
'match peer (A.B.C.D|X:X::X:X)'. This statement can only be used in
import/export route-maps, and it matches when the peer who announces
(when used in an import route-map) or is going to receive (when used
in an export route-map) the route is the same than the one specified
in the statement.
For peer-groups the statement matches if the specified peer is member
of the peer-group.
A special version of the command, 'match peer local', matches with
routes originated by the Route Server (defined with 'network ...',
redistributed routes and default-originate).
* lib/routemap.{ch}: Added a new clause 'call NAME' for use in
route-maps. It jumps into the specified route-map and when it returns
the first route-map ends if the called RM returns DENY_MATCH, or
continues in other case.
2004-09-13 07:12:46 +02:00
|
|
|
int nextpref = index->nextpref;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-09-13 Jose Luis Rubio <jrubio@dit.upm.es>
(at Technical University of Madrid as part of Euro6ix Project)
Enhanced Route Server functionality and Route-Maps:
* bgpd/bgpd.h: Modified 'struct peer' and 'struct bgp_filter' to
support rs-clients. A 'struct bgp_table *rib' has been added to the
first (to mantain a separated RIB for each rs-client) and two new
route-maps have been added to the last (for import/export policies).
Added the following #defines: RMAP_{IN|OUT|IMPORT|EXPORT|MAX},
PEER_RMAP_TYPE_{IMPORT|EXPORT} and BGP_CLEAR_SOFT_RSCLIENT.
* bgpd/bgpd.c: Modified the functions that create/delete/etc peers in
order to consider the new fields included in 'struct peer' for
supporting rs-clients, i.e. the import/export route-maps and the
'struct bgp_table'.
* bgpd/bgp_route.{ch}: Modified several functions related with
receiving/sending announces in order to support the new Route Server
capabilities.
Function 'bgp_process' has been reorganized, creating an auxiliar
function for best path selection ('bgp_best_selection').
Modified 'bgp_show' and 'bgp_show_route' for displaying information
about any RIB (and not only the main bgp RIB).
Added commands for displaying information about RS-clients RIBs:
'show bgp rsclient (A.B.C.D|X:X::X:X)', 'show bgp rsclient
(A.B.C.D|X:X::X:X) X:X::X:X/M', etc
* bgpd/bgp_table.{ch}: The structure 'struct bgp_table' now has two
new fields: type (which can take the values BGP_TABLE_{MAIN|RSCLIENT})
and 'void *owner' which points to 'struct bgp' or 'struct peer' which
owns the table.
When creating a new bgp_table by default 'type=BGP_TABLE_MAIN' is set.
* bgpd/bgp_vty.c: The commands 'neighbor ... route-server-client' and
'no neighbor ... route-server-client' now not only set/unset the flag
PEER_FLAG_RSERVER_CLIENT, but they create/destroy the 'struct
bgp_table' of the peer. Special actions are taken for peer_groups.
Command 'neighbor ... route-map WORD (in|out)' now also supports two
new kinds of route-map: 'import' and 'export'.
Added commands 'clear bgp * rsclient', etc. These commands allow a new
kind of soft_reconfig which affects only the RIB of the specified
RS-client.
Added commands 'show bgp rsclient summary', etc which display a
summary of the rs-clients configured for the corresponding address
family.
* bgpd/bgp_routemap.c: A new match statement is available,
'match peer (A.B.C.D|X:X::X:X)'. This statement can only be used in
import/export route-maps, and it matches when the peer who announces
(when used in an import route-map) or is going to receive (when used
in an export route-map) the route is the same than the one specified
in the statement.
For peer-groups the statement matches if the specified peer is member
of the peer-group.
A special version of the command, 'match peer local', matches with
routes originated by the Route Server (defined with 'network ...',
redistributed routes and default-originate).
* lib/routemap.{ch}: Added a new clause 'call NAME' for use in
route-maps. It jumps into the specified route-map and when it returns
the first route-map ends if the called RM returns DENY_MATCH, or
continues in other case.
2004-09-13 07:12:46 +02:00
|
|
|
while (next && next->pref < nextpref) {
|
2003-10-29 07:30:19 +01:00
|
|
|
index = next;
|
|
|
|
next = next->next;
|
|
|
|
}
|
|
|
|
if (next == NULL) {
|
|
|
|
/* No clauses match! */
|
2019-05-10 00:34:52 +02:00
|
|
|
goto route_map_apply_end;
|
2003-10-29 07:30:19 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
}
|
2003-10-29 07:30:19 +01:00
|
|
|
} else if (index->type == RMAP_DENY)
|
|
|
|
/* 'deny' */
|
|
|
|
{
|
2019-05-10 00:34:52 +02:00
|
|
|
ret = RMAP_DENYMATCH;
|
|
|
|
goto route_map_apply_end;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2022-10-10 16:56:51 +02:00
|
|
|
GETRUSAGE(&iafter);
|
|
|
|
event_consumed_time(&iafter, &ibefore, &cputime);
|
|
|
|
index->cputime += cputime;
|
|
|
|
ibefore = iafter;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2019-05-10 00:34:52 +02:00
|
|
|
|
|
|
|
route_map_apply_end:
|
2023-02-17 21:02:14 +01:00
|
|
|
if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP)))
|
2020-10-18 13:33:54 +02:00
|
|
|
zlog_debug("Route-map: %s, prefix: %pFX, result: %s",
|
|
|
|
(map ? map->name : "null"), prefix,
|
2019-05-10 00:34:52 +02:00
|
|
|
route_map_result_str(ret));
|
|
|
|
|
2022-05-27 17:07:36 +02:00
|
|
|
if (pref) {
|
|
|
|
if (index != NULL && ret == RMAP_PERMITMATCH)
|
|
|
|
*pref = index->pref;
|
|
|
|
else
|
|
|
|
*pref = 65536;
|
|
|
|
}
|
|
|
|
|
2022-10-10 16:56:51 +02:00
|
|
|
if (map) {
|
|
|
|
GETRUSAGE(&mafter);
|
|
|
|
event_consumed_time(&mafter, &mbefore, &cputime);
|
|
|
|
map->cputime += cputime;
|
|
|
|
}
|
|
|
|
|
2019-05-10 00:34:52 +02:00
|
|
|
return (ret);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-10-10 Paul Jakma <paul@dishone.st>
* version.h.in: (pid_output*) add const qualifier.
* command.h: Change DEFUN func to take const char *[] rather
than char **, to begin process of fixing compile warnings in lib/.
Nearly all other changes in this commit follow from this change.
* buffer.{c,h}: (buffer_write) pointer-arithmetic is gccism, take
const void * and cast an automatic const char *p to it.
(buffer_putstr) add const
* command.c: (zencrypt) const qualifier
(cmd_execute_command_real) ditto
(cmd_execute_command_strict) ditto
(config_log_file) ditto.
Fix leak of getcwd() returned string.
* memory.{c,h}: Add MTYPE_DISTRIBUTE_IFNAME for struct dist ifname.
* distribute.{c,h}: Update with const qualifier.
(distribute_free) use MTYPE_DISTRIBUTE_IFNAME
(distribute_lookup) Cast to char *, note that it's ok.
(distribute_hash_alloc) use MTYPE_DISTRIBUTE_IFNAME.
(distribute_get) Cast to char *, note that it's ok.
* filter.c: Update with const qualifier.
* if.{c,h}: ditto.
* if_rmap.{c,h}: ditto.
(if_rmap_lookup) Cast to char *, note that it's ok.
(if_rmap_get) ditto.
* log.{c,h}: Update with const qualifier.
* plist.{c,h}: ditto.
* routemap.{c,h}: ditto.
* smux.{c,h}: ditto. Fix some signed/unsigned comparisons.
* sockopt.c: (getsockopt_cmsg_data) add return for error case.
* vty.c: Update with const qualifier.
2004-10-10 13:56:56 +02:00
|
|
|
void route_map_add_hook(void (*func)(const char *))
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
route_map_master.add_hook = func;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-10-10 Paul Jakma <paul@dishone.st>
* version.h.in: (pid_output*) add const qualifier.
* command.h: Change DEFUN func to take const char *[] rather
than char **, to begin process of fixing compile warnings in lib/.
Nearly all other changes in this commit follow from this change.
* buffer.{c,h}: (buffer_write) pointer-arithmetic is gccism, take
const void * and cast an automatic const char *p to it.
(buffer_putstr) add const
* command.c: (zencrypt) const qualifier
(cmd_execute_command_real) ditto
(cmd_execute_command_strict) ditto
(config_log_file) ditto.
Fix leak of getcwd() returned string.
* memory.{c,h}: Add MTYPE_DISTRIBUTE_IFNAME for struct dist ifname.
* distribute.{c,h}: Update with const qualifier.
(distribute_free) use MTYPE_DISTRIBUTE_IFNAME
(distribute_lookup) Cast to char *, note that it's ok.
(distribute_hash_alloc) use MTYPE_DISTRIBUTE_IFNAME.
(distribute_get) Cast to char *, note that it's ok.
* filter.c: Update with const qualifier.
* if.{c,h}: ditto.
* if_rmap.{c,h}: ditto.
(if_rmap_lookup) Cast to char *, note that it's ok.
(if_rmap_get) ditto.
* log.{c,h}: Update with const qualifier.
* plist.{c,h}: ditto.
* routemap.{c,h}: ditto.
* smux.{c,h}: ditto. Fix some signed/unsigned comparisons.
* sockopt.c: (getsockopt_cmsg_data) add return for error case.
* vty.c: Update with const qualifier.
2004-10-10 13:56:56 +02:00
|
|
|
void route_map_delete_hook(void (*func)(const char *))
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
route_map_master.delete_hook = func;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-05-09 05:19:55 +02:00
|
|
|
void route_map_event_hook(void (*func)(const char *name))
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
route_map_master.event_hook = func;
|
|
|
|
}
|
|
|
|
|
2015-05-20 02:40:45 +02:00
|
|
|
/* Routines for route map dependency lists and dependency processing */
|
2018-10-17 21:27:12 +02:00
|
|
|
static bool route_map_rmap_hash_cmp(const void *p1, const void *p2)
|
2015-05-20 02:40:45 +02:00
|
|
|
{
|
2019-05-15 09:09:08 +02:00
|
|
|
return strcmp(((const struct route_map_dep_data *)p1)->rname,
|
|
|
|
((const struct route_map_dep_data *)p2)->rname)
|
|
|
|
== 0;
|
2015-05-20 02:40:45 +02:00
|
|
|
}
|
|
|
|
|
2018-10-17 21:27:12 +02:00
|
|
|
static bool route_map_dep_hash_cmp(const void *p1, const void *p2)
|
2015-05-20 02:40:45 +02:00
|
|
|
{
|
|
|
|
|
2015-05-20 03:04:26 +02:00
|
|
|
return (strcmp(((const struct route_map_dep *)p1)->dep_name,
|
|
|
|
(const char *)p2)
|
|
|
|
== 0);
|
2015-05-20 02:40:45 +02:00
|
|
|
}
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
static void route_map_clear_reference(struct hash_bucket *bucket, void *arg)
|
2015-05-20 02:40:45 +02:00
|
|
|
{
|
2019-05-15 09:09:08 +02:00
|
|
|
struct route_map_dep *dep = bucket->data;
|
|
|
|
struct route_map_dep_data *dep_data = NULL, tmp_dep_data;
|
2015-05-20 02:40:45 +02:00
|
|
|
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&tmp_dep_data, 0, sizeof(tmp_dep_data));
|
2020-12-18 04:23:02 +01:00
|
|
|
tmp_dep_data.rname = arg;
|
|
|
|
dep_data = hash_release(dep->dep_rmap_hash, &tmp_dep_data);
|
|
|
|
if (dep_data) {
|
2023-02-17 21:02:14 +01:00
|
|
|
if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP)))
|
2020-12-18 04:25:27 +01:00
|
|
|
zlog_debug("Clearing reference for %s to %s count: %d",
|
|
|
|
dep->dep_name, tmp_dep_data.rname,
|
|
|
|
dep_data->refcnt);
|
|
|
|
|
2020-12-18 04:23:02 +01:00
|
|
|
XFREE(MTYPE_ROUTE_MAP_NAME, dep_data->rname);
|
|
|
|
XFREE(MTYPE_ROUTE_MAP_DEP_DATA, dep_data);
|
|
|
|
}
|
|
|
|
if (!dep->dep_rmap_hash->count) {
|
|
|
|
dep = hash_release(dep->this_hash, (void *)dep->dep_name);
|
|
|
|
hash_free(dep->dep_rmap_hash);
|
|
|
|
XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
|
|
|
|
XFREE(MTYPE_ROUTE_MAP_DEP, dep);
|
2015-05-20 02:40:45 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2015-05-20 02:40:45 +02:00
|
|
|
static void route_map_clear_all_references(char *rmap_name)
|
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
int i;
|
|
|
|
|
2023-02-17 21:02:14 +01:00
|
|
|
if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP)))
|
2020-12-18 04:25:27 +01:00
|
|
|
zlog_debug("Clearing references for %s", rmap_name);
|
|
|
|
|
2015-05-20 02:40:45 +02:00
|
|
|
for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
|
|
|
|
hash_iterate(route_map_dep_hash[i], route_map_clear_reference,
|
|
|
|
(void *)rmap_name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-15 09:09:08 +02:00
|
|
|
static unsigned int route_map_dep_data_hash_make_key(const void *p)
|
|
|
|
{
|
|
|
|
const struct route_map_dep_data *dep_data = p;
|
|
|
|
|
|
|
|
return string_hash_make(dep_data->rname);
|
|
|
|
}
|
|
|
|
|
2015-05-20 02:40:45 +02:00
|
|
|
static void *route_map_dep_hash_alloc(void *p)
|
|
|
|
{
|
|
|
|
char *dep_name = (char *)p;
|
|
|
|
struct route_map_dep *dep_entry;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-05-20 02:40:45 +02:00
|
|
|
dep_entry = XCALLOC(MTYPE_ROUTE_MAP_DEP, sizeof(struct route_map_dep));
|
|
|
|
dep_entry->dep_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
|
2017-09-04 00:50:35 +02:00
|
|
|
dep_entry->dep_rmap_hash =
|
2019-05-15 09:09:08 +02:00
|
|
|
hash_create_size(8, route_map_dep_data_hash_make_key,
|
2017-09-04 00:50:35 +02:00
|
|
|
route_map_rmap_hash_cmp, "Route Map Dep Hash");
|
2015-05-20 02:40:45 +02:00
|
|
|
dep_entry->this_hash = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-05-15 09:09:08 +02:00
|
|
|
return dep_entry;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2015-05-20 02:40:45 +02:00
|
|
|
|
|
|
|
static void *route_map_name_hash_alloc(void *p)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
2019-05-15 09:09:08 +02:00
|
|
|
struct route_map_dep_data *dep_data = NULL, *tmp_dep_data = NULL;
|
|
|
|
|
|
|
|
dep_data = XCALLOC(MTYPE_ROUTE_MAP_DEP_DATA,
|
|
|
|
sizeof(struct route_map_dep_data));
|
|
|
|
tmp_dep_data = p;
|
|
|
|
dep_data->rname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, tmp_dep_data->rname);
|
|
|
|
return dep_data;
|
2015-05-20 02:40:45 +02:00
|
|
|
}
|
|
|
|
|
2019-05-14 22:19:07 +02:00
|
|
|
static unsigned int route_map_dep_hash_make_key(const void *p)
|
2015-05-20 02:40:45 +02:00
|
|
|
{
|
|
|
|
return (string_hash_make((char *)p));
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2015-05-20 02:40:45 +02:00
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
static void route_map_print_dependency(struct hash_bucket *bucket, void *data)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
2019-05-15 09:09:08 +02:00
|
|
|
struct route_map_dep_data *dep_data = bucket->data;
|
|
|
|
char *rmap_name = dep_data->rname;
|
|
|
|
char *dep_name = data;
|
2015-05-20 02:40:45 +02:00
|
|
|
|
2020-03-05 19:17:54 +01:00
|
|
|
zlog_debug("%s: Dependency for %s: %s", __func__, dep_name, rmap_name);
|
2015-05-20 02:40:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int route_map_dep_update(struct hash *dephash, const char *dep_name,
|
|
|
|
const char *rmap_name, route_map_event_t type)
|
|
|
|
{
|
2015-05-20 03:04:26 +02:00
|
|
|
struct route_map_dep *dep = NULL;
|
|
|
|
char *dname, *rname;
|
|
|
|
int ret = 0;
|
2019-05-15 09:09:08 +02:00
|
|
|
struct route_map_dep_data *dep_data = NULL, *ret_dep_data = NULL;
|
|
|
|
struct route_map_dep_data tmp_dep_data;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-05-20 03:04:26 +02:00
|
|
|
dname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
|
|
|
|
rname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_name);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-05-20 02:40:45 +02:00
|
|
|
switch (type) {
|
|
|
|
case RMAP_EVENT_PLIST_ADDED:
|
|
|
|
case RMAP_EVENT_CLIST_ADDED:
|
|
|
|
case RMAP_EVENT_ECLIST_ADDED:
|
|
|
|
case RMAP_EVENT_ASLIST_ADDED:
|
2016-11-15 11:00:39 +01:00
|
|
|
case RMAP_EVENT_LLIST_ADDED:
|
2015-05-20 02:40:45 +02:00
|
|
|
case RMAP_EVENT_CALL_ADDED:
|
|
|
|
case RMAP_EVENT_FILTER_ADDED:
|
2023-02-17 21:02:14 +01:00
|
|
|
if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP)))
|
2019-05-10 00:34:52 +02:00
|
|
|
zlog_debug("Adding dependency for filter %s in route-map %s",
|
|
|
|
dep_name, rmap_name);
|
2015-05-20 03:04:26 +02:00
|
|
|
dep = (struct route_map_dep *)hash_get(
|
|
|
|
dephash, dname, route_map_dep_hash_alloc);
|
|
|
|
if (!dep) {
|
|
|
|
ret = -1;
|
|
|
|
goto out;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2015-05-20 02:40:45 +02:00
|
|
|
if (!dep->this_hash)
|
|
|
|
dep->this_hash = dephash;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&tmp_dep_data, 0, sizeof(tmp_dep_data));
|
2019-05-15 09:09:08 +02:00
|
|
|
tmp_dep_data.rname = rname;
|
|
|
|
dep_data = hash_lookup(dep->dep_rmap_hash, &tmp_dep_data);
|
|
|
|
if (!dep_data)
|
|
|
|
dep_data = hash_get(dep->dep_rmap_hash, &tmp_dep_data,
|
|
|
|
route_map_name_hash_alloc);
|
|
|
|
|
|
|
|
dep_data->refcnt++;
|
2017-07-17 14:03:14 +02:00
|
|
|
break;
|
2015-05-20 02:40:45 +02:00
|
|
|
case RMAP_EVENT_PLIST_DELETED:
|
|
|
|
case RMAP_EVENT_CLIST_DELETED:
|
|
|
|
case RMAP_EVENT_ECLIST_DELETED:
|
|
|
|
case RMAP_EVENT_ASLIST_DELETED:
|
2016-11-15 11:00:39 +01:00
|
|
|
case RMAP_EVENT_LLIST_DELETED:
|
2015-05-20 02:40:45 +02:00
|
|
|
case RMAP_EVENT_CALL_DELETED:
|
|
|
|
case RMAP_EVENT_FILTER_DELETED:
|
2023-02-17 21:02:14 +01:00
|
|
|
if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP)))
|
2019-05-10 00:34:52 +02:00
|
|
|
zlog_debug("Deleting dependency for filter %s in route-map %s",
|
|
|
|
dep_name, rmap_name);
|
2015-05-20 03:04:26 +02:00
|
|
|
dep = (struct route_map_dep *)hash_get(dephash, dname, NULL);
|
|
|
|
if (!dep) {
|
|
|
|
goto out;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&tmp_dep_data, 0, sizeof(tmp_dep_data));
|
2019-05-15 09:09:08 +02:00
|
|
|
tmp_dep_data.rname = rname;
|
|
|
|
dep_data = hash_lookup(dep->dep_rmap_hash, &tmp_dep_data);
|
2020-12-18 20:38:40 +01:00
|
|
|
/*
|
|
|
|
* If dep_data is NULL then something has gone seriously
|
|
|
|
* wrong in route-map handling. Note it and prevent
|
|
|
|
* the crash.
|
|
|
|
*/
|
|
|
|
if (!dep_data) {
|
|
|
|
zlog_warn(
|
|
|
|
"route-map dependency for route-map %s: %s is not correct",
|
|
|
|
rmap_name, dep_name);
|
lib: Make sure route_map_dep_data is not NULL before decrementing refcount
```
2 0x00007fb9adb07a10 in core_handler (signo=11, siginfo=0x7ffe1414a630, context=<optimized out>) at lib/sigevent.c:228
sa_default = {__sigaction_handler = {sa_handler = 0x0, sa_sigaction = 0x0}, sa_mask = {__val = {0 <repeats 16 times>}}, sa_flags = 0, sa_restorer = 0x0}
sigset = {__val = {8192, 0 <repeats 15 times>}}
3 <signal handler called>
No locals.
4 route_map_dep_update (type=RMAP_EVENT_CLIST_DELETED, rmap_name=0x55d807ddd410 "export4-as49917", dep_name=<optimized out>, dephash=0x55d807adf170) at lib/routemap.c:2750
dep = 0x55d807d35b00
dname = 0x55d8081ba560 "123:124"
rname = 0x55d8081ba540 "export4-as49917"
ret = 0
dep_data = 0x0
ret_dep_data = 0x0
tmp_dep_data = {rname = 0x55d8081ba540 "export4-as49917", refcnt = 0}
5 route_map_upd8_dependency (type=RMAP_EVENT_CLIST_DELETED, arg=<optimized out>, rmap_name=0x55d807ddd410 "export4-as49917") at lib/routemap.c:2865
upd8_hash = 0x55d807adf170
```
Signed-off-by: Donatas Abraitis <donatas.abraitis@gmail.com>
2020-06-08 13:58:53 +02:00
|
|
|
goto out;
|
2020-12-18 20:38:40 +01:00
|
|
|
}
|
lib: Make sure route_map_dep_data is not NULL before decrementing refcount
```
2 0x00007fb9adb07a10 in core_handler (signo=11, siginfo=0x7ffe1414a630, context=<optimized out>) at lib/sigevent.c:228
sa_default = {__sigaction_handler = {sa_handler = 0x0, sa_sigaction = 0x0}, sa_mask = {__val = {0 <repeats 16 times>}}, sa_flags = 0, sa_restorer = 0x0}
sigset = {__val = {8192, 0 <repeats 15 times>}}
3 <signal handler called>
No locals.
4 route_map_dep_update (type=RMAP_EVENT_CLIST_DELETED, rmap_name=0x55d807ddd410 "export4-as49917", dep_name=<optimized out>, dephash=0x55d807adf170) at lib/routemap.c:2750
dep = 0x55d807d35b00
dname = 0x55d8081ba560 "123:124"
rname = 0x55d8081ba540 "export4-as49917"
ret = 0
dep_data = 0x0
ret_dep_data = 0x0
tmp_dep_data = {rname = 0x55d8081ba540 "export4-as49917", refcnt = 0}
5 route_map_upd8_dependency (type=RMAP_EVENT_CLIST_DELETED, arg=<optimized out>, rmap_name=0x55d807ddd410 "export4-as49917") at lib/routemap.c:2865
upd8_hash = 0x55d807adf170
```
Signed-off-by: Donatas Abraitis <donatas.abraitis@gmail.com>
2020-06-08 13:58:53 +02:00
|
|
|
|
2020-12-18 20:38:40 +01:00
|
|
|
dep_data->refcnt--;
|
2019-05-15 09:09:08 +02:00
|
|
|
|
|
|
|
if (!dep_data->refcnt) {
|
|
|
|
ret_dep_data = hash_release(dep->dep_rmap_hash,
|
|
|
|
&tmp_dep_data);
|
|
|
|
if (ret_dep_data) {
|
|
|
|
XFREE(MTYPE_ROUTE_MAP_NAME,
|
|
|
|
ret_dep_data->rname);
|
|
|
|
XFREE(MTYPE_ROUTE_MAP_DEP_DATA, ret_dep_data);
|
|
|
|
}
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-05-20 03:04:26 +02:00
|
|
|
if (!dep->dep_rmap_hash->count) {
|
|
|
|
dep = hash_release(dephash, dname);
|
2015-05-20 02:40:45 +02:00
|
|
|
hash_free(dep->dep_rmap_hash);
|
|
|
|
XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
|
|
|
|
XFREE(MTYPE_ROUTE_MAP_DEP, dep);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
break;
|
2019-05-09 05:00:52 +02:00
|
|
|
case RMAP_EVENT_SET_ADDED:
|
|
|
|
case RMAP_EVENT_SET_DELETED:
|
|
|
|
case RMAP_EVENT_SET_REPLACED:
|
|
|
|
case RMAP_EVENT_MATCH_ADDED:
|
|
|
|
case RMAP_EVENT_MATCH_DELETED:
|
|
|
|
case RMAP_EVENT_MATCH_REPLACED:
|
|
|
|
case RMAP_EVENT_INDEX_ADDED:
|
|
|
|
case RMAP_EVENT_INDEX_DELETED:
|
2017-07-17 14:03:14 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-05-20 03:04:26 +02:00
|
|
|
if (dep) {
|
2023-02-13 15:06:56 +01:00
|
|
|
if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP))
|
2015-05-20 03:04:26 +02:00
|
|
|
hash_iterate(dep->dep_rmap_hash,
|
|
|
|
route_map_print_dependency, dname);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
2015-05-20 03:04:26 +02:00
|
|
|
XFREE(MTYPE_ROUTE_MAP_NAME, rname);
|
|
|
|
XFREE(MTYPE_ROUTE_MAP_NAME, dname);
|
|
|
|
return ret;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2015-05-20 02:40:45 +02:00
|
|
|
static struct hash *route_map_get_dep_hash(route_map_event_t event)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
2015-05-20 02:40:45 +02:00
|
|
|
struct hash *upd8_hash = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-05-20 02:40:45 +02:00
|
|
|
switch (event) {
|
|
|
|
case RMAP_EVENT_PLIST_ADDED:
|
|
|
|
case RMAP_EVENT_PLIST_DELETED:
|
|
|
|
upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_PLIST];
|
2017-07-17 14:03:14 +02:00
|
|
|
break;
|
2015-05-20 02:40:45 +02:00
|
|
|
case RMAP_EVENT_CLIST_ADDED:
|
|
|
|
case RMAP_EVENT_CLIST_DELETED:
|
|
|
|
upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_CLIST];
|
2017-07-17 14:03:14 +02:00
|
|
|
break;
|
2015-05-20 02:40:45 +02:00
|
|
|
case RMAP_EVENT_ECLIST_ADDED:
|
|
|
|
case RMAP_EVENT_ECLIST_DELETED:
|
|
|
|
upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ECLIST];
|
2017-07-17 14:03:14 +02:00
|
|
|
break;
|
2015-05-20 02:40:45 +02:00
|
|
|
case RMAP_EVENT_ASLIST_ADDED:
|
|
|
|
case RMAP_EVENT_ASLIST_DELETED:
|
|
|
|
upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ASPATH];
|
2017-07-17 14:03:14 +02:00
|
|
|
break;
|
2016-11-15 11:00:39 +01:00
|
|
|
case RMAP_EVENT_LLIST_ADDED:
|
|
|
|
case RMAP_EVENT_LLIST_DELETED:
|
|
|
|
upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_LCLIST];
|
2017-07-17 14:03:14 +02:00
|
|
|
break;
|
2015-05-20 02:40:45 +02:00
|
|
|
case RMAP_EVENT_CALL_ADDED:
|
|
|
|
case RMAP_EVENT_CALL_DELETED:
|
2019-05-09 05:53:35 +02:00
|
|
|
case RMAP_EVENT_MATCH_ADDED:
|
|
|
|
case RMAP_EVENT_MATCH_DELETED:
|
2015-05-20 02:40:45 +02:00
|
|
|
upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_RMAP];
|
2017-07-17 14:03:14 +02:00
|
|
|
break;
|
2015-05-20 02:40:45 +02:00
|
|
|
case RMAP_EVENT_FILTER_ADDED:
|
|
|
|
case RMAP_EVENT_FILTER_DELETED:
|
|
|
|
upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_FILTER];
|
2017-07-17 14:03:14 +02:00
|
|
|
break;
|
2019-05-09 05:00:52 +02:00
|
|
|
/*
|
|
|
|
* Should we actually be ignoring these?
|
|
|
|
* I am not sure but at this point in time, let
|
|
|
|
* us get them into this switch and we can peel
|
|
|
|
* them into the appropriate place in the future
|
|
|
|
*/
|
|
|
|
case RMAP_EVENT_SET_ADDED:
|
|
|
|
case RMAP_EVENT_SET_DELETED:
|
|
|
|
case RMAP_EVENT_SET_REPLACED:
|
|
|
|
case RMAP_EVENT_MATCH_REPLACED:
|
|
|
|
case RMAP_EVENT_INDEX_ADDED:
|
|
|
|
case RMAP_EVENT_INDEX_DELETED:
|
2015-05-20 02:40:45 +02:00
|
|
|
upd8_hash = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
break;
|
|
|
|
}
|
2015-05-20 02:40:45 +02:00
|
|
|
return (upd8_hash);
|
|
|
|
}
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
static void route_map_process_dependency(struct hash_bucket *bucket, void *data)
|
2015-05-20 02:40:45 +02:00
|
|
|
{
|
2019-05-15 09:09:08 +02:00
|
|
|
struct route_map_dep_data *dep_data = NULL;
|
|
|
|
char *rmap_name = NULL;
|
|
|
|
|
|
|
|
dep_data = bucket->data;
|
|
|
|
rmap_name = dep_data->rname;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2023-02-17 21:02:14 +01:00
|
|
|
if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP)))
|
2019-05-10 00:34:52 +02:00
|
|
|
zlog_debug("Notifying %s of dependency", rmap_name);
|
2018-08-15 21:54:14 +02:00
|
|
|
if (route_map_master.event_hook)
|
2019-05-09 05:19:55 +02:00
|
|
|
(*route_map_master.event_hook)(rmap_name);
|
2015-05-20 02:40:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void route_map_upd8_dependency(route_map_event_t type, const char *arg,
|
|
|
|
const char *rmap_name)
|
|
|
|
{
|
|
|
|
struct hash *upd8_hash = NULL;
|
|
|
|
|
2018-09-21 06:15:49 +02:00
|
|
|
if ((upd8_hash = route_map_get_dep_hash(type))) {
|
2015-05-20 02:40:45 +02:00
|
|
|
route_map_dep_update(upd8_hash, arg, rmap_name, type);
|
2018-09-21 06:15:49 +02:00
|
|
|
|
|
|
|
if (type == RMAP_EVENT_CALL_ADDED) {
|
|
|
|
/* Execute hook. */
|
|
|
|
if (route_map_master.add_hook)
|
|
|
|
(*route_map_master.add_hook)(rmap_name);
|
|
|
|
} else if (type == RMAP_EVENT_CALL_DELETED) {
|
|
|
|
/* Execute hook. */
|
|
|
|
if (route_map_master.delete_hook)
|
|
|
|
(*route_map_master.delete_hook)(rmap_name);
|
|
|
|
}
|
|
|
|
}
|
2015-05-20 02:40:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void route_map_notify_dependencies(const char *affected_name,
|
|
|
|
route_map_event_t event)
|
|
|
|
{
|
2016-05-07 21:42:51 +02:00
|
|
|
struct route_map_dep *dep;
|
2015-05-20 02:40:45 +02:00
|
|
|
struct hash *upd8_hash;
|
2015-05-20 03:04:26 +02:00
|
|
|
char *name;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-05-20 03:04:26 +02:00
|
|
|
if (!affected_name)
|
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-05-20 03:04:26 +02:00
|
|
|
name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, affected_name);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-05-20 03:04:26 +02:00
|
|
|
if ((upd8_hash = route_map_get_dep_hash(event)) == NULL) {
|
2015-05-20 02:40:45 +02:00
|
|
|
XFREE(MTYPE_ROUTE_MAP_NAME, name);
|
|
|
|
return;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-05-20 03:04:26 +02:00
|
|
|
dep = (struct route_map_dep *)hash_get(upd8_hash, name, NULL);
|
2015-05-20 02:40:45 +02:00
|
|
|
if (dep) {
|
|
|
|
if (!dep->this_hash)
|
2016-11-15 11:00:39 +01:00
|
|
|
dep->this_hash = upd8_hash;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2023-02-17 21:02:14 +01:00
|
|
|
if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP)))
|
2019-05-10 00:34:52 +02:00
|
|
|
zlog_debug("Filter %s updated", dep->dep_name);
|
2015-05-20 02:40:45 +02:00
|
|
|
hash_iterate(dep->dep_rmap_hash, route_map_process_dependency,
|
|
|
|
(void *)event);
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-05-20 03:04:26 +02:00
|
|
|
XFREE(MTYPE_ROUTE_MAP_NAME, name);
|
2015-05-20 02:40:45 +02:00
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* VTY related functions. */
|
2019-06-20 20:10:44 +02:00
|
|
|
static void clear_route_map_helper(struct route_map *map)
|
|
|
|
{
|
|
|
|
struct route_map_index *index;
|
|
|
|
|
|
|
|
map->applied_clear = map->applied;
|
2022-10-10 16:56:51 +02:00
|
|
|
map->cputime = 0;
|
|
|
|
for (index = map->head; index; index = index->next) {
|
2019-06-20 20:10:44 +02:00
|
|
|
index->applied_clear = index->applied;
|
2022-10-10 16:56:51 +02:00
|
|
|
index->cputime = 0;
|
|
|
|
}
|
2019-06-20 20:10:44 +02:00
|
|
|
}
|
|
|
|
|
2023-03-20 13:15:03 +01:00
|
|
|
DEFPY (rmap_clear_counters,
|
2019-06-20 20:10:44 +02:00
|
|
|
rmap_clear_counters_cmd,
|
2023-03-20 13:15:03 +01:00
|
|
|
"clear route-map counters [RMAP_NAME$rmapname]",
|
2019-06-20 20:10:44 +02:00
|
|
|
CLEAR_STR
|
|
|
|
"route-map information\n"
|
|
|
|
"counters associated with the specified route-map\n"
|
|
|
|
"route-map name\n")
|
|
|
|
{
|
|
|
|
struct route_map *map;
|
|
|
|
|
2023-03-20 13:15:03 +01:00
|
|
|
if (rmapname) {
|
|
|
|
map = route_map_lookup_by_name(rmapname);
|
2019-06-20 20:10:44 +02:00
|
|
|
|
|
|
|
if (map)
|
|
|
|
clear_route_map_helper(map);
|
|
|
|
else {
|
|
|
|
vty_out(vty, "%s: 'route-map %s' not found\n",
|
2023-03-20 13:15:03 +01:00
|
|
|
frr_protonameinst, rmapname);
|
2019-06-20 20:10:44 +02:00
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (map = route_map_master.head; map; map = map->next)
|
|
|
|
clear_route_map_helper(map);
|
|
|
|
}
|
|
|
|
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
|
|
|
|
}
|
2004-07-09 16:00:01 +02:00
|
|
|
|
2023-11-20 21:32:19 +01:00
|
|
|
DEFUN_NOSH (rmap_show_name,
|
|
|
|
rmap_show_name_cmd,
|
|
|
|
"show route-map [WORD] [json]",
|
|
|
|
SHOW_STR
|
|
|
|
"route-map information\n"
|
|
|
|
"route-map name\n"
|
|
|
|
JSON_STR)
|
2004-07-09 16:00:01 +02:00
|
|
|
{
|
2021-08-02 20:38:26 +02:00
|
|
|
bool uj = use_json(argc, argv);
|
|
|
|
int idx = 0;
|
|
|
|
const char *name = NULL;
|
|
|
|
|
|
|
|
if (argv_find(argv, argc, "WORD", &idx))
|
|
|
|
name = argv[idx]->arg;
|
|
|
|
|
|
|
|
return vty_show_route_map(vty, name, uj);
|
2004-07-09 16:00:01 +02:00
|
|
|
}
|
|
|
|
|
2018-12-20 16:56:21 +01:00
|
|
|
DEFUN (rmap_show_unused,
|
|
|
|
rmap_show_unused_cmd,
|
|
|
|
"show route-map-unused",
|
|
|
|
SHOW_STR
|
|
|
|
"unused route-map information\n")
|
|
|
|
{
|
|
|
|
return vty_show_unused_route_map(vty);
|
|
|
|
}
|
|
|
|
|
2023-02-13 15:14:56 +01:00
|
|
|
DEFPY (debug_rmap,
|
2019-05-10 00:34:52 +02:00
|
|
|
debug_rmap_cmd,
|
2023-02-13 15:14:56 +01:00
|
|
|
"debug route-map [detail]$detail",
|
2019-05-10 00:34:52 +02:00
|
|
|
DEBUG_STR
|
2023-02-13 15:14:56 +01:00
|
|
|
"Debug option set for route-maps\n"
|
|
|
|
"Detailed output\n")
|
2019-05-10 00:34:52 +02:00
|
|
|
{
|
2023-02-13 15:14:56 +01:00
|
|
|
if (!detail)
|
|
|
|
SET_FLAG(rmap_debug, DEBUG_ROUTEMAP);
|
|
|
|
else
|
|
|
|
SET_FLAG(rmap_debug, DEBUG_ROUTEMAP | DEBUG_ROUTEMAP_DETAIL);
|
|
|
|
|
2019-05-10 00:34:52 +02:00
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2023-02-13 15:14:56 +01:00
|
|
|
DEFPY (no_debug_rmap,
|
2019-05-10 00:34:52 +02:00
|
|
|
no_debug_rmap_cmd,
|
2023-02-13 15:14:56 +01:00
|
|
|
"no debug route-map [detail]$detail",
|
2019-05-10 00:34:52 +02:00
|
|
|
NO_STR
|
|
|
|
DEBUG_STR
|
2023-02-13 15:14:56 +01:00
|
|
|
"Debug option set for route-maps\n"
|
|
|
|
"Detailed output\n")
|
2019-05-10 00:34:52 +02:00
|
|
|
{
|
2023-02-13 15:14:56 +01:00
|
|
|
if (!detail)
|
|
|
|
UNSET_FLAG(rmap_debug, DEBUG_ROUTEMAP);
|
|
|
|
else
|
|
|
|
UNSET_FLAG(rmap_debug, DEBUG_ROUTEMAP | DEBUG_ROUTEMAP_DETAIL);
|
|
|
|
|
2019-05-10 00:34:52 +02:00
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Debug node. */
|
2018-09-08 22:31:43 +02:00
|
|
|
static int rmap_config_write_debug(struct vty *vty);
|
2018-09-08 21:46:23 +02:00
|
|
|
static struct cmd_node rmap_debug_node = {
|
2018-09-09 00:15:50 +02:00
|
|
|
.name = "route-map debug",
|
2018-09-08 21:46:23 +02:00
|
|
|
.node = RMAP_DEBUG_NODE,
|
|
|
|
.prompt = "",
|
2018-09-08 22:31:43 +02:00
|
|
|
.config_write = rmap_config_write_debug,
|
2018-09-08 21:46:23 +02:00
|
|
|
};
|
2019-05-10 00:34:52 +02:00
|
|
|
|
2022-10-07 13:51:17 +02:00
|
|
|
void route_map_show_debug(struct vty *vty)
|
|
|
|
{
|
2023-02-13 15:06:56 +01:00
|
|
|
if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP))
|
2022-10-07 13:51:17 +02:00
|
|
|
vty_out(vty, "debug route-map\n");
|
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Configuration write function. */
|
2019-05-10 00:34:52 +02:00
|
|
|
static int rmap_config_write_debug(struct vty *vty)
|
|
|
|
{
|
|
|
|
int write = 0;
|
|
|
|
|
2023-02-13 15:06:56 +01:00
|
|
|
if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP)) {
|
2019-05-10 00:34:52 +02:00
|
|
|
vty_out(vty, "debug route-map\n");
|
|
|
|
write++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return write;
|
|
|
|
}
|
|
|
|
|
2016-10-01 20:42:34 +02:00
|
|
|
/* Common route map rules */
|
|
|
|
|
|
|
|
void *route_map_rule_tag_compile(const char *arg)
|
|
|
|
{
|
|
|
|
unsigned long int tmp;
|
|
|
|
char *endptr;
|
|
|
|
route_tag_t *tag;
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
tmp = strtoul(arg, &endptr, 0);
|
|
|
|
if (arg[0] == '\0' || *endptr != '\0' || errno || tmp > ROUTE_TAG_MAX)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
tag = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*tag));
|
|
|
|
*tag = tmp;
|
|
|
|
|
|
|
|
return tag;
|
|
|
|
}
|
|
|
|
|
|
|
|
void route_map_rule_tag_free(void *rule)
|
|
|
|
{
|
|
|
|
XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
|
|
|
|
}
|
|
|
|
|
2016-10-19 17:09:57 +02:00
|
|
|
void route_map_finish(void)
|
|
|
|
{
|
|
|
|
int i;
|
2021-11-06 16:57:52 +01:00
|
|
|
struct route_map_rule_cmd_proxy *proxy;
|
|
|
|
|
|
|
|
/* these 2 hash tables have INIT_HASH initializers, so the "default"
|
|
|
|
* state is "initialized & empty" => fini() followed by init() to
|
|
|
|
* return to that same state
|
|
|
|
*/
|
|
|
|
while ((proxy = rmap_cmd_name_pop(rmap_match_cmds)))
|
|
|
|
(void)proxy;
|
|
|
|
rmap_cmd_name_fini(rmap_match_cmds);
|
|
|
|
rmap_cmd_name_init(rmap_match_cmds);
|
2016-10-19 17:09:57 +02:00
|
|
|
|
2021-11-06 16:57:52 +01:00
|
|
|
while ((proxy = rmap_cmd_name_pop(rmap_set_cmds)))
|
|
|
|
(void)proxy;
|
|
|
|
rmap_cmd_name_fini(rmap_set_cmds);
|
|
|
|
rmap_cmd_name_init(rmap_set_cmds);
|
2016-10-19 17:09:57 +02:00
|
|
|
|
2018-08-03 14:18:11 +02:00
|
|
|
/*
|
|
|
|
* All protocols are setting these to NULL
|
|
|
|
* by default on shutdown( route_map_finish )
|
|
|
|
* Why are we making them do this work?
|
|
|
|
*/
|
|
|
|
route_map_master.add_hook = NULL;
|
|
|
|
route_map_master.delete_hook = NULL;
|
|
|
|
route_map_master.event_hook = NULL;
|
|
|
|
|
2016-10-19 17:09:57 +02:00
|
|
|
/* cleanup route_map */
|
|
|
|
while (route_map_master.head) {
|
2016-10-24 19:28:35 +02:00
|
|
|
struct route_map *map = route_map_master.head;
|
2018-04-29 01:52:41 +02:00
|
|
|
map->to_be_processed = false;
|
2016-10-24 19:28:35 +02:00
|
|
|
route_map_delete(map);
|
|
|
|
}
|
2016-10-19 17:09:57 +02:00
|
|
|
|
|
|
|
for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
|
2016-12-16 02:39:46 +01:00
|
|
|
hash_free(route_map_dep_hash[i]);
|
|
|
|
route_map_dep_hash[i] = NULL;
|
|
|
|
}
|
2016-10-19 17:09:57 +02:00
|
|
|
|
|
|
|
hash_free(route_map_master_hash);
|
2016-12-16 02:39:46 +01:00
|
|
|
route_map_master_hash = NULL;
|
2016-10-19 17:09:57 +02:00
|
|
|
}
|
|
|
|
|
2018-12-20 16:56:21 +01:00
|
|
|
/* Increment the use_count counter while attaching the route map */
|
|
|
|
void route_map_counter_increment(struct route_map *map)
|
|
|
|
{
|
|
|
|
if (map)
|
|
|
|
map->use_count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Decrement the use_count counter while detaching the route map. */
|
|
|
|
void route_map_counter_decrement(struct route_map *map)
|
|
|
|
{
|
|
|
|
if (map) {
|
|
|
|
if (map->use_count <= 0)
|
|
|
|
return;
|
|
|
|
map->use_count--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-20 07:57:09 +01:00
|
|
|
DEFUN_HIDDEN(show_route_map_pfx_tbl, show_route_map_pfx_tbl_cmd,
|
2022-06-13 11:18:36 +02:00
|
|
|
"show route-map RMAP_NAME prefix-table",
|
2019-12-20 07:57:09 +01:00
|
|
|
SHOW_STR
|
|
|
|
"route-map\n"
|
|
|
|
"route-map name\n"
|
|
|
|
"internal prefix-table\n")
|
|
|
|
{
|
|
|
|
const char *rmap_name = argv[2]->arg;
|
|
|
|
struct route_map *rmap = NULL;
|
|
|
|
struct route_table *rm_pfx_tbl4 = NULL;
|
|
|
|
struct route_table *rm_pfx_tbl6 = NULL;
|
|
|
|
struct route_node *rn = NULL, *prn = NULL;
|
|
|
|
struct list *rmap_index_list = NULL;
|
|
|
|
struct listnode *ln = NULL, *nln = NULL;
|
|
|
|
struct route_map_index *index = NULL;
|
|
|
|
uint8_t len = 54;
|
|
|
|
|
|
|
|
vty_out(vty, "%s:\n", frr_protonameinst);
|
|
|
|
rmap = route_map_lookup_by_name(rmap_name);
|
|
|
|
if (rmap) {
|
|
|
|
rm_pfx_tbl4 = rmap->ipv4_prefix_table;
|
|
|
|
if (rm_pfx_tbl4) {
|
|
|
|
vty_out(vty, "\n%s%43s%s\n", "IPv4 Prefix", "",
|
|
|
|
"Route-map Index List");
|
|
|
|
vty_out(vty, "%s%39s%s\n", "_______________", "",
|
|
|
|
"____________________");
|
|
|
|
for (rn = route_top(rm_pfx_tbl4); rn;
|
|
|
|
rn = route_next(rn)) {
|
2020-10-14 18:57:14 +02:00
|
|
|
vty_out(vty, " %pRN (%d)\n", rn,
|
2020-10-14 18:44:23 +02:00
|
|
|
route_node_get_lock_count(rn));
|
2019-12-20 07:57:09 +01:00
|
|
|
|
|
|
|
vty_out(vty, "(P) ");
|
|
|
|
prn = rn->parent;
|
|
|
|
if (prn) {
|
2020-10-14 18:57:14 +02:00
|
|
|
vty_out(vty, "%pRN\n", prn);
|
2019-12-20 07:57:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
rmap_index_list = (struct list *)rn->info;
|
|
|
|
if (!rmap_index_list
|
|
|
|
|| !listcount(rmap_index_list))
|
|
|
|
vty_out(vty, "%*s%s\n", len, "", "-");
|
|
|
|
else
|
|
|
|
for (ALL_LIST_ELEMENTS(rmap_index_list,
|
|
|
|
ln, nln,
|
|
|
|
index)) {
|
|
|
|
vty_out(vty, "%*s%s seq %d\n",
|
|
|
|
len, "",
|
|
|
|
index->map->name,
|
|
|
|
index->pref);
|
|
|
|
}
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rm_pfx_tbl6 = rmap->ipv6_prefix_table;
|
|
|
|
if (rm_pfx_tbl6) {
|
|
|
|
vty_out(vty, "\n%s%43s%s\n", "IPv6 Prefix", "",
|
|
|
|
"Route-map Index List");
|
|
|
|
vty_out(vty, "%s%39s%s\n", "_______________", "",
|
|
|
|
"____________________");
|
|
|
|
for (rn = route_top(rm_pfx_tbl6); rn;
|
|
|
|
rn = route_next(rn)) {
|
2020-10-14 18:57:14 +02:00
|
|
|
vty_out(vty, " %pRN (%d)\n", rn,
|
2020-10-14 18:44:23 +02:00
|
|
|
route_node_get_lock_count(rn));
|
2019-12-20 07:57:09 +01:00
|
|
|
|
|
|
|
vty_out(vty, "(P) ");
|
|
|
|
prn = rn->parent;
|
|
|
|
if (prn) {
|
2020-10-14 18:57:14 +02:00
|
|
|
vty_out(vty, "%pRN\n", prn);
|
2019-12-20 07:57:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
rmap_index_list = (struct list *)rn->info;
|
|
|
|
if (!rmap_index_list
|
|
|
|
|| !listcount(rmap_index_list))
|
|
|
|
vty_out(vty, "%*s%s\n", len, "", "-");
|
|
|
|
else
|
|
|
|
for (ALL_LIST_ELEMENTS(rmap_index_list,
|
|
|
|
ln, nln,
|
|
|
|
index)) {
|
|
|
|
vty_out(vty, "%*s%s seq %d\n",
|
|
|
|
len, "",
|
|
|
|
index->map->name,
|
|
|
|
index->pref);
|
|
|
|
}
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Initialization of route map vector. */
|
2024-01-24 16:59:14 +01:00
|
|
|
void route_map_init_new(bool in_backend)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2016-10-19 16:55:01 +02:00
|
|
|
int i;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-06-20 00:49:44 +02:00
|
|
|
route_map_master_hash =
|
2017-09-04 00:50:35 +02:00
|
|
|
hash_create_size(8, route_map_hash_key_make, route_map_hash_cmp,
|
|
|
|
"Route Map Master Hash");
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-10-19 16:55:01 +02:00
|
|
|
for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
|
|
|
|
route_map_dep_hash[i] = hash_create_size(
|
2017-09-04 00:50:35 +02:00
|
|
|
8, route_map_dep_hash_make_key, route_map_dep_hash_cmp,
|
|
|
|
"Route Map Dep Hash");
|
2016-10-19 16:55:01 +02:00
|
|
|
|
2023-02-13 15:06:56 +01:00
|
|
|
UNSET_FLAG(rmap_debug, DEBUG_ROUTEMAP);
|
2019-05-10 00:34:52 +02:00
|
|
|
|
2024-01-24 16:59:14 +01:00
|
|
|
if (!in_backend) {
|
|
|
|
/* we do not want to handle config commands in the backend */
|
|
|
|
route_map_cli_init();
|
|
|
|
}
|
2015-05-20 02:40:45 +02:00
|
|
|
|
2019-09-30 20:01:46 +02:00
|
|
|
/* Install route map top node. */
|
2018-09-08 22:31:43 +02:00
|
|
|
install_node(&rmap_debug_node);
|
2019-05-10 00:34:52 +02:00
|
|
|
|
2016-11-19 11:57:08 +01:00
|
|
|
/* Install route map commands. */
|
2019-05-10 00:34:52 +02:00
|
|
|
install_element(CONFIG_NODE, &debug_rmap_cmd);
|
|
|
|
install_element(CONFIG_NODE, &no_debug_rmap_cmd);
|
|
|
|
|
2016-10-06 21:56:13 +02:00
|
|
|
/* Install show command */
|
2019-06-20 20:10:44 +02:00
|
|
|
install_element(ENABLE_NODE, &rmap_clear_counters_cmd);
|
|
|
|
|
2016-10-06 21:56:13 +02:00
|
|
|
install_element(ENABLE_NODE, &rmap_show_name_cmd);
|
2018-12-20 16:56:21 +01:00
|
|
|
install_element(ENABLE_NODE, &rmap_show_unused_cmd);
|
2016-10-06 21:56:13 +02:00
|
|
|
|
2019-05-10 00:34:52 +02:00
|
|
|
install_element(ENABLE_NODE, &debug_rmap_cmd);
|
|
|
|
install_element(ENABLE_NODE, &no_debug_rmap_cmd);
|
2019-11-02 03:42:20 +01:00
|
|
|
|
2019-12-20 07:57:09 +01:00
|
|
|
install_element(ENABLE_NODE, &show_route_map_pfx_tbl_cmd);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2024-01-24 16:59:14 +01:00
|
|
|
|
|
|
|
void route_map_init(void)
|
|
|
|
{
|
|
|
|
route_map_init_new(false);
|
|
|
|
}
|