Coverage Report

Created: 2025-12-12 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/frr/bgpd/rfapi/vnc_zebra.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 *
4
 * Copyright 2009-2016, LabN Consulting, L.L.C.
5
 *
6
 */
7
8
/*
9
 * File:  vnc_zebra.c
10
 * Purpose: Handle exchange of routes between VNC and Zebra
11
 */
12
13
#include "lib/zebra.h"
14
#include "lib/prefix.h"
15
#include "lib/agg_table.h"
16
#include "lib/log.h"
17
#include "lib/command.h"
18
#include "lib/zclient.h"
19
#include "lib/stream.h"
20
#include "lib/ringbuf.h"
21
#include "lib/memory.h"
22
#include "lib/lib_errors.h"
23
24
#include "bgpd/bgpd.h"
25
#include "bgpd/bgp_ecommunity.h"
26
#include "bgpd/bgp_route.h"
27
#include "bgpd/bgp_debug.h"
28
#include "bgpd/bgp_advertise.h"
29
30
#include "bgpd/rfapi/bgp_rfapi_cfg.h"
31
#include "bgpd/rfapi/rfapi.h"
32
#include "bgpd/rfapi/rfapi_import.h"
33
#include "bgpd/rfapi/rfapi_private.h"
34
#include "bgpd/rfapi/vnc_zebra.h"
35
#include "bgpd/rfapi/rfapi_vty.h"
36
#include "bgpd/rfapi/rfapi_backend.h"
37
#include "bgpd/rfapi/vnc_debug.h"
38
39
static struct rfapi_descriptor vncHD1VR; /* Single-VR export dummy nve descr */
40
static struct zclient *zclient_vnc = NULL;
41
42
/***********************************************************************
43
 *  REDISTRIBUTE: Zebra sends updates/withdraws to BGPD
44
 ***********************************************************************/
45
46
/*
47
 * Routes coming from zebra get added to VNC here
48
 */
49
static void vnc_redistribute_add(struct prefix *p, uint32_t metric,
50
         uint8_t type)
