Coverage Report

Created: 2025-08-26 06:20

/src/frr/pimd/pim_zebra.c
Line
Count
Source (jump to first uncovered line)
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 * PIM for Quagga
4
 * Copyright (C) 2008  Everton da Silva Marques
5
 */
6
7
#include <zebra.h>
8
9
#include "if.h"
10
#include "log.h"
11
#include "prefix.h"
12
#include "zclient.h"
13
#include "stream.h"
14
#include "network.h"
15
#include "vty.h"
16
#include "plist.h"
17
#include "lib/bfd.h"
18
19
#include "pimd.h"
20
#include "pim_pim.h"
21
#include "pim_zebra.h"
22
#include "pim_iface.h"
23
#include "pim_str.h"
24
#include "pim_oil.h"
25
#include "pim_rpf.h"
26
#include "pim_time.h"
27
#include "pim_join.h"
28
#include "pim_zlookup.h"
29
#include "pim_ifchannel.h"
30
#include "pim_rp.h"
31
#include "pim_igmpv3.h"
32
#include "pim_jp_agg.h"
33
#include "pim_nht.h"
34
#include "pim_ssm.h"
35
#include "pim_vxlan.h"
36
#include "pim_mlag.h"
37
38
#undef PIM_DEBUG_IFADDR_DUMP
39
#define PIM_DEBUG_IFADDR_DUMP
40
41
struct zclient *zclient;
42
43
44
/* Router-id update message from zebra. */
45
static int pim_router_id_update_zebra(ZAPI_CALLBACK_ARGS)
46
0
{
47
0
  struct prefix router_id;
48
49
0
  zebra_router_id_update_read(zclient->ibuf, &router_id);
50
51
0
  return 0;
52
0
}
53
54
static int pim_zebra_interface_vrf_update(ZAPI_CALLBACK_ARGS)
55
0
{
56
0
  struct interface *ifp;
57
0
  vrf_id_t new_vrf_id;
58
0
  struct pim_instance *pim;
59
0
  struct pim_interface *pim_ifp;
60
61
0
  ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id,
62
0
                &new_vrf_id);
63
0
  if (!ifp)
64
0
    return 0;
65
66
0
  if (PIM_DEBUG_ZEBRA)
67
0
    zlog_debug("%s: %s updating from %u to %u", __func__, ifp->name,
68
0
         vrf_id, new_vrf_id);
69
70
0
  pim = pim_get_pim_instance(new_vrf_id);
71
0
  if (!pim)
72
0
    return 0;
73
74
0
  if_update_to_new_vrf(ifp, new_vrf_id);
75
76
0
  pim_ifp = ifp->info;
77
0
  if (!pim_ifp)
78
0
    return 0;
79
80
0
  pim_ifp->pim->mcast_if_count--;
81
0
  pim_ifp->pim = pim;
82
0
  pim_ifp->pim->mcast_if_count++;
83
84
0
  return 0;
85
0
}
86
87
#ifdef PIM_DEBUG_IFADDR_DUMP
88
static void dump_if_address(struct interface *ifp)
89
0
{
90
0
  struct connected *ifc;
91
0
  struct listnode *node;
92
93
0
  zlog_debug("%s %s: interface %s addresses:", __FILE__, __func__,
94
0
       ifp->name);
95
96
0
  for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
97
0
    struct prefix *p = ifc->address;
98
99
0
    if (p->family != AF_INET)
100
0
      continue;
101
102
0
    zlog_debug("%s %s: interface %s address %pI4 %s", __FILE__,
103
0
         __func__, ifp->name, &p->u.prefix4,
104
0
         CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)
105
0
           ? "secondary"
106
0
           : "primary");
107
0
  }
108
0
}
109
#endif
110
111
static int pim_zebra_if_address_add(ZAPI_CALLBACK_ARGS)
112
0
{
113
0
  struct connected *c;
114
0
  struct prefix *p;
115
0
  struct pim_interface *pim_ifp;
116
117
  /*
118
    zebra api notifies address adds/dels events by using the same call
119
    interface_add_read below, see comments in lib/zclient.c
120
121
    zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD, ...)
122
    will add address to interface list by calling
123
    connected_add_by_prefix()
124
  */
125
0
  c = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
126
0
  if (!c)
127
0
    return 0;
128
129
0
  pim_ifp = c->ifp->info;
130
0
  p = c->address;
131
132
0
  if (PIM_DEBUG_ZEBRA) {
133
0
    zlog_debug("%s: %s(%u) connected IP address %pFX flags %u %s",
134
0
         __func__, c->ifp->name, vrf_id, p, c->flags,
135
0
         CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)
136
0
           ? "secondary"
137
0
           : "primary");
138
139
0
#ifdef PIM_DEBUG_IFADDR_DUMP
140
0
    dump_if_address(c->ifp);
141
0
#endif
142
0
  }
