summaryrefslogtreecommitdiffstats
path: root/src/vnet/fib
diff options
context:
space:
mode:
Diffstat (limited to 'src/vnet/fib')
-rw-r--r--src/vnet/fib/fib_entry_src.c5
-rw-r--r--src/vnet/fib/fib_entry_src.h2
-rw-r--r--src/vnet/fib/fib_entry_src_interface.c88
-rw-r--r--src/vnet/fib/fib_path.c16
-rw-r--r--src/vnet/fib/fib_path.h10
-rw-r--r--src/vnet/fib/fib_sas.c121
-rw-r--r--src/vnet/fib/fib_sas.h75
-rw-r--r--src/vnet/fib/fib_table.c11
-rw-r--r--src/vnet/fib/fib_types.c19
-rw-r--r--src/vnet/fib/fib_types.h16
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;
};
/**