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