]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_iface.c
pimd: Don't send hello's out vrf interface
[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
2002dcdb
DS
597 // if (ifc->address->family != AF_INET)
598 // return;
d62a17ae 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;
896b2044 906 struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
d62a17ae 907
908 if (pim_ifp && PIM_INADDR_ISNOT_ANY(pim_ifp->update_source)) {
909 return pim_ifp->update_source;
910 }
911
912 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
913 struct prefix *p = ifc->address;
914
915 if (p->family != AF_INET) {
916 v6_addrs++;
917 continue;
918 }
919
920 if (PIM_INADDR_IS_ANY(p->u.prefix4)) {
921 zlog_warn(
922 "%s: null IPv4 address connected to interface %s",
923 __PRETTY_FUNCTION__, ifp->name);
924 continue;
925 }
926
927 v4_addrs++;
928
929 if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
930 continue;
931
932 return p->u.prefix4;
933 }
934
935 /*
936 * If we have no v4_addrs and v6 is configured
937 * We probably are using unnumbered
938 * So let's grab the loopbacks v4 address
939 * and use that as the primary address
940 */
941 if (!v4_addrs && v6_addrs && !if_is_loopback(ifp)) {
942 struct interface *lo_ifp;
fec883d9 943 // DBS - Come back and check here
896b2044
DS
944 if (ifp->vrf_id == VRF_DEFAULT)
945 lo_ifp = if_lookup_by_name("lo", vrf->vrf_id);
946 else
947 lo_ifp = if_lookup_by_name(vrf->name, vrf->vrf_id);
948
d62a17ae 949 if (lo_ifp)
950 return pim_find_primary_addr(lo_ifp);
951 }
952
953 addr.s_addr = PIM_NET_INADDR_ANY;
954
955 return addr;
12e41d03
DL
956}
957
d62a17ae 958static int pim_iface_next_vif_index(struct interface *ifp)
744d91b3 959{
f88df3a6
DS
960 struct pim_interface *pim_ifp = ifp->info;
961 struct pim_instance *pim = pim_ifp->pim;
d62a17ae 962 int i;
f88df3a6 963
d62a17ae 964 /*
965 * The pimreg vif is always going to be in index 0
966 * of the table.
967 */
968 if (ifp->ifindex == PIM_OIF_PIM_REGISTER_VIF)
969 return 0;
970
971 for (i = 1; i < MAXVIFS; i++) {
f88df3a6 972 if (pim->iface_vif_index[i] == 0)
d62a17ae 973 return i;
974 }
975 return MAXVIFS;
744d91b3
DS
976}
977
12e41d03
DL
978/*
979 pim_if_add_vif() uses ifindex as vif_index
980
981 see also pim_if_find_vifindex_by_ifindex()
982 */
983int pim_if_add_vif(struct interface *ifp)
984{
d62a17ae 985 struct pim_interface *pim_ifp = ifp->info;
986 struct in_addr ifaddr;
987 unsigned char flags = 0;
988
989 zassert(pim_ifp);
990
991 if (pim_ifp->mroute_vif_index > 0) {
992 zlog_warn("%s: vif_index=%d > 0 on interface %s ifindex=%d",
993 __PRETTY_FUNCTION__, pim_ifp->mroute_vif_index,
994 ifp->name, ifp->ifindex);
995 return -1;
996 }
997
998 if (ifp->ifindex < 0) {
999 zlog_warn("%s: ifindex=%d < 1 on interface %s",
1000 __PRETTY_FUNCTION__, ifp->ifindex, ifp->name);
1001 return -2;
1002 }
1003
1004 ifaddr = pim_ifp->primary_address;
1005 if (ifp->ifindex != PIM_OIF_PIM_REGISTER_VIF
1006 && PIM_INADDR_IS_ANY(ifaddr)) {
1007 zlog_warn(
1008 "%s: could not get address for interface %s ifindex=%d",
1009 __PRETTY_FUNCTION__, ifp->name, ifp->ifindex);
1010 return -4;
1011 }
1012
1013 pim_ifp->mroute_vif_index = pim_iface_next_vif_index(ifp);
1014
1015 if (pim_ifp->mroute_vif_index >= MAXVIFS) {
1016 zlog_warn(
1017 "%s: Attempting to configure more than MAXVIFS=%d on pim enabled interface %s",
1018 __PRETTY_FUNCTION__, MAXVIFS, ifp->name);
1019 return -3;
1020 }
1021
1022 if (ifp->ifindex == PIM_OIF_PIM_REGISTER_VIF)
1023 flags = VIFF_REGISTER;
b3f2bf7c 1024#ifdef VIFF_USE_IFINDEX
d62a17ae 1025 else
1026 flags = VIFF_USE_IFINDEX;
b3f2bf7c
RW
1027#endif
1028
d62a17ae 1029 if (pim_mroute_add_vif(ifp, ifaddr, flags)) {
1030 /* pim_mroute_add_vif reported error */
1031 return -5;
1032 }
12e41d03 1033
f88df3a6 1034 pim_ifp->pim->iface_vif_index[pim_ifp->mroute_vif_index] = 1;
d62a17ae 1035 return 0;
12e41d03
DL
1036}
1037
12e41d03
DL
1038int pim_if_del_vif(struct interface *ifp)
1039{
d62a17ae 1040 struct pim_interface *pim_ifp = ifp->info;
12e41d03 1041
d62a17ae 1042 if (pim_ifp->mroute_vif_index < 1) {
1043 zlog_warn("%s: vif_index=%d < 1 on interface %s ifindex=%d",
1044 __PRETTY_FUNCTION__, pim_ifp->mroute_vif_index,
1045 ifp->name, ifp->ifindex);
1046 return -1;
1047 }
12e41d03 1048
ea3d967b 1049 pim_mroute_del_vif(ifp);
12e41d03 1050
d62a17ae 1051 /*
1052 Update vif_index
1053 */
f88df3a6 1054 pim_ifp->pim->iface_vif_index[pim_ifp->mroute_vif_index] = 0;
12e41d03 1055
d62a17ae 1056 pim_ifp->mroute_vif_index = -1;
12e41d03 1057
d62a17ae 1058 return 0;
12e41d03
DL
1059}
1060
da82728d 1061// DBS - VRF Revist
7cfc7bcf
DS
1062struct interface *pim_if_find_by_vif_index(struct pim_instance *pim,
1063 ifindex_t vif_index)
12e41d03 1064{
d62a17ae 1065 struct listnode *ifnode;
1066 struct interface *ifp;
12e41d03 1067
7cfc7bcf
DS
1068 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), ifnode, ifp)) {
1069 if (ifp->info) {
1070 struct pim_interface *pim_ifp;
1071 pim_ifp = ifp->info;
b892f1dd 1072
7cfc7bcf
DS
1073 if (vif_index == pim_ifp->mroute_vif_index)
1074 return ifp;
d62a17ae 1075 }
1076 }
12e41d03 1077
d62a17ae 1078 return 0;
12e41d03
DL
1079}
1080
1081/*
1082 pim_if_add_vif() uses ifindex as vif_index
1083 */
7cfc7bcf 1084int pim_if_find_vifindex_by_ifindex(struct pim_instance *pim, ifindex_t ifindex)
12e41d03 1085{
d62a17ae 1086 struct pim_interface *pim_ifp;
1087 struct interface *ifp;
ae90dfbb 1088
7cfc7bcf 1089 ifp = if_lookup_by_index(ifindex, pim->vrf_id);
d62a17ae 1090 if (!ifp || !ifp->info)
1091 return -1;
1092 pim_ifp = ifp->info;
ae90dfbb 1093
d62a17ae 1094 return pim_ifp->mroute_vif_index;
12e41d03
DL
1095}
1096
1097int pim_if_lan_delay_enabled(struct interface *ifp)
1098{
d62a17ae 1099 struct pim_interface *pim_ifp;
12e41d03 1100
d62a17ae 1101 pim_ifp = ifp->info;
1102 zassert(pim_ifp);
1103 zassert(pim_ifp->pim_number_of_nonlandelay_neighbors >= 0);
12e41d03 1104
d62a17ae 1105 return pim_ifp->pim_number_of_nonlandelay_neighbors == 0;
12e41d03
DL
1106}
1107
1108uint16_t pim_if_effective_propagation_delay_msec(struct interface *ifp)
1109{
d62a17ae 1110 if (pim_if_lan_delay_enabled(ifp)) {
1111 struct pim_interface *pim_ifp;
1112 pim_ifp = ifp->info;
1113 return pim_ifp->pim_neighbors_highest_propagation_delay_msec;
1114 } else {
1115 return PIM_DEFAULT_PROPAGATION_DELAY_MSEC;
1116 }
12e41d03
DL
1117}
1118
1119uint16_t pim_if_effective_override_interval_msec(struct interface *ifp)
1120{
d62a17ae 1121 if (pim_if_lan_delay_enabled(ifp)) {
1122 struct pim_interface *pim_ifp;
1123 pim_ifp = ifp->info;
1124 return pim_ifp->pim_neighbors_highest_override_interval_msec;
1125 } else {
1126 return PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC;
1127 }
12e41d03
DL
1128}
1129
1130int pim_if_t_override_msec(struct interface *ifp)
1131{
d62a17ae 1132 int effective_override_interval_msec;
1133 int t_override_msec;
12e41d03 1134
d62a17ae 1135 effective_override_interval_msec =
1136 pim_if_effective_override_interval_msec(ifp);
12e41d03 1137
d62a17ae 1138 t_override_msec = random() % (effective_override_interval_msec + 1);
12e41d03 1139
d62a17ae 1140 return t_override_msec;
12e41d03
DL
1141}
1142
1143uint16_t pim_if_jp_override_interval_msec(struct interface *ifp)
1144{
d62a17ae 1145 return pim_if_effective_propagation_delay_msec(ifp)
1146 + pim_if_effective_override_interval_msec(ifp);
12e41d03
DL
1147}
1148
1149/*
1150 RFC 4601: 4.1.6. State Summarization Macros
1151
1152 The function NBR( I, A ) uses information gathered through PIM Hello
1153 messages to map the IP address A of a directly connected PIM
1154 neighbor router on interface I to the primary IP address of the same
1155 router (Section 4.3.4). The primary IP address of a neighbor is the
1156 address that it uses as the source of its PIM Hello messages.
1157*/
1158struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp,
1159 struct in_addr addr)
1160{
d62a17ae 1161 struct listnode *neighnode;
1162 struct pim_neighbor *neigh;
1163 struct pim_interface *pim_ifp;
1164 struct prefix p;
1165
1166 zassert(ifp);
1167
1168 pim_ifp = ifp->info;
1169 if (!pim_ifp) {
1170 zlog_warn("%s: multicast not enabled on interface %s",
1171 __PRETTY_FUNCTION__, ifp->name);
1172 return 0;
1173 }
1174
1175 p.family = AF_INET;
1176 p.u.prefix4 = addr;
1177 p.prefixlen = IPV4_MAX_PREFIXLEN;
1178
1179 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode,
1180 neigh)) {
1181
1182 /* primary address ? */
1183 if (neigh->source_addr.s_addr == addr.s_addr)
1184 return neigh;
1185
1186 /* secondary address ? */
1187 if (pim_neighbor_find_secondary(neigh, &p))
1188 return neigh;
1189 }
1190
1191 if (PIM_DEBUG_PIM_TRACE) {
1192 char addr_str[INET_ADDRSTRLEN];
1193 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
1194 zlog_debug(
1195 "%s: neighbor not found for address %s on interface %s",
1196 __PRETTY_FUNCTION__, addr_str, ifp->name);
1197 }
1198
1199 return NULL;
12e41d03
DL
1200}
1201
1202long pim_if_t_suppressed_msec(struct interface *ifp)
1203{
d62a17ae 1204 struct pim_interface *pim_ifp;
1205 long t_suppressed_msec;
1206 uint32_t ramount = 0;
12e41d03 1207
d62a17ae 1208 pim_ifp = ifp->info;
1209 zassert(pim_ifp);
12e41d03 1210
d62a17ae 1211 /* join suppression disabled ? */
1212 if (PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options))
1213 return 0;
12e41d03 1214
d62a17ae 1215 /* t_suppressed = t_periodic * rand(1.1, 1.4) */
1216 ramount = 1100 + (random() % (1400 - 1100 + 1));
1217 t_suppressed_msec = qpim_t_periodic * ramount;
12e41d03 1218
d62a17ae 1219 return t_suppressed_msec;
12e41d03
DL
1220}
1221
1222static void igmp_join_free(struct igmp_join *ij)
1223{
d62a17ae 1224 XFREE(MTYPE_PIM_IGMP_JOIN, ij);
12e41d03
DL
1225}
1226
1227static struct igmp_join *igmp_join_find(struct list *join_list,
1228 struct in_addr group_addr,
1229 struct in_addr source_addr)
1230{
d62a17ae 1231 struct listnode *node;
1232 struct igmp_join *ij;
12e41d03 1233
d62a17ae 1234 zassert(join_list);
12e41d03 1235
d62a17ae 1236 for (ALL_LIST_ELEMENTS_RO(join_list, node, ij)) {
1237 if ((group_addr.s_addr == ij->group_addr.s_addr)
1238 && (source_addr.s_addr == ij->source_addr.s_addr))
1239 return ij;
1240 }
12e41d03 1241
d62a17ae 1242 return 0;
12e41d03
DL
1243}
1244
d62a17ae 1245static int igmp_join_sock(const char *ifname, ifindex_t ifindex,
1246 struct in_addr group_addr, struct in_addr source_addr)
12e41d03 1247{
d62a17ae 1248 int join_fd;
12e41d03 1249
d62a17ae 1250 join_fd = pim_socket_raw(IPPROTO_IGMP);
1251 if (join_fd < 0) {
1252 return -1;
1253 }
12e41d03 1254
d62a17ae 1255 if (pim_socket_join_source(join_fd, ifindex, group_addr, source_addr,
1256 ifname)) {
1257 close(join_fd);
1258 return -2;
1259 }
12e41d03 1260
d62a17ae 1261 return join_fd;
12e41d03
DL
1262}
1263
1264static struct igmp_join *igmp_join_new(struct interface *ifp,
1265 struct in_addr group_addr,
1266 struct in_addr source_addr)
1267{
d62a17ae 1268 struct pim_interface *pim_ifp;
1269 struct igmp_join *ij;
1270 int join_fd;
1271
1272 pim_ifp = ifp->info;
1273 zassert(pim_ifp);
1274
1275 join_fd = igmp_join_sock(ifp->name, ifp->ifindex, group_addr,
1276 source_addr);
1277 if (join_fd < 0) {
1278 char group_str[INET_ADDRSTRLEN];
1279 char source_str[INET_ADDRSTRLEN];
1280 pim_inet4_dump("<grp?>", group_addr, group_str,
1281 sizeof(group_str));
1282 pim_inet4_dump("<src?>", source_addr, source_str,
1283 sizeof(source_str));
1284 zlog_warn(
1285 "%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
1286 __PRETTY_FUNCTION__, group_str, source_str, ifp->name);
1287 return 0;
1288 }
1289
1290 ij = XCALLOC(MTYPE_PIM_IGMP_JOIN, sizeof(*ij));
1291 if (!ij) {
1292 char group_str[INET_ADDRSTRLEN];
1293 char source_str[INET_ADDRSTRLEN];
1294 pim_inet4_dump("<grp?>", group_addr, group_str,
1295 sizeof(group_str));
1296 pim_inet4_dump("<src?>", source_addr, source_str,
1297 sizeof(source_str));
1298 zlog_err(
1299 "%s: XCALLOC(%zu) failure for IGMP group %s source %s on interface %s",
1300 __PRETTY_FUNCTION__, sizeof(*ij), group_str, source_str,
1301 ifp->name);
1302 close(join_fd);
1303 return 0;
1304 }
1305
1306 ij->sock_fd = join_fd;
1307 ij->group_addr = group_addr;
1308 ij->source_addr = source_addr;
1309 ij->sock_creation = pim_time_monotonic_sec();
1310
1311 listnode_add(pim_ifp->igmp_join_list, ij);
1312
1313 return ij;
12e41d03
DL
1314}
1315
d62a17ae 1316int pim_if_igmp_join_add(struct interface *ifp, struct in_addr group_addr,
12e41d03
DL
1317 struct in_addr source_addr)
1318{
d62a17ae 1319 struct pim_interface *pim_ifp;
1320 struct igmp_join *ij;
1321
1322 pim_ifp = ifp->info;
1323 if (!pim_ifp) {
1324 zlog_warn("%s: multicast not enabled on interface %s",
1325 __PRETTY_FUNCTION__, ifp->name);
1326 return -1;
1327 }
1328
1329 if (!pim_ifp->igmp_join_list) {
1330 pim_ifp->igmp_join_list = list_new();
1331 if (!pim_ifp->igmp_join_list) {
1332 zlog_err("%s %s: failure: igmp_join_list=list_new()",
1333 __FILE__, __PRETTY_FUNCTION__);
1334 return -2;
1335 }
1336 pim_ifp->igmp_join_list->del = (void (*)(void *))igmp_join_free;
1337 }
1338
1339 ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr);
1340 if (ij) {
1341 char group_str[INET_ADDRSTRLEN];
1342 char source_str[INET_ADDRSTRLEN];
1343 pim_inet4_dump("<grp?>", group_addr, group_str,
1344 sizeof(group_str));
1345 pim_inet4_dump("<src?>", source_addr, source_str,
1346 sizeof(source_str));
1347 zlog_warn(
1348 "%s: can't re-join existing IGMP group %s source %s on interface %s",
1349 __PRETTY_FUNCTION__, group_str, source_str, ifp->name);
1350 return -3;
1351 }
1352
1353 ij = igmp_join_new(ifp, group_addr, source_addr);
1354 if (!ij) {
1355 char group_str[INET_ADDRSTRLEN];
1356 char source_str[INET_ADDRSTRLEN];
1357 pim_inet4_dump("<grp?>", group_addr, group_str,
1358 sizeof(group_str));
1359 pim_inet4_dump("<src?>", source_addr, source_str,
1360 sizeof(source_str));
1361 zlog_warn(
1362 "%s: igmp_join_new() failure for IGMP group %s source %s on interface %s",
1363 __PRETTY_FUNCTION__, group_str, source_str, ifp->name);
1364 return -4;
1365 }
1366
1367 if (PIM_DEBUG_IGMP_EVENTS) {
1368 char group_str[INET_ADDRSTRLEN];
1369 char source_str[INET_ADDRSTRLEN];
1370 pim_inet4_dump("<grp?>", group_addr, group_str,
1371 sizeof(group_str));
1372 pim_inet4_dump("<src?>", source_addr, source_str,
1373 sizeof(source_str));
1374 zlog_debug(
1375 "%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s",
1376 __PRETTY_FUNCTION__, source_str, group_str, ifp->name);
1377 }
12e41d03 1378
d62a17ae 1379 return 0;
1380}
12e41d03
DL
1381
1382
d62a17ae 1383int pim_if_igmp_join_del(struct interface *ifp, struct in_addr group_addr,
12e41d03
DL
1384 struct in_addr source_addr)
1385{
d62a17ae 1386 struct pim_interface *pim_ifp;
1387 struct igmp_join *ij;
1388
1389 pim_ifp = ifp->info;
1390 if (!pim_ifp) {
1391 zlog_warn("%s: multicast not enabled on interface %s",
1392 __PRETTY_FUNCTION__, ifp->name);
1393 return -1;
1394 }
1395
1396 if (!pim_ifp->igmp_join_list) {
1397 zlog_warn("%s: no IGMP join on interface %s",
1398 __PRETTY_FUNCTION__, ifp->name);
1399 return -2;
1400 }
1401
1402 ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr);
1403 if (!ij) {
1404 char group_str[INET_ADDRSTRLEN];
1405 char source_str[INET_ADDRSTRLEN];
1406 pim_inet4_dump("<grp?>", group_addr, group_str,
1407 sizeof(group_str));
1408 pim_inet4_dump("<src?>", source_addr, source_str,
1409 sizeof(source_str));
1410 zlog_warn(
1411 "%s: could not find IGMP group %s source %s on interface %s",
1412 __PRETTY_FUNCTION__, group_str, source_str, ifp->name);
1413 return -3;
1414 }
1415
1416 if (close(ij->sock_fd)) {
1417 char group_str[INET_ADDRSTRLEN];
1418 char source_str[INET_ADDRSTRLEN];
1419 pim_inet4_dump("<grp?>", group_addr, group_str,
1420 sizeof(group_str));
1421 pim_inet4_dump("<src?>", source_addr, source_str,
1422 sizeof(source_str));
1423 zlog_warn(
1424 "%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s",
1425 __PRETTY_FUNCTION__, ij->sock_fd, group_str, source_str,
1426 ifp->name, errno, safe_strerror(errno));
1427 /* warning only */
1428 }
1429 listnode_delete(pim_ifp->igmp_join_list, ij);
1430 igmp_join_free(ij);
1431 if (listcount(pim_ifp->igmp_join_list) < 1) {
1432 list_delete(pim_ifp->igmp_join_list);
1433 pim_ifp->igmp_join_list = 0;
1434 }
1435
1436 return 0;
12e41d03
DL
1437}
1438
1439static void pim_if_igmp_join_del_all(struct interface *ifp)
1440{
d62a17ae 1441 struct pim_interface *pim_ifp;
1442 struct listnode *node;
1443 struct listnode *nextnode;
1444 struct igmp_join *ij;
1445
1446 pim_ifp = ifp->info;
1447 if (!pim_ifp) {
1448 zlog_warn("%s: multicast not enabled on interface %s",
1449 __PRETTY_FUNCTION__, ifp->name);
1450 return;
1451 }
1452
1453 if (!pim_ifp->igmp_join_list)
1454 return;
1455
1456 for (ALL_LIST_ELEMENTS(pim_ifp->igmp_join_list, node, nextnode, ij))
1457 pim_if_igmp_join_del(ifp, ij->group_addr, ij->source_addr);
12e41d03
DL
1458}
1459
1460/*
1461 RFC 4601
1462
1463 Transitions from "I am Assert Loser" State
1464
1465 Current Winner's GenID Changes or NLT Expires
1466
1467 The Neighbor Liveness Timer associated with the current winner
1468 expires or we receive a Hello message from the current winner
1469 reporting a different GenID from the one it previously reported.
1470 This indicates that the current winner's interface or router has
1471 gone down (and may have come back up), and so we must assume it no
1472 longer knows it was the winner.
1473 */
1474void pim_if_assert_on_neighbor_down(struct interface *ifp,
1475 struct in_addr neigh_addr)
1476{
d62a17ae 1477 struct pim_interface *pim_ifp;
1478 struct listnode *node;
1479 struct listnode *next_node;
1480 struct pim_ifchannel *ch;
1481
1482 pim_ifp = ifp->info;
1483 zassert(pim_ifp);
1484
1485 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node,
1486 ch)) {
1487 /* Is (S,G,I) assert loser ? */
1488 if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER)
1489 continue;
1490 /* Dead neighbor was winner ? */
1491 if (ch->ifassert_winner.s_addr != neigh_addr.s_addr)
1492 continue;
1493
1494 assert_action_a5(ch);
1495 }
12e41d03
DL
1496}
1497
1498void pim_if_update_join_desired(struct pim_interface *pim_ifp)
1499{
d62a17ae 1500 struct listnode *ch_node;
1501 struct pim_ifchannel *ch;
12e41d03 1502
d62a17ae 1503 /* clear off flag from interface's upstreams */
1504 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
1505 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(
1506 ch->upstream->flags);
1507 }
12e41d03 1508
d62a17ae 1509 /* scan per-interface (S,G,I) state on this I interface */
1510 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
1511 struct pim_upstream *up = ch->upstream;
12e41d03 1512
d62a17ae 1513 if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up->flags))
1514 continue;
12e41d03 1515
d62a17ae 1516 /* update join_desired for the global (S,G) state */
9b29ea95 1517 pim_upstream_update_join_desired(pim_ifp->pim, up);
d62a17ae 1518 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up->flags);
1519 }
12e41d03
DL
1520}
1521
1522void pim_if_update_assert_tracking_desired(struct interface *ifp)
1523{
d62a17ae 1524 struct pim_interface *pim_ifp;
1525 struct listnode *node;
1526 struct listnode *next_node;
1527 struct pim_ifchannel *ch;
1528
1529 pim_ifp = ifp->info;
1530 if (!pim_ifp)
1531 return;
1532
1533 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node,
1534 ch)) {
1535 pim_ifchannel_update_assert_tracking_desired(ch);
1536 }
12e41d03 1537}
c992c9a0
DS
1538
1539/*
1540 * PIM wants to have an interface pointer for everything it does.
1541 * The pimreg is a special interface that we have that is not
1542 * quite an inteface but a VIF is created for it.
1543 */
43e40fdf 1544void pim_if_create_pimreg(struct pim_instance *pim)
c992c9a0 1545{
afa2b179 1546 char pimreg_name[100];
c992c9a0 1547
43e40fdf 1548 if (!pim->regiface) {
afa2b179
DS
1549 if (pim->vrf_id == VRF_DEFAULT)
1550 strcpy(pimreg_name, "pimreg");
1551 else
1552 sprintf(pimreg_name, "pimreg%d",
1553 pim->vrf->data.l.table_id);
1554
1555 pim->regiface = if_create(pimreg_name, strlen(pimreg_name),
1556 pim->vrf_id);
43e40fdf
DS
1557 pim->regiface->ifindex = PIM_OIF_PIM_REGISTER_VIF;
1558
1559 pim_if_new(pim->regiface, 0, 0);
d62a17ae 1560 }
c992c9a0 1561}
3565202d 1562
d62a17ae 1563int pim_if_connected_to_source(struct interface *ifp, struct in_addr src)
3565202d 1564{
d62a17ae 1565 struct listnode *cnode;
1566 struct connected *c;
1567 struct prefix p;
1568
1569 if (!ifp)
1570 return 0;
1571
1572 p.family = AF_INET;
1573 p.u.prefix4 = src;
1574 p.prefixlen = IPV4_MAX_BITLEN;
1575
1576 for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) {
1577 if ((c->address->family == AF_INET)
1578 && prefix_match(CONNECTED_PREFIX(c), &p)) {
1579 return 1;
1580 }
1581 }
1582
1583 return 0;
3565202d 1584}
11699c47
DS
1585
1586int pim_if_is_loopback(struct pim_instance *pim, struct interface *ifp)
1587{
1588 if (if_is_loopback(ifp))
1589 return 1;
1590
1591 if (strcmp(ifp->name, pim->vrf->name) == 0)
1592 return 1;
1593
1594 return 0;
1595}