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