143
144
0
#if PIM_IPV == 4
145
0
  if (p->family != PIM_AF)
146
0
    SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY);
147
0
  else if (!CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)) {
148
    /* trying to add primary address? */
149
0
    pim_addr primary_addr = pim_find_primary_addr(c->ifp);
150
0
    pim_addr addr = pim_addr_from_prefix(p);
151
152
0
    if (pim_addr_cmp(primary_addr, addr)) {
153
0
      if (PIM_DEBUG_ZEBRA)
154
0
        zlog_warn(
155
0
          "%s: %s : forcing secondary flag on %pFX",
156
0
          __func__, c->ifp->name, p);
157
0
      SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY);
158
0
    }
159
0
  }
160
#else /* PIM_IPV != 4 */
161
  if (p->family != PIM_AF)
162
    return 0;
163
#endif
164
165
0
  pim_if_addr_add(c);
166
0
  if (pim_ifp) {
167
0
    struct pim_instance *pim;
168
169
0
    pim = pim_get_pim_instance(vrf_id);
170
0
    if (!pim) {
171
0
      if (PIM_DEBUG_ZEBRA)
172
0
        zlog_debug("%s: Unable to find pim instance",
173
0
             __func__);
174
0
      return 0;
175
0
    }
176
177
0
    pim_ifp->pim = pim;
178
179
0
    pim_rp_check_on_if_add(pim_ifp);
180
0
  }
181
182
0
  if (if_is_loopback(c->ifp)) {
183
0
    struct vrf *vrf = vrf_lookup_by_id(vrf_id);
184
0
    struct interface *ifp;
185
186
0
    FOR_ALL_INTERFACES (vrf, ifp) {
187
0
      if (!if_is_loopback(ifp) && if_is_operative(ifp))
188
0
        pim_if_addr_add_all(ifp);
189
0
    }
190
0
  }
191
0
  return 0;
192
0
}
193
194
static int pim_zebra_if_address_del(ZAPI_CALLBACK_ARGS)
195
0
{
196
0
  struct connected *c;
197
0
  struct prefix *p;
198
0
  struct vrf *vrf = vrf_lookup_by_id(vrf_id);
199
200
0
  if (!vrf)
201
0
    return 0;
202
203
  /*
204
    zebra api notifies address adds/dels events by using the same call
205
    interface_add_read below, see comments in lib/zclient.c
206
207
    zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE, ...)
208
    will remove address from interface list by calling
209
    connected_delete_by_prefix()
210
  */
211
0
  c = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
212
0
  if (!c)
213
0
    return 0;
214
215
0
  p = c->address;
216
217
0
  if (PIM_DEBUG_ZEBRA) {
218
0
    zlog_debug(
219
0
      "%s: %s(%u) disconnected IP address %pFX flags %u %s",
220
0
      __func__, c->ifp->name, vrf_id, p, c->flags,
221
0
      CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)
222
0
        ? "secondary"
223
0
        : "primary");
224
0
#ifdef PIM_DEBUG_IFADDR_DUMP
225
0
    dump_if_address(c->ifp);
226
0
#endif
227
0
  }
228
229
0
  if (p->family == PIM_AF) {
230
0
    struct pim_instance *pim;
231
232
0
    pim = vrf->info;
233
0
    pim_if_addr_del(c, 0);
234
0
    pim_rp_setup(pim);
235
0
    pim_i_am_rp_re_evaluate(pim);
236
0
  }
237
238
0
  connected_free(&c);
239
0
  return 0;
