summaryrefslogtreecommitdiffstats
path: root/src/vnet/fib/fib_path.h
blob: c0f764113904724dfd601912daf73c8a9e060a97 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
/*
 * Copyright (c) 2016 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.
 */

/**
 * Given a route of the form;
 *   q.r.s.t/Y
 *     via <interface> <next-hop>
 *
 * The prefix is: q.r.s.t./Y
 * the path is: 'via <interface> <next-hop>
 *
 * The path is the description of where to send the traffic, and the
 * the prefix is a description of which traffic to send.
 * It is the aim of the FIB to resolve the path, i.e. to find the corresponding
 * adjacency to match the path's description.
 */

#ifndef __FIB_PATH_H__
#define __FIB_PATH_H__

#include <vnet/ip/ip.h>
#include <vnet/dpo/load_balance.h>

#include <vnet/fib/fib_types.h>
#include <vnet/adj/adj_types.h>
#include <vnet/bier/bier_types.h>

/**
 * Enurmeration of path configuration attributes
 */
typedef enum fib_path_cfg_attribute_t_ {
    /**
     * Marker. Add new types after this one.
     */
    FIB_PATH_CFG_ATTRIBUTE_FIRST = 0,
    /**
     * The path is forced to a drop, whatever the next-hop info says.
     * something somewhere knows better...
     */
    FIB_PATH_CFG_ATTRIBUTE_DROP = FIB_PATH_CFG_ATTRIBUTE_FIRST,
    /**
     * The path uses an adj that is exclusive. I.e. it is known only by
     * the source of the route.
     */
    FIB_PATH_CFG_ATTRIBUTE_EXCLUSIVE,
    /**
     * Recursion constraint via host
     */
    FIB_PATH_CFG_ATTRIBUTE_RESOLVE_HOST,
    /**
     * Recursion constraint via attached
     */
    FIB_PATH_CFG_ATTRIBUTE_RESOLVE_ATTACHED,
    /**
     * The path is attached
     */
    FIB_PATH_CFG_ATTRIBUTE_ATTACHED,
    /**
     * The path is a for-us path
     */
    FIB_PATH_CFG_ATTRIBUTE_INTF_RX,
    /**
     * The path is a deag with rpf-id
     */
    FIB_PATH_CFG_ATTRIBUTE_RPF_ID,
    /**
     * The path is an interface recieve
     */
    FIB_PATH_CFG_ATTRIBUTE_LOCAL,
    /**
     * The path reolves via an ICMP unreachable
     */
    FIB_PATH_CFG_ATTRIBUTE_ICMP_UNREACH,
    /**
     * The path reolves via an ICMP prohibit
     */
    FIB_PATH_CFG_ATTRIBUTE_ICMP_PROHIBIT,
    /**
     * The path reolves via a classify
     */
    FIB_PATH_CFG_ATTRIBUTE_CLASSIFY,
    /**
     * The deag path does a source lookup
     */
    FIB_PATH_CFG_ATTRIBUTE_DEAG_SRC,
    /**
     * 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_GLEAN,
} __attribute__ ((packed)) fib_path_cfg_attribute_t;

/**
 * The maximum number of path attributes
 */
#define FIB_PATH_CFG_ATTRIBUTE_MAX (FIB_PATH_CFG_ATTRIBUTE_LAST + 1)

#define FIB_PATH_CFG_ATTRIBUTES {			\
    [FIB_PATH_CFG_ATTRIBUTE_DROP]  = "drop",	        \
    [FIB_PATH_CFG_ATTRIBUTE_EXCLUSIVE] = "exclusive",	\
    [FIB_PATH_CFG_ATTRIBUTE_RESOLVE_HOST] = "resolve-host", \
    [FIB_PATH_CFG_ATTRIBUTE_RESOLVE_ATTACHED] = "resolve-attached", \
    [FIB_PATH_CFG_ATTRIBUTE_LOCAL] = "local",	        \
    [FIB_PATH_CFG_ATTRIBUTE_ICMP_UNREACH] = "icmp-unreach",   \
    [FIB_PATH_CFG_ATTRIBUTE_ICMP_PROHIBIT] = "icmp-prohibit", \
    [FIB_PATH_CFG_ATTRIBUTE_CLASSIFY] = "classify", \
    [FIB_PATH_CFG_ATTRIBUTE_ATTACHED] = "attached",	\
    [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_GLEAN] = "glean",           \
}