51
0
{
52
0
  struct bgp *bgp = bgp_get_default();
53
0
  struct prefix_rd prd;
54
0
  struct rfapi_ip_addr vnaddr;
55
0
  afi_t afi;
56
0
  uint32_t local_pref =
57
0
    rfp_cost_to_localpref(metric > 255 ? 255 : metric);
58
59
0
  if (!bgp)
60
0
    return;
61
62
0
  if (!bgp->rfapi_cfg) {
63
0
    vnc_zlog_debug_verbose("%s: bgp->rfapi_cfg is NULL, skipping",
64
0
               __func__);
65
0
    return;
66
0
  }
67
68
0
  afi = family2afi(p->family);
69
0
  if (!afi) {
70
0
    vnc_zlog_debug_verbose("%s: unknown prefix address family %d",
71
0
               __func__, p->family);
72
0
    return;
73
0
  }
74
75
0
  if (!bgp->rfapi_cfg->redist[afi][type]) {
76
0
    vnc_zlog_debug_verbose(
77
0
      "%s: bgp->rfapi_cfg->redist[afi=%d][type=%d] is 0, skipping",
78
0
      __func__, afi, type);
79
0
    return;
80
0
  }
81
0
  if (!bgp->rfapi_cfg->rfg_redist) {
82
0
    vnc_zlog_debug_verbose("%s: no redist nve group, skipping",
83
0
               __func__);
84
0
    return;
85
0
  }
86
87
  /*
88
   * Assume nve group's configured VN address prefix is a host
89
   * route which also happens to give the NVE VN address to use
90
   * for redistributing into VNC.
91
   */
92
0
  vnaddr.addr_family = bgp->rfapi_cfg->rfg_redist->vn_prefix.family;
93
0
  switch (bgp->rfapi_cfg->rfg_redist->vn_prefix.family) {
94
0
  case AF_INET:
95
0
    if (bgp->rfapi_cfg->rfg_redist->vn_prefix.prefixlen
96
0
        != IPV4_MAX_BITLEN) {
97
0
      vnc_zlog_debug_verbose(
98
0
        "%s: redist nve group VN prefix len (%d) != 32, skipping",
99
0
        __func__,
100
0
        bgp->rfapi_cfg->rfg_redist->vn_prefix
101
0
          .prefixlen);
102
0
      return;
103
0
    }
104
0
    vnaddr.addr.v4 =
105
0
      bgp->rfapi_cfg->rfg_redist->vn_prefix.u.prefix4;
106
0
    break;
107
0
  case AF_INET6:
108
0
    if (bgp->rfapi_cfg->rfg_redist->vn_prefix.prefixlen
109
0
        != IPV6_MAX_BITLEN) {
110
0
      vnc_zlog_debug_verbose(
111
0
        "%s: redist nve group VN prefix len (%d) != 128, skipping",
112
0
        __func__,
113
0
        bgp->rfapi_cfg->rfg_redist->vn_prefix
114
0
          .prefixlen);
115
0
      return;
116
0
    }
117
0
    vnaddr.addr.v6 =
118
0
      bgp->rfapi_cfg->rfg_redist->vn_prefix.u.prefix6;
119
0
    break;
120
0
  default:
121
0
    vnc_zlog_debug_verbose(
122
0
      "%s: no redist nve group VN host prefix configured, skipping",
123
0
      __func__);
124
0
    return;
125
0
  }
126
127
  /*
128
   * Assume nve group's configured UN address prefix is a host
129
   * route which also happens to give the NVE UN address to use
130
   * for redistributing into VNC.
131
   */
132
133
  /*
134
   * Set UN address in dummy nve descriptor so add_vnc_route
135
   * can use it in VNC tunnel SubTLV
136
   */
137
0
  {
138
0
    struct rfapi_ip_prefix pfx_un;
139
140
0
    rfapiQprefix2Rprefix(&bgp->rfapi_cfg->rfg_redist->un_prefix,
141
0
             &pfx_un);
142
143
0
    switch (pfx_un.prefix.addr_family) {
144
0
    case AF_INET:
145
0
      if (pfx_un.length != IPV4_MAX_BITLEN) {
146
0
        vnc_zlog_debug_verbose(
147
0
          "%s: redist nve group UN prefix len (%d) != 32, skipping",
148
0
          __func__, pfx_un.length);
149
0
        return;
150
0
      }
151
0
      break;
152
0
    case AF_INET6:
153
0
      if (pfx_un.length != IPV6_MAX_BITLEN) {
154
0
        vnc_zlog_debug_verbose(
155
0
          "%s: redist nve group UN prefix len (%d) != 128, skipping",
156
0
          __func__, pfx_un.length);
157
0
        return;
158
0
      }
159
0
      break;
160
0
    default:
161
0
      vnc_zlog_debug_verbose(
162
0
        "%s: no redist nve group UN host prefix configured, skipping",
163
0
        __func__);
164
0
      return;
165
0
    }
166
167
0
    vncHD1VR.un_addr = pfx_un.prefix;
168
169
0
    if (!vncHD1VR.peer) {
170
      /*
171
       * Same setup as in rfapi_open()
172
       */
173
0
      vncHD1VR.peer = peer_new(bgp);
174
0
      vncHD1VR.peer->status =
175
0
        Established; /* keep bgp core happy */
176
177
      /*
178
       * since this peer is not on the I/O thread, this lock
179
       * is not strictly necessary, but serves as a reminder
180
       * to those who may meddle...
181
       */
182
0
      frr_with_mutex (&vncHD1VR.peer->io_mtx) {
183
        // we don't need any I/O related facilities
184
0
        if (vncHD1VR.peer->ibuf)
185
0
          stream_fifo_free(vncHD1VR.peer->ibuf);
186
0
        if (vncHD1VR.peer->obuf)
187
0
          stream_fifo_free(vncHD1VR.peer->obuf);
188
189
0
        if (vncHD1VR.peer->ibuf_work)
190
0
          ringbuf_del(vncHD1VR.peer->ibuf_work);
191
192
0
        vncHD1VR.peer->ibuf = NULL;
193
0
        vncHD1VR.peer->obuf = NULL;
194
0
        vncHD1VR.peer->ibuf_work = NULL;
195
0
      }
196
197
      /* base code assumes have valid host pointer */
198
0
      vncHD1VR.peer->host =
199
0
        XSTRDUP(MTYPE_BGP_PEER_HOST, ".zebra.");
200
201
      /* Mark peer as belonging to HD */
202
0
      SET_FLAG(vncHD1VR.peer->flags, PEER_FLAG_IS_RFAPI_HD);
203
0
    }
204
0
  }
205
206
0
  memset(&prd, 0, sizeof(prd));
207
0
  prd = bgp->rfapi_cfg->rfg_redist->rd;
208
0
  prd.family = AF_UNSPEC;
209
0
  prd.prefixlen = 64;
210
211
0
  add_vnc_route(&vncHD1VR, /* cookie + UN addr */
212
0
          bgp, SAFI_MPLS_VPN, p, &prd, &vnaddr, &local_pref,
213
0
          &(bgp->rfapi_cfg->redist_lifetime),
214
0
          NULL, /* RFP options */
215
0
          NULL, /* struct rfapi_un_option */
216
0
          NULL, /* struct rfapi_vn_option */
217
0
          bgp->rfapi_cfg->rfg_redist->rt_export_list, NULL,
218
0
          NULL,       /* label: default */
219
0
          type, BGP_ROUTE_REDISTRIBUTE, 0); /* flags */
220
0
}
221
222
/*
223
 * Route deletions from zebra propagate to VNC here
224
 */
