Coverage Report

Created: 2025-08-28 06:29

/src/frr/bgpd/rfapi/rfapi_import.c
Line
Count
Source (jump to first uncovered line)
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 * Copyright 2009-2016, LabN Consulting, L.L.C.
4
 */
5
6
/*
7
 * File:  rfapi_import.c
8
 * Purpose: Handle import of routes from BGP to RFAPI
9
 */
10
11
#include "lib/zebra.h"
12
#include "lib/prefix.h"
13
#include "lib/agg_table.h"
14
#include "lib/vty.h"
15
#include "lib/memory.h"
16
#include "lib/log.h"
17
#include "lib/skiplist.h"
18
#include "frrevent.h"
19
#include "lib/stream.h"
20
#include "lib/lib_errors.h"
21
22
#include "bgpd/bgpd.h"
23
#include "bgpd/bgp_ecommunity.h"
24
#include "bgpd/bgp_attr.h"
25
#include "bgpd/bgp_route.h"
26
#include "bgpd/bgp_mplsvpn.h" /* prefix_rd2str() */
27
#include "bgpd/bgp_vnc_types.h"
28
#include "bgpd/bgp_rd.h"
29
30
#include "bgpd/rfapi/rfapi.h"
31
#include "bgpd/rfapi/bgp_rfapi_cfg.h"
32
#include "bgpd/rfapi/rfapi_backend.h"
33
#include "bgpd/rfapi/rfapi_import.h"
34
#include "bgpd/rfapi/rfapi_private.h"
35
#include "bgpd/rfapi/rfapi_monitor.h"
36
#include "bgpd/rfapi/rfapi_nve_addr.h"
37
#include "bgpd/rfapi/rfapi_vty.h"
38
#include "bgpd/rfapi/vnc_export_bgp.h"
39
#include "bgpd/rfapi/vnc_export_bgp_p.h"
40
#include "bgpd/rfapi/vnc_zebra.h"
41
#include "bgpd/rfapi/vnc_import_bgp.h"
42
#include "bgpd/rfapi/vnc_import_bgp_p.h"
43
#include "bgpd/rfapi/rfapi_rib.h"
44
#include "bgpd/rfapi/rfapi_encap_tlv.h"
45
#include "bgpd/rfapi/vnc_debug.h"
46
47
#ifdef HAVE_GLIBC_BACKTRACE
48
/* for backtrace and friends */
49
#include <execinfo.h>
50
#endif /* HAVE_GLIBC_BACKTRACE */
51
52
#undef DEBUG_MONITOR_MOVE_SHORTER
53
#undef DEBUG_RETURNED_NHL
54
#undef DEBUG_ROUTE_COUNTERS
55
#undef DEBUG_ENCAP_MONITOR
56
#undef DEBUG_L2_EXTRA
57
#undef DEBUG_IT_NODES
58
#undef DEBUG_BI_SEARCH
59
60
/*
61
 * Allocated for each withdraw timer instance; freed when the timer
62
 * expires or is canceled
63
 */
64
struct rfapi_withdraw {
65
  struct rfapi_import_table *import_table;
66
  struct agg_node *node;
67
  struct bgp_path_info *info;
68
  safi_t safi; /* used only for bulk operations */
69
  /*
70
   * For import table node reference count checking (i.e., debugging).
71
   * Normally when a timer expires, lockoffset should be 0. However, if
72
   * the timer expiration function is called directly (e.g.,
73
   * rfapiExpireVpnNow), the node could be locked by a preceding
74
   * agg_route_top() or agg_route_next() in a loop, so we need to pass
75
   * this value in.
76
   */
77
  int lockoffset;
78
};
79
80
/*
81
 * DEBUG FUNCTION
82
 * It's evil and fiendish. It's compiler-dependent.
83
 * ? Might need LDFLAGS -rdynamic to produce all function names
84
 */
85
void rfapiDebugBacktrace(void)
86
0
{
87
0
#ifdef HAVE_GLIBC_BACKTRACE
88
0
#define RFAPI_DEBUG_BACKTRACE_NENTRIES  200
89
0
  void *buf[RFAPI_DEBUG_BACKTRACE_NENTRIES];
90
0
  char **syms;
91
0
  size_t i;
92
0
  size_t size;
93
94
0
  size = backtrace(buf, RFAPI_DEBUG_BACKTRACE_NENTRIES);
95
0
  syms = backtrace_symbols(buf, size);
96
97
0
  for (i = 0; i < size && i < RFAPI_DEBUG_BACKTRACE_NENTRIES; ++i) {
98
0
    vnc_zlog_debug_verbose("backtrace[%2zu]: %s", i, syms[i]);
99
0
  }
100
101
0
  free(syms);
102
#else
103
#endif
104
0
}
105
106
/*
107
 * DEBUG FUNCTION
108
 * Count remote routes and compare with actively-maintained values.
109
 * Abort if they disagree.
110
 */
111
void rfapiCheckRouteCount(void)
112
0
{
113
0
  struct bgp *bgp = bgp_get_default();
114
0
  struct rfapi *h;
115
0
  struct rfapi_import_table *it;
116
0
  afi_t afi;
117
118
0
  assert(bgp);
119
120
0
  h = bgp->rfapi;
121
0
  assert(h);
122
123
0
  for (it = h->imports; it; it = it->next) {
124
0
    for (afi = AFI_IP; afi < AFI_MAX; ++afi) {
125
126
0
      struct agg_table *rt;
127
0
      struct agg_node *rn;
128
129
0
      int holddown_count = 0;
130
0
      int imported_count = 0;
131
0
      int remote_count = 0;
132
133
0
      rt = it->imported_vpn[afi];
134
135
0
      for (rn = agg_route_top(rt); rn;
136
0
           rn = agg_route_next(rn)) {
137
0
        struct bgp_path_info *bpi;
138
0
        struct bgp_path_info *next;
139
140
0
        for (bpi = rn->info; bpi; bpi = next) {
141
0
          next = bpi->next;
142
143
0
          if (CHECK_FLAG(bpi->flags,
144
0
                   BGP_PATH_REMOVED)) {
145
0
            ++holddown_count;
146
147
0
          } else {
148
0
            if (!RFAPI_LOCAL_BI(bpi)) {
149
0
              if (RFAPI_DIRECT_IMPORT_BI(
150
0
                    bpi)) {
151
0
                ++imported_count;
152
0
              } else {
153
0
                ++remote_count;
154
0
              }
155
0
            }
156
0
          }
157
0
        }
158
0
      }
159
160
0
      if (it->holddown_count[afi] != holddown_count) {
161
0
        vnc_zlog_debug_verbose(
162
0
          "%s: it->holddown_count %d != holddown_count %d",
163
0
          __func__, it->holddown_count[afi],
164
0
          holddown_count);
165
0
        assert(0);
166
0
      }
167
0
      if (it->remote_count[afi] != remote_count) {
168
0
        vnc_zlog_debug_verbose(
169
0
          "%s: it->remote_count %d != remote_count %d",
170
0
          __func__, it->remote_count[afi],
171
0
          remote_count);
172
0
        assert(0);
173
0
      }
174
0
      if (it->imported_count[afi] != imported_count) {
175
0
        vnc_zlog_debug_verbose(
176
0
          "%s: it->imported_count %d != imported_count %d",
177
0
          __func__, it->imported_count[afi],
178
0
          imported_count);
179
0
        assert(0);
180
0
      }
181
0
    }
182
0
  }
183
0
}
184
185
#ifdef DEBUG_ROUTE_COUNTERS
186
#define VNC_ITRCCK do {rfapiCheckRouteCount();} while (0)
187
#else
188
#define VNC_ITRCCK
189
#endif
190
191
/*
192
 * Validate reference count for a node in an import table
193
 *
194
 * Normally lockoffset is 0 for nodes in quiescent state. However,
195
 * agg_unlock_node will delete the node if it is called when
196
 * node->lock == 1, and we have to validate the refcount before
197
 * the node is deleted. In this case, we specify lockoffset 1.
198
 */
199
void rfapiCheckRefcount(struct agg_node *rn, safi_t safi, int lockoffset)
200
0
{
201
0
  unsigned int count_bpi = 0;
202
0
  unsigned int count_monitor = 0;
203
0
  struct bgp_path_info *bpi;
204
0
  struct rfapi_monitor_encap *hme;
205
0
  struct rfapi_monitor_vpn *hmv;
206
207
0
  for (bpi = rn->info; bpi; bpi = bpi->next)
208
0
    ++count_bpi;
209
210
211
0
  if (rn->aggregate) {
212
0
    ++count_monitor; /* rfapi_it_extra */
213
214
0
    switch (safi) {
215
0
      void *cursor;
216
0
      int rc;
217
218
0
    case SAFI_ENCAP:
219
0
      for (hme = RFAPI_MONITOR_ENCAP(rn); hme;
220
0
           hme = hme->next)
221
0
        ++count_monitor;
222
0
      break;
223
224
0
    case SAFI_MPLS_VPN:
225
226
0
      for (hmv = RFAPI_MONITOR_VPN(rn); hmv; hmv = hmv->next)
227
0
        ++count_monitor;
228
229
0
      if (RFAPI_MONITOR_EXTERIOR(rn)->source) {
230
0
        ++count_monitor; /* sl */
231
0
        cursor = NULL;
232
0
        for (rc = skiplist_next(
233
0
               RFAPI_MONITOR_EXTERIOR(rn)->source,
234
0
               NULL, NULL, &cursor);
235
0
             !rc;
236
0
             rc = skiplist_next(
237
0
               RFAPI_MONITOR_EXTERIOR(rn)->source,
238
0
               NULL, NULL, &cursor)) {
239
240
0
          ++count_monitor; /* sl entry */
241
0
        }
242
0
      }
243
0
      break;
244
245
0
    case SAFI_UNSPEC:
246
0
    case SAFI_UNICAST:
247
0
    case SAFI_MULTICAST:
248
0
    case SAFI_EVPN:
249
0
    case SAFI_LABELED_UNICAST:
250
0
    case SAFI_FLOWSPEC:
251
0
    case SAFI_MAX:
252
0
      assert(!"Passed in safi should be impossible");
253
0
    }
254
0
  }
255
256
0
  if (count_bpi + count_monitor + lockoffset
257
0
      != agg_node_get_lock_count(rn)) {
258
0
    vnc_zlog_debug_verbose(
259
0
      "%s: count_bpi=%d, count_monitor=%d, lockoffset=%d, rn->lock=%d",
260
0
      __func__, count_bpi, count_monitor, lockoffset,
261
0
      agg_node_get_lock_count(rn));
262
0
    assert(0);
263
0
  }
264
0
}
265
266
/*
267
 * Perform deferred rfapi_close operations that were queued
268
 * during callbacks.
269
 */
270
static wq_item_status rfapi_deferred_close_workfunc(struct work_queue *q,
271
                void *data)
272
0
{
273
0
  struct rfapi_descriptor *rfd = data;
274
0
  struct rfapi *h = q->spec.data;
275
276
0
  assert(!(h->flags & RFAPI_INCALLBACK));
277
0
  rfapi_close(rfd);
278
0
  vnc_zlog_debug_verbose("%s: completed deferred close on handle %p",
279
0
             __func__, rfd);
280
0
  return WQ_SUCCESS;
281
0
}
282
283
/*
284
 * Extract layer 2 option from Encap TLVS in BGP attrs
285
 */
286
int rfapiGetL2o(struct attr *attr, struct rfapi_l2address_option *l2o)
287
0
{
288
0
  if (attr) {
289
0
    struct bgp_attr_encap_subtlv *pEncap;
290
291
0
    for (pEncap = bgp_attr_get_vnc_subtlvs(attr); pEncap;
292
0
         pEncap = pEncap->next) {
293
294
0
      if (pEncap->type == BGP_VNC_SUBTLV_TYPE_RFPOPTION) {
295
0
        if (pEncap->value[0]
296
0
            == RFAPI_VN_OPTION_TYPE_L2ADDR) {
297
298
0
          if (pEncap->value[1] == 14) {
299
0
            memcpy(l2o->macaddr.octet,
300
0
                   pEncap->value + 2,
301
0
                   ETH_ALEN);
302
0
            l2o->label =
303
0
              ((pEncap->value[10]
304
0
                >> 4)
305
0
               & 0x0f)
306
0
              + ((pEncap->value[9]
307
0
                  << 4)
308
0
                 & 0xff0)
309
0
              + ((pEncap->value[8]
310
0
                  << 12)
311
0
                 & 0xff000);
312
313
0
            l2o->local_nve_id =
314
0
              pEncap->value[12];
315
316
0
            l2o->logical_net_id =
317
0
              (pEncap->value[15]
318
0
               & 0xff)
319
0
              + ((pEncap->value[14]
320
0
                  << 8)
321
0
                 & 0xff00)
322
0
              + ((pEncap->value[13]
323
0
                  << 16)
324
0
                 & 0xff0000);
325
0
          }
326
327
0
          return 0;
328
0
        }
329
0
      }
330
0
    }
331
0
  }
332
333
0
  return ENOENT;
334
0
}
335
336
/*
337
 * Extract the lifetime from the Tunnel Encap attribute of a route in
338
 * an import table
339
 */
340
int rfapiGetVncLifetime(struct attr *attr, uint32_t *lifetime)
341
0
{
342
0
  struct bgp_attr_encap_subtlv *pEncap;
343
344
0
  *lifetime = RFAPI_INFINITE_LIFETIME; /* default to infinite */
345
346
0
  if (attr) {
347
348
0
    for (pEncap = bgp_attr_get_vnc_subtlvs(attr); pEncap;
349
0
         pEncap = pEncap->next) {
350
351
0
      if (pEncap->type
352
0
          == BGP_VNC_SUBTLV_TYPE_LIFETIME) { /* lifetime */
353
0
        if (pEncap->length == 4) {
354
0
          memcpy(lifetime, pEncap->value, 4);
355
0
          *lifetime = ntohl(*lifetime);
356
0
          return 0;
357
0
        }
358
0
      }
359
0
    }
360
0
  }
361
362
0
  return ENOENT;
363
0
}
364
365
/*
366
 * Look for UN address in Encap attribute
367
 */
368
int rfapiGetVncTunnelUnAddr(struct attr *attr, struct prefix *p)
369
0
{
370
0
  struct bgp_attr_encap_subtlv *pEncap;
371
0
  bgp_encap_types tun_type = BGP_ENCAP_TYPE_MPLS;/*Default tunnel type*/
372
373
0
  bgp_attr_extcom_tunnel_type(attr, &tun_type);
374
0
  if (tun_type == BGP_ENCAP_TYPE_MPLS) {
375
0
    if (!p)
376
0
      return 0;
377
    /* MPLS carries UN address in next hop */
378
0
    rfapiNexthop2Prefix(attr, p);
379
0
    if (p->family != AF_UNSPEC)
380
0
      return 0;
381
382
0
    return ENOENT;
383
0
  }
384
0
  if (attr) {
385
0
    for (pEncap = attr->encap_subtlvs; pEncap;
386
0
         pEncap = pEncap->next) {
387
388
0
      if (pEncap->type
389
0
          == BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT) { /* un
390
                     addr
391
                     */
392
0
        switch (pEncap->length) {
393
0
        case 8:
394
0
          if (p) {
395
0
            p->family = AF_INET;
396
0
            p->prefixlen = IPV4_MAX_BITLEN;
397
0
            memcpy(p->u.val, pEncap->value,
398
0
                   4);
399
0
          }
400
0
          return 0;
401
402
0
        case 20:
403
0
          if (p) {
404
0
            p->family = AF_INET6;
405
0
            p->prefixlen = IPV6_MAX_BITLEN;
406
0
            memcpy(p->u.val, pEncap->value,
407
0
                   16);
408
0
          }
409
0
          return 0;
410
0
        }
411
0
      }
412
0
    }
413
0
  }
414
415
0
  return ENOENT;
416
0
}
417
418
/*
419
 * Get UN address wherever it might be
420
 */
421
int rfapiGetUnAddrOfVpnBi(struct bgp_path_info *bpi, struct prefix *p)
422
0
{
423
  /* If it's in this route's VNC attribute, we're done */
424
0
  if (!rfapiGetVncTunnelUnAddr(bpi->attr, p))
425
0
    return 0;
426
  /*
427
   * Otherwise, see if it's cached from a corresponding ENCAP SAFI
428
   * advertisement
429
   */
430
0
  if (bpi->extra) {
431
0
    switch (bpi->extra->vnc.import.un_family) {
432
0
    case AF_INET:
433
0
      if (p) {
434
0
        p->family = bpi->extra->vnc.import.un_family;
435
0
        p->u.prefix4 = bpi->extra->vnc.import.un.addr4;
436
0
        p->prefixlen = IPV4_MAX_BITLEN;
437
0
      }
438
0
      return 0;
439
0
    case AF_INET6:
440
0
      if (p) {
441
0
        p->family = bpi->extra->vnc.import.un_family;
442
0
        p->u.prefix6 = bpi->extra->vnc.import.un.addr6;
443
0
        p->prefixlen = IPV6_MAX_BITLEN;
444
0
      }
445
0
      return 0;
446
0
    default:
447
0
      if (p)
448
0
        p->family = AF_UNSPEC;
449
#ifdef DEBUG_ENCAP_MONITOR
450
      vnc_zlog_debug_verbose(
451
        "%s: bpi->extra->vnc.import.un_family is 0, no UN addr",
452
        __func__);
453
#endif
454
0
      break;
455
0
    }
456
0
  }
457
458
0
  return ENOENT;
459
0
}
460
461
462
/*
463
 * Make a new bgp_path_info from gathered parameters
464
 */
465
static struct bgp_path_info *rfapiBgpInfoCreate(struct attr *attr,
466
            struct peer *peer, void *rfd,
467
            struct prefix_rd *prd,
468
            uint8_t type, uint8_t sub_type,
469
            uint32_t *label)
470
0
{
471
0
  struct bgp_path_info *new;
472
473
0
  new = info_make(type, sub_type, 0, peer, attr, NULL);
474
475
0
  new->attr = bgp_attr_intern(attr);
476
477
0
  bgp_path_info_extra_get(new);
478
0
  if (prd) {
479
0
    new->extra->vnc.import.rd = *prd;
480
0
    new->extra->vnc.import.create_time = monotime(NULL);
481
0
  }
482
0
  if (label)
483
0
    encode_label(*label, &new->extra->label[0]);
484
485
0
  peer_lock(peer);
486
487
0
  return new;
488
0
}
489
490
/*
491
 * Frees bgp_path_info as used in import tables (parts are not
492
 * allocated exactly the way they are in the main RIBs)
493
 */
494
static void rfapiBgpInfoFree(struct bgp_path_info *goner)
495
0
{
496
0
  if (!goner)
497
0
    return;
498
499
0
  if (goner->peer) {
500
0
    vnc_zlog_debug_verbose("%s: calling peer_unlock(%p), #%d",
501
0
               __func__, goner->peer,
502
0
               goner->peer->lock);
503
0
    peer_unlock(goner->peer);
504
0
  }
505
506
0
  bgp_attr_unintern(&goner->attr);
507
508
0
  if (goner->extra)
509
0
    bgp_path_info_extra_free(&goner->extra);
510
0
  XFREE(MTYPE_BGP_ROUTE, goner);
511
0
}
512
513
struct rfapi_import_table *rfapiMacImportTableGetNoAlloc(struct bgp *bgp,
514
               uint32_t lni)
515
0
{
516
0
  struct rfapi *h;
517
0
  struct rfapi_import_table *it = NULL;
518
0
  uintptr_t lni_as_ptr = lni;
519
520
0
  h = bgp->rfapi;
521
0
  if (!h)
522
0
    return NULL;
523
524
0
  if (!h->import_mac)
525
0
    return NULL;
526
527
0
  if (skiplist_search(h->import_mac, (void *)lni_as_ptr, (void **)&it))
528
0
    return NULL;
529
530
0
  return it;
531
0
}
532
533
struct rfapi_import_table *rfapiMacImportTableGet(struct bgp *bgp, uint32_t lni)
534
0
{
535
0
  struct rfapi *h;
536
0
  struct rfapi_import_table *it = NULL;
537
0
  uintptr_t lni_as_ptr = lni;
538
539
0
  h = bgp->rfapi;
540
0
  assert(h);
541
542
0
  if (!h->import_mac) {
543
    /* default cmp is good enough for LNI */
544
0
    h->import_mac = skiplist_new(0, NULL, NULL);
545
0
  }
546
547
0
  if (skiplist_search(h->import_mac, (void *)lni_as_ptr, (void **)&it)) {
548
549
0
    struct ecommunity *enew;
550
0
    struct ecommunity_val eval;
551
0
    afi_t afi;
552
553
0
    it = XCALLOC(MTYPE_RFAPI_IMPORTTABLE,
554
0
           sizeof(struct rfapi_import_table));
555
    /* set RT list of new import table based on LNI */
556
0
    memset((char *)&eval, 0, sizeof(eval));
557
0
    eval.val[0] = 0; /* VNC L2VPN */
558
0
    eval.val[1] = 2; /* VNC L2VPN */
559
0
    eval.val[5] = (lni >> 16) & 0xff;
560
0
    eval.val[6] = (lni >> 8) & 0xff;
561
0
    eval.val[7] = (lni >> 0) & 0xff;
562
563
0
    enew = ecommunity_new();
564
0
    ecommunity_add_val(enew, &eval, false, false);
565
0
    it->rt_import_list = enew;
566
567
0
    for (afi = AFI_IP; afi < AFI_MAX; ++afi) {
568
0
      it->imported_vpn[afi] = agg_table_init();
569
0
      it->imported_encap[afi] = agg_table_init();
570
0
    }
571
572
0
    it->l2_logical_net_id = lni;
573
574
0
    skiplist_insert(h->import_mac, (void *)lni_as_ptr, it);
575
0
  }
576
577
0
  assert(it);
578
0
  return it;
579
0
}
580
581
/*
582
 * Implement MONITOR_MOVE_SHORTER(original_node) from
583
 * RFAPI-Import-Event-Handling.txt
584
 *
585
 * Returns pointer to the list of moved monitors
586
 */
