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