]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_zebra.c
Merge pull request #13350 from opensourcerouting/typesafe-fixes-20230421
[mirror_frr.git] / pimd / pim_zebra.c
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 {
47 struct prefix router_id;
48
49 zebra_router_id_update_read(zclient->ibuf, &router_id);
50
51 return 0;
52 }
53
54 static int pim_zebra_interface_vrf_update(ZAPI_CALLBACK_ARGS)
55 {
56 struct interface *ifp;
57 vrf_id_t new_vrf_id;
58 struct pim_instance *pim;
59 struct pim_interface *pim_ifp;
60
61 ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id,
62 &new_vrf_id);
63 if (!ifp)
64 return 0;
65
66 if (PIM_DEBUG_ZEBRA)
67 zlog_debug("%s: %s updating from %u to %u", __func__, ifp->name,
68 vrf_id, new_vrf_id);
69
70 pim = pim_get_pim_instance(new_vrf_id);
71 if (!pim)
72 return 0;
73
74 if_update_to_new_vrf(ifp, new_vrf_id);
75
76 pim_ifp = ifp->info;
77 if (!pim_ifp)
78 return 0;
79
80 pim_ifp->pim->mcast_if_count--;
81 pim_ifp->pim = pim;
82 pim_ifp->pim->mcast_if_count++;
83
84 return 0;
85 }
86
87 #ifdef PIM_DEBUG_IFADDR_DUMP
88 static void dump_if_address(struct interface *ifp)
89 {
90 struct connected *ifc;
91 struct listnode *node;
92
93 zlog_debug("%s %s: interface %s addresses:", __FILE__, __func__,
94 ifp->name);
95
96 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
97 struct prefix *p = ifc->address;
98
99 if (p->family != AF_INET)
100 continue;
101
102 zlog_debug("%s %s: interface %s address %pI4 %s", __FILE__,
103 __func__, ifp->name, &p->u.prefix4,
104 CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)
105 ? "secondary"
106 : "primary");
107 }
108 }
109 #endif
110
111 static int pim_zebra_if_address_add(ZAPI_CALLBACK_ARGS)
112 {
113 struct connected *c;
114 struct prefix *p;
115 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 c = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
126 if (!c)
127 return 0;
128
129 pim_ifp = c->ifp->info;
130 p = c->address;
131
132 if (PIM_DEBUG_ZEBRA) {
133 zlog_debug("%s: %s(%u) connected IP address %pFX flags %u %s",
134 __func__, c->ifp->name, vrf_id, p, c->flags,
135 CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)
136 ? "secondary"
137 : "primary");
138
139 #ifdef PIM_DEBUG_IFADDR_DUMP
140 dump_if_address(c->ifp);
141 #endif
142 }
143
144 #if PIM_IPV == 4
145 if (p->family != PIM_AF)
146 SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY);
147 else if (!CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)) {
148 /* trying to add primary address? */
149 pim_addr primary_addr = pim_find_primary_addr(c->ifp);
150 pim_addr addr = pim_addr_from_prefix(p);
151
152 if (pim_addr_cmp(primary_addr, addr)) {
153 if (PIM_DEBUG_ZEBRA)
154 zlog_warn(
155 "%s: %s : forcing secondary flag on %pFX",
156 __func__, c->ifp->name, p);
157 SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY);
158 }
159 }
160 #else /* PIM_IPV != 4 */
161 if (p->family != PIM_AF)
162 return 0;
163 #endif
164
165 pim_if_addr_add(c);
166 if (pim_ifp) {
167 struct pim_instance *pim;
168
169 pim = pim_get_pim_instance(vrf_id);
170 if (!pim) {
171 if (PIM_DEBUG_ZEBRA)
172 zlog_debug("%s: Unable to find pim instance",
173 __func__);
174 return 0;
175 }
176
177 pim_ifp->pim = pim;
178
179 pim_rp_check_on_if_add(pim_ifp);
180 }
181
182 if (if_is_loopback(c->ifp)) {
183 struct vrf *vrf = vrf_lookup_by_id(vrf_id);
184 struct interface *ifp;
185
186 FOR_ALL_INTERFACES (vrf, ifp) {
187 if (!if_is_loopback(ifp) && if_is_operative(ifp))
188 pim_if_addr_add_all(ifp);
189 }
190 }
191 return 0;
192 }
193
194 static int pim_zebra_if_address_del(ZAPI_CALLBACK_ARGS)
195 {
196 struct connected *c;
197 struct prefix *p;
198 struct vrf *vrf = vrf_lookup_by_id(vrf_id);
199
200 if (!vrf)
201 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 c = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
212 if (!c)
213 return 0;
214
215 p = c->address;
216
217 if (PIM_DEBUG_ZEBRA) {
218 zlog_debug(
219 "%s: %s(%u) disconnected IP address %pFX flags %u %s",
220 __func__, c->ifp->name, vrf_id, p, c->flags,
221 CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)
222 ? "secondary"
223 : "primary");
224 #ifdef PIM_DEBUG_IFADDR_DUMP
225 dump_if_address(c->ifp);
226 #endif
227 }
228
229 if (p->family == PIM_AF) {
230 struct pim_instance *pim;
231
232 pim = vrf->info;
233 pim_if_addr_del(c, 0);
234 pim_rp_setup(pim);
235 pim_i_am_rp_re_evaluate(pim);
236 }
237
238 connected_free(&c);
239 return 0;
240 }
241
242 void pim_zebra_update_all_interfaces(struct pim_instance *pim)
243 {
244 struct interface *ifp;
245
246 FOR_ALL_INTERFACES (pim->vrf, ifp) {
247 struct pim_interface *pim_ifp = ifp->info;
248 struct pim_iface_upstream_switch *us;
249 struct listnode *node;
250
251 if (!pim_ifp)
252 continue;
253
254 for (ALL_LIST_ELEMENTS_RO(pim_ifp->upstream_switch_list, node,
255 us)) {
256 struct pim_rpf rpf;
257
258 rpf.source_nexthop.interface = ifp;
259 rpf.rpf_addr = us->address;
260 pim_joinprune_send(&rpf, us->us);
261 pim_jp_agg_clear_group(us->us);
262 }
263 }
264 }
265
266 void pim_zebra_upstream_rpf_changed(struct pim_instance *pim,
267 struct pim_upstream *up,
268 struct pim_rpf *old)
269 {
270 if (old->source_nexthop.interface) {
271 struct pim_neighbor *nbr;
272
273 nbr = pim_neighbor_find(old->source_nexthop.interface,
274 old->rpf_addr, true);
275
276 if (nbr)
277 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 if (up->channel_oil->oil_inherited_rescan) {
284 pim_upstream_inherited_olist_decide(pim, up);
285 up->channel_oil->oil_inherited_rescan = 0;
286 }
287
288 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 if (!up->channel_oil->installed)
295 pim_upstream_mroute_add(up->channel_oil,
296 __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 pim_jp_agg_switch_interface(old, &up->rpf, up);
315
316 pim_upstream_join_timer_restart(up, old);
317 } /* up->join_state == PIM_UPSTREAM_JOINED */
318 }
319
320 else {
321 /*
322 * We have detected a case where we might need
323 * to rescan the inherited o_list so do it.
324 */
325 if (up->channel_oil->oil_inherited_rescan) {
326 pim_upstream_inherited_olist_decide(pim, up);
327 up->channel_oil->oil_inherited_rescan = 0;
328 }
329
330 if (up->join_state == PIM_UPSTREAM_JOINED)
331 pim_jp_agg_switch_interface(old, &up->rpf, up);
332
333 if (!up->channel_oil->installed)
334 pim_upstream_mroute_add(up->channel_oil, __func__);
335 }
336
337 /* FIXME can join_desired actually be changed by pim_rpf_update()
338 * returning PIM_RPF_CHANGED ?
339 */
340 pim_upstream_update_join_desired(pim, up);
341 }
342
343 __attribute__((unused))
344 static int pim_zebra_vxlan_sg_proc(ZAPI_CALLBACK_ARGS)
345 {
346 struct stream *s;
347 struct pim_instance *pim;
348 pim_sgaddr sg;
349 size_t prefixlen;
350
351 pim = pim_get_pim_instance(vrf_id);
352 if (!pim)
353 return 0;
354
355 s = zclient->ibuf;
356
357 prefixlen = stream_getl(s);
358 stream_get(&sg.src, s, prefixlen);
359 stream_get(&sg.grp, s, prefixlen);
360
361 if (PIM_DEBUG_ZEBRA)
362 zlog_debug("%u:recv SG %s %pSG", vrf_id,
363 (cmd == ZEBRA_VXLAN_SG_ADD) ? "add" : "del", &sg);
364
365 if (cmd == ZEBRA_VXLAN_SG_ADD)
366 pim_vxlan_sg_add(pim, &sg);
367 else
368 pim_vxlan_sg_del(pim, &sg);
369
370 return 0;
371 }
372
373 __attribute__((unused))
374 static void pim_zebra_vxlan_replay(void)
375 {
376 struct stream *s = NULL;
377
378 /* Check socket. */
379 if (!zclient || zclient->sock < 0)
380 return;
381
382 s = zclient->obuf;
383 stream_reset(s);
384
385 zclient_create_header(s, ZEBRA_VXLAN_SG_REPLAY, VRF_DEFAULT);
386 stream_putw_at(s, 0, stream_get_endp(s));
387
388 zclient_send_message(zclient);
389 }
390
391 void pim_scan_oil(struct pim_instance *pim)
392 {
393 struct channel_oil *c_oil;
394
395 pim->scan_oil_last = pim_time_monotonic_sec();
396 ++pim->scan_oil_events;
397
398 frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil)
399 pim_upstream_mroute_iif_update(c_oil, __func__);
400 }
401
402 static void on_rpf_cache_refresh(struct event *t)
403 {
404 struct pim_instance *pim = EVENT_ARG(t);
405
406 /* update kernel multicast forwarding cache (MFC) */
407 pim_scan_oil(pim);
408
409 pim->rpf_cache_refresh_last = pim_time_monotonic_sec();
410 ++pim->rpf_cache_refresh_events;
411
412 // It is called as part of pim_neighbor_add
413 // pim_rp_setup ();
414 }
415
416 void sched_rpf_cache_refresh(struct pim_instance *pim)
417 {
418 ++pim->rpf_cache_refresh_requests;
419
420 pim_rpf_set_refresh_time(pim);
421
422 if (pim->rpf_cache_refresher) {
423 /* Refresh timer is already running */
424 return;
425 }
426
427 /* Start refresh timer */
428
429 if (PIM_DEBUG_ZEBRA) {
430 zlog_debug("%s: triggering %ld msec timer", __func__,
431 router->rpf_cache_refresh_delay_msec);
432 }
433
434 event_add_timer_msec(router->master, on_rpf_cache_refresh, pim,
435 router->rpf_cache_refresh_delay_msec,
436 &pim->rpf_cache_refresher);
437 }
438
439 static void pim_zebra_connected(struct zclient *zclient)
440 {
441 #if PIM_IPV == 4
442 /* Send the client registration */
443 bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, router->vrf_id);
444 #endif
445
446 zclient_send_reg_requests(zclient, router->vrf_id);
447
448 #if PIM_IPV == 4
449 /* request for VxLAN BUM group addresses */
450 pim_zebra_vxlan_replay();
451 #endif
452 }
453
454 static void pim_zebra_capabilities(struct zclient_capabilities *cap)
455 {
456 router->mlag_role = cap->role;
457 router->multipath = cap->ecmp;
458 }
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 {
480 /* Socket for receiving updates from Zebra daemon */
481 zclient = zclient_new(router->master, &zclient_options_default,
482 pim_handlers, array_size(pim_handlers));
483
484 zclient->zebra_capabilities = pim_zebra_capabilities;
485 zclient->zebra_connected = pim_zebra_connected;
486
487 zclient_init(zclient, ZEBRA_ROUTE_PIM, 0, &pimd_privs);
488 if (PIM_DEBUG_PIM_TRACE) {
489 zlog_notice("%s: zclient socket initialized", __func__);
490 }
491
492 zclient_lookup_new();
493 }
494
495 void pim_forward_start(struct pim_ifchannel *ch)
496 {
497 struct pim_upstream *up = ch->upstream;
498 uint32_t mask = 0;
499
500 if (PIM_DEBUG_PIM_TRACE)
501 zlog_debug("%s: (S,G)=%pSG oif=%s (%pPA)", __func__, &ch->sg,
502 ch->interface->name, &up->upstream_addr);
503
504 if (PIM_IF_FLAG_TEST_PROTO_IGMP(ch->flags))
505 mask = PIM_OIF_FLAG_PROTO_GM;
506
507 if (PIM_IF_FLAG_TEST_PROTO_PIM(ch->flags))
508 mask |= PIM_OIF_FLAG_PROTO_PIM;
509
510 pim_channel_add_oif(up->channel_oil, ch->interface,
511 mask, __func__);
512 }
513
514 void pim_forward_stop(struct pim_ifchannel *ch)
515 {
516 struct pim_upstream *up = ch->upstream;
517
518 if (PIM_DEBUG_PIM_TRACE) {
519 zlog_debug("%s: (S,G)=%s oif=%s installed: %d",
520 __func__, ch->sg_str, ch->interface->name,
521 up->channel_oil->installed);
522 }
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 if (pim_upstream_evaluate_join_desired_interface(up, ch, ch->parent))
529 pim_channel_add_oif(up->channel_oil, ch->interface,
530 PIM_OIF_FLAG_PROTO_PIM, __func__);
531 else
532 pim_channel_del_oif(up->channel_oil, ch->interface,
533 PIM_OIF_FLAG_PROTO_PIM, __func__);
534 }
535
536 void pim_zebra_zclient_update(struct vty *vty)
537 {
538 vty_out(vty, "Zclient update socket: ");
539
540 if (zclient) {
541 vty_out(vty, "%d failures=%d\n", zclient->sock, zclient->fail);
542 } else {
543 vty_out(vty, "<null zclient>\n");
544 }
545 }
546
547 struct zclient *pim_zebra_zclient_get(void)
548 {
549 if (zclient)
550 return zclient;
551 else
552 return NULL;
553 }
554
555 void pim_zebra_interface_set_master(struct interface *vrf,
556 struct interface *ifp)
557 {
558 zclient_interface_set_master(zclient, vrf, ifp);
559 }