587
static struct rfapi_monitor_vpn *
588
rfapiMonitorMoveShorter(struct agg_node *original_vpn_node, int lockoffset)
589
0
{
590
0
  struct bgp_path_info *bpi;
591
0
  struct agg_node *par;
592
0
  struct rfapi_monitor_vpn *m;
593
0
  struct rfapi_monitor_vpn *mlast;
594
0
  struct rfapi_monitor_vpn *moved;
595
0
  int movecount = 0;
596
0
  int parent_already_refcounted = 0;
597
598
0
  RFAPI_CHECK_REFCOUNT(original_vpn_node, SAFI_MPLS_VPN, lockoffset);
599
600
#ifdef DEBUG_MONITOR_MOVE_SHORTER
601
  {
602
    vnc_zlog_debug_verbose("%s: called with node pfx=%pFX",
603
               __func__, &original_vpn_node->p);
604
  }
605
#endif
606
607
  /*
608
   * 1. If there is at least one bpi (either regular route or
609
   *    route marked as withdrawn, with a pending timer) at
610
   *    original_node with a valid UN address, we're done. Return.
611
   */
612
0
  for (bpi = original_vpn_node->info; bpi; bpi = bpi->next) {
613
0
    struct prefix pfx;
614
615
0
    if (!rfapiGetUnAddrOfVpnBi(bpi, &pfx)) {
616
#ifdef DEBUG_MONITOR_MOVE_SHORTER
617
      vnc_zlog_debug_verbose(
618
        "%s: have valid UN at original node, no change",
619
        __func__);
620
#endif
621
0
      return NULL;
622
0
    }
623
0
  }
624
625
  /*
626
   * 2. Travel up the tree (toward less-specific prefixes) from
627
   *    original_node to find the first node that has at least
628
   *    one route (even if it is only a withdrawn route) with a
629
   *    valid UN address. Call this node "Node P."
630
   */
631
0
  for (par = agg_node_parent(original_vpn_node); par;
632
0
       par = agg_node_parent(par)) {
633
0
    for (bpi = par->info; bpi; bpi = bpi->next) {
634
0
      struct prefix pfx;
635
0
      if (!rfapiGetUnAddrOfVpnBi(bpi, &pfx)) {
636
0
        break;
637
0
      }
638
0
    }
639
0
    if (bpi)
640
0
      break;
641
0
  }
642
643
0
  if (par) {
644
0
    RFAPI_CHECK_REFCOUNT(par, SAFI_MPLS_VPN, 0);
645
0
  }
646
647
  /*
648
   * If no less-specific routes, try to use the 0/0 node
649
   */
650
0
  if (!par) {
651
0
    const struct prefix *p;
652
    /* this isn't necessarily 0/0 */
653
0
    par = agg_route_table_top(original_vpn_node);
654
655
0
    if (par)
656
0
      p = agg_node_get_prefix(par);
657
    /*
658
     * If we got the top node but it wasn't 0/0,
659
     * ignore it
660
     */
661
0
    if (par && p->prefixlen) {
662
0
      agg_unlock_node(par); /* maybe free */
663
0
      par = NULL;
664
0
    }
665
666
0
    if (par) {
667
0
      ++parent_already_refcounted;
668
0
    }
669
0
  }
670
671
  /*
672
   * Create 0/0 node if it isn't there
673
   */
674
0
  if (!par) {
675
0
    struct prefix pfx_default;
676
0
    const struct prefix *p = agg_node_get_prefix(original_vpn_node);
677
678
0
    memset(&pfx_default, 0, sizeof(pfx_default));
679
0
    pfx_default.family = p->family;
680
681
    /* creates default node if none exists */
682
0
    par = agg_node_get(agg_get_table(original_vpn_node),
683
0
           &pfx_default);
684
0
    ++parent_already_refcounted;
685
0
  }
686
687
  /*
688
   * 3. Move each of the monitors found at original_node to Node P.
689
   *    These are "Moved Monitors."
690
   *
691
   */
692
693
  /*
694
   * Attach at end so that the list pointer we return points
695
   * only to the moved routes
696
   */
697
0
  for (m = RFAPI_MONITOR_VPN(par), mlast = NULL; m;
698
0
       mlast = m, m = m->next)
699
0
    ;
700
701
0
  if (mlast) {
702
0
    moved = mlast->next = RFAPI_MONITOR_VPN(original_vpn_node);
703
0
  } else {
704
0
    moved = RFAPI_MONITOR_VPN_W_ALLOC(par) =
705
0
      RFAPI_MONITOR_VPN(original_vpn_node);
706
0
  }
707
0
  if (RFAPI_MONITOR_VPN(
708
0
        original_vpn_node)) /* check agg, so not allocated */
709
0
    RFAPI_MONITOR_VPN_W_ALLOC(original_vpn_node) = NULL;
710
711
  /*
712
   * update the node pointers on the monitors
713
   */
714
0
  for (m = moved; m; m = m->next) {
715
0
    ++movecount;
716
0
    m->node = par;
717
0
  }
718
719
0
  RFAPI_CHECK_REFCOUNT(par, SAFI_MPLS_VPN,
720
0
           parent_already_refcounted - movecount);
721
0
  while (movecount > parent_already_refcounted) {
722
0
    agg_lock_node(par);
723
0
    ++parent_already_refcounted;
724
0
  }
725
0
  while (movecount < parent_already_refcounted) {
726
    /* unlikely, but code defensively */
727
0
    agg_unlock_node(par);
728
0
    --parent_already_refcounted;
729
0
  }
730
0
  RFAPI_CHECK_REFCOUNT(original_vpn_node, SAFI_MPLS_VPN,
731
0
           movecount + lockoffset);
732
0
  while (movecount--) {
733
0
    agg_unlock_node(original_vpn_node);
734
0
  }
735
736
#ifdef DEBUG_MONITOR_MOVE_SHORTER
737
  {
738
    vnc_zlog_debug_verbose("%s: moved to node pfx=%pFX", __func__,
739
               &par->p);
740
  }
741
#endif
742
743
744
0
  return moved;
745
0
}
746
747
/*
748
 * Implement MONITOR_MOVE_LONGER(new_node) from
749
 * RFAPI-Import-Event-Handling.txt
750
 */
751
static void rfapiMonitorMoveLonger(struct agg_node *new_vpn_node)
752
0
{
753
0
  struct rfapi_monitor_vpn *monitor;
754
0
  struct rfapi_monitor_vpn *mlast;
755
0
  struct bgp_path_info *bpi;
756
0
  struct agg_node *par;
757
0
  const struct prefix *new_vpn_node_p = agg_node_get_prefix(new_vpn_node);
758
759
0
  RFAPI_CHECK_REFCOUNT(new_vpn_node, SAFI_MPLS_VPN, 0);
760
761
  /*
762
   * Make sure we have at least one valid route at the new node
763
   */
764
0
  for (bpi = new_vpn_node->info; bpi; bpi = bpi->next) {
765
0
    struct prefix pfx;
766
0
    if (!rfapiGetUnAddrOfVpnBi(bpi, &pfx))
767
0
      break;
768
0
  }
769
770
0
  if (!bpi) {
771
0
    vnc_zlog_debug_verbose(
772
0
      "%s: no valid routes at node %p, so not attempting moves",
773
0
      __func__, new_vpn_node);
774
0
    return;
775
0
  }
776
777
  /*
778
   * Find first parent node that has monitors
779
   */
780
0
  for (par = agg_node_parent(new_vpn_node); par;
781
0
       par = agg_node_parent(par)) {
782
0
    if (RFAPI_MONITOR_VPN(par))
783
0
      break;
784
0
  }
785
786
0
  if (!par) {
787
0
    vnc_zlog_debug_verbose(
788
0
      "%s: no parent nodes with monitors, done", __func__);
789
0
    return;
790
0
  }
791
792
  /*
793
   * Check each of these monitors to see of their longest-match
794
   * is now the updated node. Move any such monitors to the more-
795
   * specific updated node
796
   */
797
0
  for (mlast = NULL, monitor = RFAPI_MONITOR_VPN(par); monitor;) {
798
    /*
799
     * If new longest match for monitor prefix is the new
800
     * route's prefix, move monitor to new route's prefix
801
     */
802
0
    if (prefix_match(new_vpn_node_p, &monitor->p)) {
803
      /* detach */
804
0
      if (mlast) {
805
0
        mlast->next = monitor->next;
806
0
      } else {
807
0
        RFAPI_MONITOR_VPN_W_ALLOC(par) = monitor->next;
808
0
      }
809
810
811
      /* attach */
812
0
      monitor->next = RFAPI_MONITOR_VPN(new_vpn_node);
813
0
      RFAPI_MONITOR_VPN_W_ALLOC(new_vpn_node) = monitor;
814
0
      monitor->node = new_vpn_node;
815
816
0
      agg_lock_node(new_vpn_node); /* incr refcount */
817
818
0
      monitor = mlast ? mlast->next : RFAPI_MONITOR_VPN(par);
819
820
0
      RFAPI_CHECK_REFCOUNT(par, SAFI_MPLS_VPN, 1);
821
      /* decr refcount after we're done with par as this might
822
       * free it */
823
0
      agg_unlock_node(par);
824
825
0
      continue;
826
0
    }
827
0
    mlast = monitor;
828
0
    monitor = monitor->next;
829
0
  }
830
831
0
  RFAPI_CHECK_REFCOUNT(new_vpn_node, SAFI_MPLS_VPN, 0);
832
0
}
833
834
835
static void rfapiBgpInfoChainFree(struct bgp_path_info *bpi)
836
0
{
837
0
  struct bgp_path_info *next;
838
839
0
  while (bpi) {
840
841
    /*
842
     * If there is a timer waiting to delete this bpi, cancel
843
     * the timer and delete immediately
844
     */
845
0
    if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)
846
0
        && bpi->extra->vnc.import.timer) {
847
0
      struct rfapi_withdraw *wcb =
848
0
        EVENT_ARG(bpi->extra->vnc.import.timer);
849
850
0
      XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
851
0
      EVENT_OFF(bpi->extra->vnc.import.timer);
852
0
    }
853
854
0
    next = bpi->next;
855
0
    bpi->next = NULL;
856
0
    rfapiBgpInfoFree(bpi);
857
0
    bpi = next;
858
0
  }
859
0
}
860
861
static void rfapiImportTableFlush(struct rfapi_import_table *it)
862
0
{
863
0
  afi_t afi;
864
865
  /*
866
   * Free ecommunity
867
   */
868
0
  ecommunity_free(&it->rt_import_list);
869
0
  it->rt_import_list = NULL;
870
871
0
  for (afi = AFI_IP; afi < AFI_MAX; ++afi) {
872
873
0
    struct agg_node *rn;
874
0
    struct agg_table *at;
875
876
0
    at = it->imported_vpn[afi];
877
0
    if (at) {
878
0
      for (rn = agg_route_top(at); rn;
879
0
           rn = agg_route_next(rn)) {
880
        /*
881
         * Each route_node has:
882
         * aggregate: points to rfapi_it_extra with
883
         *     monitor chain(s)
884
         * info: points to chain of bgp_path_info
885
         */
886
        /* free bgp_path_info and its children */
887
0
        rfapiBgpInfoChainFree(rn->info);
888
0
        rn->info = NULL;
889
890
0
        rfapiMonitorExtraFlush(SAFI_MPLS_VPN, rn);
891
0
      }
892
0
      agg_table_finish(at);
893
0
    }
894
895
0
    if (at) {
896
0
      at = it->imported_encap[afi];
897
0
      for (rn = agg_route_top(at); rn;
898
0
           rn = agg_route_next(rn)) {
899
        /* free bgp_path_info and its children */
900
0
        rfapiBgpInfoChainFree(rn->info);
901
0
        rn->info = NULL;
902
903
0
        rfapiMonitorExtraFlush(SAFI_ENCAP, rn);
904
0
      }
905
0
      agg_table_finish(at);
906
0
    }
907
0
  }
908
0
  if (it->monitor_exterior_orphans) {
909
0
    skiplist_free(it->monitor_exterior_orphans);
910
0
  }
911
0
}
912
913
void rfapiImportTableRefDelByIt(struct bgp *bgp,
914
        struct rfapi_import_table *it_target)
915
0
{
916
0
  struct rfapi *h;
917
0
  struct rfapi_import_table *it;
918
0
  struct rfapi_import_table *prev = NULL;
919
920
0
  assert(it_target);
921
922
0
  h = bgp->rfapi;
923
0
  assert(h);
924
925
0
  for (it = h->imports; it; prev = it, it = it->next) {
926
0
    if (it == it_target)
927
0
      break;
928
0
  }
929
930
0
  assert(it);
931
0
  assert(it->refcount);
932
933
0
  it->refcount -= 1;
934
935
0
  if (!it->refcount) {
936
0
    if (prev) {
937
0
      prev->next = it->next;
938
0
    } else {
939
0
      h->imports = it->next;
940
0
    }
941
0
    rfapiImportTableFlush(it);
942
0
    XFREE(MTYPE_RFAPI_IMPORTTABLE, it);
943
0
  }
944
0
}
945
946
#ifdef RFAPI_REQUIRE_ENCAP_BEEC
947
/*
948
 * Look for magic BGP Encapsulation Extended Community value
949
 * Format in RFC 5512 Sect. 4.5
950
 */
951
static int rfapiEcommunitiesMatchBeec(struct ecommunity *ecom,
952
              bgp_encap_types type)
953
{
954
  int i;
955
956
  if (!ecom)
957
    return 0;
958
959
  for (i = 0; i < (ecom->size * ECOMMUNITY_SIZE); i += ECOMMUNITY_SIZE) {
960
961
    uint8_t *ep;
962
963
    ep = ecom->val + i;
964
965
    if (ep[0] == ECOMMUNITY_ENCODE_OPAQUE
966
        && ep[1] == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP
967
        && ep[6] == ((type && 0xff00) >> 8)
968
        && ep[7] == (type & 0xff)) {
969
970
      return 1;
971
    }
972
  }
973
  return 0;
974
}
975
#endif
976
977
int rfapiEcommunitiesIntersect(struct ecommunity *e1, struct ecommunity *e2)
978
0
{
979
0
  uint32_t i, j;
980
981
0
  if (!e1 || !e2)
982
0
    return 0;
983
984
0
  {
985
0
    char *s1, *s2;
986
0
    s1 = ecommunity_ecom2str(e1, ECOMMUNITY_FORMAT_DISPLAY, 0);
987
0
    s2 = ecommunity_ecom2str(e2, ECOMMUNITY_FORMAT_DISPLAY, 0);
988
0
    vnc_zlog_debug_verbose("%s: e1[%s], e2[%s]", __func__, s1, s2);
989
0
    XFREE(MTYPE_ECOMMUNITY_STR, s1);
990
0
    XFREE(MTYPE_ECOMMUNITY_STR, s2);
991
0
  }
992
993
0
  for (i = 0; i < e1->size; ++i) {
994
0
    for (j = 0; j < e2->size; ++j) {
995
0
      if (!memcmp(e1->val + (i * ECOMMUNITY_SIZE),
996
0
            e2->val + (j * ECOMMUNITY_SIZE),
997
0
            ECOMMUNITY_SIZE)) {
998
999
0
        return 1;
1000
0
      }
1001
0
    }
1002
0
  }
1003
0
  return 0;
1004
0
}
1005
1006
int rfapiEcommunityGetLNI(struct ecommunity *ecom, uint32_t *lni)
1007
0
{
1008
0
  if (ecom) {
1009
0
    uint32_t i;
1010
1011
0
    for (i = 0; i < ecom->size; ++i) {
1012
0
      uint8_t *p = ecom->val + (i * ECOMMUNITY_SIZE);
1013
1014
0
      if ((*(p + 0) == 0x00) && (*(p + 1) == 0x02)) {
1015
1016
0
        *lni = (*(p + 5) << 16) | (*(p + 6) << 8)
1017
0
               | (*(p + 7));
1018
0
        return 0;
1019
0
      }
1020
0
    }
1021
0
  }
1022
0
  return ENOENT;
1023
0
}
1024
1025
int rfapiEcommunityGetEthernetTag(struct ecommunity *ecom, uint16_t *tag_id)
1026
0
{
1027
0
  struct bgp *bgp = bgp_get_default();
1028
0
  *tag_id = 0; /* default to untagged */
1029
0
  if (ecom) {
1030
0
    uint32_t i;
1031
1032
0
    for (i = 0; i < ecom->size; ++i) {
1033
0
      as_t as = 0;
1034
0
      int encode = 0;
1035
0
      const uint8_t *p = ecom->val + (i * ECOMMUNITY_SIZE);
1036
1037
      /* High-order octet of type. */
1038
0
      encode = *p++;
1039
1040
0
      if (*p++ == ECOMMUNITY_ROUTE_TARGET) {
1041
0
        if (encode == ECOMMUNITY_ENCODE_AS4) {
1042
0
          p = ptr_get_be32(p, &as);
1043
0
        } else if (encode == ECOMMUNITY_ENCODE_AS) {
1044
0
          as = (*p++ << 8);
1045
0
          as |= (*p++);
1046
0
          p += 2; /* skip next two, tag/vid
1047
               always in lowest bytes */
1048
0
        }
1049
0
        if (as == bgp->as) {
1050
0
          *tag_id = *p++ << 8;
1051
0
          *tag_id |= (*p++);
1052
0
          return 0;
1053
0
        }
1054
0
      }
1055
0
    }
1056
0
  }
1057
0
  return ENOENT;
1058
0
}
1059
1060
static int rfapiVpnBiNhEqualsPt(struct bgp_path_info *bpi,
1061
        struct rfapi_ip_addr *hpt)
1062
0
{
1063
0
  uint8_t family;
1064
1065
0
  if (!hpt || !bpi)
1066
0
    return 0;
1067
1068
0
  family = BGP_MP_NEXTHOP_FAMILY(bpi->attr->mp_nexthop_len);
1069
1070
0
  if (hpt->addr_family != family)
1071
0
    return 0;
1072
1073
0
  switch (family) {
1074
0
  case AF_INET:
1075
0
    if (bpi->attr->mp_nexthop_global_in.s_addr
1076
0
        != hpt->addr.v4.s_addr)
1077
0
      return 0;
1078
0
    break;
1079
1080
0
  case AF_INET6:
1081
0
    if (IPV6_ADDR_CMP(&bpi->attr->mp_nexthop_global, &hpt->addr.v6))
1082
0
      return 0;
1083
0
    break;
1084
1085
0
  default:
1086
0
    return 0;
1087
0
  }
1088
1089
0
  return 1;
1090
0
}
1091
1092
1093
/*
1094
 * Compare 2 VPN BIs. Return true if they have the same VN and UN addresses
1095
 */
1096
static int rfapiVpnBiSamePtUn(struct bgp_path_info *bpi1,
1097
            struct bgp_path_info *bpi2)
1098
0
{
1099
0
  struct prefix pfx_un1;
1100
0
  struct prefix pfx_un2;
1101
1102
0
  if (!bpi1 || !bpi2)
1103
0
    return 0;
1104
1105
  /*
1106
   * VN address comparisons
1107
   */
1108
1109
0
  if (BGP_MP_NEXTHOP_FAMILY(bpi1->attr->mp_nexthop_len)
1110
0
      != BGP_MP_NEXTHOP_FAMILY(bpi2->attr->mp_nexthop_len)) {
1111
0
    return 0;
1112
0
  }
1113
1114
0
  switch (BGP_MP_NEXTHOP_FAMILY(bpi1->attr->mp_nexthop_len)) {
1115
0
  case AF_INET:
1116
0
    if (bpi1->attr->mp_nexthop_global_in.s_addr
1117
0
        != bpi2->attr->mp_nexthop_global_in.s_addr)
1118
0
      return 0;
1119
0
    break;
1120
1121
0
  case AF_INET6:
1122
0
    if (IPV6_ADDR_CMP(&bpi1->attr->mp_nexthop_global,
1123
0
          &bpi2->attr->mp_nexthop_global))
1124
0
      return 0;
1125
0
    break;
1126
1127
0
  default:
1128
0
    return 0;
1129
0
  }
1130
1131
0
  memset(&pfx_un1, 0, sizeof(pfx_un1));
1132
0
  memset(&pfx_un2, 0, sizeof(pfx_un2));
1133
1134
  /*
1135
   * UN address comparisons
1136
   */
1137
0
  if (rfapiGetVncTunnelUnAddr(bpi1->attr, &pfx_un1)) {
1138
0
    if (bpi1->extra) {
1139
0
      pfx_un1.family = bpi1->extra->vnc.import.un_family;
1140
0
      switch (bpi1->extra->vnc.import.un_family) {
1141
0
      case AF_INET:
1142
0
        pfx_un1.u.prefix4 =
1143
0
          bpi1->extra->vnc.import.un.addr4;
1144
0
        break;
1145
0
      case AF_INET6:
1146
0
        pfx_un1.u.prefix6 =
1147
0
          bpi1->extra->vnc.import.un.addr6;
1148
0
        break;
1149
0
      default:
1150
0
        pfx_un1.family = AF_UNSPEC;
1151
0
        break;
1152
0
      }
1153
0
    }
1154
0
  }
1155
1156
0
  if (rfapiGetVncTunnelUnAddr(bpi2->attr, &pfx_un2)) {
1157
0
    if (bpi2->extra) {
1158
0
      pfx_un2.family = bpi2->extra->vnc.import.un_family;
1159
0
      switch (bpi2->extra->vnc.import.un_family) {
1160
0
      case AF_INET:
1161
0
        pfx_un2.u.prefix4 =
1162
0
          bpi2->extra->vnc.import.un.addr4;
1163
0
        break;
1164
0
      case AF_INET6:
1165
0
        pfx_un2.u.prefix6 =
1166
0
          bpi2->extra->vnc.import.un.addr6;
1167
0
        break;
1168
0
      default:
1169
0
        pfx_un2.family = AF_UNSPEC;
1170
0
        break;
1171
0
      }
1172
0
    }
1173
0
  }
1174
1175
0
  if (pfx_un1.family == AF_UNSPEC || pfx_un2.family == AF_UNSPEC)
1176
0
    return 0;
1177
1178
0
  if (pfx_un1.family != pfx_un2.family)
1179
0
    return 0;
1180
1181
0
  switch (pfx_un1.family) {
1182
0
  case AF_INET:
1183
0
    if (!IPV4_ADDR_SAME(&pfx_un1.u.prefix4, &pfx_un2.u.prefix4))
1184
0
      return 0;
1185
0
    break;
1186
0
  case AF_INET6:
1187
0
    if (!IPV6_ADDR_SAME(&pfx_un1.u.prefix6, &pfx_un2.u.prefix6))
1188
0
      return 0;
1189
0
    break;
1190
0
  }
1191
1192
1193
0
  return 1;
1194
0
}
1195
1196
uint8_t rfapiRfpCost(struct attr *attr)
1197
0
{
1198
0
  if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) {
1199
0
    if (attr->local_pref > 255) {
1200
0
      return 0;
1201
0
    }
1202
0
    return 255 - attr->local_pref;
1203
0
  }
1204
1205
0
  return 255;
1206
0
}
1207
1208
/*------------------------------------------
1209
 * rfapi_extract_l2o
1210
 *
1211
 * Find Layer 2 options in an option chain
1212
 *
1213
 * input:
1214
 *  pHop    option chain
1215
 *
1216
 * output:
1217
 *  l2o   layer 2 options extracted
1218
 *
1219
 * return value:
1220
 *  0   OK
1221
 *  1   no options found
1222
 *
1223
 --------------------------------------------*/
1224
int rfapi_extract_l2o(
1225
  struct bgp_tea_options *pHop,       /* chain of options */
1226
  struct rfapi_l2address_option *l2o) /* return extracted value */
1227
0
{
1228
0
  struct bgp_tea_options *p;
1229
1230
0
  for (p = pHop; p; p = p->next) {
1231
0
    if ((p->type == RFAPI_VN_OPTION_TYPE_L2ADDR)
1232
0
        && (p->length >= 8)) {
1233
1234
0
      char *v = p->value;
1235
1236
0
      memcpy(&l2o->macaddr, v, 6);
1237
1238
0
      l2o->label = ((v[6] << 12) & 0xff000)
1239
0
             + ((v[7] << 4) & 0xff0)
1240
0
             + ((v[8] >> 4) & 0xf);
1241
1242
0
      l2o->local_nve_id = (uint8_t)v[10];
1243
1244
0
      l2o->logical_net_id =
1245
0
        (v[11] << 16) + (v[12] << 8) + (v[13] << 0);
1246
1247
0
      return 0;
1248
0
    }
1249
0
  }
1250
0
  return 1;
1251
0
}
1252
1253
static struct rfapi_next_hop_entry *
1254
rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix,
1255
          struct bgp_path_info *bpi, /* route to encode */
1256
          uint32_t lifetime,   /* use this in nhe */
1257
          struct agg_node *rn)       /* req for L2 eth addr */