225
static void vnc_redistribute_delete(struct prefix *p, uint8_t type)
226
0
{
227
0
  struct bgp *bgp = bgp_get_default();
228
0
  struct prefix_rd prd;
229
0
  afi_t afi;
230
231
0
  if (!bgp)
232
0
    return;
233
234
0
  if (!bgp->rfapi_cfg) {
235
0
    vnc_zlog_debug_verbose("%s: bgp->rfapi_cfg is NULL, skipping",
236
0
               __func__);
237
0
    return;
238
0
  }
239
0
  afi = family2afi(p->family);
240
0
  if (!afi) {
241
0
    vnc_zlog_debug_verbose("%s: unknown prefix address family %d",
242
0
               __func__, p->family);
243
0
    return;
244
0
  }
245
0
  if (!bgp->rfapi_cfg->redist[afi][type]) {
246
0
    vnc_zlog_debug_verbose(
247
0
      "%s: bgp->rfapi_cfg->redist[afi=%d][type=%d] is 0, skipping",
248
0
      __func__, afi, type);
249
0
    return;
250
0
  }
251
0
  if (!bgp->rfapi_cfg->rfg_redist) {
252
0
    vnc_zlog_debug_verbose("%s: no redist nve group, skipping",
253
0
               __func__);
254
0
    return;
255
0
  }
256
257
0
  memset(&prd, 0, sizeof(prd));
258
0
  prd = bgp->rfapi_cfg->rfg_redist->rd;
259
0
  prd.family = AF_UNSPEC;
260
0
  prd.prefixlen = 64;
261
262
0
  del_vnc_route(&vncHD1VR, /* use dummy ptr as cookie */
263
0
          vncHD1VR.peer, bgp, SAFI_MPLS_VPN, p, &prd, type,
264
0
          BGP_ROUTE_REDISTRIBUTE, NULL, 0);
265
0
}
266
267
/*
268
 * Flush all redistributed routes of type <type>
269
 */
270
static void vnc_redistribute_withdraw(struct bgp *bgp, afi_t afi, uint8_t type)
271
0
{
272
0
  struct prefix_rd prd;
273
0
  struct bgp_table *table;
274
0
  struct bgp_dest *pdest;
275
0
  struct bgp_dest *dest;
276
277
0
  vnc_zlog_debug_verbose("%s: entry", __func__);
278
279
0
  if (!bgp)
280
0
    return;
281
0
  if (!bgp->rfapi_cfg) {
282
0
    vnc_zlog_debug_verbose("%s: bgp->rfapi_cfg is NULL, skipping",
283
0
               __func__);
284
0
    return;
285
0
  }
286
287
  /*
288
   * Loop over all the RDs
289
   */
290
0
  for (pdest = bgp_table_top(bgp->rib[afi][SAFI_MPLS_VPN]); pdest;
291
0
       pdest = bgp_route_next(pdest)) {
292
0
    const struct prefix *pdest_p = bgp_dest_get_prefix(pdest);
293
294
0
    memset(&prd, 0, sizeof(prd));
295
0
    prd.family = AF_UNSPEC;
296
0
    prd.prefixlen = 64;
297
0
    memcpy(prd.val, pdest_p->u.val, 8);
298
299
    /* This is the per-RD table of prefixes */
300
0
    table = bgp_dest_get_bgp_table_info(pdest);
301
0
    if (!table)
302
0
      continue;
303
304
0
    for (dest = bgp_table_top(table); dest;
305
0
         dest = bgp_route_next(dest)) {
306
307
0
      struct bgp_path_info *ri;
308
309
0
      for (ri = bgp_dest_get_bgp_path_info(dest); ri;
310
0
           ri = ri->next) {
311
0
        if (ri->type
312
0
            == type) { /* has matching redist type */
313
0
          break;
314
0
        }
315
0
      }
316
0
      if (ri) {
317
0
        del_vnc_route(
318
0
          &vncHD1VR, /* use dummy ptr as cookie */
319
0
          vncHD1VR.peer, bgp, SAFI_MPLS_VPN,
320
0
          bgp_dest_get_prefix(dest), &prd, type,
321
0
          BGP_ROUTE_REDISTRIBUTE, NULL, 0);
322
0
      }
323
0
    }
324
0
  }
325
0
  vnc_zlog_debug_verbose("%s: return", __func__);
326
0
}
327
328
/*
329
 * Zebra route add and delete treatment.
330
 *
331
 * Assumes 1 nexthop
332
 */
