]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_zebra.c
pim6d: IPv6-adjust various pim_sgaddr uses
[mirror_frr.git] / pimd / pim_zebra.c
1 /*
2 * PIM for Quagga
3 * Copyright (C) 2008 Everton da Silva Marques
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; see the file COPYING; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #include <zebra.h>
21
22 #include "if.h"
23 #include "log.h"
24 #include "prefix.h"
25 #include "zclient.h"
26 #include "stream.h"
27 #include "network.h"
28 #include "vty.h"
29 #include "plist.h"
30 #include "lib/bfd.h"
31
32 #include "pimd.h"
33 #include "pim_pim.h"
34 #include "pim_zebra.h"
35 #include "pim_iface.h"
36 #include "pim_str.h"
37 #include "pim_oil.h"
38 #include "pim_rpf.h"
39 #include "pim_time.h"
40 #include "pim_join.h"
41 #include "pim_zlookup.h"
42 #include "pim_ifchannel.h"
43 #include "pim_rp.h"
44 #include "pim_igmpv3.h"
45 #include "pim_jp_agg.h"
46 #include "pim_nht.h"
47 #include "pim_ssm.h"
48 #include "pim_vxlan.h"
49 #include "pim_mlag.h"
50
51 #undef PIM_DEBUG_IFADDR_DUMP
52 #define PIM_DEBUG_IFADDR_DUMP
53
54 struct zclient *zclient;
55
56
57 /* Router-id update message from zebra. */
58 static int pim_router_id_update_zebra(ZAPI_CALLBACK_ARGS)
59 {
60 struct prefix router_id;
61
62 zebra_router_id_update_read(zclient->ibuf, &router_id);
63
64 return 0;
65 }
66
67 static int pim_zebra_interface_vrf_update(ZAPI_CALLBACK_ARGS)
68 {
69 struct interface *ifp;
70 vrf_id_t new_vrf_id;
71
72 ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id,
73 &new_vrf_id);
74 if (!ifp)
75 return 0;
76
77 if (PIM_DEBUG_ZEBRA)
78 zlog_debug("%s: %s updating from %u to %u", __func__, ifp->name,
79 vrf_id, new_vrf_id);
80
81 if_update_to_new_vrf(ifp, new_vrf_id);
82
83 return 0;
84 }
85
86 #ifdef PIM_DEBUG_IFADDR_DUMP
87 static void dump_if_address(struct interface *ifp)
88 {
89 struct connected *ifc;
90 struct listnode *node;
91
92 zlog_debug("%s %s: interface %s addresses:", __FILE__, __func__,
93 ifp->name);
94
95 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
96 struct prefix *p = ifc->address;
97
98 if (p->family != AF_INET)
99 continue;
100
101 zlog_debug("%s %s: interface %s address %pI4 %s", __FILE__,
102 __func__, ifp->name, &p->u.prefix4,
103 CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)
104 ? "secondary"
105 : "primary");
106 }
107 }
108 #endif
109
110 static int pim_zebra_if_address_add(ZAPI_CALLBACK_ARGS)
111 {
112 struct connected *c;
113 struct prefix *p;
114 struct pim_interface *pim_ifp;
115 struct pim_instance *pim;
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 (!CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)) {
145 /* trying to add primary address */
146
147 struct in_addr primary_addr = pim_find_primary_addr(c->ifp);
148 if (p->family != AF_INET
149 || primary_addr.s_addr != p->u.prefix4.s_addr) {
150 if (PIM_DEBUG_ZEBRA)
151 zlog_warn(
152 "%s: %s : forcing secondary flag on %pFX",
153 __func__, c->ifp->name, p);
154 SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY);
155 }
156 }
157
158 pim_if_addr_add(c);
159 if (pim_ifp) {
160 pim = pim_get_pim_instance(vrf_id);
161 pim_ifp->pim = pim;
162
163 pim_rp_check_on_if_add(pim_ifp);
164 }
165
166 if (if_is_loopback(c->ifp)) {
167 struct vrf *vrf = vrf_lookup_by_id(vrf_id);
168 struct interface *ifp;
169
170 FOR_ALL_INTERFACES (vrf, ifp) {
171 if (!if_is_loopback(ifp) && if_is_operative(ifp))
172 pim_if_addr_add_all(ifp);
173 }
174 }
175
176 return 0;
177 }
178
179 static int pim_zebra_if_address_del(ZAPI_CALLBACK_ARGS)
180 {
181 struct connected *c;
182 struct prefix *p;
183 struct vrf *vrf = vrf_lookup_by_id(vrf_id);
184 struct pim_instance *pim;
185
186 if (!vrf)
187 return 0;
188 pim = vrf->info;
189
190 /*
191 zebra api notifies address adds/dels events by using the same call
192 interface_add_read below, see comments in lib/zclient.c
193
194 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE, ...)
195 will remove address from interface list by calling
196 connected_delete_by_prefix()
197 */
198 c = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
199 if (!c)
200 return 0;
201
202 p = c->address;
203 if (p->family == AF_INET) {
204 if (PIM_DEBUG_ZEBRA) {
205 zlog_debug(
206 "%s: %s(%u) disconnected IP address %pFX flags %u %s",
207 __func__, c->ifp->name, vrf_id, p, c->flags,
208 CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)
209 ? "secondary"
210 : "primary");
211
212 #ifdef PIM_DEBUG_IFADDR_DUMP
213 dump_if_address(c->ifp);
214 #endif
215 }
216
217 pim_if_addr_del(c, 0);
218 pim_rp_setup(pim);
219 pim_i_am_rp_re_evaluate(pim);
220 }
221
222 connected_free(&c);
223 return 0;
224 }
225
226 void pim_zebra_update_all_interfaces(struct pim_instance *pim)
227 {
228 struct interface *ifp;
229
230 FOR_ALL_INTERFACES (pim->vrf, ifp) {
231 struct pim_interface *pim_ifp = ifp->info;
232 struct pim_iface_upstream_switch *us;
233 struct listnode *node;
234
235 if (!pim_ifp)
236 continue;
237
238 for (ALL_LIST_ELEMENTS_RO(pim_ifp->upstream_switch_list, node,
239 us)) {
240 struct pim_rpf rpf;
241
242 rpf.source_nexthop.interface = ifp;
243 rpf.rpf_addr.u.prefix4 = us->address;
244 pim_joinprune_send(&rpf, us->us);
245 pim_jp_agg_clear_group(us->us);
246 }
247 }
248 }
249
250 void pim_zebra_upstream_rpf_changed(struct pim_instance *pim,
251 struct pim_upstream *up,
252 struct pim_rpf *old)
253 {
254 if (old->source_nexthop.interface) {
255 struct pim_neighbor *nbr;
256
257 nbr = pim_neighbor_find(old->source_nexthop.interface,
258 old->rpf_addr.u.prefix4);
259 if (nbr)
260 pim_jp_agg_remove_group(nbr->upstream_jp_agg, up, nbr);
261
262 /*
263 * We have detected a case where we might need
264 * to rescan the inherited o_list so do it.
265 */
266 if (up->channel_oil->oil_inherited_rescan) {
267 pim_upstream_inherited_olist_decide(pim, up);
268 up->channel_oil->oil_inherited_rescan = 0;
269 }
270
271 if (up->join_state == PIM_UPSTREAM_JOINED) {
272 /*
273 * If we come up real fast we can be here
274 * where the mroute has not been installed
275 * so install it.
276 */
277 if (!up->channel_oil->installed)
278 pim_upstream_mroute_add(up->channel_oil,
279 __func__);
280
281 /*
282 * RFC 4601: 4.5.7. Sending (S,G)
283 * Join/Prune Messages
284 *
285 * Transitions from Joined State
286 *
287 * RPF'(S,G) changes not due to an Assert
288 *
289 * The upstream (S,G) state machine remains
290 * in Joined state. Send Join(S,G) to the new
291 * upstream neighbor, which is the new value
292 * of RPF'(S,G). Send Prune(S,G) to the old
293 * upstream neighbor, which is the old value
294 * of RPF'(S,G). Set the Join Timer (JT) to
295 * expire after t_periodic seconds.
296 */
297 pim_jp_agg_switch_interface(old, &up->rpf, up);
298
299 pim_upstream_join_timer_restart(up, old);
300 } /* up->join_state == PIM_UPSTREAM_JOINED */
301 }
302
303 else {
304 /*
305 * We have detected a case where we might need
306 * to rescan the inherited o_list so do it.
307 */
308 if (up->channel_oil->oil_inherited_rescan) {
309 pim_upstream_inherited_olist_decide(pim, up);
310 up->channel_oil->oil_inherited_rescan = 0;
311 }
312
313 if (up->join_state == PIM_UPSTREAM_JOINED)
314 pim_jp_agg_switch_interface(old, &up->rpf, up);
315
316 if (!up->channel_oil->installed)
317 pim_upstream_mroute_add(up->channel_oil, __func__);
318 }
319
320 /* FIXME can join_desired actually be changed by pim_rpf_update()
321 * returning PIM_RPF_CHANGED ?
322 */
323 pim_upstream_update_join_desired(pim, up);
324 }
325
326 static int pim_zebra_vxlan_sg_proc(ZAPI_CALLBACK_ARGS)
327 {
328 struct stream *s;
329 struct pim_instance *pim;
330 pim_sgaddr sg;
331 size_t prefixlen;
332
333 pim = pim_get_pim_instance(vrf_id);
334 if (!pim)
335 return 0;
336
337 s = zclient->ibuf;
338
339 prefixlen = stream_getl(s);
340 stream_get(&sg.src, s, prefixlen);
341 stream_get(&sg.grp, s, prefixlen);
342
343 if (PIM_DEBUG_ZEBRA)
344 zlog_debug("%u:recv SG %s %pSG", vrf_id,
345 (cmd == ZEBRA_VXLAN_SG_ADD) ? "add" : "del", &sg);
346
347 if (cmd == ZEBRA_VXLAN_SG_ADD)
348 pim_vxlan_sg_add(pim, &sg);
349 else
350 pim_vxlan_sg_del(pim, &sg);
351
352 return 0;
353 }
354
355 static void pim_zebra_vxlan_replay(void)
356 {
357 struct stream *s = NULL;
358
359 /* Check socket. */
360 if (!zclient || zclient->sock < 0)
361 return;
362
363 s = zclient->obuf;
364 stream_reset(s);
365
366 zclient_create_header(s, ZEBRA_VXLAN_SG_REPLAY, VRF_DEFAULT);
367 stream_putw_at(s, 0, stream_get_endp(s));
368
369 zclient_send_message(zclient);
370 }
371
372 void pim_scan_oil(struct pim_instance *pim)
373 {
374 struct channel_oil *c_oil;
375
376 pim->scan_oil_last = pim_time_monotonic_sec();
377 ++pim->scan_oil_events;
378
379 frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil)
380 pim_upstream_mroute_iif_update(c_oil, __func__);
381 }
382
383 static int on_rpf_cache_refresh(struct thread *t)
384 {
385 struct pim_instance *pim = THREAD_ARG(t);
386
387 /* update kernel multicast forwarding cache (MFC) */
388 pim_scan_oil(pim);
389
390 pim->rpf_cache_refresh_last = pim_time_monotonic_sec();
391 ++pim->rpf_cache_refresh_events;
392
393 // It is called as part of pim_neighbor_add
394 // pim_rp_setup ();
395 return 0;
396 }
397
398 void sched_rpf_cache_refresh(struct pim_instance *pim)
399 {
400 ++pim->rpf_cache_refresh_requests;
401
402 pim_rpf_set_refresh_time(pim);
403
404 if (pim->rpf_cache_refresher) {
405 /* Refresh timer is already running */
406 return;
407 }
408
409 /* Start refresh timer */
410
411 if (PIM_DEBUG_ZEBRA) {
412 zlog_debug("%s: triggering %ld msec timer", __func__,
413 router->rpf_cache_refresh_delay_msec);
414 }
415
416 thread_add_timer_msec(router->master, on_rpf_cache_refresh, pim,
417 router->rpf_cache_refresh_delay_msec,
418 &pim->rpf_cache_refresher);
419 }
420
421 static void pim_zebra_connected(struct zclient *zclient)
422 {
423 /* Send the client registration */
424 bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, router->vrf_id);
425
426 zclient_send_reg_requests(zclient, router->vrf_id);
427
428 /* request for VxLAN BUM group addresses */
429 pim_zebra_vxlan_replay();
430 }
431
432 static void pim_zebra_capabilities(struct zclient_capabilities *cap)
433 {
434 router->mlag_role = cap->role;
435 }
436
437 static zclient_handler *const pim_handlers[] = {
438 [ZEBRA_ROUTER_ID_UPDATE] = pim_router_id_update_zebra,
439 [ZEBRA_INTERFACE_ADDRESS_ADD] = pim_zebra_if_address_add,
440 [ZEBRA_INTERFACE_ADDRESS_DELETE] = pim_zebra_if_address_del,
441 [ZEBRA_INTERFACE_VRF_UPDATE] = pim_zebra_interface_vrf_update,
442 [ZEBRA_NEXTHOP_UPDATE] = pim_parse_nexthop_update,
443
444 [ZEBRA_VXLAN_SG_ADD] = pim_zebra_vxlan_sg_proc,
445 [ZEBRA_VXLAN_SG_DEL] = pim_zebra_vxlan_sg_proc,
446
447 [ZEBRA_MLAG_PROCESS_UP] = pim_zebra_mlag_process_up,
448 [ZEBRA_MLAG_PROCESS_DOWN] = pim_zebra_mlag_process_down,
449 [ZEBRA_MLAG_FORWARD_MSG] = pim_zebra_mlag_handle_msg,
450 };
451
452 void pim_zebra_init(void)
453 {
454 /* Socket for receiving updates from Zebra daemon */
455 zclient = zclient_new(router->master, &zclient_options_default,
456 pim_handlers, array_size(pim_handlers));
457
458 zclient->zebra_capabilities = pim_zebra_capabilities;
459 zclient->zebra_connected = pim_zebra_connected;
460
461 zclient_init(zclient, ZEBRA_ROUTE_PIM, 0, &pimd_privs);
462 if (PIM_DEBUG_PIM_TRACE) {
463 zlog_notice("%s: zclient socket initialized", __func__);
464 }
465
466 zclient_lookup_new();
467 }
468
469 void igmp_anysource_forward_start(struct pim_instance *pim,
470 struct gm_group *group)
471 {
472 struct gm_source *source;
473 struct in_addr src_addr = {.s_addr = 0};
474 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
475 assert(group->group_filtermode_isexcl);
476 assert(listcount(group->group_source_list) < 1);
477
478 source = igmp_get_source_by_addr(group, src_addr, NULL);
479 if (!source) {
480 zlog_warn("%s: Failure to create * source", __func__);
481 return;
482 }
483
484 igmp_source_forward_start(pim, source);
485 }
486
487 void igmp_anysource_forward_stop(struct gm_group *group)
488 {
489 struct gm_source *source;
490 struct in_addr star = {.s_addr = 0};
491
492 source = igmp_find_source_by_addr(group, star);
493 if (source)
494 igmp_source_forward_stop(source);
495 }
496
497 static void igmp_source_forward_reevaluate_one(struct pim_instance *pim,
498 struct gm_source *source)
499 {
500 pim_sgaddr sg;
501 struct gm_group *group = source->source_group;
502 struct pim_ifchannel *ch;
503
504 if ((source->source_addr.s_addr != INADDR_ANY)
505 || !IGMP_SOURCE_TEST_FORWARDING(source->source_flags))
506 return;
507
508 memset(&sg, 0, sizeof(sg));
509 sg.src = source->source_addr;
510 sg.grp = group->group_addr;
511
512 ch = pim_ifchannel_find(group->interface, &sg);
513 if (pim_is_grp_ssm(pim, group->group_addr)) {
514 /* If SSM group withdraw local membership */
515 if (ch
516 && (ch->local_ifmembership == PIM_IFMEMBERSHIP_INCLUDE)) {
517 if (PIM_DEBUG_PIM_EVENTS)
518 zlog_debug("local membership del for %pSG as G is now SSM",
519 &sg);
520 pim_ifchannel_local_membership_del(group->interface,
521 &sg);
522 }
523 } else {
524 /* If ASM group add local membership */
525 if (!ch
526 || (ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO)) {
527 if (PIM_DEBUG_PIM_EVENTS)
528 zlog_debug("local membership add for %pSG as G is now ASM",
529 &sg);
530 pim_ifchannel_local_membership_add(
531 group->interface, &sg, false /*is_vxlan*/);
532 }
533 }
534 }
535
536 void igmp_source_forward_reevaluate_all(struct pim_instance *pim)
537 {
538 struct interface *ifp;
539
540 FOR_ALL_INTERFACES (pim->vrf, ifp) {
541 struct pim_interface *pim_ifp = ifp->info;
542 struct listnode *grpnode;
543 struct gm_group *grp;
544 struct pim_ifchannel *ch, *ch_temp;
545
546 if (!pim_ifp)
547 continue;
548
549 /* scan igmp groups */
550 for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_group_list, grpnode,
551 grp)) {
552 struct listnode *srcnode;
553 struct gm_source *src;
554
555 /* scan group sources */
556 for (ALL_LIST_ELEMENTS_RO(grp->group_source_list,
557 srcnode, src)) {
558 igmp_source_forward_reevaluate_one(pim, src);
559 } /* scan group sources */
560 } /* scan igmp groups */
561
562 RB_FOREACH_SAFE (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb,
563 ch_temp) {
564 if (pim_is_grp_ssm(pim, ch->sg.grp)) {
565 if (pim_addr_is_any(ch->sg.src))
566 pim_ifchannel_delete(ch);
567 }
568 }
569 } /* scan interfaces */
570 }
571
572 void igmp_source_forward_start(struct pim_instance *pim,
573 struct gm_source *source)
574 {
575 struct pim_interface *pim_oif;
576 struct gm_group *group;
577 pim_sgaddr sg;
578 int result;
579 int input_iface_vif_index = 0;
580
581 memset(&sg, 0, sizeof(sg));
582 sg.src = source->source_addr;
583 sg.grp = source->source_group->group_addr;
584
585 if (PIM_DEBUG_IGMP_TRACE) {
586 zlog_debug("%s: (S,G)=%pSG oif=%s fwd=%d", __func__, &sg,
587 source->source_group->interface->name,
588 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
589 }
590
591 /* Prevent IGMP interface from installing multicast route multiple
592 times */
593 if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
594 return;
595 }
596
597 group = source->source_group;
598 pim_oif = group->interface->info;
599 if (!pim_oif) {
600 if (PIM_DEBUG_IGMP_TRACE) {
601 zlog_debug("%s: multicast not enabled on oif=%s ?",
602 __func__,
603 source->source_group->interface->name);
604 }
605 return;
606 }
607
608 if (!source->source_channel_oil) {
609 pim_addr vif_source;
610 struct prefix src, grp;
611 struct pim_nexthop nexthop;
612 struct pim_upstream *up = NULL;
613
614 if (!pim_rp_set_upstream_addr(pim, &vif_source,
615 source->source_addr, sg.grp)) {
616 /*Create a dummy channel oil */
617 source->source_channel_oil =
618 pim_channel_oil_add(pim, &sg, __func__);
619 }
620
621 else {
622 pim_addr_to_prefix(&src, vif_source); // RP or Src addr
623 pim_addr_to_prefix(&grp, sg.grp);
624
625 up = pim_upstream_find(pim, &sg);
626 if (up) {
627 memcpy(&nexthop, &up->rpf.source_nexthop,
628 sizeof(struct pim_nexthop));
629 pim_ecmp_nexthop_lookup(pim, &nexthop, &src,
630 &grp, 0);
631 if (nexthop.interface)
632 input_iface_vif_index =
633 pim_if_find_vifindex_by_ifindex(
634 pim,
635 nexthop.interface->ifindex);
636 } else
637 input_iface_vif_index =
638 pim_ecmp_fib_lookup_if_vif_index(
639 pim, &src, &grp);
640
641 if (PIM_DEBUG_ZEBRA)
642 zlog_debug(
643 "%s: NHT %pSG vif_source %pPAs vif_index:%d ",
644 __func__, &sg, &vif_source,
645 input_iface_vif_index);
646
647 if (input_iface_vif_index < 1) {
648 if (PIM_DEBUG_IGMP_TRACE) {
649 char source_str[INET_ADDRSTRLEN];
650 pim_inet4_dump("<source?>",
651 source->source_addr,
652 source_str, sizeof(source_str));
653 zlog_debug(
654 "%s %s: could not find input interface for source %s",
655 __FILE__, __func__, source_str);
656 }
657 source->source_channel_oil =
658 pim_channel_oil_add(pim, &sg, __func__);
659 }
660
661 else {
662 /*
663 * Protect IGMP against adding looped MFC
664 * entries created by both source and receiver
665 * attached to the same interface. See TODO
666 * T22. Block only when the intf is non DR
667 * DR must create upstream.
668 */
669 if ((input_iface_vif_index ==
670 pim_oif->mroute_vif_index) &&
671 !(PIM_I_am_DR(pim_oif))) {
672 /* ignore request for looped MFC entry
673 */
674 if (PIM_DEBUG_IGMP_TRACE) {
675 zlog_debug("%s: ignoring request for looped MFC entry (S,G)=%pSG: oif=%s vif_index=%d",
676 __func__,
677 &sg,
678 source->source_group
679 ->interface->name,
680 input_iface_vif_index);
681 }
682 return;
683 }
684
685 source->source_channel_oil =
686 pim_channel_oil_add(pim, &sg, __func__);
687 if (!source->source_channel_oil) {
688 if (PIM_DEBUG_IGMP_TRACE) {
689 zlog_debug("%s %s: could not create OIL for channel (S,G)=%pSG",
690 __FILE__, __func__,
691 &sg);
692 }
693 return;
694 }
695 }
696 }
697 }
698
699 if (PIM_I_am_DR(pim_oif) || PIM_I_am_DualActive(pim_oif)) {
700 result = pim_channel_add_oif(source->source_channel_oil,
701 group->interface,
702 PIM_OIF_FLAG_PROTO_IGMP, __func__);
703 if (result) {
704 if (PIM_DEBUG_MROUTE) {
705 zlog_warn("%s: add_oif() failed with return=%d",
706 __func__, result);
707 }
708 return;
709 }
710 } else {
711 if (PIM_DEBUG_IGMP_TRACE)
712 zlog_debug("%s: %pSG was received on %s interface but we are not DR for that interface",
713 __func__, &sg,
714 group->interface->name);
715
716 return;
717 }
718 /*
719 Feed IGMPv3-gathered local membership information into PIM
720 per-interface (S,G) state.
721 */
722 if (!pim_ifchannel_local_membership_add(group->interface, &sg,
723 false /*is_vxlan*/)) {
724 if (PIM_DEBUG_MROUTE)
725 zlog_warn("%s: Failure to add local membership for %pSG",
726 __func__, &sg);
727
728 pim_channel_del_oif(source->source_channel_oil,
729 group->interface, PIM_OIF_FLAG_PROTO_IGMP,
730 __func__);
731 return;
732 }
733
734 IGMP_SOURCE_DO_FORWARDING(source->source_flags);
735 }
736
737 /*
738 igmp_source_forward_stop: stop fowarding, but keep the source
739 igmp_source_delete: stop fowarding, and delete the source
740 */
741 void igmp_source_forward_stop(struct gm_source *source)
742 {
743 struct gm_group *group;
744 pim_sgaddr sg;
745 int result;
746
747 memset(&sg, 0, sizeof(sg));
748 sg.src = source->source_addr;
749 sg.grp = source->source_group->group_addr;
750
751 if (PIM_DEBUG_IGMP_TRACE) {
752 zlog_debug("%s: (S,G)=%pSG oif=%s fwd=%d", __func__, &sg,
753 source->source_group->interface->name,
754 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
755 }
756
757 /* Prevent IGMP interface from removing multicast route multiple
758 times */
759 if (!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
760 return;
761 }
762
763 group = source->source_group;
764
765 /*
766 It appears that in certain circumstances that
767 igmp_source_forward_stop is called when IGMP forwarding
768 was not enabled in oif_flags for this outgoing interface.
769 Possibly because of multiple calls. When that happens, we
770 enter the below if statement and this function returns early
771 which in turn triggers the calling function to assert.
772 Making the call to pim_channel_del_oif and ignoring the return code
773 fixes the issue without ill effect, similar to
774 pim_forward_stop below.
775 */
776 result = pim_channel_del_oif(source->source_channel_oil,
777 group->interface, PIM_OIF_FLAG_PROTO_IGMP,
778 __func__);
779 if (result) {
780 if (PIM_DEBUG_IGMP_TRACE)
781 zlog_debug(
782 "%s: pim_channel_del_oif() failed with return=%d",
783 __func__, result);
784 return;
785 }
786
787 /*
788 Feed IGMPv3-gathered local membership information into PIM
789 per-interface (S,G) state.
790 */
791 pim_ifchannel_local_membership_del(group->interface, &sg);
792
793 IGMP_SOURCE_DONT_FORWARDING(source->source_flags);
794 }
795
796 void pim_forward_start(struct pim_ifchannel *ch)
797 {
798 struct pim_upstream *up = ch->upstream;
799 uint32_t mask = 0;
800
801 if (PIM_DEBUG_PIM_TRACE)
802 zlog_debug("%s: (S,G)=%pSG oif=%s (%pI4)", __func__, &ch->sg,
803 ch->interface->name, &up->upstream_addr);
804
805 if (PIM_IF_FLAG_TEST_PROTO_IGMP(ch->flags))
806 mask = PIM_OIF_FLAG_PROTO_IGMP;
807
808 if (PIM_IF_FLAG_TEST_PROTO_PIM(ch->flags))
809 mask |= PIM_OIF_FLAG_PROTO_PIM;
810
811 pim_channel_add_oif(up->channel_oil, ch->interface,
812 mask, __func__);
813 }
814
815 void pim_forward_stop(struct pim_ifchannel *ch)
816 {
817 struct pim_upstream *up = ch->upstream;
818
819 if (PIM_DEBUG_PIM_TRACE) {
820 zlog_debug("%s: (S,G)=%s oif=%s installed: %d",
821 __func__, ch->sg_str, ch->interface->name,
822 up->channel_oil->installed);
823 }
824
825 /*
826 * If a channel is being removed, check to see if we still need
827 * to inherit the interface. If so make sure it is added in
828 */
829 if (pim_upstream_evaluate_join_desired_interface(up, ch, ch->parent))
830 pim_channel_add_oif(up->channel_oil, ch->interface,
831 PIM_OIF_FLAG_PROTO_PIM, __func__);
832 else
833 pim_channel_del_oif(up->channel_oil, ch->interface,
834 PIM_OIF_FLAG_PROTO_PIM, __func__);
835 }
836
837 void pim_zebra_zclient_update(struct vty *vty)
838 {
839 vty_out(vty, "Zclient update socket: ");
840
841 if (zclient) {
842 vty_out(vty, "%d failures=%d\n", zclient->sock, zclient->fail);
843 } else {
844 vty_out(vty, "<null zclient>\n");
845 }
846 }
847
848 struct zclient *pim_zebra_zclient_get(void)
849 {
850 if (zclient)
851 return zclient;
852 else
853 return NULL;
854 }
855
856 void pim_zebra_interface_set_master(struct interface *vrf,
857 struct interface *ifp)
858 {
859 zclient_interface_set_master(zclient, vrf, ifp);
860 }