1258
0
{
1259
0
  struct rfapi_next_hop_entry *new;
1260
0
  int have_vnc_tunnel_un = 0;
1261
0
  const struct prefix *p = agg_node_get_prefix(rn);
1262
1263
#ifdef DEBUG_ENCAP_MONITOR
1264
  vnc_zlog_debug_verbose("%s: entry, bpi %p, rn %p", __func__, bpi, rn);
1265
#endif
1266
1267
0
  new = XCALLOC(MTYPE_RFAPI_NEXTHOP, sizeof(struct rfapi_next_hop_entry));
1268
1269
0
  new->prefix = *rprefix;
1270
1271
0
  if (bpi->extra
1272
0
      && decode_rd_type(bpi->extra->vnc.import.rd.val)
1273
0
           == RD_TYPE_VNC_ETH) {
1274
    /* ethernet */
1275
1276
0
    struct rfapi_vn_option *vo;
1277
1278
0
    vo = XCALLOC(MTYPE_RFAPI_VN_OPTION,
1279
0
           sizeof(struct rfapi_vn_option));
1280
1281
0
    vo->type = RFAPI_VN_OPTION_TYPE_L2ADDR;
1282
1283
0
    memcpy(&vo->v.l2addr.macaddr, &p->u.prefix_eth.octet, ETH_ALEN);
1284
    /* only low 3 bytes of this are significant */
1285
0
    (void)rfapiEcommunityGetLNI(bgp_attr_get_ecommunity(bpi->attr),
1286
0
              &vo->v.l2addr.logical_net_id);
1287
0
    (void)rfapiEcommunityGetEthernetTag(
1288
0
      bgp_attr_get_ecommunity(bpi->attr),
1289
0
      &vo->v.l2addr.tag_id);
1290
1291
    /* local_nve_id comes from lower byte of RD type */
1292
0
    vo->v.l2addr.local_nve_id = bpi->extra->vnc.import.rd.val[1];
1293
1294
    /* label comes from MP_REACH_NLRI label */
1295
0
    vo->v.l2addr.label = decode_label(&bpi->extra->label[0]);
1296
1297
0
    new->vn_options = vo;
1298
1299
    /*
1300
     * If there is an auxiliary prefix (i.e., host IP address),
1301
     * use it as the nexthop prefix instead of the query prefix
1302
     */
1303
0
    if (bpi->extra->vnc.import.aux_prefix.family) {
1304
0
      rfapiQprefix2Rprefix(&bpi->extra->vnc.import.aux_prefix,
1305
0
               &new->prefix);
1306
0
    }
1307
0
  }
1308
1309
0
  bgp_encap_types tun_type = BGP_ENCAP_TYPE_MPLS; /*Default*/
1310
0
  new->prefix.cost = rfapiRfpCost(bpi->attr);
1311
1312
0
  struct bgp_attr_encap_subtlv *pEncap;
1313
1314
0
  switch (BGP_MP_NEXTHOP_FAMILY(bpi->attr->mp_nexthop_len)) {
1315
0
  case AF_INET:
1316
0
    new->vn_address.addr_family = AF_INET;
1317
0
    new->vn_address.addr.v4 = bpi->attr->mp_nexthop_global_in;
1318
0
    break;
1319
1320
0
  case AF_INET6:
1321
0
    new->vn_address.addr_family = AF_INET6;
1322
0
    new->vn_address.addr.v6 = bpi->attr->mp_nexthop_global;
1323
0
    break;
1324
1325
0
  default:
1326
0
    zlog_warn("%s: invalid vpn nexthop length: %d", __func__,
1327
0
        bpi->attr->mp_nexthop_len);
1328
0
    rfapi_free_next_hop_list(new);
1329
0
    return NULL;
1330
0
  }
1331
1332
0
  for (pEncap = bgp_attr_get_vnc_subtlvs(bpi->attr); pEncap;
1333
0
       pEncap = pEncap->next) {
1334
0
    switch (pEncap->type) {
1335
0
    case BGP_VNC_SUBTLV_TYPE_LIFETIME:
1336
      /* use configured lifetime, not attr lifetime */
1337
0
      break;
1338
1339
0
    default:
1340
0
      zlog_warn("%s: unknown VNC option type %d", __func__,
1341
0
          pEncap->type);
1342
1343
0
      break;
1344
0
    }
1345
0
  }
1346
1347
0
  bgp_attr_extcom_tunnel_type(bpi->attr, &tun_type);
1348
0
  if (tun_type == BGP_ENCAP_TYPE_MPLS) {
1349
0
    struct prefix p;
1350
    /* MPLS carries UN address in next hop */
1351
0
    rfapiNexthop2Prefix(bpi->attr, &p);
1352
0
    if (p.family != AF_UNSPEC) {
1353
0
      rfapiQprefix2Raddr(&p, &new->un_address);
1354
0
      have_vnc_tunnel_un = 1;
1355
0
    }
1356
0
  }
1357
1358
0
  for (pEncap = bpi->attr->encap_subtlvs; pEncap; pEncap = pEncap->next) {
1359
0
    switch (pEncap->type) {
1360
0
    case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT:
1361
      /*
1362
       * Overrides ENCAP UN address, if any
1363
       */
1364
0
      switch (pEncap->length) {
1365
1366
0
      case 8:
1367
0
        new->un_address.addr_family = AF_INET;
1368
0
        memcpy(&new->un_address.addr.v4, pEncap->value,
1369
0
               4);
1370
0
        have_vnc_tunnel_un = 1;
1371
0
        break;
1372
1373
0
      case 20:
1374
0
        new->un_address.addr_family = AF_INET6;
1375
0
        memcpy(&new->un_address.addr.v6, pEncap->value,
1376
0
               16);
1377
0
        have_vnc_tunnel_un = 1;
1378
0
        break;
1379
1380
0
      default:
1381
0
        zlog_warn(
1382
0
          "%s: invalid tunnel subtlv UN addr length (%d) for bpi %p",
1383
0
          __func__, pEncap->length, bpi);
1384
0
      }
1385
0
      break;
1386
1387
0
    default:
1388
0
      zlog_warn("%s: unknown Encap Attribute option type %d",
1389
0
          __func__, pEncap->type);
1390
0
      break;
1391
0
    }
1392
0
  }
1393
1394
0
  new->un_options = rfapi_encap_tlv_to_un_option(bpi->attr);
1395
1396
#ifdef DEBUG_ENCAP_MONITOR
1397
  vnc_zlog_debug_verbose("%s: line %d: have_vnc_tunnel_un=%d", __func__,
1398
             __LINE__, have_vnc_tunnel_un);
1399
#endif
1400
1401
0
  if (!have_vnc_tunnel_un && bpi->extra) {
1402
    /*
1403
     * use cached UN address from ENCAP route
1404
     */
1405
0
    new->un_address.addr_family = bpi->extra->vnc.import.un_family;
1406
0
    switch (new->un_address.addr_family) {
1407
0
    case AF_INET:
1408
0
      new->un_address.addr.v4 =
1409
0
        bpi->extra->vnc.import.un.addr4;
1410
0
      break;
1411
0
    case AF_INET6:
1412
0
      new->un_address.addr.v6 =
1413
0
        bpi->extra->vnc.import.un.addr6;
1414
0
      break;
1415
0
    default:
1416
0
      zlog_warn("%s: invalid UN addr family (%d) for bpi %p",
1417
0
          __func__, new->un_address.addr_family, bpi);
1418
0
      rfapi_free_next_hop_list(new);
1419
0
      return NULL;
1420
0
    }
1421
0
  }
1422
1423
0
  new->lifetime = lifetime;
1424
0
  return new;
1425
0
}
1426
1427
int rfapiHasNonRemovedRoutes(struct agg_node *rn)
1428
0
{
1429
0
  struct bgp_path_info *bpi;
1430
1431
0
  for (bpi = rn->info; bpi; bpi = bpi->next) {
1432
0
    struct prefix pfx;
1433
1434
0
    if (!CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)
1435
0
        && (bpi->extra && !rfapiGetUnAddrOfVpnBi(bpi, &pfx))) {
1436
1437
0
      return 1;
1438
0
    }
1439
0
  }
1440
0
  return 0;
1441
0
}
1442
1443
#ifdef DEBUG_IT_NODES
1444
/*
1445
 * DEBUG FUNCTION
1446
 */
1447
void rfapiDumpNode(struct agg_node *rn)
1448
{
1449
  struct bgp_path_info *bpi;
1450
1451
  vnc_zlog_debug_verbose("%s: rn=%p", __func__, rn);
1452
  for (bpi = rn->info; bpi; bpi = bpi->next) {
1453
    struct prefix pfx;
1454
    int ctrc = rfapiGetUnAddrOfVpnBi(bpi, &pfx);
1455
    int nr;
1456
1457
    if (!CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)
1458
        && (bpi->extra && !ctrc)) {
1459
1460
      nr = 1;
1461
    } else {
1462
      nr = 0;
1463
    }
1464
1465
    vnc_zlog_debug_verbose(
1466
      "  bpi=%p, nr=%d, flags=0x%x, extra=%p, ctrc=%d", bpi,
1467
      nr, bpi->flags, bpi->extra, ctrc);
1468
  }
1469
}
1470
#endif
1471
1472
static int rfapiNhlAddNodeRoutes(
1473
  struct agg_node *rn,          /* in */
1474
  struct rfapi_ip_prefix *rprefix,      /* in */
1475
  uint32_t lifetime,          /* in */
1476
  int removed,            /* in */
1477
  struct rfapi_next_hop_entry **head,   /* in/out */
1478
  struct rfapi_next_hop_entry **tail,   /* in/out */
1479
  struct rfapi_ip_addr *exclude_vnaddr, /* omit routes to same NVE */
1480
  struct agg_node *rfd_rib_node,  /* preload this NVE rib node */
1481
  struct prefix *pfx_target_original)   /* query target */
1482
0
{
1483
0
  struct bgp_path_info *bpi;
1484
0
  struct rfapi_next_hop_entry *new;
1485
0
  struct prefix pfx_un;
1486
0
  struct skiplist *seen_nexthops;
1487
0
  int count = 0;
1488
0
  const struct prefix *p = agg_node_get_prefix(rn);
1489
0
  int is_l2 = (p->family == AF_ETHERNET);
1490
1491
0
  if (rfd_rib_node) {
1492
0
    struct agg_table *atable = agg_get_table(rfd_rib_node);
1493
0
    struct rfapi_descriptor *rfd;
1494
1495
0
    if (atable) {
1496
0
      rfd = agg_get_table_info(atable);
1497
1498
0
      if (rfapiRibFTDFilterRecentPrefix(rfd, rn,
1499
0
                pfx_target_original))
1500
0
        return 0;
1501
0
    }
1502
0
  }
1503
1504
0
  seen_nexthops =
1505
0
    skiplist_new(0, vnc_prefix_cmp, prefix_free_lists);
1506
1507
0
  for (bpi = rn->info; bpi; bpi = bpi->next) {
1508
1509
0
    struct prefix pfx_vn;
1510
0
    struct prefix *newpfx;
1511
1512
0
    if (removed && !CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) {
1513
#ifdef DEBUG_RETURNED_NHL
1514
      vnc_zlog_debug_verbose(
1515
        "%s: want holddown, this route not holddown, skip",
1516
        __func__);
1517
#endif
1518
0
      continue;
1519
0
    }
1520
0
    if (!removed && CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) {
1521
0
      continue;
1522
0
    }
1523
1524
0
    if (!bpi->extra) {
1525
0
      continue;
1526
0
    }
1527
1528
    /*
1529
     * Check for excluded VN address
1530
     */
1531
0
    if (rfapiVpnBiNhEqualsPt(bpi, exclude_vnaddr))
1532
0
      continue;
1533
1534
    /*
1535
     * Check for VN address (nexthop) copied already
1536
     */
1537
0
    if (is_l2) {
1538
      /* L2 routes: semantic nexthop in aux_prefix; VN addr
1539
       * ain't it */
1540
0
      pfx_vn = bpi->extra->vnc.import.aux_prefix;
1541
0
    } else {
1542
0
      rfapiNexthop2Prefix(bpi->attr, &pfx_vn);
1543
0
    }
1544
0
    if (!skiplist_search(seen_nexthops, &pfx_vn, NULL)) {
1545
#ifdef DEBUG_RETURNED_NHL
1546
      vnc_zlog_debug_verbose(
1547
        "%s: already put VN/nexthop %pFX, skip",
1548
        __func__, &pfx_vn);
1549
#endif
1550
0
      continue;
1551
0
    }
1552
1553
0
    if (rfapiGetUnAddrOfVpnBi(bpi, &pfx_un)) {
1554
#ifdef DEBUG_ENCAP_MONITOR
1555
      vnc_zlog_debug_verbose(
1556
        "%s: failed to get UN address of this VPN bpi",
1557
        __func__);
1558
#endif
1559
0
      continue;
1560
0
    }
1561
1562
0
    newpfx = prefix_new();
1563
0
    *newpfx = pfx_vn;
1564
0
    skiplist_insert(seen_nexthops, newpfx, newpfx);
1565
1566
0
    new = rfapiRouteInfo2NextHopEntry(rprefix, bpi, lifetime, rn);
1567
0
    if (new) {
1568
0
      if (rfapiRibPreloadBi(rfd_rib_node, &pfx_vn, &pfx_un,
1569
0
                lifetime, bpi)) {
1570
        /* duplicate filtered by RIB */
1571
0
        rfapi_free_next_hop_list(new);
1572
0
        new = NULL;
1573
0
      }
1574
0
    }
1575
1576
0
    if (new) {
1577
0
      if (*tail) {
1578
0
        (*tail)->next = new;
1579
0
      } else {
1580
0
        *head = new;
1581
0
      }
1582
0
      *tail = new;
1583
0
      ++count;
1584
0
    }
1585
0
  }
1586
1587
0
  skiplist_free(seen_nexthops);
1588
1589
0
  return count;
1590
0
}
1591
1592
1593
/*
1594
 * Breadth-first
1595
 *
1596
 * omit_node is meant for the situation where we are adding a subtree
1597
 * of a parent of some original requested node. The response already
1598
 * contains the original requested node, and we don't want to duplicate
1599
 * its routes in the list, so we skip it if the right or left node
1600
 * matches (of course, we still travel down its child subtrees).
1601
 */
1602
static int rfapiNhlAddSubtree(
1603
  struct agg_node *rn,          /* in */
1604
  uint32_t lifetime,          /* in */
1605
  struct rfapi_next_hop_entry **head,   /* in/out */
1606
  struct rfapi_next_hop_entry **tail,   /* in/out */
1607
  struct agg_node *omit_node,    /* in */
1608
  struct rfapi_ip_addr *exclude_vnaddr, /* omit routes to same NVE */
1609
  struct agg_table *rfd_rib_table,      /* preload here */
1610
  struct prefix *pfx_target_original)   /* query target */
1611
0
{
1612
0
  struct rfapi_ip_prefix rprefix;
1613
0
  int rcount = 0;
1614
1615
  /* FIXME: need to find a better way here to work without sticking our
1616
   * hands in node->link */
1617
0
  if (agg_node_left(rn) && agg_node_left(rn) != omit_node) {
1618
0
    if (agg_node_left(rn)->info) {
1619
0
      const struct prefix *p =
1620
0
        agg_node_get_prefix(agg_node_left(rn));
1621
0
      int count = 0;
1622
0
      struct agg_node *rib_rn = NULL;
1623
1624
0
      rfapiQprefix2Rprefix(p, &rprefix);
1625
0
      if (rfd_rib_table)
1626
0
        rib_rn = agg_node_get(rfd_rib_table, p);
1627
1628
0
      count = rfapiNhlAddNodeRoutes(
1629
0
        agg_node_left(rn), &rprefix, lifetime, 0, head,
1630
0
        tail, exclude_vnaddr, rib_rn,
1631
0
        pfx_target_original);
1632
0
      if (!count) {
1633
0
        count = rfapiNhlAddNodeRoutes(
1634
0
          agg_node_left(rn), &rprefix, lifetime,
1635
0
          1, head, tail, exclude_vnaddr, rib_rn,
1636
0
          pfx_target_original);
1637
0
      }
1638
0
      rcount += count;
1639
0
      if (rib_rn)
1640
0
        agg_unlock_node(rib_rn);
1641
0
    }
1642
0
  }
1643
1644
0
  if (agg_node_right(rn) && agg_node_right(rn) != omit_node) {
1645
0
    if (agg_node_right(rn)->info) {
1646
0
      const struct prefix *p =
1647
0
        agg_node_get_prefix(agg_node_right(rn));
1648
0
      int count = 0;
1649
0
      struct agg_node *rib_rn = NULL;
1650
1651
0
      rfapiQprefix2Rprefix(p, &rprefix);
1652
0
      if (rfd_rib_table)
1653
0
        rib_rn = agg_node_get(rfd_rib_table, p);
1654
1655
0
      count = rfapiNhlAddNodeRoutes(
1656
0
        agg_node_right(rn), &rprefix, lifetime, 0, head,
1657
0
        tail, exclude_vnaddr, rib_rn,
1658
0
        pfx_target_original);
1659
0
      if (!count) {
1660
0
        count = rfapiNhlAddNodeRoutes(
1661
0
          agg_node_right(rn), &rprefix, lifetime,
1662
0
          1, head, tail, exclude_vnaddr, rib_rn,
1663
0
          pfx_target_original);
1664
0
      }
1665
0
      rcount += count;
1666
0
      if (rib_rn)
1667
0
        agg_unlock_node(rib_rn);
1668
0
    }
1669
0
  }
1670
1671
0
  if (agg_node_left(rn)) {
1672
0
    rcount += rfapiNhlAddSubtree(
1673
0
      agg_node_left(rn), lifetime, head, tail, omit_node,
1674
0
      exclude_vnaddr, rfd_rib_table, pfx_target_original);
1675
0
  }
1676
0
  if (agg_node_right(rn)) {
1677
0
    rcount += rfapiNhlAddSubtree(
1678
0
      agg_node_right(rn), lifetime, head, tail, omit_node,
1679
0
      exclude_vnaddr, rfd_rib_table, pfx_target_original);
1680
0
  }
1681
1682
0
  return rcount;
1683
0
}
1684
1685
/*
1686
 * Implementation of ROUTE_LIST(node) from RFAPI-Import-Event-Handling.txt
1687
 *
1688
 * Construct an rfapi nexthop list based on the routes attached to
1689
 * the specified node.
1690
 *
1691
 * If there are any routes that do NOT have BGP_PATH_REMOVED set,
1692
 * return those only. If there are ONLY routes with BGP_PATH_REMOVED,
1693
 * then return those, and also include all the non-removed routes from the
1694
 * next less-specific node (i.e., this node's parent) at the end.
1695
 */
1696
struct rfapi_next_hop_entry *rfapiRouteNode2NextHopList(
1697
  struct agg_node *rn, uint32_t lifetime, /* put into nexthop entries */
1698
  struct rfapi_ip_addr *exclude_vnaddr,   /* omit routes to same NVE */
1699
  struct agg_table *rfd_rib_table,  /* preload here */
1700
  struct prefix *pfx_target_original)     /* query target */
1701
0
{
1702
0
  struct rfapi_ip_prefix rprefix;
1703
0
  struct rfapi_next_hop_entry *answer = NULL;
1704
0
  struct rfapi_next_hop_entry *last = NULL;
1705
0
  struct agg_node *parent;
1706
0
  const struct prefix *p = agg_node_get_prefix(rn);
1707
0
  int count = 0;
1708
0
  struct agg_node *rib_rn;
1709
1710
#ifdef DEBUG_RETURNED_NHL
1711
  vnc_zlog_debug_verbose("%s: called with node pfx=%rRN", __func__, rn);
1712
  rfapiDebugBacktrace();
1713
#endif
1714
1715
0
  rfapiQprefix2Rprefix(p, &rprefix);
1716
1717
0
  rib_rn = rfd_rib_table ? agg_node_get(rfd_rib_table, p) : NULL;
1718
1719
  /*
1720
   * Add non-withdrawn routes at this node
1721
   */
1722
0
  count = rfapiNhlAddNodeRoutes(rn, &rprefix, lifetime, 0, &answer, &last,
1723
0
              exclude_vnaddr, rib_rn,
1724
0
              pfx_target_original);
1725
1726
  /*
1727
   * If the list has at least one entry, it's finished
1728
   */
1729
0
  if (count) {
1730
0
    count += rfapiNhlAddSubtree(rn, lifetime, &answer, &last, NULL,
1731
0
              exclude_vnaddr, rfd_rib_table,
1732
0
              pfx_target_original);
1733
0
    vnc_zlog_debug_verbose("%s: %d nexthops, answer=%p", __func__,
1734
0
               count, answer);
1735
#ifdef DEBUG_RETURNED_NHL
1736
    rfapiPrintNhl(NULL, answer);
1737
#endif
1738
0
    if (rib_rn)
1739
0
      agg_unlock_node(rib_rn);
1740
0
    return answer;
1741
0
  }
1742
1743
  /*
1744
   * Add withdrawn routes at this node
1745
   */
1746
0
  count = rfapiNhlAddNodeRoutes(rn, &rprefix, lifetime, 1, &answer, &last,
1747
0
              exclude_vnaddr, rib_rn,
1748
0
              pfx_target_original);
1749
0
  if (rib_rn)
1750
0
    agg_unlock_node(rib_rn);
1751
1752
  // rfapiPrintNhl(NULL, answer);
1753
1754
  /*
1755
   * walk up the tree until we find a node with non-deleted
1756
   * routes, then add them
1757
   */
1758
0
  for (parent = agg_node_parent(rn); parent;
1759
0
       parent = agg_node_parent(parent)) {
1760
0
    if (rfapiHasNonRemovedRoutes(parent)) {
1761
0
      break;
1762
0
    }
1763
0
  }
1764
1765
  /*
1766
   * Add non-withdrawn routes from less-specific prefix
1767
   */
1768
0
  if (parent) {
1769
0
    const struct prefix *p = agg_node_get_prefix(parent);
1770
1771
0
    rib_rn = rfd_rib_table ? agg_node_get(rfd_rib_table, p) : NULL;
1772
0
    rfapiQprefix2Rprefix(p, &rprefix);
1773
0
    count += rfapiNhlAddNodeRoutes(parent, &rprefix, lifetime, 0,
1774
0
                 &answer, &last, exclude_vnaddr,
1775
0
                 rib_rn, pfx_target_original);
1776
0
    count += rfapiNhlAddSubtree(parent, lifetime, &answer, &last,
1777
0
              rn, exclude_vnaddr, rfd_rib_table,
1778
0
              pfx_target_original);
1779
0
    if (rib_rn)
1780
0
      agg_unlock_node(rib_rn);
1781
0
  } else {
1782
    /*
1783
     * There is no parent with non-removed routes. Still need to
1784
     * add subtree of original node if it contributed routes to the
1785
     * answer.
1786
     */
1787
0
    if (count)
1788
0
      count += rfapiNhlAddSubtree(rn, lifetime, &answer,
1789
0
                &last, rn, exclude_vnaddr,
1790
0
                rfd_rib_table,
1791
0
                pfx_target_original);
1792
0
  }
1793
1794
0
  vnc_zlog_debug_verbose("%s: %d nexthops, answer=%p", __func__, count,
1795
0
             answer);
1796
#ifdef DEBUG_RETURNED_NHL
1797
  rfapiPrintNhl(NULL, answer);
1798
#endif
1799
0
  return answer;
1800
0
}
1801
1802
/*
1803
 * Construct nexthop list of all routes in table
1804
 */
1805
struct rfapi_next_hop_entry *rfapiRouteTable2NextHopList(
1806
  struct agg_table *rt, uint32_t lifetime, /* put into nexthop entries */
1807
  struct rfapi_ip_addr *exclude_vnaddr,    /* omit routes to same NVE */
1808
  struct agg_table *rfd_rib_table,    /* preload this NVE rib table */
1809
  struct prefix *pfx_target_original) /* query target */
1810
0
{
1811
0
  struct agg_node *rn;
1812
0
  struct rfapi_next_hop_entry *biglist = NULL;
1813
0
  struct rfapi_next_hop_entry *nhl;
1814
0
  struct rfapi_next_hop_entry *tail = NULL;
1815
0
  int count = 0;
1816
1817
0
  for (rn = agg_route_top(rt); rn; rn = agg_route_next(rn)) {
1818
1819
0
    nhl = rfapiRouteNode2NextHopList(rn, lifetime, exclude_vnaddr,
1820
0
             rfd_rib_table,
1821
0
             pfx_target_original);
1822
0
    if (!tail) {
1823
0
      tail = biglist = nhl;
1824
0
      if (tail)
1825
0
        count = 1;
1826
0
    } else {
1827
0
      tail->next = nhl;
1828
0
    }
1829
0
    if (tail) {
1830
0
      while (tail->next) {
1831
0
        ++count;
1832
0
        tail = tail->next;
1833
0
      }
1834
0
    }
1835
0
  }
1836
1837
0
  vnc_zlog_debug_verbose("%s: returning %d routes", __func__, count);
1838
0
  return biglist;
1839
0
}
1840
1841
struct rfapi_next_hop_entry *rfapiEthRouteNode2NextHopList(
1842
  struct agg_node *rn, struct rfapi_ip_prefix *rprefix,
1843
  uint32_t lifetime,          /* put into nexthop entries */
1844
  struct rfapi_ip_addr *exclude_vnaddr, /* omit routes to same NVE */
1845
  struct agg_table *rfd_rib_table,      /* preload NVE rib table */
1846
  struct prefix *pfx_target_original)   /* query target */
1847
0
{
1848
0
  int count = 0;
1849
0
  struct rfapi_next_hop_entry *answer = NULL;
1850
0
  struct rfapi_next_hop_entry *last = NULL;
1851
0
  struct agg_node *rib_rn;
1852
1853
0
  rib_rn = rfd_rib_table
1854
0
       ? agg_node_get(rfd_rib_table, agg_node_get_prefix(rn))
1855
0
       : NULL;
1856
1857
0
  count = rfapiNhlAddNodeRoutes(rn, rprefix, lifetime, 0, &answer, &last,
1858
0
              NULL, rib_rn, pfx_target_original);
1859
1860
#ifdef DEBUG_ENCAP_MONITOR
1861
  vnc_zlog_debug_verbose("%s: node %p: %d non-holddown routes", __func__,
1862
             rn, count);
1863
#endif
1864
1865
0
  if (!count) {
1866
0
    count = rfapiNhlAddNodeRoutes(rn, rprefix, lifetime, 1, &answer,
1867
0
                &last, exclude_vnaddr, rib_rn,
1868
0
                pfx_target_original);
1869
0
    vnc_zlog_debug_verbose("%s: node %p: %d holddown routes",
1870
0
               __func__, rn, count);
1871
0
  }
1872
1873
0
  if (rib_rn)
1874
0
    agg_unlock_node(rib_rn);
1875
1876
#ifdef DEBUG_RETURNED_NHL
1877
  rfapiPrintNhl(NULL, answer);
1878
#endif
1879
1880
0
  return answer;
1881
0
}
1882
1883
1884
/*
1885
 * Construct nexthop list of all routes in table
1886
 */
