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