]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_zebra.c
pimd: Tell ourselves to rescan when we discover an issue
[mirror_frr.git] / pimd / pim_zebra.c
CommitLineData
12e41d03
DL
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
16 along with this program; see the file COPYING; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
18 MA 02110-1301 USA
19
12e41d03
DL
20*/
21
22#include <zebra.h>
23
24#include "zebra/rib.h"
25
26#include "if.h"
27#include "log.h"
28#include "prefix.h"
29#include "zclient.h"
30#include "stream.h"
31#include "network.h"
dfe43e25
DW
32#include "vty.h"
33#include "plist.h"
12e41d03
DL
34
35#include "pimd.h"
36#include "pim_pim.h"
37#include "pim_zebra.h"
38#include "pim_iface.h"
39#include "pim_str.h"
40#include "pim_oil.h"
41#include "pim_rpf.h"
42#include "pim_time.h"
43#include "pim_join.h"
44#include "pim_zlookup.h"
45#include "pim_ifchannel.h"
8f5f5e91 46#include "pim_rp.h"
2560106c 47#include "pim_igmpv3.h"
12e41d03
DL
48
49#undef PIM_DEBUG_IFADDR_DUMP
50#define PIM_DEBUG_IFADDR_DUMP
51
52static int fib_lookup_if_vif_index(struct in_addr addr);
53static int del_oif(struct channel_oil *channel_oil,
54 struct interface *oif,
55 uint32_t proto_mask);
56
12e41d03
DL
57/* Router-id update message from zebra. */
58static int pim_router_id_update_zebra(int command, struct zclient *zclient,
469351b3 59 zebra_size_t length, vrf_id_t vrf_id)
12e41d03
DL
60{
61 struct prefix router_id;
62
63 zebra_router_id_update_read(zclient->ibuf, &router_id);
64
65 return 0;
66}
67
68static int pim_zebra_if_add(int command, struct zclient *zclient,
469351b3 69 zebra_size_t length, vrf_id_t vrf_id)
12e41d03
DL
70{
71 struct interface *ifp;
72
73 /*
74 zebra api adds/dels interfaces using the same call
75 interface_add_read below, see comments in lib/zclient.c
76 */
469351b3 77 ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
12e41d03
DL
78 if (!ifp)
79 return 0;
80
81 if (PIM_DEBUG_ZEBRA) {
82 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
83 __PRETTY_FUNCTION__,
84 ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric,
85 ifp->mtu, if_is_operative(ifp));
86 }
87
88 if (if_is_operative(ifp))
89 pim_if_addr_add_all(ifp);
90
91 return 0;
92}
93
94static int pim_zebra_if_del(int command, struct zclient *zclient,
469351b3 95 zebra_size_t length, vrf_id_t vrf_id)
12e41d03
DL
96{
97 struct interface *ifp;
98
99 /*
100 zebra api adds/dels interfaces using the same call
101 interface_add_read below, see comments in lib/zclient.c
102
103 comments in lib/zclient.c seem to indicate that calling
104 zebra_interface_add_read is the correct call, but that
105 results in an attemted out of bounds read which causes
106 pimd to assert. Other clients use zebra_interface_state_read
107 and it appears to work just fine.
108 */
469351b3 109 ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
12e41d03
DL
110 if (!ifp)
111 return 0;
112
113 if (PIM_DEBUG_ZEBRA) {
114 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
115 __PRETTY_FUNCTION__,
116 ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric,
117 ifp->mtu, if_is_operative(ifp));
118 }
119
120 if (!if_is_operative(ifp))
121 pim_if_addr_del_all(ifp);
122
123 return 0;
124}
125
126static int pim_zebra_if_state_up(int command, struct zclient *zclient,
469351b3 127 zebra_size_t length, vrf_id_t vrf_id)
12e41d03
DL
128{
129 struct interface *ifp;
130
131 /*
132 zebra api notifies interface up/down events by using the same call
133 zebra_interface_state_read below, see comments in lib/zclient.c
134 */
469351b3 135 ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
12e41d03
DL
136 if (!ifp)
137 return 0;
138
12e41d03
DL
139 if (PIM_DEBUG_ZEBRA) {
140 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
141 __PRETTY_FUNCTION__,
142 ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric,
143 ifp->mtu, if_is_operative(ifp));
144 }
145
146 if (if_is_operative(ifp)) {
147 /*
148 pim_if_addr_add_all() suffices for bringing up both IGMP and PIM
149 */
150 pim_if_addr_add_all(ifp);
151 }
152
153 return 0;
154}
155
156static int pim_zebra_if_state_down(int command, struct zclient *zclient,
469351b3 157 zebra_size_t length, vrf_id_t vrf_id)
12e41d03
DL
158{
159 struct interface *ifp;
160
161 /*
162 zebra api notifies interface up/down events by using the same call
163 zebra_interface_state_read below, see comments in lib/zclient.c
164 */
469351b3 165 ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
12e41d03
DL
166 if (!ifp)
167 return 0;
168
12e41d03
DL
169 if (PIM_DEBUG_ZEBRA) {
170 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
171 __PRETTY_FUNCTION__,
172 ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric,
173 ifp->mtu, if_is_operative(ifp));
174 }
175
176 if (!if_is_operative(ifp)) {
177 /*
178 pim_if_addr_del_all() suffices for shutting down IGMP,
179 but not for shutting down PIM
180 */
181 pim_if_addr_del_all(ifp);
182
183 /*
184 pim_sock_delete() closes the socket, stops read and timer threads,
185 and kills all neighbors.
186 */
187 if (ifp->info) {
188 pim_sock_delete(ifp, "link down");
189 }
190 }
191
192 return 0;
193}
194
195#ifdef PIM_DEBUG_IFADDR_DUMP
196static void dump_if_address(struct interface *ifp)
197{
198 struct connected *ifc;
199 struct listnode *node;
200
201 zlog_debug("%s %s: interface %s addresses:",
202 __FILE__, __PRETTY_FUNCTION__,
203 ifp->name);
204
205 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
206 struct prefix *p = ifc->address;
207
208 if (p->family != AF_INET)
209 continue;
210
211 zlog_debug("%s %s: interface %s address %s %s",
212 __FILE__, __PRETTY_FUNCTION__,
213 ifp->name,
214 inet_ntoa(p->u.prefix4),
215 CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
216 "secondary" : "primary");
217 }
218}
219#endif
220
221static int pim_zebra_if_address_add(int command, struct zclient *zclient,
469351b3 222 zebra_size_t length, vrf_id_t vrf_id)
12e41d03
DL
223{
224 struct connected *c;
225 struct prefix *p;
7176984f 226 struct pim_interface *pim_ifp;
12e41d03 227
12e41d03
DL
228 /*
229 zebra api notifies address adds/dels events by using the same call
230 interface_add_read below, see comments in lib/zclient.c
231
232 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD, ...)
233 will add address to interface list by calling
234 connected_add_by_prefix()
235 */
469351b3 236 c = zebra_interface_address_read(command, zclient->ibuf, vrf_id);
12e41d03
DL
237 if (!c)
238 return 0;
239
7176984f 240 pim_ifp = c->ifp->info;
12e41d03 241 p = c->address;
d8424057 242
12e41d03
DL
243 if (PIM_DEBUG_ZEBRA) {
244 char buf[BUFSIZ];
245 prefix2str(p, buf, BUFSIZ);
246 zlog_debug("%s: %s connected IP address %s flags %u %s",
247 __PRETTY_FUNCTION__,
248 c->ifp->name, buf, c->flags,
249 CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary");
250
251#ifdef PIM_DEBUG_IFADDR_DUMP
252 dump_if_address(c->ifp);
253#endif
254 }
255
d8424057
DS
256 if (p->family != AF_INET)
257 {
d8424057
DS
258 struct listnode *cnode;
259 struct connected *conn;
260 int v4addrs = 0;
261
262 for (ALL_LIST_ELEMENTS_RO (c->ifp->connected, cnode, conn))
263 {
264 if (conn->address->family == AF_INET)
265 v4addrs++;
266 }
267 if (!v4addrs && pim_ifp)
268 {
d8424057
DS
269 pim_ifp->primary_address = pim_find_primary_addr (c->ifp);
270 pim_if_addr_add_all (c->ifp);
80219b76 271 pim_if_add_vif (c->ifp);
d8424057
DS
272 }
273 return 0;
274 }
275
12e41d03
DL
276 if (!CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)) {
277 /* trying to add primary address */
278
279 struct in_addr primary_addr = pim_find_primary_addr(c->ifp);
280 if (primary_addr.s_addr != p->u.prefix4.s_addr) {
c5cb17ec
DS
281 if (PIM_DEBUG_ZEBRA) {
282 /* but we had a primary address already */
12e41d03 283
c5cb17ec 284 char buf[BUFSIZ];
12e41d03 285
c5cb17ec 286 prefix2str(p, buf, BUFSIZ);
12e41d03 287
7176984f 288 zlog_warn("%s: %s : forcing secondary flag on %s",
c5cb17ec 289 __PRETTY_FUNCTION__,
7176984f 290 c->ifp->name, buf);
c5cb17ec 291 }
12e41d03
DL
292 SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY);
293 }
294 }
295
296 pim_if_addr_add(c);
7176984f 297 if (pim_ifp)
298 pim_rp_check_on_if_add(pim_ifp);
12e41d03 299
d8424057
DS
300 if (if_is_loopback (c->ifp))
301 {
302 struct listnode *ifnode;
303 struct interface *ifp;
304
305 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), ifnode, ifp))
306 {
307 if (!if_is_loopback (ifp) && if_is_operative (ifp))
308 pim_if_addr_add_all (ifp);
309 }
310 }
311
12e41d03
DL
312 return 0;
313}
314
315static int pim_zebra_if_address_del(int command, struct zclient *client,
469351b3 316 zebra_size_t length, vrf_id_t vrf_id)
12e41d03
DL
317{
318 struct connected *c;
319 struct prefix *p;
320
12e41d03
DL
321 /*
322 zebra api notifies address adds/dels events by using the same call
323 interface_add_read below, see comments in lib/zclient.c
324
325 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE, ...)
326 will remove address from interface list by calling
327 connected_delete_by_prefix()
328 */
469351b3 329 c = zebra_interface_address_read(command, client->ibuf, vrf_id);
12e41d03
DL
330 if (!c)
331 return 0;
332
333 p = c->address;
334 if (p->family != AF_INET)
335 return 0;
336
337 if (PIM_DEBUG_ZEBRA) {
338 char buf[BUFSIZ];
339 prefix2str(p, buf, BUFSIZ);
340 zlog_debug("%s: %s disconnected IP address %s flags %u %s",
341 __PRETTY_FUNCTION__,
342 c->ifp->name, buf, c->flags,
343 CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary");
344
345#ifdef PIM_DEBUG_IFADDR_DUMP
346 dump_if_address(c->ifp);
347#endif
348 }
349
350 pim_if_addr_del(c, 0);
da3dcffb 351 pim_rp_setup();
7176984f 352 pim_i_am_rp_re_evaluate();
12e41d03
DL
353
354 return 0;
355}
356
357static void scan_upstream_rpf_cache()
358{
359 struct listnode *up_node;
360 struct listnode *up_nextnode;
361 struct pim_upstream *up;
362
0f588989 363 for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up)) {
12e41d03 364 struct in_addr old_rpf_addr;
7747bad6 365 struct interface *old_interface;
12e41d03
DL
366 enum pim_rpf_result rpf_result;
367
7747bad6 368 old_interface = up->rpf.source_nexthop.interface;
f24405b1 369 rpf_result = pim_rpf_update(up, &old_rpf_addr);
12e41d03
DL
370 if (rpf_result == PIM_RPF_FAILURE)
371 continue;
372
373 if (rpf_result == PIM_RPF_CHANGED) {
b5183fd1
DS
374
375 /*
376 * We have detected a case where we might need to rescan
377 * the inherited o_list so do it.
378 */
379 if (up->channel_oil->oil_inherited_rescan)
380 {
381 pim_upstream_inherited_olist_decide (up);
382 up->channel_oil->oil_inherited_rescan = 0;
383 }
384
12e41d03 385 if (up->join_state == PIM_UPSTREAM_JOINED) {
34fe48e7
DS
386 /*
387 * If we come up real fast we can be here
388 * where the mroute has not been installed
389 * so install it.
390 */
b5183fd1
DS
391 if (!up->channel_oil->installed)
392 pim_mroute_add (up->channel_oil, __PRETTY_FUNCTION__);
34fe48e7 393
12e41d03
DL
394 /*
395 RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages
396
397 Transitions from Joined State
398
399 RPF'(S,G) changes not due to an Assert
400
401 The upstream (S,G) state machine remains in Joined
402 state. Send Join(S,G) to the new upstream neighbor, which is
403 the new value of RPF'(S,G). Send Prune(S,G) to the old
404 upstream neighbor, which is the old value of RPF'(S,G). Set
405 the Join Timer (JT) to expire after t_periodic seconds.
406 */
407
408
409 /* send Prune(S,G) to the old upstream neighbor */
7747bad6 410 pim_joinprune_send(old_interface, old_rpf_addr,
372eab92 411 up, 0 /* prune */);
12e41d03
DL
412
413 /* send Join(S,G) to the current upstream neighbor */
414 pim_joinprune_send(up->rpf.source_nexthop.interface,
63c59d0c 415 up->rpf.rpf_addr.u.prefix4,
372eab92 416 up,
12e41d03
DL
417 1 /* join */);
418
419 pim_upstream_join_timer_restart(up);
420 } /* up->join_state == PIM_UPSTREAM_JOINED */
421
422 /* FIXME can join_desired actually be changed by pim_rpf_update()
423 returning PIM_RPF_CHANGED ? */
424 pim_upstream_update_join_desired(up);
425
426 } /* PIM_RPF_CHANGED */
427
428 } /* for (qpim_upstream_list) */
429
430}
431
8a67a996
DS
432void
433pim_scan_individual_oil (struct channel_oil *c_oil)
12e41d03 434{
60cd0356
DS
435 struct in_addr vif_source;
436 int input_iface_vif_index;
8a67a996 437 int old_vif_index;
12e41d03 438
36d6bd7d 439 if (!pim_rp_set_upstream_addr (&vif_source, c_oil->oil.mfcc_origin, c_oil->oil.mfcc_mcastgrp))
60cd0356
DS
440 return;
441
442 input_iface_vif_index = fib_lookup_if_vif_index (vif_source);
8a67a996
DS
443 if (input_iface_vif_index < 1)
444 {
60cd0356
DS
445 if (PIM_DEBUG_ZEBRA)
446 {
eaa54bdb
DW
447 char source_str[INET_ADDRSTRLEN];
448 char group_str[INET_ADDRSTRLEN];
60cd0356
DS
449 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
450 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
451 zlog_debug("%s %s: could not find input interface(%d) for (S,G)=(%s,%s)",
452 __FILE__, __PRETTY_FUNCTION__, c_oil->oil.mfcc_parent,
453 source_str, group_str);
454 }
6a78764e 455 pim_mroute_del (c_oil, __PRETTY_FUNCTION__);
8a67a996 456 return;
12e41d03
DL
457 }
458
8a67a996
DS
459 if (input_iface_vif_index == c_oil->oil.mfcc_parent)
460 {
b1d15e15 461 if (!c_oil->installed)
6a78764e 462 pim_mroute_add (c_oil, __PRETTY_FUNCTION__);
b1d15e15 463
12e41d03 464 /* RPF unchanged */
8a67a996 465 return;
12e41d03
DL
466 }
467
8a67a996
DS
468 if (PIM_DEBUG_ZEBRA)
469 {
12e41d03
DL
470 struct interface *old_iif = pim_if_find_by_vif_index(c_oil->oil.mfcc_parent);
471 struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
eaa54bdb
DW
472 char source_str[INET_ADDRSTRLEN];
473 char group_str[INET_ADDRSTRLEN];
12e41d03
DL
474 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
475 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
476 zlog_debug("%s %s: (S,G)=(%s,%s) input interface changed from %s vif_index=%d to %s vif_index=%d",
477 __FILE__, __PRETTY_FUNCTION__,
478 source_str, group_str,
469c6aa2
DS
479 old_iif->name, c_oil->oil.mfcc_parent,
480 new_iif->name, input_iface_vif_index);
12e41d03
DL
481 }
482
8a67a996
DS
483 /* new iif loops to existing oif ? */
484 if (c_oil->oil.mfcc_ttls[input_iface_vif_index])
485 {
12e41d03
DL
486 struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
487
488 if (PIM_DEBUG_ZEBRA) {
eaa54bdb
DW
489 char source_str[INET_ADDRSTRLEN];
490 char group_str[INET_ADDRSTRLEN];
12e41d03
DL
491 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
492 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
493 zlog_debug("%s %s: (S,G)=(%s,%s) new iif loops to existing oif: %s vif_index=%d",
494 __FILE__, __PRETTY_FUNCTION__,
495 source_str, group_str,
469c6aa2 496 new_iif->name, input_iface_vif_index);
12e41d03
DL
497 }
498
d52ff9b7 499 //del_oif(c_oil, new_iif, PIM_OIF_FLAG_PROTO_ANY);
12e41d03
DL
500 }
501
502 /* update iif vif_index */
503 old_vif_index = c_oil->oil.mfcc_parent;
504 c_oil->oil.mfcc_parent = input_iface_vif_index;
505
506 /* update kernel multicast forwarding cache (MFC) */
6a78764e 507 if (pim_mroute_add(c_oil, __PRETTY_FUNCTION__))
8a67a996 508 {
8711a53d
DS
509 if (PIM_DEBUG_MROUTE)
510 {
511 /* just log warning */
512 struct interface *old_iif = pim_if_find_by_vif_index(old_vif_index);
513 struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
514 char source_str[INET_ADDRSTRLEN];
515 char group_str[INET_ADDRSTRLEN];
516 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
517 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
518 zlog_debug("%s %s: (S,G)=(%s,%s) failure updating input interface from %s vif_index=%d to %s vif_index=%d",
519 __FILE__, __PRETTY_FUNCTION__,
520 source_str, group_str,
521 old_iif ? old_iif->name : "<old_iif?>", c_oil->oil.mfcc_parent,
522 new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
523 }
12e41d03 524 }
8a67a996
DS
525}
526
527void pim_scan_oil()
528{
529 struct listnode *node;
530 struct listnode *nextnode;
531 struct channel_oil *c_oil;
532
533 qpim_scan_oil_last = pim_time_monotonic_sec();
534 ++qpim_scan_oil_events;
12e41d03 535
040d86ad 536 for (ALL_LIST_ELEMENTS(pim_channel_oil_list, node, nextnode, c_oil))
8a67a996 537 pim_scan_individual_oil (c_oil);
12e41d03
DL
538}
539
540static int on_rpf_cache_refresh(struct thread *t)
541{
12e41d03
DL
542 zassert(qpim_rpf_cache_refresher);
543
544 qpim_rpf_cache_refresher = 0;
545
546 /* update PIM protocol state */
547 scan_upstream_rpf_cache();
548
549 /* update kernel multicast forwarding cache (MFC) */
550 pim_scan_oil();
551
552 qpim_rpf_cache_refresh_last = pim_time_monotonic_sec();
553 ++qpim_rpf_cache_refresh_events;
554
00d07c6f 555 pim_rp_setup ();
12e41d03
DL
556 return 0;
557}
558
da72c9fd 559void sched_rpf_cache_refresh(void)
12e41d03
DL
560{
561 ++qpim_rpf_cache_refresh_requests;
562
e71bf8f7
DS
563 pim_rpf_set_refresh_time ();
564
12e41d03
DL
565 if (qpim_rpf_cache_refresher) {
566 /* Refresh timer is already running */
567 return;
568 }
569
570 /* Start refresh timer */
571
572 if (PIM_DEBUG_ZEBRA) {
573 zlog_debug("%s: triggering %ld msec timer",
574 __PRETTY_FUNCTION__,
575 qpim_rpf_cache_refresh_delay_msec);
576 }
577
578 THREAD_TIMER_MSEC_ON(master, qpim_rpf_cache_refresher,
579 on_rpf_cache_refresh,
580 0, qpim_rpf_cache_refresh_delay_msec);
581}
582
583static int redist_read_ipv4_route(int command, struct zclient *zclient,
469351b3 584 zebra_size_t length, vrf_id_t vrf_id)
12e41d03
DL
585{
586 struct stream *s;
587 struct zapi_ipv4 api;
b892f1dd 588 ifindex_t ifindex;
12e41d03
DL
589 struct in_addr nexthop;
590 struct prefix_ipv4 p;
591 int min_len = 4;
592
593 if (length < min_len) {
594 zlog_warn("%s %s: short buffer: length=%d min=%d",
595 __FILE__, __PRETTY_FUNCTION__,
596 length, min_len);
597 return -1;
598 }
599
600 s = zclient->ibuf;
601 ifindex = 0;
602 nexthop.s_addr = 0;
603
604 /* Type, flags, message. */
605 api.type = stream_getc(s);
5d3c5e6d 606 api.instance = stream_getw (s);
0fc452dc 607 api.flags = stream_getl(s);
12e41d03
DL
608 api.message = stream_getc(s);
609
610 /* IPv4 prefix length. */
611 memset(&p, 0, sizeof(struct prefix_ipv4));
612 p.family = AF_INET;
613 p.prefixlen = stream_getc(s);
614
615 min_len +=
616 PSIZE(p.prefixlen) +
617 CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? 5 : 0 +
618 CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? 5 : 0 +
619 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? 1 : 0 +
620 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? 4 : 0;
621
622 if (PIM_DEBUG_ZEBRA) {
623 zlog_debug("%s %s: length=%d min_len=%d flags=%s%s%s%s",
624 __FILE__, __PRETTY_FUNCTION__,
625 length, min_len,
626 CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? "nh" : "",
627 CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? " ifi" : "",
628 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? " dist" : "",
629 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : "");
630 }
631
12e41d03
DL
632 /* IPv4 prefix. */
633 stream_get(&p.prefix, s, PSIZE(p.prefixlen));
634
635 /* Nexthop, ifindex, distance, metric. */
636 if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
637 api.nexthop_num = stream_getc(s);
638 nexthop.s_addr = stream_get_ipv4(s);
639 }
640 if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX)) {
641 api.ifindex_num = stream_getc(s);
642 ifindex = stream_getl(s);
643 }
644
645 api.distance = CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ?
646 stream_getc(s) :
647 0;
648
649 api.metric = CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ?
650 stream_getl(s) :
651 0;
652
5d3c5e6d 653 if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG))
dc9ffce8 654 api.tag = stream_getl (s);
5d3c5e6d
DS
655 else
656 api.tag = 0;
657
12e41d03 658 switch (command) {
5d3c5e6d 659 case ZEBRA_REDISTRIBUTE_IPV4_ADD:
12e41d03
DL
660 if (PIM_DEBUG_ZEBRA) {
661 char buf[2][INET_ADDRSTRLEN];
662 zlog_debug("%s: add %s %s/%d "
b892f1dd 663 "nexthop %s ifindex %d metric%s %u distance%s %u",
12e41d03
DL
664 __PRETTY_FUNCTION__,
665 zebra_route_string(api.type),
666 inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
667 p.prefixlen,
668 inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
669 ifindex,
670 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss",
671 api.metric,
672 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss",
673 api.distance);
674 }
675 break;
5d3c5e6d 676 case ZEBRA_REDISTRIBUTE_IPV4_DEL:
12e41d03
DL
677 if (PIM_DEBUG_ZEBRA) {
678 char buf[2][INET_ADDRSTRLEN];
679 zlog_debug("%s: delete %s %s/%d "
b892f1dd 680 "nexthop %s ifindex %d metric%s %u distance%s %u",
12e41d03
DL
681 __PRETTY_FUNCTION__,
682 zebra_route_string(api.type),
683 inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
684 p.prefixlen,
685 inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
686 ifindex,
687 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss",
688 api.metric,
689 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss",
690 api.distance);
691 }
692 break;
693 default:
694 zlog_warn("%s: unknown command=%d", __PRETTY_FUNCTION__, command);
695 return -1;
696 }
697
698 sched_rpf_cache_refresh();
699
00d07c6f 700 pim_rp_setup ();
12e41d03
DL
701 return 0;
702}
703
48e8451b
DS
704static void
705pim_zebra_connected (struct zclient *zclient)
706{
707 zclient_send_reg_requests (zclient, VRF_DEFAULT);
708}
8711a53d 709
12e41d03
DL
710void pim_zebra_init(char *zebra_sock_path)
711{
712 int i;
713
714 if (zebra_sock_path)
715 zclient_serv_path_set(zebra_sock_path);
716
717#ifdef HAVE_TCP_ZEBRA
718 zlog_notice("zclient update contacting ZEBRA daemon at socket TCP %s,%d", "127.0.0.1", ZEBRA_PORT);
719#else
720 zlog_notice("zclient update contacting ZEBRA daemon at socket UNIX %s", zclient_serv_path_get());
721#endif
722
723 /* Socket for receiving updates from Zebra daemon */
469351b3 724 qpim_zclient_update = zclient_new (master);
12e41d03 725
48e8451b 726 qpim_zclient_update->zebra_connected = pim_zebra_connected;
12e41d03
DL
727 qpim_zclient_update->router_id_update = pim_router_id_update_zebra;
728 qpim_zclient_update->interface_add = pim_zebra_if_add;
729 qpim_zclient_update->interface_delete = pim_zebra_if_del;
730 qpim_zclient_update->interface_up = pim_zebra_if_state_up;
731 qpim_zclient_update->interface_down = pim_zebra_if_state_down;
732 qpim_zclient_update->interface_address_add = pim_zebra_if_address_add;
733 qpim_zclient_update->interface_address_delete = pim_zebra_if_address_del;
5d3c5e6d
DS
734 qpim_zclient_update->redistribute_route_ipv4_add = redist_read_ipv4_route;
735 qpim_zclient_update->redistribute_route_ipv4_del = redist_read_ipv4_route;
12e41d03 736
469351b3 737 zclient_init(qpim_zclient_update, ZEBRA_ROUTE_PIM, 0);
12e41d03
DL
738 if (PIM_DEBUG_PIM_TRACE) {
739 zlog_info("zclient_init cleared redistribution request");
740 }
741
742 zassert(qpim_zclient_update->redist_default == ZEBRA_ROUTE_PIM);
743
744 /* Request all redistribution */
745 for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
746 if (i == qpim_zclient_update->redist_default)
747 continue;
469351b3 748 vrf_bitmap_set (qpim_zclient_update->redist[AFI_IP][i], VRF_DEFAULT);;
12e41d03
DL
749 if (PIM_DEBUG_PIM_TRACE) {
750 zlog_debug("%s: requesting redistribution for %s (%i)",
751 __PRETTY_FUNCTION__, zebra_route_string(i), i);
752 }
753 }
754
755 /* Request default information */
756 zclient_redistribute_default (ZEBRA_REDISTRIBUTE_DEFAULT_ADD,
757 qpim_zclient_update, VRF_DEFAULT);
758
759 if (PIM_DEBUG_PIM_TRACE) {
760 zlog_info("%s: requesting default information redistribution",
761 __PRETTY_FUNCTION__);
762
763 zlog_notice("%s: zclient update socket initialized",
764 __PRETTY_FUNCTION__);
765 }
766
05b0d0d0 767 zclient_lookup_new();
12e41d03
DL
768}
769
770void igmp_anysource_forward_start(struct igmp_group *group)
771{
cab8707e
DS
772 struct igmp_source *source;
773 struct in_addr src_addr = { .s_addr = 0 };
12e41d03
DL
774 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
775 zassert(group->group_filtermode_isexcl);
776 zassert(listcount(group->group_source_list) < 1);
777
cab8707e
DS
778 source = source_new (group, src_addr);
779 if (!source)
780 {
781 zlog_warn ("%s: Failure to create * source", __PRETTY_FUNCTION__);
782 return;
783 }
784
785 igmp_source_forward_start (source);
12e41d03
DL
786}
787
788void igmp_anysource_forward_stop(struct igmp_group *group)
789{
2560106c
DS
790 struct igmp_source *source;
791 struct in_addr star = { .s_addr = 0 };
12e41d03 792
2560106c
DS
793 source = igmp_find_source_by_addr (group, star);
794 if (source)
795 igmp_source_forward_stop (source);
12e41d03
DL
796}
797
798static int fib_lookup_if_vif_index(struct in_addr addr)
799{
7b2c4d16 800 struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM];
12e41d03
DL
801 int num_ifindex;
802 int vif_index;
b892f1dd 803 ifindex_t first_ifindex;
12e41d03 804
05b0d0d0 805 num_ifindex = zclient_lookup_nexthop(nexthop_tab,
7b2c4d16 806 MULTIPATH_NUM, addr,
12e41d03
DL
807 PIM_NEXTHOP_LOOKUP_MAX);
808 if (num_ifindex < 1) {
8711a53d
DS
809 if (PIM_DEBUG_ZEBRA)
810 {
811 char addr_str[INET_ADDRSTRLEN];
812 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
813 zlog_debug("%s %s: could not find nexthop ifindex for address %s",
814 __FILE__, __PRETTY_FUNCTION__,
815 addr_str);
816 }
12e41d03
DL
817 return -1;
818 }
819
820 first_ifindex = nexthop_tab[0].ifindex;
821
822 if (num_ifindex > 1) {
8711a53d
DS
823 if (PIM_DEBUG_ZEBRA)
824 {
825 char addr_str[INET_ADDRSTRLEN];
826 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
827 zlog_debug("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
828 __FILE__, __PRETTY_FUNCTION__,
829 num_ifindex, addr_str, first_ifindex);
830 }
12e41d03
DL
831 /* debug warning only, do not return */
832 }
833
834 if (PIM_DEBUG_ZEBRA) {
eaa54bdb 835 char addr_str[INET_ADDRSTRLEN];
12e41d03
DL
836 pim_inet4_dump("<ifaddr?>", addr, addr_str, sizeof(addr_str));
837 zlog_debug("%s %s: found nexthop ifindex=%d (interface %s) for address %s",
838 __FILE__, __PRETTY_FUNCTION__,
839 first_ifindex, ifindex2ifname(first_ifindex), addr_str);
840 }
841
842 vif_index = pim_if_find_vifindex_by_ifindex(first_ifindex);
843
ae90dfbb 844 if (vif_index < 0) {
8711a53d
DS
845 if (PIM_DEBUG_ZEBRA)
846 {
847 char addr_str[INET_ADDRSTRLEN];
848 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
849 zlog_debug("%s %s: low vif_index=%d < 1 nexthop for address %s",
850 __FILE__, __PRETTY_FUNCTION__,
851 vif_index, addr_str);
852 }
12e41d03
DL
853 return -2;
854 }
855
12e41d03
DL
856 return vif_index;
857}
858
12e41d03
DL
859static int del_oif(struct channel_oil *channel_oil,
860 struct interface *oif,
861 uint32_t proto_mask)
862{
863 struct pim_interface *pim_ifp;
864 int old_ttl;
865
12e41d03
DL
866 pim_ifp = oif->info;
867
12e41d03 868 if (PIM_DEBUG_MROUTE) {
eaa54bdb
DW
869 char group_str[INET_ADDRSTRLEN];
870 char source_str[INET_ADDRSTRLEN];
12e41d03
DL
871 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
872 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
873 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
874 __FILE__, __PRETTY_FUNCTION__,
875 source_str, group_str,
876 proto_mask, oif->name, pim_ifp->mroute_vif_index);
877 }
878
879 /* Prevent single protocol from unsubscribing same interface from
880 channel (S,G) multiple times */
881 if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask)) {
05ca4827
DS
882 if (PIM_DEBUG_MROUTE)
883 {
eaa54bdb
DW
884 char group_str[INET_ADDRSTRLEN];
885 char source_str[INET_ADDRSTRLEN];
05ca4827
DS
886 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
887 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
8711a53d
DS
888 zlog_debug("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
889 __FILE__, __PRETTY_FUNCTION__,
890 proto_mask, oif->name, pim_ifp->mroute_vif_index,
891 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
892 source_str, group_str);
05ca4827 893 }
12e41d03
DL
894 return -2;
895 }
896
897 /* Mark that protocol is no longer interested in this OIF */
898 channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~proto_mask;
899
900 /* Allow multiple protocols to unsubscribe same interface from
901 channel (S,G) multiple times, by silently ignoring requests while
902 there is at least one protocol interested in the channel */
903 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
904
905 /* Check the OIF keeps existing before returning, and only log
906 warning otherwise */
907 if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
8711a53d
DS
908 if (PIM_DEBUG_MROUTE)
909 {
910 char group_str[INET_ADDRSTRLEN];
911 char source_str[INET_ADDRSTRLEN];
912 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
913 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
914 zlog_debug("%s %s: protocol mask %u removing nonexistent OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
915 __FILE__, __PRETTY_FUNCTION__,
916 proto_mask, oif->name, pim_ifp->mroute_vif_index,
917 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
918 source_str, group_str);
919 }
12e41d03
DL
920 }
921
922 return 0;
923 }
924
925 old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
926
927 if (old_ttl < 1) {
8711a53d
DS
928 if (PIM_DEBUG_MROUTE)
929 {
930 char group_str[INET_ADDRSTRLEN];
931 char source_str[INET_ADDRSTRLEN];
932 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
933 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
934 zlog_debug("%s %s: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)",
935 __FILE__, __PRETTY_FUNCTION__,
936 oif->name, pim_ifp->mroute_vif_index,
937 source_str, group_str);
938 }
12e41d03
DL
939 return -3;
940 }
941
942 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0;
943
6a78764e 944 if (pim_mroute_add(channel_oil, __PRETTY_FUNCTION__)) {
8711a53d 945 char group_str[INET_ADDRSTRLEN];
eaa54bdb 946 char source_str[INET_ADDRSTRLEN];
12e41d03
DL
947 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
948 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
949 zlog_warn("%s %s: could not remove output interface %s (vif_index=%d) from channel (S,G)=(%s,%s)",
950 __FILE__, __PRETTY_FUNCTION__,
951 oif->name, pim_ifp->mroute_vif_index,
952 source_str, group_str);
953
954 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
955 return -4;
956 }
957
958 --channel_oil->oil_size;
959
960 if (channel_oil->oil_size < 1) {
6a78764e 961 if (pim_mroute_del(channel_oil, __PRETTY_FUNCTION__)) {
8711a53d
DS
962 if (PIM_DEBUG_MROUTE)
963 {
964 /* just log a warning in case of failure */
965 char group_str[INET_ADDRSTRLEN];
966 char source_str[INET_ADDRSTRLEN];
967 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
968 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
969 zlog_debug("%s %s: failure removing OIL for channel (S,G)=(%s,%s)",
970 __FILE__, __PRETTY_FUNCTION__,
971 source_str, group_str);
972 }
12e41d03
DL
973 }
974 }
975
976 if (PIM_DEBUG_MROUTE) {
eaa54bdb
DW
977 char group_str[INET_ADDRSTRLEN];
978 char source_str[INET_ADDRSTRLEN];
12e41d03
DL
979 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
980 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
981 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
982 __FILE__, __PRETTY_FUNCTION__,
983 source_str, group_str,
984 proto_mask, oif->name, pim_ifp->mroute_vif_index);
985 }
986
987 return 0;
988}
989
990void igmp_source_forward_start(struct igmp_source *source)
991{
992 struct igmp_group *group;
4ed0af70 993 struct prefix_sg sg;
12e41d03
DL
994 int result;
995
02e6923e 996 memset (&sg, 0, sizeof (struct prefix_sg));
4ed0af70
DS
997 sg.src = source->source_addr;
998 sg.grp = source->source_group->group_addr;
05e451f8 999
12e41d03 1000 if (PIM_DEBUG_IGMP_TRACE) {
05e451f8 1001 zlog_debug("%s: (S,G)=%s igmp_sock=%d oif=%s fwd=%d",
12e41d03 1002 __PRETTY_FUNCTION__,
05e451f8 1003 pim_str_sg_dump (&sg),
12e41d03
DL
1004 source->source_group->group_igmp_sock->fd,
1005 source->source_group->group_igmp_sock->interface->name,
1006 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
1007 }
1008
1009 /* Prevent IGMP interface from installing multicast route multiple
1010 times */
1011 if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
1012 return;
1013 }
1014
1015 group = source->source_group;
1016
1017 if (!source->source_channel_oil) {
8f5f5e91 1018 struct in_addr vif_source;
12e41d03 1019 struct pim_interface *pim_oif;
8f5f5e91 1020
36d6bd7d 1021 if (!pim_rp_set_upstream_addr (&vif_source, source->source_addr, sg.grp))
8f5f5e91
DS
1022 return;
1023
1024 int input_iface_vif_index = fib_lookup_if_vif_index(vif_source);
12e41d03 1025 if (input_iface_vif_index < 1) {
8711a53d
DS
1026 if (PIM_DEBUG_IGMP_TRACE)
1027 {
1028 char source_str[INET_ADDRSTRLEN];
1029 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1030 zlog_debug("%s %s: could not find input interface for source %s",
1031 __FILE__, __PRETTY_FUNCTION__,
1032 source_str);
1033 }
12e41d03
DL
1034 return;
1035 }
1036
1037 /*
1038 Protect IGMP against adding looped MFC entries created by both
1039 source and receiver attached to the same interface. See TODO
1040 T22.
1041 */
1042 pim_oif = source->source_group->group_igmp_sock->interface->info;
1043 if (!pim_oif) {
8711a53d
DS
1044 if (PIM_DEBUG_IGMP_TRACE)
1045 {
1046 zlog_debug("%s: multicast not enabled on oif=%s ?",
1047 __PRETTY_FUNCTION__,
1048 source->source_group->group_igmp_sock->interface->name);
1049 }
12e41d03
DL
1050 return;
1051 }
8711a53d 1052
12e41d03
DL
1053 if (input_iface_vif_index == pim_oif->mroute_vif_index) {
1054 /* ignore request for looped MFC entry */
1055 if (PIM_DEBUG_IGMP_TRACE) {
05e451f8 1056 zlog_debug("%s: ignoring request for looped MFC entry (S,G)=%s: igmp_sock=%d oif=%s vif_index=%d",
12e41d03 1057 __PRETTY_FUNCTION__,
05e451f8 1058 pim_str_sg_dump (&sg),
12e41d03
DL
1059 source->source_group->group_igmp_sock->fd,
1060 source->source_group->group_igmp_sock->interface->name,
1061 input_iface_vif_index);
1062 }
1063 return;
1064 }
1065
05e451f8 1066 source->source_channel_oil = pim_channel_oil_add(&sg,
12e41d03
DL
1067 input_iface_vif_index);
1068 if (!source->source_channel_oil) {
8711a53d
DS
1069 if (PIM_DEBUG_IGMP_TRACE)
1070 {
1071 zlog_debug("%s %s: could not create OIL for channel (S,G)=%s",
1072 __FILE__, __PRETTY_FUNCTION__,
1073 pim_str_sg_dump (&sg));
1074 }
12e41d03
DL
1075 return;
1076 }
1077 }
1078
1865a44a
DS
1079 result = pim_channel_add_oif(source->source_channel_oil,
1080 group->group_igmp_sock->interface,
1081 PIM_OIF_FLAG_PROTO_IGMP);
12e41d03 1082 if (result) {
0afd31c9
DW
1083 if (PIM_DEBUG_MROUTE)
1084 {
1085 zlog_warn("%s: add_oif() failed with return=%d",
1086 __func__, result);
1087 }
12e41d03
DL
1088 return;
1089 }
1090
1091 /*
1092 Feed IGMPv3-gathered local membership information into PIM
1093 per-interface (S,G) state.
1094 */
69283639 1095 pim_ifchannel_local_membership_add(group->group_igmp_sock->interface, &sg);
12e41d03
DL
1096
1097 IGMP_SOURCE_DO_FORWARDING(source->source_flags);
1098}
1099
1100/*
1101 igmp_source_forward_stop: stop fowarding, but keep the source
1102 igmp_source_delete: stop fowarding, and delete the source
1103 */
1104void igmp_source_forward_stop(struct igmp_source *source)
1105{
1106 struct igmp_group *group;
4ed0af70 1107 struct prefix_sg sg;
12e41d03
DL
1108 int result;
1109
02e6923e 1110 memset (&sg, 0, sizeof (struct prefix_sg));
4ed0af70
DS
1111 sg.src = source->source_addr;
1112 sg.grp = source->source_group->group_addr;
1103466b 1113
12e41d03 1114 if (PIM_DEBUG_IGMP_TRACE) {
1103466b 1115 zlog_debug("%s: (S,G)=%s igmp_sock=%d oif=%s fwd=%d",
12e41d03 1116 __PRETTY_FUNCTION__,
1103466b 1117 pim_str_sg_dump (&sg),
12e41d03
DL
1118 source->source_group->group_igmp_sock->fd,
1119 source->source_group->group_igmp_sock->interface->name,
1120 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
1121 }
1122
1123 /* Prevent IGMP interface from removing multicast route multiple
1124 times */
1125 if (!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
1126 return;
1127 }
1128
1129 group = source->source_group;
1130
1131 /*
1132 It appears that in certain circumstances that
1133 igmp_source_forward_stop is called when IGMP forwarding
1134 was not enabled in oif_flags for this outgoing interface.
1135 Possibly because of multiple calls. When that happens, we
1136 enter the below if statement and this function returns early
1137 which in turn triggers the calling function to assert.
1138 Making the call to del_oif and ignoring the return code
1139 fixes the issue without ill effect, similar to
1140 pim_forward_stop below.
1141 */
1142 result = del_oif(source->source_channel_oil,
1143 group->group_igmp_sock->interface,
1144 PIM_OIF_FLAG_PROTO_IGMP);
1145 if (result) {
8711a53d
DS
1146 if (PIM_DEBUG_IGMP_TRACE)
1147 zlog_debug("%s: del_oif() failed with return=%d",
1148 __func__, result);
12e41d03
DL
1149 return;
1150 }
1151
1152 /*
1153 Feed IGMPv3-gathered local membership information into PIM
1154 per-interface (S,G) state.
1155 */
1156 pim_ifchannel_local_membership_del(group->group_igmp_sock->interface,
1103466b 1157 &sg);
12e41d03
DL
1158
1159 IGMP_SOURCE_DONT_FORWARDING(source->source_flags);
1160}
1161
1162void pim_forward_start(struct pim_ifchannel *ch)
1163{
1164 struct pim_upstream *up = ch->upstream;
1165
1166 if (PIM_DEBUG_PIM_TRACE) {
eaa54bdb
DW
1167 char source_str[INET_ADDRSTRLEN];
1168 char group_str[INET_ADDRSTRLEN];
1169 char upstream_str[INET_ADDRSTRLEN];
8f5f5e91 1170
4ed0af70
DS
1171 pim_inet4_dump("<source?>", ch->sg.src, source_str, sizeof(source_str));
1172 pim_inet4_dump("<group?>", ch->sg.grp, group_str, sizeof(group_str));
8f5f5e91
DS
1173 pim_inet4_dump("<upstream?>", up->upstream_addr, upstream_str, sizeof(upstream_str));
1174 zlog_debug("%s: (S,G)=(%s,%s) oif=%s(%s)",
12e41d03 1175 __PRETTY_FUNCTION__,
8f5f5e91 1176 source_str, group_str, ch->interface->name, upstream_str);
12e41d03
DL
1177 }
1178
1179 if (!up->channel_oil) {
8f5f5e91 1180 int input_iface_vif_index = fib_lookup_if_vif_index(up->upstream_addr);
12e41d03 1181 if (input_iface_vif_index < 1) {
8711a53d
DS
1182 if (PIM_DEBUG_PIM_TRACE)
1183 {
1184 char source_str[INET_ADDRSTRLEN];
1185 pim_inet4_dump("<source?>", up->sg.src, source_str, sizeof(source_str));
1186 zlog_debug("%s %s: could not find input interface for source %s",
1187 __FILE__, __PRETTY_FUNCTION__,
1188 source_str);
1189 }
12e41d03
DL
1190 return;
1191 }
1192
05e451f8 1193 up->channel_oil = pim_channel_oil_add(&up->sg,
12e41d03
DL
1194 input_iface_vif_index);
1195 if (!up->channel_oil) {
8711a53d
DS
1196 if (PIM_DEBUG_PIM_TRACE)
1197 zlog_debug("%s %s: could not create OIL for channel (S,G)=%s",
1198 __FILE__, __PRETTY_FUNCTION__,
8bfb8b67 1199 up->sg_str);
12e41d03
DL
1200 return;
1201 }
1202 }
1203
1865a44a
DS
1204 pim_channel_add_oif(up->channel_oil,
1205 ch->interface,
1206 PIM_OIF_FLAG_PROTO_PIM);
12e41d03
DL
1207}
1208
1209void pim_forward_stop(struct pim_ifchannel *ch)
1210{
1211 struct pim_upstream *up = ch->upstream;
1212
1213 if (PIM_DEBUG_PIM_TRACE) {
05e451f8 1214 zlog_debug("%s: (S,G)=%s oif=%s",
12e41d03 1215 __PRETTY_FUNCTION__,
8bfb8b67 1216 ch->sg_str, ch->interface->name);
12e41d03
DL
1217 }
1218
1219 if (!up->channel_oil) {
8711a53d
DS
1220 if (PIM_DEBUG_PIM_TRACE)
1221 zlog_debug("%s: (S,G)=%s oif=%s missing channel OIL",
1222 __PRETTY_FUNCTION__,
8bfb8b67 1223 ch->sg_str, ch->interface->name);
12e41d03
DL
1224
1225 return;
1226 }
1227
1228 del_oif(up->channel_oil,
1229 ch->interface,
1230 PIM_OIF_FLAG_PROTO_PIM);
1231}