]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_iface.c
pimd: Cleanup pim_ssm.c to use '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
7cfc7bcf
DS
1057struct interface *pim_if_find_by_vif_index(struct pim_instance *pim,
1058 ifindex_t vif_index)
12e41d03 1059{
d62a17ae 1060 struct listnode *ifnode;
1061 struct interface *ifp;
12e41d03 1062
7cfc7bcf
DS
1063 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), ifnode, ifp)) {
1064 if (ifp->info) {
1065 struct pim_interface *pim_ifp;
1066 pim_ifp = ifp->info;
b892f1dd 1067
7cfc7bcf
DS
1068 if (vif_index == pim_ifp->mroute_vif_index)
1069 return ifp;
d62a17ae 1070 }
1071 }
12e41d03 1072
d62a17ae 1073 return 0;
12e41d03
DL
1074}
1075
1076/*
1077 pim_if_add_vif() uses ifindex as vif_index
1078 */
7cfc7bcf 1079int pim_if_find_vifindex_by_ifindex(struct pim_instance *pim, ifindex_t ifindex)
12e41d03 1080{
d62a17ae 1081 struct pim_interface *pim_ifp;
1082 struct interface *ifp;
ae90dfbb 1083
7cfc7bcf 1084 ifp = if_lookup_by_index(ifindex, pim->vrf_id);
d62a17ae 1085 if (!ifp || !ifp->info)
1086 return -1;
1087 pim_ifp = ifp->info;
ae90dfbb 1088
d62a17ae 1089 return pim_ifp->mroute_vif_index;
12e41d03
DL
1090}
1091
1092int pim_if_lan_delay_enabled(struct interface *ifp)
1093{
d62a17ae 1094 struct pim_interface *pim_ifp;
12e41d03 1095
d62a17ae 1096 pim_ifp = ifp->info;
1097 zassert(pim_ifp);
1098 zassert(pim_ifp->pim_number_of_nonlandelay_neighbors >= 0);
12e41d03 1099
d62a17ae 1100 return pim_ifp->pim_number_of_nonlandelay_neighbors == 0;
12e41d03
DL
1101}
1102
1103uint16_t pim_if_effective_propagation_delay_msec(struct interface *ifp)
1104{
d62a17ae 1105 if (pim_if_lan_delay_enabled(ifp)) {
1106 struct pim_interface *pim_ifp;
1107 pim_ifp = ifp->info;
1108 return pim_ifp->pim_neighbors_highest_propagation_delay_msec;
1109 } else {
1110 return PIM_DEFAULT_PROPAGATION_DELAY_MSEC;
1111 }
12e41d03
DL
1112}
1113
1114uint16_t pim_if_effective_override_interval_msec(struct interface *ifp)
1115{
d62a17ae 1116 if (pim_if_lan_delay_enabled(ifp)) {
1117 struct pim_interface *pim_ifp;
1118 pim_ifp = ifp->info;
1119 return pim_ifp->pim_neighbors_highest_override_interval_msec;
1120 } else {
1121 return PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC;
1122 }
12e41d03
DL
1123}
1124
1125int pim_if_t_override_msec(struct interface *ifp)
1126{
d62a17ae 1127 int effective_override_interval_msec;
1128 int t_override_msec;
12e41d03 1129
d62a17ae 1130 effective_override_interval_msec =
1131 pim_if_effective_override_interval_msec(ifp);
12e41d03 1132
d62a17ae 1133 t_override_msec = random() % (effective_override_interval_msec + 1);
12e41d03 1134
d62a17ae 1135 return t_override_msec;
12e41d03
DL
1136}
1137
1138uint16_t pim_if_jp_override_interval_msec(struct interface *ifp)
1139{
d62a17ae 1140 return pim_if_effective_propagation_delay_msec(ifp)
1141 + pim_if_effective_override_interval_msec(ifp);
12e41d03
DL
1142}
1143
1144/*
1145 RFC 4601: 4.1.6. State Summarization Macros
1146
1147 The function NBR( I, A ) uses information gathered through PIM Hello
1148 messages to map the IP address A of a directly connected PIM
1149 neighbor router on interface I to the primary IP address of the same
1150 router (Section 4.3.4). The primary IP address of a neighbor is the
1151 address that it uses as the source of its PIM Hello messages.
1152*/
1153struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp,
1154 struct in_addr addr)
1155{
d62a17ae 1156 struct listnode *neighnode;
1157 struct pim_neighbor *neigh;
1158 struct pim_interface *pim_ifp;
1159 struct prefix p;
1160
1161 zassert(ifp);
1162
1163 pim_ifp = ifp->info;
1164 if (!pim_ifp) {
1165 zlog_warn("%s: multicast not enabled on interface %s",
1166 __PRETTY_FUNCTION__, ifp->name);
1167 return 0;
1168 }
1169
1170 p.family = AF_INET;
1171 p.u.prefix4 = addr;
1172 p.prefixlen = IPV4_MAX_PREFIXLEN;
1173
1174 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode,
1175 neigh)) {
1176
1177 /* primary address ? */
1178 if (neigh->source_addr.s_addr == addr.s_addr)
1179 return neigh;
1180
1181 /* secondary address ? */
1182 if (pim_neighbor_find_secondary(neigh, &p))
1183 return neigh;
1184 }
1185
1186 if (PIM_DEBUG_PIM_TRACE) {
1187 char addr_str[INET_ADDRSTRLEN];
1188 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
1189 zlog_debug(
1190 "%s: neighbor not found for address %s on interface %s",
1191 __PRETTY_FUNCTION__, addr_str, ifp->name);
1192 }
1193
1194 return NULL;
12e41d03
DL
1195}
1196
1197long pim_if_t_suppressed_msec(struct interface *ifp)
1198{
d62a17ae 1199 struct pim_interface *pim_ifp;
1200 long t_suppressed_msec;
1201 uint32_t ramount = 0;
12e41d03 1202
d62a17ae 1203 pim_ifp = ifp->info;
1204 zassert(pim_ifp);
12e41d03 1205
d62a17ae 1206 /* join suppression disabled ? */
1207 if (PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options))
1208 return 0;
12e41d03 1209
d62a17ae 1210 /* t_suppressed = t_periodic * rand(1.1, 1.4) */
1211 ramount = 1100 + (random() % (1400 - 1100 + 1));
1212 t_suppressed_msec = qpim_t_periodic * ramount;
12e41d03 1213
d62a17ae 1214 return t_suppressed_msec;
12e41d03
DL
1215}
1216
1217static void igmp_join_free(struct igmp_join *ij)
1218{
d62a17ae 1219 XFREE(MTYPE_PIM_IGMP_JOIN, ij);
12e41d03
DL
1220}
1221
1222static struct igmp_join *igmp_join_find(struct list *join_list,
1223 struct in_addr group_addr,
1224 struct in_addr source_addr)
1225{
d62a17ae 1226 struct listnode *node;
1227 struct igmp_join *ij;
12e41d03 1228
d62a17ae 1229 zassert(join_list);
12e41d03 1230
d62a17ae 1231 for (ALL_LIST_ELEMENTS_RO(join_list, node, ij)) {
1232 if ((group_addr.s_addr == ij->group_addr.s_addr)
1233 && (source_addr.s_addr == ij->source_addr.s_addr))
1234 return ij;
1235 }
12e41d03 1236
d62a17ae 1237 return 0;
12e41d03
DL
1238}
1239
d62a17ae 1240static int igmp_join_sock(const char *ifname, ifindex_t ifindex,
1241 struct in_addr group_addr, struct in_addr source_addr)
12e41d03 1242{
d62a17ae 1243 int join_fd;
12e41d03 1244
d62a17ae 1245 join_fd = pim_socket_raw(IPPROTO_IGMP);
1246 if (join_fd < 0) {
1247 return -1;
1248 }
12e41d03 1249
d62a17ae 1250 if (pim_socket_join_source(join_fd, ifindex, group_addr, source_addr,
1251 ifname)) {
1252 close(join_fd);
1253 return -2;
1254 }
12e41d03 1255
d62a17ae 1256 return join_fd;
12e41d03
DL
1257}
1258
1259static struct igmp_join *igmp_join_new(struct interface *ifp,
1260 struct in_addr group_addr,
1261 struct in_addr source_addr)
1262{
d62a17ae 1263 struct pim_interface *pim_ifp;
1264 struct igmp_join *ij;
1265 int join_fd;
1266
1267 pim_ifp = ifp->info;
1268 zassert(pim_ifp);
1269
1270 join_fd = igmp_join_sock(ifp->name, ifp->ifindex, group_addr,
1271 source_addr);
1272 if (join_fd < 0) {
1273 char group_str[INET_ADDRSTRLEN];
1274 char source_str[INET_ADDRSTRLEN];
1275 pim_inet4_dump("<grp?>", group_addr, group_str,
1276 sizeof(group_str));
1277 pim_inet4_dump("<src?>", source_addr, source_str,
1278 sizeof(source_str));
1279 zlog_warn(
1280 "%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
1281 __PRETTY_FUNCTION__, group_str, source_str, ifp->name);
1282 return 0;
1283 }
1284
1285 ij = XCALLOC(MTYPE_PIM_IGMP_JOIN, sizeof(*ij));
1286 if (!ij) {
1287 char group_str[INET_ADDRSTRLEN];
1288 char source_str[INET_ADDRSTRLEN];
1289 pim_inet4_dump("<grp?>", group_addr, group_str,
1290 sizeof(group_str));
1291 pim_inet4_dump("<src?>", source_addr, source_str,
1292 sizeof(source_str));
1293 zlog_err(
1294 "%s: XCALLOC(%zu) failure for IGMP group %s source %s on interface %s",
1295 __PRETTY_FUNCTION__, sizeof(*ij), group_str, source_str,
1296 ifp->name);
1297 close(join_fd);
1298 return 0;
1299 }
1300
1301 ij->sock_fd = join_fd;
1302 ij->group_addr = group_addr;
1303 ij->source_addr = source_addr;
1304 ij->sock_creation = pim_time_monotonic_sec();
1305
1306 listnode_add(pim_ifp->igmp_join_list, ij);
1307
1308 return ij;
12e41d03
DL
1309}
1310
d62a17ae 1311int pim_if_igmp_join_add(struct interface *ifp, struct in_addr group_addr,
12e41d03
DL
1312 struct in_addr source_addr)
1313{
d62a17ae 1314 struct pim_interface *pim_ifp;
1315 struct igmp_join *ij;
1316
1317 pim_ifp = ifp->info;
1318 if (!pim_ifp) {
1319 zlog_warn("%s: multicast not enabled on interface %s",
1320 __PRETTY_FUNCTION__, ifp->name);
1321 return -1;
1322 }
1323
1324 if (!pim_ifp->igmp_join_list) {
1325 pim_ifp->igmp_join_list = list_new();
1326 if (!pim_ifp->igmp_join_list) {
1327 zlog_err("%s %s: failure: igmp_join_list=list_new()",
1328 __FILE__, __PRETTY_FUNCTION__);
1329 return -2;
1330 }
1331 pim_ifp->igmp_join_list->del = (void (*)(void *))igmp_join_free;
1332 }
1333
1334 ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr);
1335 if (ij) {
1336 char group_str[INET_ADDRSTRLEN];
1337 char source_str[INET_ADDRSTRLEN];
1338 pim_inet4_dump("<grp?>", group_addr, group_str,
1339 sizeof(group_str));
1340 pim_inet4_dump("<src?>", source_addr, source_str,
1341 sizeof(source_str));
1342 zlog_warn(
1343 "%s: can't re-join existing IGMP group %s source %s on interface %s",
1344 __PRETTY_FUNCTION__, group_str, source_str, ifp->name);
1345 return -3;
1346 }
1347
1348 ij = igmp_join_new(ifp, group_addr, source_addr);
1349 if (!ij) {
1350 char group_str[INET_ADDRSTRLEN];
1351 char source_str[INET_ADDRSTRLEN];
1352 pim_inet4_dump("<grp?>", group_addr, group_str,
1353 sizeof(group_str));
1354 pim_inet4_dump("<src?>", source_addr, source_str,
1355 sizeof(source_str));
1356 zlog_warn(
1357 "%s: igmp_join_new() failure for IGMP group %s source %s on interface %s",
1358 __PRETTY_FUNCTION__, group_str, source_str, ifp->name);
1359 return -4;
1360 }
1361
1362 if (PIM_DEBUG_IGMP_EVENTS) {
1363 char group_str[INET_ADDRSTRLEN];
1364 char source_str[INET_ADDRSTRLEN];
1365 pim_inet4_dump("<grp?>", group_addr, group_str,
1366 sizeof(group_str));
1367 pim_inet4_dump("<src?>", source_addr, source_str,
1368 sizeof(source_str));
1369 zlog_debug(
1370 "%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s",
1371 __PRETTY_FUNCTION__, source_str, group_str, ifp->name);
1372 }
12e41d03 1373
d62a17ae 1374 return 0;
1375}
12e41d03
DL
1376
1377
d62a17ae 1378int pim_if_igmp_join_del(struct interface *ifp, struct in_addr group_addr,
12e41d03
DL
1379 struct in_addr source_addr)
1380{
d62a17ae 1381 struct pim_interface *pim_ifp;
1382 struct igmp_join *ij;
1383
1384 pim_ifp = ifp->info;
1385 if (!pim_ifp) {
1386 zlog_warn("%s: multicast not enabled on interface %s",
1387 __PRETTY_FUNCTION__, ifp->name);
1388 return -1;
1389 }
1390
1391 if (!pim_ifp->igmp_join_list) {
1392 zlog_warn("%s: no IGMP join on interface %s",
1393 __PRETTY_FUNCTION__, ifp->name);
1394 return -2;
1395 }
1396
1397 ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr);
1398 if (!ij) {
1399 char group_str[INET_ADDRSTRLEN];
1400 char source_str[INET_ADDRSTRLEN];
1401 pim_inet4_dump("<grp?>", group_addr, group_str,
1402 sizeof(group_str));
1403 pim_inet4_dump("<src?>", source_addr, source_str,
1404 sizeof(source_str));
1405 zlog_warn(
1406 "%s: could not find IGMP group %s source %s on interface %s",
1407 __PRETTY_FUNCTION__, group_str, source_str, ifp->name);
1408 return -3;
1409 }
1410
1411 if (close(ij->sock_fd)) {
1412 char group_str[INET_ADDRSTRLEN];
1413 char source_str[INET_ADDRSTRLEN];
1414 pim_inet4_dump("<grp?>", group_addr, group_str,
1415 sizeof(group_str));
1416 pim_inet4_dump("<src?>", source_addr, source_str,
1417 sizeof(source_str));
1418 zlog_warn(
1419 "%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s",
1420 __PRETTY_FUNCTION__, ij->sock_fd, group_str, source_str,
1421 ifp->name, errno, safe_strerror(errno));
1422 /* warning only */
1423 }
1424 listnode_delete(pim_ifp->igmp_join_list, ij);
1425 igmp_join_free(ij);
1426 if (listcount(pim_ifp->igmp_join_list) < 1) {
1427 list_delete(pim_ifp->igmp_join_list);
1428 pim_ifp->igmp_join_list = 0;
1429 }
1430
1431 return 0;
12e41d03
DL
1432}
1433
1434static void pim_if_igmp_join_del_all(struct interface *ifp)
1435{
d62a17ae 1436 struct pim_interface *pim_ifp;
1437 struct listnode *node;
1438 struct listnode *nextnode;
1439 struct igmp_join *ij;
1440
1441 pim_ifp = ifp->info;
1442 if (!pim_ifp) {
1443 zlog_warn("%s: multicast not enabled on interface %s",
1444 __PRETTY_FUNCTION__, ifp->name);
1445 return;
1446 }
1447
1448 if (!pim_ifp->igmp_join_list)
1449 return;
1450
1451 for (ALL_LIST_ELEMENTS(pim_ifp->igmp_join_list, node, nextnode, ij))
1452 pim_if_igmp_join_del(ifp, ij->group_addr, ij->source_addr);
12e41d03
DL
1453}
1454
1455/*
1456 RFC 4601
1457
1458 Transitions from "I am Assert Loser" State
1459
1460 Current Winner's GenID Changes or NLT Expires
1461
1462 The Neighbor Liveness Timer associated with the current winner
1463 expires or we receive a Hello message from the current winner
1464 reporting a different GenID from the one it previously reported.
1465 This indicates that the current winner's interface or router has
1466 gone down (and may have come back up), and so we must assume it no
1467 longer knows it was the winner.
1468 */
1469void pim_if_assert_on_neighbor_down(struct interface *ifp,
1470 struct in_addr neigh_addr)
1471{
d62a17ae 1472 struct pim_interface *pim_ifp;
1473 struct listnode *node;
1474 struct listnode *next_node;
1475 struct pim_ifchannel *ch;
1476
1477 pim_ifp = ifp->info;
1478 zassert(pim_ifp);
1479
1480 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node,
1481 ch)) {
1482 /* Is (S,G,I) assert loser ? */
1483 if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER)
1484 continue;
1485 /* Dead neighbor was winner ? */
1486 if (ch->ifassert_winner.s_addr != neigh_addr.s_addr)
1487 continue;
1488
1489 assert_action_a5(ch);
1490 }
12e41d03
DL
1491}
1492
1493void pim_if_update_join_desired(struct pim_interface *pim_ifp)
1494{
d62a17ae 1495 struct listnode *ch_node;
1496 struct pim_ifchannel *ch;
12e41d03 1497
d62a17ae 1498 /* clear off flag from interface's upstreams */
1499 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
1500 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(
1501 ch->upstream->flags);
1502 }
12e41d03 1503
d62a17ae 1504 /* scan per-interface (S,G,I) state on this I interface */
1505 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
1506 struct pim_upstream *up = ch->upstream;
12e41d03 1507
d62a17ae 1508 if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up->flags))
1509 continue;
12e41d03 1510
d62a17ae 1511 /* update join_desired for the global (S,G) state */
9b29ea95 1512 pim_upstream_update_join_desired(pim_ifp->pim, up);
d62a17ae 1513 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up->flags);
1514 }
12e41d03
DL
1515}
1516
1517void pim_if_update_assert_tracking_desired(struct interface *ifp)
1518{
d62a17ae 1519 struct pim_interface *pim_ifp;
1520 struct listnode *node;
1521 struct listnode *next_node;
1522 struct pim_ifchannel *ch;
1523
1524 pim_ifp = ifp->info;
1525 if (!pim_ifp)
1526 return;
1527
1528 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node,
1529 ch)) {
1530 pim_ifchannel_update_assert_tracking_desired(ch);
1531 }
12e41d03 1532}
c992c9a0
DS
1533
1534/*
1535 * PIM wants to have an interface pointer for everything it does.
1536 * The pimreg is a special interface that we have that is not
1537 * quite an inteface but a VIF is created for it.
1538 */
43e40fdf 1539void pim_if_create_pimreg(struct pim_instance *pim)
c992c9a0 1540{
afa2b179 1541 char pimreg_name[100];
c992c9a0 1542
43e40fdf 1543 if (!pim->regiface) {
afa2b179
DS
1544 if (pim->vrf_id == VRF_DEFAULT)
1545 strcpy(pimreg_name, "pimreg");
1546 else
1547 sprintf(pimreg_name, "pimreg%d",
1548 pim->vrf->data.l.table_id);
1549
1550 pim->regiface = if_create(pimreg_name, strlen(pimreg_name),
1551 pim->vrf_id);
43e40fdf
DS
1552 pim->regiface->ifindex = PIM_OIF_PIM_REGISTER_VIF;
1553
1554 pim_if_new(pim->regiface, 0, 0);
d62a17ae 1555 }
c992c9a0 1556}
3565202d 1557
d62a17ae 1558int pim_if_connected_to_source(struct interface *ifp, struct in_addr src)
3565202d 1559{
d62a17ae 1560 struct listnode *cnode;
1561 struct connected *c;
1562 struct prefix p;
1563
1564 if (!ifp)
1565 return 0;
1566
1567 p.family = AF_INET;
1568 p.u.prefix4 = src;
1569 p.prefixlen = IPV4_MAX_BITLEN;
1570
1571 for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) {
1572 if ((c->address->family == AF_INET)
1573 && prefix_match(CONNECTED_PREFIX(c), &p)) {
1574 return 1;
1575 }
1576 }
1577
1578 return 0;
3565202d 1579}
9f0edbc9 1580
d62a17ae 1581struct interface *pim_if_lookup_address_vrf(struct in_addr src, vrf_id_t vrf_id)
9f0edbc9 1582{
d62a17ae 1583 struct listnode *ifnode;
1584 struct interface *ifp;
1585
1586 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(vrf_id), ifnode, ifp)) {
1587 if (pim_if_connected_to_source(ifp, src) && ifp->info)
1588 return ifp;
1589 }
1590 return NULL;
9f0edbc9 1591}