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
This commit is contained in:
Neale Ranns
2020-11-26 08:37:27 +00:00
committed by Ole Tr�an
parent 9b8cb50824
commit e2fe097424
34 changed files with 868 additions and 394 deletions
+2 -2
View File
@@ -16,6 +16,7 @@
*/
#include <igmp/igmp_pkt.h>
#include <vnet/fib/fib_sas.h>
static void
vlib_buffer_append (vlib_buffer_t * b, uword l)
@@ -76,8 +77,7 @@ igmp_pkt_build_ip_header (igmp_pkt_build_t * bk,
ip4->protocol = IP_PROTOCOL_IGMP;
ip4->tos = 0xc0;
ip4_src_address_for_packet (&ip4_main.lookup_main,
bk->sw_if_index, &ip4->src_address);
fib_sas4_get (bk->sw_if_index, NULL, &ip4->src_address);
vlib_buffer_append (b, sizeof (*ip4));
bk->n_avail -= sizeof (*ip4);
+8 -10
View File
@@ -18,7 +18,7 @@
#include <vlib/vlib.h>
#include <vnet/fib/ip6_fib.h>
#include <vnet/fib/ip4_fib.h>
#include <vnet/fib/fib_entry.h>
#include <vnet/fib/fib_sas.h>
#include <vnet/ip/ip6_link.h>
#include <vnet/plugin/plugin.h>
#include <vpp/app/version.h>
@@ -725,24 +725,22 @@ ip46_fill_l3_header (ip46_address_t * pa46, vlib_buffer_t * b0, int is_ip6)
}
}
static int
static bool
ip46_set_src_address (u32 sw_if_index, vlib_buffer_t * b0, int is_ip6)
{
int res;
bool res = false;
if (is_ip6)
{
ip6_header_t *ip6 = vlib_buffer_get_current (b0);
res = ip6_src_address_for_packet (sw_if_index,
&ip6->dst_address, &ip6->src_address);
res = fib_sas6_get (sw_if_index, &ip6->dst_address, &ip6->src_address);
}
else
{
ip4_main_t *im = &ip4_main;
ip4_header_t *ip4 = vlib_buffer_get_current (b0);
res = ip4_src_address_for_packet (&im->lookup_main,
sw_if_index, &ip4->src_address);
/* IP4 and IP6 paths have the inverse logic. Harmonize. */
res = !res;
res = fib_sas4_get (sw_if_index, &ip4->dst_address, &ip4->src_address);
}
return res;
}
+8 -6
View File
@@ -898,9 +898,6 @@ fib_test_v4 (void)
adj = adj_get(ai);
FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
"attached interface adj is glean");
FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
&adj->sub_type.glean.receive_addr)),
"attached interface adj is receive ok");
local_pfx.fp_len = 32;
fib_table_entry_update_one_path(fib_index, &local_pfx,
@@ -937,6 +934,9 @@ fib_test_v4 (void)
FIB_PROTOCOL_IP4,
FIB_SOURCE_INTERFACE)),
"2 Interface Source'd prefixes");
FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
&adj->sub_type.glean.rx_pfx.fp_addr)),
"attached interface adj is receive ok");
/*
* +2 interface routes +2 non-shared path-lists
@@ -4495,9 +4495,6 @@ fib_test_v6 (void)
adj = adj_get(ai);
FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
"attached interface adj is glean");
FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
&adj->sub_type.glean.receive_addr)),
"attached interface adj is receive ok");
dpo = fib_entry_contribute_ip_forwarding(fei);
FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
1,
@@ -4535,6 +4532,9 @@ fib_test_v6 (void)
1,
&local_pfx.fp_addr.ip6)),
"local-route; fwd and non-fwd tables match");
FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
&adj->sub_type.glean.rx_pfx.fp_addr)),
"attached interface adj is receive ok");
/*
* +2 entries. +2 unshared path-lists
@@ -5257,6 +5257,8 @@ fib_test_v6 (void)
FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
adj_nbr_db_size());
FIB_TEST((0 == adj_glean_db_size()), "ADJ DB size is %d",
adj_glean_db_size());
return (res);
}
+2 -2
View File
@@ -12,6 +12,7 @@
#include <vnet/ip/ip4_packet.h>
#include <vnet/ip/ip6_link.h>
#include <vnet/ethernet/arp_packet.h>
#include <vnet/fib/fib_sas.h>
#include <vppinfra/error.h>
#include <vrrp/vrrp.h>
#include <vrrp/vrrp_packet.h>
@@ -119,8 +120,7 @@ vrrp_vr_addr_cmp (vrrp_vr_t * vr, vrrp_header_t * pkt)
peer_addr = &(((ip4_header_t *) pkt) - 1)->src_address;
local_addr = &addr.ip4;
addr_size = 4;
ip4_src_address_for_packet (&ip4_main.lookup_main,
vrc->sw_if_index, local_addr);
fib_sas4_get (vrc->sw_if_index, NULL, local_addr);
}
return memcmp (local_addr, peer_addr, addr_size);
+3 -4
View File
@@ -14,6 +14,7 @@
#include <vnet/adj/adj.h>
#include <vnet/adj/adj_mcast.h>
#include <vnet/fib/fib_table.h>
#include <vnet/fib/fib_sas.h>
#include <vnet/ip/igmp_packet.h>
#include <vnet/ip/ip6_link.h>
#include <vnet/ethernet/arp_packet.h>
@@ -107,8 +108,7 @@ vrrp_adv_l3_build (vrrp_vr_t * vr, vlib_buffer_t * b,
ip4->ttl = 255;
ip4->protocol = IP_PROTOCOL_VRRP;
clib_memcpy (&ip4->dst_address, &dst->ip4, sizeof (dst->ip4));
ip4_src_address_for_packet (&ip4_main.lookup_main,
vr->config.sw_if_index, &ip4->src_address);
fib_sas4_get (vr->config.sw_if_index, NULL, &ip4->src_address);
ip4->length = clib_host_to_net_u16 (sizeof (*ip4) +
vrrp_adv_payload_len (vr));
ip4->checksum = ip4_header_checksum (ip4);
@@ -541,8 +541,7 @@ vrrp_igmp_pkt_build (vrrp_vr_t * vr, vlib_buffer_t * b)
ip4 = vlib_buffer_get_current (b);
clib_memcpy (ip4, &igmp_ip4_mcast, sizeof (*ip4));
ip4_src_address_for_packet (&ip4_main.lookup_main, vr->config.sw_if_index,
&ip4->src_address);
fib_sas4_get (vr->config.sw_if_index, NULL, &ip4->src_address);
vlib_buffer_chain_increase_length (b, b, sizeof (*ip4));
vlib_buffer_advance (b, sizeof (*ip4));
+2
View File
@@ -1195,6 +1195,7 @@ list(APPEND VNET_SOURCES
fib/fib_path_list.c
fib/fib_path.c
fib/fib_path_ext.c
fib/fib_sas.c
fib/fib_source.c
fib/fib_urpf_list.c
fib/fib_attached_export.c
@@ -1213,6 +1214,7 @@ list(APPEND VNET_HEADERS
fib/fib_node_list.h
fib/fib_entry.h
fib/fib_entry_delegate.h
fib/fib_sas.h
fib/fib_source.h
)
+1 -2
View File
@@ -288,8 +288,7 @@ adj_last_lock_gone (ip_adjacency_t *adj)
adj->rewrite_header.sw_if_index);
break;
case IP_LOOKUP_NEXT_GLEAN:
adj_glean_remove(adj->ia_nh_proto,
adj->rewrite_header.sw_if_index);
adj_glean_remove(adj);
break;
case IP_LOOKUP_NEXT_MCAST_MIDCHAIN:
adj_midchain_teardown(adj);
+1 -1
View File
@@ -297,7 +297,7 @@ typedef struct ip_adjacency_t_
*/
struct
{
ip46_address_t receive_addr;
fib_prefix_t rx_pfx;
} glean;
} sub_type;
+243 -69
View File
File diff suppressed because it is too large Load Diff
+24 -2
View File
@@ -46,7 +46,7 @@
extern adj_index_t adj_glean_add_or_lock(fib_protocol_t proto,
vnet_link_t linkt,
u32 sw_if_index,
const ip46_address_t *nh_addr);
const fib_prefix_t *conn);
/**
* @brief Get an existing glean
@@ -54,7 +54,8 @@ extern adj_index_t adj_glean_add_or_lock(fib_protocol_t proto,
* @return INVALID if it does not exist
*/
extern adj_index_t adj_glean_get(fib_protocol_t proto,
u32 sw_if_index);
u32 sw_if_index,
const ip46_address_t *nh_addr);
/**
* adj_glean_update_rewrite
@@ -66,16 +67,37 @@ extern adj_index_t adj_glean_get(fib_protocol_t proto,
* glean behaviour on an adjacency liked to a connected prefix.
*/
extern void adj_glean_update_rewrite(adj_index_t adj_index);
extern void adj_glean_update_rewrite_itf(u32 sw_if_index);
/**
* Return the source address from the glean
*/
const ip46_address_t *adj_glean_get_src(fib_protocol_t proto,
u32 sw_if_index,
const ip46_address_t *nh_addr);
/**
* @brief Format/display a glean adjacency.
*/
extern u8* format_adj_glean(u8* s, va_list *ap);
/**
* Walk all the gleans on an interface
*/
extern void adj_glean_walk (u32 sw_if_index,
adj_walk_cb_t,
void *);
/**
* @brief
* Module initialisation
*/
extern void adj_glean_module_init(void);
/**
* @brief
* Return the size of the adjacency database. for testing purposes
*/
extern u32 adj_glean_db_size(void);
#endif
+1 -2
View File
@@ -120,8 +120,7 @@ extern void adj_nbr_remove(adj_index_t ai,
vnet_link_t link_type,
const ip46_address_t *nh_addr,
u32 sw_if_index);
extern void adj_glean_remove(fib_protocol_t proto,
u32 sw_if_index);
extern void adj_glean_remove(ip_adjacency_t *adj);
extern void adj_mcast_remove(fib_protocol_t proto,
u32 sw_if_index);
extern void adj_midchain_teardown(ip_adjacency_t *adj);
+3 -2
View File
@@ -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);
}
+2
View File
@@ -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);
+64 -30
View File
@@ -48,6 +48,63 @@ 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 int
fib_entry_src_interface_update_glean (fib_entry_t *cover,
const fib_entry_t *local)
{
fib_entry_src_t *src;
adj_index_t ai;
src = fib_entry_src_find (cover, FIB_SOURCE_INTERFACE);
if (NULL == src)
{
/*
* 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(cover));
if (INDEX_INVALID != ai)
{
ip_adjacency_t *adj;
adj = adj_get(ai);
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))
{
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
@@ -56,37 +113,7 @@ fib_entry_src_interface_path_swap (fib_entry_src_t *src,
fib_path_list_flags_t pl_flags,
const fib_route_path_t *paths)
{
fib_node_index_t fib_entry_index;
ip_adjacency_t *adj;
fib_entry_index = fib_entry_get_index(entry);
src->fes_pl = fib_path_list_create(pl_flags, paths);
/*
* 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))
{
adj_index_t ai;
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);
if (IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index)
{
/*
* 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;
}
}
}
}
/*
@@ -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);
}
}
+14 -2
View File
@@ -245,6 +245,10 @@ typedef struct fib_path_t_ {
u32 fp_interface;
} attached_next_hop;
struct {
/**
* The Connected local address
*/
fib_prefix_t fp_connected;
/**
* The 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;
+8 -2
View File
@@ -99,10 +99,14 @@ typedef enum fib_path_cfg_attribute_t_ {
* The path pops a Psuedo Wire Control Word
*/
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_
+121
View File
@@ -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);
}
+75
View File
@@ -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
+10 -1
View File
@@ -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;
+19
View File
@@ -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)
{
+16
View File
@@ -266,6 +266,13 @@ extern int fib_prefix_is_cover(const fib_prefix_t *p1,
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
*/
@@ -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;
};
/**
+14 -15
View File
@@ -40,23 +40,23 @@
#include <vnet/ip-neighbor/ip4_neighbor.h>
#include <vnet/ethernet/ethernet.h>
#include <vnet/util/throttle.h>
#include <vnet/fib/fib_sas.h>
/** ARP throttling */
static throttle_t arp_throttle;
void
ip4_neighbor_probe_dst (const ip_adjacency_t * adj, const ip4_address_t * dst)
ip4_neighbor_probe_dst (u32 sw_if_index, const ip4_address_t * dst)
{
ip_interface_address_t *ia;
ip4_address_t *src;
ip4_address_t src;
adj_index_t ai;
src = ip4_interface_address_matching_destination
(&ip4_main,
&adj->sub_type.nbr.next_hop.ip4, adj->rewrite_header.sw_if_index, &ia);
if (!src)
return;
/* any glean will do, it's just for the rewrite */
ai = adj_glean_get (FIB_PROTOCOL_IP4, sw_if_index, NULL);
ip4_neighbor_probe (vlib_get_main (), vnet_get_main (), adj, src, dst);
if (ADJ_INDEX_INVALID != ai && fib_sas4_get (sw_if_index, dst, &src))
ip4_neighbor_probe (vlib_get_main (),
vnet_get_main (), adj_get (ai), &src, dst);
}
void
@@ -67,11 +67,12 @@ ip4_neighbor_advertise (vlib_main_t * vm,
vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
ip4_main_t *i4m = &ip4_main;
u8 *rewrite, rewrite_len;
ip4_address_t tmp;
if (NULL == addr)
{
ip4_main_t *i4m = &ip4_main;
addr = ip4_interface_first_address (i4m, sw_if_index, 0);
fib_sas4_get (sw_if_index, NULL, &tmp);
addr = &tmp;
}
if (addr)
@@ -122,8 +123,6 @@ ip4_arp_inline (vlib_main_t * vm,
vlib_frame_t * frame, int is_glean)
{
vnet_main_t *vnm = vnet_get_main ();
ip4_main_t *im = &ip4_main;
ip_lookup_main_t *lm = &im->lookup_main;
u32 *from, *to_next_drop;
uword n_left_from, n_left_to_next_drop, next_index;
u32 thread_index = vm->thread_index;
@@ -171,14 +170,14 @@ ip4_arp_inline (vlib_main_t * vm,
/* resolve the packet's destination */
ip4_header_t *ip0 = vlib_buffer_get_current (p0);
resolve0 = ip0->dst_address;
src0 = adj0->sub_type.glean.receive_addr.ip4;
src0 = adj0->sub_type.glean.rx_pfx.fp_addr.ip4;
}
else
{
/* resolve the incomplete adj */
resolve0 = adj0->sub_type.nbr.next_hop.ip4;
/* Src IP address in ARP header. */
if (ip4_src_address_for_packet (lm, sw_if_index0, &src0))
if (!fib_sas4_get (sw_if_index0, &resolve0, &src0))
{
/* No source address available */
p0->error = node->errors[IP4_ARP_ERROR_NO_SOURCE_ADDRESS];
+1 -1
View File
@@ -19,7 +19,7 @@
#include <vnet/ip/ip.h>
#include <vnet/ethernet/arp_packet.h>
extern void ip4_neighbor_probe_dst (const ip_adjacency_t * adj,
extern void ip4_neighbor_probe_dst (u32 sw_if_index,
const ip4_address_t * dst);
extern void ip4_neighbor_advertise (vlib_main_t * vm,
vnet_main_t * vnm,
+9 -13
View File
@@ -17,23 +17,19 @@
#include <vnet/ip-neighbor/ip6_neighbor.h>
#include <vnet/util/throttle.h>
#include <vnet/fib/fib_sas.h>
/** ND throttling */
static throttle_t nd_throttle;
void
ip6_neighbor_probe_dst (const ip_adjacency_t * adj, const ip6_address_t * dst)
ip6_neighbor_probe_dst (u32 sw_if_index, const ip6_address_t * dst)
{
ip_interface_address_t *ia;
ip6_address_t *src;
ip6_address_t src;
src = ip6_interface_address_matching_destination
(&ip6_main, dst, adj->rewrite_header.sw_if_index, &ia);
if (!src)
return;
ip6_neighbor_probe (vlib_get_main (), vnet_get_main (), adj, src, dst);
if (fib_sas6_get (sw_if_index, dst, &src))
ip6_neighbor_probe (vlib_get_main (), vnet_get_main (),
sw_if_index, &src, dst);
}
void
@@ -210,15 +206,15 @@ ip6_discover_neighbor_inline (vlib_main_t * vm,
* Choose source address based on destination lookup
* adjacency.
*/
if (!ip6_src_address_for_packet (sw_if_index0,
&ip0->dst_address, &src))
if (!fib_sas6_get (sw_if_index0, &ip0->dst_address, &src))
{
/* There is no address on the interface */
p0->error = node->errors[IP6_NBR_ERROR_NO_SOURCE_ADDRESS];
continue;
}
b0 = ip6_neighbor_probe (vm, vnm, adj0, &src, &ip0->dst_address);
b0 = ip6_neighbor_probe (vm, vnm, sw_if_index0,
&src, &ip0->dst_address);
if (PREDICT_TRUE (NULL != b0))
{
+8 -7
View File
@@ -34,17 +34,18 @@ extern void ip6_neighbor_advertise (vlib_main_t * vm,
u32 sw_if_index,
const ip6_address_t * addr);
extern void ip6_neighbor_probe_dst (const ip_adjacency_t * adj,
extern void ip6_neighbor_probe_dst (u32 sw_if_index,
const ip6_address_t * dst);
always_inline vlib_buffer_t *
ip6_neighbor_probe (vlib_main_t * vm,
vnet_main_t * vnm,
const ip_adjacency_t * adj,
u32 sw_if_index,
const ip6_address_t * src, const ip6_address_t * dst)
{
icmp6_neighbor_solicitation_header_t *h0;
vnet_hw_interface_t *hw_if0;
const ip_adjacency_t *adj;
vlib_buffer_t *b0;
int bogus_length;
u32 bi0 = 0;
@@ -52,17 +53,17 @@ ip6_neighbor_probe (vlib_main_t * vm,
h0 = vlib_packet_template_get_packet
(vm, &ip6_neighbor_packet_template, &bi0);
if (!h0)
return NULL;;
return NULL;
/* if the interface has been disabled for ip6, later steps to retrieve
* an adjacency will result in a segv.
*/
if (!ip6_link_is_enabled (adj->rewrite_header.sw_if_index))
if (!ip6_link_is_enabled (sw_if_index))
return NULL;
b0 = vlib_get_buffer (vm, bi0);
hw_if0 = vnet_get_sup_hw_interface (vnm, adj->rewrite_header.sw_if_index);
hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index);
/*
* Destination address is a solicited node multicast address.
@@ -87,11 +88,11 @@ ip6_neighbor_probe (vlib_main_t * vm,
ASSERT (bogus_length == 0);
VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
vnet_buffer (b0)->sw_if_index[VLIB_TX] = adj->rewrite_header.sw_if_index;
vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index;
/* Use the link's mcast adj to ship the packet */
vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
ip6_link_get_mcast_adj (adj->rewrite_header.sw_if_index);
ip6_link_get_mcast_adj (sw_if_index);
adj = adj_get (vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
b0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
+14 -25
View File
@@ -1011,22 +1011,19 @@ ip_neighbor_register (ip_address_family_t af, const ip_neighbor_vft_t * vft)
}
void
ip_neighbor_probe_dst (const ip_adjacency_t * adj, const ip46_address_t * dst)
ip_neighbor_probe_dst (u32 sw_if_index,
ip_address_family_t af, const ip46_address_t * dst)
{
if (!vnet_sw_interface_is_admin_up (vnet_get_main (),
adj->rewrite_header.sw_if_index))
if (!vnet_sw_interface_is_admin_up (vnet_get_main (), sw_if_index))
return;
switch (adj->ia_nh_proto)
switch (af)
{
case FIB_PROTOCOL_IP6:
ip6_neighbor_probe_dst (adj, &dst->ip6);
case AF_IP6:
ip6_neighbor_probe_dst (sw_if_index, &dst->ip6);
break;
case FIB_PROTOCOL_IP4:
ip4_neighbor_probe_dst (adj, &dst->ip4);
break;
case FIB_PROTOCOL_MPLS:
ASSERT (0);
case AF_IP4:
ip4_neighbor_probe_dst (sw_if_index, &dst->ip4);
break;
}
}
@@ -1034,7 +1031,9 @@ ip_neighbor_probe_dst (const ip_adjacency_t * adj, const ip46_address_t * dst)
void
ip_neighbor_probe (const ip_adjacency_t * adj)
{
ip_neighbor_probe_dst (adj, &adj->sub_type.nbr.next_hop);
ip_neighbor_probe_dst (adj->rewrite_header.sw_if_index,
ip_address_family_from_fib_proto (adj->ia_nh_proto),
&adj->sub_type.nbr.next_hop);
}
void
@@ -1147,7 +1146,6 @@ ip_neighbor_ethernet_change_mac (ethernet_main_t * em,
u32 sw_if_index, uword opaque)
{
ip_neighbor_t *ipn;
adj_index_t ai;
IP_NEIGHBOR_DBG ("mac-change: %U",
format_vnet_sw_if_index_name, vnet_get_main (),
@@ -1165,10 +1163,7 @@ ip_neighbor_ethernet_change_mac (ethernet_main_t * em,
}));
/* *INDENT-ON* */
ai = adj_glean_get (FIB_PROTOCOL_IP4, sw_if_index);
if (ADJ_INDEX_INVALID != ai)
adj_glean_update_rewrite (ai);
adj_glean_update_rewrite_itf (sw_if_index);
}
void
@@ -1543,14 +1538,8 @@ ip_neighbour_age_out (index_t ipni, f64 now, f64 * wait)
}
else
{
adj_index_t ai;
ai = adj_glean_get (ip_address_family_to_fib_proto (af),
ip_neighbor_get_sw_if_index (ipn));
if (ADJ_INDEX_INVALID != ai)
ip_neighbor_probe_dst (adj_get (ai),
&ip_addr_46 (&ipn->ipn_key->ipnk_ip));
ip_neighbor_probe_dst (ip_neighbor_get_sw_if_index (ipn),
af, &ip_addr_46 (&ipn->ipn_key->ipnk_ip));
ipn->ipn_n_probes++;
*wait = 1;
+2 -1
View File
@@ -54,7 +54,8 @@ extern void ip_neighbor_learn (const ip_neighbor_learn_t * l);
extern void ip_neighbor_update (vnet_main_t * vnm, adj_index_t ai);
extern void ip_neighbor_probe (const ip_adjacency_t * adj);
extern void ip_neighbor_probe_dst (const ip_adjacency_t * adj,
extern void ip_neighbor_probe_dst (u32 sw_if_index,
ip_address_family_t af,
const ip46_address_t * ip);
extern void ip_neighbor_mark (ip_address_family_t af);
-20
View File
@@ -201,26 +201,6 @@ ip4_destination_matches_interface (ip4_main_t * im,
return ip4_destination_matches_route (im, key, a, ia->address_length);
}
always_inline int
ip4_src_address_for_packet (ip_lookup_main_t * lm,
u32 sw_if_index, ip4_address_t * src)
{
u32 if_add_index = lm->if_address_pool_index_by_sw_if_index[sw_if_index];
if (PREDICT_TRUE (if_add_index != ~0))
{
ip_interface_address_t *if_add =
pool_elt_at_index (lm->if_address_pool, if_add_index);
ip4_address_t *if_ip = ip_interface_address_get_address (lm, if_add);
*src = *if_ip;
return 0;
}
else
{
src->as_u32 = 0;
}
return (!0);
}
/* Find interface address which matches destination. */
always_inline ip4_address_t *
ip4_interface_address_matching_destination (ip4_main_t * im,
+49 -89
View File
@@ -380,28 +380,28 @@ ip4_add_interface_prefix_routes (ip4_main_t *im,
mhash_set (&lm->prefix_to_if_prefix_index, &key,
if_prefix - lm->if_prefix_pool, 0 /* old value */);
pfx_special.fp_len = a->address_length;
pfx_special.fp_addr.ip4.as_u32 = address->as_u32;
/* set the glean route for the prefix */
fib_table_entry_update_one_path (fib_index, &pfx_special,
FIB_SOURCE_INTERFACE,
(FIB_ENTRY_FLAG_CONNECTED |
FIB_ENTRY_FLAG_ATTACHED),
DPO_PROTO_IP4,
/* No next-hop address */
NULL,
sw_if_index,
/* invalid FIB index */
~0,
1,
/* no out-label stack */
NULL,
FIB_ROUTE_PATH_FLAG_NONE);
/* length <= 30 - add glean, drop first address, maybe drop bcast address */
if (a->address_length <= 30)
{
pfx_special.fp_len = a->address_length;
pfx_special.fp_addr.ip4.as_u32 = address->as_u32;
/* set the glean route for the prefix */
fib_table_entry_update_one_path (fib_index, &pfx_special,
FIB_SOURCE_INTERFACE,
(FIB_ENTRY_FLAG_CONNECTED |
FIB_ENTRY_FLAG_ATTACHED),
DPO_PROTO_IP4,
/* No next-hop address */
NULL,
sw_if_index,
/* invalid FIB index */
~0,
1,
/* no out-label stack */
NULL,
FIB_ROUTE_PATH_FLAG_NONE);
/* set a drop route for the base address of the prefix */
pfx_special.fp_len = 32;
pfx_special.fp_addr.ip4.as_u32 =
@@ -528,90 +528,52 @@ ip4_del_interface_prefix_routes (ip4_main_t * im,
if_prefix->ref_count -= 1;
/*
* Routes need to be adjusted if:
* - deleting last intf addr in prefix
* - deleting intf addr used as default source address in glean adjacency
* Routes need to be adjusted if deleting last intf addr in prefix
*
* We're done now otherwise
*/
if ((if_prefix->ref_count > 0) &&
!pool_is_free_index (lm->if_address_pool, if_prefix->src_ia_index))
if (if_prefix->ref_count > 0)
return;
/* length <= 30, delete glean route, first address, last address */
if (address_length <= 30)
{
/* Less work to do in FIB if we remove the covered /32s first */
/* remove glean route for prefix */
pfx_special.fp_addr.ip4 = *address;
pfx_special.fp_len = address_length;
fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
/* first address in prefix */
pfx_special.fp_addr.ip4.as_u32 =
address->as_u32 & im->fib_masks[address_length];
pfx_special.fp_len = 32;
/* if no more intf addresses in prefix, remove other special routes */
if (!if_prefix->ref_count)
{
/* first address in prefix */
pfx_special.fp_addr.ip4.as_u32 =
address->as_u32 & im->fib_masks[address_length];
pfx_special.fp_len = 32;
if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
fib_table_entry_special_remove (fib_index,
&pfx_special,
FIB_SOURCE_INTERFACE);
if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
fib_table_entry_special_remove (fib_index,
&pfx_special,
FIB_SOURCE_INTERFACE);
/* prefix broadcast address */
pfx_special.fp_addr.ip4.as_u32 =
address->as_u32 | ~im->fib_masks[address_length];
pfx_special.fp_len = 32;
/* prefix broadcast address */
pfx_special.fp_addr.ip4.as_u32 =
address->as_u32 | ~im->fib_masks[address_length];
pfx_special.fp_len = 32;
if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
fib_table_entry_special_remove (fib_index,
&pfx_special,
FIB_SOURCE_INTERFACE);
}
else
/* default source addr just got deleted, find another */
{
ip_interface_address_t *new_src_ia = NULL;
ip4_address_t *new_src_addr = NULL;
new_src_addr =
ip4_interface_address_matching_destination
(im, address, sw_if_index, &new_src_ia);
if_prefix->src_ia_index = new_src_ia - lm->if_address_pool;
pfx_special.fp_len = address_length;
pfx_special.fp_addr.ip4 = *new_src_addr;
/* set new glean route for the prefix */
fib_table_entry_update_one_path (fib_index, &pfx_special,
FIB_SOURCE_INTERFACE,
(FIB_ENTRY_FLAG_CONNECTED |
FIB_ENTRY_FLAG_ATTACHED),
DPO_PROTO_IP4,
/* No next-hop address */
NULL,
sw_if_index,
/* invalid FIB index */
~0,
1,
/* no out-label stack */
NULL,
FIB_ROUTE_PATH_FLAG_NONE);
return;
}
if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
fib_table_entry_special_remove (fib_index,
&pfx_special,
FIB_SOURCE_INTERFACE);
}
/* length == 31, delete attached route for the other address */
else if (address_length == 31)
{
/* length == 31, delete attached route for the other address */
pfx_special.fp_addr.ip4.as_u32 =
address->as_u32 ^ clib_host_to_net_u32(1);
fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
}
/* remove glean route for prefix */
pfx_special.fp_addr.ip4 = *address;
pfx_special.fp_len = address_length;
fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
mhash_unset (&lm->prefix_to_if_prefix_index, &key, 0 /* old_value */);
pool_put (lm->if_prefix_pool, if_prefix);
}
@@ -623,16 +585,15 @@ ip4_del_interface_routes (u32 sw_if_index,
ip4_address_t * address, u32 address_length)
{
fib_prefix_t pfx = {
.fp_len = address_length,
.fp_len = 32,
.fp_proto = FIB_PROTOCOL_IP4,
.fp_addr.ip4 = *address,
};
fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
ip4_del_interface_prefix_routes (im, sw_if_index, fib_index,
address, address_length);
pfx.fp_len = 32;
fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
}
#ifndef CLIB_MARCH_VARIANT
@@ -2540,9 +2501,8 @@ ip4_rewrite_inline_with_gso (vlib_main_t * vm,
thread_index, adj_index0, 1,
vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
if (is_midchain && adj0->sub_type.midchain.fixup_func)
adj0->sub_type.midchain.fixup_func
(vm, adj0, b[0], adj0->sub_type.midchain.fixup_data);
if (is_midchain)
adj_midchain_fixup (vm, adj0, b[0]);
if (is_mcast)
/* copy bytes from the IP address into the MAC rewrite */
-35
View File
@@ -336,41 +336,6 @@ ip6_link_get_mcast_adj (u32 sw_if_index)
return (il->il_mcast_adj);
}
int
ip6_src_address_for_packet (u32 sw_if_index,
const ip6_address_t * dst, ip6_address_t * src)
{
ip_lookup_main_t *lm;
lm = &ip6_main.lookup_main;
if (ip6_address_is_link_local_unicast (dst))
{
ip6_address_copy (src, ip6_get_link_local_address (sw_if_index));
return (!0);
}
else
{
u32 if_add_index =
lm->if_address_pool_index_by_sw_if_index[sw_if_index];
if (PREDICT_TRUE (if_add_index != ~0))
{
ip_interface_address_t *if_add =
pool_elt_at_index (lm->if_address_pool, if_add_index);
ip6_address_t *if_ip =
ip_interface_address_get_address (lm, if_add);
*src = *if_ip;
return (!0);
}
}
src->as_u64[0] = 0;
src->as_u64[1] = 0;
return (0);
}
int
ip6_link_set_local_address (u32 sw_if_index, const ip6_address_t * address)
{

Some files were not shown because too many files have changed in this diff Show More