1 /*
2   PIM for Quagga
3   Copyright (C) 2008  Everton da Silva Marques
4   This program is free software; you can redistribute it and/or modify
5   it under the terms of the GNU General Public License as published by
6   the Free Software Foundation; either version 2 of the License, or
7   (at your option) any later version.
8 
9   This program is distributed in the hope that it will be useful, but
10   WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   General Public License for more details.
13 
14   You should have received a copy of the GNU General Public License
15   along with this program; see the file COPYING; if not, write to the
16   Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
17   MA 02110-1301 USA
18 
19   $QuaggaId: $Format:%an, %ai, %h$ $
20 */
21 
22 #include <zebra.h>
23 
24 #include "if.h"
25 #include "log.h"
26 #include "vty.h"
27 #include "memory.h"
28 #include "prefix.h"
29 
30 #include "pimd.h"
31 #include "pim_iface.h"
32 #include "pim_igmp.h"
33 #include "pim_mroute.h"
34 #include "pim_oil.h"
35 #include "pim_str.h"
36 #include "pim_pim.h"
37 #include "pim_neighbor.h"
38 #include "pim_ifchannel.h"
39 #include "pim_sock.h"
40 #include "pim_time.h"
41 #include "pim_ssmpingd.h"
42 
43 static void pim_if_igmp_join_del_all(struct interface *ifp);
44 
if_list_clean(struct pim_interface * pim_ifp)45 static void *if_list_clean(struct pim_interface *pim_ifp)
46 {
47   if (pim_ifp->igmp_join_list) {
48     list_delete(pim_ifp->igmp_join_list);
49   }
50 
51   if (pim_ifp->igmp_socket_list) {
52     list_delete(pim_ifp->igmp_socket_list);
53   }
54 
55   if (pim_ifp->pim_neighbor_list) {
56     list_delete(pim_ifp->pim_neighbor_list);
57   }
58 
59   if (pim_ifp->pim_ifchannel_list) {
60     list_delete(pim_ifp->pim_ifchannel_list);
61   }
62 
63   XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
64 
65   return 0;
66 }
67 
pim_if_new(struct interface * ifp,int igmp,int pim)68 struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
69 {
70   struct pim_interface *pim_ifp;
71 
72   zassert(ifp);
73   zassert(!ifp->info);
74 
75   pim_ifp = XMALLOC(MTYPE_PIM_INTERFACE, sizeof(*pim_ifp));
76   if (!pim_ifp) {
77     zlog_err("PIM XMALLOC(%zu) failure", sizeof(*pim_ifp));
78     return 0;
79   }
80 
81   pim_ifp->options                           = 0;
82   pim_ifp->mroute_vif_index                  = -1;
83 
84   pim_ifp->igmp_default_robustness_variable           = IGMP_DEFAULT_ROBUSTNESS_VARIABLE;
85   pim_ifp->igmp_default_query_interval                = IGMP_GENERAL_QUERY_INTERVAL;
86   pim_ifp->igmp_query_max_response_time_dsec          = IGMP_QUERY_MAX_RESPONSE_TIME_DSEC;
87   pim_ifp->igmp_specific_query_max_response_time_dsec = IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC;
88 
89   /*
90     RFC 3376: 8.3. Query Response Interval
91     The number of seconds represented by the [Query Response Interval]
92     must be less than the [Query Interval].
93    */
94   zassert(pim_ifp->igmp_query_max_response_time_dsec < pim_ifp->igmp_default_query_interval);
95 
96   if (pim)
97     PIM_IF_DO_PIM(pim_ifp->options);
98   if (igmp)
99     PIM_IF_DO_IGMP(pim_ifp->options);
100 
101 #if 0
102   /* FIXME: Should join? */
103   PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp->options);
104 #endif
105 
106   pim_ifp->igmp_join_list = 0;
107   pim_ifp->igmp_socket_list = 0;
108   pim_ifp->pim_neighbor_list = 0;
109   pim_ifp->pim_ifchannel_list = 0;
110   pim_ifp->pim_generation_id = 0;
111 
112   /* list of struct igmp_sock */
113   pim_ifp->igmp_socket_list = list_new();
114   if (!pim_ifp->igmp_socket_list) {
115     zlog_err("%s %s: failure: igmp_socket_list=list_new()",
116 	     __FILE__, __PRETTY_FUNCTION__);
117     return if_list_clean(pim_ifp);
118   }
119   pim_ifp->igmp_socket_list->del = (void (*)(void *)) igmp_sock_free;
120 
121   /* list of struct pim_neighbor */
122   pim_ifp->pim_neighbor_list = list_new();
123   if (!pim_ifp->pim_neighbor_list) {
124     zlog_err("%s %s: failure: pim_neighbor_list=list_new()",
125 	     __FILE__, __PRETTY_FUNCTION__);
126     return if_list_clean(pim_ifp);
127   }
128   pim_ifp->pim_neighbor_list->del = (void (*)(void *)) pim_neighbor_free;
129 
130   /* list of struct pim_ifchannel */
131   pim_ifp->pim_ifchannel_list = list_new();
132   if (!pim_ifp->pim_ifchannel_list) {
133     zlog_err("%s %s: failure: pim_ifchannel_list=list_new()",
134 	     __FILE__, __PRETTY_FUNCTION__);
135     return if_list_clean(pim_ifp);
136   }
137   pim_ifp->pim_ifchannel_list->del = (void (*)(void *)) pim_ifchannel_free;
138 
139   ifp->info = pim_ifp;
140 
141   pim_sock_reset(ifp);
142 
143   zassert(PIM_IF_TEST_PIM(pim_ifp->options) || PIM_IF_TEST_IGMP(pim_ifp->options));
144 
145   if (PIM_MROUTE_IS_ENABLED) {
146     pim_if_add_vif(ifp);
147   }
148 
149   return pim_ifp;
150 }
151 
pim_if_delete(struct interface * ifp)152 void pim_if_delete(struct interface *ifp)
153 {
154   struct pim_interface *pim_ifp;
155 
156   zassert(ifp);
157   pim_ifp = ifp->info;
158   zassert(pim_ifp);
159 
160   if (pim_ifp->igmp_join_list) {
161     pim_if_igmp_join_del_all(ifp);
162   }
163   zassert(!pim_ifp->igmp_join_list);
164 
165   zassert(pim_ifp->igmp_socket_list);
166   zassert(!listcount(pim_ifp->igmp_socket_list));
167 
168   zassert(pim_ifp->pim_neighbor_list);
169   zassert(!listcount(pim_ifp->pim_neighbor_list));
170 
171   zassert(pim_ifp->pim_ifchannel_list);
172   zassert(!listcount(pim_ifp->pim_ifchannel_list));
173 
174   if (PIM_MROUTE_IS_ENABLED) {
175     pim_if_del_vif(ifp);
176   }
177 
178   list_delete(pim_ifp->igmp_socket_list);
179   list_delete(pim_ifp->pim_neighbor_list);
180   list_delete(pim_ifp->pim_ifchannel_list);
181 
182   XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
183 
184   ifp->info = 0;
185 }
186 
pim_if_update_could_assert(struct interface * ifp)187 void pim_if_update_could_assert(struct interface *ifp)
188 {
189   struct pim_interface *pim_ifp;
190   struct listnode      *node;
191   struct listnode      *next_node;
192   struct pim_ifchannel *ch;
193 
194   pim_ifp = ifp->info;
195   zassert(pim_ifp);
196 
197   for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
198     pim_ifchannel_update_could_assert(ch);
199   }
200 }
201 
pim_if_update_my_assert_metric(struct interface * ifp)202 static void pim_if_update_my_assert_metric(struct interface *ifp)
203 {
204   struct pim_interface *pim_ifp;
205   struct listnode      *node;
206   struct listnode      *next_node;
207   struct pim_ifchannel *ch;
208 
209   pim_ifp = ifp->info;
210   zassert(pim_ifp);
211 
212   for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
213     pim_ifchannel_update_my_assert_metric(ch);
214   }
215 }
216 
pim_addr_change(struct interface * ifp)217 static void pim_addr_change(struct interface *ifp)
218 {
219   struct pim_interface *pim_ifp;
220 
221   pim_ifp = ifp->info;
222   zassert(pim_ifp);
223 
224   pim_if_dr_election(ifp); /* router's own DR Priority (addr) changes -- Done TODO T30 */
225   pim_if_update_join_desired(pim_ifp); /* depends on DR */
226   pim_if_update_could_assert(ifp); /* depends on DR */
227   pim_if_update_my_assert_metric(ifp); /* depends on could_assert */
228   pim_if_update_assert_tracking_desired(ifp); /* depends on DR, join_desired */
229 
230   /*
231     RFC 4601: 4.3.1.  Sending Hello Messages
232 
233     1) Before an interface goes down or changes primary IP address, a
234     Hello message with a zero HoldTime should be sent immediately
235     (with the old IP address if the IP address changed).
236     -- FIXME See CAVEAT C13
237 
238     2) After an interface has changed its IP address, it MUST send a
239     Hello message with its new IP address.
240     -- DONE below
241 
242     3) If an interface changes one of its secondary IP addresses, a
243     Hello message with an updated Address_List option and a non-zero
244     HoldTime should be sent immediately.
245     -- FIXME See TODO T31
246    */
247   pim_ifp->pim_ifstat_hello_sent = 0; /* reset hello counter */
248   if (pim_ifp->pim_sock_fd < 0)
249     return;
250   pim_hello_restart_now(ifp);         /* send hello and restart timer */
251 }
252 
detect_primary_address_change(struct interface * ifp,int force_prim_as_any,const char * caller)253 static int detect_primary_address_change(struct interface *ifp,
254 					 int force_prim_as_any,
255 					 const char *caller)
256 {
257   struct pim_interface *pim_ifp;
258   struct in_addr new_prim_addr;
259   int changed;
260 
261   pim_ifp = ifp->info;
262   if (!pim_ifp)
263     return 0;
264 
265   if (force_prim_as_any)
266     new_prim_addr = qpim_inaddr_any;
267   else
268     new_prim_addr = pim_find_primary_addr(ifp);
269 
270   changed = new_prim_addr.s_addr != pim_ifp->primary_address.s_addr;
271 
272   if (PIM_DEBUG_ZEBRA) {
273     char new_prim_str[100];
274     char old_prim_str[100];
275     pim_inet4_dump("<new?>", new_prim_addr, new_prim_str, sizeof(new_prim_str));
276     pim_inet4_dump("<old?>", pim_ifp->primary_address, old_prim_str, sizeof(old_prim_str));
277     zlog_debug("%s: old=%s new=%s on interface %s: %s",
278 	       __PRETTY_FUNCTION__,
279 	       old_prim_str, new_prim_str, ifp->name,
280 	       changed ? "changed" : "unchanged");
281   }
282 
283   if (changed) {
284     pim_ifp->primary_address = new_prim_addr;
285 
286     if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
287       return changed;
288     }
289 
290     pim_addr_change(ifp);
291   }
292 
293   return changed;
294 }
295 
detect_secondary_address_change(struct interface * ifp,const char * caller)296 static void detect_secondary_address_change(struct interface *ifp,
297 					    const char *caller)
298 {
299   struct pim_interface *pim_ifp;
300   int changed;
301 
302   pim_ifp = ifp->info;
303   if (!pim_ifp)
304     return;
305 
306   changed = 1; /* true */
307   if (PIM_DEBUG_ZEBRA)
308     zlog_debug("FIXME T31 C15 %s: on interface %s: acting on any addr change",
309 	      __PRETTY_FUNCTION__, ifp->name);
310 
311   if (!changed) {
312     return;
313   }
314 
315   if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
316     return;
317   }
318 
319   pim_addr_change(ifp);
320 }
321 
detect_address_change(struct interface * ifp,int force_prim_as_any,const char * caller)322 static void detect_address_change(struct interface *ifp,
323 				 int force_prim_as_any,
324 				 const char *caller)
325 {
326   int prim_changed;
327 
328   prim_changed = detect_primary_address_change(ifp, force_prim_as_any, caller);
329   if (prim_changed) {
330     /* no need to detect secondary change because
331        the reaction would be the same */
332     return;
333   }
334 
335   detect_secondary_address_change(ifp, caller);
336 }
337 
pim_if_addr_add(struct connected * ifc)338 void pim_if_addr_add(struct connected *ifc)
339 {
340   struct pim_interface *pim_ifp;
341   struct interface *ifp;
342   struct in_addr ifaddr;
343 
344   zassert(ifc);
345 
346   ifp = ifc->ifp;
347   zassert(ifp);
348   pim_ifp = ifp->info;
349   if (!pim_ifp)
350     return;
351 
352   if (!if_is_operative(ifp))
353     return;
354 
355   if (PIM_DEBUG_ZEBRA) {
356     char buf[BUFSIZ];
357     prefix2str(ifc->address, buf, BUFSIZ);
358     zlog_debug("%s: %s ifindex=%d connected IP address %s %s",
359 	       __PRETTY_FUNCTION__,
360 	       ifp->name, ifp->ifindex, buf,
361 	       CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
362 	       "secondary" : "primary");
363   }
364 
365   ifaddr = ifc->address->u.prefix4;
366 
367   detect_address_change(ifp, 0, __PRETTY_FUNCTION__);
368 
369   if (PIM_IF_TEST_IGMP(pim_ifp->options)) {
370     struct igmp_sock *igmp;
371 
372     /* lookup IGMP socket */
373     igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
374 				       ifaddr);
375     if (!igmp) {
376       /* if addr new, add IGMP socket */
377       pim_igmp_sock_add(pim_ifp->igmp_socket_list, ifaddr, ifp);
378     }
379   } /* igmp */
380 
381   if (PIM_IF_TEST_PIM(pim_ifp->options)) {
382 
383     /* Interface has a valid primary address ? */
384     if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) {
385 
386       /* Interface has a valid socket ? */
387       if (pim_ifp->pim_sock_fd < 0) {
388 	if (pim_sock_add(ifp)) {
389 	  zlog_warn("Failure creating PIM socket for interface %s",
390 		    ifp->name);
391 	}
392       }
393 
394     }
395   } /* pim */
396 
397   if (PIM_MROUTE_IS_ENABLED) {
398     /*
399       PIM or IGMP is enabled on interface, and there is at least one
400       address assigned, then try to create a vif_index.
401     */
402     if (pim_ifp->mroute_vif_index < 0) {
403       pim_if_add_vif(ifp);
404     }
405   }
406 }
407 
pim_if_addr_del_igmp(struct connected * ifc)408 static void pim_if_addr_del_igmp(struct connected *ifc)
409 {
410   struct pim_interface *pim_ifp = ifc->ifp->info;
411   struct igmp_sock *igmp;
412   struct in_addr ifaddr;
413 
414   if (ifc->address->family != AF_INET) {
415     /* non-IPv4 address */
416     return;
417   }
418 
419   if (!pim_ifp) {
420     /* IGMP not enabled on interface */
421     return;
422   }
423 
424   ifaddr = ifc->address->u.prefix4;
425 
426   /* lookup IGMP socket */
427   igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
428 				     ifaddr);
429   if (igmp) {
430     /* if addr found, del IGMP socket */
431     igmp_sock_delete(igmp);
432   }
433 }
434 
pim_if_addr_del_pim(struct connected * ifc)435 static void pim_if_addr_del_pim(struct connected *ifc)
436 {
437   struct pim_interface *pim_ifp = ifc->ifp->info;
438 
439   if (ifc->address->family != AF_INET) {
440     /* non-IPv4 address */
441     return;
442   }
443 
444   if (!pim_ifp) {
445     /* PIM not enabled on interface */
446     return;
447   }
448 
449   if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) {
450     /* Interface keeps a valid primary address */
451     return;
452   }
453 
454   if (pim_ifp->pim_sock_fd < 0) {
455     /* Interface does not hold a valid socket any longer */
456     return;
457   }
458 
459   /*
460     pim_sock_delete() closes the socket, stops read and timer threads,
461     and kills all neighbors.
462    */
463   pim_sock_delete(ifc->ifp, "last address has been removed from interface");
464 }
465 
pim_if_addr_del(struct connected * ifc,int force_prim_as_any)466 void pim_if_addr_del(struct connected *ifc, int force_prim_as_any)
467 {
468   struct interface *ifp;
469 
470   zassert(ifc);
471   ifp = ifc->ifp;
472   zassert(ifp);
473 
474   if (PIM_DEBUG_ZEBRA) {
475     char buf[BUFSIZ];
476     prefix2str(ifc->address, buf, BUFSIZ);
477     zlog_debug("%s: %s ifindex=%d disconnected IP address %s %s",
478 	       __PRETTY_FUNCTION__,
479 	       ifp->name, ifp->ifindex, buf,
480 	       CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
481 	       "secondary" : "primary");
482   }
483 
484   detect_address_change(ifp, force_prim_as_any, __PRETTY_FUNCTION__);
485 
486   pim_if_addr_del_igmp(ifc);
487   pim_if_addr_del_pim(ifc);
488 }
489 
pim_if_addr_add_all(struct interface * ifp)490 void pim_if_addr_add_all(struct interface *ifp)
491 {
492   struct connected *ifc;
493   struct listnode *node;
494   struct listnode *nextnode;
495 
496   /* PIM/IGMP enabled ? */
497   if (!ifp->info)
498     return;
499 
500   for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
501     struct prefix *p = ifc->address;
502 
503     if (p->family != AF_INET)
504       continue;
505 
506     pim_if_addr_add(ifc);
507   }
508 }
509 
pim_if_addr_del_all(struct interface * ifp)510 void pim_if_addr_del_all(struct interface *ifp)
511 {
512   struct connected *ifc;
513   struct listnode *node;
514   struct listnode *nextnode;
515 
516   /* PIM/IGMP enabled ? */
517   if (!ifp->info)
518     return;
519 
520   for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
521     struct prefix *p = ifc->address;
522 
523     if (p->family != AF_INET)
524       continue;
525 
526     pim_if_addr_del(ifc, 1 /* force_prim_as_any=true */);
527   }
528 }
529 
pim_if_addr_del_all_igmp(struct interface * ifp)530 void pim_if_addr_del_all_igmp(struct interface *ifp)
531 {
532   struct connected *ifc;
533   struct listnode *node;
534   struct listnode *nextnode;
535 
536   /* PIM/IGMP enabled ? */
537   if (!ifp->info)
538     return;
539 
540   for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
541     struct prefix *p = ifc->address;
542 
543     if (p->family != AF_INET)
544       continue;
545 
546     pim_if_addr_del_igmp(ifc);
547   }
548 }
549 
pim_if_addr_del_all_pim(struct interface * ifp)550 void pim_if_addr_del_all_pim(struct interface *ifp)
551 {
552   struct connected *ifc;
553   struct listnode *node;
554   struct listnode *nextnode;
555 
556   /* PIM/IGMP enabled ? */
557   if (!ifp->info)
558     return;
559 
560   for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
561     struct prefix *p = ifc->address;
562 
563     if (p->family != AF_INET)
564       continue;
565 
566     pim_if_addr_del_pim(ifc);
567   }
568 }
569 
find_first_nonsec_addr(struct interface * ifp)570 static struct in_addr find_first_nonsec_addr(struct interface *ifp)
571 {
572   struct connected *ifc;
573   struct listnode *node;
574   struct in_addr addr;
575 
576   for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
577     struct prefix *p = ifc->address;
578 
579     if (p->family != AF_INET)
580       continue;
581 
582     if (PIM_INADDR_IS_ANY(p->u.prefix4)) {
583       zlog_warn("%s: null IPv4 address connected to interface %s",
584 		__PRETTY_FUNCTION__, ifp->name);
585       continue;
586     }
587 
588     if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
589       continue;
590 
591     return p->u.prefix4;
592   }
593 
594   addr.s_addr = PIM_NET_INADDR_ANY;
595 
596   return addr;
597 }
598 
pim_find_primary_addr(struct interface * ifp)599 struct in_addr pim_find_primary_addr(struct interface *ifp)
600 {
601   return find_first_nonsec_addr(ifp);
602 }
603 
604 /*
605   pim_if_add_vif() uses ifindex as vif_index
606 
607   see also pim_if_find_vifindex_by_ifindex()
608  */
pim_if_add_vif(struct interface * ifp)609 int pim_if_add_vif(struct interface *ifp)
610 {
611   struct pim_interface *pim_ifp = ifp->info;
612   struct in_addr ifaddr;
613 
614   zassert(pim_ifp);
615 
616   if (pim_ifp->mroute_vif_index > 0) {
617     zlog_warn("%s: vif_index=%d > 0 on interface %s ifindex=%d",
618 	      __PRETTY_FUNCTION__,
619 	      pim_ifp->mroute_vif_index, ifp->name, ifp->ifindex);
620     return -1;
621   }
622 
623   if (ifp->ifindex < 1) {
624     zlog_warn("%s: ifindex=%d < 1 on interface %s",
625 	      __PRETTY_FUNCTION__,
626 	      ifp->ifindex, ifp->name);
627     return -2;
628   }
629 
630   if (ifp->ifindex >= MAXVIFS) {
631     zlog_warn("%s: ifindex=%d >= MAXVIFS=%d on interface %s",
632 	      __PRETTY_FUNCTION__,
633 	      ifp->ifindex, MAXVIFS, ifp->name);
634     return -3;
635   }
636 
637   ifaddr = pim_ifp->primary_address;
638   if (PIM_INADDR_IS_ANY(ifaddr)) {
639     zlog_warn("%s: could not get address for interface %s ifindex=%d",
640 	      __PRETTY_FUNCTION__,
641 	      ifp->name, ifp->ifindex);
642     return -4;
643   }
644 
645   if (pim_mroute_add_vif(ifp->ifindex, ifaddr)) {
646     /* pim_mroute_add_vif reported error */
647     return -5;
648   }
649 
650   pim_ifp->mroute_vif_index = ifp->ifindex;
651 
652   /*
653     Update highest vif_index
654    */
655   if (pim_ifp->mroute_vif_index > qpim_mroute_oif_highest_vif_index) {
656     qpim_mroute_oif_highest_vif_index = pim_ifp->mroute_vif_index;
657   }
658 
659   return 0;
660 }
661 
iflist_find_highest_vif_index()662 static int iflist_find_highest_vif_index()
663 {
664   struct listnode      *ifnode;
665   struct interface     *ifp;
666   struct pim_interface *pim_ifp;
667   int                   highest_vif_index = -1;
668 
669   for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) {
670     pim_ifp = ifp->info;
671     if (!pim_ifp)
672       continue;
673 
674     if (pim_ifp->mroute_vif_index > highest_vif_index) {
675       highest_vif_index = pim_ifp->mroute_vif_index;
676     }
677   }
678 
679   return highest_vif_index;
680 }
681 
pim_if_del_vif(struct interface * ifp)682 int pim_if_del_vif(struct interface *ifp)
683 {
684   struct pim_interface *pim_ifp = ifp->info;
685   int old_vif_index;
686 
687   if (pim_ifp->mroute_vif_index < 1) {
688     zlog_warn("%s: vif_index=%d < 1 on interface %s ifindex=%d",
689 	      __PRETTY_FUNCTION__,
690 	      pim_ifp->mroute_vif_index, ifp->name, ifp->ifindex);
691     return -1;
692   }
693 
694   if (pim_mroute_del_vif(pim_ifp->mroute_vif_index)) {
695     /* pim_mroute_del_vif reported error */
696     return -2;
697   }
698 
699   /*
700     Update highest vif_index
701    */
702 
703   /* save old vif_index in order to compare with highest below */
704   old_vif_index = pim_ifp->mroute_vif_index;
705 
706   pim_ifp->mroute_vif_index = -1;
707 
708   if (old_vif_index == qpim_mroute_oif_highest_vif_index) {
709     qpim_mroute_oif_highest_vif_index = iflist_find_highest_vif_index();
710   }
711 
712   return 0;
713 }
714 
pim_if_add_vif_all()715 void pim_if_add_vif_all()
716 {
717   struct listnode  *ifnode;
718   struct listnode  *ifnextnode;
719   struct interface *ifp;
720 
721   for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
722     if (!ifp->info)
723       continue;
724 
725     pim_if_add_vif(ifp);
726   }
727 }
728 
pim_if_del_vif_all()729 void pim_if_del_vif_all()
730 {
731   struct listnode  *ifnode;
732   struct listnode  *ifnextnode;
733   struct interface *ifp;
734 
735   for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
736     if (!ifp->info)
737       continue;
738 
739     pim_if_del_vif(ifp);
740   }
741 }
742 
pim_if_find_by_vif_index(int vif_index)743 struct interface *pim_if_find_by_vif_index(int vif_index)
744 {
745   struct listnode  *ifnode;
746   struct interface *ifp;
747 
748   for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) {
749     if (ifp->info) {
750       struct pim_interface *pim_ifp;
751       pim_ifp = ifp->info;
752       if (vif_index == pim_ifp->mroute_vif_index)
753 	return ifp;
754     }
755   }
756 
757   return 0;
758 }
759 
760 /*
761   pim_if_add_vif() uses ifindex as vif_index
762  */
pim_if_find_vifindex_by_ifindex(ifindex_t ifindex)763 int pim_if_find_vifindex_by_ifindex(ifindex_t ifindex)
764 {
765   return ifindex;
766 }
767 
pim_if_lan_delay_enabled(struct interface * ifp)768 int pim_if_lan_delay_enabled(struct interface *ifp)
769 {
770   struct pim_interface *pim_ifp;
771 
772   pim_ifp = ifp->info;
773   zassert(pim_ifp);
774   zassert(pim_ifp->pim_number_of_nonlandelay_neighbors >= 0);
775 
776   return pim_ifp->pim_number_of_nonlandelay_neighbors == 0;
777 }
778 
pim_if_effective_propagation_delay_msec(struct interface * ifp)779 uint16_t pim_if_effective_propagation_delay_msec(struct interface *ifp)
780 {
781   if (pim_if_lan_delay_enabled(ifp)) {
782     struct pim_interface *pim_ifp;
783     pim_ifp = ifp->info;
784     return pim_ifp->pim_neighbors_highest_propagation_delay_msec;
785   }
786   else {
787     return PIM_DEFAULT_PROPAGATION_DELAY_MSEC;
788   }
789 }
790 
pim_if_effective_override_interval_msec(struct interface * ifp)791 uint16_t pim_if_effective_override_interval_msec(struct interface *ifp)
792 {
793   if (pim_if_lan_delay_enabled(ifp)) {
794     struct pim_interface *pim_ifp;
795     pim_ifp = ifp->info;
796     return pim_ifp->pim_neighbors_highest_override_interval_msec;
797   }
798   else {
799     return PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC;
800   }
801 }
802 
pim_if_t_override_msec(struct interface * ifp)803 int pim_if_t_override_msec(struct interface *ifp)
804 {
805   int effective_override_interval_msec;
806   int t_override_msec;
807 
808   effective_override_interval_msec =
809     pim_if_effective_override_interval_msec(ifp);
810 
811   t_override_msec = random() % (effective_override_interval_msec + 1);
812 
813   return t_override_msec;
814 }
815 
pim_if_jp_override_interval_msec(struct interface * ifp)816 uint16_t pim_if_jp_override_interval_msec(struct interface *ifp)
817 {
818   return pim_if_effective_propagation_delay_msec(ifp) +
819     pim_if_effective_override_interval_msec(ifp);
820 }
821 
822 /*
823   RFC 4601: 4.1.6.  State Summarization Macros
824 
825   The function NBR( I, A ) uses information gathered through PIM Hello
826   messages to map the IP address A of a directly connected PIM
827   neighbor router on interface I to the primary IP address of the same
828   router (Section 4.3.4).  The primary IP address of a neighbor is the
829   address that it uses as the source of its PIM Hello messages.
830 */
pim_if_find_neighbor(struct interface * ifp,struct in_addr addr)831 struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp,
832 					  struct in_addr addr)
833 {
834   struct listnode *neighnode;
835   struct pim_neighbor *neigh;
836   struct pim_interface *pim_ifp;
837 
838   zassert(ifp);
839 
840   pim_ifp = ifp->info;
841   if (!pim_ifp) {
842     zlog_warn("%s: multicast not enabled on interface %s",
843 	      __PRETTY_FUNCTION__,
844 	      ifp->name);
845     return 0;
846   }
847 
848   for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) {
849 
850     /* primary address ? */
851     if (neigh->source_addr.s_addr == addr.s_addr)
852       return neigh;
853 
854     /* secondary address ? */
855     if (pim_neighbor_find_secondary(neigh, addr))
856 	return neigh;
857   }
858 
859   if (PIM_DEBUG_PIM_TRACE) {
860     char addr_str[100];
861     pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
862     zlog_debug("%s: neighbor not found for address %s on interface %s",
863 	       __PRETTY_FUNCTION__,
864 	       addr_str, ifp->name);
865   }
866 
867   return 0;
868 }
869 
pim_if_t_suppressed_msec(struct interface * ifp)870 long pim_if_t_suppressed_msec(struct interface *ifp)
871 {
872   struct pim_interface *pim_ifp;
873   long t_suppressed_msec;
874   uint32_t ramount = 0;
875 
876   pim_ifp = ifp->info;
877   zassert(pim_ifp);
878 
879   /* join suppression disabled ? */
880   if (PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options))
881     return 0;
882 
883   /* t_suppressed = t_periodic * rand(1.1, 1.4) */
884   ramount = 1100 + (random() % (1400 - 1100 + 1));
885   t_suppressed_msec = qpim_t_periodic * ramount;
886 
887   return t_suppressed_msec;
888 }
889 
igmp_join_free(struct igmp_join * ij)890 static void igmp_join_free(struct igmp_join *ij)
891 {
892   XFREE(MTYPE_PIM_IGMP_JOIN, ij);
893 }
894 
igmp_join_find(struct list * join_list,struct in_addr group_addr,struct in_addr source_addr)895 static struct igmp_join *igmp_join_find(struct list *join_list,
896 					struct in_addr group_addr,
897 					struct in_addr source_addr)
898 {
899   struct listnode *node;
900   struct igmp_join *ij;
901 
902   zassert(join_list);
903 
904   for (ALL_LIST_ELEMENTS_RO(join_list, node, ij)) {
905     if ((group_addr.s_addr == ij->group_addr.s_addr) &&
906 	(source_addr.s_addr == ij->source_addr.s_addr))
907       return ij;
908   }
909 
910   return 0;
911 }
912 
igmp_join_sock(const char * ifname,ifindex_t ifindex,struct in_addr group_addr,struct in_addr source_addr)913 static int igmp_join_sock(const char *ifname,
914 			  ifindex_t ifindex,
915 			  struct in_addr group_addr,
916 			  struct in_addr source_addr)
917 {
918   int join_fd;
919 
920   join_fd = pim_socket_raw(IPPROTO_IGMP);
921   if (join_fd < 0) {
922     return -1;
923   }
924 
925   if (pim_socket_join_source(join_fd, ifindex, group_addr, source_addr, ifname)) {
926     close(join_fd);
927     return -2;
928   }
929 
930   return join_fd;
931 }
932 
igmp_join_new(struct interface * ifp,struct in_addr group_addr,struct in_addr source_addr)933 static struct igmp_join *igmp_join_new(struct interface *ifp,
934 				       struct in_addr group_addr,
935 				       struct in_addr source_addr)
936 {
937   struct pim_interface *pim_ifp;
938   struct igmp_join *ij;
939   int join_fd;
940 
941   pim_ifp = ifp->info;
942   zassert(pim_ifp);
943 
944   join_fd = igmp_join_sock(ifp->name, ifp->ifindex, group_addr, source_addr);
945   if (join_fd < 0) {
946     char group_str[100];
947     char source_str[100];
948     pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
949     pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
950     zlog_warn("%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
951 	      __PRETTY_FUNCTION__,
952 	      group_str, source_str, ifp->name);
953     return 0;
954   }
955 
956   ij = XMALLOC(MTYPE_PIM_IGMP_JOIN, sizeof(*ij));
957   if (!ij) {
958     char group_str[100];
959     char source_str[100];
960     pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
961     pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
962     zlog_err("%s: XMALLOC(%zu) failure for IGMP group %s source %s on interface %s",
963 	     __PRETTY_FUNCTION__,
964 	     sizeof(*ij), group_str, source_str, ifp->name);
965     close(join_fd);
966     return 0;
967   }
968 
969   ij->sock_fd       = join_fd;
970   ij->group_addr    = group_addr;
971   ij->source_addr   = source_addr;
972   ij->sock_creation = pim_time_monotonic_sec();
973 
974   listnode_add(pim_ifp->igmp_join_list, ij);
975 
976   return ij;
977 }
978 
pim_if_igmp_join_add(struct interface * ifp,struct in_addr group_addr,struct in_addr source_addr)979 int pim_if_igmp_join_add(struct interface *ifp,
980 			 struct in_addr group_addr,
981 			 struct in_addr source_addr)
982 {
983   struct pim_interface *pim_ifp;
984   struct igmp_join *ij;
985 
986   pim_ifp = ifp->info;
987   if (!pim_ifp) {
988     zlog_warn("%s: multicast not enabled on interface %s",
989 	      __PRETTY_FUNCTION__,
990 	      ifp->name);
991     return -1;
992   }
993 
994   if (!pim_ifp->igmp_join_list) {
995     pim_ifp->igmp_join_list = list_new();
996     if (!pim_ifp->igmp_join_list) {
997       zlog_err("%s %s: failure: igmp_join_list=list_new()",
998 	       __FILE__, __PRETTY_FUNCTION__);
999       return -2;
1000     }
1001     pim_ifp->igmp_join_list->del = (void (*)(void *)) igmp_join_free;
1002   }
1003 
1004   ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr);
1005   if (ij) {
1006     char group_str[100];
1007     char source_str[100];
1008     pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1009     pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1010     zlog_warn("%s: can't re-join existing IGMP group %s source %s on interface %s",
1011 	      __PRETTY_FUNCTION__,
1012 	      group_str, source_str, ifp->name);
1013     return -3;
1014   }
1015 
1016   ij = igmp_join_new(ifp, group_addr, source_addr);
1017   if (!ij) {
1018     char group_str[100];
1019     char source_str[100];
1020     pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1021     pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1022     zlog_warn("%s: igmp_join_new() failure for IGMP group %s source %s on interface %s",
1023 	      __PRETTY_FUNCTION__,
1024 	      group_str, source_str, ifp->name);
1025     return -4;
1026   }
1027 
1028   if (PIM_DEBUG_IGMP_EVENTS) {
1029     char group_str[100];
1030     char source_str[100];
1031     pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1032     pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1033     zlog_debug("%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s",
1034 	      __PRETTY_FUNCTION__,
1035 	      source_str, group_str, ifp->name);
1036   }
1037 
1038   return 0;
1039 }
1040 
1041 
1042 
pim_if_igmp_join_del(struct interface * ifp,struct in_addr group_addr,struct in_addr source_addr)1043 int pim_if_igmp_join_del(struct interface *ifp,
1044 			 struct in_addr group_addr,
1045 			 struct in_addr source_addr)
1046 {
1047   struct pim_interface *pim_ifp;
1048   struct igmp_join *ij;
1049 
1050   pim_ifp = ifp->info;
1051   if (!pim_ifp) {
1052     zlog_warn("%s: multicast not enabled on interface %s",
1053 	      __PRETTY_FUNCTION__,
1054 	      ifp->name);
1055     return -1;
1056   }
1057 
1058   if (!pim_ifp->igmp_join_list) {
1059     zlog_warn("%s: no IGMP join on interface %s",
1060 	      __PRETTY_FUNCTION__,
1061 	      ifp->name);
1062     return -2;
1063   }
1064 
1065   ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr);
1066   if (!ij) {
1067     char group_str[100];
1068     char source_str[100];
1069     pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1070     pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1071     zlog_warn("%s: could not find IGMP group %s source %s on interface %s",
1072 	      __PRETTY_FUNCTION__,
1073 	      group_str, source_str, ifp->name);
1074     return -3;
1075   }
1076 
1077   if (close(ij->sock_fd)) {
1078     int e = errno;
1079     char group_str[100];
1080     char source_str[100];
1081     pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1082     pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1083     zlog_warn("%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s",
1084 	      __PRETTY_FUNCTION__,
1085 	      ij->sock_fd, group_str, source_str, ifp->name, e, safe_strerror(e));
1086     /* warning only */
1087   }
1088   listnode_delete(pim_ifp->igmp_join_list, ij);
1089   igmp_join_free(ij);
1090   if (listcount(pim_ifp->igmp_join_list) < 1) {
1091     list_delete(pim_ifp->igmp_join_list);
1092     pim_ifp->igmp_join_list = 0;
1093   }
1094 
1095   return 0;
1096 }
1097 
pim_if_igmp_join_del_all(struct interface * ifp)1098 static void pim_if_igmp_join_del_all(struct interface *ifp)
1099 {
1100   struct pim_interface *pim_ifp;
1101   struct listnode *node;
1102   struct listnode *nextnode;
1103   struct igmp_join *ij;
1104 
1105   pim_ifp = ifp->info;
1106   if (!pim_ifp) {
1107     zlog_warn("%s: multicast not enabled on interface %s",
1108 	      __PRETTY_FUNCTION__,
1109 	      ifp->name);
1110     return;
1111   }
1112 
1113   if (!pim_ifp->igmp_join_list)
1114     return;
1115 
1116   for (ALL_LIST_ELEMENTS(pim_ifp->igmp_join_list, node, nextnode, ij))
1117     pim_if_igmp_join_del(ifp, ij->group_addr, ij->source_addr);
1118 }
1119 
1120 /*
1121   RFC 4601
1122 
1123   Transitions from "I am Assert Loser" State
1124 
1125   Current Winner's GenID Changes or NLT Expires
1126 
1127   The Neighbor Liveness Timer associated with the current winner
1128   expires or we receive a Hello message from the current winner
1129   reporting a different GenID from the one it previously reported.
1130   This indicates that the current winner's interface or router has
1131   gone down (and may have come back up), and so we must assume it no
1132   longer knows it was the winner.
1133  */
pim_if_assert_on_neighbor_down(struct interface * ifp,struct in_addr neigh_addr)1134 void pim_if_assert_on_neighbor_down(struct interface *ifp,
1135 				    struct in_addr neigh_addr)
1136 {
1137   struct pim_interface *pim_ifp;
1138   struct listnode      *node;
1139   struct listnode      *next_node;
1140   struct pim_ifchannel *ch;
1141 
1142   pim_ifp = ifp->info;
1143   zassert(pim_ifp);
1144 
1145   for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
1146     /* Is (S,G,I) assert loser ? */
1147     if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER)
1148       continue;
1149     /* Dead neighbor was winner ? */
1150     if (ch->ifassert_winner.s_addr != neigh_addr.s_addr)
1151       continue;
1152 
1153     assert_action_a5(ch);
1154   }
1155 }
1156 
pim_if_update_join_desired(struct pim_interface * pim_ifp)1157 void pim_if_update_join_desired(struct pim_interface *pim_ifp)
1158 {
1159   struct listnode      *ch_node;
1160   struct pim_ifchannel *ch;
1161 
1162   /* clear off flag from interface's upstreams */
1163   for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
1164     PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(ch->upstream->flags);
1165   }
1166 
1167   /* scan per-interface (S,G,I) state on this I interface */
1168   for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
1169     struct pim_upstream *up = ch->upstream;
1170 
1171     if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up->flags))
1172       continue;
1173 
1174     /* update join_desired for the global (S,G) state */
1175     pim_upstream_update_join_desired(up);
1176     PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up->flags);
1177   }
1178 }
1179 
pim_if_update_assert_tracking_desired(struct interface * ifp)1180 void pim_if_update_assert_tracking_desired(struct interface *ifp)
1181 {
1182   struct pim_interface *pim_ifp;
1183   struct listnode      *node;
1184   struct listnode      *next_node;
1185   struct pim_ifchannel *ch;
1186 
1187   pim_ifp = ifp->info;
1188   if (!pim_ifp)
1189     return;
1190 
1191   for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
1192     pim_ifchannel_update_assert_tracking_desired(ch);
1193   }
1194 }
1195