Coverage Report

Created: 2025-08-28 06:29

/src/frr/zebra/zebra_gr.c
Line
Count
Source (jump to first uncovered line)
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 * Zebra GR related helper functions.
4
 *
5
 * Portions:
6
 *  Copyright (C) 2019 VMware, Inc.
7
 *  et al.
8
 */
9
10
#include <zebra.h>
11
#include <libgen.h>
12
13
#include "lib/prefix.h"
14
#include "lib/command.h"
15
#include "lib/if.h"
16
#include "frrevent.h"
17
#include "lib/stream.h"
18
#include "lib/memory.h"
19
#include "lib/table.h"
20
#include "lib/network.h"
21
#include "lib/sockunion.h"
22
#include "lib/log.h"
23
#include "lib/zclient.h"
24
#include "lib/privs.h"
25
#include "lib/network.h"
26
#include "lib/buffer.h"
27
#include "lib/nexthop.h"
28
#include "lib/vrf.h"
29
#include "lib/libfrr.h"
30
#include "lib/sockopt.h"
31
32
#include "zebra/zebra_router.h"
33
#include "zebra/debug.h"
34
#include "zebra/zapi_msg.h"
35
36
DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_GR, "GR");
37
38
/*
39
 * Forward declaration.
40
 */
41
static struct zserv *zebra_gr_find_stale_client(struct zserv *client);
42
static void zebra_gr_route_stale_delete_timer_expiry(struct event *thread);
43
static int32_t zebra_gr_delete_stale_routes(struct client_gr_info *info);
44
static void zebra_gr_process_client_stale_routes(struct zserv *client,
45
             struct client_gr_info *info);
46
static void zebra_gr_delete_stale_route_table_afi(struct event *event);
47
/*
48
 * Debug macros.
49
 */
