diff options
author | Neale Ranns <neale.ranns@cisco.com> | 2020-11-26 08:37:27 +0000 |
---|---|---|
committer | Ole Tr�an <otroan@employees.org> | 2020-12-08 09:00:24 +0000 |
commit | e2fe097424fb169dfe01421ff17b8ccd0c26b4a6 (patch) | |
tree | 2d9993f78d9165c1aba23b1daa4067106da81b45 /src/vnet/fib | |
parent | 9b8cb5082471dd670066b8ba2872ffbcc35a87f8 (diff) |
fib: Source Address Selection
Type: feature
Use the FIB to provide SAS (in so far as it is today)
- Use the glean adjacency as the record of the connected prefixes
= there's a glean per-{interface, protocol, connected-prefix}
- Keep the glean up to date with whatever the recieve host prefix is
(since it can change)
Signed-off-by: Neale Ranns <neale.ranns@cisco.com>
Change-Id: I0f3dd1edb1f3fc965af1c7c586709028eb9cdeac
Diffstat (limited to 'src/vnet/fib')
-rw-r--r-- | src/vnet/fib/fib_entry_src.c | 5 | ||||
-rw-r--r-- | src/vnet/fib/fib_entry_src.h | 2 | ||||
-rw-r--r-- | src/vnet/fib/fib_entry_src_interface.c | 88 | ||||
-rw-r--r-- | src/vnet/fib/fib_path.c | 16 | ||||
-rw-r--r-- | src/vnet/fib/fib_path.h | 10 | ||||
-rw-r--r-- | src/vnet/fib/fib_sas.c | 121 | ||||
-rw-r--r-- | src/vnet/fib/fib_sas.h | 75 | ||||
-rw-r--r-- | src/vnet/fib/fib_table.c | 11 | ||||
-rw-r--r-- | src/vnet/fib/fib_types.c | 19 | ||||
-rw-r--r-- | src/vnet/fib/fib_types.h | 16 |
10 files changed, 329 insertions, 34 deletions
diff --git a/src/vnet/fib/fib_entry_src.c b/src/vnet/fib/fib_entry_src.c index ad8b23e4af1..7f4db6a071b 100644 --- a/src/vnet/fib/fib_entry_src.c +++ b/src/vnet/fib/fib_entry_src.c @@ -127,7 +127,7 @@ fib_entry_src_find_i (const fib_entry_t *fib_entry, return (NULL); } -static fib_entry_src_t * +fib_entry_src_t * fib_entry_src_find (const fib_entry_t *fib_entry, fib_source_t source) @@ -1491,7 +1491,8 @@ fib_path_is_attached (const fib_route_path_t *rpath) { return (!0); } - else if (rpath->frp_flags & FIB_ROUTE_PATH_ATTACHED) + else if (rpath->frp_flags & FIB_ROUTE_PATH_ATTACHED || + rpath->frp_flags & FIB_ROUTE_PATH_GLEAN) { return (!0); } diff --git a/src/vnet/fib/fib_entry_src.h b/src/vnet/fib/fib_entry_src.h index edeaaf980e8..210507932c4 100644 --- a/src/vnet/fib/fib_entry_src.h +++ b/src/vnet/fib/fib_entry_src.h @@ -258,6 +258,8 @@ typedef struct fib_entry_src_vft_t_ { extern const fib_entry_src_vft_t*fib_entry_src_get_vft( const fib_entry_src_t *esrc); +extern fib_entry_src_t * fib_entry_src_find (const fib_entry_t *fib_entry, + fib_source_t source); extern u8* fib_entry_src_format(fib_entry_t *entry, fib_source_t source, u8* s); diff --git a/src/vnet/fib/fib_entry_src_interface.c b/src/vnet/fib/fib_entry_src_interface.c index e1725773d93..402369d1dfc 100644 --- a/src/vnet/fib/fib_entry_src_interface.c +++ b/src/vnet/fib/fib_entry_src_interface.c @@ -48,45 +48,72 @@ static void fib_entry_src_interface_remove (fib_entry_src_t *src) { src->fes_pl = FIB_NODE_INDEX_INVALID; + ASSERT(src->u.interface.fesi_sibling == ~0); } -static void -fib_entry_src_interface_path_swap (fib_entry_src_t *src, - const fib_entry_t *entry, - fib_path_list_flags_t pl_flags, - const fib_route_path_t *paths) +static int +fib_entry_src_interface_update_glean (fib_entry_t *cover, + const fib_entry_t *local) { - fib_node_index_t fib_entry_index; - ip_adjacency_t *adj; + fib_entry_src_t *src; + adj_index_t ai; - fib_entry_index = fib_entry_get_index(entry); - src->fes_pl = fib_path_list_create(pl_flags, paths); + src = fib_entry_src_find (cover, FIB_SOURCE_INTERFACE); - /* - * this is a hack to get the entry's prefix into the glean adjacency - * so that it is available for fast retrieval in the switch path. - */ - if (!(FIB_ENTRY_FLAG_LOCAL & src->fes_entry_flags)) + if (NULL == src) { - adj_index_t ai; + /* + * The cover is not an interface source, no work + */ + return 0; + } - ai = fib_path_list_get_adj(src->fes_pl, - fib_entry_get_default_chain_type( - fib_entry_get(fib_entry_index))); - if (INDEX_INVALID != ai) - { - adj = adj_get(ai); + ai = fib_path_list_get_adj(src->fes_pl, + fib_entry_get_default_chain_type(cover)); + + if (INDEX_INVALID != ai) + { + ip_adjacency_t *adj; + + adj = adj_get(ai); - if (IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index) + if (IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index) + { + /* + * the connected prefix will link to a glean on a non-p2p + * interface. + * Ensure we are updating with a host in the connected's subnet + */ + if (fib_prefix_is_cover(&adj->sub_type.glean.rx_pfx, + &local->fe_prefix)) { - /* - * the connected prefix will link to a glean on a non-p2p - * u.interface. - */ - adj->sub_type.glean.receive_addr = entry->fe_prefix.fp_addr; + adj->sub_type.glean.rx_pfx.fp_addr = local->fe_prefix.fp_addr; + return (1); } } } + + return (0); +} + +static walk_rc_t +fib_entry_src_interface_update_glean_walk (fib_entry_t *cover, + fib_node_index_t covered, + void *ctx) +{ + if (fib_entry_src_interface_update_glean(cover, fib_entry_get(covered))) + return (WALK_STOP); + + return (WALK_CONTINUE); +} + +static void +fib_entry_src_interface_path_swap (fib_entry_src_t *src, + const fib_entry_t *entry, + fib_path_list_flags_t pl_flags, + const fib_route_path_t *paths) +{ + src->fes_pl = fib_path_list_create(pl_flags, paths); } /* @@ -116,6 +143,8 @@ fib_entry_src_interface_activate (fib_entry_src_t *src, src->u.interface.fesi_sibling = fib_entry_cover_track(cover, fib_entry_get_index(fib_entry)); + + fib_entry_src_interface_update_glean(cover, fib_entry); } return (!0); @@ -142,6 +171,11 @@ fib_entry_src_interface_deactivate (fib_entry_src_t *src, fib_entry_cover_untrack(cover, src->u.interface.fesi_sibling); src->u.interface.fesi_cover = FIB_NODE_INDEX_INVALID; + src->u.interface.fesi_sibling = ~0; + + fib_entry_cover_walk(cover, + fib_entry_src_interface_update_glean_walk, + NULL); } } diff --git a/src/vnet/fib/fib_path.c b/src/vnet/fib/fib_path.c index 2cee8467647..2a4e6ab551f 100644 --- a/src/vnet/fib/fib_path.c +++ b/src/vnet/fib/fib_path.c @@ -246,6 +246,10 @@ typedef struct fib_path_t_ { } attached_next_hop; struct { /** + * The Connected local address + */ + fib_prefix_t fp_connected; + /** * The interface */ u32 fp_interface; @@ -732,7 +736,7 @@ fib_path_attached_get_adj (fib_path_t *path, ai = adj_glean_add_or_lock(nh_proto, link, path->attached.fp_interface, - NULL); + &path->attached.fp_connected); dpo_set(dpo, DPO_ADJACENCY_GLEAN, vnet_link_to_dpo_proto(link), ai); adj_unlock(ai); } @@ -1262,6 +1266,8 @@ fib_path_route_flags_to_cfg_flags (const fib_route_path_t *rpath) cfg_flags |= FIB_PATH_CFG_FLAG_ICMP_UNREACH; if (rpath->frp_flags & FIB_ROUTE_PATH_ICMP_PROHIBIT) cfg_flags |= FIB_PATH_CFG_FLAG_ICMP_PROHIBIT; + if (rpath->frp_flags & FIB_ROUTE_PATH_GLEAN) + cfg_flags |= FIB_PATH_CFG_FLAG_GLEAN; return (cfg_flags); } @@ -1365,6 +1371,12 @@ fib_path_create (fib_node_index_t pl_index, path->fp_type = FIB_PATH_TYPE_SPECIAL; path->classify.fp_classify_table_id = rpath->frp_classify_table_id; } + else if (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_GLEAN) + { + path->fp_type = FIB_PATH_TYPE_ATTACHED; + path->attached.fp_interface = rpath->frp_sw_if_index; + path->attached.fp_connected = rpath->frp_connected; + } else if (~0 != rpath->frp_sw_if_index) { if (ip46_address_is_zero(&rpath->frp_addr)) @@ -2105,7 +2117,7 @@ fib_path_resolve (fib_node_index_t path_index) break; } case FIB_PATH_TYPE_DVR: - dvr_dpo_add_or_lock(path->attached.fp_interface, + dvr_dpo_add_or_lock(path->dvr.fp_interface, path->fp_nh_proto, &path->fp_dpo); break; diff --git a/src/vnet/fib/fib_path.h b/src/vnet/fib/fib_path.h index 76f876d8f10..c0f76411390 100644 --- a/src/vnet/fib/fib_path.h +++ b/src/vnet/fib/fib_path.h @@ -100,9 +100,13 @@ typedef enum fib_path_cfg_attribute_t_ { */ FIB_PATH_CFG_ATTRIBUTE_POP_PW_CW, /** + * The path is a glean + */ + FIB_PATH_CFG_ATTRIBUTE_GLEAN, + /** * Marker. Add new types before this one, then update it. */ - FIB_PATH_CFG_ATTRIBUTE_LAST = FIB_PATH_CFG_ATTRIBUTE_POP_PW_CW, + FIB_PATH_CFG_ATTRIBUTE_LAST = FIB_PATH_CFG_ATTRIBUTE_GLEAN, } __attribute__ ((packed)) fib_path_cfg_attribute_t; /** @@ -123,7 +127,8 @@ typedef enum fib_path_cfg_attribute_t_ { [FIB_PATH_CFG_ATTRIBUTE_INTF_RX] = "interface-rx", \ [FIB_PATH_CFG_ATTRIBUTE_RPF_ID] = "rpf-id", \ [FIB_PATH_CFG_ATTRIBUTE_DEAG_SRC] = "deag-src", \ - [FIB_PATH_CFG_ATTRIBUTE_POP_PW_CW] = "pop-pw-cw", \ + [FIB_PATH_CFG_ATTRIBUTE_POP_PW_CW] = "pop-pw-cw", \ + [FIB_PATH_CFG_ATTRIBUTE_GLEAN] = "glean", \ } #define FOR_EACH_FIB_PATH_CFG_ATTRIBUTE(_item) \ @@ -149,6 +154,7 @@ typedef enum fib_path_cfg_flags_t_ { FIB_PATH_CFG_FLAG_RPF_ID = (1 << FIB_PATH_CFG_ATTRIBUTE_RPF_ID), FIB_PATH_CFG_FLAG_DEAG_SRC = (1 << FIB_PATH_CFG_ATTRIBUTE_DEAG_SRC), FIB_PATH_CFG_FLAG_POP_PW_CW = (1 << FIB_PATH_CFG_ATTRIBUTE_POP_PW_CW), + FIB_PATH_CFG_FLAG_GLEAN = (1 << FIB_PATH_CFG_ATTRIBUTE_GLEAN), } __attribute__ ((packed)) fib_path_cfg_flags_t; typedef enum fib_path_format_flags_t_ diff --git a/src/vnet/fib/fib_sas.c b/src/vnet/fib/fib_sas.c new file mode 100644 index 00000000000..b607a0b5be8 --- /dev/null +++ b/src/vnet/fib/fib_sas.c @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @brief FIB Source Address selection + * + * Use the FIB for source address selection on an interface + */ + +#include <vnet/fib/fib_sas.h> +#include <vnet/adj/adj_glean.h> +#include <vnet/ip/ip6_link.h> + + +bool +fib_sas_get (u32 sw_if_index, + ip_address_family_t af, + const ip46_address_t *dst, + ip46_address_t *src) +{ + switch (af) + { + case AF_IP4: + if (dst) + return (fib_sas4_get(sw_if_index, &dst->ip4, &src->ip4)); + else + return (fib_sas4_get(sw_if_index, NULL, &src->ip4)); + case AF_IP6: + if (dst) + return (fib_sas6_get(sw_if_index, &dst->ip6, &src->ip6)); + else + return (fib_sas6_get(sw_if_index, NULL, &src->ip6)); + } + return (false); +} + +bool +fib_sas4_get (u32 sw_if_index, + const ip4_address_t *dst, + ip4_address_t *src) +{ + ip46_address_t d_tmp, *d_tmpp = NULL; + const ip46_address_t *s_tmp; + vnet_sw_interface_t *swif; + + if (dst) + { + d_tmpp = &d_tmp; + d_tmp.ip4 = *dst; + } + + /* + * If the interface is unnumbered then use the IP interface + */ + swif = vnet_get_sw_interface (vnet_get_main(), sw_if_index); + + if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) + sw_if_index = swif->unnumbered_sw_if_index; + + /* + * get the source address from the glean adjacency + */ + s_tmp = adj_glean_get_src (FIB_PROTOCOL_IP4, sw_if_index, d_tmpp); + + if (NULL != s_tmp) + { + src->as_u32 = s_tmp->ip4.as_u32; + return (true); + } + + return (false); +} + +bool +fib_sas6_get (u32 sw_if_index, + const ip6_address_t *dst, + ip6_address_t *src) +{ + ip46_address_t d_tmp, *d_tmpp = NULL; + const ip46_address_t *s_tmp; + + if (dst) + { + d_tmpp = &d_tmp; + d_tmp.ip6 = *dst; + } + + /* + * if the dst is v6 and link local, use the source link local + */ + if (ip6_address_is_link_local_unicast (dst)) + { + ip6_address_copy (src, ip6_get_link_local_address (sw_if_index)); + return (true); + } + + /* + * get the source address from the glean adjacency + */ + s_tmp = adj_glean_get_src (FIB_PROTOCOL_IP6, sw_if_index, d_tmpp); + + if (NULL != s_tmp) + { + ip6_address_copy(src, &s_tmp->ip6); + return (true); + } + + return (false); +} diff --git a/src/vnet/fib/fib_sas.h b/src/vnet/fib/fib_sas.h new file mode 100644 index 00000000000..172a4d6b2dc --- /dev/null +++ b/src/vnet/fib/fib_sas.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @brief FIB Source Address selection + * + * Use the FIB for source address selection on an interface + */ + +#ifndef __FIB_SAS_H__ +#define __FIB_SAS_H__ + +#include <vnet/fib/fib_types.h> +#include <vnet/ip/ip_types.h> + +/** + * @brief Get a Source address to use in a packet being sent out + * an interface + * + * @param sw_if_index The interface on which the packet is to be sent + * @param af The address family of the packet + * @param dst The destination of the packet (can be NULL in which case any + * of the available address will be returned) + * @param src OUT the source address to use + * + * @return True if an address is available False (and src is unset) otherwise + */ +extern bool fib_sas_get (u32 sw_if_index, + ip_address_family_t af, + const ip46_address_t *dst, + ip46_address_t *src); + +/** + * @brief Get an IPv4 Source address to use in a packet being sent out + * an interface + * + * @param sw_if_index The interface on which the packet is to be sent + * @param dst The destination of the packet (can be NULL in which case any + * of the available address will be returned) + * @param src OUT the source address to use + * + * @return True if an address is available False (and src is unset) otherwise + */ +extern bool fib_sas4_get (u32 sw_if_index, + const ip4_address_t *dst, + ip4_address_t *src); + +/** + * @brief Get an IPv6 Source address to use in a packet being sent out + * an interface + * + * @param sw_if_index The interface on which the packet is to be sent + * @param dst The destination of the packet (can be NULL in which case any + * of the available address will be returned) + * @param src OUT the source address to use + * + * @return True if an address is available False (and src is unset) otherwise + */ +extern bool fib_sas6_get (u32 sw_if_index, + const ip6_address_t *dst, + ip6_address_t *src); + +#endif diff --git a/src/vnet/fib/fib_table.c b/src/vnet/fib/fib_table.c index ec2acc59c52..e71e6c36bfb 100644 --- a/src/vnet/fib/fib_table.c +++ b/src/vnet/fib/fib_table.c @@ -510,7 +510,7 @@ fib_table_route_path_fixup (const fib_prefix_t *prefix, (~0 == path->frp_sw_if_index) && (0 == ip46_address_cmp(&path->frp_addr, &prefix->fp_addr))) { - /* Prefix recurses via itse;f */ + /* Prefix recurses via itself */ path->frp_flags |= FIB_ROUTE_PATH_DROP; } if (!(path->frp_flags & FIB_ROUTE_PATH_LOCAL) && @@ -522,6 +522,15 @@ fib_table_route_path_fixup (const fib_prefix_t *prefix, path->frp_addr = prefix->fp_addr; path->frp_flags |= FIB_ROUTE_PATH_ATTACHED; } + else if ((*eflags & FIB_ENTRY_FLAG_CONNECTED) && + !(*eflags & FIB_ENTRY_FLAG_LOCAL)) + { + if (ip46_address_is_zero(&path->frp_addr)) + { + path->frp_flags |= FIB_ROUTE_PATH_GLEAN; + fib_prefix_normalize(prefix, &path->frp_connected); + } + } if (*eflags & FIB_ENTRY_FLAG_DROP) { path->frp_flags |= FIB_ROUTE_PATH_DROP; diff --git a/src/vnet/fib/fib_types.c b/src/vnet/fib/fib_types.c index b5576161d80..2fce6a85c74 100644 --- a/src/vnet/fib/fib_types.c +++ b/src/vnet/fib/fib_types.c @@ -260,6 +260,25 @@ fib_prefix_is_host (const fib_prefix_t *prefix) return (0); } +void +fib_prefix_normalize (const fib_prefix_t *p, + fib_prefix_t *out) +{ + fib_prefix_copy (out, p); + + switch (p->fp_proto) + { + case FIB_PROTOCOL_IP4: + ip4_address_normalize(&out->fp_addr.ip4, out->fp_len); + break; + case FIB_PROTOCOL_IP6: + ip6_address_normalize(&out->fp_addr.ip6, out->fp_len); + break; + case FIB_PROTOCOL_MPLS: + break; + } +} + u8 * format_fib_prefix (u8 * s, va_list * args) { diff --git a/src/vnet/fib/fib_types.h b/src/vnet/fib/fib_types.h index 832092c5679..b5a58e7b674 100644 --- a/src/vnet/fib/fib_types.h +++ b/src/vnet/fib/fib_types.h @@ -267,6 +267,13 @@ extern int fib_prefix_is_host(const fib_prefix_t *p); extern u8 fib_prefix_get_host_length (fib_protocol_t proto); /** + * normalise a prefix (i.e. mask the host bits according to the + * prefix length) + */ +extern void fib_prefix_normalize(const fib_prefix_t *p, + fib_prefix_t *out); + +/** * \brief Host prefix from ip */ extern void fib_prefix_from_ip46_addr (const ip46_address_t *addr, @@ -393,6 +400,10 @@ typedef enum fib_route_path_flags_t_ * Pop a Psuedo Wire Control Word */ FIB_ROUTE_PATH_POP_PW_CW = (1 << 18), + /** + * A path that resolves via a glean adjacency + */ + FIB_ROUTE_PATH_GLEAN = (1 << 19), } fib_route_path_flags_t; /** @@ -520,6 +531,11 @@ typedef struct fib_route_path_t_ { * Present in an mfib path list */ index_t frp_bier_imp; + + /** + * Glean prefix on a glean path + */ + fib_prefix_t frp_connected; }; /** |