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