]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_iface.c
*: update hash_create(), hash_create_size()
[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 along
15 * with this program; see the file COPYING; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include <zebra.h>
20
21 #include "if.h"
22 #include "log.h"
23 #include "vty.h"
24 #include "memory.h"
25 #include "prefix.h"
26 #include "vrf.h"
27 #include "linklist.h"
28 #include "plist.h"
29 #include "hash.h"
30
31 #include "pimd.h"
32 #include "pim_zebra.h"
33 #include "pim_iface.h"
34 #include "pim_igmp.h"
35 #include "pim_mroute.h"
36 #include "pim_oil.h"
37 #include "pim_str.h"
38 #include "pim_pim.h"
39 #include "pim_neighbor.h"
40 #include "pim_ifchannel.h"
41 #include "pim_sock.h"
42 #include "pim_time.h"
43 #include "pim_ssmpingd.h"
44 #include "pim_rp.h"
45 #include "pim_nht.h"
46
47 struct interface *pim_regiface = NULL;
48 struct list *pim_ifchannel_list = NULL;
49 static int pim_iface_vif_index[MAXVIFS];
50
51 static void pim_if_igmp_join_del_all(struct interface *ifp);
52 static int igmp_join_sock(const char *ifname, ifindex_t ifindex,
53 struct in_addr group_addr, struct in_addr source_addr);
54
55 void
56 pim_if_init (void)
57 {
58 int i;
59
60 for (i = 0; i < MAXVIFS; i++)
61 pim_iface_vif_index[i] = 0;
62
63 pim_ifchannel_list = list_new();
64 pim_ifchannel_list->cmp = (int (*)(void *, void *))pim_ifchannel_compare;
65 }
66
67 void
68 pim_if_terminate (void)
69 {
70 if (pim_ifchannel_list)
71 list_free (pim_ifchannel_list);
72 }
73
74 static void *if_list_clean(struct pim_interface *pim_ifp)
75 {
76 if (pim_ifp->igmp_join_list) {
77 list_delete(pim_ifp->igmp_join_list);
78 }
79
80 if (pim_ifp->igmp_socket_list) {
81 list_delete(pim_ifp->igmp_socket_list);
82 }
83
84 if (pim_ifp->pim_neighbor_list) {
85 list_delete(pim_ifp->pim_neighbor_list);
86 }
87
88 if (pim_ifp->upstream_switch_list)
89 list_delete(pim_ifp->upstream_switch_list);
90
91 if (pim_ifp->pim_ifchannel_list) {
92 list_delete(pim_ifp->pim_ifchannel_list);
93 }
94
95 if (pim_ifp->pim_ifchannel_hash)
96 hash_free(pim_ifp->pim_ifchannel_hash);
97
98 XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
99
100 return 0;
101 }
102
103 struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
104 {
105 struct pim_interface *pim_ifp;
106
107 zassert(ifp);
108 zassert(!ifp->info);
109
110 pim_ifp = XCALLOC(MTYPE_PIM_INTERFACE, sizeof(*pim_ifp));
111 if (!pim_ifp) {
112 zlog_err("PIM XCALLOC(%zu) failure", sizeof(*pim_ifp));
113 return 0;
114 }
115
116 pim_ifp->options = 0;
117 pim_ifp->mroute_vif_index = -1;
118
119 pim_ifp->igmp_version = IGMP_DEFAULT_VERSION;
120 pim_ifp->igmp_default_robustness_variable = IGMP_DEFAULT_ROBUSTNESS_VARIABLE;
121 pim_ifp->igmp_default_query_interval = IGMP_GENERAL_QUERY_INTERVAL;
122 pim_ifp->igmp_query_max_response_time_dsec = IGMP_QUERY_MAX_RESPONSE_TIME_DSEC;
123 pim_ifp->igmp_specific_query_max_response_time_dsec = IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC;
124
125 /*
126 RFC 3376: 8.3. Query Response Interval
127 The number of seconds represented by the [Query Response Interval]
128 must be less than the [Query Interval].
129 */
130 zassert(pim_ifp->igmp_query_max_response_time_dsec < pim_ifp->igmp_default_query_interval);
131
132 if (pim)
133 PIM_IF_DO_PIM(pim_ifp->options);
134 if (igmp)
135 PIM_IF_DO_IGMP(pim_ifp->options);
136
137 PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp->options);
138
139 pim_ifp->igmp_join_list = NULL;
140 pim_ifp->igmp_socket_list = NULL;
141 pim_ifp->pim_neighbor_list = NULL;
142 pim_ifp->upstream_switch_list = NULL;
143 pim_ifp->pim_ifchannel_list = NULL;
144 pim_ifp->pim_ifchannel_hash = NULL;
145 pim_ifp->pim_generation_id = 0;
146
147 /* list of struct igmp_sock */
148 pim_ifp->igmp_socket_list = list_new();
149 if (!pim_ifp->igmp_socket_list) {
150 zlog_err("%s %s: failure: igmp_socket_list=list_new()",
151 __FILE__, __PRETTY_FUNCTION__);
152 return if_list_clean(pim_ifp);
153 }
154 pim_ifp->igmp_socket_list->del = (void (*)(void *)) igmp_sock_free;
155
156 /* list of struct pim_neighbor */
157 pim_ifp->pim_neighbor_list = list_new();
158 if (!pim_ifp->pim_neighbor_list) {
159 zlog_err("%s %s: failure: pim_neighbor_list=list_new()",
160 __FILE__, __PRETTY_FUNCTION__);
161 return if_list_clean(pim_ifp);
162 }
163 pim_ifp->pim_neighbor_list->del = (void (*)(void *)) pim_neighbor_free;
164
165 pim_ifp->upstream_switch_list = list_new();
166 if (!pim_ifp->upstream_switch_list) {
167 zlog_err("%s %s: failure: upstream_switch_list=list_new()",
168 __FILE__, __PRETTY_FUNCTION__);
169 return if_list_clean(pim_ifp);
170 }
171
172 /* list of struct pim_ifchannel */
173 pim_ifp->pim_ifchannel_list = list_new();
174 if (!pim_ifp->pim_ifchannel_list) {
175 zlog_err("%s %s: failure: pim_ifchannel_list=list_new()",
176 __FILE__, __PRETTY_FUNCTION__);
177 return if_list_clean(pim_ifp);
178 }
179 pim_ifp->pim_ifchannel_list->del = (void (*)(void *)) pim_ifchannel_free;
180 pim_ifp->pim_ifchannel_list->cmp = (int (*)(void *, void *)) pim_ifchannel_compare;
181
182 pim_ifp->pim_ifchannel_hash = hash_create (pim_ifchannel_hash_key,
183 pim_ifchannel_equal, NULL);
184
185 ifp->info = pim_ifp;
186
187 pim_sock_reset(ifp);
188
189 pim_if_add_vif(ifp);
190
191 return pim_ifp;
192 }
193
194 void pim_if_delete(struct interface *ifp)
195 {
196 struct pim_interface *pim_ifp;
197
198 zassert(ifp);
199 pim_ifp = ifp->info;
200 zassert(pim_ifp);
201
202 if (pim_ifp->igmp_join_list) {
203 pim_if_igmp_join_del_all(ifp);
204 }
205
206 pim_ifchannel_delete_all (ifp);
207 igmp_sock_delete_all (ifp);
208
209 pim_neighbor_delete_all (ifp, "Interface removed from configuration");
210
211 pim_if_del_vif(ifp);
212
213 list_delete(pim_ifp->igmp_socket_list);
214 list_delete(pim_ifp->pim_neighbor_list);
215 list_delete(pim_ifp->upstream_switch_list);
216 list_delete(pim_ifp->pim_ifchannel_list);
217
218 hash_free (pim_ifp->pim_ifchannel_hash);
219
220 XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
221
222 ifp->info = NULL;
223 }
224
225 void pim_if_update_could_assert(struct interface *ifp)
226 {
227 struct pim_interface *pim_ifp;
228 struct listnode *node;
229 struct listnode *next_node;
230 struct pim_ifchannel *ch;
231
232 pim_ifp = ifp->info;
233 zassert(pim_ifp);
234
235 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
236 pim_ifchannel_update_could_assert(ch);
237 }
238 }
239
240 static void pim_if_update_my_assert_metric(struct interface *ifp)
241 {
242 struct pim_interface *pim_ifp;
243 struct listnode *node;
244 struct listnode *next_node;
245 struct pim_ifchannel *ch;
246
247 pim_ifp = ifp->info;
248 zassert(pim_ifp);
249
250 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
251 pim_ifchannel_update_my_assert_metric(ch);
252 }
253 }
254
255 static void pim_addr_change(struct interface *ifp)
256 {
257 struct pim_interface *pim_ifp;
258
259 pim_ifp = ifp->info;
260 zassert(pim_ifp);
261
262 pim_if_dr_election(ifp); /* router's own DR Priority (addr) changes -- Done TODO T30 */
263 pim_if_update_join_desired(pim_ifp); /* depends on DR */
264 pim_if_update_could_assert(ifp); /* depends on DR */
265 pim_if_update_my_assert_metric(ifp); /* depends on could_assert */
266 pim_if_update_assert_tracking_desired(ifp); /* depends on DR, join_desired */
267
268 /*
269 RFC 4601: 4.3.1. Sending Hello Messages
270
271 1) Before an interface goes down or changes primary IP address, a
272 Hello message with a zero HoldTime should be sent immediately
273 (with the old IP address if the IP address changed).
274 -- FIXME See CAVEAT C13
275
276 2) After an interface has changed its IP address, it MUST send a
277 Hello message with its new IP address.
278 -- DONE below
279
280 3) If an interface changes one of its secondary IP addresses, a
281 Hello message with an updated Address_List option and a non-zero
282 HoldTime should be sent immediately.
283 -- FIXME See TODO T31
284 */
285 pim_ifp->pim_ifstat_hello_sent = 0; /* reset hello counter */
286 if (pim_ifp->pim_sock_fd < 0)
287 return;
288 pim_hello_restart_now(ifp); /* send hello and restart timer */
289 }
290
291 static int detect_primary_address_change(struct interface *ifp,
292 int force_prim_as_any,
293 const char *caller)
294 {
295 struct pim_interface *pim_ifp = ifp->info;
296 struct in_addr new_prim_addr;
297 int changed;
298
299 if (force_prim_as_any)
300 new_prim_addr.s_addr = INADDR_ANY;
301 else
302 new_prim_addr = pim_find_primary_addr(ifp);
303
304 changed = new_prim_addr.s_addr != pim_ifp->primary_address.s_addr;
305
306 if (PIM_DEBUG_ZEBRA) {
307 char new_prim_str[INET_ADDRSTRLEN];
308 char old_prim_str[INET_ADDRSTRLEN];
309 pim_inet4_dump("<new?>", new_prim_addr, new_prim_str, sizeof(new_prim_str));
310 pim_inet4_dump("<old?>", pim_ifp->primary_address, old_prim_str, sizeof(old_prim_str));
311 zlog_debug("%s: old=%s new=%s on interface %s: %s",
312 __PRETTY_FUNCTION__,
313 old_prim_str, new_prim_str, ifp->name,
314 changed ? "changed" : "unchanged");
315 }
316
317 if (changed) {
318 pim_ifp->primary_address = new_prim_addr;
319 }
320
321 return changed;
322 }
323
324 static int pim_sec_addr_comp(const void *p1, const void *p2)
325 {
326 const struct pim_secondary_addr *sec1 = p1;
327 const struct pim_secondary_addr *sec2 = p2;
328
329 if (sec1->addr.family == AF_INET &&
330 sec2->addr.family == AF_INET6)
331 return -1;
332
333 if (sec1->addr.family == AF_INET6 &&
334 sec2->addr.family == AF_INET)
335 return 1;
336
337 if (sec1->addr.family == AF_INET)
338 {
339 if (ntohl(sec1->addr.u.prefix4.s_addr) < ntohl(sec2->addr.u.prefix4.s_addr))
340 return -1;
341
342 if (ntohl(sec1->addr.u.prefix4.s_addr) > ntohl(sec2->addr.u.prefix4.s_addr))
343 return 1;
344 }
345 else
346 {
347 return memcmp (&sec1->addr.u.prefix6,
348 &sec2->addr.u.prefix6,
349 sizeof (struct in6_addr));
350 }
351
352 return 0;
353 }
354
355 static void pim_sec_addr_free(struct pim_secondary_addr *sec_addr)
356 {
357 XFREE(MTYPE_PIM_SEC_ADDR, sec_addr);
358 }
359
360 static struct pim_secondary_addr *
361 pim_sec_addr_find(struct pim_interface *pim_ifp, struct prefix *addr)
362 {
363 struct pim_secondary_addr *sec_addr;
364 struct listnode *node;
365
366 if (!pim_ifp->sec_addr_list) {
367 return NULL;
368 }
369
370 for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
371 if (prefix_cmp(&sec_addr->addr, addr)) {
372 return sec_addr;
373 }
374 }
375
376 return NULL;
377 }
378
379 static void pim_sec_addr_del(struct pim_interface *pim_ifp,
380 struct pim_secondary_addr *sec_addr)
381 {
382 listnode_delete(pim_ifp->sec_addr_list, sec_addr);
383 pim_sec_addr_free(sec_addr);
384 }
385
386 static int pim_sec_addr_add(struct pim_interface *pim_ifp, struct prefix *addr)
387 {
388 int changed = 0;
389 struct pim_secondary_addr *sec_addr;
390
391 sec_addr = pim_sec_addr_find(pim_ifp, addr);
392 if (sec_addr) {
393 sec_addr->flags &= ~PIM_SEC_ADDRF_STALE;
394 return changed;
395 }
396
397 if (!pim_ifp->sec_addr_list) {
398 pim_ifp->sec_addr_list = list_new();
399 pim_ifp->sec_addr_list->del = (void (*)(void *))pim_sec_addr_free;
400 pim_ifp->sec_addr_list->cmp = (int (*)(void *, void *))pim_sec_addr_comp;
401 }
402
403 sec_addr = XCALLOC(MTYPE_PIM_SEC_ADDR, sizeof(*sec_addr));
404 if (!sec_addr) {
405 if (list_isempty(pim_ifp->sec_addr_list)) {
406 list_free(pim_ifp->sec_addr_list);
407 pim_ifp->sec_addr_list = NULL;
408 }
409 return changed;
410 }
411
412 changed = 1;
413 sec_addr->addr = *addr;
414 listnode_add_sort(pim_ifp->sec_addr_list, sec_addr);
415
416 return changed;
417 }
418
419 static int pim_sec_addr_del_all(struct pim_interface *pim_ifp)
420 {
421 int changed = 0;
422
423 if (!pim_ifp->sec_addr_list) {
424 return changed;
425 }
426 if (!list_isempty(pim_ifp->sec_addr_list)) {
427 changed = 1;
428 /* remove all nodes and free up the list itself */
429 list_delete_all_node(pim_ifp->sec_addr_list);
430 list_free(pim_ifp->sec_addr_list);
431 pim_ifp->sec_addr_list = NULL;
432 }
433
434 return changed;
435 }
436
437 static int pim_sec_addr_update(struct interface *ifp)
438 {
439 struct pim_interface *pim_ifp = ifp->info;
440 struct connected *ifc;
441 struct listnode *node;
442 struct listnode *nextnode;
443 struct pim_secondary_addr *sec_addr;
444 int changed = 0;
445
446 if (pim_ifp->sec_addr_list) {
447 for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
448 sec_addr->flags |= PIM_SEC_ADDRF_STALE;
449 }
450 }
451
452 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
453 struct prefix *p = ifc->address;
454
455 if (PIM_INADDR_IS_ANY(p->u.prefix4)) {
456 continue;
457 }
458
459 if (pim_ifp->primary_address.s_addr == p->u.prefix4.s_addr) {
460 /* don't add the primary address into the secondary address list */
461 continue;
462 }
463
464 if (pim_sec_addr_add(pim_ifp, p)) {
465 changed = 1;
466 }
467 }
468
469 if (pim_ifp->sec_addr_list) {
470 /* Drop stale entries */
471 for (ALL_LIST_ELEMENTS(pim_ifp->sec_addr_list, node, nextnode, sec_addr)) {
472 if (sec_addr->flags & PIM_SEC_ADDRF_STALE) {
473 pim_sec_addr_del(pim_ifp, sec_addr);
474 changed = 1;
475 }
476 }
477
478 /* If the list went empty free it up */
479 if (list_isempty(pim_ifp->sec_addr_list)) {
480 list_free(pim_ifp->sec_addr_list);
481 pim_ifp->sec_addr_list = NULL;
482 }
483 }
484
485 return changed;
486 }
487
488 static int detect_secondary_address_change(struct interface *ifp,
489 int force_prim_as_any,
490 const char *caller)
491 {
492 struct pim_interface *pim_ifp = ifp->info;
493 int changed = 0;
494
495 if (force_prim_as_any) {
496 /* if primary address is being forced to zero just flush the
497 * secondary address list */
498 changed = pim_sec_addr_del_all(pim_ifp);
499 } else {
500 /* re-evaluate the secondary address list */
501 changed = pim_sec_addr_update(ifp);
502 }
503
504 return changed;
505 }
506
507 static void detect_address_change(struct interface *ifp,
508 int force_prim_as_any,
509 const char *caller)
510 {
511 int changed = 0;
512 struct pim_interface *pim_ifp;
513
514 pim_ifp = ifp->info;
515 if (!pim_ifp)
516 return;
517
518 if (detect_primary_address_change(ifp, force_prim_as_any, caller)) {
519 changed = 1;
520 }
521
522 if (detect_secondary_address_change(ifp, force_prim_as_any, caller)) {
523 changed = 1;
524 }
525
526
527 if (changed) {
528 if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
529 return;
530 }
531
532 pim_addr_change(ifp);
533 }
534
535 /* XXX: if we have unnumbered interfaces we need to run detect address
536 * address change on all of them when the lo address changes */
537 }
538
539 int pim_update_source_set(struct interface *ifp, struct in_addr source)
540 {
541 struct pim_interface *pim_ifp = ifp->info;
542
543 if (!pim_ifp) {
544 return PIM_IFACE_NOT_FOUND;
545 }
546
547 if (pim_ifp->update_source.s_addr == source.s_addr) {
548 return PIM_UPDATE_SOURCE_DUP;
549 }
550
551 pim_ifp->update_source = source;
552 detect_address_change(ifp, 0 /* force_prim_as_any */,
553 __PRETTY_FUNCTION__);
554
555 return PIM_SUCCESS;
556 }
557
558 void pim_if_addr_add(struct connected *ifc)
559 {
560 struct pim_interface *pim_ifp;
561 struct interface *ifp;
562 struct in_addr ifaddr;
563
564 zassert(ifc);
565
566 ifp = ifc->ifp;
567 zassert(ifp);
568 pim_ifp = ifp->info;
569 if (!pim_ifp)
570 return;
571
572 if (!if_is_operative(ifp))
573 return;
574
575 if (PIM_DEBUG_ZEBRA) {
576 char buf[BUFSIZ];
577 prefix2str(ifc->address, buf, BUFSIZ);
578 zlog_debug("%s: %s ifindex=%d connected IP address %s %s",
579 __PRETTY_FUNCTION__,
580 ifp->name, ifp->ifindex, buf,
581 CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
582 "secondary" : "primary");
583 }
584
585 ifaddr = ifc->address->u.prefix4;
586
587 detect_address_change(ifp, 0, __PRETTY_FUNCTION__);
588
589 if (ifc->address->family != AF_INET)
590 return;
591
592 if (PIM_IF_TEST_IGMP(pim_ifp->options)) {
593 struct igmp_sock *igmp;
594
595 /* lookup IGMP socket */
596 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
597 ifaddr);
598 if (!igmp) {
599 /* if addr new, add IGMP socket */
600 pim_igmp_sock_add(pim_ifp->igmp_socket_list, ifaddr, ifp);
601 }
602
603 /* Replay Static IGMP groups */
604 if (pim_ifp->igmp_join_list)
605 {
606 struct listnode *node;
607 struct listnode *nextnode;
608 struct igmp_join *ij;
609 int join_fd;
610
611 for (ALL_LIST_ELEMENTS (pim_ifp->igmp_join_list, node, nextnode, ij))
612 {
613 /* Close socket and reopen with Source and Group */
614 close(ij->sock_fd);
615 join_fd = igmp_join_sock(ifp->name, ifp->ifindex, ij->group_addr, ij->source_addr);
616 if (join_fd < 0)
617 {
618 char group_str[INET_ADDRSTRLEN];
619 char source_str[INET_ADDRSTRLEN];
620 pim_inet4_dump("<grp?>", ij->group_addr, group_str, sizeof(group_str));
621 pim_inet4_dump("<src?>", ij->source_addr, source_str, sizeof(source_str));
622 zlog_warn("%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
623 __PRETTY_FUNCTION__,
624 group_str, source_str, ifp->name);
625 /* warning only */
626 }
627 else
628 ij->sock_fd = join_fd;
629 }
630 }
631 } /* igmp */
632
633 if (PIM_IF_TEST_PIM(pim_ifp->options))
634 {
635
636 if (PIM_INADDR_ISNOT_ANY (pim_ifp->primary_address))
637 {
638
639 /* Interface has a valid socket ? */
640 if (pim_ifp->pim_sock_fd < 0)
641 {
642 if (pim_sock_add (ifp))
643 {
644 zlog_warn ("Failure creating PIM socket for interface %s",
645 ifp->name);
646 }
647 }
648 struct pim_nexthop_cache *pnc = NULL;
649 struct pim_rpf rpf;
650 struct zclient *zclient = NULL;
651
652 zclient = pim_zebra_zclient_get ();
653 /* RP config might come prior to (local RP's interface) IF UP event.
654 In this case, pnc would not have pim enabled nexthops.
655 Once Interface is UP and pim info is available, reregister
656 with RNH address to receive update and add the interface as nexthop. */
657 memset (&rpf, 0, sizeof (struct pim_rpf));
658 rpf.rpf_addr.family = AF_INET;
659 rpf.rpf_addr.prefixlen = IPV4_MAX_BITLEN;
660 rpf.rpf_addr.u.prefix4 = ifc->address->u.prefix4;
661 pnc = pim_nexthop_cache_find (&rpf);
662 if (pnc)
663 pim_sendmsg_zebra_rnh (zclient, pnc,
664 ZEBRA_NEXTHOP_REGISTER);
665 }
666 } /* pim */
667
668 /*
669 PIM or IGMP is enabled on interface, and there is at least one
670 address assigned, then try to create a vif_index.
671 */
672 if (pim_ifp->mroute_vif_index < 0) {
673 pim_if_add_vif(ifp);
674 }
675 pim_ifchannel_scan_forward_start (ifp);
676 }
677
678 static void pim_if_addr_del_igmp(struct connected *ifc)
679 {
680 struct pim_interface *pim_ifp = ifc->ifp->info;
681 struct igmp_sock *igmp;
682 struct in_addr ifaddr;
683
684 if (ifc->address->family != AF_INET) {
685 /* non-IPv4 address */
686 return;
687 }
688
689 if (!pim_ifp) {
690 /* IGMP not enabled on interface */
691 return;
692 }
693
694 ifaddr = ifc->address->u.prefix4;
695
696 /* lookup IGMP socket */
697 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
698 ifaddr);
699 if (igmp) {
700 /* if addr found, del IGMP socket */
701 igmp_sock_delete(igmp);
702 }
703 }
704
705 static void pim_if_addr_del_pim(struct connected *ifc)
706 {
707 struct pim_interface *pim_ifp = ifc->ifp->info;
708
709 if (ifc->address->family != AF_INET) {
710 /* non-IPv4 address */
711 return;
712 }
713
714 if (!pim_ifp) {
715 /* PIM not enabled on interface */
716 return;
717 }
718
719 if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) {
720 /* Interface keeps a valid primary address */
721 return;
722 }
723
724 if (pim_ifp->pim_sock_fd < 0) {
725 /* Interface does not hold a valid socket any longer */
726 return;
727 }
728
729 /*
730 pim_sock_delete() closes the socket, stops read and timer threads,
731 and kills all neighbors.
732 */
733 pim_sock_delete(ifc->ifp, "last address has been removed from interface");
734 }
735
736 void pim_if_addr_del(struct connected *ifc, int force_prim_as_any)
737 {
738 struct interface *ifp;
739
740 zassert(ifc);
741 ifp = ifc->ifp;
742 zassert(ifp);
743
744 if (ifc->address->family != AF_INET)
745 return;
746
747 if (PIM_DEBUG_ZEBRA) {
748 char buf[BUFSIZ];
749 prefix2str(ifc->address, buf, BUFSIZ);
750 zlog_debug("%s: %s ifindex=%d disconnected IP address %s %s",
751 __PRETTY_FUNCTION__,
752 ifp->name, ifp->ifindex, buf,
753 CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
754 "secondary" : "primary");
755 }
756
757 detect_address_change(ifp, force_prim_as_any, __PRETTY_FUNCTION__);
758
759 pim_if_addr_del_igmp(ifc);
760 pim_if_addr_del_pim(ifc);
761 }
762
763 void pim_if_addr_add_all(struct interface *ifp)
764 {
765 struct connected *ifc;
766 struct listnode *node;
767 struct listnode *nextnode;
768 int v4_addrs = 0;
769 int v6_addrs = 0;
770 struct pim_interface *pim_ifp = ifp->info;
771
772
773 /* PIM/IGMP enabled ? */
774 if (!pim_ifp)
775 return;
776
777 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
778 struct prefix *p = ifc->address;
779
780 if (p->family != AF_INET)
781 v6_addrs++;
782 else
783 v4_addrs++;
784 pim_if_addr_add(ifc);
785 }
786
787 if (!v4_addrs && v6_addrs && !if_is_loopback (ifp))
788 {
789 if (PIM_IF_TEST_PIM(pim_ifp->options)) {
790
791 /* Interface has a valid primary address ? */
792 if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) {
793
794 /* Interface has a valid socket ? */
795 if (pim_ifp->pim_sock_fd < 0) {
796 if (pim_sock_add(ifp)) {
797 zlog_warn("Failure creating PIM socket for interface %s",
798 ifp->name);
799 }
800 }
801
802 }
803 } /* pim */
804 }
805 /*
806 * PIM or IGMP is enabled on interface, and there is at least one
807 * address assigned, then try to create a vif_index.
808 */
809 if (pim_ifp->mroute_vif_index < 0) {
810 pim_if_add_vif(ifp);
811 }
812 pim_ifchannel_scan_forward_start (ifp);
813
814 pim_rp_setup();
815 pim_rp_check_on_if_add(pim_ifp);
816 }
817
818 void pim_if_addr_del_all(struct interface *ifp)
819 {
820 struct connected *ifc;
821 struct listnode *node;
822 struct listnode *nextnode;
823
824 /* PIM/IGMP enabled ? */
825 if (!ifp->info)
826 return;
827
828 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
829 struct prefix *p = ifc->address;
830
831 if (p->family != AF_INET)
832 continue;
833
834 pim_if_addr_del(ifc, 1 /* force_prim_as_any=true */);
835 }
836
837 pim_rp_setup();
838 pim_i_am_rp_re_evaluate();
839 }
840
841 void pim_if_addr_del_all_igmp(struct interface *ifp)
842 {
843 struct connected *ifc;
844 struct listnode *node;
845 struct listnode *nextnode;
846
847 /* PIM/IGMP enabled ? */
848 if (!ifp->info)
849 return;
850
851 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
852 struct prefix *p = ifc->address;
853
854 if (p->family != AF_INET)
855 continue;
856
857 pim_if_addr_del_igmp(ifc);
858 }
859 }
860
861 void pim_if_addr_del_all_pim(struct interface *ifp)
862 {
863 struct connected *ifc;
864 struct listnode *node;
865 struct listnode *nextnode;
866
867 /* PIM/IGMP enabled ? */
868 if (!ifp->info)
869 return;
870
871 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
872 struct prefix *p = ifc->address;
873
874 if (p->family != AF_INET)
875 continue;
876
877 pim_if_addr_del_pim(ifc);
878 }
879 }
880
881 struct in_addr
882 pim_find_primary_addr (struct interface *ifp)
883 {
884 struct connected *ifc;
885 struct listnode *node;
886 struct in_addr addr;
887 int v4_addrs = 0;
888 int v6_addrs = 0;
889 struct pim_interface *pim_ifp = ifp->info;
890
891 if (pim_ifp && PIM_INADDR_ISNOT_ANY(pim_ifp->update_source)) {
892 return pim_ifp->update_source;
893 }
894
895 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
896 struct prefix *p = ifc->address;
897
898 if (p->family != AF_INET)
899 {
900 v6_addrs++;
901 continue;
902 }
903
904 if (PIM_INADDR_IS_ANY(p->u.prefix4)) {
905 zlog_warn("%s: null IPv4 address connected to interface %s",
906 __PRETTY_FUNCTION__, ifp->name);
907 continue;
908 }
909
910 v4_addrs++;
911
912 if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
913 continue;
914
915 return p->u.prefix4;
916 }
917
918 /*
919 * If we have no v4_addrs and v6 is configured
920 * We probably are using unnumbered
921 * So let's grab the loopbacks v4 address
922 * and use that as the primary address
923 */
924 if (!v4_addrs && v6_addrs && !if_is_loopback (ifp))
925 {
926 struct interface *lo_ifp;
927 lo_ifp = if_lookup_by_name ("lo", VRF_DEFAULT);
928 if (lo_ifp)
929 return pim_find_primary_addr (lo_ifp);
930 }
931
932 addr.s_addr = PIM_NET_INADDR_ANY;
933
934 return addr;
935 }
936
937 static int
938 pim_iface_next_vif_index (struct interface *ifp)
939 {
940 int i;
941 /*
942 * The pimreg vif is always going to be in index 0
943 * of the table.
944 */
945 if (ifp->ifindex == PIM_OIF_PIM_REGISTER_VIF)
946 return 0;
947
948 for (i = 1 ; i < MAXVIFS; i++)
949 {
950 if (pim_iface_vif_index[i] == 0)
951 return i;
952 }
953 return MAXVIFS;
954 }
955
956 /*
957 pim_if_add_vif() uses ifindex as vif_index
958
959 see also pim_if_find_vifindex_by_ifindex()
960 */
961 int pim_if_add_vif(struct interface *ifp)
962 {
963 struct pim_interface *pim_ifp = ifp->info;
964 struct in_addr ifaddr;
965 unsigned char flags = 0;
966
967 zassert(pim_ifp);
968
969 if (pim_ifp->mroute_vif_index > 0) {
970 zlog_warn("%s: vif_index=%d > 0 on interface %s ifindex=%d",
971 __PRETTY_FUNCTION__,
972 pim_ifp->mroute_vif_index, ifp->name, ifp->ifindex);
973 return -1;
974 }
975
976 if (ifp->ifindex < 0) {
977 zlog_warn("%s: ifindex=%d < 1 on interface %s",
978 __PRETTY_FUNCTION__,
979 ifp->ifindex, ifp->name);
980 return -2;
981 }
982
983 ifaddr = pim_ifp->primary_address;
984 if (ifp->ifindex != PIM_OIF_PIM_REGISTER_VIF && PIM_INADDR_IS_ANY(ifaddr)) {
985 zlog_warn("%s: could not get address for interface %s ifindex=%d",
986 __PRETTY_FUNCTION__,
987 ifp->name, ifp->ifindex);
988 return -4;
989 }
990
991 pim_ifp->mroute_vif_index = pim_iface_next_vif_index (ifp);
992
993 if (pim_ifp->mroute_vif_index >= MAXVIFS)
994 {
995 zlog_warn("%s: Attempting to configure more than MAXVIFS=%d on pim enabled interface %s",
996 __PRETTY_FUNCTION__,
997 MAXVIFS, ifp->name);
998 return -3;
999 }
1000
1001 if (ifp->ifindex == PIM_OIF_PIM_REGISTER_VIF)
1002 flags = VIFF_REGISTER;
1003 #ifdef VIFF_USE_IFINDEX
1004 else
1005 flags = VIFF_USE_IFINDEX;
1006 #endif
1007
1008 if (pim_mroute_add_vif(ifp, ifaddr, flags)) {
1009 /* pim_mroute_add_vif reported error */
1010 return -5;
1011 }
1012
1013 pim_iface_vif_index[pim_ifp->mroute_vif_index] = 1;
1014 return 0;
1015 }
1016
1017 int pim_if_del_vif(struct interface *ifp)
1018 {
1019 struct pim_interface *pim_ifp = ifp->info;
1020
1021 if (pim_ifp->mroute_vif_index < 1) {
1022 zlog_warn("%s: vif_index=%d < 1 on interface %s ifindex=%d",
1023 __PRETTY_FUNCTION__,
1024 pim_ifp->mroute_vif_index, ifp->name, ifp->ifindex);
1025 return -1;
1026 }
1027
1028 pim_mroute_del_vif(pim_ifp->mroute_vif_index);
1029
1030 /*
1031 Update vif_index
1032 */
1033 pim_iface_vif_index[pim_ifp->mroute_vif_index] = 0;
1034
1035 pim_ifp->mroute_vif_index = -1;
1036
1037 return 0;
1038 }
1039
1040 void pim_if_add_vif_all()
1041 {
1042 struct listnode *ifnode;
1043 struct listnode *ifnextnode;
1044 struct interface *ifp;
1045
1046 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
1047 if (!ifp->info)
1048 continue;
1049
1050 pim_if_add_vif(ifp);
1051 }
1052 }
1053
1054 void pim_if_del_vif_all()
1055 {
1056 struct listnode *ifnode;
1057 struct listnode *ifnextnode;
1058 struct interface *ifp;
1059
1060 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
1061 if (!ifp->info)
1062 continue;
1063
1064 pim_if_del_vif(ifp);
1065 }
1066 }
1067
1068 struct interface *pim_if_find_by_vif_index(ifindex_t vif_index)
1069 {
1070 struct listnode *ifnode;
1071 struct interface *ifp;
1072
1073 if (vif_index == 0)
1074 return if_lookup_by_name ("pimreg", VRF_DEFAULT);
1075
1076 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), ifnode, ifp)) {
1077 if (ifp->info) {
1078 struct pim_interface *pim_ifp;
1079 pim_ifp = ifp->info;
1080
1081 if (vif_index == pim_ifp->mroute_vif_index)
1082 return ifp;
1083 }
1084 }
1085
1086 return 0;
1087 }
1088
1089 /*
1090 pim_if_add_vif() uses ifindex as vif_index
1091 */
1092 int pim_if_find_vifindex_by_ifindex(ifindex_t ifindex)
1093 {
1094 struct pim_interface *pim_ifp;
1095 struct interface *ifp;
1096
1097 ifp = if_lookup_by_index (ifindex, VRF_DEFAULT);
1098 if (!ifp || !ifp->info)
1099 return -1;
1100 pim_ifp = ifp->info;
1101
1102 return pim_ifp->mroute_vif_index;
1103 }
1104
1105 int pim_if_lan_delay_enabled(struct interface *ifp)
1106 {
1107 struct pim_interface *pim_ifp;
1108
1109 pim_ifp = ifp->info;
1110 zassert(pim_ifp);
1111 zassert(pim_ifp->pim_number_of_nonlandelay_neighbors >= 0);
1112
1113 return pim_ifp->pim_number_of_nonlandelay_neighbors == 0;
1114 }
1115
1116 uint16_t pim_if_effective_propagation_delay_msec(struct interface *ifp)
1117 {
1118 if (pim_if_lan_delay_enabled(ifp)) {
1119 struct pim_interface *pim_ifp;
1120 pim_ifp = ifp->info;
1121 return pim_ifp->pim_neighbors_highest_propagation_delay_msec;
1122 }
1123 else {
1124 return PIM_DEFAULT_PROPAGATION_DELAY_MSEC;
1125 }
1126 }
1127
1128 uint16_t pim_if_effective_override_interval_msec(struct interface *ifp)
1129 {
1130 if (pim_if_lan_delay_enabled(ifp)) {
1131 struct pim_interface *pim_ifp;
1132 pim_ifp = ifp->info;
1133 return pim_ifp->pim_neighbors_highest_override_interval_msec;
1134 }
1135 else {
1136 return PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC;
1137 }
1138 }
1139
1140 int pim_if_t_override_msec(struct interface *ifp)
1141 {
1142 int effective_override_interval_msec;
1143 int t_override_msec;
1144
1145 effective_override_interval_msec =
1146 pim_if_effective_override_interval_msec(ifp);
1147
1148 t_override_msec = random() % (effective_override_interval_msec + 1);
1149
1150 return t_override_msec;
1151 }
1152
1153 uint16_t pim_if_jp_override_interval_msec(struct interface *ifp)
1154 {
1155 return pim_if_effective_propagation_delay_msec(ifp) +
1156 pim_if_effective_override_interval_msec(ifp);
1157 }
1158
1159 /*
1160 RFC 4601: 4.1.6. State Summarization Macros
1161
1162 The function NBR( I, A ) uses information gathered through PIM Hello
1163 messages to map the IP address A of a directly connected PIM
1164 neighbor router on interface I to the primary IP address of the same
1165 router (Section 4.3.4). The primary IP address of a neighbor is the
1166 address that it uses as the source of its PIM Hello messages.
1167 */
1168 struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp,
1169 struct in_addr addr)
1170 {
1171 struct listnode *neighnode;
1172 struct pim_neighbor *neigh;
1173 struct pim_interface *pim_ifp;
1174 struct prefix p;
1175
1176 zassert(ifp);
1177
1178 pim_ifp = ifp->info;
1179 if (!pim_ifp) {
1180 zlog_warn("%s: multicast not enabled on interface %s",
1181 __PRETTY_FUNCTION__,
1182 ifp->name);
1183 return 0;
1184 }
1185
1186 p.family = AF_INET;
1187 p.u.prefix4 = addr;
1188 p.prefixlen = IPV4_MAX_PREFIXLEN;
1189
1190 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) {
1191
1192 /* primary address ? */
1193 if (neigh->source_addr.s_addr == addr.s_addr)
1194 return neigh;
1195
1196 /* secondary address ? */
1197 if (pim_neighbor_find_secondary(neigh, &p))
1198 return neigh;
1199 }
1200
1201 if (PIM_DEBUG_PIM_TRACE) {
1202 char addr_str[INET_ADDRSTRLEN];
1203 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
1204 zlog_debug("%s: neighbor not found for address %s on interface %s",
1205 __PRETTY_FUNCTION__,
1206 addr_str, ifp->name);
1207 }
1208
1209 return NULL;
1210 }
1211
1212 long pim_if_t_suppressed_msec(struct interface *ifp)
1213 {
1214 struct pim_interface *pim_ifp;
1215 long t_suppressed_msec;
1216 uint32_t ramount = 0;
1217
1218 pim_ifp = ifp->info;
1219 zassert(pim_ifp);
1220
1221 /* join suppression disabled ? */
1222 if (PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options))
1223 return 0;
1224
1225 /* t_suppressed = t_periodic * rand(1.1, 1.4) */
1226 ramount = 1100 + (random() % (1400 - 1100 + 1));
1227 t_suppressed_msec = qpim_t_periodic * ramount;
1228
1229 return t_suppressed_msec;
1230 }
1231
1232 static void igmp_join_free(struct igmp_join *ij)
1233 {
1234 XFREE(MTYPE_PIM_IGMP_JOIN, ij);
1235 }
1236
1237 static struct igmp_join *igmp_join_find(struct list *join_list,
1238 struct in_addr group_addr,
1239 struct in_addr source_addr)
1240 {
1241 struct listnode *node;
1242 struct igmp_join *ij;
1243
1244 zassert(join_list);
1245
1246 for (ALL_LIST_ELEMENTS_RO(join_list, node, ij)) {
1247 if ((group_addr.s_addr == ij->group_addr.s_addr) &&
1248 (source_addr.s_addr == ij->source_addr.s_addr))
1249 return ij;
1250 }
1251
1252 return 0;
1253 }
1254
1255 static int igmp_join_sock(const char *ifname,
1256 ifindex_t ifindex,
1257 struct in_addr group_addr,
1258 struct in_addr source_addr)
1259 {
1260 int join_fd;
1261
1262 join_fd = pim_socket_raw(IPPROTO_IGMP);
1263 if (join_fd < 0) {
1264 return -1;
1265 }
1266
1267 if (pim_socket_join_source(join_fd, ifindex, group_addr, source_addr, ifname)) {
1268 close(join_fd);
1269 return -2;
1270 }
1271
1272 return join_fd;
1273 }
1274
1275 static struct igmp_join *igmp_join_new(struct interface *ifp,
1276 struct in_addr group_addr,
1277 struct in_addr source_addr)
1278 {
1279 struct pim_interface *pim_ifp;
1280 struct igmp_join *ij;
1281 int join_fd;
1282
1283 pim_ifp = ifp->info;
1284 zassert(pim_ifp);
1285
1286 join_fd = igmp_join_sock(ifp->name, ifp->ifindex, group_addr, source_addr);
1287 if (join_fd < 0) {
1288 char group_str[INET_ADDRSTRLEN];
1289 char source_str[INET_ADDRSTRLEN];
1290 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1291 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1292 zlog_warn("%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
1293 __PRETTY_FUNCTION__,
1294 group_str, source_str, ifp->name);
1295 return 0;
1296 }
1297
1298 ij = XCALLOC(MTYPE_PIM_IGMP_JOIN, sizeof(*ij));
1299 if (!ij) {
1300 char group_str[INET_ADDRSTRLEN];
1301 char source_str[INET_ADDRSTRLEN];
1302 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1303 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1304 zlog_err("%s: XCALLOC(%zu) failure for IGMP group %s source %s on interface %s",
1305 __PRETTY_FUNCTION__,
1306 sizeof(*ij), group_str, source_str, ifp->name);
1307 close(join_fd);
1308 return 0;
1309 }
1310
1311 ij->sock_fd = join_fd;
1312 ij->group_addr = group_addr;
1313 ij->source_addr = source_addr;
1314 ij->sock_creation = pim_time_monotonic_sec();
1315
1316 listnode_add(pim_ifp->igmp_join_list, ij);
1317
1318 return ij;
1319 }
1320
1321 int pim_if_igmp_join_add(struct interface *ifp,
1322 struct in_addr group_addr,
1323 struct in_addr source_addr)
1324 {
1325 struct pim_interface *pim_ifp;
1326 struct igmp_join *ij;
1327
1328 pim_ifp = ifp->info;
1329 if (!pim_ifp) {
1330 zlog_warn("%s: multicast not enabled on interface %s",
1331 __PRETTY_FUNCTION__,
1332 ifp->name);
1333 return -1;
1334 }
1335
1336 if (!pim_ifp->igmp_join_list) {
1337 pim_ifp->igmp_join_list = list_new();
1338 if (!pim_ifp->igmp_join_list) {
1339 zlog_err("%s %s: failure: igmp_join_list=list_new()",
1340 __FILE__, __PRETTY_FUNCTION__);
1341 return -2;
1342 }
1343 pim_ifp->igmp_join_list->del = (void (*)(void *)) igmp_join_free;
1344 }
1345
1346 ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr);
1347 if (ij) {
1348 char group_str[INET_ADDRSTRLEN];
1349 char source_str[INET_ADDRSTRLEN];
1350 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1351 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1352 zlog_warn("%s: can't re-join existing IGMP group %s source %s on interface %s",
1353 __PRETTY_FUNCTION__,
1354 group_str, source_str, ifp->name);
1355 return -3;
1356 }
1357
1358 ij = igmp_join_new(ifp, group_addr, source_addr);
1359 if (!ij) {
1360 char group_str[INET_ADDRSTRLEN];
1361 char source_str[INET_ADDRSTRLEN];
1362 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1363 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1364 zlog_warn("%s: igmp_join_new() failure for IGMP group %s source %s on interface %s",
1365 __PRETTY_FUNCTION__,
1366 group_str, source_str, ifp->name);
1367 return -4;
1368 }
1369
1370 if (PIM_DEBUG_IGMP_EVENTS) {
1371 char group_str[INET_ADDRSTRLEN];
1372 char source_str[INET_ADDRSTRLEN];
1373 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1374 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1375 zlog_debug("%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s",
1376 __PRETTY_FUNCTION__,
1377 source_str, group_str, ifp->name);
1378 }
1379
1380 return 0;
1381 }
1382
1383
1384
1385 int pim_if_igmp_join_del(struct interface *ifp,
1386 struct in_addr group_addr,
1387 struct in_addr source_addr)
1388 {
1389 struct pim_interface *pim_ifp;
1390 struct igmp_join *ij;
1391
1392 pim_ifp = ifp->info;
1393 if (!pim_ifp) {
1394 zlog_warn("%s: multicast not enabled on interface %s",
1395 __PRETTY_FUNCTION__,
1396 ifp->name);
1397 return -1;
1398 }
1399
1400 if (!pim_ifp->igmp_join_list) {
1401 zlog_warn("%s: no IGMP join on interface %s",
1402 __PRETTY_FUNCTION__,
1403 ifp->name);
1404 return -2;
1405 }
1406
1407 ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr);
1408 if (!ij) {
1409 char group_str[INET_ADDRSTRLEN];
1410 char source_str[INET_ADDRSTRLEN];
1411 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1412 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1413 zlog_warn("%s: could not find IGMP group %s source %s on interface %s",
1414 __PRETTY_FUNCTION__,
1415 group_str, source_str, ifp->name);
1416 return -3;
1417 }
1418
1419 if (close(ij->sock_fd)) {
1420 char group_str[INET_ADDRSTRLEN];
1421 char source_str[INET_ADDRSTRLEN];
1422 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1423 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1424 zlog_warn("%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s",
1425 __PRETTY_FUNCTION__,
1426 ij->sock_fd, group_str, source_str, ifp->name, errno, safe_strerror(errno));
1427 /* warning only */
1428 }
1429 listnode_delete(pim_ifp->igmp_join_list, ij);
1430 igmp_join_free(ij);
1431 if (listcount(pim_ifp->igmp_join_list) < 1) {
1432 list_delete(pim_ifp->igmp_join_list);
1433 pim_ifp->igmp_join_list = 0;
1434 }
1435
1436 return 0;
1437 }
1438
1439 static void pim_if_igmp_join_del_all(struct interface *ifp)
1440 {
1441 struct pim_interface *pim_ifp;
1442 struct listnode *node;
1443 struct listnode *nextnode;
1444 struct igmp_join *ij;
1445
1446 pim_ifp = ifp->info;
1447 if (!pim_ifp) {
1448 zlog_warn("%s: multicast not enabled on interface %s",
1449 __PRETTY_FUNCTION__,
1450 ifp->name);
1451 return;
1452 }
1453
1454 if (!pim_ifp->igmp_join_list)
1455 return;
1456
1457 for (ALL_LIST_ELEMENTS(pim_ifp->igmp_join_list, node, nextnode, ij))
1458 pim_if_igmp_join_del(ifp, ij->group_addr, ij->source_addr);
1459 }
1460
1461 /*
1462 RFC 4601
1463
1464 Transitions from "I am Assert Loser" State
1465
1466 Current Winner's GenID Changes or NLT Expires
1467
1468 The Neighbor Liveness Timer associated with the current winner
1469 expires or we receive a Hello message from the current winner
1470 reporting a different GenID from the one it previously reported.
1471 This indicates that the current winner's interface or router has
1472 gone down (and may have come back up), and so we must assume it no
1473 longer knows it was the winner.
1474 */
1475 void pim_if_assert_on_neighbor_down(struct interface *ifp,
1476 struct in_addr neigh_addr)
1477 {
1478 struct pim_interface *pim_ifp;
1479 struct listnode *node;
1480 struct listnode *next_node;
1481 struct pim_ifchannel *ch;
1482
1483 pim_ifp = ifp->info;
1484 zassert(pim_ifp);
1485
1486 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
1487 /* Is (S,G,I) assert loser ? */
1488 if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER)
1489 continue;
1490 /* Dead neighbor was winner ? */
1491 if (ch->ifassert_winner.s_addr != neigh_addr.s_addr)
1492 continue;
1493
1494 assert_action_a5(ch);
1495 }
1496 }
1497
1498 void pim_if_update_join_desired(struct pim_interface *pim_ifp)
1499 {
1500 struct listnode *ch_node;
1501 struct pim_ifchannel *ch;
1502
1503 /* clear off flag from interface's upstreams */
1504 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
1505 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(ch->upstream->flags);
1506 }
1507
1508 /* scan per-interface (S,G,I) state on this I interface */
1509 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
1510 struct pim_upstream *up = ch->upstream;
1511
1512 if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up->flags))
1513 continue;
1514
1515 /* update join_desired for the global (S,G) state */
1516 pim_upstream_update_join_desired(up);
1517 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up->flags);
1518 }
1519 }
1520
1521 void pim_if_update_assert_tracking_desired(struct interface *ifp)
1522 {
1523 struct pim_interface *pim_ifp;
1524 struct listnode *node;
1525 struct listnode *next_node;
1526 struct pim_ifchannel *ch;
1527
1528 pim_ifp = ifp->info;
1529 if (!pim_ifp)
1530 return;
1531
1532 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
1533 pim_ifchannel_update_assert_tracking_desired(ch);
1534 }
1535 }
1536
1537 /*
1538 * PIM wants to have an interface pointer for everything it does.
1539 * The pimreg is a special interface that we have that is not
1540 * quite an inteface but a VIF is created for it.
1541 */
1542 void pim_if_create_pimreg (void)
1543 {
1544 if (!pim_regiface) {
1545 pim_regiface = if_create("pimreg", strlen("pimreg"), VRF_DEFAULT);
1546 pim_regiface->ifindex = PIM_OIF_PIM_REGISTER_VIF;
1547
1548 pim_if_new(pim_regiface, 0, 0);
1549 }
1550 }
1551
1552 int
1553 pim_if_connected_to_source (struct interface *ifp, struct in_addr src)
1554 {
1555 struct listnode *cnode;
1556 struct connected *c;
1557 struct prefix p;
1558
1559 if (!ifp)
1560 return 0;
1561
1562 p.family = AF_INET;
1563 p.u.prefix4 = src;
1564 p.prefixlen = IPV4_MAX_BITLEN;
1565
1566 for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c))
1567 {
1568 if ((c->address->family == AF_INET) &&
1569 prefix_match (CONNECTED_PREFIX (c), &p))
1570 {
1571 return 1;
1572 }
1573 }
1574
1575 return 0;
1576 }
1577
1578 struct interface *
1579 pim_if_lookup_address_vrf (struct in_addr src, vrf_id_t vrf_id)
1580 {
1581 struct listnode *ifnode;
1582 struct interface *ifp;
1583
1584 for (ALL_LIST_ELEMENTS_RO (vrf_iflist(vrf_id), ifnode, ifp))
1585 {
1586 if (pim_if_connected_to_source (ifp, src) && ifp->info)
1587 return ifp;
1588 }
1589 return NULL;
1590 }