1887
struct rfapi_next_hop_entry *rfapiEthRouteTable2NextHopList(
1888
  uint32_t logical_net_id, struct rfapi_ip_prefix *rprefix,
1889
  uint32_t lifetime,          /* put into nexthop entries */
1890
  struct rfapi_ip_addr *exclude_vnaddr, /* omit routes to same NVE */
1891
  struct agg_table *rfd_rib_table,      /* preload NVE rib node */
1892
  struct prefix *pfx_target_original)   /* query target */
1893
0
{
1894
0
  struct rfapi_import_table *it;
1895
0
  struct bgp *bgp = bgp_get_default();
1896
0
  struct agg_table *rt;
1897
0
  struct agg_node *rn;
1898
0
  struct rfapi_next_hop_entry *biglist = NULL;
1899
0
  struct rfapi_next_hop_entry *nhl;
1900
0
  struct rfapi_next_hop_entry *tail = NULL;
1901
0
  int count = 0;
1902
1903
1904
0
  it = rfapiMacImportTableGet(bgp, logical_net_id);
1905
0
  rt = it->imported_vpn[AFI_L2VPN];
1906
1907
0
  for (rn = agg_route_top(rt); rn; rn = agg_route_next(rn)) {
1908
1909
0
    nhl = rfapiEthRouteNode2NextHopList(
1910
0
      rn, rprefix, lifetime, exclude_vnaddr, rfd_rib_table,
1911
0
      pfx_target_original);
1912
0
    if (!tail) {
1913
0
      tail = biglist = nhl;
1914
0
      if (tail)
1915
0
        count = 1;
1916
0
    } else {
1917
0
      tail->next = nhl;
1918
0
    }
1919
0
    if (tail) {
1920
0
      while (tail->next) {
1921
0
        ++count;
1922
0
        tail = tail->next;
1923
0
      }
1924
0
    }
1925
0
  }
1926
1927
0
  vnc_zlog_debug_verbose("%s: returning %d routes", __func__, count);
1928
0
  return biglist;
1929
0
}
1930
1931
/*
1932
 * Insert a new bpi to the imported route table node,
1933
 * keeping the list of BPIs sorted best route first
1934
 */
1935
static void rfapiBgpInfoAttachSorted(struct agg_node *rn,
1936
             struct bgp_path_info *info_new, afi_t afi,
1937
             safi_t safi)
1938
0
{
1939
0
  struct bgp *bgp;
1940
0
  struct bgp_path_info *prev;
1941
0
  struct bgp_path_info *next;
1942
0
  char pfx_buf[PREFIX2STR_BUFFER] = {};
1943
1944
1945
0
  bgp = bgp_get_default(); /* assume 1 instance for now */
1946
1947
0
  if (VNC_DEBUG(IMPORT_BI_ATTACH)) {
1948
0
    vnc_zlog_debug_verbose("%s: info_new->peer=%p", __func__,
1949
0
               info_new->peer);
1950
0
    vnc_zlog_debug_verbose("%s: info_new->peer->su_remote=%p",
1951
0
               __func__, info_new->peer->su_remote);
1952
0
  }
1953
1954
0
  for (prev = NULL, next = rn->info; next;
1955
0
       prev = next, next = next->next) {
1956
0
    enum bgp_path_selection_reason reason;
1957
1958
0
    if (!bgp
1959
0
        || (!CHECK_FLAG(info_new->flags, BGP_PATH_REMOVED)
1960
0
      && CHECK_FLAG(next->flags, BGP_PATH_REMOVED))
1961
0
        || bgp_path_info_cmp_compatible(bgp, info_new, next,
1962
0
                pfx_buf, afi, safi,
1963
0
                &reason)
1964
0
             == -1) { /* -1 if 1st is better */
1965
0
      break;
1966
0
    }
1967
0
  }
1968
0
  vnc_zlog_debug_verbose("%s: prev=%p, next=%p", __func__, prev, next);
1969
0
  if (prev) {
1970
0
    prev->next = info_new;
1971
0
  } else {
1972
0
    rn->info = info_new;
1973
0
  }
1974
0
  info_new->prev = prev;
1975
0
  info_new->next = next;
1976
0
  if (next)
1977
0
    next->prev = info_new;
1978
0
  bgp_attr_intern(info_new->attr);
1979
0
}
1980
1981
static void rfapiBgpInfoDetach(struct agg_node *rn, struct bgp_path_info *bpi)
1982
0
{
1983
  /*
1984
   * Remove the route (doubly-linked)
1985
   */
1986
  //  bgp_attr_unintern (&bpi->attr);
1987
0
  if (bpi->next)
1988
0
    bpi->next->prev = bpi->prev;
1989
0
  if (bpi->prev)
1990
0
    bpi->prev->next = bpi->next;
1991
0
  else
1992
0
    rn->info = bpi->next;
1993
0
}
1994
1995
/*
1996
 * For L3-indexed import tables
1997
 */
1998
static int rfapi_bi_peer_rd_cmp(const void *b1, const void *b2)
1999
0
{
2000
0
  const struct bgp_path_info *bpi1 = b1;
2001
0
  const struct bgp_path_info *bpi2 = b2;
2002
2003
  /*
2004
   * Compare peers
2005
   */
2006
0
  if (bpi1->peer < bpi2->peer)
2007
0
    return -1;
2008
0
  if (bpi1->peer > bpi2->peer)
2009
0
    return 1;
2010
2011
  /*
2012
   * compare RDs
2013
   */
2014
0
  return vnc_prefix_cmp(
2015
0
    (const struct prefix *)&bpi1->extra->vnc.import.rd,
2016
0
    (const struct prefix *)&bpi2->extra->vnc.import.rd);
2017
0
}
2018
2019
/*
2020
 * For L2-indexed import tables
2021
 * The BPIs in these tables should ALWAYS have an aux_prefix set because
2022
 * they arrive via IPv4 or IPv6 advertisements.
2023
 */
2024
static int rfapi_bi_peer_rd_aux_cmp(const void *b1, const void *b2)
2025
0
{
2026
0
  const struct bgp_path_info *bpi1 = b1;
2027
0
  const struct bgp_path_info *bpi2 = b2;
2028
0
  int rc;
2029
2030
  /*
2031
   * Compare peers
2032
   */
2033
0
  if (bpi1->peer < bpi2->peer)
2034
0
    return -1;
2035
0
  if (bpi1->peer > bpi2->peer)
2036
0
    return 1;
2037
2038
  /*
2039
   * compare RDs
2040
   */
2041
0
  rc = vnc_prefix_cmp((struct prefix *)&bpi1->extra->vnc.import.rd,
2042
0
          (struct prefix *)&bpi2->extra->vnc.import.rd);
2043
0
  if (rc) {
2044
0
    return rc;
2045
0
  }
2046
2047
  /*
2048
   * L2 import tables can have multiple entries with the
2049
   * same MAC address, same RD, but different L3 addresses.
2050
   *
2051
   * Use presence of aux_prefix with AF=ethernet and prefixlen=1
2052
   * as magic value to signify explicit wildcarding of the aux_prefix.
2053
   * This magic value will not appear in bona fide bpi entries in
2054
   * the import table, but is allowed in the "fake" bpi used to
2055
   * probe the table when searching. (We have to test both b1 and b2
2056
   * because there is no guarantee of the order the test key and
2057
   * the real key will be passed)
2058
   */
2059
0
  if ((bpi1->extra->vnc.import.aux_prefix.family == AF_ETHERNET
2060
0
       && (bpi1->extra->vnc.import.aux_prefix.prefixlen == 1))
2061
0
      || (bpi2->extra->vnc.import.aux_prefix.family == AF_ETHERNET
2062
0
    && (bpi2->extra->vnc.import.aux_prefix.prefixlen == 1))) {
2063
2064
    /*
2065
     * wildcard aux address specified
2066
     */
2067
0
    return 0;
2068
0
  }
2069
2070
0
  return vnc_prefix_cmp(&bpi1->extra->vnc.import.aux_prefix,
2071
0
            &bpi2->extra->vnc.import.aux_prefix);
2072
0
}
2073
2074
2075
/*
2076
 * Index on RD and Peer
2077
 */
2078
static void rfapiItBiIndexAdd(struct agg_node *rn, /* Import table VPN node */
2079
            struct bgp_path_info *bpi) /* new BPI */
2080
0
{
2081
0
  struct skiplist *sl;
2082
0
  const struct prefix *p;
2083
2084
0
  assert(rn);
2085
0
  assert(bpi);
2086
0
  assert(bpi->extra);
2087
2088
0
  vnc_zlog_debug_verbose("%s: bpi %p, peer %p, rd %pRDP", __func__, bpi,
2089
0
             bpi->peer, &bpi->extra->vnc.import.rd);
2090
2091
0
  sl = RFAPI_RDINDEX_W_ALLOC(rn);
2092
0
  if (!sl) {
2093
0
    p = agg_node_get_prefix(rn);
2094
0
    if (AF_ETHERNET == p->family) {
2095
0
      sl = skiplist_new(0, rfapi_bi_peer_rd_aux_cmp, NULL);
2096
0
    } else {
2097
0
      sl = skiplist_new(0, rfapi_bi_peer_rd_cmp, NULL);
2098
0
    }
2099
0
    RFAPI_IT_EXTRA_GET(rn)->u.vpn.idx_rd = sl;
2100
0
    agg_lock_node(rn); /* for skiplist */
2101
0
  }
2102
0
  assert(!skiplist_insert(sl, (void *)bpi, (void *)bpi));
2103
0
  agg_lock_node(rn); /* for skiplist entry */
2104
2105
  /* NB: BPIs in import tables are not refcounted */
2106
0
}
2107
2108
static void rfapiItBiIndexDump(struct agg_node *rn)
2109
0
{
2110
0
  struct skiplist *sl;
2111
0
  void *cursor = NULL;
2112
0
  struct bgp_path_info *k;
2113
0
  struct bgp_path_info *v;
2114
0
  int rc;
2115
2116
0
  sl = RFAPI_RDINDEX(rn);
2117
0
  if (!sl)
2118
0
    return;
2119
2120
0
  for (rc = skiplist_next(sl, (void **)&k, (void **)&v, &cursor); !rc;
2121
0
       rc = skiplist_next(sl, (void **)&k, (void **)&v, &cursor)) {
2122
2123
0
    char buf[RD_ADDRSTRLEN];
2124
0
    char buf_aux_pfx[PREFIX_STRLEN];
2125
2126
0
    prefix_rd2str(
2127
0
      &k->extra->vnc.import.rd, buf, sizeof(buf),
2128
0
      bgp_get_asnotation(k->peer ? k->peer->bgp : NULL));
2129
0
    if (k->extra->vnc.import.aux_prefix.family) {
2130
0
      prefix2str(&k->extra->vnc.import.aux_prefix,
2131
0
           buf_aux_pfx, sizeof(buf_aux_pfx));
2132
0
    } else
2133
0
      strlcpy(buf_aux_pfx, "(none)", sizeof(buf_aux_pfx));
2134
2135
0
    vnc_zlog_debug_verbose("bpi %p, peer %p, rd %s, aux_prefix %s",
2136
0
               k, k->peer, buf, buf_aux_pfx);
2137
0
  }
2138
0
}
2139
2140
static struct bgp_path_info *rfapiItBiIndexSearch(
2141
  struct agg_node *rn, /* Import table VPN node */
2142
  struct prefix_rd *prd, struct peer *peer,
2143
  const struct prefix *aux_prefix) /* optional L3 addr for L2 ITs */
2144
0
{
2145
0
  struct skiplist *sl;
2146
0
  int rc;
2147
0
  struct bgp_path_info bpi_fake = {0};
2148
0
  struct bgp_path_info_extra bpi_extra = {0};
2149
0
  struct bgp_path_info *bpi_result;
2150
2151
0
  sl = RFAPI_RDINDEX(rn);
2152
0
  if (!sl)
2153
0
    return NULL;
2154
2155
#ifdef DEBUG_BI_SEARCH
2156
  {
2157
    char buf_aux_pfx[PREFIX_STRLEN];
2158
2159
    if (aux_prefix) {
2160
      prefix2str(aux_prefix, buf_aux_pfx,
2161
           sizeof(buf_aux_pfx));
2162
    } else
2163
      strlcpy(buf_aux_pfx, "(nil)", sizeof(buf_aux_pfx));
2164
2165
    vnc_zlog_debug_verbose(
2166
      "%s want prd=%pRDP, peer=%p, aux_prefix=%s", __func__,
2167
      prd, peer, buf_aux_pfx);
2168
    rfapiItBiIndexDump(rn);
2169
  }
2170
#endif
2171
2172
  /* threshold is a WAG */
2173
0
  if (sl->count < 3) {
2174
#ifdef DEBUG_BI_SEARCH
2175
    vnc_zlog_debug_verbose("%s: short list algorithm", __func__);
2176
#endif
2177
    /* if short list, linear search might be faster */
2178
0
    for (bpi_result = rn->info; bpi_result;
2179
0
         bpi_result = bpi_result->next) {
2180
#ifdef DEBUG_BI_SEARCH
2181
      vnc_zlog_debug_verbose(
2182
        "%s: bpi has prd=%pRDP, peer=%p", __func__,
2183
        &bpi_result->extra->vnc.import.rd,
2184
        bpi_result->peer);
2185
#endif
2186
0
      if (peer == bpi_result->peer
2187
0
          && !prefix_cmp((struct prefix *)&bpi_result->extra
2188
0
               ->vnc.import.rd,
2189
0
             (struct prefix *)prd)) {
2190
2191
#ifdef DEBUG_BI_SEARCH
2192
        vnc_zlog_debug_verbose(
2193
          "%s: peer and RD same, doing aux_prefix check",
2194
          __func__);
2195
#endif
2196
0
        if (!aux_prefix
2197
0
            || !prefix_cmp(
2198
0
                 aux_prefix,
2199
0
                 &bpi_result->extra->vnc.import
2200
0
              .aux_prefix)) {
2201
2202
#ifdef DEBUG_BI_SEARCH
2203
          vnc_zlog_debug_verbose("%s: match",
2204
                     __func__);
2205
#endif
2206
0
          break;
2207
0
        }
2208
0
      }
2209
0
    }
2210
0
    return bpi_result;
2211
0
  }
2212
2213
0
  bpi_fake.peer = peer;
2214
0
  bpi_fake.extra = &bpi_extra;
2215
0
  bpi_fake.extra->vnc.import.rd = *prd;
2216
0
  if (aux_prefix) {
2217
0
    bpi_fake.extra->vnc.import.aux_prefix = *aux_prefix;
2218
0
  } else {
2219
    /* wildcard */
2220
0
    bpi_fake.extra->vnc.import.aux_prefix.family = AF_ETHERNET;
2221
0
    bpi_fake.extra->vnc.import.aux_prefix.prefixlen = 1;
2222
0
  }
2223
2224
0
  rc = skiplist_search(sl, (void *)&bpi_fake, (void *)&bpi_result);
2225
2226
0
  if (rc) {
2227
#ifdef DEBUG_BI_SEARCH
2228
    vnc_zlog_debug_verbose("%s: no match", __func__);
2229
#endif
2230
0
    return NULL;
2231
0
  }
2232
2233
#ifdef DEBUG_BI_SEARCH
2234
  vnc_zlog_debug_verbose("%s: matched bpi=%p", __func__, bpi_result);
2235
#endif
2236
2237
0
  return bpi_result;
2238
0
}
2239
2240
static void rfapiItBiIndexDel(struct agg_node *rn, /* Import table VPN node */
2241
            struct bgp_path_info *bpi) /* old BPI */
2242
0
{
2243
0
  struct skiplist *sl;
2244
0
  int rc;
2245
2246
0
  vnc_zlog_debug_verbose("%s: bpi %p, peer %p, rd %pRDP", __func__, bpi,
2247
0
             bpi->peer, &bpi->extra->vnc.import.rd);
2248
2249
0
  sl = RFAPI_RDINDEX(rn);
2250
0
  assert(sl);
2251
2252
0
  rc = skiplist_delete(sl, (void *)(bpi), (void *)bpi);
2253
0
  if (rc) {
2254
0
    rfapiItBiIndexDump(rn);
2255
0
  }
2256
0
  assert(!rc);
2257
2258
0
  agg_unlock_node(rn); /* for skiplist entry */
2259
2260
  /* NB: BPIs in import tables are not refcounted */
2261
0
}
2262
2263
/*
2264
 * Add a backreference at the ENCAP node to the VPN route that
2265
 * refers to it
2266
 */
2267
static void
2268
rfapiMonitorEncapAdd(struct rfapi_import_table *import_table,
2269
         struct prefix *p,        /* VN address */
2270
         struct agg_node *vpn_rn,       /* VPN node */
2271
         struct bgp_path_info *vpn_bpi) /* VPN bpi/route */
2272
0
{
2273
0
  afi_t afi = family2afi(p->family);
2274
0
  struct agg_node *rn;
2275
0
  struct rfapi_monitor_encap *m;
2276
2277
0
  assert(afi);
2278
0
  rn = agg_node_get(import_table->imported_encap[afi], p); /* locks rn */
2279
0
  assert(rn);
2280
2281
0
  m = XCALLOC(MTYPE_RFAPI_MONITOR_ENCAP,
2282
0
        sizeof(struct rfapi_monitor_encap));
2283
2284
0
  m->node = vpn_rn;
2285
0
  m->bpi = vpn_bpi;
2286
0
  m->rn = rn;
2287
2288
  /* insert to encap node's list */
2289
0
  m->next = RFAPI_MONITOR_ENCAP(rn);
2290
0
  if (m->next)
2291
0
    m->next->prev = m;
2292
0
  RFAPI_MONITOR_ENCAP_W_ALLOC(rn) = m;
2293
2294
  /* for easy lookup when deleting vpn route */
2295
0
  vpn_bpi->extra->vnc.import.hme = m;
2296
2297
0
  vnc_zlog_debug_verbose(
2298
0
    "%s: it=%p, vpn_bpi=%p, afi=%d, encap rn=%p, setting vpn_bpi->extra->vnc.import.hme=%p",
2299
0
    __func__, import_table, vpn_bpi, afi, rn, m);
2300
2301
0
  RFAPI_CHECK_REFCOUNT(rn, SAFI_ENCAP, 0);
2302
0
  bgp_attr_intern(vpn_bpi->attr);
2303
0
}
2304
2305
static void rfapiMonitorEncapDelete(struct bgp_path_info *vpn_bpi)
2306
0
{
2307
  /*
2308
   * Remove encap monitor
2309
   */
2310
0
  vnc_zlog_debug_verbose("%s: vpn_bpi=%p", __func__, vpn_bpi);
2311
0
  if (vpn_bpi->extra) {
2312
0
    struct rfapi_monitor_encap *hme =
2313
0
      vpn_bpi->extra->vnc.import.hme;
2314
2315
0
    if (hme) {
2316
2317
0
      vnc_zlog_debug_verbose("%s: hme=%p", __func__, hme);
2318
2319
      /* Refcount checking takes too long here */
2320
      // RFAPI_CHECK_REFCOUNT(hme->rn, SAFI_ENCAP, 0);
2321
0
      if (hme->next)
2322
0
        hme->next->prev = hme->prev;
2323
0
      if (hme->prev)
2324
0
        hme->prev->next = hme->next;
2325
0
      else
2326
0
        RFAPI_MONITOR_ENCAP_W_ALLOC(hme->rn) =
2327
0
          hme->next;
2328
      /* Refcount checking takes too long here */
2329
      // RFAPI_CHECK_REFCOUNT(hme->rn, SAFI_ENCAP, 1);
2330
2331
      /* see if the struct rfapi_it_extra is empty and can be
2332
       * freed */
2333
0
      rfapiMonitorExtraPrune(SAFI_ENCAP, hme->rn);
2334
2335
0
      agg_unlock_node(hme->rn); /* decr ref count */
2336
0
      XFREE(MTYPE_RFAPI_MONITOR_ENCAP, hme);
2337
0
      vpn_bpi->extra->vnc.import.hme = NULL;
2338
0
    }
2339
0
  }
2340
0
}
2341
2342
/*
2343
 * Timer callback for withdraw
2344
 */
2345
static void rfapiWithdrawTimerVPN(struct event *t)
2346
0
{
2347
0
  struct rfapi_withdraw *wcb = EVENT_ARG(t);
2348
0
  struct bgp_path_info *bpi = wcb->info;
2349
0
  struct bgp *bgp = bgp_get_default();
2350
0
  const struct prefix *p;
2351
0
  struct rfapi_monitor_vpn *moved;
2352
0
  afi_t afi;
2353
0
  bool early_exit = false;
2354
2355
0
  if (bgp == NULL) {
2356
0
    vnc_zlog_debug_verbose(
2357
0
                   "%s: NULL BGP pointer, assume shutdown race condition!!!",
2358
0
                   __func__);
2359
0
    early_exit = true;
2360
0
  }
2361
0
  if (bgp && CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS)) {
2362
0
    vnc_zlog_debug_verbose(
2363
0
      "%s: BGP delete in progress, assume shutdown race condition!!!",
2364
0
      __func__);
2365
0
    early_exit = true;
2366
0
  }
2367
2368
  /* This callback is responsible for the withdraw object's memory */
2369
0
  if (early_exit) {
2370
0
    XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
2371
0
    return;
2372
0
  }
2373
2374
0
  assert(wcb->node);
2375
0
  assert(bpi);
2376
0
  assert(wcb->import_table);
2377
0
  assert(bpi->extra);
2378
2379
0
  RFAPI_CHECK_REFCOUNT(wcb->node, SAFI_MPLS_VPN, wcb->lockoffset);
2380
2381
0
  vnc_zlog_debug_verbose("%s: removing bpi %p at prefix %pRN", __func__,
2382
0
             bpi, wcb->node);
2383
2384
  /*
2385
   * Remove the route (doubly-linked)
2386
   */
2387
0
  if (CHECK_FLAG(bpi->flags, BGP_PATH_VALID)
2388
0
      && VALID_INTERIOR_TYPE(bpi->type))
2389
0
    RFAPI_MONITOR_EXTERIOR(wcb->node)->valid_interior_count--;
2390
2391
0
  p = agg_node_get_prefix(wcb->node);
2392
0
  afi = family2afi(p->family);
2393
0
  wcb->import_table->holddown_count[afi] -= 1; /* keep count consistent */
2394
0
  rfapiItBiIndexDel(wcb->node, bpi);
2395
0
  rfapiBgpInfoDetach(wcb->node, bpi); /* with removed bpi */
2396
2397
0
  vnc_import_bgp_exterior_del_route_interior(bgp, wcb->import_table,
2398
0
               wcb->node, bpi);
2399
2400
2401
  /*
2402
   * If VNC is configured to send response remove messages, AND
2403
   * if the removed route had a UN address, do response removal
2404
   * processing.
2405
   */
2406
0
  if (!(bgp->rfapi_cfg->flags
2407
0
        & BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE)) {
2408
2409
0
    int has_valid_duplicate = 0;
2410
0
    struct bgp_path_info *bpii;
2411
2412
    /*
2413
     * First check if there are any OTHER routes at this node
2414
     * that have the same nexthop and a valid UN address. If
2415
     * there are (e.g., from other peers), then the route isn't
2416
     * really gone, so skip sending a response removal message.
2417
     */
2418
0
    for (bpii = wcb->node->info; bpii; bpii = bpii->next) {
2419
0
      if (rfapiVpnBiSamePtUn(bpi, bpii)) {
2420
0
        has_valid_duplicate = 1;
2421
0
        break;
2422
0
      }
2423
0
    }
2424
2425
0
    vnc_zlog_debug_verbose("%s: has_valid_duplicate=%d", __func__,
2426
0
               has_valid_duplicate);
2427
2428
0
    if (!has_valid_duplicate) {
2429
0
      rfapiRibPendingDeleteRoute(bgp, wcb->import_table, afi,
2430
0
               wcb->node);
2431
0
    }
2432
0
  }
2433
2434
0
  rfapiMonitorEncapDelete(bpi);
2435
2436
  /*
2437
   * If there are no VPN monitors at this VPN Node A,
2438
   * we are done
2439
   */
2440
0
  if (!RFAPI_MONITOR_VPN(wcb->node)) {
2441
0
    vnc_zlog_debug_verbose("%s: no VPN monitors at this node",
2442
0
               __func__);
2443
0
    goto done;
2444
0
  }
2445
2446
  /*
2447
   * rfapiMonitorMoveShorter only moves monitors if there are
2448
   * no remaining valid routes at the current node
2449
   */
2450
0
  moved = rfapiMonitorMoveShorter(wcb->node, 1);