333
static int vnc_zebra_read_route(ZAPI_CALLBACK_ARGS)
334
0
{
335
0
  struct zapi_route api;
336
0
  int add;
337
338
0
  if (zapi_route_decode(zclient->ibuf, &api) < 0)
339
0
    return -1;
340
341
  /* we completely ignore srcdest routes for now. */
342
0
  if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
343
0
    return 0;
344
345
0
  add = (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD);
346
0
  if (add)
347
0
    vnc_redistribute_add(&api.prefix, api.metric, api.type);
348
0
  else
349
0
    vnc_redistribute_delete(&api.prefix, api.type);
350
351
0
  if (BGP_DEBUG(zebra, ZEBRA))
352
0
    vnc_zlog_debug_verbose(
353
0
      "%s: Zebra rcvd: route delete %s %pFX metric %u",
354
0
      __func__, zebra_route_string(api.type), &api.prefix,
355
0
      api.metric);
356
357
0
  return 0;
358
0
}
359
360
/***********************************************************************
361
 *  vnc_bgp_zebra_*: VNC sends updates/withdraws to Zebra
362
 ***********************************************************************/
363
364
/*
365
 * low-level message builder
366
 */
367
static void vnc_zebra_route_msg(const struct prefix *p, unsigned int nhp_count,
368
        void *nhp_ary, int add) /* 1 = add, 0 = del */
369
0
{
370
0
  struct zapi_route api;
371
0
  struct zapi_nexthop *api_nh;
372
0
  int i;
373
0
  struct in_addr **nhp_ary4 = nhp_ary;
374
0
  struct in6_addr **nhp_ary6 = nhp_ary;
375
376
0
  if (!nhp_count) {
377
0
    vnc_zlog_debug_verbose("%s: empty nexthop list, skipping",
378
0
               __func__);
379
0
    return;
380
0
  }
381
382
0
  memset(&api, 0, sizeof(api));
383
0
  api.vrf_id = VRF_DEFAULT;
384
0
  api.type = ZEBRA_ROUTE_VNC;
385
0
  api.safi = SAFI_UNICAST;
386
0
  api.prefix = *p;
387
388
  /* Nexthops */
389
0
  SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
390
0
  api.nexthop_num = MIN(nhp_count, multipath_num);
391
0
  for (i = 0; i < api.nexthop_num; i++) {
392
393
0
    api_nh = &api.nexthops[i];
394
0
    api_nh->vrf_id = VRF_DEFAULT;
395
0
    switch (p->family) {
396
0
    case AF_INET:
397
0
      memcpy(&api_nh->gate.ipv4, nhp_ary4[i],
398
0
             sizeof(api_nh->gate.ipv4));
399
0
      api_nh->type = NEXTHOP_TYPE_IPV4;
400
0
      break;
401
0
    case AF_INET6:
402
0
      memcpy(&api_nh->gate.ipv6, nhp_ary6[i],
403
0
             sizeof(api_nh->gate.ipv6));
404
0
      api_nh->type = NEXTHOP_TYPE_IPV6;
405
0
      break;
406
0
    }
407
0
  }
408
409
0
  if (BGP_DEBUG(zebra, ZEBRA))
410
0
    vnc_zlog_debug_verbose(
411
0
      "%s: Zebra send: route %s %pFX, nhp_count=%d", __func__,
412
0
      (add ? "add" : "del"), &api.prefix, nhp_count);
413
414
0
  zclient_route_send((add ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE),
415
0
         zclient_vnc, &api);
416
0
}
417
418
419
static void
420
nve_list_to_nh_array(uint8_t family, struct list *nve_list,
421
         unsigned int *nh_count_ret,
422
         void **nh_ary_ret,  /* returned address array */
423
         void **nhp_ary_ret) /* returned pointer array */
