blob: f42cf28f53e131a3e5a3787ef1719a732dc447fd [file] [log] [blame]
Neale Rannsd6953332021-08-10 07:39:18 +00001/*
2 * Copyright (c) 2016 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <vnet/fib/fib_table.h>
17#include <vnet/fib/fib_entry.h>
18#include <vnet/fib/ip4_fib.h>
19
20/*
21 * ip4_fib_hash_table_lookup_exact_match
22 *
23 * Exact match prefix lookup
24 */
25fib_node_index_t
26ip4_fib_hash_table_lookup_exact_match (const ip4_fib_hash_t *fib,
27 const ip4_address_t *addr,
28 u32 len)
29{
30 uword * hash, * result;
31 u32 key;
32
33 hash = fib->fib_entry_by_dst_address[len];
34 key = (addr->data_u32 & ip4_main.fib_masks[len]);
35
36 result = hash_get(hash, key);
37
38 if (NULL != result) {
39 return (result[0]);
40 }
41 return (FIB_NODE_INDEX_INVALID);
42}
43
44/*
45 * ip4_fib_hash_table_lookup_adj
46 *
47 * Longest prefix match
48 */
49index_t
50ip4_fib_hash_table_lookup_lb (const ip4_fib_hash_t *fib,
51 const ip4_address_t *addr)
52{
53 fib_node_index_t fei;
54
55 fei = ip4_fib_hash_table_lookup(fib, addr, 32);
56
57 if (FIB_NODE_INDEX_INVALID != fei)
58 {
59 const dpo_id_t *dpo;
60
61 dpo = fib_entry_contribute_ip_forwarding(fei);
62
63 return (dpo->dpoi_index);
64 }
65 return (INDEX_INVALID);
66}
67
68/*
69 * ip4_fib_hash_table_lookup
70 *
71 * Longest prefix match
72 */
73fib_node_index_t
74ip4_fib_hash_table_lookup (const ip4_fib_hash_t *fib,
75 const ip4_address_t *addr,
76 u32 len)
77{
78 uword * hash, * result;
79 i32 mask_len;
80 u32 key;
81
82 for (mask_len = len; mask_len >= 0; mask_len--)
83 {
84 hash = fib->fib_entry_by_dst_address[mask_len];
85 key = (addr->data_u32 & ip4_main.fib_masks[mask_len]);
86
87 result = hash_get (hash, key);
88
89 if (NULL != result) {
90 return (result[0]);
91 }
92 }
93 return (FIB_NODE_INDEX_INVALID);
94}
95
96void
97ip4_fib_hash_table_entry_insert (ip4_fib_hash_t *fib,
98 const ip4_address_t *addr,
99 u32 len,
100 fib_node_index_t fib_entry_index)
101{
102 uword * hash, * result;
103 u32 key;
104
105 key = (addr->data_u32 & ip4_main.fib_masks[len]);
106 hash = fib->fib_entry_by_dst_address[len];
107 result = hash_get (hash, key);
108
109 if (NULL == result) {
110 /*
111 * adding a new entry
112 */
113
114 if (NULL == hash) {
115 hash = hash_create (32 /* elts */, sizeof (uword));
116 hash_set_flags (hash, HASH_FLAG_NO_AUTO_SHRINK);
117
118 }
119 hash = hash_set(hash, key, fib_entry_index);
120 fib->fib_entry_by_dst_address[len] = hash;
121 }
122 else
123 {
124 ASSERT(0);
125 }
126}
127
128void
129ip4_fib_hash_table_entry_remove (ip4_fib_hash_t *fib,
130 const ip4_address_t *addr,
131 u32 len)
132{
133 uword * hash, * result;
134 u32 key;
135
136 key = (addr->data_u32 & ip4_main.fib_masks[len]);
137 hash = fib->fib_entry_by_dst_address[len];
138 result = hash_get (hash, key);
139
140 if (NULL == result)
141 {
142 /*
143 * removing a non-existent entry. i'll allow it.
144 */
145 }
146 else
147 {
148 hash_unset(hash, key);
149 }
150
151 fib->fib_entry_by_dst_address[len] = hash;
152}
153
154void
155ip4_fib_hash_table_walk (ip4_fib_hash_t *fib,
156 fib_table_walk_fn_t fn,
157 void *ctx)
158{
159 fib_prefix_t root = {
160 .fp_proto = FIB_PROTOCOL_IP4,
161 // address and length default to all 0
162 };
163
164 /*
165 * A full tree walk is the dengenerate case of a sub-tree from
166 * the very root
167 */
168 return (ip4_fib_hash_table_sub_tree_walk(fib, &root, fn, ctx));
169}
170
171void
172ip4_fib_hash_table_sub_tree_walk (ip4_fib_hash_t *fib,
173 const fib_prefix_t *root,
174 fib_table_walk_fn_t fn,
175 void *ctx)
176{
177 fib_prefix_t *sub_trees = NULL;
178 int i;
179
180 /*
181 * There is no efficient way to walk this array of hash tables.
182 * so we walk each table with a mask length greater than and equal to
183 * the required root and check it is covered by the root.
184 */
185 for (i = root->fp_len;
186 i < ARRAY_LEN (fib->fib_entry_by_dst_address);
187 i++)
188 {
189 uword * hash = fib->fib_entry_by_dst_address[i];
190
191 if (NULL != hash)
192 {
193 ip4_address_t key;
194 hash_pair_t * p;
195
196 hash_foreach_pair (p, hash,
197 ({
198 key.as_u32 = p->key;
199 if (ip4_destination_matches_route(&ip4_main,
200 &key,
201 &root->fp_addr.ip4,
202 root->fp_len))
203 {
204 const fib_prefix_t *sub_tree;
205 int skip = 0;
206
207 /*
208 * exclude sub-trees the walk does not want to explore
209 */
210 vec_foreach(sub_tree, sub_trees)
211 {
212 if (ip4_destination_matches_route(&ip4_main,
213 &key,
214 &sub_tree->fp_addr.ip4,
215 sub_tree->fp_len))
216 {
217 skip = 1;
218 break;
219 }
220 }
221
222 if (!skip)
223 {
224 switch (fn(p->value[0], ctx))
225 {
226 case FIB_TABLE_WALK_CONTINUE:
227 break;
228 case FIB_TABLE_WALK_SUB_TREE_STOP: {
229 fib_prefix_t pfx = {
230 .fp_proto = FIB_PROTOCOL_IP4,
231 .fp_len = i,
232 .fp_addr.ip4 = key,
233 };
234 vec_add1(sub_trees, pfx);
235 break;
236 }
237 case FIB_TABLE_WALK_STOP:
238 goto done;
239 }
240 }
241 }
242 }));
243 }
244 }
245done:
246 vec_free(sub_trees);
247 return;
248}
249