240
0
}
241
242
void pim_zebra_update_all_interfaces(struct pim_instance *pim)
243
7.04k
{
244
7.04k
  struct interface *ifp;
245
246
14.0k
  FOR_ALL_INTERFACES (pim->vrf, ifp) {
247
14.0k
    struct pim_interface *pim_ifp = ifp->info;
248
14.0k
    struct pim_iface_upstream_switch *us;
249
14.0k
    struct listnode *node;
250
251
14.0k
    if (!pim_ifp)
252
0
      continue;
253
254
14.0k
    for (ALL_LIST_ELEMENTS_RO(pim_ifp->upstream_switch_list, node,
255
14.0k
            us)) {
256
0
      struct pim_rpf rpf;
257
258
0
      rpf.source_nexthop.interface = ifp;
259
0
      rpf.rpf_addr = us->address;
260
0
      pim_joinprune_send(&rpf, us->us);
261
0
      pim_jp_agg_clear_group(us->us);
262
0
    }
263
14.0k
  }
264
7.04k
}
265
266
void pim_zebra_upstream_rpf_changed(struct pim_instance *pim,
267
            struct pim_upstream *up,
268
            struct pim_rpf *old)
269
0
{
270
0
  if (old->source_nexthop.interface) {
271
0
    struct pim_neighbor *nbr;
272
273
0
    nbr = pim_neighbor_find(old->source_nexthop.interface,
274
0
          old->rpf_addr, true);
275
276
0
    if (nbr)
277
0
      pim_jp_agg_remove_group(nbr->upstream_jp_agg, up, nbr);
278
279
    /*
280
     * We have detected a case where we might need
281
     * to rescan the inherited o_list so do it.
282
     */
283
0
    if (up->channel_oil->oil_inherited_rescan) {
284
0
      pim_upstream_inherited_olist_decide(pim, up);
285
0
      up->channel_oil->oil_inherited_rescan = 0;
286
0
    }
287
288
0
    if (up->join_state == PIM_UPSTREAM_JOINED) {
289
      /*
290
       * If we come up real fast we can be here
291
       * where the mroute has not been installed
292
       * so install it.
293
       */
294
0
      if (!up->channel_oil->installed)
295
0
        pim_upstream_mroute_add(up->channel_oil,
296
0
              __func__);
297
298
      /*
299
       * RFC 4601: 4.5.7.  Sending (S,G)
300
       * Join/Prune Messages
301
       *
302
       * Transitions from Joined State
303
       *
304
       * RPF'(S,G) changes not due to an Assert
305
       *
306
       * The upstream (S,G) state machine remains
307
       * in Joined state. Send Join(S,G) to the new
308
       * upstream neighbor, which is the new value
309
       * of RPF'(S,G).  Send Prune(S,G) to the old
310
       * upstream neighbor, which is the old value
311
       * of RPF'(S,G).  Set the Join Timer (JT) to
312
       * expire after t_periodic seconds.
313
       */
314
0
      pim_jp_agg_switch_interface(old, &up->rpf, up);
315
316
0
      pim_upstream_join_timer_restart(up, old);
317
0
    } /* up->join_state == PIM_UPSTREAM_JOINED */
318
0
  }
319
320
0
  else {
321
    /*
322
     * We have detected a case where we might need
323
     * to rescan the inherited o_list so do it.
324
     */
325
0
    if (up->channel_oil->oil_inherited_rescan) {
326
0
      pim_upstream_inherited_olist_decide(pim, up);
327
0
      up->channel_oil->oil_inherited_rescan = 0;
328
0
    }
329
330
0
    if (up->join_state == PIM_UPSTREAM_JOINED)
331
0
      pim_jp_agg_switch_interface(old, &up->rpf, up);
332
333
0
    if (!up->channel_oil->installed)
334
0
      pim_upstream_mroute_add(up->channel_oil, __func__);
335
0
  }
336
337
  /* FIXME can join_desired actually be changed by pim_rpf_update()
338
   * returning PIM_RPF_CHANGED ?
339
   */
340
0
  pim_upstream_update_join_desired(pim, up);
341
0
}
342
343
__attribute__((unused))
344
static int pim_zebra_vxlan_sg_proc(ZAPI_CALLBACK_ARGS)
345
0
{
346
0
  struct stream *s;
347
0
  struct pim_instance *pim;
348
0
  pim_sgaddr sg;
349
0
  size_t prefixlen;
350
351
0
  pim = pim_get_pim_instance(vrf_id);
352
0
  if (!pim)
353
0
    return 0;
354
355
0
  s = zclient->ibuf;
356
357
0
  prefixlen = stream_getl(s);
358
0
  stream_get(&sg.src, s, prefixlen);
359
0
  stream_get(&sg.grp, s, prefixlen);
360
361
0
  if (PIM_DEBUG_ZEBRA)
362
0
    zlog_debug("%u:recv SG %s %pSG", vrf_id,
363
0
         (cmd == ZEBRA_VXLAN_SG_ADD) ? "add" : "del", &sg);
364
365
0
  if (cmd == ZEBRA_VXLAN_SG_ADD)
366
0
    pim_vxlan_sg_add(pim, &sg);
367
0
  else
368
0
    pim_vxlan_sg_del(pim, &sg);
369
370
0
  return 0;
371
0
}
372
373
__attribute__((unused))
374
static void pim_zebra_vxlan_replay(void)
375
0
{
376
0
  struct stream *s = NULL;
377
378
  /* Check socket. */
379
0
  if (!zclient || zclient->sock < 0)
380
0
    return;
381
382
0
  s = zclient->obuf;
383
0
  stream_reset(s);
384
385
0
  zclient_create_header(s, ZEBRA_VXLAN_SG_REPLAY, VRF_DEFAULT);
386
0
  stream_putw_at(s, 0, stream_get_endp(s));
387
388
0
  zclient_send_message(zclient);
389
0
}
390
391
void pim_scan_oil(struct pim_instance *pim)
392
0
{
393
0
  struct channel_oil *c_oil;
394
395
0
  pim->scan_oil_last = pim_time_monotonic_sec();
396
0
  ++pim->scan_oil_events;
397
398
0
  frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil)