424
0
{
425
0
  int nve_count = listcount(nve_list);
426
427
0
  *nh_count_ret = 0;
428
0
  *nh_ary_ret = NULL;
429
0
  *nhp_ary_ret = NULL;
430
431
0
  if (!nve_count) {
432
0
    vnc_zlog_debug_verbose("%s: empty nve_list, skipping",
433
0
               __func__);
434
0
    return;
435
0
  }
436
437
0
  if (family == AF_INET) {
438
0
    struct listnode *ln;
439
0
    struct in_addr *iap;
440
0
    struct in_addr **v;
441
442
    /*
443
     * Array of nexthop addresses
444
     */
445
0
    *nh_ary_ret =
446
0
      XCALLOC(MTYPE_TMP, nve_count * sizeof(struct in_addr));
447
448
    /*
449
     * Array of pointers to nexthop addresses
450
     */
451
0
    *nhp_ary_ret = XCALLOC(MTYPE_TMP,
452
0
               nve_count * sizeof(struct in_addr *));
453
0
    iap = *nh_ary_ret;
454
0
    v = *nhp_ary_ret;
455
456
0
    for (ln = listhead(nve_list); ln; ln = listnextnode(ln)) {
457
458
0
      struct rfapi_descriptor *irfd;
459
0
      struct prefix nhp;
460
461
0
      irfd = listgetdata(ln);
462
463
0
      if (rfapiRaddr2Qprefix(&irfd->vn_addr, &nhp))
464
0
        continue;
465
466
0
      *iap = nhp.u.prefix4;
467
0
      *v = iap;
468
0
      vnc_zlog_debug_verbose(
469
0
        "%s: ipadr: (%p)<-0x%x, ptr: (%p)<-%p",
470
0
        __func__, iap, nhp.u.prefix4.s_addr, v, iap);
471
472
0
      ++iap;
473
0
      ++v;
474
0
      ++*nh_count_ret;
475
0
    }
476
477
0
  } else if (family == AF_INET6) {
478
479
0
    struct listnode *ln;
480
481
0
    *nh_ary_ret =
482
0
      XCALLOC(MTYPE_TMP, nve_count * sizeof(struct in6_addr));
483
484
0
    *nhp_ary_ret = XCALLOC(MTYPE_TMP,
485
0
               nve_count * sizeof(struct in6_addr *));
486
487
0
    for (ln = listhead(nve_list); ln; ln = listnextnode(ln)) {
488
489
0
      struct rfapi_descriptor *irfd;
490
0
      struct in6_addr *iap = *nh_ary_ret;
491
0
      struct in6_addr **v = *nhp_ary_ret;
492
0
      struct prefix nhp;
493
494
0
      irfd = listgetdata(ln);
495
496
0
      if (rfapiRaddr2Qprefix(&irfd->vn_addr, &nhp))
497
0
        continue;
498
499
0
      *iap = nhp.u.prefix6;
500
0
      *v = iap;
501
502
0
      ++iap;
503
0
      ++v;
504
0
      ++*nh_count_ret;
505
0
    }
506
0
  }
507
0
}
508
509
static void import_table_to_nve_list_zebra(struct bgp *bgp,
510
             struct rfapi_import_table *it,
511
             struct list **nves, uint8_t family)
512
0
{
513
0
  struct listnode *node;
514
0
  struct rfapi_rfg_name *rfgn;
515
516
  /*
517
   * Loop over the list of NVE-Groups configured for
518
   * exporting to direct-bgp.
519
   *
520
   * Build a list of NVEs that use this import table
521
   */
522
0
  *nves = NULL;
523
0
  for (ALL_LIST_ELEMENTS_RO(bgp->rfapi_cfg->rfg_export_zebra_l, node,
524
0
          rfgn)) {
525
526
    /*
527
     * If this NVE-Group's import table matches the current one
528
     */
529
0
    if (rfgn->rfg && rfgn->rfg->nves
530
0
        && rfgn->rfg->rfapi_import_table == it) {
531
532
0
      nve_group_to_nve_list(rfgn->rfg, nves, family);
533
0
    }
534
0
  }
535
0
}
536
537
static void vnc_zebra_add_del_prefix(struct bgp *bgp,
538
             struct rfapi_import_table *import_table,
539
             struct agg_node *rn,
540
             int add) /* !0 = add, 0 = del */
541
0
{
542
0
  struct list *nves;
543
0
  const struct prefix *p = agg_node_get_prefix(rn);
544
0
  unsigned int nexthop_count = 0;
545
0
  void *nh_ary = NULL;
546
0
  void *nhp_ary = NULL;
547
548
0
  vnc_zlog_debug_verbose("%s: entry, add=%d", __func__, add);
549
550
0
  if (zclient_vnc->sock < 0)
551
0
    return;
552
553
0
  if (p->family != AF_INET && p->family != AF_INET6) {
554
0
    flog_err(EC_LIB_DEVELOPMENT,
555
0
       "%s: invalid route node addr family", __func__);
556
0
    return;
557
0
  }
558
559
0
  if (!vrf_bitmap_check(
560
0
        zclient_vnc->redist[family2afi(p->family)][ZEBRA_ROUTE_VNC],
561
0
        VRF_DEFAULT))
562
0
    return;
563
564
0
  if (!bgp->rfapi_cfg) {
565
0
    vnc_zlog_debug_verbose("%s: bgp->rfapi_cfg is NULL, skipping",
566
0
               __func__);
567
0
    return;
568
0
  }
569
0
  if (!listcount(bgp->rfapi_cfg->rfg_export_zebra_l)) {
570
0
    vnc_zlog_debug_verbose(
571
0
      "%s: no zebra export nve group, skipping", __func__);
572
0
    return;
573
0
  }
574
575
0
  import_table_to_nve_list_zebra(bgp, import_table, &nves, p->family);
576
577
0
  if (nves) {
578
0
    nve_list_to_nh_array(p->family, nves, &nexthop_count, &nh_ary,
579
0
             &nhp_ary);
580
581
0
    list_delete(&nves);
582
583
0
    if (nexthop_count)
584
0
      vnc_zebra_route_msg(p, nexthop_count, nhp_ary, add);
585
0
  }
586
587
0
  XFREE(MTYPE_TMP, nhp_ary);
588
0
  XFREE(MTYPE_TMP, nh_ary);
589
0
}
590
591
void vnc_zebra_add_prefix(struct bgp *bgp,
592
        struct rfapi_import_table *import_table,
593
        struct agg_node *rn)