50
#define LOG_GR(msg, ...)                                                       \
51
0
  do {                                                                   \
52
0
    if (IS_ZEBRA_DEBUG_EVENT)                                      \
53
0
      zlog_debug(msg, ##__VA_ARGS__);                        \
54
0
  } while (0)
55
56
/*
57
 * Client connection functions
58
 */
59
60
/*
61
 * Function to clean all the stale clients,
62
 * function will also clean up all per instance
63
 * capabilities that are exchanged.
64
 */
65
void zebra_gr_stale_client_cleanup(struct list *client_list)
66
0
{
67
0
  struct listnode *node, *nnode;
68
0
  struct zserv *s_client = NULL;
69
0
  struct client_gr_info *info, *ninfo;
70
71
  /* Find the stale client */
72
0
  for (ALL_LIST_ELEMENTS(client_list, node, nnode, s_client)) {
73
74
0
    LOG_GR("%s: Stale client %s is being deleted", __func__,
75
0
           zebra_route_string(s_client->proto));
76
77
0
    TAILQ_FOREACH_SAFE (info, &s_client->gr_info_queue, gr_info,
78
0
            ninfo) {
79
80
      /* Cancel the stale timer */
81
0
      if (info->t_stale_removal != NULL) {
82
0
        EVENT_OFF(info->t_stale_removal);
83
0
        info->t_stale_removal = NULL;
84
0
        info->do_delete = true;
85
        /* Process the stale routes */
86
0
        event_execute(
87
0
          zrouter.master,
88
0
          zebra_gr_route_stale_delete_timer_expiry,
89
0
          info, 0);
90
0
      }
91
0
    }
92
0
  }
93
0
}
94
95
/*
96
 * A helper function to create client info.
97
 */
98
static struct client_gr_info *zebra_gr_client_info_create(struct zserv *client)
99
0
{
100
0
  struct client_gr_info *info;
101
102
0
  info = XCALLOC(MTYPE_ZEBRA_GR, sizeof(struct client_gr_info));
103
104
0
  info->stale_client_ptr = client;
105
106
0
  TAILQ_INSERT_TAIL(&(client->gr_info_queue), info, gr_info);
107
0
  return info;
108
0
}
109
110
/*
111
 * A helper function to delete and destroy client info.
112
 */
113
static void zebra_gr_client_info_delete(struct zserv *client,
114
          struct client_gr_info *info)
115
0
{
116
0
  struct vrf *vrf = vrf_lookup_by_id(info->vrf_id);
117
118
0
  TAILQ_REMOVE(&(client->gr_info_queue), info, gr_info);
119
120
0
  EVENT_OFF(info->t_stale_removal);
121
122
0
  LOG_GR("%s: Instance info is being deleted for client %s vrf %s(%u)",
123
0
         __func__, zebra_route_string(client->proto), VRF_LOGNAME(vrf),
124
0
         info->vrf_id);
125
126
  /* Delete all the stale routes. */
127
0
  info->do_delete = true;
128
0
  zebra_gr_delete_stale_routes(info);
129
130
0
  XFREE(MTYPE_ZEBRA_GR, info);
131
0
}
132
133
/*
134
 * Function to handle client when it disconnect.
135
 */
136
int32_t zebra_gr_client_disconnect(struct zserv *client)
137
0
{
138
0
  struct zserv *stale_client;
139
0
  struct timeval tv;
140
0
  struct client_gr_info *info = NULL;
141
142
  /* Find the stale client */
143
0
  stale_client = zebra_gr_find_stale_client(client);
144
145
  /*
146
   * We should never be here.
147
   */
148
0
  if (stale_client) {
149
0
    LOG_GR("%s: Stale client %s exist, we should not be here!",
150
0
           __func__, zebra_route_string(client->proto));
151
#ifndef FUZZING
152
    assert(0);
153
#endif
154
0
  }
155
156
0
  client->restart_time = monotime(&tv);
157
158
  /* For all the GR instance start the stale removal timer. */
159
0
#ifdef FUZZING
160
0
  struct client_gr_info dupinfo = {};
161
0
#endif
162
0
  TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) {
163
0
    if (ZEBRA_CLIENT_GR_ENABLED(info->capabilities)
164
0
        && (info->t_stale_removal == NULL)) {
165
0
      struct vrf *vrf = vrf_lookup_by_id(info->vrf_id);
166
167
0
      event_add_timer(
168
0
        zrouter.master,
169
0
        zebra_gr_route_stale_delete_timer_expiry, info,
170
0
        info->stale_removal_time,
171
0
        &info->t_stale_removal);
172
0
      info->stale_client_ptr = client;
173
0
      info->stale_client = true;
174
0
      LOG_GR("%s: Client %s vrf %s(%u) Stale timer update to %d",
175
0
             __func__, zebra_route_string(client->proto),
176
0
             VRF_LOGNAME(vrf), info->vrf_id,
177
0
             info->stale_removal_time);
178
179
0
      dupinfo = *info;
180
0
#ifdef FUZZING
181
      // yeah, that thread will never execute...clean it up now
182
      //struct thread t = {};
183
0
      struct event t = {};
184
0
      t.arg = info;
185
0
      info->t_stale_removal = &t;
186
0
      zebra_gr_route_stale_delete_timer_expiry(&t);
187
0
      info = &dupinfo;
188
0
#endif
189
0
    }
190
0
  }
191
#ifndef FUZZING
192
  listnode_add(zrouter.stale_client_list, client);
193
#endif
194
0
  return 0;
195
0
}
196
197
/*
198
 * Function to delete stale client
199
 */
200
static void zebra_gr_delete_stale_client(struct client_gr_info *info)
201
0
{
202
0
  struct client_gr_info *bgp_info;
203
0
  struct zserv *s_client = NULL;
204
0
  struct vrf *vrf = vrf_lookup_by_id(info->vrf_id);
205
206
0
  s_client = info->stale_client_ptr;
207
208
0
  if (!s_client || !info->stale_client)
209
0
    return;
210
211
  /*
212
   * If there are bgp instances with the stale delete timer pending
213
   * then stale client is not deleted
214
   */
215
0
  if ((s_client->gr_instance_count > 0) && info->gr_enable)
216
0
    s_client->gr_instance_count--;
217
218
0
  TAILQ_REMOVE(&(s_client->gr_info_queue), info, gr_info);
219
220
0
  LOG_GR("%s: Client %s gr count %d", __func__,
221
0
         zebra_route_string(s_client->proto),
222
0
         s_client->gr_instance_count);
223
224
0
  TAILQ_FOREACH (bgp_info, &s_client->gr_info_queue, gr_info) {
225
0
    if (bgp_info->t_stale_removal != NULL)
226
0
      return;
227
0
  }
228
229
0
  LOG_GR("%s: Client %s vrf %s(%u) is being deleted", __func__,
230
0
         zebra_route_string(s_client->proto), VRF_LOGNAME(vrf),
231
0
         info->vrf_id);
232
233
0
  TAILQ_INIT(&(s_client->gr_info_queue));
234
0
  listnode_delete(zrouter.stale_client_list, s_client);
235
0
  if (info->stale_client)
236
0
    zserv_client_delete(s_client);
237
0
  XFREE(MTYPE_ZEBRA_GR, info);
238
0
}
239
240
/*
241
 * Function to find stale client.
242
 */