#define FOR_EACH_FIB_PATH_CFG_ATTRIBUTE(_item) \
    for (_item = FIB_PATH_CFG_ATTRIBUTE_FIRST; \
	 _item <= FIB_PATH_CFG_ATTRIBUTE_LAST; \
	 _item++)

/**
 * Path config flags from the attributes
 */
typedef enum fib_path_cfg_flags_t_ {
    FIB_PATH_CFG_FLAG_NONE  = 0,
    FIB_PATH_CFG_FLAG_DROP  = (1 << FIB_PATH_CFG_ATTRIBUTE_DROP),
    FIB_PATH_CFG_FLAG_EXCLUSIVE = (1 << FIB_PATH_CFG_ATTRIBUTE_EXCLUSIVE),
    FIB_PATH_CFG_FLAG_RESOLVE_HOST = (1 << FIB_PATH_CFG_ATTRIBUTE_RESOLVE_HOST),
    FIB_PATH_CFG_FLAG_RESOLVE_ATTACHED = (1 << FIB_PATH_CFG_ATTRIBUTE_RESOLVE_ATTACHED),
    FIB_PATH_CFG_FLAG_LOCAL = (1 << FIB_PATH_CFG_ATTRIBUTE_LOCAL),
    FIB_PATH_CFG_FLAG_ICMP_UNREACH = (1 << FIB_PATH_CFG_ATTRIBUTE_ICMP_UNREACH),
    FIB_PATH_CFG_FLAG_ICMP_PROHIBIT = (1 << FIB_PATH_CFG_ATTRIBUTE_ICMP_PROHIBIT),
    FIB_PATH_CFG_FLAG_CLASSIFY = (1 << FIB_PATH_CFG_ATTRIBUTE_CLASSIFY),
    FIB_PATH_CFG_FLAG_ATTACHED = (1 << FIB_PATH_CFG_ATTRIBUTE_ATTACHED),
    FIB_PATH_CFG_FLAG_INTF_RX = (1 << FIB_PATH_CFG_ATTRIBUTE_INTF_RX),
    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_
{
    FIB_PATH_FORMAT_FLAGS_NONE = 0,
    FIB_PATH_FORMAT_FLAGS_ONE_LINE = (1 << 0),
} fib_format_path_flags_t;

extern u8 *format_fib_path(u8 *s, va_list *args);

extern fib_node_index_t fib_path_create(fib_node_index_t pl_index,
					const fib_route_path_t *path);
extern fib_node_index_t fib_path_create_special(fib_node_index_t pl_index,
						dpo_proto_t nh_proto,
						fib_path_cfg_flags_t flags,
						const dpo_id_t *dpo);

extern int fib_path_cmp(fib_node_index_t path_index1,
			fib_node_index_t path_index2);
extern int fib_path_cmp_for_sort(void * a1, void * a2);
extern int fib_path_cmp_w_route_path(fib_node_index_t path_index,
				     const fib_route_path_t *rpath);
extern fib_node_index_t fib_path_copy(fib_node_index_t path_index,
				      fib_node_index_t path_list_index);
extern int fib_path_resolve(fib_node_index_t path_index);
extern int fib_path_is_resolved(fib_node_index_t path_index);
extern int fib_path_is_recursive_constrained(fib_node_index_t path_index);
extern int fib_path_is_exclusive(fib_node_index_t path_index);
extern int fib_path_is_deag(fib_node_index_t path_index);
extern int fib_path_is_looped(fib_node_index_t path_index);
extern dpo_proto_t fib_path_get_proto(fib_node_index_t path_index);
extern void fib_path_destroy(fib_node_index_t path_index);
extern uword fib_path_hash(fib_node_index_t path_index);
extern load_balance_path_t * fib_path_append_nh_for_multipath_hash(
    fib_node_index_t path_index,
    fib_forward_chain_type_t fct,
    load_balance_path_t *hash_key);
extern void fib_path_stack_mpls_disp(fib_node_index_t path_index,
                                     dpo_proto_t payload_proto,
                                     fib_mpls_lsp_mode_t mode,
                                     dpo_id_t *dpo);
extern void fib_path_contribute_forwarding(fib_node_index_t path_index,
					   fib_forward_chain_type_t type,
					   dpo_id_t *dpo);
extern void fib_path_contribute_urpf(fib_node_index_t path_index,
				     index_t urpf);
extern adj_index_t fib_path_get_adj(fib_node_index_t path_index);
extern int fib_path_recursive_loop_detect(fib_node_index_t path_index,
					  fib_node_index_t **entry_indicies);
extern u32 fib_path_get_resolving_interface(fib_node_index_t fib_entry_index);
extern index_t fib_path_get_resolving_index(fib_node_index_t path_index);
extern u16 fib_path_get_weight(fib_node_index_t path_index);
extern u16 fib_path_get_preference(fib_node_index_t path_index);
extern u32 fib_path_get_rpf_id(fib_node_index_t path_index);

extern void fib_path_module_init(void);

/**
 * Path encode context to use when walking a path-list
 * to encode paths
 */
typedef struct fib_path_encode_ctx_t_
{
    fib_route_path_t *rpaths;
} fib_path_encode_ctx_t;

extern fib_path_list_walk_rc_t fib_path_encode(fib_node_index_t path_list_index,
                                               fib_node_index_t path_index,
                                               const struct fib_path_ext_t_ *ext_list,
                                               void *ctx);

#endif
">.fp_len = 10; fib_table_entry_special_dpo_add(fib_index, &pfx, FIB_SOURCE_SPECIAL, FIB_ENTRY_FLAG_NONE, ip6_ll_dpo_get()); } static u32 create_fib_with_table_id (u32 table_id, fib_source_t src, fib_table_flags_t flags, u8 *desc) { fib_table_t *fib_table; ip6_fib_t *v6_fib; pool_get(ip6_main.fibs, fib_table); pool_get_aligned(ip6_main.v6_fibs, v6_fib, CLIB_CACHE_LINE_BYTES); memset(fib_table, 0, sizeof(*fib_table)); memset(v6_fib, 0, sizeof(*v6_fib)); ASSERT((fib_table - ip6_main.fibs) == (v6_fib - ip6_main.v6_fibs)); fib_table->ft_proto = FIB_PROTOCOL_IP6; fib_table->ft_index = v6_fib->index = (fib_table - ip6_main.fibs); hash_set(ip6_main.fib_index_by_table_id, table_id, fib_table->ft_index); fib_table->ft_table_id = v6_fib->table_id = table_id; fib_table->ft_flow_hash_config = IP_FLOW_HASH_DEFAULT; fib_table->ft_flags = flags; fib_table->ft_desc = desc; vnet_ip6_fib_init(fib_table->ft_index); fib_table_lock(fib_table->ft_index, FIB_PROTOCOL_IP6, src); return (fib_table->ft_index); } u32 ip6_fib_table_find_or_create_and_lock (u32 table_id, fib_source_t src) { uword * p; p = hash_get (ip6_main.fib_index_by_table_id, table_id); if (NULL == p) return create_fib_with_table_id(table_id, src, FIB_TABLE_FLAG_NONE, NULL); fib_table_lock(p[0], FIB_PROTOCOL_IP6, src); return (p[0]); } u32 ip6_fib_table_create_and_lock (fib_source_t src, fib_table_flags_t flags, u8 *desc) { return (create_fib_with_table_id(~0, src, flags, desc)); } void ip6_fib_table_destroy (u32 fib_index) { /* * all link local first ... */ fib_prefix_t pfx = { .fp_proto = FIB_PROTOCOL_IP6, .fp_len = 10, .fp_addr = { .ip6 = { .as_u8 = { [0] = 0xFE, [1] = 0x80, }, }, } }; fib_table_entry_delete(fib_index, &pfx, FIB_SOURCE_SPECIAL); /* * ... then the default route. */ pfx.fp_addr.ip6.as_u64[0] = 0; pfx.fp_len = 00; fib_table_entry_special_remove(fib_index, &pfx, FIB_SOURCE_DEFAULT_ROUTE); fib_table_t *fib_table = fib_table_get(fib_index, FIB_PROTOCOL_IP6); fib_source_t source; /* * validate no more routes. */ ASSERT(0 == fib_table->ft_total_route_counts); FOR_EACH_FIB_SOURCE(source) { ASSERT(0 == fib_table->ft_src_route_counts[source]); } if (~0 != fib_table->ft_table_id) { hash_unset (ip6_main.fib_index_by_table_id, fib_table->ft_table_id); } pool_put_index(ip6_main.v6_fibs, fib_table->ft_index); pool_put(ip6_main.fibs, fib_table); } fib_node_index_t ip6_fib_table_lookup (u32 fib_index, const ip6_address_t *addr, u32 len) { ip6_fib_table_instance_t *table; BVT(clib_bihash_kv) kv, value; int i, n_p, rv; u64 fib; table = &ip6_main.ip6_table[IP6_FIB_TABLE_NON_FWDING]; n_p = vec_len (table->prefix_lengths_in_search_order); kv.key[0] = addr->as_u64[0]; kv.key[1] = addr->as_u64[1]; fib = ((u64)((fib_index))<<32); /* * start search from a mask length same length or shorter. * we don't want matches longer than the mask passed */ i = 0; while (i < n_p && table->prefix_lengths_in_search_order[i] > len) { i++; } for (; i < n_p; i++) { int dst_address_length = table->prefix_lengths_in_search_order[i]; ip6_address_t * mask = &ip6_main.fib_masks[dst_address_length]; ASSERT(dst_address_length >= 0 && dst_address_length <= 128); //As lengths are decreasing, masks are increasingly specific. kv.key[0] &= mask->as_u64[0]; kv.key[1] &= mask->as_u64[1]; kv.key[2] = fib | dst_address_length; rv = BV(clib_bihash_search_inline_2)(&table->ip6_hash, &kv, &value); if (rv == 0) return value.value; } return (FIB_NODE_INDEX_INVALID); } fib_node_index_t ip6_fib_table_lookup_exact_match (u32 fib_index, const ip6_address_t *addr, u32 len) { ip6_fib_table_instance_t *table; BVT(clib_bihash_kv) kv, value; ip6_address_t *mask; u64 fib; int rv; table = &ip6_main.ip6_table[IP6_FIB_TABLE_NON_FWDING]; mask = &ip6_main.fib_masks[len]; fib = ((u64)((fib_index))<<32); kv.key[0] = addr->as_u64[0] & mask->as_u64[0]; kv.key[1] = addr->as_u64[1] & mask->as_u64[1]; kv.key[2] = fib | len; rv = BV(clib_bihash_search_inline_2)(&table->ip6_hash, &kv, &value); if (rv == 0) return value.value; return (FIB_NODE_INDEX_INVALID); } static void compute_prefix_lengths_in_search_order (ip6_fib_table_instance_t *table) { int i; vec_reset_length (table->prefix_lengths_in_search_order); /* Note: bitmap reversed so this is in fact a longest prefix match */ clib_bitmap_foreach (i, table->non_empty_dst_address_length_bitmap, ({ int dst_address_length = 128 - i; vec_add1(table->prefix_lengths_in_search_order, dst_address_length); })); } void ip6_fib_table_entry_remove (u32 fib_index, const ip6_address_t *addr, u32 len) { ip6_fib_table_instance_t *table; BVT(clib_bihash_kv) kv; ip6_address_t *mask; u64 fib; table = &ip6_main.ip6_table[IP6_FIB_TABLE_NON_FWDING]; mask = &ip6_main.fib_masks[len]; fib = ((u64)((fib_index))<<32); kv.key[0] = addr->as_u64[0] & mask->as_u64[0]; kv.key[1] = addr->as_u64[1] & mask->as_u64[1]; kv.key[2] = fib | len; BV(clib_bihash_add_del)(&table->ip6_hash, &kv, 0); /* refcount accounting */ ASSERT (table->dst_address_length_refcounts[len] > 0); if (--table->dst_address_length_refcounts[len] == 0) { table->non_empty_dst_address_length_bitmap = clib_bitmap_set (table->non_empty_dst_address_length_bitmap, 128 - len, 0); compute_prefix_lengths_in_search_order (table); } } void ip6_fib_table_entry_insert (u32 fib_index, const ip6_address_t *addr, u32 len, fib_node_index_t fib_entry_index) { ip6_fib_table_instance_t *table; BVT(clib_bihash_kv) kv; ip6_address_t *mask; u64 fib; table = &ip6_main.ip6_table[IP6_FIB_TABLE_NON_FWDING]; mask = &ip6_main.fib_masks[len]; fib = ((u64)((fib_index))<<32); kv.key[0] = addr->as_u64[0] & mask->as_u64[0]; kv.key[1] = addr->as_u64[1] & mask->as_u64[1]; kv.key[2] = fib | len; kv.value = fib_entry_index; BV(clib_bihash_add_del)(&table->ip6_hash, &kv, 1); table->dst_address_length_refcounts[len]++; table->non_empty_dst_address_length_bitmap = clib_bitmap_set (table->non_empty_dst_address_length_bitmap, 128 - len, 1); compute_prefix_lengths_in_search_order (table); } u32 ip6_fib_table_fwding_lookup_with_if_index (ip6_main_t * im, u32 sw_if_index, const ip6_address_t * dst) { u32 fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index); return ip6_fib_table_fwding_lookup(im, fib_index, dst); } u32 ip6_fib_table_get_index_for_sw_if_index (u32 sw_if_index) { if (sw_if_index >= vec_len(ip6_main.fib_index_by_sw_if_index)) { /* * This is the case for interfaces that are not yet mapped to * a IP table */ return (~0); } return (ip6_main.fib_index_by_sw_if_index[sw_if_index]); } void ip6_fib_table_fwding_dpo_update (u32 fib_index, const ip6_address_t *addr, u32 len, const dpo_id_t *dpo) { ip6_fib_table_instance_t *table; BVT(clib_bihash_kv) kv; ip6_address_t *mask; u64 fib; table = &ip6_main.ip6_table[IP6_FIB_TABLE_FWDING]; mask = &ip6_main.fib_masks[len]; fib = ((u64)((fib_index))<<32); kv.key[0] = addr->as_u64[0] & mask->as_u64[0]; kv.key[1] = addr->as_u64[1] & mask->as_u64[1]; kv.key[2] = fib | len; kv.value = dpo->dpoi_index; BV(clib_bihash_add_del)(&table->ip6_hash, &kv, 1); table->dst_address_length_refcounts[len]++; table->non_empty_dst_address_length_bitmap = clib_bitmap_set (table->non_empty_dst_address_length_bitmap, 128 - len, 1); compute_prefix_lengths_in_search_order (table); } void ip6_fib_table_fwding_dpo_remove (u32 fib_index, const ip6_address_t *addr, u32 len, const dpo_id_t *dpo) { ip6_fib_table_instance_t *table; BVT(clib_bihash_kv) kv; ip6_address_t *mask; u64 fib; table = &ip6_main.ip6_table[IP6_FIB_TABLE_FWDING]; mask = &ip6_main.fib_masks[len]; fib = ((u64)((fib_index))<<32); kv.key[0] = addr->as_u64[0] & mask->as_u64[0]; kv.key[1] = addr->as_u64[1] & mask->as_u64[1]; kv.key[2] = fib | len; kv.value = dpo->dpoi_index; BV(clib_bihash_add_del)(&table->ip6_hash, &kv, 0); /* refcount accounting */ ASSERT (table->dst_address_length_refcounts[len] > 0); if (--table->dst_address_length_refcounts[len] == 0) { table->non_empty_dst_address_length_bitmap = clib_bitmap_set (table->non_empty_dst_address_length_bitmap, 128 - len, 0); compute_prefix_lengths_in_search_order (table); } } /** * @brief Context when walking the IPv6 table. Since all VRFs are in the * same hash table, we need to filter only those we need as we walk */ typedef struct ip6_fib_walk_ctx_t_ { u32 i6w_fib_index; fib_table_walk_fn_t i6w_fn; void *i6w_ctx; fib_prefix_t i6w_root; fib_prefix_t *i6w_sub_trees; } ip6_fib_walk_ctx_t; static int ip6_fib_walk_cb (clib_bihash_kv_24_8_t * kvp, void *arg) { ip6_fib_walk_ctx_t *ctx = arg; ip6_address_t key; if ((kvp->key[2] >> 32) == ctx->i6w_fib_index) { key.as_u64[0] = kvp->key[0]; key.as_u64[1] = kvp->key[1]; if (ip6_destination_matches_route(&ip6_main, &key, &ctx->i6w_root.fp_addr.ip6, ctx->i6w_root.fp_len)) { const fib_prefix_t *sub_tree; int skip = 0; /* * exclude sub-trees the walk does not want to explore */ vec_foreach(sub_tree, ctx->i6w_sub_trees) { if (ip6_destination_matches_route(&ip6_main, &key, &sub_tree->fp_addr.ip6, sub_tree->fp_len)) { skip = 1; break; } } if (!skip) { switch (ctx->i6w_fn(kvp->value, ctx->i6w_ctx)) { case FIB_TABLE_WALK_CONTINUE: break; case FIB_TABLE_WALK_SUB_TREE_STOP: { fib_prefix_t pfx = { .fp_proto = FIB_PROTOCOL_IP6, .fp_len = kvp->key[2] & 0xffffffff, .fp_addr.ip6 = key, }; vec_add1(ctx->i6w_sub_trees, pfx); break; } case FIB_TABLE_WALK_STOP: goto done; } } } } done: return (1); } void ip6_fib_table_walk (u32 fib_index, fib_table_walk_fn_t fn, void *arg) { ip6_fib_walk_ctx_t ctx = { .i6w_fib_index = fib_index, .i6w_fn = fn, .i6w_ctx = arg, .i6w_root = { .fp_proto = FIB_PROTOCOL_IP6, }, .i6w_sub_trees = NULL, }; BV(clib_bihash_foreach_key_value_pair)( &ip6_main.ip6_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash, ip6_fib_walk_cb, &ctx); vec_free(ctx.i6w_sub_trees); } void ip6_fib_table_sub_tree_walk (u32 fib_index, const fib_prefix_t *root, fib_table_walk_fn_t fn, void *arg) { ip6_fib_walk_ctx_t ctx = { .i6w_fib_index = fib_index, .i6w_fn = fn, .i6w_ctx = arg, .i6w_root = *root, }; BV(clib_bihash_foreach_key_value_pair)( &ip6_main.ip6_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash, ip6_fib_walk_cb, &ctx); } typedef struct ip6_fib_show_ctx_t_ { fib_node_index_t *entries; } ip6_fib_show_ctx_t; static fib_table_walk_rc_t ip6_fib_table_show_walk (fib_node_index_t fib_entry_index, void *arg) { ip6_fib_show_ctx_t *ctx = arg; vec_add1(ctx->entries, fib_entry_index); return (FIB_TABLE_WALK_CONTINUE); } static void ip6_fib_table_show_all (ip6_fib_t *fib, vlib_main_t * vm) { fib_node_index_t *fib_entry_index; ip6_fib_show_ctx_t ctx = { .entries = NULL, }; ip6_fib_table_walk(fib->index, ip6_fib_table_show_walk, &ctx); vec_sort_with_function(ctx.entries, fib_entry_cmp_for_sort); vec_foreach(fib_entry_index, ctx.entries) { vlib_cli_output(vm, "%U", format_fib_entry, *fib_entry_index, FIB_ENTRY_FORMAT_BRIEF); } vec_free(ctx.entries); } static void ip6_fib_table_show_one (ip6_fib_t *fib, vlib_main_t * vm, ip6_address_t *address, u32 mask_len, int detail) { vlib_cli_output(vm, "%U", format_fib_entry, ip6_fib_table_lookup(fib->index, address, mask_len), (detail ? FIB_ENTRY_FORMAT_DETAIL2: FIB_ENTRY_FORMAT_DETAIL)); } u8 * format_ip6_fib_table_memory (u8 * s, va_list * args) { uword bytes_inuse; bytes_inuse = ip6_main.ip6_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash.alloc_arena_next - ip6_main.ip6_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash.alloc_arena; bytes_inuse += ip6_main.ip6_table[IP6_FIB_TABLE_FWDING].ip6_hash.alloc_arena_next - ip6_main.ip6_table[IP6_FIB_TABLE_FWDING].ip6_hash.alloc_arena; s = format(s, "%=30s %=6d %=8ld\n", "IPv6 unicast", pool_elts(ip6_main.fibs), bytes_inuse); return (s); } typedef struct { u32 fib_index; u64 count_by_prefix_length[129]; } count_routes_in_fib_at_prefix_length_arg_t; static void count_routes_in_fib_at_prefix_length (BVT(clib_bihash_kv) * kvp, void *arg) { count_routes_in_fib_at_prefix_length_arg_t * ap = arg; int mask_width; if ((kvp->key[2]>>32) != ap->fib_index) return; mask_width = kvp->key[2] & 0xFF; ap->count_by_prefix_length[mask_width]++; } static clib_error_t * ip6_show_fib (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { count_routes_in_fib_at_prefix_length_arg_t _ca, *ca = &_ca; ip6_main_t * im6 = &ip6_main; fib_table_t *fib_table; ip6_fib_t * fib; int verbose, matching; ip6_address_t matching_address; u32 mask_len = 128; int table_id = -1, fib_index = ~0; int detail = 0; verbose = 1; matching = 0; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { if (unformat (input, "brief") || unformat (input, "summary") || unformat (input, "sum")) verbose = 0; else if (unformat (input, "detail") || unformat (input, "det")) detail = 1; else if (unformat (input, "%U/%d", unformat_ip6_address, &matching_address, &mask_len)) matching = 1; else if (unformat (input, "%U", unformat_ip6_address, &matching_address)) matching = 1; else if (unformat (input, "table %d", &table_id)) ; else if (unformat (input, "index %d", &fib_index)) ; else break; } pool_foreach (fib_table, im6->fibs, ({ fib_source_t source; u8 *s = NULL; fib = pool_elt_at_index(im6->v6_fibs, fib_table->ft_index); if (table_id >= 0 && table_id != (int)fib->table_id) continue; if (fib_index != ~0 && fib_index != (int)fib->index) continue; if (fib_table->ft_flags & FIB_TABLE_FLAG_IP6_LL) continue; s = format(s, "%U, fib_index:%d, flow hash:[%U] locks:[", format_fib_table_name, fib->index, FIB_PROTOCOL_IP6, fib->index, format_ip_flow_hash_config, fib_table->ft_flow_hash_config); FOR_EACH_FIB_SOURCE(source) { if (0 != fib_table->ft_locks[source]) { s = format(s, "%U:%d, ", format_fib_source, source, fib_table->ft_locks[source]); } } s = format (s, "]"); vlib_cli_output (vm, "%v", s); vec_free(s); /* Show summary? */ if (! verbose) { BVT(clib_bihash) * h = &im6->ip6_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash; int len; vlib_cli_output (vm, "%=20s%=16s", "Prefix length", "Count"); memset (ca, 0, sizeof(*ca)); ca->fib_index = fib->index; BV(clib_bihash_foreach_key_value_pair) (h, count_routes_in_fib_at_prefix_length, ca); for (len = 128; len >= 0; len--) { if (ca->count_by_prefix_length[len]) vlib_cli_output (vm, "%=20d%=16lld", len, ca->count_by_prefix_length[len]); } continue; } if (!matching) { ip6_fib_table_show_all(fib, vm); } else { ip6_fib_table_show_one(fib, vm, &matching_address, mask_len, detail); } })); return 0; } /*? * This command displays the IPv6 FIB Tables (VRF Tables) and the route * entries for each table. * * @note This command will run for a long time when the FIB tables are * comprised of millions of entries. For those senarios, consider displaying * in summary mode. * * @cliexpar * @parblock * Example of how to display all the IPv6 FIB tables: * @cliexstart{show ip6 fib} * ipv6-VRF:0, fib_index 0, flow hash: src dst sport dport proto * @::/0 * unicast-ip6-chain * [@0]: dpo-load-balance: [index:5 buckets:1 uRPF:5 to:[0:0]] * [0] [@0]: dpo-drop ip6 * fe80::/10 * unicast-ip6-chain * [@0]: dpo-load-balance: [index:10 buckets:1 uRPF:10 to:[0:0]] * [0] [@2]: dpo-receive * ff02::1/128 * unicast-ip6-chain * [@0]: dpo-load-balance: [index:8 buckets:1 uRPF:8 to:[0:0]] * [0] [@2]: dpo-receive * ff02::2/128 * unicast-ip6-chain * [@0]: dpo-load-balance: [index:7 buckets:1 uRPF:7 to:[0:0]] * [0] [@2]: dpo-receive * ff02::16/128 * unicast-ip6-chain * [@0]: dpo-load-balance: [index:9 buckets:1 uRPF:9 to:[0:0]] * [0] [@2]: dpo-receive * ff02::1:ff00:0/104 * unicast-ip6-chain * [@0]: dpo-load-balance: [index:6 buckets:1 uRPF:6 to:[0:0]] * [0] [@2]: dpo-receive * ipv6-VRF:8, fib_index 1, flow hash: src dst sport dport proto * @::/0 * unicast-ip6-chain * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]] * [0] [@0]: dpo-drop ip6 * @::a:1:1:0:4/126 * unicast-ip6-chain * [@0]: dpo-load-balance: [index:27 buckets:1 uRPF:26 to:[0:0]] * [0] [@4]: ipv6-glean: af_packet0 * @::a:1:1:0:7/128 * unicast-ip6-chain * [@0]: dpo-load-balance: [index:28 buckets:1 uRPF:27 to:[0:0]] * [0] [@2]: dpo-receive: @::a:1:1:0:7 on af_packet0 * fe80::/10 * unicast-ip6-chain * [@0]: dpo-load-balance: [index:26 buckets:1 uRPF:25 to:[0:0]] * [0] [@2]: dpo-receive * fe80::fe:3eff:fe3e:9222/128 * unicast-ip6-chain * [@0]: dpo-load-balance: [index:29 buckets:1 uRPF:28 to:[0:0]] * [0] [@2]: dpo-receive: fe80::fe:3eff:fe3e:9222 on af_packet0 * ff02::1/128 * unicast-ip6-chain * [@0]: dpo-load-balance: [index:24 buckets:1 uRPF:23 to:[0:0]] * [0] [@2]: dpo-receive * ff02::2/128 * unicast-ip6-chain * [@0]: dpo-load-balance: [index:23 buckets:1 uRPF:22 to:[0:0]] * [0] [@2]: dpo-receive * ff02::16/128 * unicast-ip6-chain * [@0]: dpo-load-balance: [index:25 buckets:1 uRPF:24 to:[0:0]] * [0] [@2]: dpo-receive * ff02::1:ff00:0/104 * unicast-ip6-chain * [@0]: dpo-load-balance: [index:22 buckets:1 uRPF:21 to:[0:0]] * [0] [@2]: dpo-receive * @cliexend * * Example of how to display a summary of all IPv6 FIB tables: * @cliexstart{show ip6 fib summary} * ipv6-VRF:0, fib_index 0, flow hash: src dst sport dport proto * Prefix length Count * 128 3 * 104 1 * 10 1 * 0 1 * ipv6-VRF:8, fib_index 1, flow hash: src dst sport dport proto * Prefix length Count * 128 5 * 126 1 * 104 1 * 10 1 * 0 1 * @cliexend * @endparblock ?*/ /* *INDENT-OFF* */ VLIB_CLI_COMMAND (ip6_show_fib_command, static) = { .path = "show ip6 fib", .short_help = "show ip6 fib [summary] [table <table-id>] [index <fib-id>] [<ip6-addr>[/<width>]] [detail]", .function = ip6_show_fib, }; /* *INDENT-ON* */