399
0
    pim_upstream_mroute_iif_update(c_oil, __func__);
400
0
}
401
402
static void on_rpf_cache_refresh(struct event *t)
403
0
{
404
0
  struct pim_instance *pim = EVENT_ARG(t);
405
0
406
0
  /* update kernel multicast forwarding cache (MFC) */
407
0
  pim_scan_oil(pim);
408
0
409
0
  pim->rpf_cache_refresh_last = pim_time_monotonic_sec();
410
0
  ++pim->rpf_cache_refresh_events;
411
0
412
0
  // It is called as part of pim_neighbor_add
413
0
  // pim_rp_setup ();
414
0
}
415
416
void sched_rpf_cache_refresh(struct pim_instance *pim)
417
394
{
418
394
  ++pim->rpf_cache_refresh_requests;
419
420
394
  pim_rpf_set_refresh_time(pim);
421
422
394
  if (pim->rpf_cache_refresher) {
423
    /* Refresh timer is already running */
424
0
    return;
425
0
  }
426
427
  /* Start refresh timer */
428
429
394
  if (PIM_DEBUG_ZEBRA) {
430
0
    zlog_debug("%s: triggering %ld msec timer", __func__,
431
0
         router->rpf_cache_refresh_delay_msec);
432
0
  }
433
434
394
  event_add_timer_msec(router->master, on_rpf_cache_refresh, pim,
435
394
           router->rpf_cache_refresh_delay_msec,
436
394
           &pim->rpf_cache_refresher);
437
394
}
438
439
static void pim_zebra_connected(struct zclient *zclient)
440
0
{
441
0
#if PIM_IPV == 4
442
  /* Send the client registration */
443
0
  bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, router->vrf_id);
444
0
#endif
445
446
0
  zclient_send_reg_requests(zclient, router->vrf_id);
447
448
0
#if PIM_IPV == 4
449
  /* request for VxLAN BUM group addresses */
450
0
  pim_zebra_vxlan_replay();