243
static struct zserv *zebra_gr_find_stale_client(struct zserv *client)
244
0
{
245
0
  struct listnode *node, *nnode;
246
0
  struct zserv *stale_client;
247
248
  /* Find the stale client */
249
0
  for (ALL_LIST_ELEMENTS(zrouter.stale_client_list, node, nnode,
250
0
             stale_client)) {
251
0
    if (client->proto == stale_client->proto
252
0
        && client->instance == stale_client->instance) {
253
0
      return stale_client;
254
0
    }
255
0
  }
256
257
0
  return NULL;
258
0
}
259
260
/*
261
 * Function to handle reconnect of client post restart.
262
 */
263
void zebra_gr_client_reconnect(struct zserv *client)
264
0
{
265
0
  struct listnode *node, *nnode;
266
0
  struct zserv *old_client = NULL;
267
0
  struct client_gr_info *info = NULL;
268
269
  /* Find the stale client */
270
0
  for (ALL_LIST_ELEMENTS(zrouter.stale_client_list, node, nnode,
271
0
             old_client)) {
272
0
    if (client->proto == old_client->proto
273
0
        && client->instance == old_client->instance)
274
0
      break;
275
0
  }
276
277
  /* Copy the timers */
278
0
  if (!old_client)
279
0
    return;
280
281
0
  client->gr_instance_count = old_client->gr_instance_count;
282
0
  client->restart_time = old_client->restart_time;
283
284
0
  LOG_GR("%s : old client %s, gr_instance_count %d", __func__,
285
0
         zebra_route_string(old_client->proto),
286
0
         old_client->gr_instance_count);
287
288
0
  if (TAILQ_FIRST(&old_client->gr_info_queue)) {
289
0
    TAILQ_CONCAT(&client->gr_info_queue, &old_client->gr_info_queue,
290
0
           gr_info);
291
0
    TAILQ_INIT(&old_client->gr_info_queue);
292
0
  }
293
294
0
  TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) {
295
0
    info->stale_client_ptr = client;
296
0
    info->stale_client = false;
297
0
  }
298
299
  /* Delete the stale client */
300
0
  listnode_delete(zrouter.stale_client_list, old_client);
301
  /* Delete old client */
302
0
  zserv_client_delete(old_client);
303
0
}
304
305
struct zebra_gr_afi_clean {
306
  struct client_gr_info *info;
307
  afi_t afi;
308
  uint8_t proto;
309
  uint8_t instance;
310
311
  struct event *t_gac;
312
};
313
314
/*
315
 * Functions to deal with capabilities
316
 */
317
318
/*
319
 * Function to decode and call appropriate functions
320
 * to handle client capabilities.
321
 */
322
void zread_client_capabilities(ZAPI_HANDLER_ARGS)
323
0
{
324
0
  struct zapi_cap api;
325
0
  struct client_gr_info *info = NULL;
326
0
  struct stream *s;
327
0
  struct vrf *vrf;
328
329
0
  s = msg;
330
331
0
  if (zapi_capabilities_decode(s, &api)) {
332
0
    LOG_GR("%s: Error in reading capabilities for client %s",
333
0
           __func__, zebra_route_string(client->proto));
334
0
    return;
335
0
  }
336
337
0
  vrf = vrf_lookup_by_id(api.vrf_id);
338
339
  /*
340
   * If this ever matters uncomment and add safi to the
341
   * arrays as needed to track
342
   */
343
0
  if (api.safi != SAFI_UNICAST)
344
0
    return;
345
346
  /* GR only for dynamic clients */
347
0
  if (client->proto <= ZEBRA_ROUTE_CONNECT) {
348
0
    LOG_GR("%s: GR capabilities for client %s not supported",
349
0
           __func__, zebra_route_string(client->proto));
350
0
    return;
351
0
  }
352
353
  /* Find the bgp information for the specified vrf id */
354
0
  TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) {
355
0
    if (info->vrf_id == api.vrf_id)
356
0
      break;
357
0
  }
