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