]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_zebra.c
pimd: When nexthop_lookup fails allow a retry.
[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 286 char buf[BUFSIZ];
eaa54bdb 287 char old[INET_ADDRSTRLEN];
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
0f588989 365 for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up)) {
12e41d03 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 {
eaa54bdb
DW
439 char source_str[INET_ADDRSTRLEN];
440 char group_str[INET_ADDRSTRLEN];
60cd0356
DS
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 {
b1d15e15
DS
453 if (!c_oil->installed)
454 pim_mroute_add (c_oil);
455
12e41d03 456 /* RPF unchanged */
8a67a996 457 return;
12e41d03
DL
458 }
459
8a67a996
DS
460 if (PIM_DEBUG_ZEBRA)
461 {
12e41d03
DL
462 struct interface *old_iif = pim_if_find_by_vif_index(c_oil->oil.mfcc_parent);
463 struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
eaa54bdb
DW
464 char source_str[INET_ADDRSTRLEN];
465 char group_str[INET_ADDRSTRLEN];
12e41d03
DL
466 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
467 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
468 zlog_debug("%s %s: (S,G)=(%s,%s) input interface changed from %s vif_index=%d to %s vif_index=%d",
469 __FILE__, __PRETTY_FUNCTION__,
470 source_str, group_str,
469c6aa2
DS
471 old_iif->name, c_oil->oil.mfcc_parent,
472 new_iif->name, input_iface_vif_index);
12e41d03
DL
473 }
474
8a67a996
DS
475 /* new iif loops to existing oif ? */
476 if (c_oil->oil.mfcc_ttls[input_iface_vif_index])
477 {
12e41d03
DL
478 struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
479
480 if (PIM_DEBUG_ZEBRA) {
eaa54bdb
DW
481 char source_str[INET_ADDRSTRLEN];
482 char group_str[INET_ADDRSTRLEN];
12e41d03
DL
483 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
484 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
485 zlog_debug("%s %s: (S,G)=(%s,%s) new iif loops to existing oif: %s vif_index=%d",
486 __FILE__, __PRETTY_FUNCTION__,
487 source_str, group_str,
469c6aa2 488 new_iif->name, input_iface_vif_index);
12e41d03
DL
489 }
490
491 del_oif(c_oil, new_iif, PIM_OIF_FLAG_PROTO_ANY);
492 }
493
494 /* update iif vif_index */
495 old_vif_index = c_oil->oil.mfcc_parent;
496 c_oil->oil.mfcc_parent = input_iface_vif_index;
497
498 /* update kernel multicast forwarding cache (MFC) */
c171d6d8 499 if (pim_mroute_add(c_oil))
8a67a996 500 {
12e41d03
DL
501 /* just log warning */
502 struct interface *old_iif = pim_if_find_by_vif_index(old_vif_index);
503 struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
eaa54bdb
DW
504 char source_str[INET_ADDRSTRLEN];
505 char group_str[INET_ADDRSTRLEN];
12e41d03
DL
506 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
507 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
508 zlog_warn("%s %s: (S,G)=(%s,%s) failure updating input interface from %s vif_index=%d to %s vif_index=%d",
8a67a996
DS
509 __FILE__, __PRETTY_FUNCTION__,
510 source_str, group_str,
511 old_iif ? old_iif->name : "<old_iif?>", c_oil->oil.mfcc_parent,
512 new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
12e41d03 513 }
8a67a996
DS
514}
515
516void pim_scan_oil()
517{
518 struct listnode *node;
519 struct listnode *nextnode;
520 struct channel_oil *c_oil;
521
522 qpim_scan_oil_last = pim_time_monotonic_sec();
523 ++qpim_scan_oil_events;
12e41d03 524
040d86ad 525 for (ALL_LIST_ELEMENTS(pim_channel_oil_list, node, nextnode, c_oil))
8a67a996 526 pim_scan_individual_oil (c_oil);
12e41d03
DL
527}
528
529static int on_rpf_cache_refresh(struct thread *t)
530{
531 zassert(t);
532 zassert(qpim_rpf_cache_refresher);
533
534 qpim_rpf_cache_refresher = 0;
535
536 /* update PIM protocol state */
537 scan_upstream_rpf_cache();
538
539 /* update kernel multicast forwarding cache (MFC) */
540 pim_scan_oil();
541
542 qpim_rpf_cache_refresh_last = pim_time_monotonic_sec();
543 ++qpim_rpf_cache_refresh_events;
544
00d07c6f 545 pim_rp_setup ();
12e41d03
DL
546 return 0;
547}
548
549static void sched_rpf_cache_refresh()
550{
551 ++qpim_rpf_cache_refresh_requests;
552
e71bf8f7
DS
553 pim_rpf_set_refresh_time ();
554
12e41d03
DL
555 if (qpim_rpf_cache_refresher) {
556 /* Refresh timer is already running */
557 return;
558 }
559
560 /* Start refresh timer */
561
562 if (PIM_DEBUG_ZEBRA) {
563 zlog_debug("%s: triggering %ld msec timer",
564 __PRETTY_FUNCTION__,
565 qpim_rpf_cache_refresh_delay_msec);
566 }
567
568 THREAD_TIMER_MSEC_ON(master, qpim_rpf_cache_refresher,
569 on_rpf_cache_refresh,
570 0, qpim_rpf_cache_refresh_delay_msec);
571}
572
573static int redist_read_ipv4_route(int command, struct zclient *zclient,
469351b3 574 zebra_size_t length, vrf_id_t vrf_id)
12e41d03
DL
575{
576 struct stream *s;
577 struct zapi_ipv4 api;
b892f1dd 578 ifindex_t ifindex;
12e41d03
DL
579 struct in_addr nexthop;
580 struct prefix_ipv4 p;
581 int min_len = 4;
582
583 if (length < min_len) {
584 zlog_warn("%s %s: short buffer: length=%d min=%d",
585 __FILE__, __PRETTY_FUNCTION__,
586 length, min_len);
587 return -1;
588 }
589
590 s = zclient->ibuf;
591 ifindex = 0;
592 nexthop.s_addr = 0;
593
594 /* Type, flags, message. */
595 api.type = stream_getc(s);
5d3c5e6d 596 api.instance = stream_getw (s);
0fc452dc 597 api.flags = stream_getl(s);
12e41d03
DL
598 api.message = stream_getc(s);
599
600 /* IPv4 prefix length. */
601 memset(&p, 0, sizeof(struct prefix_ipv4));
602 p.family = AF_INET;
603 p.prefixlen = stream_getc(s);
604
605 min_len +=
606 PSIZE(p.prefixlen) +
607 CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? 5 : 0 +
608 CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? 5 : 0 +
609 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? 1 : 0 +
610 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? 4 : 0;
611
612 if (PIM_DEBUG_ZEBRA) {
613 zlog_debug("%s %s: length=%d min_len=%d flags=%s%s%s%s",
614 __FILE__, __PRETTY_FUNCTION__,
615 length, min_len,
616 CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? "nh" : "",
617 CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? " ifi" : "",
618 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? " dist" : "",
619 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : "");
620 }
621
622 if (length < min_len) {
623 zlog_warn("%s %s: short buffer: 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 return -1;
631 }
632
633 /* IPv4 prefix. */
634 stream_get(&p.prefix, s, PSIZE(p.prefixlen));
635
636 /* Nexthop, ifindex, distance, metric. */
637 if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
638 api.nexthop_num = stream_getc(s);
639 nexthop.s_addr = stream_get_ipv4(s);
640 }
641 if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX)) {
642 api.ifindex_num = stream_getc(s);
643 ifindex = stream_getl(s);
644 }
645
646 api.distance = CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ?
647 stream_getc(s) :
648 0;
649
650 api.metric = CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ?
651 stream_getl(s) :
652 0;
653
5d3c5e6d 654 if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG))
dc9ffce8 655 api.tag = stream_getl (s);
5d3c5e6d
DS
656 else
657 api.tag = 0;
658
12e41d03 659 switch (command) {
5d3c5e6d 660 case ZEBRA_REDISTRIBUTE_IPV4_ADD:
12e41d03
DL
661 if (PIM_DEBUG_ZEBRA) {
662 char buf[2][INET_ADDRSTRLEN];
663 zlog_debug("%s: add %s %s/%d "
b892f1dd 664 "nexthop %s ifindex %d metric%s %u distance%s %u",
12e41d03
DL
665 __PRETTY_FUNCTION__,
666 zebra_route_string(api.type),
667 inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
668 p.prefixlen,
669 inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
670 ifindex,
671 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss",
672 api.metric,
673 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss",
674 api.distance);
675 }
676 break;
5d3c5e6d 677 case ZEBRA_REDISTRIBUTE_IPV4_DEL:
12e41d03
DL
678 if (PIM_DEBUG_ZEBRA) {
679 char buf[2][INET_ADDRSTRLEN];
680 zlog_debug("%s: delete %s %s/%d "
b892f1dd 681 "nexthop %s ifindex %d metric%s %u distance%s %u",
12e41d03
DL
682 __PRETTY_FUNCTION__,
683 zebra_route_string(api.type),
684 inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
685 p.prefixlen,
686 inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
687 ifindex,
688 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss",
689 api.metric,
690 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss",
691 api.distance);
692 }
693 break;
694 default:
695 zlog_warn("%s: unknown command=%d", __PRETTY_FUNCTION__, command);
696 return -1;
697 }
698
699 sched_rpf_cache_refresh();
700
00d07c6f 701 pim_rp_setup ();
12e41d03
DL
702 return 0;
703}
704
48e8451b
DS
705static void
706pim_zebra_connected (struct zclient *zclient)
707{
708 zclient_send_reg_requests (zclient, VRF_DEFAULT);
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) {
eaa54bdb 809 char addr_str[INET_ADDRSTRLEN];
12e41d03
DL
810 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
811 zlog_warn("%s %s: could not find nexthop ifindex for address %s",
812 __FILE__, __PRETTY_FUNCTION__,
813 addr_str);
814 return -1;
815 }
816
817 first_ifindex = nexthop_tab[0].ifindex;
818
819 if (num_ifindex > 1) {
eaa54bdb 820 char addr_str[INET_ADDRSTRLEN];
12e41d03 821 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
7adf0260 822 zlog_info("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
12e41d03
DL
823 __FILE__, __PRETTY_FUNCTION__,
824 num_ifindex, addr_str, first_ifindex);
825 /* debug warning only, do not return */
826 }
827
828 if (PIM_DEBUG_ZEBRA) {
eaa54bdb 829 char addr_str[INET_ADDRSTRLEN];
12e41d03
DL
830 pim_inet4_dump("<ifaddr?>", addr, addr_str, sizeof(addr_str));
831 zlog_debug("%s %s: found nexthop ifindex=%d (interface %s) for address %s",
832 __FILE__, __PRETTY_FUNCTION__,
833 first_ifindex, ifindex2ifname(first_ifindex), addr_str);
834 }
835
836 vif_index = pim_if_find_vifindex_by_ifindex(first_ifindex);
837
ae90dfbb 838 if (vif_index < 0) {
eaa54bdb 839 char addr_str[INET_ADDRSTRLEN];
12e41d03
DL
840 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
841 zlog_warn("%s %s: low vif_index=%d < 1 nexthop for address %s",
842 __FILE__, __PRETTY_FUNCTION__,
843 vif_index, addr_str);
844 return -2;
845 }
846
847 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
848
849 if (vif_index > qpim_mroute_oif_highest_vif_index) {
eaa54bdb 850 char addr_str[INET_ADDRSTRLEN];
12e41d03
DL
851 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
852 zlog_warn("%s %s: high vif_index=%d > highest_vif_index=%d nexthop for address %s",
853 __FILE__, __PRETTY_FUNCTION__,
854 vif_index, qpim_mroute_oif_highest_vif_index, addr_str);
855
856 zlog_warn("%s %s: pim disabled on interface %s vif_index=%d ?",
857 __FILE__, __PRETTY_FUNCTION__,
858 ifindex2ifname(vif_index),
859 vif_index);
860
861 return -3;
862 }
863
864 return vif_index;
865}
866
12e41d03
DL
867static int del_oif(struct channel_oil *channel_oil,
868 struct interface *oif,
869 uint32_t proto_mask)
870{
871 struct pim_interface *pim_ifp;
872 int old_ttl;
873
874 zassert(channel_oil);
875
876 pim_ifp = oif->info;
877
878 zassert(pim_ifp->mroute_vif_index >= 1);
879 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
880 zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index);
881
882 if (PIM_DEBUG_MROUTE) {
eaa54bdb
DW
883 char group_str[INET_ADDRSTRLEN];
884 char source_str[INET_ADDRSTRLEN];
12e41d03
DL
885 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
886 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
887 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
888 __FILE__, __PRETTY_FUNCTION__,
889 source_str, group_str,
890 proto_mask, oif->name, pim_ifp->mroute_vif_index);
891 }
892
893 /* Prevent single protocol from unsubscribing same interface from
894 channel (S,G) multiple times */
895 if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask)) {
05ca4827
DS
896 if (PIM_DEBUG_MROUTE)
897 {
eaa54bdb
DW
898 char group_str[INET_ADDRSTRLEN];
899 char source_str[INET_ADDRSTRLEN];
05ca4827
DS
900 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
901 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
902 zlog_warn("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
903 __FILE__, __PRETTY_FUNCTION__,
904 proto_mask, oif->name, pim_ifp->mroute_vif_index,
905 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
906 source_str, group_str);
907 }
12e41d03
DL
908 return -2;
909 }
910
911 /* Mark that protocol is no longer interested in this OIF */
912 channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~proto_mask;
913
914 /* Allow multiple protocols to unsubscribe same interface from
915 channel (S,G) multiple times, by silently ignoring requests while
916 there is at least one protocol interested in the channel */
917 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
918
919 /* Check the OIF keeps existing before returning, and only log
920 warning otherwise */
921 if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
eaa54bdb
DW
922 char group_str[INET_ADDRSTRLEN];
923 char source_str[INET_ADDRSTRLEN];
12e41d03
DL
924 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
925 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
926 zlog_warn("%s %s: protocol mask %u removing nonexistent OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
927 __FILE__, __PRETTY_FUNCTION__,
928 proto_mask, oif->name, pim_ifp->mroute_vif_index,
929 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
930 source_str, group_str);
931 }
932
933 return 0;
934 }
935
936 old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
937
938 if (old_ttl < 1) {
eaa54bdb
DW
939 char group_str[INET_ADDRSTRLEN];
940 char source_str[INET_ADDRSTRLEN];
12e41d03
DL
941 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
942 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
943 zlog_warn("%s %s: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)",
944 __FILE__, __PRETTY_FUNCTION__,
945 oif->name, pim_ifp->mroute_vif_index,
946 source_str, group_str);
947 return -3;
948 }
949
950 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0;
951
c171d6d8 952 if (pim_mroute_add(channel_oil)) {
eaa54bdb
DW
953 char group_str[INET_ADDRSTRLEN];
954 char source_str[INET_ADDRSTRLEN];
12e41d03
DL
955 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
956 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
957 zlog_warn("%s %s: could not remove output interface %s (vif_index=%d) from channel (S,G)=(%s,%s)",
958 __FILE__, __PRETTY_FUNCTION__,
959 oif->name, pim_ifp->mroute_vif_index,
960 source_str, group_str);
961
962 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
963 return -4;
964 }
965
966 --channel_oil->oil_size;
967
968 if (channel_oil->oil_size < 1) {
c171d6d8 969 if (pim_mroute_del(channel_oil)) {
12e41d03 970 /* just log a warning in case of failure */
eaa54bdb
DW
971 char group_str[INET_ADDRSTRLEN];
972 char source_str[INET_ADDRSTRLEN];
12e41d03
DL
973 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
974 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
975 zlog_warn("%s %s: failure removing OIL for channel (S,G)=(%s,%s)",
976 __FILE__, __PRETTY_FUNCTION__,
977 source_str, group_str);
978 }
979 }
980
981 if (PIM_DEBUG_MROUTE) {
eaa54bdb
DW
982 char group_str[INET_ADDRSTRLEN];
983 char source_str[INET_ADDRSTRLEN];
12e41d03
DL
984 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
985 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
986 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
987 __FILE__, __PRETTY_FUNCTION__,
988 source_str, group_str,
989 proto_mask, oif->name, pim_ifp->mroute_vif_index);
990 }
991
992 return 0;
993}
994
995void igmp_source_forward_start(struct igmp_source *source)
996{
997 struct igmp_group *group;
4ed0af70 998 struct prefix_sg sg;
12e41d03
DL
999 int result;
1000
02e6923e 1001 memset (&sg, 0, sizeof (struct prefix_sg));
4ed0af70
DS
1002 sg.src = source->source_addr;
1003 sg.grp = source->source_group->group_addr;
05e451f8 1004
12e41d03 1005 if (PIM_DEBUG_IGMP_TRACE) {
05e451f8 1006 zlog_debug("%s: (S,G)=%s igmp_sock=%d oif=%s fwd=%d",
12e41d03 1007 __PRETTY_FUNCTION__,
05e451f8 1008 pim_str_sg_dump (&sg),
12e41d03
DL
1009 source->source_group->group_igmp_sock->fd,
1010 source->source_group->group_igmp_sock->interface->name,
1011 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
1012 }
1013
1014 /* Prevent IGMP interface from installing multicast route multiple
1015 times */
1016 if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
1017 return;
1018 }
1019
1020 group = source->source_group;
1021
1022 if (!source->source_channel_oil) {
8f5f5e91 1023 struct in_addr vif_source;
12e41d03 1024 struct pim_interface *pim_oif;
8f5f5e91 1025
36d6bd7d 1026 if (!pim_rp_set_upstream_addr (&vif_source, source->source_addr, sg.grp))
8f5f5e91
DS
1027 return;
1028
1029 int input_iface_vif_index = fib_lookup_if_vif_index(vif_source);
12e41d03 1030 if (input_iface_vif_index < 1) {
eaa54bdb 1031 char source_str[INET_ADDRSTRLEN];
12e41d03
DL
1032 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1033 zlog_warn("%s %s: could not find input interface for source %s",
1034 __FILE__, __PRETTY_FUNCTION__,
1035 source_str);
1036 return;
1037 }
1038
1039 /*
1040 Protect IGMP against adding looped MFC entries created by both
1041 source and receiver attached to the same interface. See TODO
1042 T22.
1043 */
1044 pim_oif = source->source_group->group_igmp_sock->interface->info;
1045 if (!pim_oif) {
1046 zlog_warn("%s: multicast not enabled on oif=%s ?",
1047 __PRETTY_FUNCTION__,
1048 source->source_group->group_igmp_sock->interface->name);
1049 return;
1050 }
1051 if (pim_oif->mroute_vif_index < 1) {
1052 zlog_warn("%s %s: oif=%s vif_index=%d < 1",
1053 __FILE__, __PRETTY_FUNCTION__,
1054 source->source_group->group_igmp_sock->interface->name,
1055 pim_oif->mroute_vif_index);
1056 return;
1057 }
1058 if (input_iface_vif_index == pim_oif->mroute_vif_index) {
1059 /* ignore request for looped MFC entry */
1060 if (PIM_DEBUG_IGMP_TRACE) {
05e451f8 1061 zlog_debug("%s: ignoring request for looped MFC entry (S,G)=%s: igmp_sock=%d oif=%s vif_index=%d",
12e41d03 1062 __PRETTY_FUNCTION__,
05e451f8 1063 pim_str_sg_dump (&sg),
12e41d03
DL
1064 source->source_group->group_igmp_sock->fd,
1065 source->source_group->group_igmp_sock->interface->name,
1066 input_iface_vif_index);
1067 }
1068 return;
1069 }
1070
05e451f8 1071 source->source_channel_oil = pim_channel_oil_add(&sg,
12e41d03
DL
1072 input_iface_vif_index);
1073 if (!source->source_channel_oil) {
05e451f8 1074 zlog_warn("%s %s: could not create OIL for channel (S,G)=%s",
12e41d03 1075 __FILE__, __PRETTY_FUNCTION__,
05e451f8 1076 pim_str_sg_dump (&sg));
12e41d03
DL
1077 return;
1078 }
1079 }
1080
1865a44a
DS
1081 result = pim_channel_add_oif(source->source_channel_oil,
1082 group->group_igmp_sock->interface,
1083 PIM_OIF_FLAG_PROTO_IGMP);
12e41d03
DL
1084 if (result) {
1085 zlog_warn("%s: add_oif() failed with return=%d",
1086 __func__, result);
1087 return;
1088 }
1089
1090 /*
1091 Feed IGMPv3-gathered local membership information into PIM
1092 per-interface (S,G) state.
1093 */
69283639 1094 pim_ifchannel_local_membership_add(group->group_igmp_sock->interface, &sg);
12e41d03
DL
1095
1096 IGMP_SOURCE_DO_FORWARDING(source->source_flags);
1097}
1098
1099/*
1100 igmp_source_forward_stop: stop fowarding, but keep the source
1101 igmp_source_delete: stop fowarding, and delete the source
1102 */
1103void igmp_source_forward_stop(struct igmp_source *source)
1104{
1105 struct igmp_group *group;
4ed0af70 1106 struct prefix_sg sg;
12e41d03
DL
1107 int result;
1108
02e6923e 1109 memset (&sg, 0, sizeof (struct prefix_sg));
4ed0af70
DS
1110 sg.src = source->source_addr;
1111 sg.grp = source->source_group->group_addr;
1103466b 1112
12e41d03 1113 if (PIM_DEBUG_IGMP_TRACE) {
1103466b 1114 zlog_debug("%s: (S,G)=%s igmp_sock=%d oif=%s fwd=%d",
12e41d03 1115 __PRETTY_FUNCTION__,
1103466b 1116 pim_str_sg_dump (&sg),
12e41d03
DL
1117 source->source_group->group_igmp_sock->fd,
1118 source->source_group->group_igmp_sock->interface->name,
1119 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
1120 }
1121
1122 /* Prevent IGMP interface from removing multicast route multiple
1123 times */
1124 if (!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
1125 return;
1126 }
1127
1128 group = source->source_group;
1129
1130 /*
1131 It appears that in certain circumstances that
1132 igmp_source_forward_stop is called when IGMP forwarding
1133 was not enabled in oif_flags for this outgoing interface.
1134 Possibly because of multiple calls. When that happens, we
1135 enter the below if statement and this function returns early
1136 which in turn triggers the calling function to assert.
1137 Making the call to del_oif and ignoring the return code
1138 fixes the issue without ill effect, similar to
1139 pim_forward_stop below.
1140 */
1141 result = del_oif(source->source_channel_oil,
1142 group->group_igmp_sock->interface,
1143 PIM_OIF_FLAG_PROTO_IGMP);
1144 if (result) {
1145 zlog_warn("%s: del_oif() failed with return=%d",
1146 __func__, result);
1147 return;
1148 }
1149
1150 /*
1151 Feed IGMPv3-gathered local membership information into PIM
1152 per-interface (S,G) state.
1153 */
1154 pim_ifchannel_local_membership_del(group->group_igmp_sock->interface,
1103466b 1155 &sg);
12e41d03
DL
1156
1157 IGMP_SOURCE_DONT_FORWARDING(source->source_flags);
1158}
1159
1160void pim_forward_start(struct pim_ifchannel *ch)
1161{
1162 struct pim_upstream *up = ch->upstream;
1163
1164 if (PIM_DEBUG_PIM_TRACE) {
eaa54bdb
DW
1165 char source_str[INET_ADDRSTRLEN];
1166 char group_str[INET_ADDRSTRLEN];
1167 char upstream_str[INET_ADDRSTRLEN];
8f5f5e91 1168
4ed0af70
DS
1169 pim_inet4_dump("<source?>", ch->sg.src, source_str, sizeof(source_str));
1170 pim_inet4_dump("<group?>", ch->sg.grp, group_str, sizeof(group_str));
8f5f5e91
DS
1171 pim_inet4_dump("<upstream?>", up->upstream_addr, upstream_str, sizeof(upstream_str));
1172 zlog_debug("%s: (S,G)=(%s,%s) oif=%s(%s)",
12e41d03 1173 __PRETTY_FUNCTION__,
8f5f5e91 1174 source_str, group_str, ch->interface->name, upstream_str);
12e41d03
DL
1175 }
1176
1177 if (!up->channel_oil) {
8f5f5e91 1178 int input_iface_vif_index = fib_lookup_if_vif_index(up->upstream_addr);
12e41d03 1179 if (input_iface_vif_index < 1) {
eaa54bdb 1180 char source_str[INET_ADDRSTRLEN];
4ed0af70 1181 pim_inet4_dump("<source?>", up->sg.src, source_str, sizeof(source_str));
12e41d03
DL
1182 zlog_warn("%s %s: could not find input interface for source %s",
1183 __FILE__, __PRETTY_FUNCTION__,
1184 source_str);
1185 return;
1186 }
1187
05e451f8 1188 up->channel_oil = pim_channel_oil_add(&up->sg,
12e41d03
DL
1189 input_iface_vif_index);
1190 if (!up->channel_oil) {
05e451f8 1191 zlog_warn("%s %s: could not create OIL for channel (S,G)=%s",
12e41d03 1192 __FILE__, __PRETTY_FUNCTION__,
05e451f8 1193 pim_str_sg_dump (&up->sg));
12e41d03
DL
1194 return;
1195 }
1196 }
1197
1865a44a
DS
1198 pim_channel_add_oif(up->channel_oil,
1199 ch->interface,
1200 PIM_OIF_FLAG_PROTO_PIM);
12e41d03
DL
1201}
1202
1203void pim_forward_stop(struct pim_ifchannel *ch)
1204{
1205 struct pim_upstream *up = ch->upstream;
1206
1207 if (PIM_DEBUG_PIM_TRACE) {
05e451f8 1208 zlog_debug("%s: (S,G)=%s oif=%s",
12e41d03 1209 __PRETTY_FUNCTION__,
05e451f8 1210 pim_str_sg_dump (&ch->sg), ch->interface->name);
12e41d03
DL
1211 }
1212
1213 if (!up->channel_oil) {
05e451f8
DS
1214 zlog_warn("%s: (S,G)=%s oif=%s missing channel OIL",
1215 __PRETTY_FUNCTION__,
1216 pim_str_sg_dump(&ch->sg), ch->interface->name);
12e41d03
DL
1217
1218 return;
1219 }
1220
1221 del_oif(up->channel_oil,
1222 ch->interface,
1223 PIM_OIF_FLAG_PROTO_PIM);
1224}