358
359
  /*
360
   * If the command is delete, then cancel the stale timer and
361
   * delete the bgp info
362
   */
363
0
  switch (api.cap) {
364
0
  case ZEBRA_CLIENT_GR_DISABLE:
365
0
    if (!info)
366
0
      return;
367
368
0
    LOG_GR("%s: Client %s instance GR disabled count %d", __func__,
369
0
           zebra_route_string(client->proto),
370
0
           client->gr_instance_count);
371
372
0
    if ((info->gr_enable) && (client->gr_instance_count > 0))
373
0
      client->gr_instance_count--;
374
375
0
    zebra_gr_client_info_delete(client, info);
376
0
    break;
377
0
  case ZEBRA_CLIENT_GR_CAPABILITIES:
378
    /* Allocate bgp info */
379
0
    if (!info)
380
0
      info = zebra_gr_client_info_create(client);
381
382
    /* Update other parameters */
383
0
    if (!info->gr_enable) {
384
0
      client->gr_instance_count++;
385
386
0
      LOG_GR("%s: Cient %s vrf %s(%u) GR enabled count %d",
387
0
             __func__, zebra_route_string(client->proto),
388
0
             VRF_LOGNAME(vrf), api.vrf_id,
389
0
             client->gr_instance_count);
390
391
0
      info->capabilities = api.cap;
392
0
      info->stale_removal_time = api.stale_removal_time;
393
0
      info->vrf_id = api.vrf_id;
394
0
      info->gr_enable = true;
395
0
    }
396
0
    break;
397
0
  case ZEBRA_CLIENT_RIB_STALE_TIME:
398
0
    LOG_GR("%s: Client %s stale time update event", __func__,
399
0
           zebra_route_string(client->proto));
400
401
    /* Update the stale removal timer */
402
0
    if (info && info->t_stale_removal == NULL) {
403
404
0
      LOG_GR("%s: vrf %s(%u) Stale time: %d is now update to: %d",
405
0
             __func__, VRF_LOGNAME(vrf), info->vrf_id,
406
0
             info->stale_removal_time,
407
0
             api.stale_removal_time);
408
409
0
      info->stale_removal_time = api.stale_removal_time;
410
0
    }
411
412
0
    break;
413
0
  case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE:
414
0
    if (!info) {
415
0
      LOG_GR("%s: Client %s route update complete for AFI %d, SAFI %d, no Graceful Restart communication, returning",
416
0
             __func__, zebra_route_string(client->proto),
417
0
             api.afi, api.safi);
418
0
      return;
419
0
    }
420
421
0
    LOG_GR("%s: Client %s vrf %s(%u) route update complete for AFI %d, SAFI %d",
422
0
           __func__, zebra_route_string(client->proto),
423
0
           VRF_LOGNAME(vrf), info->vrf_id, api.afi, api.safi);
424
0
    info->route_sync[api.afi] = true;
425
426
    /*
427
     * Schedule for after anything already in the meta Q
428
     */
429
0
    rib_add_gr_run(api.afi, api.vrf_id, client->proto,
430
0
             client->instance);
431
0
    zebra_gr_process_client_stale_routes(client, info);
432
0
    break;
433
0
  case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING:
434
0
    if (!info) {
435
0
      LOG_GR("%s: Client %s route update pending for AFI %d, SAFI %d",
436
0
             __func__, zebra_route_string(client->proto),
437
0
             api.afi, api.safi);
438
0
    } else {
439
0
      LOG_GR("%s: Client %s vrf %s(%u) route update pending for AFI %d, SAFI %d",
440
0
             __func__, zebra_route_string(client->proto),
441
0
             VRF_LOGNAME(vrf), info->vrf_id, api.afi,
442
0
             api.safi);
443
444
0
      info->af_enabled[api.afi] = true;
445
0
    }
446
0
    break;
447
0
  }
448
0
}
449
450
/*
451
 * Stale route handling
452
 */
453
454
/*
455
 * Delete all the stale routes that have not been refreshed
456
 * post restart.
457
 */
