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