blob: 5ea96fd0cf6f672c55402ef1c13181b15efa5902 [file] [log] [blame]
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001/*
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_entry.h>
17#include <vnet/fib/fib_table.h>
18
Neale Rannsad422ed2016-11-02 14:20:04 +000019#include <vnet/fib/fib_attached_export.h>
20#include <vnet/fib/fib_entry_cover.h>
21#include <vnet/fib/fib_entry_src.h>
22#include <vnet/fib/fib_entry_delegate.h>
Neale Ranns2303cb12018-02-21 04:57:17 -080023#include <vnet/dpo/drop_dpo.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010024
25/**
26 * A description of the need to import routes from the export table
27 */
28typedef struct fib_ae_import_t_
29{
30 /**
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -070031 * The entry in the export table that this importer
Neale Ranns0bfe5d82016-08-25 15:29:12 +010032 * is importing covereds from
33 */
34 fib_node_index_t faei_export_entry;
35
36 /**
37 * The attached entry in the import table
38 */
39 fib_node_index_t faei_import_entry;
40 /**
41 * the sibling index on the cover
42 */
43 u32 faei_export_sibling;
44
45 /**
46 * The index of the exporter tracker. Not set if the
47 * export entry is not valid for export
48 */
49 fib_node_index_t faei_exporter;
50
51 /**
52 * A vector/list of imported entry indicies
53 */
54 fib_node_index_t *faei_importeds;
55
56 /**
57 * The FIB index and prefix we are tracking
58 */
59 fib_node_index_t faei_export_fib;
60 fib_prefix_t faei_prefix;
61
62 /**
63 * The FIB index we are importing into
64 */
65 fib_node_index_t faei_import_fib;
66} fib_ae_import_t;
67
68/**
69 * A description of the need to export routes to one or more export tables
70 */
71typedef struct fib_ae_export_t_ {
72 /**
73 * The vector/list of import tracker indicies
74 */
75 fib_node_index_t *faee_importers;
76
77 /**
78 * THe connected entry this export is acting on behalf of
79 */
80 fib_node_index_t faee_ei;
81
82 /**
83 * Reference counting locks
84 */
85 u32 faee_locks;
86} fib_ae_export_t;
87
88/*
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -070089 * memory pools for the importers and exporters
Neale Ranns0bfe5d82016-08-25 15:29:12 +010090 */
91static fib_ae_import_t *fib_ae_import_pool;
92static fib_ae_export_t *fib_ae_export_pool;
93
94static fib_ae_export_t *
95fib_entry_ae_add_or_lock (fib_node_index_t connected)
96{
Neale Rannsad422ed2016-11-02 14:20:04 +000097 fib_entry_delegate_t *fed;
Neale Ranns0bfe5d82016-08-25 15:29:12 +010098 fib_ae_export_t *export;
99 fib_entry_t *entry;
100
101 entry = fib_entry_get(connected);
Neale Ranns1f50bf82019-07-16 15:28:52 +0000102 fed = fib_entry_delegate_find(entry,
103 FIB_ENTRY_DELEGATE_ATTACHED_EXPORT);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100104
Neale Rannsad422ed2016-11-02 14:20:04 +0000105 if (NULL == fed)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100106 {
Neale Rannsad422ed2016-11-02 14:20:04 +0000107 fed = fib_entry_delegate_find_or_add(entry,
108 FIB_ENTRY_DELEGATE_ATTACHED_EXPORT);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100109 pool_get(fib_ae_export_pool, export);
Dave Barachb7b92992018-10-17 10:38:51 -0400110 clib_memset(export, 0, sizeof(*export));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100111
Neale Rannsad422ed2016-11-02 14:20:04 +0000112 fed->fd_index = (export - fib_ae_export_pool);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100113 export->faee_ei = connected;
114 }
115 else
116 {
Neale Rannsad422ed2016-11-02 14:20:04 +0000117 export = pool_elt_at_index(fib_ae_export_pool, fed->fd_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100118 }
119
120 export->faee_locks++;
121
122 return (export);
123}
124
125static void
126fib_entry_import_remove (fib_ae_import_t *import,
127 fib_node_index_t entry_index)
128{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100129 u32 index;
130
131 /*
132 * find the index in the vector of the entry we are removing
133 */
134 index = vec_search(import->faei_importeds, entry_index);
135
136 if (index < vec_len(import->faei_importeds))
137 {
138 /*
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700139 * this is an entry that was previously imported
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100140 */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100141 fib_table_entry_special_remove(import->faei_import_fib,
Neale Rannsc5d43172018-07-30 08:04:40 -0700142 fib_entry_get_prefix(entry_index),
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100143 FIB_SOURCE_AE);
144
145 fib_entry_unlock(entry_index);
146 vec_del1(import->faei_importeds, index);
147 }
148}
149
150static void
151fib_entry_import_add (fib_ae_import_t *import,
152 fib_node_index_t entry_index)
153{
154 fib_node_index_t *existing;
Neale Ranns320dfcf2019-11-06 11:17:54 +0000155 fib_prefix_t prefix;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100156
157 /*
158 * ensure we only add the exported entry once, since
159 * sourcing prefixes in the table is reference counted
160 */
161 vec_foreach(existing, import->faei_importeds)
162 {
163 if (*existing == entry_index)
164 {
165 return;
166 }
167 }
168
169 /*
170 * this is the first time this export entry has been imported
Neale Ranns320dfcf2019-11-06 11:17:54 +0000171 * Add it to the import FIB and to the list of importeds.
172 * make a copy of the prefix in case the underlying entry reallocs.
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100173 */
Neale Ranns320dfcf2019-11-06 11:17:54 +0000174 fib_prefix_copy(&prefix, fib_entry_get_prefix(entry_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100175
176 /*
177 * don't import entries that have the same prefix the import entry
178 */
Neale Ranns320dfcf2019-11-06 11:17:54 +0000179 if (0 != fib_prefix_cmp(&prefix, &import->faei_prefix))
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100180 {
181 const dpo_id_t *dpo;
182
183 dpo = fib_entry_contribute_ip_forwarding(entry_index);
184
Neale Ranns2303cb12018-02-21 04:57:17 -0800185 if (dpo_id_is_valid(dpo) && !dpo_is_drop(dpo))
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100186 {
187 fib_table_entry_special_dpo_add(import->faei_import_fib,
Neale Ranns320dfcf2019-11-06 11:17:54 +0000188 &prefix,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100189 FIB_SOURCE_AE,
Neale Rannsfa0fb582016-12-10 21:59:14 +0000190 (fib_entry_get_flags(entry_index) |
191 FIB_ENTRY_FLAG_EXCLUSIVE),
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100192 load_balance_get_bucket(dpo->dpoi_index, 0));
193
194 fib_entry_lock(entry_index);
195 vec_add1(import->faei_importeds, entry_index);
196 }
197 /*
198 * else
199 * the entry currently has no valid forwarding. when it
200 * does it will export itself
201 */
202 }
203}
204
205/**
206 * Call back when walking a connected prefix's covered prefixes for import
207 */
Neale Rannsfdf6b6f2020-11-26 09:34:39 +0000208static walk_rc_t
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100209fib_entry_covered_walk_import (fib_entry_t *cover,
210 fib_node_index_t covered,
211 void *ctx)
212{
213 fib_ae_import_t *import = ctx;
214
215 fib_entry_import_add(import, covered);
216
Neale Rannsfdf6b6f2020-11-26 09:34:39 +0000217 return (WALK_CONTINUE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100218}
219
220/*
221 * fib_entry_ae_import_add
222 *
223 * Add an importer to a connected entry
224 */
225static void
226fib_ae_export_import_add (fib_ae_export_t *export,
227 fib_ae_import_t *import)
228{
229 fib_entry_t *entry;
230
231 import->faei_exporter = (export - fib_ae_export_pool);
232 entry = fib_entry_get(export->faee_ei);
233
234 fib_entry_cover_walk(entry,
235 fib_entry_covered_walk_import,
236 import);
237}
238
239void
240fib_attached_export_import (fib_entry_t *fib_entry,
241 fib_node_index_t export_fib)
242{
Neale Rannsad422ed2016-11-02 14:20:04 +0000243 fib_entry_delegate_t *fed;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100244 fib_ae_import_t *import;
Neale Rannsf8fc0f62017-01-10 18:13:41 +0100245 fib_node_index_t fei;
246
247 /*
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700248 * save index for later post-realloc retrieval
Neale Rannsf8fc0f62017-01-10 18:13:41 +0100249 */
250 fei = fib_entry_get_index(fib_entry);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100251
252 pool_get(fib_ae_import_pool, import);
253
254 import->faei_import_fib = fib_entry->fe_fib_index;
255 import->faei_export_fib = export_fib;
256 import->faei_prefix = fib_entry->fe_prefix;
257 import->faei_import_entry = fib_entry_get_index(fib_entry);
258 import->faei_export_sibling = ~0;
259
260 /*
261 * do an exact match in the export table
262 */
263 import->faei_export_entry =
264 fib_table_lookup_exact_match(import->faei_export_fib,
265 &import->faei_prefix);
266
267 if (FIB_NODE_INDEX_INVALID == import->faei_export_entry)
268 {
269 /*
270 * no exact matching entry in the export table. can't be good.
271 * track the next best thing
272 */
273 import->faei_export_entry =
274 fib_table_lookup(import->faei_export_fib,
275 &import->faei_prefix);
276 import->faei_exporter = FIB_NODE_INDEX_INVALID;
277 }
278 else
279 {
280 /*
281 * found the entry in the export table. import the
282 * the prefixes that it covers.
283 * only if the prefix found in the export FIB really is
284 * attached do we want to import its covered
285 */
286 if (FIB_ENTRY_FLAG_ATTACHED &
287 fib_entry_get_flags_i(fib_entry_get(import->faei_export_entry)))
288 {
289 fib_ae_export_t *export;
290
291 export = fib_entry_ae_add_or_lock(import->faei_export_entry);
292 vec_add1(export->faee_importers, (import - fib_ae_import_pool));
293 fib_ae_export_import_add(export, import);
294 }
295 }
296
297 /*
298 * track the entry in the export table so we can update appropriately
Neale Rannsf8fc0f62017-01-10 18:13:41 +0100299 * when it changes.
300 * Exporting prefixes will have allocated new fib_entry_t objects, so the pool
301 * may have realloc'd.
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100302 */
Neale Rannsf8fc0f62017-01-10 18:13:41 +0100303 fib_entry = fib_entry_get(fei);
Neale Ranns32e1c012016-11-22 17:07:28 +0000304 import->faei_export_sibling =
305 fib_entry_cover_track(fib_entry_get(import->faei_export_entry), fei);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100306
Neale Rannsad422ed2016-11-02 14:20:04 +0000307 fed = fib_entry_delegate_find_or_add(fib_entry,
308 FIB_ENTRY_DELEGATE_ATTACHED_IMPORT);
309 fed->fd_index = (import - fib_ae_import_pool);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100310}
311
312/**
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700313 * \brief All the imported entries need to be purged
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100314 */
315void
316fib_attached_export_purge (fib_entry_t *fib_entry)
317{
Neale Rannsad422ed2016-11-02 14:20:04 +0000318 fib_entry_delegate_t *fed;
319
Neale Ranns1f50bf82019-07-16 15:28:52 +0000320 fed = fib_entry_delegate_find(fib_entry,
321 FIB_ENTRY_DELEGATE_ATTACHED_IMPORT);
Neale Rannsad422ed2016-11-02 14:20:04 +0000322
323 if (NULL != fed)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100324 {
325 fib_node_index_t *import_index;
326 fib_entry_t *export_entry;
327 fib_ae_import_t *import;
328 fib_ae_export_t *export;
329
Neale Rannsad422ed2016-11-02 14:20:04 +0000330 import = pool_elt_at_index(fib_ae_import_pool, fed->fd_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100331
332 /*
333 * remove each imported entry
334 */
335 vec_foreach(import_index, import->faei_importeds)
336 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100337 fib_table_entry_delete(import->faei_import_fib,
Neale Rannsc5d43172018-07-30 08:04:40 -0700338 fib_entry_get_prefix(*import_index),
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100339 FIB_SOURCE_AE);
340 fib_entry_unlock(*import_index);
341 }
342 vec_free(import->faei_importeds);
343
344 /*
345 * stop tracking the export entry
346 */
347 if (~0 != import->faei_export_sibling)
348 {
349 fib_entry_cover_untrack(fib_entry_get(import->faei_export_entry),
350 import->faei_export_sibling);
351 }
352 import->faei_export_sibling = ~0;
353
354 /*
355 * remove this import tracker from the export's list,
356 * if it is attached to one. It won't be in the case the tracked
357 * export entry is not an attached exact match.
358 */
359 if (FIB_NODE_INDEX_INVALID != import->faei_exporter)
360 {
Neale Rannsad422ed2016-11-02 14:20:04 +0000361 fib_entry_delegate_t *fed;
362
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100363 export_entry = fib_entry_get(import->faei_export_entry);
Neale Rannsad422ed2016-11-02 14:20:04 +0000364
Neale Ranns1f50bf82019-07-16 15:28:52 +0000365 fed = fib_entry_delegate_find(export_entry,
366 FIB_ENTRY_DELEGATE_ATTACHED_EXPORT);
Dave Barach47d41ad2020-02-17 09:13:26 -0500367 ALWAYS_ASSERT(NULL != fed);
Neale Rannsad422ed2016-11-02 14:20:04 +0000368
369 export = pool_elt_at_index(fib_ae_export_pool, fed->fd_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100370
371 u32 index = vec_search(export->faee_importers,
372 (import - fib_ae_import_pool));
373
374 ASSERT(index < vec_len(export->faee_importers));
375 vec_del1(export->faee_importers, index);
376
377 /*
378 * free the exporter if there are no longer importers
379 */
380 if (0 == --export->faee_locks)
381 {
382 pool_put(fib_ae_export_pool, export);
Neale Rannsad422ed2016-11-02 14:20:04 +0000383 fib_entry_delegate_remove(export_entry,
384 FIB_ENTRY_DELEGATE_ATTACHED_EXPORT);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100385 }
386 }
387
388 /*
389 * free the import tracker
390 */
391 pool_put(fib_ae_import_pool, import);
Neale Rannsad422ed2016-11-02 14:20:04 +0000392 fib_entry_delegate_remove(fib_entry,
393 FIB_ENTRY_DELEGATE_ATTACHED_IMPORT);
Dave Barach47d41ad2020-02-17 09:13:26 -0500394 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100395}
396
397void
398fib_attached_export_covered_added (fib_entry_t *cover,
399 fib_node_index_t covered)
400{
Neale Rannsad422ed2016-11-02 14:20:04 +0000401 fib_entry_delegate_t *fed;
402
Neale Ranns1f50bf82019-07-16 15:28:52 +0000403 fed = fib_entry_delegate_find(cover,
404 FIB_ENTRY_DELEGATE_ATTACHED_EXPORT);
Neale Rannsad422ed2016-11-02 14:20:04 +0000405
406 if (NULL != fed)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100407 {
408 /*
409 * the covering prefix is exporting to other tables
410 */
411 fib_node_index_t *import_index;
412 fib_ae_import_t *import;
413 fib_ae_export_t *export;
414
Neale Rannsad422ed2016-11-02 14:20:04 +0000415 export = pool_elt_at_index(fib_ae_export_pool, fed->fd_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100416
417 /*
418 * export the covered entry to each of the importers
419 */
420 vec_foreach(import_index, export->faee_importers)
421 {
422 import = pool_elt_at_index(fib_ae_import_pool, *import_index);
423
424 fib_entry_import_add(import, covered);
425 }
426 }
427}
428
429void
430fib_attached_export_covered_removed (fib_entry_t *cover,
431 fib_node_index_t covered)
432{
Neale Rannsad422ed2016-11-02 14:20:04 +0000433 fib_entry_delegate_t *fed;
434
Neale Ranns1f50bf82019-07-16 15:28:52 +0000435 fed = fib_entry_delegate_find(cover,
436 FIB_ENTRY_DELEGATE_ATTACHED_EXPORT);
Neale Rannsad422ed2016-11-02 14:20:04 +0000437
438 if (NULL != fed)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100439 {
440 /*
441 * the covering prefix is exporting to other tables
442 */
443 fib_node_index_t *import_index;
444 fib_ae_import_t *import;
445 fib_ae_export_t *export;
446
Neale Rannsad422ed2016-11-02 14:20:04 +0000447 export = pool_elt_at_index(fib_ae_export_pool, fed->fd_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100448
449 /*
450 * remove the covered entry from each of the importers
451 */
452 vec_foreach(import_index, export->faee_importers)
453 {
454 import = pool_elt_at_index(fib_ae_import_pool, *import_index);
455
456 fib_entry_import_remove(import, covered);
457 }
458 }
459}
460
461static void
462fib_attached_export_cover_modified_i (fib_entry_t *fib_entry)
463{
Neale Rannsad422ed2016-11-02 14:20:04 +0000464 fib_entry_delegate_t *fed;
465
Neale Ranns1f50bf82019-07-16 15:28:52 +0000466 fed = fib_entry_delegate_find(fib_entry,
467 FIB_ENTRY_DELEGATE_ATTACHED_IMPORT);
Neale Rannsad422ed2016-11-02 14:20:04 +0000468
469 if (NULL != fed)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100470 {
471 fib_ae_import_t *import;
472 u32 export_fib;
473
474 /*
475 * safe the temporaries we need from the existing import
476 * since it will be toast after the purge.
477 */
Neale Rannsad422ed2016-11-02 14:20:04 +0000478 import = pool_elt_at_index(fib_ae_import_pool, fed->fd_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100479 export_fib = import->faei_export_fib;
480
481 /*
482 * keep it simple. purge anything that was previously imported.
483 * then re-evaluate the need to import.
484 */
485 fib_attached_export_purge(fib_entry);
486 fib_attached_export_import(fib_entry, export_fib);
487 }
488}
489
490/**
491 * \brief If this entry is tracking a cover (in another table)
492 * then that cover has changed. re-evaluate import.
493 */
494void
495fib_attached_export_cover_change (fib_entry_t *fib_entry)
496{
497 fib_attached_export_cover_modified_i(fib_entry);
498}
499
500/**
501 * \brief If this entry is tracking a cover (in another table)
502 * then that cover has been updated. re-evaluate import.
503 */
504void
505fib_attached_export_cover_update (fib_entry_t *fib_entry)
506{
507 fib_attached_export_cover_modified_i(fib_entry);
508}
509
510u8*
Neale Ranns88fc83e2017-04-05 08:11:14 -0700511fib_ae_import_format (fib_node_index_t impi,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100512 u8* s)
513{
Neale Ranns88fc83e2017-04-05 08:11:14 -0700514 fib_node_index_t *index;
515 fib_ae_import_t *import;
Neale Rannsad422ed2016-11-02 14:20:04 +0000516
Neale Ranns88fc83e2017-04-05 08:11:14 -0700517 import = pool_elt_at_index(fib_ae_import_pool, impi);
Neale Rannsad422ed2016-11-02 14:20:04 +0000518
Neale Ranns88fc83e2017-04-05 08:11:14 -0700519 s = format(s, "\n Attached-Import:%d:[", (import - fib_ae_import_pool));
520 s = format(s, "export-prefix:%U ", format_fib_prefix, &import->faei_prefix);
521 s = format(s, "export-entry:%d ", import->faei_export_entry);
522 s = format(s, "export-sibling:%d ", import->faei_export_sibling);
523 s = format(s, "exporter:%d ", import->faei_exporter);
524 s = format(s, "export-fib:%d ", import->faei_export_fib);
Dave Barach47d41ad2020-02-17 09:13:26 -0500525
Neale Ranns88fc83e2017-04-05 08:11:14 -0700526 s = format(s, "import-entry:%d ", import->faei_import_entry);
527 s = format(s, "import-fib:%d ", import->faei_import_fib);
528
529 s = format(s, "importeds:[");
530 vec_foreach(index, import->faei_importeds)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100531 {
Neale Ranns88fc83e2017-04-05 08:11:14 -0700532 s = format(s, "%d, ", *index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100533 }
Neale Ranns88fc83e2017-04-05 08:11:14 -0700534 s = format(s, "]]");
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100535
536 return (s);
537}
538
539u8*
Neale Ranns88fc83e2017-04-05 08:11:14 -0700540fib_ae_export_format (fib_node_index_t expi,
Neale Rannsad422ed2016-11-02 14:20:04 +0000541 u8* s)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100542{
Neale Ranns88fc83e2017-04-05 08:11:14 -0700543 fib_node_index_t *index;
544 fib_ae_export_t *export;
Neale Rannsad422ed2016-11-02 14:20:04 +0000545
Neale Ranns88fc83e2017-04-05 08:11:14 -0700546 export = pool_elt_at_index(fib_ae_export_pool, expi);
Dave Barach47d41ad2020-02-17 09:13:26 -0500547
Neale Ranns88fc83e2017-04-05 08:11:14 -0700548 s = format(s, "\n Attached-Export:%d:[", (export - fib_ae_export_pool));
549 s = format(s, "export-entry:%d ", export->faee_ei);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100550
Neale Ranns88fc83e2017-04-05 08:11:14 -0700551 s = format(s, "importers:[");
552 vec_foreach(index, export->faee_importers)
553 {
554 s = format(s, "%d, ", *index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100555 }
Neale Ranns88fc83e2017-04-05 08:11:14 -0700556 s = format(s, "]]");
557
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100558 return (s);
559}