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