2451
2452
0
  if (moved) {
2453
0
    rfapiMonitorMovedUp(wcb->import_table, wcb->node, moved->node,
2454
0
            moved);
2455
0
  }
2456
2457
0
done:
2458
  /*
2459
   * Free VPN bpi
2460
   */
2461
0
  rfapiBgpInfoFree(bpi);
2462
0
  wcb->info = NULL;
2463
2464
  /*
2465
   * If route count at this node has gone to 0, withdraw exported prefix
2466
   */
2467
0
  if (!wcb->node->info) {
2468
    /* see if the struct rfapi_it_extra is empty and can be freed */
2469
0
    rfapiMonitorExtraPrune(SAFI_MPLS_VPN, wcb->node);
2470
0
    vnc_direct_bgp_del_prefix(bgp, wcb->import_table, wcb->node);
2471
0
    vnc_zebra_del_prefix(bgp, wcb->import_table, wcb->node);
2472
0
  } else {
2473
    /*
2474
     * nexthop change event
2475
     * vnc_direct_bgp_add_prefix() will recompute the VN addr
2476
     * ecommunity
2477
     */
2478
0
    vnc_direct_bgp_add_prefix(bgp, wcb->import_table, wcb->node);
2479
0
  }
2480
2481
0
  RFAPI_CHECK_REFCOUNT(wcb->node, SAFI_MPLS_VPN, 1 + wcb->lockoffset);
2482
0
  agg_unlock_node(wcb->node); /* decr ref count */
2483
0
  XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
2484
0
}
2485
2486
/*
2487
 * This works for multiprotocol extension, but not for plain ol'
2488
 * unicast IPv4 because that nexthop is stored in attr->nexthop
2489
 */
2490
void rfapiNexthop2Prefix(struct attr *attr, struct prefix *p)
2491
0
{
2492
0
  assert(p);
2493
0
  assert(attr);
2494
2495
0
  memset(p, 0, sizeof(struct prefix));
2496
2497
0
  switch (p->family = BGP_MP_NEXTHOP_FAMILY(attr->mp_nexthop_len)) {
2498
0
  case AF_INET:
2499
0
    p->u.prefix4 = attr->mp_nexthop_global_in;
2500
0
    p->prefixlen = IPV4_MAX_BITLEN;
2501
0
    break;
2502
2503
0
  case AF_INET6:
2504
0
    p->u.prefix6 = attr->mp_nexthop_global;
2505
0
    p->prefixlen = IPV6_MAX_BITLEN;
2506
0
    break;
2507
2508
0
  default:
2509
0
    vnc_zlog_debug_verbose("%s: Family is unknown = %d", __func__,
2510
0
               p->family);
2511
0
  }
2512
0
}
2513
2514
void rfapiUnicastNexthop2Prefix(afi_t afi, struct attr *attr, struct prefix *p)
2515
0
{
2516
0
  if (afi == AFI_IP) {
2517
0
    p->family = AF_INET;
2518
0
    p->prefixlen = IPV4_MAX_BITLEN;
2519
0
    p->u.prefix4 = attr->nexthop;
2520
0
  } else {
2521
0
    rfapiNexthop2Prefix(attr, p);
2522
0
  }
2523
0
}
2524
2525
static int rfapiAttrNexthopAddrDifferent(struct prefix *p1, struct prefix *p2)
2526
0
{
2527
0
  if (!p1 || !p2) {
2528
0
    vnc_zlog_debug_verbose("%s: p1 or p2 is NULL", __func__);
2529
0
    return 1;
2530
0
  }
2531
2532
  /*
2533
   * Are address families the same?
2534
   */
2535
0
  if (p1->family != p2->family) {
2536
0
    return 1;
2537
0
  }
2538
2539
0
  switch (p1->family) {
2540
0
  case AF_INET:
2541
0
    if (IPV4_ADDR_SAME(&p1->u.prefix4, &p2->u.prefix4))
2542
0
      return 0;
2543
0
    break;
2544
2545
0
  case AF_INET6:
2546
0
    if (IPV6_ADDR_SAME(&p1->u.prefix6, &p2->u.prefix6))
2547
0
      return 0;
2548
0
    break;
2549
2550
0
  default:
2551
0
    assert(1);
2552
0
  }
2553
2554
0
  return 1;
2555
0
}
2556
2557
static void rfapiCopyUnEncap2VPN(struct bgp_path_info *encap_bpi,
2558
         struct bgp_path_info *vpn_bpi)
2559
0
{
2560
0
  if (!vpn_bpi || !vpn_bpi->extra) {
2561
0
    zlog_warn("%s: no vpn  bpi attr/extra, can't copy UN address",
2562
0
        __func__);
2563
0
    return;
2564
0
  }
2565
2566
0
  switch (BGP_MP_NEXTHOP_FAMILY(encap_bpi->attr->mp_nexthop_len)) {
2567
0
  case AF_INET:
2568
2569
    /*
2570
     * instrumentation to debug segfault of 091127
2571
     */
2572
0
    vnc_zlog_debug_verbose("%s: vpn_bpi=%p", __func__, vpn_bpi);
2573
0
    vnc_zlog_debug_verbose("%s: vpn_bpi->extra=%p", __func__,
2574
0
               vpn_bpi->extra);
2575
2576
0
    vpn_bpi->extra->vnc.import.un_family = AF_INET;
2577
0
    vpn_bpi->extra->vnc.import.un.addr4 =
2578
0
      encap_bpi->attr->mp_nexthop_global_in;
2579
0
    break;
2580
2581
0
  case AF_INET6:
2582
0
    vpn_bpi->extra->vnc.import.un_family = AF_INET6;
2583
0
    vpn_bpi->extra->vnc.import.un.addr6 =
2584
0
      encap_bpi->attr->mp_nexthop_global;
2585
0
    break;
2586
2587
0
  default:
2588
0
    zlog_warn("%s: invalid encap nexthop length: %d", __func__,
2589
0
        encap_bpi->attr->mp_nexthop_len);
2590
0
    vpn_bpi->extra->vnc.import.un_family = AF_UNSPEC;
2591
0
    break;
2592
0
  }
2593
0
}
2594
2595
/*
2596
 * returns 0 on success, nonzero on error
2597
 */
2598
static int
2599
rfapiWithdrawEncapUpdateCachedUn(struct rfapi_import_table *import_table,
2600
         struct bgp_path_info *encap_bpi,
2601
         struct agg_node *vpn_rn,
2602
         struct bgp_path_info *vpn_bpi)
2603
0
{
2604
0
  if (!encap_bpi) {
2605
2606
    /*
2607
     * clear cached UN address
2608
     */
2609
0
    if (!vpn_bpi || !vpn_bpi->extra) {
2610
0
      zlog_warn(
2611
0
        "%s: missing VPN bpi/extra, can't clear UN addr",
2612
0
        __func__);
2613
0
      return 1;
2614
0
    }
2615
0
    vpn_bpi->extra->vnc.import.un_family = AF_UNSPEC;
2616
0
    memset(&vpn_bpi->extra->vnc.import.un, 0,
2617
0
           sizeof(vpn_bpi->extra->vnc.import.un));
2618
0
    if (CHECK_FLAG(vpn_bpi->flags, BGP_PATH_VALID)) {
2619
0
      if (rfapiGetVncTunnelUnAddr(vpn_bpi->attr, NULL)) {
2620
0
        UNSET_FLAG(vpn_bpi->flags, BGP_PATH_VALID);
2621
0
        if (VALID_INTERIOR_TYPE(vpn_bpi->type))
2622
0
          RFAPI_MONITOR_EXTERIOR(vpn_rn)
2623
0
            ->valid_interior_count--;
2624
        /* signal interior route withdrawal to
2625
         * import-exterior */
2626
0
        vnc_import_bgp_exterior_del_route_interior(
2627
0
          bgp_get_default(), import_table, vpn_rn,
2628
0
          vpn_bpi);
2629
0
      }
2630
0
    }
2631
2632
0
  } else {
2633
0
    if (!vpn_bpi) {
2634
0
      zlog_warn("%s: missing VPN bpi, can't clear UN addr",
2635
0
          __func__);
2636
0
      return 1;
2637
0
    }
2638
0
    rfapiCopyUnEncap2VPN(encap_bpi, vpn_bpi);
2639
0
    if (!CHECK_FLAG(vpn_bpi->flags, BGP_PATH_VALID)) {
2640
0
      SET_FLAG(vpn_bpi->flags, BGP_PATH_VALID);
2641
0
      if (VALID_INTERIOR_TYPE(vpn_bpi->type))
2642
0
        RFAPI_MONITOR_EXTERIOR(vpn_rn)
2643
0
          ->valid_interior_count++;
2644
      /* signal interior route withdrawal to import-exterior
2645
       */
2646
0
      vnc_import_bgp_exterior_add_route_interior(
2647
0
        bgp_get_default(), import_table, vpn_rn,
2648
0
        vpn_bpi);
2649
0
    }
2650
0
  }
2651
0
  return 0;
2652
0
}
2653
2654
static void rfapiWithdrawTimerEncap(struct event *t)
2655
0
{
2656
0
  struct rfapi_withdraw *wcb = EVENT_ARG(t);
2657
0
  struct bgp_path_info *bpi = wcb->info;
2658
0
  int was_first_route = 0;
2659
0
  struct rfapi_monitor_encap *em;
2660
0
  struct skiplist *vpn_node_sl = skiplist_new(0, NULL, NULL);
2661
2662
0
  assert(wcb->node);
2663
0
  assert(bpi);
2664
0
  assert(wcb->import_table);
2665
2666
0
  RFAPI_CHECK_REFCOUNT(wcb->node, SAFI_ENCAP, 0);
2667
2668
0
  if (wcb->node->info == bpi)
2669
0
    was_first_route = 1;
2670
2671
  /*
2672
   * Remove the route/bpi and free it
2673
   */
2674
0
  rfapiBgpInfoDetach(wcb->node, bpi);
2675
0
  rfapiBgpInfoFree(bpi);
2676
2677
0
  if (!was_first_route)
2678
0
    goto done;
2679
2680
0
  for (em = RFAPI_MONITOR_ENCAP(wcb->node); em; em = em->next) {
2681
2682
    /*
2683
     * Update monitoring VPN BPIs with new encap info at the
2684
     * head of the encap bpi chain (which could be NULL after
2685
     * removing the expiring bpi above)
2686
     */
2687
0
    if (rfapiWithdrawEncapUpdateCachedUn(wcb->import_table,
2688
0
                 wcb->node->info, em->node,
2689
0
                 em->bpi))
2690
0
      continue;
2691
2692
    /*
2693
     * Build a list of unique VPN nodes referenced by these
2694
     * monitors.
2695
     * Use a skiplist for speed.
2696
     */
2697
0
    skiplist_insert(vpn_node_sl, em->node, em->node);
2698
0
  }
2699
2700
2701
  /*
2702
   * for each VPN node referenced in the ENCAP monitors:
2703
   */
2704
0
  struct agg_node *rn;
2705
0
  while (!skiplist_first(vpn_node_sl, (void **)&rn, NULL)) {
2706
0
    if (!wcb->node->info) {
2707
0
      struct rfapi_monitor_vpn *moved;
2708
2709
0
      moved = rfapiMonitorMoveShorter(rn, 0);
2710
0
      if (moved) {
2711
        // rfapiDoRouteCallback(wcb->import_table,
2712
        // moved->node, moved);
2713
0
        rfapiMonitorMovedUp(wcb->import_table, rn,
2714
0
                moved->node, moved);
2715
0
      }
2716
0
    } else {
2717
      // rfapiDoRouteCallback(wcb->import_table, rn, NULL);
2718
0
      rfapiMonitorItNodeChanged(wcb->import_table, rn, NULL);
2719
0
    }
2720
0
    skiplist_delete_first(vpn_node_sl);
2721
0
  }
2722
2723
0
done:
2724
0
  RFAPI_CHECK_REFCOUNT(wcb->node, SAFI_ENCAP, 1);
2725
0
  agg_unlock_node(wcb->node); /* decr ref count */
2726
0
  XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
2727
0
  skiplist_free(vpn_node_sl);
2728
0
}
2729
2730
2731
/*
2732
 * Works for both VPN and ENCAP routes; timer_service_func is different
2733
 * in each case
2734
 */
2735
static void
2736
rfapiBiStartWithdrawTimer(struct rfapi_import_table *import_table,
2737
        struct agg_node *rn, struct bgp_path_info *bpi,
2738
        afi_t afi, safi_t safi,
2739
        void (*timer_service_func)(struct event *))
2740
0
{
2741
0
  uint32_t lifetime;
2742
0
  struct rfapi_withdraw *wcb;
2743
2744
0
  if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) {
2745
    /*
2746
     * Already on the path to being withdrawn,
2747
     * should already have a timer set up to
2748
     * delete it.
2749
     */
2750
0
    vnc_zlog_debug_verbose(
2751
0
      "%s: already being withdrawn, do nothing", __func__);
2752
0
    return;
2753
0
  }
2754
2755
0
  rfapiGetVncLifetime(bpi->attr, &lifetime);
2756
0
  vnc_zlog_debug_verbose("%s: VNC lifetime is %u", __func__, lifetime);
2757
2758
  /*
2759
   * withdrawn routes get to hang around for a while
2760
   */
2761
0
  SET_FLAG(bpi->flags, BGP_PATH_REMOVED);
2762
2763
  /* set timer to remove the route later */
2764
0
  lifetime = rfapiGetHolddownFromLifetime(lifetime);
2765
0
  vnc_zlog_debug_verbose("%s: using timeout %u", __func__, lifetime);
2766
2767
  /*
2768
   * Stash import_table, node, and info for use by timer
2769
   * service routine, which is supposed to free the wcb.
2770
   */
2771
0
  wcb = XCALLOC(MTYPE_RFAPI_WITHDRAW, sizeof(struct rfapi_withdraw));
2772
0
  wcb->node = rn;
2773
0
  wcb->info = bpi;
2774
0
  wcb->import_table = import_table;
2775
0
  bgp_attr_intern(bpi->attr);
2776
2777
0
  if (VNC_DEBUG(VERBOSE)) {
2778
0
    vnc_zlog_debug_verbose(
2779
0
      "%s: wcb values: node=%p, info=%p, import_table=%p (bpi follows)",
2780
0
      __func__, wcb->node, wcb->info, wcb->import_table);
2781
0
    rfapiPrintBi(NULL, bpi);
2782
0
  }
2783
2784
2785
0
  assert(bpi->extra);
2786
0
  if (lifetime > UINT32_MAX / 1001) {
2787
    /* sub-optimal case, but will probably never happen */
2788
0
    bpi->extra->vnc.import.timer = NULL;
2789
0
    event_add_timer(bm->master, timer_service_func, wcb, lifetime,
2790
0
        &bpi->extra->vnc.import.timer);
2791
0
  } else {
2792
0
    static uint32_t jitter;
2793
0
    uint32_t lifetime_msec;
2794
2795
    /*
2796
     * the goal here is to spread out the timers so they are
2797
     * sortable in the skip list
2798
     */
2799
0
    if (++jitter >= 1000)
2800
0
      jitter = 0;
2801
2802
0
    lifetime_msec = (lifetime * 1000) + jitter;
2803
2804
0
    bpi->extra->vnc.import.timer = NULL;
2805
0
    event_add_timer_msec(bm->master, timer_service_func, wcb,
2806
0
             lifetime_msec,
2807
0
             &bpi->extra->vnc.import.timer);
2808
0
  }
2809
2810
  /* re-sort route list (BGP_PATH_REMOVED routes are last) */
2811
0
  if (((struct bgp_path_info *)rn->info)->next) {
2812
0
    rfapiBgpInfoDetach(rn, bpi);
2813
0
    rfapiBgpInfoAttachSorted(rn, bpi, afi, safi);
2814
0
  }
2815
0
}
2816
2817
2818
typedef void(rfapi_bi_filtered_import_f)(struct rfapi_import_table *table,
2819
           int action, struct peer *peer,
2820
           void *rfd, const struct prefix *prefix,
2821
           const struct prefix *aux_prefix,
2822
           afi_t afi, struct prefix_rd *prd,
2823
           struct attr *attr, uint8_t type,
2824
           uint8_t sub_type, uint32_t *label);
2825
2826
2827
static void rfapiExpireEncapNow(struct rfapi_import_table *it,
2828
        struct agg_node *rn, struct bgp_path_info *bpi)
2829
0
{
2830
0
  struct rfapi_withdraw *wcb;
2831
0
  struct event t;
2832
2833
  /*
2834
   * pretend we're an expiring timer
2835
   */
2836
0
  wcb = XCALLOC(MTYPE_RFAPI_WITHDRAW, sizeof(struct rfapi_withdraw));
2837
0
  wcb->info = bpi;
2838
0
  wcb->node = rn;
2839
0
  wcb->import_table = it;
2840
0
  memset(&t, 0, sizeof(t));
2841
0
  t.arg = wcb;
2842
0
  rfapiWithdrawTimerEncap(&t); /* frees wcb */
2843
0
}
2844
2845
static int rfapiGetNexthop(struct attr *attr, struct prefix *prefix)
2846
0
{
2847
0
  switch (BGP_MP_NEXTHOP_FAMILY(attr->mp_nexthop_len)) {
2848
0
  case AF_INET:
2849
0
    prefix->family = AF_INET;
2850
0
    prefix->prefixlen = IPV4_MAX_BITLEN;
2851
0
    prefix->u.prefix4 = attr->mp_nexthop_global_in;
2852
0
    break;
2853
0
  case AF_INET6:
2854
0
    prefix->family = AF_INET6;
2855
0
    prefix->prefixlen = IPV6_MAX_BITLEN;
2856
0
    prefix->u.prefix6 = attr->mp_nexthop_global;
2857
0
    break;
2858
0
  default:
2859
0
    vnc_zlog_debug_verbose("%s: unknown attr->mp_nexthop_len %d",
2860
0
               __func__, attr->mp_nexthop_len);
2861
0
    return EINVAL;
2862
0
  }
2863
0
  return 0;
2864
0
}
2865
2866
/*
2867
 * import a bgp_path_info if its route target list intersects with the
2868
 * import table's route target list
2869
 */
2870
static void rfapiBgpInfoFilteredImportEncap(
2871
  struct rfapi_import_table *import_table, int action, struct peer *peer,
2872
  void *rfd, /* set for looped back routes */
2873
  const struct prefix *p,
2874
  const struct prefix *aux_prefix, /* Unused for encap routes */
2875
  afi_t afi, struct prefix_rd *prd,
2876
  struct attr *attr, /* part of bgp_path_info */
2877
  uint8_t type,    /* part of bgp_path_info */
2878
  uint8_t sub_type,  /* part of bgp_path_info */
2879
  uint32_t *label)   /* part of bgp_path_info */
2880
0
{
2881
0
  struct agg_table *rt = NULL;
2882
0
  struct agg_node *rn;
2883
0
  struct bgp_path_info *info_new;
2884
0
  struct bgp_path_info *bpi;
2885
0
  struct bgp_path_info *next;
2886
0
  char buf[BUFSIZ];
2887
2888
0
  struct prefix p_firstbpi_old;
2889
0
  struct prefix p_firstbpi_new;
2890
0
  int replacing = 0;
2891
0
  const char *action_str = NULL;
2892
0
  struct prefix un_prefix;
2893
2894
0
  struct bgp *bgp;
2895
0
  bgp = bgp_get_default(); /* assume 1 instance for now */
2896
2897
0
  switch (action) {
2898
0
  case FIF_ACTION_UPDATE:
2899
0
    action_str = "update";
2900
0
    break;
2901
0
  case FIF_ACTION_WITHDRAW:
2902
0
    action_str = "withdraw";
2903
0
    break;
2904
0
  case FIF_ACTION_KILL:
2905
0
    action_str = "kill";
2906
0
    break;
2907
0
  default:
2908
0
    assert(0);
2909
0
    break;
2910
0
  }
2911
2912
0
  vnc_zlog_debug_verbose(
2913
0
    "%s: entry: %s: prefix %s/%d", __func__, action_str,
2914
0
    inet_ntop(p->family, &p->u.prefix, buf, sizeof(buf)),
2915
0
    p->prefixlen);
2916
2917
0
  memset(&p_firstbpi_old, 0, sizeof(p_firstbpi_old));
2918
0
  memset(&p_firstbpi_new, 0, sizeof(p_firstbpi_new));
2919
2920
0
  if (action == FIF_ACTION_UPDATE) {
2921
    /*
2922
     * Compare rt lists. If no intersection, don't import this route
2923
     * On a withdraw, peer and RD are sufficient to determine if
2924
     * we should act.
2925
     */
2926
0
    if (!attr || !bgp_attr_get_ecommunity(attr)) {
2927
2928
0
      vnc_zlog_debug_verbose(
2929
0
        "%s: attr, extra, or ecommunity missing, not importing",
2930
0
        __func__);
2931
0
      return;
2932
0
    }
2933
#ifdef RFAPI_REQUIRE_ENCAP_BEEC
2934
    if (!rfapiEcommunitiesMatchBeec(
2935
          bgp_attr_get_ecommunity(attr))) {
2936
      vnc_zlog_debug_verbose(
2937
        "%s: it=%p: no match for BGP Encapsulation ecommunity",
2938
        __func__, import_table);
2939
      return;
2940
    }
2941
#endif
2942
0
    if (!rfapiEcommunitiesIntersect(
2943
0
          import_table->rt_import_list,
2944
0
          bgp_attr_get_ecommunity(attr))) {
2945
2946
0
      vnc_zlog_debug_verbose(
2947
0
        "%s: it=%p: no ecommunity intersection",
2948
0
        __func__, import_table);
2949
0
      return;
2950
0
    }
2951
2952
    /*
2953
     * Updates must also have a nexthop address
2954
     */
2955
0
    memset(&un_prefix, 0,
2956
0
           sizeof(un_prefix)); /* keep valgrind happy */
2957
0
    if (rfapiGetNexthop(attr, &un_prefix)) {
2958
0
      vnc_zlog_debug_verbose("%s: missing nexthop address",
2959
0
                 __func__);
2960
0
      return;
2961
0
    }
2962
0
  }
2963
2964
  /*
2965
   * Figure out which radix tree the route would go into
2966
   */
2967
0
  switch (afi) {
2968
0
  case AFI_IP:
2969
0
  case AFI_IP6:
2970
0
    rt = import_table->imported_encap[afi];
2971
0
    break;
2972
2973
0
  case AFI_UNSPEC:
2974
0
  case AFI_L2VPN:
2975
0
  case AFI_MAX:
2976
0
    flog_err(EC_LIB_DEVELOPMENT, "%s: bad afi %d", __func__, afi);
2977
0
    return;
2978
0
  }
2979
2980
  /*
2981
   * agg_node_lookup returns a node only if there is at least
2982
   * one route attached.
2983
   */
2984
0
  rn = agg_node_lookup(rt, p);
2985
2986
#ifdef DEBUG_ENCAP_MONITOR
2987
  vnc_zlog_debug_verbose("%s: initial encap lookup(it=%p) rn=%p",
2988
             __func__, import_table, rn);
2989
#endif
2990
2991
0
  if (rn) {
2992
2993
0
    RFAPI_CHECK_REFCOUNT(rn, SAFI_ENCAP, 1);
2994
0
    agg_unlock_node(rn); /* undo lock in agg_node_lookup */
2995
2996
2997
    /*
2998
     * capture nexthop of first bpi
2999
     */
3000
0
    if (rn->info) {
3001
0
      rfapiNexthop2Prefix(
3002
0
        ((struct bgp_path_info *)(rn->info))->attr,
3003
0
        &p_firstbpi_old);
3004
0
    }
3005
3006
0
    for (bpi = rn->info; bpi; bpi = bpi->next) {
3007
3008
      /*
3009
       * Does this bgp_path_info refer to the same route
3010
       * as we are trying to add?
3011
       */
3012
0
      vnc_zlog_debug_verbose("%s: comparing BPI %p", __func__,
3013
0
                 bpi);
3014
3015
3016
      /*
3017
       * Compare RDs
3018
       *
3019
       * RD of import table bpi is in
3020
       * bpi->extra->vnc.import.rd RD of info_orig is in prd
3021
       */
3022
0
      if (!bpi->extra) {
3023
0
        vnc_zlog_debug_verbose("%s: no bpi->extra",
3024
0
                   __func__);
3025
0
        continue;
3026
0
      }
3027
0
      if (prefix_cmp(
3028
0
            (struct prefix *)&bpi->extra->vnc.import.rd,
3029
0
            (struct prefix *)prd)) {
3030
3031
0
        vnc_zlog_debug_verbose("%s: prd does not match",
3032
0
                   __func__);
3033
0
        continue;
3034
0
      }
3035
3036
      /*
3037
       * Compare peers
3038
       */
3039
0
      if (bpi->peer != peer) {
3040
0
        vnc_zlog_debug_verbose(
3041
0
          "%s: peer does not match", __func__);
3042
0
        continue;
3043
0
      }
3044
3045
0
      vnc_zlog_debug_verbose("%s: found matching bpi",
3046
0
                 __func__);
3047
3048
      /* Same route. Delete this bpi, replace with new one */
3049
3050
0
      if (action == FIF_ACTION_WITHDRAW) {
3051
3052
0
        vnc_zlog_debug_verbose(
3053
0
          "%s: withdrawing at prefix %pRN",
3054
0
          __func__, rn);
3055
3056
0
        rfapiBiStartWithdrawTimer(
3057
0
          import_table, rn, bpi, afi, SAFI_ENCAP,
3058
0
          rfapiWithdrawTimerEncap);
3059
3060
0
      } else {
3061
0
        vnc_zlog_debug_verbose(
3062
0
          "%s: %s at prefix %pRN", __func__,
3063
0
          ((action == FIF_ACTION_KILL)
3064
0
             ? "killing"
3065
0
             : "replacing"),
3066
0
          rn);
3067
3068
        /*
3069
         * If this route is waiting to be deleted
3070
         * because of
3071
         * a previous withdraw, we must cancel its
3072
         * timer.
3073
         */
3074
0
        if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)
3075
0
            && bpi->extra->vnc.import.timer) {
3076
0
          struct rfapi_withdraw *wcb = EVENT_ARG(
3077
0
            bpi->extra->vnc.import.timer);
3078
3079
0
          XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
3080
0
          EVENT_OFF(bpi->extra->vnc.import.timer);
3081
0
        }
3082
3083
0
        if (action == FIF_ACTION_UPDATE) {
3084
0
          rfapiBgpInfoDetach(rn, bpi);
3085
0
          rfapiBgpInfoFree(bpi);
3086
0
          replacing = 1;
3087
0
        } else {
3088
          /*
3089
           * Kill: do export stuff when removing
3090
           * bpi
3091
           */
3092
0
          struct rfapi_withdraw *wcb;
3093
0
          struct event t;
3094
3095
          /*
3096
           * pretend we're an expiring timer
3097
           */
3098
0
          wcb = XCALLOC(
3099
0
            MTYPE_RFAPI_WITHDRAW,
3100
0
            sizeof(struct rfapi_withdraw));
3101
0
          wcb->info = bpi;
3102
0
          wcb->node = rn;
3103
0
          wcb->import_table = import_table;
3104
0
          memset(&t, 0, sizeof(t));
3105
0
          t.arg = wcb;
3106
0
          rfapiWithdrawTimerEncap(
3107
0
            &t); /* frees wcb */
3108
0
        }
3109
0
      }
3110
3111
0
      break;
3112
0
    }