594
0
{
595
0
  vnc_zebra_add_del_prefix(bgp, import_table, rn, 1);
596
0
}
597
598
void vnc_zebra_del_prefix(struct bgp *bgp,
599
        struct rfapi_import_table *import_table,
600
        struct agg_node *rn)
601
0
{
602
0
  vnc_zebra_add_del_prefix(bgp, import_table, rn, 0);
603
0
}
604
605
606
static void vnc_zebra_add_del_nve(struct bgp *bgp, struct rfapi_descriptor *rfd,
607
          int add) /* 0 = del, !0 = add */
608
0
{
609
0
  struct listnode *node;
610
0
  struct rfapi_rfg_name *rfgn;
611
0
  struct rfapi_nve_group_cfg *rfg = rfd->rfg;
612
0
  afi_t afi = family2afi(rfd->vn_addr.addr_family);
613
0
  struct prefix nhp;
614
0
  void *pAddr;
615
616
0
  vnc_zlog_debug_verbose("%s: entry, add=%d", __func__, add);
617
618
0
  if (zclient_vnc->sock < 0)
619
0
    return;
620
621
0
  if (!vrf_bitmap_check(zclient_vnc->redist[afi][ZEBRA_ROUTE_VNC],
622
0
            VRF_DEFAULT))
623
0
    return;
624
625
0
  if (afi != AFI_IP && afi != AFI_IP6) {
626
0
    flog_err(EC_LIB_DEVELOPMENT, "%s: invalid vn addr family",
627
0
       __func__);
628
0
    return;
629
0
  }
630
631
0
  if (!bgp)
632
0
    return;
633
0
  if (!bgp->rfapi_cfg) {
634
0
    vnc_zlog_debug_verbose("%s: bgp->rfapi_cfg is NULL, skipping",
635
0
               __func__);
636
0
    return;
637
0
  }
638
639
0
  if (rfapiRaddr2Qprefix(&rfd->vn_addr, &nhp)) {
640
0
    vnc_zlog_debug_verbose("%s: can't convert vn address, skipping",
641
0
               __func__);
642
0
    return;
643
0
  }
644
645
0
  pAddr = &nhp.u.val;
646
647
  /*
648
   * Loop over the list of NVE-Groups configured for
649
   * exporting to zebra and see if this new NVE's
650
   * group is among them.
651
   */
652
0
  for (ALL_LIST_ELEMENTS_RO(bgp->rfapi_cfg->rfg_export_zebra_l, node,
653
0
          rfgn)) {
654
655
    /*
656
     * Yes, this NVE's group is configured for export to zebra
657
     */
658
0
    if (rfgn->rfg == rfg) {
659
660
0
      struct agg_table *rt = NULL;
661
0
      struct agg_node *rn;
662
0
      struct rfapi_import_table *import_table;
663
0
      import_table = rfg->rfapi_import_table;
664
665
0
      vnc_zlog_debug_verbose(
666
0
        "%s: this nve's group is in zebra export list",
667
0
        __func__);
668
669
0
      rt = import_table->imported_vpn[afi];
670
671
      /*
672
       * Walk the NVE-Group's VNC Import table
673
       */
674
0
      for (rn = agg_route_top(rt); rn;
675
0
           rn = agg_route_next(rn)) {
676
0
        if (!rn->info)
677
0
          continue;
678
679
0
        vnc_zlog_debug_verbose("%s: sending %s",
680
0
                   __func__,
681
0
                   (add ? "add" : "del"));
682
0
        vnc_zebra_route_msg(agg_node_get_prefix(rn), 1,
683
0
                &pAddr, add);
684
0
      }
685
0
    }
686
0
  }
687
0
}
688
689
void vnc_zebra_add_nve(struct bgp *bgp, struct rfapi_descriptor *rfd)
690
0
{
691
0
  vnc_zebra_add_del_nve(bgp, rfd, 1);
692
0
}
693
694
void vnc_zebra_del_nve(struct bgp *bgp, struct rfapi_descriptor *rfd)
695
0
{
696
0
  vnc_zebra_add_del_nve(bgp, rfd, 0);
697
0
}
698
699
static void vnc_zebra_add_del_group_afi(struct bgp *bgp,
700
          struct rfapi_nve_group_cfg *rfg,
701
          afi_t afi, int add)
