]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_iface.c
pimd: Use macro for pimreg interface
[mirror_frr.git] / pimd / pim_iface.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
12e41d03 2/*
896014f4
DL
3 * PIM for Quagga
4 * Copyright (C) 2008 Everton da Silva Marques
896014f4 5 */
12e41d03
DL
6
7#include <zebra.h>
8
9#include "if.h"
10#include "log.h"
11#include "vty.h"
12#include "memory.h"
13#include "prefix.h"
469351b3 14#include "vrf.h"
9f0edbc9 15#include "linklist.h"
7176984f 16#include "plist.h"
a625e937 17#include "hash.h"
37664928 18#include "ferr.h"
5920b3eb 19#include "network.h"
12e41d03
DL
20
21#include "pimd.h"
c2cf4b02 22#include "pim_instance.h"
cba44481 23#include "pim_zebra.h"
12e41d03
DL
24#include "pim_iface.h"
25#include "pim_igmp.h"
26#include "pim_mroute.h"
27#include "pim_oil.h"
28#include "pim_str.h"
29#include "pim_pim.h"
30#include "pim_neighbor.h"
31#include "pim_ifchannel.h"
12e41d03
DL
32#include "pim_sock.h"
33#include "pim_time.h"
34#include "pim_ssmpingd.h"
7176984f 35#include "pim_rp.h"
cba44481 36#include "pim_nht.h"
69ccd63e 37#include "pim_jp_agg.h"
c936e76f 38#include "pim_igmp_join.h"
269c1fe1 39#include "pim_vxlan.h"
12e41d03 40
5e5034b0
DL
41#include "pim6_mld.h"
42
5a46a3de 43#if PIM_IPV == 4
12e41d03 44static void pim_if_igmp_join_del_all(struct interface *ifp);
5a46a3de 45#endif
bd2c824a
A
46static int gm_join_sock(const char *ifname, ifindex_t ifindex,
47 pim_addr group_addr, pim_addr source_addr,
48 struct pim_interface *pim_ifp);
12e41d03 49
f88df3a6 50void pim_if_init(struct pim_instance *pim)
ea4a71fc 51{
d62a17ae 52 int i;
dc0665f1 53
d62a17ae 54 for (i = 0; i < MAXVIFS; i++)
f88df3a6 55 pim->iface_vif_index[i] = 0;
ea4a71fc
DS
56}
57
f88df3a6 58void pim_if_terminate(struct pim_instance *pim)
ea4a71fc 59{
39949580
DS
60 struct interface *ifp;
61
62 FOR_ALL_INTERFACES (pim->vrf, ifp) {
63 struct pim_interface *pim_ifp = ifp->info;
64
65 if (!pim_ifp)
66 continue;
67
68 pim_if_delete(ifp);
69 }
1a8a3da8 70 return;
ea4a71fc
DS
71}
72
f09eaf1c
DS
73static void pim_sec_addr_free(struct pim_secondary_addr *sec_addr)
74{
75 XFREE(MTYPE_PIM_SEC_ADDR, sec_addr);
76}
77
94120cb2 78__attribute__((unused))
f09eaf1c
DS
79static int pim_sec_addr_comp(const void *p1, const void *p2)
80{
81 const struct pim_secondary_addr *sec1 = p1;
82 const struct pim_secondary_addr *sec2 = p2;
83
84 if (sec1->addr.family == AF_INET && sec2->addr.family == AF_INET6)
85 return -1;
86
87 if (sec1->addr.family == AF_INET6 && sec2->addr.family == AF_INET)
88 return 1;
89
90 if (sec1->addr.family == AF_INET) {
91 if (ntohl(sec1->addr.u.prefix4.s_addr)
92 < ntohl(sec2->addr.u.prefix4.s_addr))
93 return -1;
94
95 if (ntohl(sec1->addr.u.prefix4.s_addr)
96 > ntohl(sec2->addr.u.prefix4.s_addr))
97 return 1;
98 } else {
99 return memcmp(&sec1->addr.u.prefix6, &sec2->addr.u.prefix6,
100 sizeof(struct in6_addr));
101 }
102
103 return 0;
104}
105
5c1b3cd2 106struct pim_interface *pim_if_new(struct interface *ifp, bool gm, bool pim,
b1891fa0 107 bool ispimreg, bool is_vxlan_term)
12e41d03 108{
d62a17ae 109 struct pim_interface *pim_ifp;
110
df5dfb77
DL
111 assert(ifp);
112 assert(!ifp->info);
d62a17ae 113
114 pim_ifp = XCALLOC(MTYPE_PIM_INTERFACE, sizeof(*pim_ifp));
d62a17ae 115
096f7609 116 pim_ifp->pim = ifp->vrf->info;
d62a17ae 117 pim_ifp->mroute_vif_index = -1;
118
29e58225 119 pim_ifp->igmp_version = IGMP_DEFAULT_VERSION;
5afe22f5 120 pim_ifp->mld_version = MLD_DEFAULT_VERSION;
18adcff1 121 pim_ifp->gm_default_robustness_variable =
de5dc092
A
122 GM_DEFAULT_ROBUSTNESS_VARIABLE;
123 pim_ifp->gm_default_query_interval = GM_GENERAL_QUERY_INTERVAL;
18adcff1 124 pim_ifp->gm_query_max_response_time_dsec =
de5dc092 125 GM_QUERY_MAX_RESPONSE_TIME_DSEC;
18adcff1 126 pim_ifp->gm_specific_query_max_response_time_dsec =
de5dc092
A
127 GM_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC;
128 pim_ifp->gm_last_member_query_count = GM_DEFAULT_ROBUSTNESS_VARIABLE;
d62a17ae 129
2951a7a4 130 /* BSM config on interface: true by default */
19de48b9 131 pim_ifp->bsm_enable = true;
132 pim_ifp->ucast_bsm_accept = true;
46a9ea8b 133 pim_ifp->am_i_dr = false;
19de48b9 134
d62a17ae 135 /*
136 RFC 3376: 8.3. Query Response Interval
137 The number of seconds represented by the [Query Response Interval]
138 must be less than the [Query Interval].
139 */
18adcff1
SG
140 assert(pim_ifp->gm_query_max_response_time_dsec <
141 pim_ifp->gm_default_query_interval);
d62a17ae 142
b6fcc0b7 143 pim_ifp->pim_enable = pim;
78039cb2 144 pim_ifp->pim_passive_enable = false;
5c1b3cd2 145 pim_ifp->gm_enable = gm;
d62a17ae 146
18adcff1 147 pim_ifp->gm_join_list = NULL;
d62a17ae 148 pim_ifp->pim_neighbor_list = NULL;
149 pim_ifp->upstream_switch_list = NULL;
d62a17ae 150 pim_ifp->pim_generation_id = 0;
151
c5f76fad 152 /* list of struct gm_sock */
dda4d23c 153 pim_igmp_if_init(pim_ifp, ifp);
d62a17ae 154
155 /* list of struct pim_neighbor */
156 pim_ifp->pim_neighbor_list = list_new();
d62a17ae 157 pim_ifp->pim_neighbor_list->del = (void (*)(void *))pim_neighbor_free;
158
159 pim_ifp->upstream_switch_list = list_new();
69ccd63e
DS
160 pim_ifp->upstream_switch_list->del =
161 (void (*)(void *))pim_jp_agg_group_list_free;
162 pim_ifp->upstream_switch_list->cmp = pim_jp_agg_group_list_cmp;
d62a17ae 163
f09eaf1c 164 pim_ifp->sec_addr_list = list_new();
f09eaf1c
DS
165 pim_ifp->sec_addr_list->del = (void (*)(void *))pim_sec_addr_free;
166 pim_ifp->sec_addr_list->cmp =
167 (int (*)(void *, void *))pim_sec_addr_comp;
168
414d885a
DS
169 pim_ifp->activeactive = false;
170
ad7b74c4 171 RB_INIT(pim_ifchannel_rb, &pim_ifp->ifchannel_rb);
d62a17ae 172
173 ifp->info = pim_ifp;
174
175 pim_sock_reset(ifp);
176
b1891fa0 177 pim_if_add_vif(ifp, ispimreg, is_vxlan_term);
ccf696e8 178 pim_ifp->pim->mcast_if_count++;
d62a17ae 179
180 return pim_ifp;
12e41d03
DL
181}
182
183void pim_if_delete(struct interface *ifp)
184{
d62a17ae 185 struct pim_interface *pim_ifp;
12e41d03 186
df5dfb77 187 assert(ifp);
d62a17ae 188 pim_ifp = ifp->info;
df5dfb77 189 assert(pim_ifp);
12e41d03 190
94120cb2
DL
191 pim_ifp->pim->mcast_if_count--;
192#if PIM_IPV == 4
18adcff1 193 if (pim_ifp->gm_join_list) {
d62a17ae 194 pim_if_igmp_join_del_all(ifp);
195 }
97feb13f 196#endif
12e41d03 197
d62a17ae 198 pim_ifchannel_delete_all(ifp);
97feb13f 199#if PIM_IPV == 4
d62a17ae 200 igmp_sock_delete_all(ifp);
97feb13f 201#endif
1925ca8f
SP
202 if (pim_ifp->pim_sock_fd >= 0)
203 pim_sock_delete(ifp, "Interface removed from configuration");
12e41d03 204
d62a17ae 205 pim_if_del_vif(ifp);
12e41d03 206
dda4d23c
DL
207 pim_igmp_if_fini(pim_ifp);
208
6a154c88
DL
209 list_delete(&pim_ifp->pim_neighbor_list);
210 list_delete(&pim_ifp->upstream_switch_list);
211 list_delete(&pim_ifp->sec_addr_list);
12e41d03 212
2ce3c8ec
MR
213 if (pim_ifp->bfd_config.profile)
214 XFREE(MTYPE_TMP, pim_ifp->bfd_config.profile);
215
0a22ddfb 216 XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist);
d62a17ae 217 XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
12e41d03 218
d62a17ae 219 ifp->info = NULL;
12e41d03
DL
220}
221
222void pim_if_update_could_assert(struct interface *ifp)
223{
d62a17ae 224 struct pim_interface *pim_ifp;
d62a17ae 225 struct pim_ifchannel *ch;
12e41d03 226
d62a17ae 227 pim_ifp = ifp->info;
df5dfb77 228 assert(pim_ifp);
12e41d03 229
a2addae8 230 RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
d62a17ae 231 pim_ifchannel_update_could_assert(ch);
232 }
12e41d03
DL
233}
234
235static void pim_if_update_my_assert_metric(struct interface *ifp)
236{
d62a17ae 237 struct pim_interface *pim_ifp;
d62a17ae 238 struct pim_ifchannel *ch;
12e41d03 239
d62a17ae 240 pim_ifp = ifp->info;
df5dfb77 241 assert(pim_ifp);
12e41d03 242
a2addae8 243 RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
d62a17ae 244 pim_ifchannel_update_my_assert_metric(ch);
245 }
12e41d03
DL
246}
247
248static void pim_addr_change(struct interface *ifp)
249{
d62a17ae 250 struct pim_interface *pim_ifp;
251
252 pim_ifp = ifp->info;
df5dfb77 253 assert(pim_ifp);
d62a17ae 254
255 pim_if_dr_election(ifp); /* router's own DR Priority (addr) changes --
256 Done TODO T30 */
257 pim_if_update_join_desired(pim_ifp); /* depends on DR */
258 pim_if_update_could_assert(ifp); /* depends on DR */
259 pim_if_update_my_assert_metric(ifp); /* depends on could_assert */
260 pim_if_update_assert_tracking_desired(
261 ifp); /* depends on DR, join_desired */
262
263 /*
264 RFC 4601: 4.3.1. Sending Hello Messages
265
266 1) Before an interface goes down or changes primary IP address, a
267 Hello message with a zero HoldTime should be sent immediately
268 (with the old IP address if the IP address changed).
b279f95c 269 -- Done at the caller of the function as new ip already updated here
d62a17ae 270
271 2) After an interface has changed its IP address, it MUST send a
272 Hello message with its new IP address.
273 -- DONE below
274
275 3) If an interface changes one of its secondary IP addresses, a
276 Hello message with an updated Address_List option and a non-zero
277 HoldTime should be sent immediately.
278 -- FIXME See TODO T31
279 */
79992e8a 280 PIM_IF_FLAG_UNSET_HELLO_SENT(pim_ifp->flags);
d62a17ae 281 if (pim_ifp->pim_sock_fd < 0)
282 return;
283 pim_hello_restart_now(ifp); /* send hello and restart timer */
12e41d03
DL
284}
285
12e41d03
DL
286static int detect_primary_address_change(struct interface *ifp,
287 int force_prim_as_any,
288 const char *caller)
289{
d62a17ae 290 struct pim_interface *pim_ifp = ifp->info;
034db86b 291 pim_addr new_prim_addr;
d62a17ae 292 int changed;
293
294 if (force_prim_as_any)
034db86b 295 new_prim_addr = PIMADDR_ANY;
d62a17ae 296 else
297 new_prim_addr = pim_find_primary_addr(ifp);
298
034db86b 299 changed = pim_addr_cmp(new_prim_addr, pim_ifp->primary_address);
d62a17ae 300
034db86b
DL
301 if (PIM_DEBUG_ZEBRA)
302 zlog_debug("%s: old=%pPA new=%pPA on interface %s: %s",
303 __func__, &pim_ifp->primary_address, &new_prim_addr,
304 ifp->name, changed ? "changed" : "unchanged");
d62a17ae 305
306 if (changed) {
b279f95c 307 /* Before updating pim_ifp send Hello time with 0 hold time */
b6fcc0b7 308 if (pim_ifp->pim_enable) {
b279f95c 309 pim_hello_send(ifp, 0 /* zero-sec holdtime */);
310 }
d62a17ae 311 pim_ifp->primary_address = new_prim_addr;
312 }
313
314 return changed;
12e41d03
DL
315}
316
7176984f 317static struct pim_secondary_addr *
294b6d72 318pim_sec_addr_find(struct pim_interface *pim_ifp, struct prefix *addr)
7176984f 319{
d62a17ae 320 struct pim_secondary_addr *sec_addr;
321 struct listnode *node;
7176984f 322
d62a17ae 323 for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
ddba0a04 324 if (prefix_cmp(&sec_addr->addr, addr) == 0) {
d62a17ae 325 return sec_addr;
326 }
327 }
7176984f 328
d62a17ae 329 return NULL;
7176984f 330}
331
332static void pim_sec_addr_del(struct pim_interface *pim_ifp,
d62a17ae 333 struct pim_secondary_addr *sec_addr)
7176984f 334{
d62a17ae 335 listnode_delete(pim_ifp->sec_addr_list, sec_addr);
336 pim_sec_addr_free(sec_addr);
7176984f 337}
338
294b6d72 339static int pim_sec_addr_add(struct pim_interface *pim_ifp, struct prefix *addr)
7176984f 340{
d62a17ae 341 int changed = 0;
342 struct pim_secondary_addr *sec_addr;
343
344 sec_addr = pim_sec_addr_find(pim_ifp, addr);
345 if (sec_addr) {
346 sec_addr->flags &= ~PIM_SEC_ADDRF_STALE;
347 return changed;
348 }
349
d62a17ae 350 sec_addr = XCALLOC(MTYPE_PIM_SEC_ADDR, sizeof(*sec_addr));
d62a17ae 351
352 changed = 1;
353 sec_addr->addr = *addr;
354 listnode_add_sort(pim_ifp->sec_addr_list, sec_addr);
355
356 return changed;
7176984f 357}
358
359static int pim_sec_addr_del_all(struct pim_interface *pim_ifp)
360{
d62a17ae 361 int changed = 0;
362
d62a17ae 363 if (!list_isempty(pim_ifp->sec_addr_list)) {
364 changed = 1;
365 /* remove all nodes and free up the list itself */
366 list_delete_all_node(pim_ifp->sec_addr_list);
d62a17ae 367 }
368
369 return changed;
7176984f 370}
371
372static int pim_sec_addr_update(struct interface *ifp)
373{
d62a17ae 374 struct pim_interface *pim_ifp = ifp->info;
375 struct connected *ifc;
376 struct listnode *node;
377 struct listnode *nextnode;
378 struct pim_secondary_addr *sec_addr;
379 int changed = 0;
380
996c9314 381 for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
f09eaf1c 382 sec_addr->flags |= PIM_SEC_ADDRF_STALE;
d62a17ae 383 }
384
385 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
034db86b 386 pim_addr addr = pim_addr_from_prefix(ifc->address);
d62a17ae 387
034db86b 388 if (pim_addr_is_any(addr))
d62a17ae 389 continue;
d62a17ae 390
034db86b 391 if (!pim_addr_cmp(addr, pim_ifp->primary_address)) {
d62a17ae 392 /* don't add the primary address into the secondary
393 * address list */
394 continue;
395 }
396
034db86b 397 if (pim_sec_addr_add(pim_ifp, ifc->address)) {
d62a17ae 398 changed = 1;
399 }
400 }
401
f09eaf1c
DS
402 /* Drop stale entries */
403 for (ALL_LIST_ELEMENTS(pim_ifp->sec_addr_list, node, nextnode,
404 sec_addr)) {
405 if (sec_addr->flags & PIM_SEC_ADDRF_STALE) {
406 pim_sec_addr_del(pim_ifp, sec_addr);
407 changed = 1;
d62a17ae 408 }
409 }
410
411 return changed;
7176984f 412}
413
4763cd0e 414static int detect_secondary_address_change(struct interface *ifp,
d62a17ae 415 int force_prim_as_any,
416 const char *caller)
12e41d03 417{
d62a17ae 418 struct pim_interface *pim_ifp = ifp->info;
419 int changed = 0;
420
421 if (force_prim_as_any) {
422 /* if primary address is being forced to zero just flush the
423 * secondary address list */
424 changed = pim_sec_addr_del_all(pim_ifp);
425 } else {
426 /* re-evaluate the secondary address list */
427 changed = pim_sec_addr_update(ifp);
428 }
429
430 return changed;
4763cd0e 431}
432
d62a17ae 433static void detect_address_change(struct interface *ifp, int force_prim_as_any,
434 const char *caller)
4763cd0e 435{
d62a17ae 436 int changed = 0;
437 struct pim_interface *pim_ifp;
12e41d03 438
d62a17ae 439 pim_ifp = ifp->info;
440 if (!pim_ifp)
441 return;
4763cd0e 442
d62a17ae 443 if (detect_primary_address_change(ifp, force_prim_as_any, caller)) {
444 changed = 1;
445 }
12e41d03 446
d62a17ae 447 if (detect_secondary_address_change(ifp, force_prim_as_any, caller)) {
448 changed = 1;
449 }
4763cd0e 450
451
d62a17ae 452 if (changed) {
b6fcc0b7 453 if (!pim_ifp->pim_enable) {
d62a17ae 454 return;
455 }
4763cd0e 456
d62a17ae 457 pim_addr_change(ifp);
458 }
12e41d03 459
d62a17ae 460 /* XXX: if we have unnumbered interfaces we need to run detect address
461 * address change on all of them when the lo address changes */
12e41d03
DL
462}
463
034db86b 464int pim_update_source_set(struct interface *ifp, pim_addr source)
12e41d03 465{
d62a17ae 466 struct pim_interface *pim_ifp = ifp->info;
12e41d03 467
d62a17ae 468 if (!pim_ifp) {
469 return PIM_IFACE_NOT_FOUND;
470 }
12e41d03 471
034db86b 472 if (!pim_addr_cmp(pim_ifp->update_source, source)) {
d62a17ae 473 return PIM_UPDATE_SOURCE_DUP;
474 }
4763cd0e 475
d62a17ae 476 pim_ifp->update_source = source;
15569c58 477 detect_address_change(ifp, 0 /* force_prim_as_any */, __func__);
4763cd0e 478
d62a17ae 479 return PIM_SUCCESS;
12e41d03
DL
480}
481
482void pim_if_addr_add(struct connected *ifc)
483{
d62a17ae 484 struct pim_interface *pim_ifp;
485 struct interface *ifp;
650d9ad1 486 bool vxlan_term;
d62a17ae 487
df5dfb77 488 assert(ifc);
d62a17ae 489
490 ifp = ifc->ifp;
df5dfb77 491 assert(ifp);
d62a17ae 492 pim_ifp = ifp->info;
493 if (!pim_ifp)
494 return;
495
496 if (!if_is_operative(ifp))
497 return;
498
2dbe669b
DA
499 if (PIM_DEBUG_ZEBRA)
500 zlog_debug("%s: %s ifindex=%d connected IP address %pFX %s",
501 __func__, ifp->name, ifp->ifindex, ifc->address,
d62a17ae 502 CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)
503 ? "secondary"
504 : "primary");
cfef6155
DL
505#if PIM_IPV != 4
506 if (IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6) ||
507 IN6_IS_ADDR_LOOPBACK(&ifc->address->u.prefix6)) {
508 if (IN6_IS_ADDR_UNSPECIFIED(&pim_ifp->ll_lowest))
509 pim_ifp->ll_lowest = ifc->address->u.prefix6;
510 else if (IPV6_ADDR_CMP(&ifc->address->u.prefix6,
511 &pim_ifp->ll_lowest) < 0)
512 pim_ifp->ll_lowest = ifc->address->u.prefix6;
513
514 if (IPV6_ADDR_CMP(&ifc->address->u.prefix6,
515 &pim_ifp->ll_highest) > 0)
516 pim_ifp->ll_highest = ifc->address->u.prefix6;
517
518 if (PIM_DEBUG_ZEBRA)
519 zlog_debug(
520 "%s: new link-local %pI6, lowest now %pI6, highest %pI6",
521 ifc->ifp->name, &ifc->address->u.prefix6,
522 &pim_ifp->ll_lowest, &pim_ifp->ll_highest);
523 }
524#endif
d62a17ae 525
5e81f5dd 526 detect_address_change(ifp, 0, __func__);
d62a17ae 527
2002dcdb
DS
528 // if (ifc->address->family != AF_INET)
529 // return;
d62a17ae 530
94120cb2
DL
531#if PIM_IPV == 4
532 struct in_addr ifaddr = ifc->address->u.prefix4;
533
4fecac21 534 if (pim_ifp->gm_enable) {
c5f76fad 535 struct gm_sock *igmp;
d62a17ae 536
537 /* lookup IGMP socket */
18adcff1 538 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->gm_socket_list,
d62a17ae 539 ifaddr);
540 if (!igmp) {
541 /* if addr new, add IGMP socket */
c77a04e4 542 if (ifc->address->family == AF_INET)
18adcff1 543 pim_igmp_sock_add(pim_ifp->gm_socket_list,
29e58225 544 ifaddr, ifp, false);
f83f3966
MS
545 } else if (igmp->mtrace_only) {
546 igmp_sock_delete(igmp);
18adcff1
SG
547 pim_igmp_sock_add(pim_ifp->gm_socket_list, ifaddr, ifp,
548 false);
d62a17ae 549 }
550
551 /* Replay Static IGMP groups */
18adcff1 552 if (pim_ifp->gm_join_list) {
d62a17ae 553 struct listnode *node;
554 struct listnode *nextnode;
7caa9451 555 struct gm_join *ij;
d62a17ae 556 int join_fd;
557
18adcff1 558 for (ALL_LIST_ELEMENTS(pim_ifp->gm_join_list, node,
d62a17ae 559 nextnode, ij)) {
560 /* Close socket and reopen with Source and Group
561 */
562 close(ij->sock_fd);
bd2c824a 563 join_fd = gm_join_sock(
d62a17ae 564 ifp->name, ifp->ifindex, ij->group_addr,
f2058cb4 565 ij->source_addr, pim_ifp);
d62a17ae 566 if (join_fd < 0) {
567 char group_str[INET_ADDRSTRLEN];
568 char source_str[INET_ADDRSTRLEN];
569 pim_inet4_dump("<grp?>", ij->group_addr,
570 group_str,
571 sizeof(group_str));
572 pim_inet4_dump(
573 "<src?>", ij->source_addr,
574 source_str, sizeof(source_str));
575 zlog_warn(
bd2c824a 576 "%s: gm_join_sock() failure for IGMP group %s source %s on interface %s",
5e81f5dd
DS
577 __func__, group_str, source_str,
578 ifp->name);
d62a17ae 579 /* warning only */
580 } else
581 ij->sock_fd = join_fd;
582 }
583 }
584 } /* igmp */
f83f3966 585 else {
c5f76fad 586 struct gm_sock *igmp;
f83f3966
MS
587
588 /* lookup IGMP socket */
18adcff1 589 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->gm_socket_list,
f83f3966
MS
590 ifaddr);
591 if (ifc->address->family == AF_INET) {
592 if (igmp)
593 igmp_sock_delete(igmp);
594 /* if addr new, add IGMP socket */
18adcff1
SG
595 pim_igmp_sock_add(pim_ifp->gm_socket_list, ifaddr, ifp,
596 true);
f83f3966
MS
597 }
598 } /* igmp mtrace only */
94120cb2 599#endif
d62a17ae 600
b6fcc0b7 601 if (pim_ifp->pim_enable) {
d62a17ae 602
3ca68c9c 603 if (!pim_addr_is_any(pim_ifp->primary_address)) {
d62a17ae 604
605 /* Interface has a valid socket ? */
606 if (pim_ifp->pim_sock_fd < 0) {
607 if (pim_sock_add(ifp)) {
608 zlog_warn(
609 "Failure creating PIM socket for interface %s",
610 ifp->name);
611 }
612 }
613 struct pim_nexthop_cache *pnc = NULL;
614 struct pim_rpf rpf;
615 struct zclient *zclient = NULL;
616
617 zclient = pim_zebra_zclient_get();
618 /* RP config might come prior to (local RP's interface)
619 IF UP event.
620 In this case, pnc would not have pim enabled
621 nexthops.
622 Once Interface is UP and pim info is available,
623 reregister
624 with RNH address to receive update and add the
625 interface as nexthop. */
626 memset(&rpf, 0, sizeof(struct pim_rpf));
4a8336cf 627 rpf.rpf_addr = pim_addr_from_prefix(ifc->address);
d0a4f55d 628 pnc = pim_nexthop_cache_find(pim_ifp->pim, &rpf);
d62a17ae 629 if (pnc)
64c86530 630 pim_sendmsg_zebra_rnh(pim_ifp->pim, zclient,
cf663ceb 631 pnc,
d62a17ae 632 ZEBRA_NEXTHOP_REGISTER);
633 }
634 } /* pim */
635
636 /*
637 PIM or IGMP is enabled on interface, and there is at least one
638 address assigned, then try to create a vif_index.
639 */
640 if (pim_ifp->mroute_vif_index < 0) {
650d9ad1
AK
641 vxlan_term = pim_vxlan_is_term_dev_cfg(pim_ifp->pim, ifp);
642 pim_if_add_vif(ifp, false, vxlan_term);
d62a17ae 643 }
5e5034b0 644 gm_ifp_update(ifp);
d62a17ae 645 pim_ifchannel_scan_forward_start(ifp);
12e41d03
DL
646}
647
648static void pim_if_addr_del_igmp(struct connected *ifc)
649{
94120cb2 650#if PIM_IPV == 4
d62a17ae 651 struct pim_interface *pim_ifp = ifc->ifp->info;
c5f76fad 652 struct gm_sock *igmp;
d62a17ae 653 struct in_addr ifaddr;
654
655 if (ifc->address->family != AF_INET) {
656 /* non-IPv4 address */
657 return;
658 }
659
660 if (!pim_ifp) {
661 /* IGMP not enabled on interface */
662 return;
663 }
664
665 ifaddr = ifc->address->u.prefix4;
666
667 /* lookup IGMP socket */
18adcff1 668 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->gm_socket_list, ifaddr);
d62a17ae 669 if (igmp) {
670 /* if addr found, del IGMP socket */
671 igmp_sock_delete(igmp);
672 }
94120cb2 673#endif
12e41d03
DL
674}
675
676static void pim_if_addr_del_pim(struct connected *ifc)
677{
d62a17ae 678 struct pim_interface *pim_ifp = ifc->ifp->info;
12e41d03 679
78623256 680 if (ifc->address->family != PIM_AF) {
d62a17ae 681 /* non-IPv4 address */
682 return;
683 }
12e41d03 684
d62a17ae 685 if (!pim_ifp) {
686 /* PIM not enabled on interface */
687 return;
688 }
689
3ca68c9c 690 if (!pim_addr_is_any(pim_ifp->primary_address)) {
d62a17ae 691 /* Interface keeps a valid primary address */
692 return;
693 }
12e41d03 694
d62a17ae 695 if (pim_ifp->pim_sock_fd < 0) {
696 /* Interface does not hold a valid socket any longer */
697 return;
698 }
294b6d72 699
d62a17ae 700 /*
701 pim_sock_delete() closes the socket, stops read and timer threads,
702 and kills all neighbors.
703 */
704 pim_sock_delete(ifc->ifp,
705 "last address has been removed from interface");
706}
12e41d03 707
d62a17ae 708void pim_if_addr_del(struct connected *ifc, int force_prim_as_any)
709{
710 struct interface *ifp;
711
df5dfb77 712 assert(ifc);
d62a17ae 713 ifp = ifc->ifp;
df5dfb77 714 assert(ifp);
d62a17ae 715
2dbe669b
DA
716 if (PIM_DEBUG_ZEBRA)
717 zlog_debug("%s: %s ifindex=%d disconnected IP address %pFX %s",
718 __func__, ifp->name, ifp->ifindex, ifc->address,
d62a17ae 719 CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)
720 ? "secondary"
721 : "primary");
12e41d03 722
cfef6155
DL
723#if PIM_IPV == 6
724 struct pim_interface *pim_ifp = ifc->ifp->info;
725
726 if (pim_ifp &&
727 (!IPV6_ADDR_CMP(&ifc->address->u.prefix6, &pim_ifp->ll_lowest) ||
728 !IPV6_ADDR_CMP(&ifc->address->u.prefix6, &pim_ifp->ll_highest))) {
729 struct listnode *cnode;
730 struct connected *cc;
731
732 memset(&pim_ifp->ll_lowest, 0xff, sizeof(pim_ifp->ll_lowest));
733 memset(&pim_ifp->ll_highest, 0, sizeof(pim_ifp->ll_highest));
734
735 for (ALL_LIST_ELEMENTS_RO(ifc->ifp->connected, cnode, cc)) {
736 if (!IN6_IS_ADDR_LINKLOCAL(&cc->address->u.prefix6) &&
737 !IN6_IS_ADDR_LOOPBACK(&cc->address->u.prefix6))
738 continue;
739
740 if (IPV6_ADDR_CMP(&cc->address->u.prefix6,
741 &pim_ifp->ll_lowest) < 0)
742 pim_ifp->ll_lowest = cc->address->u.prefix6;
743 if (IPV6_ADDR_CMP(&cc->address->u.prefix6,
744 &pim_ifp->ll_highest) > 0)
745 pim_ifp->ll_highest = cc->address->u.prefix6;
746 }
747
748 if (pim_ifp->ll_lowest.s6_addr[0] == 0xff)
749 memset(&pim_ifp->ll_lowest, 0,
750 sizeof(pim_ifp->ll_lowest));
751
752 if (PIM_DEBUG_ZEBRA)
753 zlog_debug(
754 "%s: removed link-local %pI6, lowest now %pI6, highest %pI6",
755 ifc->ifp->name, &ifc->address->u.prefix6,
756 &pim_ifp->ll_lowest, &pim_ifp->ll_highest);
5e5034b0
DL
757
758 gm_ifp_update(ifp);
cfef6155
DL
759 }
760#endif
761
15569c58 762 detect_address_change(ifp, force_prim_as_any, __func__);
d62a17ae 763
764 pim_if_addr_del_igmp(ifc);
765 pim_if_addr_del_pim(ifc);
12e41d03
DL
766}
767
768void pim_if_addr_add_all(struct interface *ifp)
769{
d62a17ae 770 struct connected *ifc;
771 struct listnode *node;
772 struct listnode *nextnode;
773 int v4_addrs = 0;
774 int v6_addrs = 0;
775 struct pim_interface *pim_ifp = ifp->info;
650d9ad1 776 bool vxlan_term;
d62a17ae 777
778
779 /* PIM/IGMP enabled ? */
780 if (!pim_ifp)
781 return;
782
783 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
784 struct prefix *p = ifc->address;
785
786 if (p->family != AF_INET)
787 v6_addrs++;
788 else
789 v4_addrs++;
790 pim_if_addr_add(ifc);
791 }
d8424057 792
0c7f978e
MR
793 if (!v4_addrs && v6_addrs && !if_is_loopback(ifp) &&
794 pim_ifp->pim_enable && !pim_addr_is_any(pim_ifp->primary_address) &&
795 pim_ifp->pim_sock_fd < 0 && pim_sock_add(ifp)) {
796 /* Interface has a valid primary address ? */
797 /* Interface has a valid socket ? */
798 zlog_warn("Failure creating PIM socket for interface %s",
799 ifp->name);
d62a17ae 800 }
801 /*
5c1b3cd2 802 * PIM or IGMP/MLD is enabled on interface, and there is at least one
d62a17ae 803 * address assigned, then try to create a vif_index.
804 */
805 if (pim_ifp->mroute_vif_index < 0) {
650d9ad1
AK
806 vxlan_term = pim_vxlan_is_term_dev_cfg(pim_ifp->pim, ifp);
807 pim_if_add_vif(ifp, false, vxlan_term);
d62a17ae 808 }
5e5034b0 809 gm_ifp_update(ifp);
d62a17ae 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;
819f099b
DS
821 struct pim_instance *pim;
822
096f7609
IR
823 pim = ifp->vrf->info;
824 if (!pim)
819f099b 825 return;
d62a17ae 826
827 /* PIM/IGMP enabled ? */
828 if (!ifp->info)
829 return;
12e41d03 830
d62a17ae 831 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
832 struct prefix *p = ifc->address;
12e41d03 833
78623256 834 if (p->family != PIM_AF)
d62a17ae 835 continue;
12e41d03 836
d62a17ae 837 pim_if_addr_del(ifc, 1 /* force_prim_as_any=true */);
838 }
da3dcffb 839
5ec5d976
DS
840 pim_rp_setup(pim);
841 pim_i_am_rp_re_evaluate(pim);
12e41d03
DL
842}
843
844void pim_if_addr_del_all_igmp(struct interface *ifp)
845{
d62a17ae 846 struct connected *ifc;
847 struct listnode *node;
848 struct listnode *nextnode;
849
850 /* PIM/IGMP enabled ? */
851 if (!ifp->info)
852 return;
853
854 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
855 struct prefix *p = ifc->address;
856
857 if (p->family != AF_INET)
858 continue;
859
860 pim_if_addr_del_igmp(ifc);
861 }
12e41d03
DL
862}
863
034db86b 864pim_addr pim_find_primary_addr(struct interface *ifp)
12e41d03 865{
d62a17ae 866 struct connected *ifc;
867 struct listnode *node;
d62a17ae 868 struct pim_interface *pim_ifp = ifp->info;
819f099b 869
cfef6155 870 if (pim_ifp && !pim_addr_is_any(pim_ifp->update_source))
d62a17ae 871 return pim_ifp->update_source;
cfef6155
DL
872
873#if PIM_IPV == 6
b4460a6b 874 if (pim_ifp && !pim_addr_is_any(pim_ifp->ll_highest))
cfef6155
DL
875 return pim_ifp->ll_highest;
876
877 pim_addr best_addr = PIMADDR_ANY;
d62a17ae 878
879 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
034db86b 880 pim_addr addr;
d62a17ae 881
cfef6155
DL
882 if (ifc->address->family != AF_INET6)
883 continue;
884
885 addr = pim_addr_from_prefix(ifc->address);
886 if (!IN6_IS_ADDR_LINKLOCAL(&addr))
887 continue;
888 if (pim_addr_cmp(addr, best_addr) > 0)
889 best_addr = addr;
890 }
891
892 return best_addr;
893#else
894 int v4_addrs = 0;
895 int v6_addrs = 0;
896
897 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
034db86b
DL
898 switch (ifc->address->family) {
899 case AF_INET:
900 v4_addrs++;
901 break;
902 case AF_INET6:
d62a17ae 903 v6_addrs++;
034db86b
DL
904 break;
905 default:
d62a17ae 906 continue;
907 }
908
034db86b 909 if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
d62a17ae 910 continue;
d62a17ae 911
034db86b 912 if (ifc->address->family != PIM_AF)
d62a17ae 913 continue;
914
cfef6155 915 return pim_addr_from_prefix(ifc->address);
d62a17ae 916 }
917
918 /*
919 * If we have no v4_addrs and v6 is configured
920 * We probably are using unnumbered
921 * So let's grab the loopbacks v4 address
922 * and use that as the primary address
923 */
2430f057 924 if (!v4_addrs && v6_addrs) {
d62a17ae 925 struct interface *lo_ifp;
2430f057 926
fec883d9 927 // DBS - Come back and check here
096f7609
IR
928 if (ifp->vrf->vrf_id == VRF_DEFAULT)
929 lo_ifp = if_lookup_by_name("lo", ifp->vrf->vrf_id);
896b2044 930 else
096f7609
IR
931 lo_ifp = if_lookup_by_name(ifp->vrf->name,
932 ifp->vrf->vrf_id);
896b2044 933
2430f057 934 if (lo_ifp && (lo_ifp != ifp))
d62a17ae 935 return pim_find_primary_addr(lo_ifp);
936 }
034db86b 937 return PIMADDR_ANY;
cfef6155 938#endif
12e41d03
DL
939}
940
d62a17ae 941static int pim_iface_next_vif_index(struct interface *ifp)
744d91b3 942{
f88df3a6
DS
943 struct pim_interface *pim_ifp = ifp->info;
944 struct pim_instance *pim = pim_ifp->pim;
d62a17ae 945 int i;
f88df3a6 946
d62a17ae 947 /*
948 * The pimreg vif is always going to be in index 0
949 * of the table.
950 */
951 if (ifp->ifindex == PIM_OIF_PIM_REGISTER_VIF)
952 return 0;
953
954 for (i = 1; i < MAXVIFS; i++) {
f88df3a6 955 if (pim->iface_vif_index[i] == 0)
d62a17ae 956 return i;
957 }
958 return MAXVIFS;
744d91b3
DS
959}
960
12e41d03
DL
961/*
962 pim_if_add_vif() uses ifindex as vif_index
963
964 see also pim_if_find_vifindex_by_ifindex()
965 */
b1891fa0 966int pim_if_add_vif(struct interface *ifp, bool ispimreg, bool is_vxlan_term)
12e41d03 967{
d62a17ae 968 struct pim_interface *pim_ifp = ifp->info;
3ca68c9c 969 pim_addr ifaddr;
d62a17ae 970 unsigned char flags = 0;
971
df5dfb77 972 assert(pim_ifp);
d62a17ae 973
974 if (pim_ifp->mroute_vif_index > 0) {
975 zlog_warn("%s: vif_index=%d > 0 on interface %s ifindex=%d",
15569c58
DA
976 __func__, pim_ifp->mroute_vif_index, ifp->name,
977 ifp->ifindex);
d62a17ae 978 return -1;
979 }
980
981 if (ifp->ifindex < 0) {
f403844a 982 zlog_warn("%s: ifindex=%d < 0 on interface %s", __func__,
15569c58 983 ifp->ifindex, ifp->name);
d62a17ae 984 return -2;
f403844a 985 } else if ((ifp->ifindex == PIM_OIF_PIM_REGISTER_VIF) &&
522ec0a9
SG
986 ((strncmp(ifp->name, "pimreg", 6)) &&
987 (strncmp(ifp->name, "pim6reg", 7)))) {
f403844a 988 zlog_warn("%s: ifindex=%d on interface %s", __func__,
522ec0a9
SG
989 ifp->ifindex, ifp->name);
990 return -2;
d62a17ae 991 }
992
993 ifaddr = pim_ifp->primary_address;
5e5034b0
DL
994#if PIM_IPV != 6
995 /* IPv6 API is always by interface index */
3ca68c9c 996 if (!ispimreg && !is_vxlan_term && pim_addr_is_any(ifaddr)) {
d62a17ae 997 zlog_warn(
998 "%s: could not get address for interface %s ifindex=%d",
15569c58 999 __func__, ifp->name, ifp->ifindex);
d62a17ae 1000 return -4;
1001 }
5e5034b0 1002#endif
d62a17ae 1003
1004 pim_ifp->mroute_vif_index = pim_iface_next_vif_index(ifp);
1005
1006 if (pim_ifp->mroute_vif_index >= MAXVIFS) {
1007 zlog_warn(
1008 "%s: Attempting to configure more than MAXVIFS=%d on pim enabled interface %s",
15569c58 1009 __func__, MAXVIFS, ifp->name);
d62a17ae 1010 return -3;
1011 }
1012
1013 if (ifp->ifindex == PIM_OIF_PIM_REGISTER_VIF)
1014 flags = VIFF_REGISTER;
b3f2bf7c 1015#ifdef VIFF_USE_IFINDEX
d62a17ae 1016 else
1017 flags = VIFF_USE_IFINDEX;
b3f2bf7c
RW
1018#endif
1019
d62a17ae 1020 if (pim_mroute_add_vif(ifp, ifaddr, flags)) {
1021 /* pim_mroute_add_vif reported error */
1022 return -5;
1023 }
12e41d03 1024
f88df3a6 1025 pim_ifp->pim->iface_vif_index[pim_ifp->mroute_vif_index] = 1;
269c1fe1 1026
2ea34a81 1027 if (!ispimreg)
1028 gm_ifp_update(ifp);
5e5034b0 1029
269c1fe1
AK
1030 /* if the device qualifies as pim_vxlan iif/oif update vxlan entries */
1031 pim_vxlan_add_vif(ifp);
d62a17ae 1032 return 0;
12e41d03
DL
1033}
1034
12e41d03
DL
1035int pim_if_del_vif(struct interface *ifp)
1036{
d62a17ae 1037 struct pim_interface *pim_ifp = ifp->info;
12e41d03 1038
d62a17ae 1039 if (pim_ifp->mroute_vif_index < 1) {
1040 zlog_warn("%s: vif_index=%d < 1 on interface %s ifindex=%d",
15569c58
DA
1041 __func__, pim_ifp->mroute_vif_index, ifp->name,
1042 ifp->ifindex);
d62a17ae 1043 return -1;
1044 }
12e41d03 1045
269c1fe1
AK
1046 /* if the device was a pim_vxlan iif/oif update vxlan mroute entries */
1047 pim_vxlan_del_vif(ifp);
1048
5e5034b0
DL
1049 gm_ifp_teardown(ifp);
1050
ea3d967b 1051 pim_mroute_del_vif(ifp);
12e41d03 1052
d62a17ae 1053 /*
1054 Update vif_index
1055 */
f88df3a6 1056 pim_ifp->pim->iface_vif_index[pim_ifp->mroute_vif_index] = 0;
12e41d03 1057
d62a17ae 1058 pim_ifp->mroute_vif_index = -1;
d62a17ae 1059 return 0;
12e41d03
DL
1060}
1061
da82728d 1062// DBS - VRF Revist
7cfc7bcf
DS
1063struct interface *pim_if_find_by_vif_index(struct pim_instance *pim,
1064 ifindex_t vif_index)
12e41d03 1065{
d62a17ae 1066 struct interface *ifp;
12e41d03 1067
451fda4f 1068 FOR_ALL_INTERFACES (pim->vrf, ifp) {
7cfc7bcf
DS
1069 if (ifp->info) {
1070 struct pim_interface *pim_ifp;
1071 pim_ifp = ifp->info;
b892f1dd 1072
7cfc7bcf
DS
1073 if (vif_index == pim_ifp->mroute_vif_index)
1074 return ifp;
d62a17ae 1075 }
1076 }
12e41d03 1077
d62a17ae 1078 return 0;
12e41d03
DL
1079}
1080
1081/*
1082 pim_if_add_vif() uses ifindex as vif_index
1083 */
7cfc7bcf 1084int pim_if_find_vifindex_by_ifindex(struct pim_instance *pim, ifindex_t ifindex)
12e41d03 1085{
d62a17ae 1086 struct pim_interface *pim_ifp;
1087 struct interface *ifp;
ae90dfbb 1088
d3cc1e45 1089 ifp = if_lookup_by_index(ifindex, pim->vrf->vrf_id);
d62a17ae 1090 if (!ifp || !ifp->info)
1091 return -1;
1092 pim_ifp = ifp->info;
ae90dfbb 1093
d62a17ae 1094 return pim_ifp->mroute_vif_index;
12e41d03
DL
1095}
1096
1097int pim_if_lan_delay_enabled(struct interface *ifp)
1098{
d62a17ae 1099 struct pim_interface *pim_ifp;
12e41d03 1100
d62a17ae 1101 pim_ifp = ifp->info;
df5dfb77
DL
1102 assert(pim_ifp);
1103 assert(pim_ifp->pim_number_of_nonlandelay_neighbors >= 0);
12e41d03 1104
d62a17ae 1105 return pim_ifp->pim_number_of_nonlandelay_neighbors == 0;
12e41d03
DL
1106}
1107
1108uint16_t pim_if_effective_propagation_delay_msec(struct interface *ifp)
1109{
d62a17ae 1110 if (pim_if_lan_delay_enabled(ifp)) {
1111 struct pim_interface *pim_ifp;
1112 pim_ifp = ifp->info;
1113 return pim_ifp->pim_neighbors_highest_propagation_delay_msec;
1114 } else {
1115 return PIM_DEFAULT_PROPAGATION_DELAY_MSEC;
1116 }
12e41d03
DL
1117}
1118
1119uint16_t pim_if_effective_override_interval_msec(struct interface *ifp)
1120{
d62a17ae 1121 if (pim_if_lan_delay_enabled(ifp)) {
1122 struct pim_interface *pim_ifp;
1123 pim_ifp = ifp->info;
1124 return pim_ifp->pim_neighbors_highest_override_interval_msec;
1125 } else {
1126 return PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC;
1127 }
12e41d03
DL
1128}
1129
1130int pim_if_t_override_msec(struct interface *ifp)
1131{
d62a17ae 1132 int effective_override_interval_msec;
1133 int t_override_msec;
12e41d03 1134
d62a17ae 1135 effective_override_interval_msec =
1136 pim_if_effective_override_interval_msec(ifp);
12e41d03 1137
5920b3eb
RZ
1138 t_override_msec =
1139 frr_weak_random() % (effective_override_interval_msec + 1);
12e41d03 1140
d62a17ae 1141 return t_override_msec;
12e41d03
DL
1142}
1143
1144uint16_t pim_if_jp_override_interval_msec(struct interface *ifp)
1145{
d62a17ae 1146 return pim_if_effective_propagation_delay_msec(ifp)
1147 + pim_if_effective_override_interval_msec(ifp);
12e41d03
DL
1148}
1149
1150/*
1151 RFC 4601: 4.1.6. State Summarization Macros
1152
1153 The function NBR( I, A ) uses information gathered through PIM Hello
1154 messages to map the IP address A of a directly connected PIM
1155 neighbor router on interface I to the primary IP address of the same
1156 router (Section 4.3.4). The primary IP address of a neighbor is the
1157 address that it uses as the source of its PIM Hello messages.
1158*/
9bb93fa0 1159struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp, pim_addr addr)
12e41d03 1160{
d62a17ae 1161 struct listnode *neighnode;
1162 struct pim_neighbor *neigh;
1163 struct pim_interface *pim_ifp;
1164 struct prefix p;
1165
df5dfb77 1166 assert(ifp);
d62a17ae 1167
1168 pim_ifp = ifp->info;
1169 if (!pim_ifp) {
5e81f5dd
DS
1170 zlog_warn("%s: multicast not enabled on interface %s", __func__,
1171 ifp->name);
d62a17ae 1172 return 0;
1173 }
1174
9bb93fa0 1175 pim_addr_to_prefix(&p, addr);
d62a17ae 1176
1177 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode,
1178 neigh)) {
1179
1180 /* primary address ? */
9bb93fa0 1181 if (!pim_addr_cmp(neigh->source_addr, addr))
d62a17ae 1182 return neigh;
1183
1184 /* secondary address ? */
1185 if (pim_neighbor_find_secondary(neigh, &p))
1186 return neigh;
1187 }
1188
9bb93fa0 1189 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1190 zlog_debug(
9bb93fa0
DL
1191 "%s: neighbor not found for address %pPA on interface %s",
1192 __func__, &addr, ifp->name);
d62a17ae 1193
1194 return NULL;
12e41d03
DL
1195}
1196
1197long pim_if_t_suppressed_msec(struct interface *ifp)
1198{
d62a17ae 1199 struct pim_interface *pim_ifp;
1200 long t_suppressed_msec;
1201 uint32_t ramount = 0;
12e41d03 1202
d62a17ae 1203 pim_ifp = ifp->info;
df5dfb77 1204 assert(pim_ifp);
12e41d03 1205
d62a17ae 1206 /* join suppression disabled ? */
b6fcc0b7 1207 if (pim_ifp->pim_can_disable_join_suppression)
d62a17ae 1208 return 0;
12e41d03 1209
d62a17ae 1210 /* t_suppressed = t_periodic * rand(1.1, 1.4) */
5920b3eb 1211 ramount = 1100 + (frr_weak_random() % (1400 - 1100 + 1));
5b45753e 1212 t_suppressed_msec = router->t_periodic * ramount;
12e41d03 1213
d62a17ae 1214 return t_suppressed_msec;
12e41d03
DL
1215}
1216
bd2c824a 1217static void gm_join_free(struct gm_join *ij)
12e41d03 1218{
d62a17ae 1219 XFREE(MTYPE_PIM_IGMP_JOIN, ij);
12e41d03
DL
1220}
1221
bd2c824a
A
1222static struct gm_join *gm_join_find(struct list *join_list, pim_addr group_addr,
1223 pim_addr source_addr)
12e41d03 1224{
d62a17ae 1225 struct listnode *node;
7caa9451 1226 struct gm_join *ij;
12e41d03 1227
df5dfb77 1228 assert(join_list);
12e41d03 1229
d62a17ae 1230 for (ALL_LIST_ELEMENTS_RO(join_list, node, ij)) {
bd2c824a
A
1231 if ((!pim_addr_cmp(group_addr, ij->group_addr)) &&
1232 (!pim_addr_cmp(source_addr, ij->source_addr)))
d62a17ae 1233 return ij;
1234 }
12e41d03 1235
d62a17ae 1236 return 0;
12e41d03
DL
1237}
1238
bd2c824a
A
1239static int gm_join_sock(const char *ifname, ifindex_t ifindex,
1240 pim_addr group_addr, pim_addr source_addr,
1241 struct pim_interface *pim_ifp)
12e41d03 1242{
d62a17ae 1243 int join_fd;
12e41d03 1244
f2058cb4
DA
1245 pim_ifp->igmp_ifstat_joins_sent++;
1246
bd2c824a 1247 join_fd = pim_socket_raw(IPPROTO_GM);
d62a17ae 1248 if (join_fd < 0) {
f2058cb4 1249 pim_ifp->igmp_ifstat_joins_failed++;
d62a17ae 1250 return -1;
1251 }
12e41d03 1252
bd2c824a 1253 if (pim_gm_join_source(join_fd, ifindex, group_addr, source_addr)) {
c936e76f 1254 zlog_warn(
bd2c824a
A
1255 "%s: setsockopt(fd=%d) failure for " GM
1256 " group %pPAs source %pPAs ifindex %d on interface %s: errno=%d: %s",
1257 __func__, join_fd, &group_addr, &source_addr, ifindex,
15569c58 1258 ifname, errno, safe_strerror(errno));
c936e76f 1259
f2058cb4
DA
1260 pim_ifp->igmp_ifstat_joins_failed++;
1261
d62a17ae 1262 close(join_fd);
1263 return -2;
1264 }
12e41d03 1265
d62a17ae 1266 return join_fd;
12e41d03
DL
1267}
1268
bd2c824a
A
1269static struct gm_join *gm_join_new(struct interface *ifp, pim_addr group_addr,
1270 pim_addr source_addr)
12e41d03 1271{
d62a17ae 1272 struct pim_interface *pim_ifp;
7caa9451 1273 struct gm_join *ij;
d62a17ae 1274 int join_fd;
1275
1276 pim_ifp = ifp->info;
df5dfb77 1277 assert(pim_ifp);
d62a17ae 1278
bd2c824a
A
1279 join_fd = gm_join_sock(ifp->name, ifp->ifindex, group_addr, source_addr,
1280 pim_ifp);
d62a17ae 1281 if (join_fd < 0) {
bd2c824a
A
1282 zlog_warn("%s: gm_join_sock() failure for " GM
1283 " group %pPAs source %pPAs on interface %s",
1284 __func__, &group_addr, &source_addr, ifp->name);
d62a17ae 1285 return 0;
1286 }
1287
1288 ij = XCALLOC(MTYPE_PIM_IGMP_JOIN, sizeof(*ij));
d62a17ae 1289
1290 ij->sock_fd = join_fd;
1291 ij->group_addr = group_addr;
1292 ij->source_addr = source_addr;
1293 ij->sock_creation = pim_time_monotonic_sec();
1294
18adcff1 1295 listnode_add(pim_ifp->gm_join_list, ij);
d62a17ae 1296
1297 return ij;
12e41d03
DL
1298}
1299
bd2c824a
A
1300ferr_r pim_if_gm_join_add(struct interface *ifp, pim_addr group_addr,
1301 pim_addr source_addr)
12e41d03 1302{
d62a17ae 1303 struct pim_interface *pim_ifp;
7caa9451 1304 struct gm_join *ij;
d62a17ae 1305
1306 pim_ifp = ifp->info;
1307 if (!pim_ifp) {
37664928
DS
1308 return ferr_cfg_invalid("multicast not enabled on interface %s",
1309 ifp->name);
d62a17ae 1310 }
1311
18adcff1
SG
1312 if (!pim_ifp->gm_join_list) {
1313 pim_ifp->gm_join_list = list_new();
bd2c824a 1314 pim_ifp->gm_join_list->del = (void (*)(void *))gm_join_free;
d62a17ae 1315 }
1316
bd2c824a 1317 ij = gm_join_find(pim_ifp->gm_join_list, group_addr, source_addr);
53d829f5 1318
bd2c824a
A
1319 /* This interface has already been configured to join this IGMP/MLD
1320 * group
53d829f5 1321 */
d62a17ae 1322 if (ij) {
53d829f5 1323 return ferr_ok();
d62a17ae 1324 }
1325
bd2c824a 1326 (void)gm_join_new(ifp, group_addr, source_addr);
d62a17ae 1327
95b13dc5 1328 if (PIM_DEBUG_GM_EVENTS) {
d62a17ae 1329 zlog_debug(
bd2c824a
A
1330 "%s: issued static " GM
1331 " join for channel (S,G)=(%pPA,%pPA) on interface %s",
1332 __func__, &source_addr, &group_addr, ifp->name);
d62a17ae 1333 }
12e41d03 1334
37664928 1335 return ferr_ok();
d62a17ae 1336}
12e41d03 1337
bd2c824a
A
1338int pim_if_gm_join_del(struct interface *ifp, pim_addr group_addr,
1339 pim_addr source_addr)
12e41d03 1340{
d62a17ae 1341 struct pim_interface *pim_ifp;
7caa9451 1342 struct gm_join *ij;
d62a17ae 1343
1344 pim_ifp = ifp->info;
1345 if (!pim_ifp) {
15569c58
DA
1346 zlog_warn("%s: multicast not enabled on interface %s", __func__,
1347 ifp->name);
d62a17ae 1348 return -1;
1349 }
1350
18adcff1 1351 if (!pim_ifp->gm_join_list) {
bd2c824a 1352 zlog_warn("%s: no " GM " join on interface %s", __func__,
15569c58 1353 ifp->name);
d62a17ae 1354 return -2;
1355 }
1356
bd2c824a 1357 ij = gm_join_find(pim_ifp->gm_join_list, group_addr, source_addr);
d62a17ae 1358 if (!ij) {
bd2c824a
A
1359 zlog_warn("%s: could not find " GM
1360 " group %pPAs source %pPAs on interface %s",
1361 __func__, &group_addr, &source_addr, ifp->name);
d62a17ae 1362 return -3;
1363 }
1364
1365 if (close(ij->sock_fd)) {
d62a17ae 1366 zlog_warn(
bd2c824a
A
1367 "%s: failure closing sock_fd=%d for " GM
1368 " group %pPAs source %pPAs on interface %s: errno=%d: %s",
1369 __func__, ij->sock_fd, &group_addr, &source_addr,
1370 ifp->name, errno, safe_strerror(errno));
d62a17ae 1371 /* warning only */
1372 }
18adcff1 1373 listnode_delete(pim_ifp->gm_join_list, ij);
bd2c824a 1374 gm_join_free(ij);
18adcff1
SG
1375 if (listcount(pim_ifp->gm_join_list) < 1) {
1376 list_delete(&pim_ifp->gm_join_list);
1377 pim_ifp->gm_join_list = 0;
d62a17ae 1378 }
1379
1380 return 0;
12e41d03
DL
1381}
1382
bd2c824a 1383#if PIM_IPV == 4
94120cb2 1384__attribute__((unused))
12e41d03
DL
1385static void pim_if_igmp_join_del_all(struct interface *ifp)
1386{
d62a17ae 1387 struct pim_interface *pim_ifp;
1388 struct listnode *node;
1389 struct listnode *nextnode;
7caa9451 1390 struct gm_join *ij;
d62a17ae 1391
1392 pim_ifp = ifp->info;
1393 if (!pim_ifp) {
5e81f5dd
DS
1394 zlog_warn("%s: multicast not enabled on interface %s", __func__,
1395 ifp->name);
d62a17ae 1396 return;
1397 }
1398
18adcff1 1399 if (!pim_ifp->gm_join_list)
d62a17ae 1400 return;
1401
18adcff1 1402 for (ALL_LIST_ELEMENTS(pim_ifp->gm_join_list, node, nextnode, ij))
bd2c824a 1403 pim_if_gm_join_del(ifp, ij->group_addr, ij->source_addr);
12e41d03 1404}
bd2c824a 1405#endif /* PIM_IPV == 4 */
12e41d03
DL
1406
1407/*
1408 RFC 4601
1409
1410 Transitions from "I am Assert Loser" State
1411
1412 Current Winner's GenID Changes or NLT Expires
1413
1414 The Neighbor Liveness Timer associated with the current winner
1415 expires or we receive a Hello message from the current winner
1416 reporting a different GenID from the one it previously reported.
1417 This indicates that the current winner's interface or router has
1418 gone down (and may have come back up), and so we must assume it no
1419 longer knows it was the winner.
1420 */
9bb93fa0 1421void pim_if_assert_on_neighbor_down(struct interface *ifp, pim_addr neigh_addr)
12e41d03 1422{
d62a17ae 1423 struct pim_interface *pim_ifp;
d62a17ae 1424 struct pim_ifchannel *ch;
1425
1426 pim_ifp = ifp->info;
df5dfb77 1427 assert(pim_ifp);
d62a17ae 1428
a2addae8 1429 RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
d62a17ae 1430 /* Is (S,G,I) assert loser ? */
1431 if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER)
1432 continue;
1433 /* Dead neighbor was winner ? */
9bb93fa0 1434 if (pim_addr_cmp(ch->ifassert_winner, neigh_addr))
d62a17ae 1435 continue;
1436
1437 assert_action_a5(ch);
1438 }
12e41d03
DL
1439}
1440
1441void pim_if_update_join_desired(struct pim_interface *pim_ifp)
1442{
d62a17ae 1443 struct pim_ifchannel *ch;
12e41d03 1444
d62a17ae 1445 /* clear off flag from interface's upstreams */
a2addae8 1446 RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
d62a17ae 1447 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(
1448 ch->upstream->flags);
1449 }
12e41d03 1450
d62a17ae 1451 /* scan per-interface (S,G,I) state on this I interface */
a2addae8 1452 RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
d62a17ae 1453 struct pim_upstream *up = ch->upstream;
12e41d03 1454
d62a17ae 1455 if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up->flags))
1456 continue;
12e41d03 1457
d62a17ae 1458 /* update join_desired for the global (S,G) state */
9b29ea95 1459 pim_upstream_update_join_desired(pim_ifp->pim, up);
d62a17ae 1460 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up->flags);
1461 }
12e41d03
DL
1462}
1463
1464void pim_if_update_assert_tracking_desired(struct interface *ifp)
1465{
d62a17ae 1466 struct pim_interface *pim_ifp;
d62a17ae 1467 struct pim_ifchannel *ch;
1468
1469 pim_ifp = ifp->info;
1470 if (!pim_ifp)
1471 return;
1472
a2addae8 1473 RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
d62a17ae 1474 pim_ifchannel_update_assert_tracking_desired(ch);
1475 }
12e41d03 1476}
c992c9a0
DS
1477
1478/*
1479 * PIM wants to have an interface pointer for everything it does.
1480 * The pimreg is a special interface that we have that is not
3819e4ce 1481 * quite an interface but a VIF is created for it.
c992c9a0 1482 */
43e40fdf 1483void pim_if_create_pimreg(struct pim_instance *pim)
c992c9a0 1484{
bcc24579 1485 char pimreg_name[INTERFACE_NAMSIZ];
c992c9a0 1486
43e40fdf 1487 if (!pim->regiface) {
d3cc1e45 1488 if (pim->vrf->vrf_id == VRF_DEFAULT)
ee1c4ba9 1489 strlcpy(pimreg_name, PIMREG, sizeof(pimreg_name));
afa2b179 1490 else
ee1c4ba9 1491 snprintf(pimreg_name, sizeof(pimreg_name), PIMREG "%u",
bcc24579 1492 pim->vrf->data.l.table_id);
afa2b179 1493
f60a1188
IR
1494 pim->regiface = if_get_by_name(pimreg_name, pim->vrf->vrf_id,
1495 pim->vrf->name);
43e40fdf
DS
1496 pim->regiface->ifindex = PIM_OIF_PIM_REGISTER_VIF;
1497
7ae7a3bf
DS
1498 if (!pim->regiface->info)
1499 pim_if_new(pim->regiface, false, false, true,
1500 false /*vxlan_term*/);
1501
85d25587
DS
1502 /*
1503 * On vrf moves we delete the interface if there
1504 * is nothing going on with it. We cannot have
1505 * the pimregiface deleted.
1506 */
1507 pim->regiface->configured = true;
1508
d62a17ae 1509 }
c992c9a0 1510}
3565202d 1511
034db86b 1512struct prefix *pim_if_connected_to_source(struct interface *ifp, pim_addr src)
3565202d 1513{
d62a17ae 1514 struct listnode *cnode;
1515 struct connected *c;
1516 struct prefix p;
1517
1518 if (!ifp)
efe6f185 1519 return NULL;
d62a17ae 1520
034db86b 1521 pim_addr_to_prefix(&p, src);
d62a17ae 1522
1523 for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) {
034db86b 1524 if (c->address->family != PIM_AF)
a2810d30
DL
1525 continue;
1526 if (prefix_match(c->address, &p))
1527 return c->address;
1528 if (CONNECTED_PEER(c) && prefix_match(c->destination, &p))
1529 /* this is not a typo, on PtP we need to return the
1530 * *local* address that lines up with src.
1531 */
1532 return c->address;
d62a17ae 1533 }
1534
efe6f185 1535 return NULL;
3565202d 1536}
11699c47 1537
e55a43d4 1538bool pim_if_is_vrf_device(struct interface *ifp)
90133de6 1539{
e55a43d4
DS
1540 if (if_is_vrf(ifp))
1541 return true;
90133de6 1542
e55a43d4 1543 return false;
90133de6 1544}
ad7b74c4
DS
1545
1546int pim_if_ifchannel_count(struct pim_interface *pim_ifp)
1547{
1548 struct pim_ifchannel *ch;
1549 int count = 0;
1550
a2addae8 1551 RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
ad7b74c4
DS
1552 count++;
1553 }
1554
1555 return count;
1556}
138c5a74 1557
6b88faa7 1558static int pim_ifp_create(struct interface *ifp)
138c5a74 1559{
ef7bd2a3
DS
1560 struct pim_instance *pim;
1561
096f7609 1562 pim = ifp->vrf->info;
ef7bd2a3
DS
1563 if (PIM_DEBUG_ZEBRA) {
1564 zlog_debug(
096f7609
IR
1565 "%s: %s index %d vrf %s(%u) flags %ld metric %d mtu %d operative %d",
1566 __func__, ifp->name, ifp->ifindex, ifp->vrf->name,
1567 ifp->vrf->vrf_id, (long)ifp->flags, ifp->metric,
1568 ifp->mtu, if_is_operative(ifp));
ef7bd2a3
DS
1569 }
1570
1571 if (if_is_operative(ifp)) {
1572 struct pim_interface *pim_ifp;
1573
1574 pim_ifp = ifp->info;
1575 /*
1576 * If we have a pim_ifp already and this is an if_add
1577 * that means that we probably have a vrf move event
1578 * If that is the case, set the proper vrfness.
1579 */
1580 if (pim_ifp)
1581 pim_ifp->pim = pim;
1582 pim_if_addr_add_all(ifp);
e5981db7
DS
1583
1584 /*
1585 * Due to ordering issues based upon when
1586 * a command is entered we should ensure that
1587 * the pim reg is created for this vrf if we
1588 * have configuration for it already.
1589 *
1590 * this is a no-op if it's already been done.
1591 */
1592 pim_if_create_pimreg(pim);
ef7bd2a3
DS
1593 }
1594
94120cb2 1595#if PIM_IPV == 4
ef7bd2a3
DS
1596 /*
1597 * If we are a vrf device that is up, open up the pim_socket for
1598 * listening
1599 * to incoming pim messages irrelevant if the user has configured us
1600 * for pim or not.
1601 */
1602 if (pim_if_is_vrf_device(ifp)) {
1603 struct pim_interface *pim_ifp;
1604
1605 if (!ifp->info) {
1606 pim_ifp = pim_if_new(ifp, false, false, false,
1607 false /*vxlan_term*/);
1608 ifp->info = pim_ifp;
1609 }
1610
1611 pim_sock_add(ifp);
1612 }
1613
1614 if (!strncmp(ifp->name, PIM_VXLAN_TERM_DEV_NAME,
ccf696e8 1615 sizeof(PIM_VXLAN_TERM_DEV_NAME))) {
1616 if (pim->mcast_if_count < MAXVIFS)
1617 pim_vxlan_add_term_dev(pim, ifp);
1618 else
1619 zlog_warn(
1620 "%s: Cannot enable pim on %s. MAXVIFS(%d) reached. Deleting and readding the vxlan termimation device after unconfiguring pim from other interfaces may succeed.",
1621 __func__, ifp->name, MAXVIFS);
1622 }
94120cb2 1623#endif
ef7bd2a3 1624
138c5a74
DS
1625 return 0;
1626}
1627
6b88faa7 1628static int pim_ifp_up(struct interface *ifp)
138c5a74 1629{
97feb13f 1630 uint32_t table_id;
85d25587 1631 struct pim_interface *pim_ifp;
ddbf3e60 1632 struct pim_instance *pim;
ddbf3e60
DS
1633
1634 if (PIM_DEBUG_ZEBRA) {
1635 zlog_debug(
096f7609
IR
1636 "%s: %s index %d vrf %s(%u) flags %ld metric %d mtu %d operative %d",
1637 __func__, ifp->name, ifp->ifindex, ifp->vrf->name,
1638 ifp->vrf->vrf_id, (long)ifp->flags, ifp->metric,
1639 ifp->mtu, if_is_operative(ifp));
ddbf3e60
DS
1640 }
1641
096f7609 1642 pim = ifp->vrf->info;
ddbf3e60 1643
85d25587
DS
1644 pim_ifp = ifp->info;
1645 /*
1646 * If we have a pim_ifp already and this is an if_add
1647 * that means that we probably have a vrf move event
1648 * If that is the case, set the proper vrfness.
1649 */
1650 if (pim_ifp)
1651 pim_ifp->pim = pim;
ddbf3e60 1652
85d25587
DS
1653 /*
1654 pim_if_addr_add_all() suffices for bringing up both IGMP and
1655 PIM
1656 */
1657 pim_if_addr_add_all(ifp);
ddbf3e60
DS
1658
1659 /*
1660 * If we have a pimreg device callback and it's for a specific
1661 * table set the master appropriately
1662 */
ee1c4ba9 1663 if (sscanf(ifp->name, "" PIMREG "%" SCNu32, &table_id) == 1) {
ddbf3e60
DS
1664 struct vrf *vrf;
1665 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
1666 if ((table_id == vrf->data.l.table_id)
096f7609 1667 && (ifp->vrf->vrf_id != vrf->vrf_id)) {
ddbf3e60
DS
1668 struct interface *master = if_lookup_by_name(
1669 vrf->name, vrf->vrf_id);
1670
1671 if (!master) {
1672 zlog_debug(
1673 "%s: Unable to find Master interface for %s",
15569c58 1674 __func__, vrf->name);
ddbf3e60
DS
1675 return 0;
1676 }
1677 pim_zebra_interface_set_master(master, ifp);
1678 }
1679 }
1680 }
138c5a74
DS
1681 return 0;
1682}
1683
6b88faa7 1684static int pim_ifp_down(struct interface *ifp)
138c5a74 1685{
b0b69e59
DS
1686 if (PIM_DEBUG_ZEBRA) {
1687 zlog_debug(
096f7609
IR
1688 "%s: %s index %d vrf %s(%u) flags %ld metric %d mtu %d operative %d",
1689 __func__, ifp->name, ifp->ifindex, ifp->vrf->name,
1690 ifp->vrf->vrf_id, (long)ifp->flags, ifp->metric,
1691 ifp->mtu, if_is_operative(ifp));
b0b69e59
DS
1692 }
1693
1694 if (!if_is_operative(ifp)) {
1695 pim_ifchannel_delete_all(ifp);
1696 /*
1697 pim_if_addr_del_all() suffices for shutting down IGMP,
1698 but not for shutting down PIM
1699 */
1700 pim_if_addr_del_all(ifp);
1701
1702 /*
1703 pim_sock_delete() closes the socket, stops read and timer
1704 threads,
1705 and kills all neighbors.
1706 */
1707 if (ifp->info) {
1708 pim_sock_delete(ifp, "link down");
1709 }
1710 }
1711
79992e8a 1712 if (ifp->info) {
b0b69e59 1713 pim_if_del_vif(ifp);
79992e8a 1714 pim_ifstat_reset(ifp);
97feb13f 1715 }
b0b69e59 1716
138c5a74
DS
1717 return 0;
1718}
1719
6b88faa7 1720static int pim_ifp_destroy(struct interface *ifp)
138c5a74 1721{
3c3c3252
DS
1722 if (PIM_DEBUG_ZEBRA) {
1723 zlog_debug(
096f7609
IR
1724 "%s: %s index %d vrf %s(%u) flags %ld metric %d mtu %d operative %d",
1725 __func__, ifp->name, ifp->ifindex, ifp->vrf->name,
1726 ifp->vrf->vrf_id, (long)ifp->flags, ifp->metric,
1727 ifp->mtu, if_is_operative(ifp));
3c3c3252
DS
1728 }
1729
1730 if (!if_is_operative(ifp))
1731 pim_if_addr_del_all(ifp);
1732
97feb13f
DL
1733#if PIM_IPV == 4
1734 struct pim_instance *pim;
1735
096f7609 1736 pim = ifp->vrf->info;
3c3c3252
DS
1737 if (pim && pim->vxlan.term_if == ifp)
1738 pim_vxlan_del_term_dev(pim);
94120cb2 1739#endif
3c3c3252 1740
138c5a74
DS
1741 return 0;
1742}
6b88faa7
IR
1743
1744static int pim_if_new_hook(struct interface *ifp)
1745{
1746 return 0;
1747}
1748
1749static int pim_if_delete_hook(struct interface *ifp)
1750{
3c10fb92
IR
1751 if (ifp->info)
1752 pim_if_delete(ifp);
1753
6b88faa7
IR
1754 return 0;
1755}
1756
1757void pim_iface_init(void)
1758{
1759 hook_register_prio(if_add, 0, pim_if_new_hook);
1760 hook_register_prio(if_del, 0, pim_if_delete_hook);
1761
1762 if_zapi_callbacks(pim_ifp_create, pim_ifp_up, pim_ifp_down,
1763 pim_ifp_destroy);
1764}