3113
0
  }
3114
3115
0
  if (rn)
3116
0
    RFAPI_CHECK_REFCOUNT(rn, SAFI_ENCAP, replacing ? 1 : 0);
3117
3118
0
  if (action == FIF_ACTION_WITHDRAW || action == FIF_ACTION_KILL)
3119
0
    return;
3120
3121
0
  info_new =
3122
0
    rfapiBgpInfoCreate(attr, peer, rfd, prd, type, sub_type, NULL);
3123
3124
0
  if (rn) {
3125
0
    if (!replacing)
3126
0
      agg_lock_node(rn); /* incr ref count for new BPI */
3127
0
  } else {
3128
0
    rn = agg_node_get(rt, p);
3129
0
  }
3130
3131
0
  vnc_zlog_debug_verbose("%s: (afi=%d, rn=%p) inserting at prefix %pRN",
3132
0
             __func__, afi, rn, rn);
3133
3134
0
  rfapiBgpInfoAttachSorted(rn, info_new, afi, SAFI_ENCAP);
3135
3136
  /*
3137
   * Delete holddown routes from same NVE. See details in
3138
   * rfapiBgpInfoFilteredImportVPN()
3139
   */
3140
0
  for (bpi = info_new->next; bpi; bpi = next) {
3141
3142
0
    struct prefix pfx_un;
3143
0
    int un_match = 0;
3144
3145
0
    next = bpi->next;
3146
0
    if (!CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED))
3147
0
      continue;
3148
3149
    /*
3150
     * We already match the VN address (it is the prefix
3151
     * of the route node)
3152
     */
3153
3154
0
    if (!rfapiGetNexthop(bpi->attr, &pfx_un)
3155
0
        && prefix_same(&pfx_un, &un_prefix)) {
3156
3157
0
      un_match = 1;
3158
0
    }
3159
3160
0
    if (!un_match)
3161
0
      continue;
3162
3163
0
    vnc_zlog_debug_verbose(
3164
0
      "%s: removing holddown bpi matching NVE of new route",
3165
0
      __func__);
3166
0
    if (bpi->extra->vnc.import.timer) {
3167
0
      struct rfapi_withdraw *wcb =
3168
0
        EVENT_ARG(bpi->extra->vnc.import.timer);
3169
3170
0
      XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
3171
0
      EVENT_OFF(bpi->extra->vnc.import.timer);
3172
0
    }
3173
0
    rfapiExpireEncapNow(import_table, rn, bpi);
3174
0
  }
3175
3176
0
  rfapiNexthop2Prefix(((struct bgp_path_info *)(rn->info))->attr,
3177
0
          &p_firstbpi_new);
3178
3179
  /*
3180
   * If the nexthop address of the selected Encap route (i.e.,
3181
   * the UN address) has changed, then we must update the VPN
3182
   * routes that refer to this Encap route and possibly force
3183
   * rfapi callbacks.
3184
   */
3185
0
  if (rfapiAttrNexthopAddrDifferent(&p_firstbpi_old, &p_firstbpi_new)) {
3186
3187
0
    struct rfapi_monitor_encap *m;
3188
0
    struct rfapi_monitor_encap *mnext;
3189
3190
0
    struct agg_node *referenced_vpn_prefix;
3191
3192
    /*
3193
     * Optimized approach: build radix tree on the fly to
3194
     * hold list of VPN nodes referenced by the ENCAP monitors
3195
     *
3196
     * The nodes in this table correspond to prefixes of VPN routes.
3197
     * The "info" pointer of the node points to a chain of
3198
     * struct rfapi_monitor_encap, each of which refers to a
3199
     * specific VPN node.
3200
     */
3201
0
    struct agg_table *referenced_vpn_table;
3202
3203
0
    referenced_vpn_table = agg_table_init();
3204
3205
/*
3206
 * iterate over the set of monitors at this ENCAP node.
3207
 */
3208
#ifdef DEBUG_ENCAP_MONITOR
3209
    vnc_zlog_debug_verbose("%s: examining monitors at rn=%p",
3210
               __func__, rn);
3211
#endif
3212
0
    for (m = RFAPI_MONITOR_ENCAP(rn); m; m = m->next) {
3213
0
      const struct prefix *p;
3214
3215
      /*
3216
       * For each referenced bpi/route, copy the ENCAP route's
3217
       * nexthop to the VPN route's cached UN address field
3218
       * and set
3219
       * the address family of the cached UN address field.
3220
       */
3221
0
      rfapiCopyUnEncap2VPN(info_new, m->bpi);
3222
0
      if (!CHECK_FLAG(m->bpi->flags, BGP_PATH_VALID)) {
3223
0
        SET_FLAG(m->bpi->flags, BGP_PATH_VALID);
3224
0
        if (VALID_INTERIOR_TYPE(m->bpi->type))
3225
0
          RFAPI_MONITOR_EXTERIOR(m->node)
3226
0
            ->valid_interior_count++;
3227
0
        vnc_import_bgp_exterior_add_route_interior(
3228
0
          bgp, import_table, m->node, m->bpi);
3229
0
      }
3230
3231
      /*
3232
       * Build a list of unique VPN nodes referenced by these
3233
       * monitors
3234
       *
3235
       * There could be more than one VPN node here with a
3236
       * given
3237
       * prefix. Those are currently in an unsorted linear
3238
       * list
3239
       * per prefix.
3240
       */
3241
0
      p = agg_node_get_prefix(m->node);
3242
0
      referenced_vpn_prefix =
3243
0
        agg_node_get(referenced_vpn_table, p);
3244
0
      assert(referenced_vpn_prefix);
3245
0
      for (mnext = referenced_vpn_prefix->info; mnext;
3246
0
           mnext = mnext->next) {
3247
3248
0
        if (mnext->node == m->node)
3249
0
          break;
3250
0
      }
3251
3252
0
      if (mnext) {
3253
        /*
3254
         * already have an entry for this VPN node
3255
         */
3256
0
        agg_unlock_node(referenced_vpn_prefix);
3257
0
      } else {
3258
0
        mnext = XCALLOC(
3259
0
          MTYPE_RFAPI_MONITOR_ENCAP,
3260
0
          sizeof(struct rfapi_monitor_encap));
3261
0
        mnext->node = m->node;
3262
0
        mnext->next = referenced_vpn_prefix->info;
3263
0
        referenced_vpn_prefix->info = mnext;
3264
0
      }
3265
0
    }
3266
3267
    /*
3268
     * for each VPN node referenced in the ENCAP monitors:
3269
     */
3270
0
    for (referenced_vpn_prefix =
3271
0
           agg_route_top(referenced_vpn_table);
3272
0
         referenced_vpn_prefix;
3273
0
         referenced_vpn_prefix =
3274
0
           agg_route_next(referenced_vpn_prefix)) {
3275
3276
0
      while ((m = referenced_vpn_prefix->info)) {
3277
3278
0
        struct agg_node *n;
3279
3280
0
        rfapiMonitorMoveLonger(m->node);
3281
0
        for (n = m->node; n; n = agg_node_parent(n)) {
3282
          // rfapiDoRouteCallback(import_table, n,
3283
          // NULL);
3284
0
        }
3285
0
        rfapiMonitorItNodeChanged(import_table, m->node,
3286
0
                NULL);
3287
3288
0
        referenced_vpn_prefix->info = m->next;
3289
0
        agg_unlock_node(referenced_vpn_prefix);
3290
0
        XFREE(MTYPE_RFAPI_MONITOR_ENCAP, m);
3291
0
      }
3292
0
    }
3293
0
    agg_table_finish(referenced_vpn_table);
3294
0
  }
3295
3296
0
  RFAPI_CHECK_REFCOUNT(rn, SAFI_ENCAP, 0);
3297
0
}
3298
3299
static void rfapiExpireVpnNow(struct rfapi_import_table *it,
3300
            struct agg_node *rn, struct bgp_path_info *bpi,
3301
            int lockoffset)
3302
0
{
3303
0
  struct rfapi_withdraw *wcb;
3304
0
  struct event t;
3305
3306
  /*
3307
   * pretend we're an expiring timer
3308
   */
3309
0
  wcb = XCALLOC(MTYPE_RFAPI_WITHDRAW, sizeof(struct rfapi_withdraw));
3310
0
  wcb->info = bpi;
3311
0
  wcb->node = rn;
3312
0
  wcb->import_table = it;
3313
0
  wcb->lockoffset = lockoffset;
3314
0
  memset(&t, 0, sizeof(t));
3315
0
  t.arg = wcb;
3316
0
  rfapiWithdrawTimerVPN(&t); /* frees wcb */
3317
0
}
3318
3319
3320
/*
3321
 * import a bgp_path_info if its route target list intersects with the
3322
 * import table's route target list
3323
 */
3324
void rfapiBgpInfoFilteredImportVPN(
3325
  struct rfapi_import_table *import_table, int action, struct peer *peer,
3326
  void *rfd, /* set for looped back routes */
3327
  const struct prefix *p,
3328
  const struct prefix *aux_prefix, /* AFI_L2VPN: optional IP */
3329
  afi_t afi, struct prefix_rd *prd,
3330
  struct attr *attr, /* part of bgp_path_info */
3331
  uint8_t type,    /* part of bgp_path_info */
3332
  uint8_t sub_type,  /* part of bgp_path_info */
3333
  uint32_t *label)   /* part of bgp_path_info */
3334
0
{
3335
0
  struct agg_table *rt = NULL;
3336
0
  struct agg_node *rn;
3337
0
  struct agg_node *n;
3338
0
  struct bgp_path_info *info_new;
3339
0
  struct bgp_path_info *bpi;
3340
0
  struct bgp_path_info *next;
3341
0
  char buf[BUFSIZ];
3342
0
  struct prefix vn_prefix;
3343
0
  struct prefix un_prefix;
3344
0
  int un_prefix_valid = 0;
3345
0
  struct agg_node *ern;
3346
0
  int replacing = 0;
3347
0
  int original_had_routes = 0;
3348
0
  struct prefix original_nexthop;
3349
0
  const char *action_str = NULL;
3350
0
  int is_it_ce = 0;
3351
3352
0
  struct bgp *bgp;
3353
0
  bgp = bgp_get_default(); /* assume 1 instance for now */
3354
3355
0
  switch (action) {
3356
0
  case FIF_ACTION_UPDATE:
3357
0
    action_str = "update";
3358
0
    break;
3359
0
  case FIF_ACTION_WITHDRAW:
3360
0
    action_str = "withdraw";
3361
0
    break;
3362
0
  case FIF_ACTION_KILL:
3363
0
    action_str = "kill";
3364
0
    break;
3365
0
  default:
3366
0
    assert(0);
3367
0
    break;
3368
0
  }
3369
3370
0
  if (import_table == bgp->rfapi->it_ce)
3371
0
    is_it_ce = 1;
3372
3373
0
  vnc_zlog_debug_verbose("%s: entry: %s%s: prefix %s/%d: it %p, afi %s",
3374
0
             __func__, (is_it_ce ? "CE-IT " : ""), action_str,
3375
0
             rfapi_ntop(p->family, &p->u.prefix, buf, BUFSIZ),
3376
0
             p->prefixlen, import_table, afi2str(afi));
3377
3378
0
  VNC_ITRCCK;
3379
3380
  /*
3381
   * Compare rt lists. If no intersection, don't import this route
3382
   * On a withdraw, peer and RD are sufficient to determine if
3383
   * we should act.
3384
   */
3385
0
  if (action == FIF_ACTION_UPDATE) {
3386
0
    if (!attr || !bgp_attr_get_ecommunity(attr)) {
3387
3388
0
      vnc_zlog_debug_verbose(
3389
0
        "%s: attr, extra, or ecommunity missing, not importing",
3390
0
        __func__);
3391
0
      return;
3392
0
    }
3393
0
    if ((import_table != bgp->rfapi->it_ce) &&
3394
0
        !rfapiEcommunitiesIntersect(
3395
0
          import_table->rt_import_list,
3396
0
          bgp_attr_get_ecommunity(attr))) {
3397
3398
0
      vnc_zlog_debug_verbose(
3399
0
        "%s: it=%p: no ecommunity intersection",
3400
0
        __func__, import_table);
3401
0
      return;
3402
0
    }
3403
3404
0
    memset(&vn_prefix, 0,
3405
0
           sizeof(vn_prefix)); /* keep valgrind happy */
3406
0
    if (rfapiGetNexthop(attr, &vn_prefix)) {
3407
      /* missing nexthop address would be a bad, bad thing */
3408
0
      vnc_zlog_debug_verbose("%s: missing nexthop", __func__);
3409
0
      return;
3410
0
    }
3411
0
  }
3412
3413
  /*
3414
   * Figure out which radix tree the route would go into
3415
   */
3416
0
  switch (afi) {
3417
0
  case AFI_IP:
3418
0
  case AFI_IP6:
3419
0
  case AFI_L2VPN:
3420
0
    rt = import_table->imported_vpn[afi];
3421
0
    break;
3422
3423
0
  case AFI_UNSPEC:
3424
0
  case AFI_MAX:
3425
0
    flog_err(EC_LIB_DEVELOPMENT, "%s: bad afi %d", __func__, afi);
3426
0
    return;
3427
0
  }
3428
3429
  /* clear it */
3430
0
  memset(&original_nexthop, 0, sizeof(original_nexthop));
3431
3432
  /*
3433
   * agg_node_lookup returns a node only if there is at least
3434
   * one route attached.
3435
   */
3436
0
  rn = agg_node_lookup(rt, p);
3437
3438
0
  vnc_zlog_debug_verbose("%s: rn=%p", __func__, rn);
3439
3440
0
  if (rn) {
3441
3442
0
    RFAPI_CHECK_REFCOUNT(rn, SAFI_MPLS_VPN, 1);
3443
0
    agg_unlock_node(rn); /* undo lock in agg_node_lookup */
3444
3445
0
    if (rn->info)
3446
0
      original_had_routes = 1;
3447
3448
0
    if (VNC_DEBUG(VERBOSE)) {
3449
0
      vnc_zlog_debug_verbose("%s: showing IT node on entry",
3450
0
                 __func__);
3451
0
      rfapiShowItNode(NULL, rn); /* debug */
3452
0
    }
3453
3454
    /*
3455
     * Look for same route (will have same RD and peer)
3456
     */
3457
0
    bpi = rfapiItBiIndexSearch(rn, prd, peer, aux_prefix);
3458
3459
0
    if (bpi) {
3460
3461
      /*
3462
       * This was an old test when we iterated over the
3463
       * BPIs linearly. Since we're now looking up with
3464
       * RD and peer, comparing types should not be
3465
       * needed. Changed to assertion.
3466
       *
3467
       * Compare types. Doing so prevents a RFP-originated
3468
       * route from matching an imported route, for example.
3469
       */
3470
0
      if (VNC_DEBUG(VERBOSE) && bpi->type != type)
3471
        /* should be handled by RDs, but warn for now */
3472
0
        zlog_warn("%s: type mismatch! (bpi=%d, arg=%d)",
3473
0
            __func__, bpi->type, type);
3474
3475
0
      vnc_zlog_debug_verbose("%s: found matching bpi",
3476
0
                 __func__);
3477
3478
      /*
3479
       * In the special CE table, withdrawals occur without
3480
       * holddown
3481
       */
3482
0
      if (import_table == bgp->rfapi->it_ce) {
3483
0
        vnc_direct_bgp_del_route_ce(bgp, rn, bpi);
3484
0
        if (action == FIF_ACTION_WITHDRAW)
3485
0
          action = FIF_ACTION_KILL;
3486
0
      }
3487
3488
0
      if (action == FIF_ACTION_WITHDRAW) {
3489
3490
0
        int washolddown = CHECK_FLAG(bpi->flags,
3491
0
                   BGP_PATH_REMOVED);
3492
3493
0
        vnc_zlog_debug_verbose(
3494
0
          "%s: withdrawing at prefix %pRN%s",
3495
0
          __func__, rn,
3496
0
          (washolddown
3497
0
             ? " (already being withdrawn)"
3498
0
             : ""));
3499
3500
0
        VNC_ITRCCK;
3501
0
        if (!washolddown) {
3502
0
          rfapiBiStartWithdrawTimer(
3503
0
            import_table, rn, bpi, afi,
3504
0
            SAFI_MPLS_VPN,
3505
0
            rfapiWithdrawTimerVPN);
3506
3507
0
          RFAPI_UPDATE_ITABLE_COUNT(
3508
0
            bpi, import_table, afi, -1);
3509
0
          import_table->holddown_count[afi] += 1;
3510
0
        }
3511
0
        VNC_ITRCCK;
3512
0
      } else {
3513
0
        vnc_zlog_debug_verbose(
3514
0
          "%s: %s at prefix %pRN", __func__,
3515
0
          ((action == FIF_ACTION_KILL)
3516
0
             ? "killing"
3517
0
             : "replacing"),
3518
0
          rn);
3519
3520
        /*
3521
         * If this route is waiting to be deleted
3522
         * because of
3523
         * a previous withdraw, we must cancel its
3524
         * timer.
3525
         */
3526
0
        if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)
3527
0
            && bpi->extra->vnc.import.timer) {
3528
0
          struct rfapi_withdraw *wcb = EVENT_ARG(
3529
0
            bpi->extra->vnc.import.timer);
3530
3531
0
          XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
3532
0
          EVENT_OFF(bpi->extra->vnc.import.timer);
3533
3534
0
          import_table->holddown_count[afi] -= 1;
3535
0
          RFAPI_UPDATE_ITABLE_COUNT(
3536
0
            bpi, import_table, afi, 1);
3537
0
        }
3538
        /*
3539
         * decrement remote count (if route is remote)
3540
         * because
3541
         * we are going to remove it below
3542
         */
3543
0
        RFAPI_UPDATE_ITABLE_COUNT(bpi, import_table,
3544
0
                afi, -1);
3545
0
        if (action == FIF_ACTION_UPDATE) {
3546
0
          replacing = 1;
3547
3548
          /*
3549
           * make copy of original nexthop so we
3550
           * can see if it changed
3551
           */
3552
0
          rfapiGetNexthop(bpi->attr,
3553
0
              &original_nexthop);
3554
3555
          /*
3556
           * remove bpi without doing any export
3557
           * processing
3558
           */
3559
0
          if (CHECK_FLAG(bpi->flags,
3560
0
                   BGP_PATH_VALID)
3561
0
              && VALID_INTERIOR_TYPE(bpi->type))
3562
0
            RFAPI_MONITOR_EXTERIOR(rn)
3563
0
              ->valid_interior_count--;
3564
0
          rfapiItBiIndexDel(rn, bpi);
3565
0
          rfapiBgpInfoDetach(rn, bpi);
3566
0
          rfapiMonitorEncapDelete(bpi);
3567
0
          vnc_import_bgp_exterior_del_route_interior(
3568
0
            bgp, import_table, rn, bpi);
3569
0
          rfapiBgpInfoFree(bpi);
3570
0
        } else {
3571
          /* Kill */
3572
          /*
3573
           * remove bpi and do export processing
3574
           */
3575
0
          import_table->holddown_count[afi] += 1;
3576
0
          rfapiExpireVpnNow(import_table, rn, bpi,
3577
0
                0);
3578
0
        }
3579
0
      }
3580
0
    }
3581
0
  }
3582
3583
0
  if (rn)
3584
0
    RFAPI_CHECK_REFCOUNT(rn, SAFI_MPLS_VPN, replacing ? 1 : 0);
3585
3586
0
  if (action == FIF_ACTION_WITHDRAW || action == FIF_ACTION_KILL) {
3587
0
    VNC_ITRCCK;
3588
0
    return;
3589
0
  }
3590
3591
0
  info_new =
3592
0
    rfapiBgpInfoCreate(attr, peer, rfd, prd, type, sub_type, label);
3593
3594
  /*
3595
   * lookup un address in encap table
3596
   */
3597
0
  ern = agg_node_match(import_table->imported_encap[afi], &vn_prefix);
3598
0
  if (ern) {
3599
0
    rfapiCopyUnEncap2VPN(ern->info, info_new);
3600
0
    agg_unlock_node(ern); /* undo lock in route_note_match */
3601
0
  } else {
3602
    /* Not a big deal, just means VPN route got here first */
3603
0
    vnc_zlog_debug_verbose("%s: no encap route for vn addr %pFX",
3604
0
               __func__, &vn_prefix);
3605
0
    info_new->extra->vnc.import.un_family = AF_UNSPEC;
3606
0
  }
3607
3608
0
  if (rn) {
3609
0
    if (!replacing)
3610
0
      agg_lock_node(rn);
3611
0
  } else {
3612
    /*
3613
     * No need to increment reference count, so only "get"
3614
     * if the node is not there already
3615
     */
3616
0
    rn = agg_node_get(rt, p);
3617
0
  }
3618
3619
  /*
3620
   * For ethernet routes, if there is an accompanying IP address,
3621
   * save it in the bpi
3622
   */
3623
0
  if ((AFI_L2VPN == afi) && aux_prefix) {
3624
3625
0
    vnc_zlog_debug_verbose("%s: setting BPI's aux_prefix",
3626
0
               __func__);
3627
0
    info_new->extra->vnc.import.aux_prefix = *aux_prefix;
3628
0
  }
3629
3630
0
  vnc_zlog_debug_verbose("%s: inserting bpi %p at prefix %pRN #%d",
3631
0
             __func__, info_new, rn,
3632
0
             agg_node_get_lock_count(rn));
3633
3634
0
  rfapiBgpInfoAttachSorted(rn, info_new, afi, SAFI_MPLS_VPN);
3635
0
  rfapiItBiIndexAdd(rn, info_new);
3636
0
  if (!rfapiGetUnAddrOfVpnBi(info_new, NULL)) {
3637
0
    if (VALID_INTERIOR_TYPE(info_new->type))
3638
0
      RFAPI_MONITOR_EXTERIOR(rn)->valid_interior_count++;
3639
0
    SET_FLAG(info_new->flags, BGP_PATH_VALID);
3640
0
  }