451
0
#endif
452
0
}
453
454
static void pim_zebra_capabilities(struct zclient_capabilities *cap)
455
0
{
456
0
  router->mlag_role = cap->role;
457
0
  router->multipath = cap->ecmp;
458
0
}
459
460
static zclient_handler *const pim_handlers[] = {
461
  [ZEBRA_INTERFACE_ADDRESS_ADD] = pim_zebra_if_address_add,
462
  [ZEBRA_INTERFACE_ADDRESS_DELETE] = pim_zebra_if_address_del,
463
464
  [ZEBRA_NEXTHOP_UPDATE] = pim_parse_nexthop_update,
465
  [ZEBRA_ROUTER_ID_UPDATE] = pim_router_id_update_zebra,
466
  [ZEBRA_INTERFACE_VRF_UPDATE] = pim_zebra_interface_vrf_update,
467
468
#if PIM_IPV == 4
469
  [ZEBRA_VXLAN_SG_ADD] = pim_zebra_vxlan_sg_proc,
470
  [ZEBRA_VXLAN_SG_DEL] = pim_zebra_vxlan_sg_proc,
471
472
  [ZEBRA_MLAG_PROCESS_UP] = pim_zebra_mlag_process_up,
473
  [ZEBRA_MLAG_PROCESS_DOWN] = pim_zebra_mlag_process_down,
474
  [ZEBRA_MLAG_FORWARD_MSG] = pim_zebra_mlag_handle_msg,
475
#endif
476
};
477
478
void pim_zebra_init(void)
479
1
{
480
  /* Socket for receiving updates from Zebra daemon */
481
1
  zclient = zclient_new(router->master, &zclient_options_default,
482
1
            pim_handlers, array_size(pim_handlers));
483
484
1
  zclient->zebra_capabilities = pim_zebra_capabilities;
485
1
  zclient->zebra_connected = pim_zebra_connected;
486
487
1
  zclient_init(zclient, ZEBRA_ROUTE_PIM, 0, &pimd_privs);
488
1
  if (PIM_DEBUG_PIM_TRACE) {
489
0
    zlog_notice("%s: zclient socket initialized", __func__);
490
0
  }
491
492
1
  zclient_lookup_new();
493
1
}
494
495
void pim_forward_start(struct pim_ifchannel *ch)
496
0
{
497
0
  struct pim_upstream *up = ch->upstream;
498
0
  uint32_t mask = 0;
499
500
0
  if (PIM_DEBUG_PIM_TRACE)
501
0
    zlog_debug("%s: (S,G)=%pSG oif=%s (%pPA)", __func__, &ch->sg,
502
0
         ch->interface->name, &up->upstream_addr);
503
504
0
  if (PIM_IF_FLAG_TEST_PROTO_IGMP(ch->flags))
505
0
    mask = PIM_OIF_FLAG_PROTO_GM;
506
507
0
  if (PIM_IF_FLAG_TEST_PROTO_PIM(ch->flags))
508
0
    mask |= PIM_OIF_FLAG_PROTO_PIM;
509
510
0
  pim_channel_add_oif(up->channel_oil, ch->interface,
511
0
      mask, __func__);
512
0
}
513
514
void pim_forward_stop(struct pim_ifchannel *ch)
515
0
{
516
0
  struct pim_upstream *up = ch->upstream;
517
518
0
  if (PIM_DEBUG_PIM_TRACE) {
519
0
    zlog_debug("%s: (S,G)=%s oif=%s installed: %d",
520
0
         __func__, ch->sg_str, ch->interface->name,
521
0
         up->channel_oil->installed);
522
0
  }
523
524
  /*
525
   * If a channel is being removed, check to see if we still need
526
   * to inherit the interface.  If so make sure it is added in
527
   */
528
0
  if (pim_upstream_evaluate_join_desired_interface(up, ch, ch->parent))
529
0
    pim_channel_add_oif(up->channel_oil, ch->interface,
530
0
            PIM_OIF_FLAG_PROTO_PIM, __func__);
531
0
  else
532
0
    pim_channel_del_oif(up->channel_oil, ch->interface,
533
0
            PIM_OIF_FLAG_PROTO_PIM, __func__);
534
0
}
535
536
void pim_zebra_zclient_update(struct vty *vty)
537
0
{
538
0
  vty_out(vty, "Zclient update socket: ");
539
540
0
  if (zclient) {
541
0
    vty_out(vty, "%d failures=%d\n", zclient->sock, zclient->fail);
542
0
  } else {
543
0
    vty_out(vty, "<null zclient>\n");
544
0
  }
545
0
}
546
547
struct zclient *pim_zebra_zclient_get(void)
548
164k
{
549
164k
  if (zclient)
550
164k
    return zclient;
551
0
  else
552
0
    return NULL;
553
164k
}
554
555
void pim_zebra_interface_set_master(struct interface *vrf,
556
            struct interface *ifp)
557
0
{
558
0
  zclient_interface_set_master(zclient, vrf, ifp);
559
0
}