702
0
{
703
0
  struct agg_table *rt = NULL;
704
0
  struct agg_node *rn;
705
0
  struct rfapi_import_table *import_table;
706
0
  uint8_t family = afi2family(afi);
707
708
0
  struct list *nves = NULL;
709
0
  unsigned int nexthop_count = 0;
710
0
  void *nh_ary = NULL;
711
0
  void *nhp_ary = NULL;
712
713
0
  vnc_zlog_debug_verbose("%s: entry", __func__);
714
0
  import_table = rfg->rfapi_import_table;
715
0
  if (!import_table) {
716
0
    vnc_zlog_debug_verbose(
717
0
      "%s: import table not defined, returning", __func__);
718
0
    return;
719
0
  }
720
721
0
  if (afi == AFI_IP || afi == AFI_IP6) {
722
0
    rt = import_table->imported_vpn[afi];
723
0
  } else {
724
0
    flog_err(EC_LIB_DEVELOPMENT, "%s: bad afi %d", __func__, afi);
725
0
    return;
726
0
  }
727
728
0
  if (!family) {
729
0
    flog_err(EC_LIB_DEVELOPMENT, "%s: computed bad family: %d",
730
0
       __func__, family);
731
0
    return;
732
0
  }
733
734
0
  if (!rfg->nves) {
735
    /* avoid segfault below if list doesn't exist */
736
0
    vnc_zlog_debug_verbose("%s: no NVEs in this group", __func__);
737
0
    return;
738
0
  }
739
740
0
  nve_group_to_nve_list(rfg, &nves, family);
741
0
  if (nves) {
742
0
    vnc_zlog_debug_verbose("%s: have nves", __func__);
743
0
    nve_list_to_nh_array(family, nves, &nexthop_count, &nh_ary,
744
0
             &nhp_ary);
745
746
0
    vnc_zlog_debug_verbose("%s: family: %d, nve count: %d",
747
0
               __func__, family, nexthop_count);
748
749
0
    list_delete(&nves);
750
751
0
    if (nexthop_count) {
752
      /*
753
       * Walk the NVE-Group's VNC Import table
754
       */
755
0
      for (rn = agg_route_top(rt); rn;
756
0
           rn = agg_route_next(rn)) {
757
0
        if (rn->info) {
758
0
          vnc_zebra_route_msg(
759
0
            agg_node_get_prefix(rn),
760
0
            nexthop_count, nhp_ary, add);
761
0
        }
762
0
      }
763
0
    }
764
0
    XFREE(MTYPE_TMP, nhp_ary);
765
0
    XFREE(MTYPE_TMP, nh_ary);
766
0
  }
767
0
}
768
769
void vnc_zebra_add_group(struct bgp *bgp, struct rfapi_nve_group_cfg *rfg)
770
0
{
771
0
  vnc_zebra_add_del_group_afi(bgp, rfg, AFI_IP, 1);
772
0
  vnc_zebra_add_del_group_afi(bgp, rfg, AFI_IP6, 1);
773
0
}
774
775
void vnc_zebra_del_group(struct bgp *bgp, struct rfapi_nve_group_cfg *rfg)
776
0
{
777
0
  vnc_zlog_debug_verbose("%s: entry", __func__);
778
0
  vnc_zebra_add_del_group_afi(bgp, rfg, AFI_IP, 0);
779
0
  vnc_zebra_add_del_group_afi(bgp, rfg, AFI_IP6, 0);
780
0
}
781
782
void vnc_zebra_reexport_group_afi(struct bgp *bgp,
783
          struct rfapi_nve_group_cfg *rfg, afi_t afi)
784
0
{
785
0
  struct listnode *node;
786
0
  struct rfapi_rfg_name *rfgn;
787
788
0
  for (ALL_LIST_ELEMENTS_RO(bgp->rfapi_cfg->rfg_export_zebra_l, node,
789
0
          rfgn)) {
790
791
0
    if (rfgn->rfg == rfg) {
792
0
      vnc_zebra_add_del_group_afi(bgp, rfg, afi, 0);
793
0
      vnc_zebra_add_del_group_afi(bgp, rfg, afi, 1);
794
0
      break;
795
0
    }
796
0
  }
797
0
}
798
799
800
/***********************************************************************
801
 *      CONTROL INTERFACE
802
 ***********************************************************************/