3641
0
  RFAPI_UPDATE_ITABLE_COUNT(info_new, import_table, afi, 1);
3642
0
  vnc_import_bgp_exterior_add_route_interior(bgp, import_table, rn,
3643
0
               info_new);
3644
3645
0
  if (import_table == bgp->rfapi->it_ce)
3646
0
    vnc_direct_bgp_add_route_ce(bgp, rn, info_new);
3647
3648
0
  if (VNC_DEBUG(VERBOSE)) {
3649
0
    vnc_zlog_debug_verbose("%s: showing IT node", __func__);
3650
0
    rfapiShowItNode(NULL, rn); /* debug */
3651
0
  }
3652
3653
0
  rfapiMonitorEncapAdd(import_table, &vn_prefix, rn, info_new);
3654
3655
0
  if (!rfapiGetUnAddrOfVpnBi(info_new, &un_prefix)) {
3656
3657
    /*
3658
     * if we have a valid UN address (either via Encap route
3659
     * or via tunnel attribute), then we should attempt
3660
     * to move any monitors at less-specific nodes to this node
3661
     */
3662
0
    rfapiMonitorMoveLonger(rn);
3663
3664
0
    un_prefix_valid = 1;
3665
0
  }
3666
3667
  /*
3668
   * 101129 Enhancement: if we add a route (implication: it is not
3669
   * in holddown), delete all other routes from this nve at this
3670
   * node that are in holddown, regardless of peer.
3671
   *
3672
   * Reasons it's OK to do that:
3673
   *
3674
   * - if the holddown route being deleted originally came from BGP VPN,
3675
   *   it is already gone from BGP (implication of holddown), so there
3676
   *   won't be any added inconsistency with the BGP RIB.
3677
   *
3678
   * - once a fresh route is added at a prefix, any routes in holddown
3679
   *   at that prefix will not show up in RFP responses, so deleting
3680
   *   the holddown routes won't affect the contents of responses.
3681
   *
3682
   * - lifetimes are supposed to be consistent, so there should not
3683
   *   be a case where the fresh route has a shorter lifetime than
3684
   *   the holddown route, so we don't expect the fresh route to
3685
   *   disappear and complete its holddown time before the existing
3686
   *   holddown routes time out. Therefore, we won't have a situation
3687
   *   where we expect the existing holddown routes to be hidden and
3688
   *   then  to reappear sometime later (as holddown routes) in a
3689
   *   RFP response.
3690
   *
3691
   * Among other things, this would enable us to skirt the problem
3692
   * of local holddown routes that refer to NVE descriptors that
3693
   * have already been closed (if the same NVE triggers a subsequent
3694
   * rfapi_open(), the new peer is different and doesn't match the
3695
   * peer of the holddown route, so the stale holddown route still
3696
   * hangs around until it times out instead of just being replaced
3697
   * by the fresh route).
3698
   */
3699
  /*
3700
   * We know that the new bpi will have been inserted before any routes
3701
   * in holddown, so we can skip any that came before it
3702
   */
3703
0
  for (bpi = info_new->next; bpi; bpi = next) {
3704
3705
0
    struct prefix pfx_vn;
3706
0
    struct prefix pfx_un;
3707
0
    int un_match = 0;
3708
0
    int remote_peer_match = 0;
3709
3710
0
    next = bpi->next;
3711
3712
    /*
3713
     * Must be holddown
3714
     */
3715
0
    if (!CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED))
3716
0
      continue;
3717
3718
    /*
3719
     * Must match VN address (nexthop of VPN route)
3720
     */
3721
0
    if (rfapiGetNexthop(bpi->attr, &pfx_vn))
3722
0
      continue;
3723
0
    if (!prefix_same(&pfx_vn, &vn_prefix))
3724
0
      continue;
3725
3726
0
    if (un_prefix_valid && /* new route UN addr */
3727
0
        !rfapiGetUnAddrOfVpnBi(bpi, &pfx_un)
3728
0
        &&          /* old route UN addr */
3729
0
        prefix_same(&pfx_un, &un_prefix)) { /* compare */
3730
0
      un_match = 1;
3731
0
    }
3732
0
    if (!RFAPI_LOCAL_BI(bpi) && !RFAPI_LOCAL_BI(info_new)
3733
0
        && sockunion_same(&bpi->peer->su, &info_new->peer->su)) {
3734
      /* old & new are both remote, same peer */
3735
0
      remote_peer_match = 1;
3736
0
    }
3737
3738
0
    if (!un_match && !remote_peer_match)
3739
0
      continue;
3740
3741
0
    vnc_zlog_debug_verbose(
3742
0
      "%s: removing holddown bpi matching NVE of new route",
3743
0
      __func__);
3744
0
    if (bpi->extra->vnc.import.timer) {
3745
0
      struct rfapi_withdraw *wcb =
3746
0
        EVENT_ARG(bpi->extra->vnc.import.timer);
3747
3748
0
      XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
3749
0
      EVENT_OFF(bpi->extra->vnc.import.timer);
3750
0
    }
3751
0
    rfapiExpireVpnNow(import_table, rn, bpi, 0);
3752
0
  }
3753
3754
0
  if (!original_had_routes) {
3755
    /*
3756
     * We went from 0 usable routes to 1 usable route. Perform the
3757
     * "Adding a Route" export process.
3758
     */
3759
0
    vnc_direct_bgp_add_prefix(bgp, import_table, rn);
3760
0
    vnc_zebra_add_prefix(bgp, import_table, rn);
3761
0
  } else {
3762
    /*
3763
     * Check for nexthop change event
3764
     * Note: the prefix_same() test below detects two situations:
3765
     * 1. route is replaced, new route has different nexthop
3766
     * 2. new route is added (original_nexthop is 0)
3767
     */
3768
0
    struct prefix new_nexthop;
3769
3770
0
    rfapiGetNexthop(attr, &new_nexthop);
3771
0
    if (!prefix_same(&original_nexthop, &new_nexthop)) {
3772
      /*
3773
       * nexthop change event
3774
       * vnc_direct_bgp_add_prefix() will recompute VN addr
3775
       * ecommunity
3776
       */
3777
0
      vnc_direct_bgp_add_prefix(bgp, import_table, rn);
3778
0
    }
3779
0
  }
3780
3781
0
  if (!(bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_CALLBACK_DISABLE)) {
3782
0
    for (n = rn; n; n = agg_node_parent(n)) {
3783
      // rfapiDoRouteCallback(import_table, n, NULL);
3784
0
    }
3785
0
    rfapiMonitorItNodeChanged(import_table, rn, NULL);
3786
0
  }
3787
0
  RFAPI_CHECK_REFCOUNT(rn, SAFI_MPLS_VPN, 0);
3788
0
  VNC_ITRCCK;
3789
0
}
3790
3791
static void rfapiBgpInfoFilteredImportBadSafi(
3792
  struct rfapi_import_table *import_table, int action, struct peer *peer,
3793
  void *rfd, /* set for looped back routes */
3794
  const struct prefix *p,
3795
  const struct prefix *aux_prefix, /* AFI_L2VPN: optional IP */
3796
  afi_t afi, struct prefix_rd *prd,
3797
  struct attr *attr, /* part of bgp_path_info */
3798
  uint8_t type,    /* part of bgp_path_info */
3799
  uint8_t sub_type,  /* part of bgp_path_info */
3800
  uint32_t *label)   /* part of bgp_path_info */
3801
0
{
3802
0
  vnc_zlog_debug_verbose("%s: Error, bad safi", __func__);
3803
0
}
3804
3805
static rfapi_bi_filtered_import_f *
3806
rfapiBgpInfoFilteredImportFunction(safi_t safi)
3807
0
{
3808
0
  switch (safi) {
3809
0
  case SAFI_MPLS_VPN:
3810
0
    return rfapiBgpInfoFilteredImportVPN;
3811
3812
0
  case SAFI_ENCAP:
3813
0
    return rfapiBgpInfoFilteredImportEncap;
3814
3815
0
  case SAFI_UNSPEC:
3816
0
  case SAFI_UNICAST:
3817
0
  case SAFI_MULTICAST:
3818
0
  case SAFI_EVPN:
3819
0
  case SAFI_LABELED_UNICAST:
3820
0
  case SAFI_FLOWSPEC:
3821
0
  case SAFI_MAX:
3822
    /* not expected */
3823
0
    flog_err(EC_LIB_DEVELOPMENT, "%s: bad safi %d", __func__, safi);
3824
0
    return rfapiBgpInfoFilteredImportBadSafi;
3825
0
  }
3826
3827
0
  assert(!"Reached end of function when we were not expecting to");
3828
0
}
3829
3830
void rfapiProcessUpdate(struct peer *peer,
3831
      void *rfd, /* set when looped from RFP/RFAPI */
3832
      const struct prefix *p, struct prefix_rd *prd,
3833
      struct attr *attr, afi_t afi, safi_t safi, uint8_t type,
3834
      uint8_t sub_type, uint32_t *label)
3835
0
{
3836
0
  struct bgp *bgp;
3837
0
  struct rfapi *h;
3838
0
  struct rfapi_import_table *it;
3839
0
  int has_ip_route = 1;
3840
0
  uint32_t lni = 0;
3841
3842
0
  bgp = bgp_get_default(); /* assume 1 instance for now */
3843
0
  assert(bgp);
3844
3845
0
  h = bgp->rfapi;
3846
0
  assert(h);
3847
3848
  /*
3849
   * look at high-order byte of RD. FF means MAC
3850
   * address is present (VNC L2VPN)
3851
   */
3852
0
  if ((safi == SAFI_MPLS_VPN)
3853
0
      && (decode_rd_type(prd->val) == RD_TYPE_VNC_ETH)) {
3854
0
    struct prefix pfx_mac_buf;
3855
0
    struct prefix pfx_nexthop_buf;
3856
0
    int rc;
3857
3858
    /*
3859
     * Set flag if prefix and nexthop are the same - don't
3860
     * add the route to normal IP-based import tables
3861
     */
3862
0
    if (!rfapiGetNexthop(attr, &pfx_nexthop_buf)) {
3863
0
      if (!prefix_cmp(&pfx_nexthop_buf, p)) {
3864
0
        has_ip_route = 0;
3865
0
      }
3866
0
    }
3867
3868
0
    memset(&pfx_mac_buf, 0, sizeof(pfx_mac_buf));
3869
0
    pfx_mac_buf.family = AF_ETHERNET;
3870
0
    pfx_mac_buf.prefixlen = 48;
3871
0
    memcpy(&pfx_mac_buf.u.prefix_eth.octet, prd->val + 2, 6);
3872
3873
    /*
3874
     * Find rt containing LNI (Logical Network ID), which
3875
     * _should_ always be present when mac address is present
3876
     */
3877
0
    rc = rfapiEcommunityGetLNI(bgp_attr_get_ecommunity(attr), &lni);
3878
3879
0
    vnc_zlog_debug_verbose(
3880
0
      "%s: rfapiEcommunityGetLNI returned %d, lni=%d, attr=%p",
3881
0
      __func__, rc, lni, attr);
3882
0
    if (!rc) {
3883
0
      it = rfapiMacImportTableGet(bgp, lni);
3884
3885
0
      rfapiBgpInfoFilteredImportVPN(
3886
0
        it, FIF_ACTION_UPDATE, peer, rfd,
3887
0
        &pfx_mac_buf, /* prefix */
3888
0
        p,      /* aux prefix: IP addr */
3889
0
        AFI_L2VPN, prd, attr, type, sub_type, label);
3890
0
    }
3891
0
  }
3892
3893
0
  if (!has_ip_route)
3894
0
    return;
3895
3896
  /*
3897
   * Iterate over all import tables; do a filtered import
3898
   * for the afi/safi combination
3899
   */
3900
0
  for (it = h->imports; it; it = it->next) {
3901
0
    (*rfapiBgpInfoFilteredImportFunction(safi))(
3902
0
      it, FIF_ACTION_UPDATE, peer, rfd, p, /* prefix */
3903
0
      NULL, afi, prd, attr, type, sub_type, label);
3904
0
  }
3905
3906
0
  if (safi == SAFI_MPLS_VPN) {
3907
0
    vnc_direct_bgp_rh_add_route(bgp, afi, p, peer, attr);
3908
0
    rfapiBgpInfoFilteredImportVPN(
3909
0
      bgp->rfapi->it_ce, FIF_ACTION_UPDATE, peer, rfd,
3910
0
      p, /* prefix */
3911
0
      NULL, afi, prd, attr, type, sub_type, label);
3912
0
  }
3913
0
}
3914
3915
3916
void rfapiProcessWithdraw(struct peer *peer, void *rfd, const struct prefix *p,
3917
        struct prefix_rd *prd, struct attr *attr, afi_t afi,
3918
        safi_t safi, uint8_t type, int kill)
3919
0
{
3920
0
  struct bgp *bgp;
3921
0
  struct rfapi *h;
3922
0
  struct rfapi_import_table *it;
3923
3924
0
  bgp = bgp_get_default(); /* assume 1 instance for now */
3925
0
  assert(bgp);
3926
3927
0
  h = bgp->rfapi;
3928
0
  assert(h);
3929
3930
  /*
3931
   * look at high-order byte of RD. FF means MAC
3932
   * address is present (VNC L2VPN)
3933
   */
3934
0
  if (h->import_mac != NULL && safi == SAFI_MPLS_VPN
3935
0
      && decode_rd_type(prd->val) == RD_TYPE_VNC_ETH) {
3936
0
    struct prefix pfx_mac_buf;
3937
0
    void *cursor = NULL;
3938
0
    int rc;
3939
3940
0
    memset(&pfx_mac_buf, 0, sizeof(pfx_mac_buf));
3941
0
    pfx_mac_buf.family = AF_ETHERNET;
3942
0
    pfx_mac_buf.prefixlen = 48;
3943
0
    memcpy(&pfx_mac_buf.u.prefix_eth, prd->val + 2, 6);
3944
3945
    /*
3946
     * withdraw does not contain attrs, so we don't have
3947
     * access to the route's LNI, which would ordinarily
3948
     * select the specific mac-based import table. Instead,
3949
     * we must iterate over all mac-based tables and rely
3950
     * on the RD to match.
3951
     *
3952
     * If this approach is too slow, add an index where
3953
     * key is {RD, peer} and value is the import table
3954
     */
3955
0
    for (rc = skiplist_next(h->import_mac, NULL, (void **)&it,
3956
0
          &cursor);
3957
0
         rc == 0; rc = skiplist_next(h->import_mac, NULL,
3958
0
             (void **)&it, &cursor)) {
3959
3960
#ifdef DEBUG_L2_EXTRA
3961
      vnc_zlog_debug_verbose(
3962
        "%s: calling rfapiBgpInfoFilteredImportVPN(it=%p, afi=AFI_L2VPN)",
3963
        __func__, it);
3964
#endif
3965
3966
0
      rfapiBgpInfoFilteredImportVPN(
3967
0
        it,
3968
0
        (kill ? FIF_ACTION_KILL : FIF_ACTION_WITHDRAW),
3969
0
        peer, rfd, &pfx_mac_buf, /* prefix */
3970
0
        p,       /* aux_prefix: IP */
3971
0
        AFI_L2VPN, prd, attr, type, 0,
3972
0
        NULL); /* sub_type & label unused for withdraw
3973
            */
3974
0
    }
3975
0
  }
3976
3977
  /*
3978
   * XXX For the case where the withdraw involves an L2
3979
   * route with no IP information, we rely on the lack
3980
   * of RT-list intersection to filter out the withdraw
3981
   * from the IP-based import tables below
3982
   */
3983
3984
  /*
3985
   * Iterate over all import tables; do a filtered import
3986
   * for the afi/safi combination
3987
   */
3988
3989
0
  for (it = h->imports; it; it = it->next) {
3990
0
    (*rfapiBgpInfoFilteredImportFunction(safi))(
3991
0
      it, (kill ? FIF_ACTION_KILL : FIF_ACTION_WITHDRAW),
3992
0
      peer, rfd, p, /* prefix */
3993
0
      NULL, afi, prd, attr, type, 0,
3994
0
      NULL); /* sub_type & label unused for withdraw */
3995
0
  }
3996
3997
  /* TBD the deletion should happen after the lifetime expires */
3998
0
  if (safi == SAFI_MPLS_VPN)
3999
0
    vnc_direct_bgp_rh_del_route(bgp, afi, p, peer);
4000
4001
0
  if (safi == SAFI_MPLS_VPN) {
4002
0
    rfapiBgpInfoFilteredImportVPN(
4003
0
      bgp->rfapi->it_ce,
4004
0
      (kill ? FIF_ACTION_KILL : FIF_ACTION_WITHDRAW), peer,
4005
0
      rfd, p, /* prefix */
4006
0
      NULL, afi, prd, attr, type, 0,
4007
0
      NULL); /* sub_type & label unused for withdraw */
4008
0
  }
4009
0
}
4010
4011
/*
4012
 * TBD optimized withdraw timer algorithm for case of many
4013
 * routes expiring at the same time due to peer drop.
4014
 */
4015
/*
4016
 * 1. Visit all BPIs in all ENCAP import tables.
4017
 *
4018
 *    a. If a bpi's peer is the failed peer, remove the bpi.
4019
 *    b. If the removed ENCAP bpi was first in the list of
4020
 *       BPIs at this ENCAP node, loop over all monitors
4021
 *       at this node:
4022
 *
4023
 *       (1) for each ENCAP monitor, loop over all its
4024
 *           VPN node monitors and set their RFAPI_MON_FLAG_NEEDCALLBACK
4025
 *           flags.
4026
 *
4027
 * 2. Visit all BPIs in all VPN import tables.
4028
 *    a. If a bpi's peer is the failed peer, remove the bpi.
4029
 *    b. loop over all the VPN node monitors and set their
4030
 *       RFAPI_MON_FLAG_NEEDCALLBACK flags
4031
 *    c. If there are no BPIs left at this VPN node,
4032
 *
4033
 */
4034
4035
4036
/* surprise, this gets called from peer_delete(), from rfapi_close() */
4037
static void rfapiProcessPeerDownRt(struct peer *peer,
4038
           struct rfapi_import_table *import_table,
4039
           afi_t afi, safi_t safi)
4040
0
{
4041
0
  struct agg_node *rn;
4042
0
  struct bgp_path_info *bpi;
4043
0
  struct agg_table *rt = NULL;
4044
0
  void (*timer_service_func)(struct event *) = NULL;
4045
4046
0
  assert(afi == AFI_IP || afi == AFI_IP6);
4047
4048
0
  VNC_ITRCCK;
4049
4050
0
  switch (safi) {
4051
0
  case SAFI_MPLS_VPN:
4052
0
    rt = import_table->imported_vpn[afi];
4053
0
    timer_service_func = rfapiWithdrawTimerVPN;
4054
0
    break;
4055
0
  case SAFI_ENCAP:
4056
0
    rt = import_table->imported_encap[afi];
4057
0
    timer_service_func = rfapiWithdrawTimerEncap;
4058
0
    break;
4059
0
  case SAFI_UNSPEC:
4060
0
  case SAFI_UNICAST:
4061
0
  case SAFI_MULTICAST:
4062
0
  case SAFI_EVPN:
4063
0
  case SAFI_LABELED_UNICAST:
4064
0
  case SAFI_FLOWSPEC:
4065
0
  case SAFI_MAX:
4066
    /* Suppress uninitialized variable warning */
4067
0
    rt = NULL;
4068
0
    timer_service_func = NULL;
4069
0
    assert(0);
4070
0
  }
4071
4072
0
  for (rn = agg_route_top(rt); rn; rn = agg_route_next(rn)) {
4073
0
    for (bpi = rn->info; bpi; bpi = bpi->next) {
4074
0
      if (bpi->peer == peer) {
4075
4076
0
        if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) {
4077
          /* already in holddown, skip */
4078
0
          continue;
4079
0
        }
4080
4081
0
        if (safi == SAFI_MPLS_VPN) {
4082
0
          RFAPI_UPDATE_ITABLE_COUNT(
4083
0
            bpi, import_table, afi, -1);
4084
0
          import_table->holddown_count[afi] += 1;
4085
0
        }
4086
0
        rfapiBiStartWithdrawTimer(import_table, rn, bpi,
4087
0
                afi, safi,
4088
0
                timer_service_func);
4089
0
      }
4090
0
    }
4091
0
  }
4092
0
  VNC_ITRCCK;
4093
0
}
4094
4095
/*
4096
 * This gets called when a peer connection drops. We have to remove
4097
 * all the routes from this peer.
4098
 *
4099
 * Current approach is crude. TBD Optimize by setting fewer timers and
4100
 * grouping withdrawn routes so we can generate callbacks more
4101
 * efficiently.
4102
 */
4103
void rfapiProcessPeerDown(struct peer *peer)
4104
0
{
4105
0
  struct bgp *bgp;
4106
0
  struct rfapi *h;
4107
0
  struct rfapi_import_table *it;
4108
4109
  /*
4110
   * If this peer is a "dummy" peer structure atached to a RFAPI
4111
   * nve_descriptor, we don't need to walk the import tables
4112
   * because the routes are already withdrawn by rfapi_close()
4113
   */
4114
0
  if (CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD))
4115
0
    return;
4116
4117
  /*
4118
   * 1. Visit all BPIs in all ENCAP import tables.
4119
   *    Start withdraw timer on the BPIs that match peer.
4120
   *
4121
   * 2. Visit All BPIs in all VPN import tables.
4122
   *    Start withdraw timer on the BPIs that match peer.
4123
   */
4124
4125
0
  bgp = bgp_get_default(); /* assume 1 instance for now */
4126
0
  if (!bgp)
4127
0
    return;
4128
4129
0
  h = bgp->rfapi;
4130
0
  assert(h);
4131
4132
0
  for (it = h->imports; it; it = it->next) {
4133
0
    rfapiProcessPeerDownRt(peer, it, AFI_IP, SAFI_ENCAP);
4134
0
    rfapiProcessPeerDownRt(peer, it, AFI_IP6, SAFI_ENCAP);
4135
0
    rfapiProcessPeerDownRt(peer, it, AFI_IP, SAFI_MPLS_VPN);
4136
0
    rfapiProcessPeerDownRt(peer, it, AFI_IP6, SAFI_MPLS_VPN);
4137
0
  }
4138
4139
0
  if (h->it_ce) {
4140
0
    rfapiProcessPeerDownRt(peer, h->it_ce, AFI_IP, SAFI_MPLS_VPN);
4141
0
    rfapiProcessPeerDownRt(peer, h->it_ce, AFI_IP6, SAFI_MPLS_VPN);
4142
0
  }
4143
0
}
4144
4145
/*
4146
 * Import an entire RIB (for an afi/safi) to an import table RIB,
4147
 * filtered according to the import table's RT list
4148
 *
4149
 * TBD: does this function need additions to match rfapiProcessUpdate()
4150
 * for, e.g., L2 handling?
4151
 */
4152
static void rfapiBgpTableFilteredImport(struct bgp *bgp,
4153
          struct rfapi_import_table *it,
4154
          afi_t afi, safi_t safi)
