]> git.sommitrealweird.co.uk Git - quagga-debian.git/blob - pimd/pim_iface.c
New upstream release and new maintainer
[quagga-debian.git] / pimd / pim_iface.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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  */
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
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
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
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
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
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  */
763 int pim_if_find_vifindex_by_ifindex(ifindex_t ifindex)
764 {
765   return ifindex;
766 }
767
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
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
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
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
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 */
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
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
890 static void igmp_join_free(struct igmp_join *ij)
891 {
892   XFREE(MTYPE_PIM_IGMP_JOIN, ij);
893 }
894
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
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
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
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
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
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  */
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
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
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 }