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