]>
Commit | Line | Data |
---|---|---|
955bfd98 PZ |
1 | /* |
2 | * BGP Label Pool - Manage label chunk allocations from zebra asynchronously | |
3 | * | |
4 | * Copyright (C) 2018 LabN Consulting, L.L.C. | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify it | |
7 | * under the terms of the GNU General Public License as published by the Free | |
8 | * Software Foundation; either version 2 of the License, or (at your option) | |
9 | * any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
14 | * more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License along | |
17 | * with this program; see the file COPYING; if not, write to the Free Software | |
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
19 | */ | |
20 | ||
21 | #include <zebra.h> | |
22 | ||
23 | #include "log.h" | |
24 | #include "memory.h" | |
25 | #include "stream.h" | |
26 | #include "mpls.h" | |
27 | #include "vty.h" | |
955bfd98 PZ |
28 | #include "linklist.h" |
29 | #include "skiplist.h" | |
30 | #include "workqueue.h" | |
31 | #include "zclient.h" | |
0e3b6a92 | 32 | #include "mpls.h" |
955bfd98 PZ |
33 | |
34 | #include "bgpd/bgpd.h" | |
35 | #include "bgpd/bgp_labelpool.h" | |
36 | #include "bgpd/bgp_debug.h" | |
14454c9f | 37 | #include "bgpd/bgp_errors.h" |
668cfa98 | 38 | #include "bgpd/bgp_route.h" |
955bfd98 PZ |
39 | |
40 | /* | |
41 | * Definitions and external declarations. | |
42 | */ | |
43 | extern struct zclient *zclient; | |
44 | ||
45 | /* | |
46 | * Remember where pool data are kept | |
47 | */ | |
48 | static struct labelpool *lp; | |
49 | ||
50 | /* request this many labels at a time from zebra */ | |
51 | #define LP_CHUNK_SIZE 50 | |
52 | ||
53 | DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_CHUNK, "BGP Label Chunk") | |
41397f2e | 54 | DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_FIFO, "BGP Label FIFO item") |
955bfd98 PZ |
55 | DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_CB, "BGP Dynamic Label Assignment") |
56 | DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_CBQ, "BGP Dynamic Label Callback") | |
57 | ||
955bfd98 PZ |
58 | struct lp_chunk { |
59 | uint32_t first; | |
60 | uint32_t last; | |
61 | }; | |
62 | ||
63 | /* | |
64 | * label control block | |
65 | */ | |
66 | struct lp_lcb { | |
67 | mpls_label_t label; /* MPLS_LABEL_NONE = not allocated */ | |
68 | int type; | |
69 | void *labelid; /* unique ID */ | |
70 | /* | |
71 | * callback for label allocation and loss | |
72 | * | |
73 | * allocated: false = lost | |
74 | */ | |
75 | int (*cbfunc)(mpls_label_t label, void *lblid, bool alloc); | |
76 | }; | |
77 | ||
955bfd98 | 78 | struct lp_fifo { |
41397f2e | 79 | struct lp_fifo_item fifo; |
955bfd98 PZ |
80 | struct lp_lcb lcb; |
81 | }; | |
82 | ||
41397f2e DL |
83 | DECLARE_LIST(lp_fifo, struct lp_fifo, fifo) |
84 | ||
955bfd98 PZ |
85 | struct lp_cbq_item { |
86 | int (*cbfunc)(mpls_label_t label, void *lblid, bool alloc); | |
87 | int type; | |
88 | mpls_label_t label; | |
89 | void *labelid; | |
90 | bool allocated; /* false = lost */ | |
91 | }; | |
92 | ||
93 | static wq_item_status lp_cbq_docallback(struct work_queue *wq, void *data) | |
94 | { | |
95 | struct lp_cbq_item *lcbq = data; | |
96 | int rc; | |
97 | int debug = BGP_DEBUG(labelpool, LABELPOOL); | |
98 | ||
99 | if (debug) | |
100 | zlog_debug("%s: calling callback with labelid=%p label=%u allocated=%d", | |
101 | __func__, lcbq->labelid, lcbq->label, lcbq->allocated); | |
102 | ||
103 | if (lcbq->label == MPLS_LABEL_NONE) { | |
104 | /* shouldn't happen */ | |
e50f7cfd | 105 | flog_err(EC_BGP_LABEL, "%s: error: label==MPLS_LABEL_NONE", |
1c50c1c0 | 106 | __func__); |
955bfd98 PZ |
107 | return WQ_SUCCESS; |
108 | } | |
109 | ||
110 | rc = (*(lcbq->cbfunc))(lcbq->label, lcbq->labelid, lcbq->allocated); | |
111 | ||
112 | if (lcbq->allocated && rc) { | |
113 | /* | |
114 | * Callback rejected allocation. This situation could arise | |
115 | * if there was a label request followed by the requestor | |
116 | * deciding it didn't need the assignment (e.g., config | |
117 | * change) while the reply to the original request (with | |
118 | * label) was in the work queue. | |
119 | */ | |
120 | if (debug) | |
121 | zlog_debug("%s: callback rejected allocation, releasing labelid=%p label=%u", | |
122 | __func__, lcbq->labelid, lcbq->label); | |
123 | ||
124 | uintptr_t lbl = lcbq->label; | |
125 | void *labelid; | |
126 | struct lp_lcb *lcb; | |
127 | ||
128 | /* | |
129 | * If the rejected label was marked inuse by this labelid, | |
130 | * release the label back to the pool. | |
131 | * | |
132 | * Further, if the rejected label was still assigned to | |
133 | * this labelid in the LCB, delete the LCB. | |
134 | */ | |
135 | if (!skiplist_search(lp->inuse, (void *)lbl, &labelid)) { | |
136 | if (labelid == lcbq->labelid) { | |
137 | if (!skiplist_search(lp->ledger, labelid, | |
138 | (void **)&lcb)) { | |
139 | if (lcbq->label == lcb->label) | |
140 | skiplist_delete(lp->ledger, | |
141 | labelid, NULL); | |
142 | } | |
143 | skiplist_delete(lp->inuse, (void *)lbl, NULL); | |
144 | } | |
145 | } | |
146 | } | |
147 | ||
148 | return WQ_SUCCESS; | |
149 | } | |
150 | ||
151 | static void lp_cbq_item_free(struct work_queue *wq, void *data) | |
152 | { | |
153 | XFREE(MTYPE_BGP_LABEL_CBQ, data); | |
154 | } | |
155 | ||
156 | static void lp_lcb_free(void *goner) | |
157 | { | |
0a22ddfb | 158 | XFREE(MTYPE_BGP_LABEL_CB, goner); |
955bfd98 PZ |
159 | } |
160 | ||
161 | static void lp_chunk_free(void *goner) | |
162 | { | |
0a22ddfb | 163 | XFREE(MTYPE_BGP_LABEL_CHUNK, goner); |
955bfd98 PZ |
164 | } |
165 | ||
166 | void bgp_lp_init(struct thread_master *master, struct labelpool *pool) | |
167 | { | |
168 | if (BGP_DEBUG(labelpool, LABELPOOL)) | |
169 | zlog_debug("%s: entry", __func__); | |
170 | ||
171 | lp = pool; /* Set module pointer to pool data */ | |
172 | ||
173 | lp->ledger = skiplist_new(0, NULL, lp_lcb_free); | |
174 | lp->inuse = skiplist_new(0, NULL, NULL); | |
175 | lp->chunks = list_new(); | |
176 | lp->chunks->del = lp_chunk_free; | |
41397f2e | 177 | lp_fifo_init(&lp->requests); |
955bfd98 | 178 | lp->callback_q = work_queue_new(master, "label callbacks"); |
955bfd98 PZ |
179 | |
180 | lp->callback_q->spec.workfunc = lp_cbq_docallback; | |
181 | lp->callback_q->spec.del_item_data = lp_cbq_item_free; | |
182 | lp->callback_q->spec.max_retries = 0; | |
183 | } | |
184 | ||
ea63ff6b EDP |
185 | /* check if a label callback was for a BGP LU path, and if so, unlock it */ |
186 | static void check_bgp_lu_cb_unlock(struct lp_lcb *lcb) | |
187 | { | |
188 | if (lcb->type == LP_TYPE_BGP_LU) | |
189 | bgp_path_info_unlock(lcb->labelid); | |
190 | } | |
191 | ||
192 | /* check if a label callback was for a BGP LU path, and if so, lock it */ | |
193 | static void check_bgp_lu_cb_lock(struct lp_lcb *lcb) | |
194 | { | |
195 | if (lcb->type == LP_TYPE_BGP_LU) | |
196 | bgp_path_info_lock(lcb->labelid); | |
197 | } | |
198 | ||
955bfd98 PZ |
199 | void bgp_lp_finish(void) |
200 | { | |
201 | struct lp_fifo *lf; | |
ea63ff6b | 202 | struct work_queue_item *item, *titem; |
955bfd98 PZ |
203 | |
204 | if (!lp) | |
205 | return; | |
206 | ||
207 | skiplist_free(lp->ledger); | |
208 | lp->ledger = NULL; | |
209 | ||
210 | skiplist_free(lp->inuse); | |
211 | lp->inuse = NULL; | |
212 | ||
6a154c88 | 213 | list_delete(&lp->chunks); |
955bfd98 | 214 | |
ea63ff6b EDP |
215 | while ((lf = lp_fifo_pop(&lp->requests))) { |
216 | check_bgp_lu_cb_unlock(&lf->lcb); | |
955bfd98 | 217 | XFREE(MTYPE_BGP_LABEL_FIFO, lf); |
ea63ff6b | 218 | } |
41397f2e | 219 | lp_fifo_fini(&lp->requests); |
955bfd98 | 220 | |
ea63ff6b EDP |
221 | /* we must unlock path infos for LU callbacks; but we cannot do that |
222 | * in the deletion callback of the workqueue, as that is also called | |
223 | * to remove an element from the queue after it has been run, resulting | |
224 | * in a double unlock. Hence we need to iterate over our queues and | |
225 | * lists and manually perform the unlocking (ugh) | |
226 | */ | |
227 | STAILQ_FOREACH_SAFE (item, &lp->callback_q->items, wq, titem) | |
228 | check_bgp_lu_cb_unlock(item->data); | |
229 | ||
955bfd98 PZ |
230 | work_queue_free_and_null(&lp->callback_q); |
231 | ||
232 | lp = NULL; | |
233 | } | |
234 | ||
235 | static mpls_label_t get_label_from_pool(void *labelid) | |
236 | { | |
237 | struct listnode *node; | |
238 | struct lp_chunk *chunk; | |
239 | int debug = BGP_DEBUG(labelpool, LABELPOOL); | |
240 | ||
241 | /* | |
242 | * Find a free label | |
243 | * Linear search is not efficient but should be executed infrequently. | |
244 | */ | |
245 | for (ALL_LIST_ELEMENTS_RO(lp->chunks, node, chunk)) { | |
246 | uintptr_t lbl; | |
247 | ||
248 | if (debug) | |
249 | zlog_debug("%s: chunk first=%u last=%u", | |
250 | __func__, chunk->first, chunk->last); | |
251 | ||
252 | for (lbl = chunk->first; lbl <= chunk->last; ++lbl) { | |
253 | /* labelid is key to all-request "ledger" list */ | |
254 | if (!skiplist_insert(lp->inuse, (void *)lbl, labelid)) { | |
255 | /* | |
256 | * Success | |
257 | */ | |
258 | return lbl; | |
259 | } | |
260 | } | |
261 | } | |
262 | return MPLS_LABEL_NONE; | |
263 | } | |
264 | ||
265 | /* | |
266 | * Success indicated by value of "label" field in returned LCB | |
267 | */ | |
268 | static struct lp_lcb *lcb_alloc( | |
269 | int type, | |
270 | void *labelid, | |
271 | int (*cbfunc)(mpls_label_t label, void *labelid, bool allocated)) | |
272 | { | |
273 | /* | |
274 | * Set up label control block | |
275 | */ | |
276 | struct lp_lcb *new = XCALLOC(MTYPE_BGP_LABEL_CB, | |
277 | sizeof(struct lp_lcb)); | |
278 | ||
279 | new->label = get_label_from_pool(labelid); | |
280 | new->type = type; | |
281 | new->labelid = labelid; | |
282 | new->cbfunc = cbfunc; | |
283 | ||
284 | return new; | |
285 | } | |
286 | ||
287 | /* | |
288 | * Callers who need labels must supply a type, labelid, and callback. | |
289 | * The type is a value defined in bgp_labelpool.h (add types as needed). | |
290 | * The callback is for asynchronous notification of label allocation. | |
291 | * The labelid is passed as an argument to the callback. It should be unique | |
292 | * to the requested label instance. | |
293 | * | |
294 | * If zebra is not connected, callbacks with labels will be delayed | |
295 | * until connection is established. If zebra connection is lost after | |
296 | * labels have been assigned, existing assignments via this labelpool | |
297 | * module will continue until reconnection. | |
298 | * | |
299 | * When connection to zebra is reestablished, previous label assignments | |
300 | * will be invalidated (via callbacks having the "allocated" parameter unset) | |
301 | * and new labels will be automatically reassigned by this labelpool module | |
302 | * (that is, a requestor does not need to call lp_get() again if it is | |
303 | * notified via callback that its label has been lost: it will eventually | |
304 | * get another callback with a new label assignment). | |
305 | * | |
306 | * Prior requests for a given labelid are detected so that requests and | |
307 | * assignments are not duplicated. | |
308 | */ | |
309 | void bgp_lp_get( | |
310 | int type, | |
311 | void *labelid, | |
312 | int (*cbfunc)(mpls_label_t label, void *labelid, bool allocated)) | |
313 | { | |
314 | struct lp_lcb *lcb; | |
315 | int requested = 0; | |
316 | int debug = BGP_DEBUG(labelpool, LABELPOOL); | |
317 | ||
318 | if (debug) | |
319 | zlog_debug("%s: labelid=%p", __func__, labelid); | |
320 | ||
321 | /* | |
322 | * Have we seen this request before? | |
323 | */ | |
324 | if (!skiplist_search(lp->ledger, labelid, (void **)&lcb)) { | |
325 | requested = 1; | |
326 | } else { | |
327 | lcb = lcb_alloc(type, labelid, cbfunc); | |
328 | if (debug) | |
329 | zlog_debug("%s: inserting lcb=%p label=%u", | |
330 | __func__, lcb, lcb->label); | |
331 | int rc = skiplist_insert(lp->ledger, labelid, lcb); | |
332 | ||
333 | if (rc) { | |
334 | /* shouldn't happen */ | |
e50f7cfd | 335 | flog_err(EC_BGP_LABEL, |
1c50c1c0 QY |
336 | "%s: can't insert new LCB into ledger list", |
337 | __func__); | |
955bfd98 PZ |
338 | XFREE(MTYPE_BGP_LABEL_CB, lcb); |
339 | return; | |
340 | } | |
341 | } | |
342 | ||
343 | if (lcb->label != MPLS_LABEL_NONE) { | |
344 | /* | |
345 | * Fast path: we filled the request from local pool (or | |
346 | * this is a duplicate request that we filled already). | |
347 | * Enqueue response work item with new label. | |
348 | */ | |
349 | struct lp_cbq_item *q; | |
350 | ||
351 | q = XCALLOC(MTYPE_BGP_LABEL_CBQ, sizeof(struct lp_cbq_item)); | |
352 | ||
353 | q->cbfunc = lcb->cbfunc; | |
354 | q->type = lcb->type; | |
355 | q->label = lcb->label; | |
356 | q->labelid = lcb->labelid; | |
357 | q->allocated = true; | |
358 | ||
ea63ff6b EDP |
359 | /* if this is a LU request, lock path info before queueing */ |
360 | check_bgp_lu_cb_lock(lcb); | |
361 | ||
955bfd98 PZ |
362 | work_queue_add(lp->callback_q, q); |
363 | ||
364 | return; | |
365 | } | |
366 | ||
367 | if (requested) | |
368 | return; | |
369 | ||
370 | if (debug) | |
371 | zlog_debug("%s: slow path. lcb=%p label=%u", | |
372 | __func__, lcb, lcb->label); | |
373 | ||
374 | /* | |
375 | * Slow path: we are out of labels in the local pool, | |
376 | * so remember the request and also get another chunk from | |
377 | * the label manager. | |
378 | * | |
379 | * We track number of outstanding label requests: don't | |
380 | * need to get a chunk for each one. | |
381 | */ | |
382 | ||
383 | struct lp_fifo *lf = XCALLOC(MTYPE_BGP_LABEL_FIFO, | |
384 | sizeof(struct lp_fifo)); | |
385 | ||
386 | lf->lcb = *lcb; | |
ea63ff6b EDP |
387 | /* if this is a LU request, lock path info before queueing */ |
388 | check_bgp_lu_cb_lock(lcb); | |
389 | ||
41397f2e | 390 | lp_fifo_add_tail(&lp->requests, lf); |
955bfd98 | 391 | |
41397f2e | 392 | if (lp_fifo_count(&lp->requests) > lp->pending_count) { |
ea63ff6b | 393 | if (!zclient || zclient->sock < 0) |
955bfd98 | 394 | return; |
0e3b6a92 EDP |
395 | if (!zclient_send_get_label_chunk(zclient, 0, LP_CHUNK_SIZE, |
396 | MPLS_LABEL_BASE_ANY)) | |
ea63ff6b | 397 | lp->pending_count += LP_CHUNK_SIZE; |
955bfd98 PZ |
398 | } |
399 | } | |
400 | ||
401 | void bgp_lp_release( | |
402 | int type, | |
403 | void *labelid, | |
404 | mpls_label_t label) | |
405 | { | |
406 | struct lp_lcb *lcb; | |
407 | ||
408 | if (!skiplist_search(lp->ledger, labelid, (void **)&lcb)) { | |
409 | if (label == lcb->label && type == lcb->type) { | |
410 | uintptr_t lbl = label; | |
411 | ||
412 | /* no longer in use */ | |
413 | skiplist_delete(lp->inuse, (void *)lbl, NULL); | |
414 | ||
415 | /* no longer requested */ | |
416 | skiplist_delete(lp->ledger, labelid, NULL); | |
417 | } | |
418 | } | |
419 | } | |
420 | ||
421 | /* | |
422 | * zebra response giving us a chunk of labels | |
423 | */ | |
424 | void bgp_lp_event_chunk(uint8_t keep, uint32_t first, uint32_t last) | |
425 | { | |
426 | struct lp_chunk *chunk; | |
427 | int debug = BGP_DEBUG(labelpool, LABELPOOL); | |
428 | struct lp_fifo *lf; | |
429 | ||
430 | if (last < first) { | |
e50f7cfd | 431 | flog_err(EC_BGP_LABEL, |
1c50c1c0 QY |
432 | "%s: zebra label chunk invalid: first=%u, last=%u", |
433 | __func__, first, last); | |
955bfd98 PZ |
434 | return; |
435 | } | |
436 | ||
437 | chunk = XCALLOC(MTYPE_BGP_LABEL_CHUNK, sizeof(struct lp_chunk)); | |
438 | ||
439 | chunk->first = first; | |
440 | chunk->last = last; | |
441 | ||
442 | listnode_add(lp->chunks, chunk); | |
443 | ||
444 | lp->pending_count -= (last - first + 1); | |
445 | ||
446 | if (debug) { | |
41397f2e DL |
447 | zlog_debug("%s: %zu pending requests", __func__, |
448 | lp_fifo_count(&lp->requests)); | |
955bfd98 PZ |
449 | } |
450 | ||
41397f2e | 451 | while ((lf = lp_fifo_first(&lp->requests))) { |
955bfd98 PZ |
452 | |
453 | struct lp_lcb *lcb; | |
454 | void *labelid = lf->lcb.labelid; | |
455 | ||
456 | if (skiplist_search(lp->ledger, labelid, (void **)&lcb)) { | |
457 | /* request no longer in effect */ | |
458 | ||
459 | if (debug) { | |
460 | zlog_debug("%s: labelid %p: request no longer in effect", | |
461 | __func__, labelid); | |
462 | } | |
463 | goto finishedrequest; | |
464 | } | |
465 | ||
466 | /* have LCB */ | |
467 | if (lcb->label != MPLS_LABEL_NONE) { | |
468 | /* request already has a label */ | |
469 | if (debug) { | |
470 | zlog_debug("%s: labelid %p: request already has a label: %u=0x%x, lcb=%p", | |
471 | __func__, labelid, | |
472 | lcb->label, lcb->label, lcb); | |
473 | } | |
ea63ff6b EDP |
474 | /* if this was a BGP_LU request, unlock path info node |
475 | */ | |
476 | check_bgp_lu_cb_unlock(lcb); | |
477 | ||
955bfd98 PZ |
478 | goto finishedrequest; |
479 | } | |
480 | ||
481 | lcb->label = get_label_from_pool(lcb->labelid); | |
482 | ||
483 | if (lcb->label == MPLS_LABEL_NONE) { | |
484 | /* | |
485 | * Out of labels in local pool, await next chunk | |
486 | */ | |
487 | if (debug) { | |
488 | zlog_debug("%s: out of labels, await more", | |
489 | __func__); | |
490 | } | |
491 | break; | |
492 | } | |
493 | ||
494 | /* | |
495 | * we filled the request from local pool. | |
496 | * Enqueue response work item with new label. | |
497 | */ | |
498 | struct lp_cbq_item *q = XCALLOC(MTYPE_BGP_LABEL_CBQ, | |
499 | sizeof(struct lp_cbq_item)); | |
500 | ||
501 | q->cbfunc = lcb->cbfunc; | |
502 | q->type = lcb->type; | |
503 | q->label = lcb->label; | |
504 | q->labelid = lcb->labelid; | |
505 | q->allocated = true; | |
506 | ||
507 | if (debug) | |
508 | zlog_debug("%s: assigning label %u to labelid %p", | |
509 | __func__, q->label, q->labelid); | |
510 | ||
511 | work_queue_add(lp->callback_q, q); | |
512 | ||
513 | finishedrequest: | |
41397f2e | 514 | lp_fifo_del(&lp->requests, lf); |
955bfd98 PZ |
515 | XFREE(MTYPE_BGP_LABEL_FIFO, lf); |
516 | } | |
517 | } | |
518 | ||
519 | /* | |
520 | * continue using allocated labels until zebra returns | |
521 | */ | |
522 | void bgp_lp_event_zebra_down(void) | |
523 | { | |
524 | /* rats. */ | |
525 | } | |
526 | ||
527 | /* | |
528 | * Inform owners of previously-allocated labels that their labels | |
529 | * are not valid. Request chunk from zebra large enough to satisfy | |
530 | * previously-allocated labels plus any outstanding requests. | |
531 | */ | |
532 | void bgp_lp_event_zebra_up(void) | |
533 | { | |
534 | int labels_needed; | |
535 | int chunks_needed; | |
536 | void *labelid; | |
537 | struct lp_lcb *lcb; | |
f533be73 | 538 | int lm_init_ok; |
955bfd98 PZ |
539 | |
540 | /* | |
541 | * Get label chunk allocation request dispatched to zebra | |
542 | */ | |
41397f2e | 543 | labels_needed = lp_fifo_count(&lp->requests) + |
955bfd98 PZ |
544 | skiplist_count(lp->inuse); |
545 | ||
546 | /* round up */ | |
547 | chunks_needed = (labels_needed / LP_CHUNK_SIZE) + 1; | |
548 | labels_needed = chunks_needed * LP_CHUNK_SIZE; | |
549 | ||
f533be73 | 550 | lm_init_ok = lm_label_manager_connect(zclient, 1) == 0; |
551 | ||
ea63ff6b | 552 | if (!lm_init_ok) { |
f533be73 | 553 | zlog_err("%s: label manager connection error", __func__); |
ea63ff6b EDP |
554 | return; |
555 | } | |
f533be73 | 556 | |
0e3b6a92 EDP |
557 | zclient_send_get_label_chunk(zclient, 0, labels_needed, |
558 | MPLS_LABEL_BASE_ANY); | |
955bfd98 PZ |
559 | lp->pending_count = labels_needed; |
560 | ||
561 | /* | |
562 | * Invalidate current list of chunks | |
563 | */ | |
564 | list_delete_all_node(lp->chunks); | |
565 | ||
566 | /* | |
567 | * Invalidate any existing labels and requeue them as requests | |
568 | */ | |
569 | while (!skiplist_first(lp->inuse, NULL, &labelid)) { | |
570 | ||
571 | /* | |
572 | * Get LCB | |
573 | */ | |
574 | if (!skiplist_search(lp->ledger, labelid, (void **)&lcb)) { | |
575 | ||
576 | if (lcb->label != MPLS_LABEL_NONE) { | |
577 | /* | |
578 | * invalidate | |
579 | */ | |
580 | struct lp_cbq_item *q; | |
581 | ||
582 | q = XCALLOC(MTYPE_BGP_LABEL_CBQ, | |
583 | sizeof(struct lp_cbq_item)); | |
584 | q->cbfunc = lcb->cbfunc; | |
585 | q->type = lcb->type; | |
586 | q->label = lcb->label; | |
587 | q->labelid = lcb->labelid; | |
588 | q->allocated = false; | |
ea63ff6b | 589 | check_bgp_lu_cb_lock(lcb); |
955bfd98 PZ |
590 | work_queue_add(lp->callback_q, q); |
591 | ||
592 | lcb->label = MPLS_LABEL_NONE; | |
593 | } | |
594 | ||
595 | /* | |
596 | * request queue | |
597 | */ | |
598 | struct lp_fifo *lf = XCALLOC(MTYPE_BGP_LABEL_FIFO, | |
599 | sizeof(struct lp_fifo)); | |
600 | ||
601 | lf->lcb = *lcb; | |
ea63ff6b | 602 | check_bgp_lu_cb_lock(lcb); |
41397f2e | 603 | lp_fifo_add_tail(&lp->requests, lf); |
955bfd98 PZ |
604 | } |
605 | ||
606 | skiplist_delete_first(lp->inuse); | |
607 | } | |
608 | } |