803
804
805
/* Other routes redistribution into BGP. */
806
int vnc_redistribute_set(struct bgp *bgp, afi_t afi, int type)
807
0
{
808
0
  if (!bgp->rfapi_cfg) {
809
0
    return CMD_WARNING_CONFIG_FAILED;
810
0
  }
811
812
  /* Set flag to BGP instance. */
813
0
  bgp->rfapi_cfg->redist[afi][type] = 1;
814
815
  //  bgp->redist[afi][type] = 1;
816
817
  /* Return if already redistribute flag is set. */
818
0
  if (vrf_bitmap_check(zclient_vnc->redist[afi][type], VRF_DEFAULT))
819
0
    return CMD_WARNING_CONFIG_FAILED;
820
821
0
  vrf_bitmap_set(zclient_vnc->redist[afi][type], VRF_DEFAULT);
822
823
  // vrf_bitmap_set(zclient_vnc->redist[afi][type], VRF_DEFAULT);
824
825
  /* Return if zebra connection is not established. */
826
0
  if (zclient_vnc->sock < 0)
827
0
    return CMD_WARNING_CONFIG_FAILED;
828
829
0
  if (BGP_DEBUG(zebra, ZEBRA))
830
0
    vnc_zlog_debug_verbose("Zebra send: redistribute add %s",
831
0
               zebra_route_string(type));
832
833
  /* Send distribute add message to zebra. */
834
0
  zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient_vnc, afi, type,
835
0
        0, VRF_DEFAULT);
836
837
0
  return CMD_SUCCESS;
838
0
}
839
840
/* Unset redistribution.  */
841
int vnc_redistribute_unset(struct bgp *bgp, afi_t afi, int type)
842
0
{
843
0
  vnc_zlog_debug_verbose("%s: type=%d entry", __func__, type);
844
845
0
  if (!bgp->rfapi_cfg) {
846
0
    vnc_zlog_debug_verbose("%s: return (no rfapi_cfg)", __func__);
847
0
    return CMD_WARNING_CONFIG_FAILED;
848
0
  }
849
850
  /* Unset flag from BGP instance. */
851
0
  bgp->rfapi_cfg->redist[afi][type] = 0;
852
853
  /* Return if zebra connection is disabled. */
854
0
  if (!vrf_bitmap_check(zclient_vnc->redist[afi][type], VRF_DEFAULT))
855
0
    return CMD_WARNING_CONFIG_FAILED;
856
0
  vrf_bitmap_unset(zclient_vnc->redist[afi][type], VRF_DEFAULT);
857
858
0
  if (bgp->rfapi_cfg->redist[AFI_IP][type] == 0
859
0
      && bgp->rfapi_cfg->redist[AFI_IP6][type] == 0
860
0
      && zclient_vnc->sock >= 0) {
861
    /* Send distribute delete message to zebra. */
862
0
    if (BGP_DEBUG(zebra, ZEBRA))
863
0
      vnc_zlog_debug_verbose(
864
0
        "Zebra send: redistribute delete %s",
865
0
        zebra_route_string(type));
866
0
    zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE, zclient_vnc,
867
0
          afi, type, 0, VRF_DEFAULT);
868
0
  }
869
870
  /* Withdraw redistributed routes from current BGP's routing table. */
871
0
  vnc_redistribute_withdraw(bgp, afi, type);
872
873
0
  vnc_zlog_debug_verbose("%s: return", __func__);
874
875
0
  return CMD_SUCCESS;
876
0
}
877
878
extern struct zebra_privs_t bgpd_privs;
879
880
static zclient_handler *const vnc_handlers[] = {
881
  [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = vnc_zebra_read_route,
882
  [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = vnc_zebra_read_route,
883
};
884
885
/*
886
 * Modeled after bgp_zebra.c'bgp_zebra_init()
887
 * Charriere asks, "Is it possible to carry two?"
888
 */
889
void vnc_zebra_init(struct event_loop *master)
890
1
{
891
  /* Set default values. */
892
1
  zclient_vnc = zclient_new(master, &zclient_options_default,
893
1
          vnc_handlers, array_size(vnc_handlers));
894
1
  zclient_init(zclient_vnc, ZEBRA_ROUTE_VNC, 0, &bgpd_privs);
895
1
}
896
897
void vnc_zebra_destroy(void)
898
0
{
899
0
  if (zclient_vnc == NULL)
900
0
    return;
901
0
  zclient_stop(zclient_vnc);
902
0
  zclient_free(zclient_vnc);
903
  zclient_vnc = NULL;
904
0
}