458
static void zebra_gr_route_stale_delete_timer_expiry(struct event *thread)
459
0
{
460
0
  struct client_gr_info *info = EVENT_ARG(thread);
461
0
  int32_t cnt = 0;
462
0
  struct zserv *client;
463
0
  struct vrf *vrf = vrf_lookup_by_id(info->vrf_id);
464
465
0
  client = (struct zserv *)info->stale_client_ptr;
466
467
0
  cnt = zebra_gr_delete_stale_routes(info);
468
469
  /* Restart the timer */
470
0
  if (cnt > 0) {
471
0
    LOG_GR("%s: Client %s vrf %s(%u) processed %d routes. Start timer again",
472
0
           __func__, zebra_route_string(client->proto),
473
0
           VRF_LOGNAME(vrf), info->vrf_id, cnt);
474
475
0
    event_add_timer(zrouter.master,
476
0
        zebra_gr_route_stale_delete_timer_expiry, info,
477
0
        ZEBRA_DEFAULT_STALE_UPDATE_DELAY,
478
0
        &info->t_stale_removal);
479
0
  } else {
480
    /* No routes to delete for the VRF */
481
0
    LOG_GR("%s: Client %s vrf %s(%u) all stale routes processed",
482
0
           __func__, zebra_route_string(client->proto),
483
0
           VRF_LOGNAME(vrf), info->vrf_id);
484
485
0
    zebra_gr_delete_stale_client(info);
486
0
  }
487
0
}
488
489
490
/*
491
 * Function to process to check if route entry is stale
492
 * or has been updated.
493
 *
494
 * Returns true when a node is deleted else false
495
 */
496
static bool zebra_gr_process_route_entry(struct zserv *client,
497
           struct route_node *rn,
498
           struct route_entry *re)
499
0
{
500
0
  /* If the route is not refreshed after restart, delete the entry */
501
0
  if (re->uptime < client->restart_time) {
502
0
    if (IS_ZEBRA_DEBUG_RIB)
503
0
      zlog_debug("%s: Client %s stale route %pFX is deleted",
504
0
           __func__, zebra_route_string(client->proto),
505
0
           &rn->p);
506
0
    rib_delnode(rn, re);
507
0
508
0
    return true;
509
0
  }
510
0
511
0
  return false;
512
0
}
513
514
static void zebra_gr_delete_stale_route_table_afi(struct event *event)
515
0
{
516
0
  struct zebra_gr_afi_clean *gac = EVENT_ARG(event);
517
0
  struct route_table *table;
518
0
  struct route_node *rn;
519
0
  struct route_entry *re, *next;
520
0
  struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(gac->info->vrf_id);
521
0
  int32_t n = 0;
522
0
523
0
  if (!zvrf)
524
0
    goto done;
525
0
526
0
  table = zvrf->table[gac->afi][SAFI_UNICAST];
527
0
  if (!table)
528
0
    goto done;
529
0
530
0
  for (rn = route_top(table); rn; rn = srcdest_route_next(rn)) {
531
0
    RNODE_FOREACH_RE_SAFE (rn, re, next) {
532
0
      if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
533
0
        continue;
534
0
535
0
      /* If the route refresh is received
536
0
       * after restart then do not delete
537
0
       * the route
538
0
       */
539
0
540
0
      if (re->type == gac->proto &&
541
0
          re->instance == gac->instance &&
542
0
          zebra_gr_process_route_entry(
543
0
            gac->info->stale_client_ptr, rn, re))
544
0
        n++;
545
0
546
0
      /* If the max route count is reached
547
0
       * then timer thread will be restarted
548
0
       * Store the current prefix and afi
549
0
       */
550
0
      if ((n >= ZEBRA_MAX_STALE_ROUTE_COUNT) &&
551
0
          (gac->info->do_delete == false)) {
552
0
        event_add_timer(
553
0
          zrouter.master,
554
0
          zebra_gr_delete_stale_route_table_afi,
555
0
          gac, ZEBRA_DEFAULT_STALE_UPDATE_DELAY,
556
0
          &gac->t_gac);
557
0
      }
558
0
    }
559
0
  }
560
0
561
0
done:
562
0
  XFREE(MTYPE_ZEBRA_GR, gac);
563
0
}
564
565
/*
566
 * This function walks through the route table for all vrf and deletes
567
 * the stale routes for the restarted client specified by the protocol
568
 * type
569
 */
570
static int32_t zebra_gr_delete_stale_route(struct client_gr_info *info,
571
             struct zebra_vrf *zvrf)
