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