4155
0
{
4156
0
  struct bgp_dest *dest1;
4157
0
  struct bgp_dest *dest2;
4158
4159
  /* Only these SAFIs have 2-level RIBS */
4160
0
  assert(safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP);
4161
4162
  /*
4163
   * Now visit all the rd nodes and the nodes of all the
4164
   * route tables attached to them, and import the routes
4165
   * if they have matching route targets
4166
   */
4167
0
  for (dest1 = bgp_table_top(bgp->rib[afi][safi]); dest1;
4168
0
       dest1 = bgp_route_next(dest1)) {
4169
4170
0
    if (bgp_dest_has_bgp_path_info_data(dest1)) {
4171
4172
0
      for (dest2 = bgp_table_top(
4173
0
             bgp_dest_get_bgp_table_info(dest1));
4174
0
           dest2; dest2 = bgp_route_next(dest2)) {
4175
4176
0
        struct bgp_path_info *bpi;
4177
4178
0
        for (bpi = bgp_dest_get_bgp_path_info(dest2);
4179
0
             bpi; bpi = bpi->next) {
4180
0
          uint32_t label = 0;
4181
4182
0
          if (CHECK_FLAG(bpi->flags,
4183
0
                   BGP_PATH_REMOVED))
4184
0
            continue;
4185
4186
0
          if (bpi->extra)
4187
0
            label = decode_label(
4188
0
              &bpi->extra->label[0]);
4189
0
          (*rfapiBgpInfoFilteredImportFunction(
4190
0
            safi))(
4191
0
            it, /* which import table */
4192
0
            FIF_ACTION_UPDATE, bpi->peer,
4193
0
            NULL,
4194
0
            bgp_dest_get_prefix(dest2),
4195
0
            NULL, afi,
4196
0
            (struct prefix_rd *)
4197
0
              bgp_dest_get_prefix(
4198
0
                dest1),
4199
0
            bpi->attr, bpi->type,
4200
0
            bpi->sub_type, &label);
4201
0
        }
4202
0
      }
4203
0
    }
4204
0
  }
4205
0
}
4206
4207
4208
/* per-bgp-instance rfapi data */
4209
struct rfapi *bgp_rfapi_new(struct bgp *bgp)
4210
0
{
4211
0
  struct rfapi *h;
4212
0
  afi_t afi;
4213
0
  struct rfapi_rfp_cfg *cfg = NULL;
4214
0
  struct rfapi_rfp_cb_methods *cbm = NULL;
4215
4216
0
  assert(bgp->rfapi_cfg == NULL);
4217
4218
0
  h = XCALLOC(MTYPE_RFAPI, sizeof(struct rfapi));
4219
4220
0
  for (afi = AFI_IP; afi < AFI_MAX; afi++) {
4221
0
    h->un[afi] = agg_table_init();
4222
0
  }
4223
4224
  /*
4225
   * initialize the ce import table
4226
   */
4227
0
  h->it_ce = XCALLOC(MTYPE_RFAPI_IMPORTTABLE,
4228
0
         sizeof(struct rfapi_import_table));
4229
0
  h->it_ce->imported_vpn[AFI_IP] = agg_table_init();
4230
0
  h->it_ce->imported_vpn[AFI_IP6] = agg_table_init();
4231
0
  h->it_ce->imported_encap[AFI_IP] = agg_table_init();
4232
0
  h->it_ce->imported_encap[AFI_IP6] = agg_table_init();
4233
0
  rfapiBgpTableFilteredImport(bgp, h->it_ce, AFI_IP, SAFI_MPLS_VPN);
4234
0
  rfapiBgpTableFilteredImport(bgp, h->it_ce, AFI_IP6, SAFI_MPLS_VPN);
4235
4236
  /*
4237
   * Set up work queue for deferred rfapi_close operations
4238
   */
4239
0
  h->deferred_close_q =
4240
0
    work_queue_new(bm->master, "rfapi deferred close");
4241
0
  h->deferred_close_q->spec.workfunc = rfapi_deferred_close_workfunc;
4242
0
  h->deferred_close_q->spec.data = h;
4243
4244
0
  h->rfp = rfp_start(bm->master, &cfg, &cbm);
4245
0
  bgp->rfapi_cfg = bgp_rfapi_cfg_new(cfg);
4246
0
  if (cbm != NULL) {
4247
0
    h->rfp_methods = *cbm;
4248
0
  }
4249
0
  return h;
4250
0
}
4251
4252
void bgp_rfapi_destroy(struct bgp *bgp, struct rfapi *h)
4253
0
{
4254
0
  afi_t afi;
4255
4256
0
  if (bgp == NULL || h == NULL)
4257
0
    return;
4258
4259
0
  if (h->resolve_nve_nexthop) {
4260
0
    skiplist_free(h->resolve_nve_nexthop);
4261
0
    h->resolve_nve_nexthop = NULL;
4262
0
  }
4263
4264
0
  rfapiImportTableFlush(h->it_ce);
4265
4266
0
  if (h->import_mac) {
4267
0
    struct rfapi_import_table *it;
4268
0
    void *cursor;
4269
0
    int rc;
4270
4271
0
    for (cursor = NULL,
4272
0
        rc = skiplist_next(h->import_mac, NULL, (void **)&it,
4273
0
               &cursor);
4274
0
         !rc; rc = skiplist_next(h->import_mac, NULL, (void **)&it,
4275
0
               &cursor)) {
4276
4277
0
      rfapiImportTableFlush(it);
4278
0
      XFREE(MTYPE_RFAPI_IMPORTTABLE, it);
4279
0
    }
4280
0
    skiplist_free(h->import_mac);
4281
0
    h->import_mac = NULL;
4282
0
  }
4283
4284
0
  work_queue_free_and_null(&h->deferred_close_q);
4285
4286
0
  if (h->rfp != NULL)
4287
0
    rfp_stop(h->rfp);
4288
4289
0
  for (afi = AFI_IP; afi < AFI_MAX; afi++) {
4290
0
    agg_table_finish(h->un[afi]);
4291
0
  }
4292
4293
0
  XFREE(MTYPE_RFAPI_IMPORTTABLE, h->it_ce);
4294
0
  XFREE(MTYPE_RFAPI, h);
4295
0
}
4296
4297
struct rfapi_import_table *
4298
rfapiImportTableRefAdd(struct bgp *bgp, struct ecommunity *rt_import_list,
4299
           struct rfapi_nve_group_cfg *rfg)
4300
0
{
4301
0
  struct rfapi *h;
4302
0
  struct rfapi_import_table *it;
4303
0
  afi_t afi;
4304
4305
0
  h = bgp->rfapi;
4306
0
  assert(h);
4307
4308
0
  for (it = h->imports; it; it = it->next) {
4309
0
    if (ecommunity_cmp(it->rt_import_list, rt_import_list))
4310
0
      break;
4311
0
  }
4312
4313
0
  vnc_zlog_debug_verbose("%s: matched it=%p", __func__, it);
4314
4315
0
  if (!it) {
4316
0
    it = XCALLOC(MTYPE_RFAPI_IMPORTTABLE,
4317
0
           sizeof(struct rfapi_import_table));
4318
0
    it->next = h->imports;
4319
0
    h->imports = it;
4320
4321
0
    it->rt_import_list = ecommunity_dup(rt_import_list);
4322
0
    it->rfg = rfg;
4323
0
    it->monitor_exterior_orphans =
4324
0
      skiplist_new(0, NULL, prefix_free_lists);
4325
4326
    /*
4327
     * fill import route tables from RIBs
4328
     *
4329
     * Potential area for optimization. If this occurs when
4330
     * tables are large (e.g., the operator adds a nve group
4331
     * with a new RT list to a running system), it could take
4332
     * a while.
4333
     *
4334
     */
4335
0
    for (afi = AFI_IP; afi < AFI_MAX; ++afi) {
4336
4337
0
      it->imported_vpn[afi] = agg_table_init();
4338
0
      it->imported_encap[afi] = agg_table_init();
4339
4340
0
      rfapiBgpTableFilteredImport(bgp, it, afi,
4341
0
                SAFI_MPLS_VPN);
4342
0
      rfapiBgpTableFilteredImport(bgp, it, afi, SAFI_ENCAP);
4343
4344
0
      vnc_import_bgp_exterior_redist_enable_it(bgp, afi, it);
4345
0
    }
4346
0
  }
4347
4348
0
  it->refcount += 1;
4349
4350
0
  return it;
4351
0
}
4352
4353
/*
4354
 * skiplist element free function
4355
 */
4356
static void delete_rem_pfx_na_free(void *na)
4357
0
{
4358
0
  uint32_t *pCounter = ((struct rfapi_nve_addr *)na)->info;
4359
4360
0
  *pCounter += 1;
4361
0
  XFREE(MTYPE_RFAPI_NVE_ADDR, na);
4362
0
}
4363
4364
/*
4365
 * Common deleter for IP and MAC import tables
4366
 */
4367
static void rfapiDeleteRemotePrefixesIt(
4368
  struct bgp *bgp, struct rfapi_import_table *it, struct prefix *un,
4369
  struct prefix *vn, struct prefix *p, int delete_active,
4370
  int delete_holddown, uint32_t *pARcount, uint32_t *pAHcount,
4371
  uint32_t *pHRcount, uint32_t *pHHcount,
4372
  struct skiplist *uniq_active_nves, struct skiplist *uniq_holddown_nves)
4373
0
{
4374
0
  afi_t afi;
4375
4376
#ifdef DEBUG_L2_EXTRA
4377
  {
4378
    char buf_pfx[PREFIX_STRLEN];
4379
4380
    if (p) {
4381
      prefix2str(p, buf_pfx, sizeof(buf_pfx));
4382
    } else {
4383
      buf_pfx[0] = '*';
4384
      buf_pfx[1] = 0;
4385
    }
4386
4387
    vnc_zlog_debug_verbose(
4388
      "%s: entry, p=%s, delete_active=%d, delete_holddown=%d",
4389
      __func__, buf_pfx, delete_active, delete_holddown);
4390
  }
4391
#endif
4392
4393
0
  for (afi = AFI_IP; afi < AFI_MAX; ++afi) {
4394
4395
0
    struct agg_table *rt;
4396
0
    struct agg_node *rn;
4397
4398
0
    if (p && (family2afi(p->family) != afi)) {
4399
0
      continue;
4400
0
    }
4401
4402
0
    rt = it->imported_vpn[afi];
4403
0
    if (!rt)
4404
0
      continue;
4405
4406
0
    vnc_zlog_debug_verbose("%s: scanning rt for afi=%d", __func__,
4407
0
               afi);
4408
4409
0
    for (rn = agg_route_top(rt); rn; rn = agg_route_next(rn)) {
4410
0
      struct bgp_path_info *bpi;
4411
0
      struct bgp_path_info *next;
4412
0
      const struct prefix *rn_p = agg_node_get_prefix(rn);
4413
4414
0
      if (p && VNC_DEBUG(IMPORT_DEL_REMOTE))
4415
0
        vnc_zlog_debug_any("%s: want %pFX, have %pRN",
4416
0
               __func__, p, rn);
4417
4418
0
      if (p && prefix_cmp(p, rn_p))
4419
0
        continue;
4420
4421
0
      vnc_zlog_debug_verbose("%s: rn pfx=%pRN", __func__, rn);
4422
4423
      /* TBD is this valid for afi == AFI_L2VPN? */
4424
0
      RFAPI_CHECK_REFCOUNT(rn, SAFI_MPLS_VPN, 1);
4425
4426
0
      for (bpi = rn->info; bpi; bpi = next) {
4427
0
        next = bpi->next;
4428
4429
0
        struct prefix qpt;
4430
0
        struct prefix qct;
4431
0
        int qpt_valid = 0;
4432
0
        int qct_valid = 0;
4433
0
        int is_active = 0;
4434
4435
0
        vnc_zlog_debug_verbose("%s: examining bpi %p",
4436
0
                   __func__, bpi);
4437
4438
0
        if (!rfapiGetNexthop(bpi->attr, &qpt))
4439
0
          qpt_valid = 1;
4440
4441
0
        if (vn) {
4442
0
          if (!qpt_valid
4443
0
              || !prefix_match(vn, &qpt)) {
4444
#ifdef DEBUG_L2_EXTRA
4445
            vnc_zlog_debug_verbose(
4446
              "%s: continue at vn && !qpt_valid || !prefix_match(vn, &qpt)",
4447
              __func__);
4448
#endif
4449
0
            continue;
4450
0
          }
4451
0
        }
4452
4453
0
        if (!rfapiGetUnAddrOfVpnBi(bpi, &qct))
4454
0
          qct_valid = 1;
4455
4456
0
        if (un) {
4457
0
          if (!qct_valid
4458
0
              || !prefix_match(un, &qct)) {
4459
#ifdef DEBUG_L2_EXTRA
4460
            vnc_zlog_debug_verbose(
4461
              "%s: continue at un && !qct_valid || !prefix_match(un, &qct)",
4462
              __func__);
4463
#endif
4464
0
            continue;
4465
0
          }
4466
0
        }
4467
4468
4469
        /*
4470
         * Blow bpi away
4471
         */
4472
        /*
4473
         * If this route is waiting to be deleted
4474
         * because of
4475
         * a previous withdraw, we must cancel its
4476
         * timer.
4477
         */
4478
0
        if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) {
4479
0
          if (!delete_holddown)
4480
0
            continue;
4481
0
          if (bpi->extra->vnc.import.timer) {
4482
0
            struct rfapi_withdraw *wcb =
4483
0
              EVENT_ARG(
4484
0
                bpi->extra->vnc
4485
0
                  .import
4486
0
                  .timer);
4487
4488
0
            wcb->import_table
4489
0
              ->holddown_count[afi] -=
4490
0
              1;
4491
0
            RFAPI_UPDATE_ITABLE_COUNT(
4492
0
              bpi, wcb->import_table,
4493
0
              afi, 1);
4494
0
            XFREE(MTYPE_RFAPI_WITHDRAW,
4495
0
                  wcb);
4496
0
            EVENT_OFF(bpi->extra->vnc.import
4497
0
                  .timer);
4498
0
          }
4499
0
        } else {
4500
0
          if (!delete_active)
4501
0
            continue;
4502
0
          is_active = 1;
4503
0
        }
4504
4505
0
        vnc_zlog_debug_verbose(
4506
0
          "%s: deleting bpi %p (qct_valid=%d, qpt_valid=%d, delete_holddown=%d, delete_active=%d)",
4507
0
          __func__, bpi, qct_valid, qpt_valid,
4508
0
          delete_holddown, delete_active);
4509
4510
4511
        /*
4512
         * add nve to list
4513
         */
4514
0
        if (qct_valid && qpt_valid) {
4515
4516
0
          struct rfapi_nve_addr na;
4517
0
          struct rfapi_nve_addr *nap;
4518
4519
0
          memset(&na, 0, sizeof(na));
4520
0
          assert(!rfapiQprefix2Raddr(&qct,
4521
0
                   &na.un));
4522
0
          assert(!rfapiQprefix2Raddr(&qpt,
4523
0
                   &na.vn));
4524
4525
0
          if (skiplist_search(
4526
0
                (is_active
4527
0
                   ? uniq_active_nves
4528
0
                   : uniq_holddown_nves),
4529
0
                &na, (void **)&nap)) {
4530
0
            char line[BUFSIZ];
4531
4532
0
            nap = XCALLOC(
4533
0
              MTYPE_RFAPI_NVE_ADDR,
4534
0
              sizeof(struct
4535
0
                     rfapi_nve_addr));
4536
0
            *nap = na;
4537
0
            nap->info = is_active
4538
0
                    ? pAHcount
4539
0
                    : pHHcount;
4540
0
            skiplist_insert(
4541
0
              (is_active
4542
0
                 ? uniq_active_nves
4543
0
                 : uniq_holddown_nves),
4544
0
              nap, nap);
4545
4546
0
            rfapiNveAddr2Str(nap, line,
4547
0
                 BUFSIZ);
4548
0
          }
4549
0
        }
4550
4551
0
        vnc_direct_bgp_rh_del_route(bgp, afi, rn_p,
4552
0
                  bpi->peer);
4553
4554
0
        RFAPI_UPDATE_ITABLE_COUNT(bpi, it, afi, -1);
4555
0
        it->holddown_count[afi] += 1;
4556
0
        rfapiExpireVpnNow(it, rn, bpi, 1);
4557
4558
0
        vnc_zlog_debug_verbose(
4559
0
          "%s: incrementing count (is_active=%d)",
4560
0
          __func__, is_active);
4561
4562
0
        if (is_active)
4563
0
          ++*pARcount;
4564
0
        else
4565
0
          ++*pHRcount;
4566
0
      }
4567
0
    }
4568
0
  }
4569
0
}
4570
4571
4572
/*
4573
 * For use by the "clear vnc prefixes" command
4574
 */
4575
/*------------------------------------------
4576
 * rfapiDeleteRemotePrefixes
4577
 *
4578
 * UI helper: For use by the "clear vnc prefixes" command
4579
 *
4580
 * input:
4581
 *  un      if set, tunnel must match this prefix
4582
 *  vn      if set, nexthop prefix must match this prefix
4583
 *  p     if set, prefix must match this prefix
4584
 *      it                      if set, only look in this import table
4585
 *
4586
 * output
4587
 *  pARcount    number of active routes deleted
4588
 *  pAHcount    number of active nves deleted
4589
 *  pHRcount    number of holddown routes deleted
4590
 *  pHHcount    number of holddown nves deleted
4591
 *
4592
 * return value:
4593
 *  void
4594
 --------------------------------------------*/
4595
void rfapiDeleteRemotePrefixes(struct prefix *un, struct prefix *vn,
4596
             struct prefix *p,
4597
             struct rfapi_import_table *arg_it,
4598
             int delete_active, int delete_holddown,
4599
             uint32_t *pARcount, uint32_t *pAHcount,
4600
             uint32_t *pHRcount, uint32_t *pHHcount)
4601
0
{
4602
0
  struct bgp *bgp;
4603
0
  struct rfapi *h;
4604
0
  struct rfapi_import_table *it;
4605
0
  uint32_t deleted_holddown_route_count = 0;
4606
0
  uint32_t deleted_active_route_count = 0;
4607
0
  uint32_t deleted_holddown_nve_count = 0;
4608
0
  uint32_t deleted_active_nve_count = 0;
4609
0
  struct skiplist *uniq_holddown_nves;
4610
0
  struct skiplist *uniq_active_nves;
4611
4612
0
  VNC_ITRCCK;
4613
4614
0
  bgp = bgp_get_default(); /* assume 1 instance for now */
4615
  /* If no bgp instantiated yet, no vnc prefixes exist */
4616
0
  if (!bgp)
4617
0
    return;
4618
4619
0
  h = bgp->rfapi;
4620
0
  assert(h);
4621
4622
0
  uniq_holddown_nves =
4623
0
    skiplist_new(0, rfapi_nve_addr_cmp, delete_rem_pfx_na_free);
4624
0
  uniq_active_nves =
4625
0
    skiplist_new(0, rfapi_nve_addr_cmp, delete_rem_pfx_na_free);
4626
4627
  /*
4628
   * Iterate over all import tables; do a filtered import
4629
   * for the afi/safi combination
4630
   */
4631
4632
0
  if (arg_it)
4633
0
    it = arg_it;
4634
0
  else
4635
0
    it = h->imports;
4636
0
  for (; it;) {
4637
4638
0
    vnc_zlog_debug_verbose(
4639
0
      "%s: calling rfapiDeleteRemotePrefixesIt() on (IP) import %p",
4640
0
      __func__, it);
4641
4642
0
    rfapiDeleteRemotePrefixesIt(
4643
0
      bgp, it, un, vn, p, delete_active, delete_holddown,
4644
0
      &deleted_active_route_count, &deleted_active_nve_count,
4645
0
      &deleted_holddown_route_count,
4646
0
      &deleted_holddown_nve_count, uniq_active_nves,
4647
0
      uniq_holddown_nves);
4648
4649
0
    if (arg_it)
4650
0
      it = NULL;
4651
0
    else
4652
0
      it = it->next;
4653
0
  }
4654
4655
  /*
4656
   * Now iterate over L2 import tables
4657
   */
4658
0
  if (h->import_mac && !(p && (p->family != AF_ETHERNET))) {
4659
4660
0
    void *cursor = NULL;
4661
0
    int rc;
4662
4663
0
    for (cursor = NULL,
4664
0
        rc = skiplist_next(h->import_mac, NULL, (void **)&it,
4665
0
               &cursor);
4666
0
         !rc; rc = skiplist_next(h->import_mac, NULL, (void **)&it,
4667
0
               &cursor)) {
4668
4669
0
      vnc_zlog_debug_verbose(
4670
0
        "%s: calling rfapiDeleteRemotePrefixesIt() on import_mac %p",
4671
0
        __func__, it);
4672
4673
0
      rfapiDeleteRemotePrefixesIt(
4674
0
        bgp, it, un, vn, p, delete_active,
4675
0
        delete_holddown, &deleted_active_route_count,
4676
0
        &deleted_active_nve_count,
4677
0
        &deleted_holddown_route_count,
4678
0
        &deleted_holddown_nve_count, uniq_active_nves,
4679
0
        uniq_holddown_nves);
4680
0
    }
4681
0
  }
4682
4683
  /*
4684
   * our custom element freeing function above counts as it deletes
4685
   */
4686
0
  skiplist_free(uniq_holddown_nves);
4687
0
  skiplist_free(uniq_active_nves);
4688
4689
0
  if (pARcount)
4690
0
    *pARcount = deleted_active_route_count;
4691
0
  if (pAHcount)
4692
0
    *pAHcount = deleted_active_nve_count;
4693
0
  if (pHRcount)
4694
0
    *pHRcount = deleted_holddown_route_count;
4695
0
  if (pHHcount)
4696
0
    *pHHcount = deleted_holddown_nve_count;
4697
4698
0
  VNC_ITRCCK;
4699
0
}
4700
4701
/*------------------------------------------
4702
 * rfapiCountRemoteRoutes
4703
 *
4704
 * UI helper: count VRF routes from BGP side
4705
 *
4706
 * input:
4707
 *
4708
 * output
4709
 *  pALRcount   count of active local routes
4710
 *  pARRcount   count of active remote routes
4711
 *  pHRcount    count of holddown routes
4712
 *  pIRcount    count of direct imported routes
4713
 *
4714
 * return value:
4715
 *  void
4716
 --------------------------------------------*/
4717
void rfapiCountAllItRoutes(int *pALRcount, /* active local routes */
4718
         int *pARRcount, /* active remote routes */
4719
         int *pHRcount,  /* holddown routes */
4720
         int *pIRcount)  /* imported routes */
4721
0
{
4722
0
  struct bgp *bgp;
4723
0
  struct rfapi *h;
4724
0
  struct rfapi_import_table *it;
4725
0
  afi_t afi;
4726
4727
0
  int total_active_local = 0;
4728
0
  int total_active_remote = 0;
4729
0
  int total_holddown = 0;
4730
0
  int total_imported = 0;
4731
4732
0
  bgp = bgp_get_default(); /* assume 1 instance for now */
4733
0
  assert(bgp);
4734
4735
0
  h = bgp->rfapi;
4736
0
  assert(h);
4737
4738
  /*
4739
   * Iterate over all import tables; do a filtered import
4740
   * for the afi/safi combination
4741
   */
4742
4743
0
  for (it = h->imports; it; it = it->next) {
4744
4745
0
    for (afi = AFI_IP; afi < AFI_MAX; ++afi) {
4746
4747
0
      total_active_local += it->local_count[afi];
4748
0
      total_active_remote += it->remote_count[afi];
4749
0
      total_holddown += it->holddown_count[afi];
4750
0
      total_imported += it->imported_count[afi];
4751
0
    }
4752
0
  }
4753
4754
0
  void *cursor;
4755
0
  int rc;
4756
4757
0
  if (h->import_mac) {
4758
0
    for (cursor = NULL,
4759
0
        rc = skiplist_next(h->import_mac, NULL, (void **)&it,
4760
0
               &cursor);
4761
0
         !rc; rc = skiplist_next(h->import_mac, NULL, (void **)&it,
4762
0
               &cursor)) {
4763
4764
0
      total_active_local += it->local_count[AFI_L2VPN];
4765
0
      total_active_remote += it->remote_count[AFI_L2VPN];
4766
0
      total_holddown += it->holddown_count[AFI_L2VPN];
4767
0
      total_imported += it->imported_count[AFI_L2VPN];
4768
0
    }
4769
0
  }
4770
4771
4772
0
  if (pALRcount) {
4773
0
    *pALRcount = total_active_local;
4774
0
  }
4775
0
  if (pARRcount) {
4776
0
    *pARRcount = total_active_remote;
4777
0
  }
4778
0
  if (pHRcount) {
4779
0
    *pHRcount = total_holddown;
4780
0
  }
4781
0
  if (pIRcount) {
4782
0
    *pIRcount = total_imported;
4783
0
  }
4784
0
}
4785
4786
/*------------------------------------------
4787
 * rfapiGetHolddownFromLifetime
4788
 *
4789
 * calculate holddown value based on lifetime
4790
 *
4791
 * input:
4792
 *     lifetime                lifetime
4793
 *
4794
 * return value:
4795
 *     Holddown value based on lifetime, holddown_factor,
4796
 *     and RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY
4797
 *
4798
 --------------------------------------------*/
4799
/* hold down time maxes out at RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY */
4800
uint32_t rfapiGetHolddownFromLifetime(uint32_t lifetime)
4801
0
{
4802
0
  uint32_t factor;
4803
0
  struct bgp *bgp;
4804
4805
0
  bgp = bgp_get_default();
4806
0
  if (bgp && bgp->rfapi_cfg)
4807
0
    factor = bgp->rfapi_cfg->rfp_cfg.holddown_factor;
4808
0
  else
4809
0
    factor = RFAPI_RFP_CFG_DEFAULT_HOLDDOWN_FACTOR;
4810
4811
0
  if (factor < 100 || lifetime < RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY)
4812
0
    lifetime = lifetime * factor / 100;
4813
0
  if (lifetime < RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY)
4814
0
    return lifetime;
4815
0
  else
4816
0
    return RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY;
4817
0
}