572
0
{
573
0
  afi_t afi;
574
0
  uint8_t proto;
575
0
  uint16_t instance;
576
0
  struct zserv *s_client;
577
578
0
  s_client = info->stale_client_ptr;
579
0
  if (s_client == NULL) {
580
0
    LOG_GR("%s: Stale client %s(%u) not present", __func__,
581
0
           zvrf->vrf->name, zvrf->vrf->vrf_id);
582
0
    return -1;
583
0
  }
584
585
0
  proto = s_client->proto;
586
0
  instance = s_client->instance;
587
588
0
  LOG_GR("%s: Client %s %s(%u) stale routes are being deleted", __func__,
589
0
         zebra_route_string(proto), zvrf->vrf->name, zvrf->vrf->vrf_id);
590
591
  /* Process routes for all AFI */
592
0
  for (afi = AFI_IP; afi < AFI_MAX; afi++) {
593
594
    /*
595
     * Schedule for immediately after anything in the
596
     * meta-Q
597
     */
598
0
    rib_add_gr_run(afi, info->vrf_id, proto, instance);
599
0
  }
600
0
  return 0;
601
0
}
602
603
/*
604
 * Delete the stale routes when client is restarted and routes are not
605
 * refreshed within the stale timeout
606
 */
607
static int32_t zebra_gr_delete_stale_routes(struct client_gr_info *info)
608
0
{
609
0
  struct zebra_vrf *zvrf;
610
0
  uint64_t cnt = 0;
611
612
0
  if (info == NULL)
613
0
    return -1;
614
615
0
  zvrf = zebra_vrf_lookup_by_id(info->vrf_id);
616
0
  if (zvrf == NULL) {
617
0
    LOG_GR("%s: Invalid VRF entry %u", __func__, info->vrf_id);
618
0
    return -1;
619
0
  }
620
621
0
  cnt = zebra_gr_delete_stale_route(info, zvrf);
622
0
  return cnt;
623
0
}
624
625
/*
626
 * This function checks if route update for all AFI, SAFI is completed
627
 * and cancels the stale timer
628
 */
629
static void zebra_gr_process_client_stale_routes(struct zserv *client,
630
             struct client_gr_info *info)
631
0
{
632
0
  afi_t afi;
633
634
0
  if (info == NULL)
635
0
    return;
636
637
  /* Check if route update completed for all AFI, SAFI */
638
0
  for (afi = AFI_IP; afi < AFI_MAX; afi++) {
639
0
    if (info->af_enabled[afi] && !info->route_sync[afi]) {
640
0
      struct vrf *vrf = vrf_lookup_by_id(info->vrf_id);
641
642
0
      LOG_GR("%s: Client %s vrf: %s(%u) route update not completed for AFI %d",
643
0
             __func__, zebra_route_string(client->proto),
644
0
             VRF_LOGNAME(vrf), info->vrf_id, afi);
645
0
      return;
646
0
    }
647
0
  }
648
649
  /*
650
   * Route update completed for all AFI, SAFI
651
   * Cancel the stale timer, routes are already being processed
652
   */
653
0
  if (info->t_stale_removal) {
654
0
    struct vrf *vrf = vrf_lookup_by_id(info->vrf_id);
655
656
0
    LOG_GR("%s: Client %s canceled stale delete timer vrf %s(%d)",
657
0
           __func__, zebra_route_string(client->proto),
658
0
           VRF_LOGNAME(vrf), info->vrf_id);
659
0
    EVENT_OFF(info->t_stale_removal);
660
0
  }
661
0
}
662
663
void zebra_gr_process_client(afi_t afi, vrf_id_t vrf_id, uint8_t proto,
664
           uint8_t instance)
665
0
{
666
0
  struct zserv *client = zserv_find_client(proto, instance);
667
0
  struct client_gr_info *info = NULL;
668
0
  struct zebra_gr_afi_clean *gac;
669
670
0
  if (client == NULL)
671
0
    return;
672
673
0
  TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) {
674
0
    if (info->vrf_id == vrf_id)
675
0
      break;
676
0
  }
677
678
0
  if (info == NULL)
679
0
    return;
680
681
0
  gac = XCALLOC(MTYPE_ZEBRA_GR, sizeof(*gac));
682
0
  gac->info = info;
683
0
  gac->afi = afi;
684
0
  gac->proto = proto;
685
0
  gac->instance = instance;
686
687
0
  event_add_event(zrouter.master, zebra_gr_delete_stale_route_table_afi,
688
0
      gac, 0, &gac->t_gac);
689
0
}