]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_register.c
pimd: FRR-PIM sending register packet even after receiving (*,G) register stop
[mirror_frr.git] / pimd / pim_register.c
CommitLineData
01d68c9b
DS
1/*
2 * PIM for Quagga
3 * Copyright (C) 2015 Cumulus Networks, Inc.
4 * Donald Sharp
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
896014f4
DL
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
01d68c9b
DS
19 */
20
21#include <zebra.h>
22
23#include "log.h"
24#include "if.h"
25#include "thread.h"
13c2408c 26#include "prefix.h"
dfe43e25
DW
27#include "vty.h"
28#include "plist.h"
01d68c9b
DS
29
30#include "pimd.h"
998af219
DS
31#include "pim_mroute.h"
32#include "pim_iface.h"
33#include "pim_msg.h"
34#include "pim_pim.h"
01d68c9b
DS
35#include "pim_str.h"
36#include "pim_rp.h"
37#include "pim_register.h"
80c0d168 38#include "pim_upstream.h"
01d68c9b 39#include "pim_br.h"
2ca35b3d
DS
40#include "pim_rpf.h"
41#include "pim_oil.h"
42#include "pim_zebra.h"
43#include "pim_join.h"
13c2408c 44#include "pim_util.h"
15a5dafe 45#include "pim_ssm.h"
b9f3a51c 46#include "pim_vxlan.h"
01d68c9b
DS
47
48struct thread *send_test_packet_timer = NULL;
49
d62a17ae 50void pim_register_join(struct pim_upstream *up)
15a5dafe 51{
ac7eaeb4
DS
52 struct pim_instance *pim = up->channel_oil->pim;
53
6f439a70 54 if (pim_is_grp_ssm(pim, up->sg.grp)) {
d62a17ae 55 if (PIM_DEBUG_PIM_EVENTS)
56 zlog_debug("%s register setup skipped as group is SSM",
57 up->sg_str);
58 return;
59 }
60
ac7eaeb4 61 pim_channel_add_oif(up->channel_oil, pim->regiface,
1b249e70 62 PIM_OIF_FLAG_PROTO_PIM, __func__);
d62a17ae 63 up->reg_state = PIM_REG_JOIN;
03f9d812 64 pim_vxlan_update_sg_reg_state(pim, up, true);
15a5dafe 65}
66
6fff2cc6 67void pim_register_stop_send(struct interface *ifp, pim_sgaddr *sg,
d62a17ae 68 struct in_addr src, struct in_addr originator)
01d68c9b 69{
d62a17ae 70 struct pim_interface *pinfo;
71 unsigned char buffer[10000];
72 unsigned int b1length = 0;
73 unsigned int length;
74 uint8_t *b1;
d62a17ae 75
76 if (PIM_DEBUG_PIM_REG) {
98a81d2b
DL
77 zlog_debug("Sending Register stop for %pSG to %pI4 on %s", sg,
78 &originator, ifp->name);
d62a17ae 79 }
80
81 memset(buffer, 0, 10000);
82 b1 = (uint8_t *)buffer + PIM_MSG_REGISTER_STOP_LEN;
83
84 length = pim_encode_addr_group(b1, AFI_IP, 0, 0, sg->grp);
85 b1length += length;
86 b1 += length;
87
0d360092 88 length = pim_encode_addr_ucast(b1, sg->src);
d62a17ae 89 b1length += length;
90
91 pim_msg_build_header(buffer, b1length + PIM_MSG_REGISTER_STOP_LEN,
d57a8bbf 92 PIM_MSG_TYPE_REG_STOP, false);
d62a17ae 93
94 pinfo = (struct pim_interface *)ifp->info;
95 if (!pinfo) {
96 if (PIM_DEBUG_PIM_TRACE)
15569c58 97 zlog_debug("%s: No pinfo!", __func__);
d62a17ae 98 return;
13c2408c 99 }
d62a17ae 100 if (pim_msg_send(pinfo->pim_sock_fd, src, originator, buffer,
101 b1length + PIM_MSG_REGISTER_STOP_LEN, ifp->name)) {
102 if (PIM_DEBUG_PIM_TRACE) {
103 zlog_debug(
104 "%s: could not send PIM register stop message on interface %s",
15569c58 105 __func__, ifp->name);
d62a17ae 106 }
107 }
108 ++pinfo->pim_ifstat_reg_stop_send;
01d68c9b
DS
109}
110
03f9d812 111static void pim_reg_stop_upstream(struct pim_instance *pim,
112 struct pim_upstream *up)
113{
114 switch (up->reg_state) {
115 case PIM_REG_NOINFO:
116 case PIM_REG_PRUNE:
117 return;
118 case PIM_REG_JOIN:
119 up->reg_state = PIM_REG_PRUNE;
120 pim_channel_del_oif(up->channel_oil, pim->regiface,
121 PIM_OIF_FLAG_PROTO_PIM, __func__);
122 pim_upstream_start_register_stop_timer(up, 0);
123 pim_vxlan_update_sg_reg_state(pim, up, false);
124 break;
125 case PIM_REG_JOIN_PENDING:
126 up->reg_state = PIM_REG_PRUNE;
127 pim_upstream_start_register_stop_timer(up, 0);
128 return;
129 }
130}
131
b206566b 132int pim_register_stop_recv(struct interface *ifp, uint8_t *buf, int buf_size)
4dffc880 133{
b206566b
DS
134 struct pim_interface *pim_ifp = ifp->info;
135 struct pim_instance *pim = pim_ifp->pim;
03f9d812 136 struct pim_upstream *up = NULL;
137 struct pim_rpf *rp;
138 pim_addr rpf_addr;
6fff2cc6 139 pim_sgaddr sg;
03f9d812 140 struct listnode *up_node;
141 struct pim_upstream *child;
0d360092 142 bool wrong_af = false;
03f9d812 143 bool handling_star = false;
d62a17ae 144 int l;
145
25ed72fe
SP
146 ++pim_ifp->pim_ifstat_reg_stop_recv;
147
6fff2cc6 148 memset(&sg, 0, sizeof(sg));
d62a17ae 149 l = pim_parse_addr_group(&sg, buf, buf_size);
150 buf += l;
151 buf_size -= l;
0d360092
DL
152 pim_parse_addr_ucast(&sg.src, buf, buf_size, &wrong_af);
153
154 if (wrong_af) {
155 zlog_err("invalid AF in Register-Stop on %s", ifp->name);
156 return 0;
157 }
d62a17ae 158
d62a17ae 159
160 if (PIM_DEBUG_PIM_REG)
03f9d812 161 zlog_debug("Received Register stop for %pSG", &sg);
162
163 rp = RP(pim_ifp->pim, sg.grp);
164 if (rp) {
165 rpf_addr = pim_addr_from_prefix(&rp->rpf_addr);
166 if (pim_addr_cmp(sg.src, rpf_addr) == 0) {
167 handling_star = true;
168 sg.src = PIMADDR_ANY;
169 }
170 }
d62a17ae 171
03f9d812 172 /*
173 * RFC 7761 Sec 4.4.1
174 * Handling Register-Stop(*,G) Messages at the DR:
175 * A Register-Stop(*,G) should be treated as a
176 * Register-Stop(S,G) for all (S,G) Register state
177 * machines that are not in the NoInfo state.
178 */
179 up = pim_upstream_find(pim, &sg);
180 if (up) {
181 /*
182 * If the upstream find actually found a particular
183 * S,G then we *know* that the following for loop
184 * is not going to execute and this is ok
185 */
186 for (ALL_LIST_ELEMENTS_RO(up->sources, up_node, child)) {
187 if (PIM_DEBUG_PIM_REG)
188 zlog_debug("Executing Reg stop for %s",
189 child->sg_str);
190
191 pim_reg_stop_upstream(pim, child);
192 }
193
194 if (PIM_DEBUG_PIM_REG)
195 zlog_debug("Executing Reg stop for %s", up->sg_str);
196 pim_reg_stop_upstream(pim, up);
197 } else {
198 if (!handling_star)
199 return 0;
200 /*
201 * Unfortunately pim was unable to find a *,G
202 * but pim may still actually have individual
203 * S,G's that need to be processed. In that
204 * case pim must do the expensive walk to find
205 * and stop
206 */
207 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
208 if (pim_addr_cmp(up->sg.grp, sg.grp) == 0) {
209 if (PIM_DEBUG_PIM_REG)
210 zlog_debug("Executing Reg stop for %s",
211 up->sg_str);
212 pim_reg_stop_upstream(pim, up);
213 }
214 }
d62a17ae 215 }
216
217 return 0;
4dffc880
DS
218}
219
d62a17ae 220void pim_register_send(const uint8_t *buf, int buf_size, struct in_addr src,
221 struct pim_rpf *rpg, int null_register,
222 struct pim_upstream *up)
998af219 223{
d62a17ae 224 unsigned char buffer[10000];
225 unsigned char *b1;
226 struct pim_interface *pinfo;
227 struct interface *ifp;
228
229 if (PIM_DEBUG_PIM_REG) {
ee2bbf7c 230 zlog_debug("Sending %s %sRegister Packet to %pI4", up->sg_str,
d62a17ae 231 null_register ? "NULL " : "",
ee2bbf7c 232 &rpg->rpf_addr.u.prefix4);
d62a17ae 233 }
234
235 ifp = rpg->source_nexthop.interface;
236 if (!ifp) {
237 if (PIM_DEBUG_PIM_REG)
238 zlog_debug("%s: No interface to transmit register on",
15569c58 239 __func__);
d62a17ae 240 return;
241 }
242 pinfo = (struct pim_interface *)ifp->info;
243 if (!pinfo) {
244 if (PIM_DEBUG_PIM_REG)
245 zlog_debug(
63efca0e 246 "%s: Interface: %s not configured for pim to transmit on!",
15569c58 247 __func__, ifp->name);
d62a17ae 248 return;
249 }
250
251 if (PIM_DEBUG_PIM_REG) {
ee2bbf7c 252 zlog_debug("%s: Sending %s %sRegister Packet to %pI4 on %s",
15569c58 253 __func__, up->sg_str, null_register ? "NULL " : "",
ee2bbf7c 254 &rpg->rpf_addr.u.prefix4, ifp->name);
d62a17ae 255 }
256
257 memset(buffer, 0, 10000);
258 b1 = buffer + PIM_MSG_HEADER_LEN;
259 *b1 |= null_register << 6;
260 b1 = buffer + PIM_MSG_REGISTER_LEN;
261
262 memcpy(b1, (const unsigned char *)buf, buf_size);
263
264 pim_msg_build_header(buffer, buf_size + PIM_MSG_REGISTER_LEN,
d57a8bbf 265 PIM_MSG_TYPE_REGISTER, false);
d62a17ae 266
267 ++pinfo->pim_ifstat_reg_send;
268
269 if (pim_msg_send(pinfo->pim_sock_fd, src, rpg->rpf_addr.u.prefix4,
270 buffer, buf_size + PIM_MSG_REGISTER_LEN, ifp->name)) {
271 if (PIM_DEBUG_PIM_TRACE) {
272 zlog_debug(
273 "%s: could not send PIM register message on interface %s",
15569c58 274 __func__, ifp->name);
d62a17ae 275 }
276 return;
277 }
998af219
DS
278}
279
aea1f845
AK
280void pim_null_register_send(struct pim_upstream *up)
281{
282 struct ip ip_hdr;
283 struct pim_interface *pim_ifp;
284 struct pim_rpf *rpg;
285 struct in_addr src;
286
287 pim_ifp = up->rpf.source_nexthop.interface->info;
288 if (!pim_ifp) {
23fc858a 289 if (PIM_DEBUG_PIM_TRACE)
aea1f845
AK
290 zlog_debug(
291 "%s: Cannot send null-register for %s no valid iif",
15569c58 292 __func__, up->sg_str);
aea1f845
AK
293 return;
294 }
295
296 rpg = RP(pim_ifp->pim, up->sg.grp);
297 if (!rpg) {
23fc858a 298 if (PIM_DEBUG_PIM_TRACE)
aea1f845
AK
299 zlog_debug(
300 "%s: Cannot send null-register for %s no RPF to the RP",
15569c58 301 __func__, up->sg_str);
aea1f845
AK
302 return;
303 }
304
305 memset(&ip_hdr, 0, sizeof(struct ip));
306 ip_hdr.ip_p = PIM_IP_PROTO_PIM;
307 ip_hdr.ip_hl = 5;
308 ip_hdr.ip_v = 4;
309 ip_hdr.ip_src = up->sg.src;
310 ip_hdr.ip_dst = up->sg.grp;
311 ip_hdr.ip_len = htons(20);
312
313 /* checksum is broken */
314 src = pim_ifp->primary_address;
d9e75668
AK
315 if (PIM_UPSTREAM_FLAG_TEST_SRC_VXLAN_ORIG(up->flags)) {
316 if (!pim_vxlan_get_register_src(pim_ifp->pim, up, &src)) {
23fc858a 317 if (PIM_DEBUG_PIM_TRACE)
d9e75668
AK
318 zlog_debug(
319 "%s: Cannot send null-register for %s vxlan-aa PIP unavailable",
15569c58 320 __func__, up->sg_str);
d9e75668
AK
321 return;
322 }
323 }
aea1f845
AK
324 pim_register_send((uint8_t *)&ip_hdr, sizeof(struct ip),
325 src, rpg, 1, up);
326}
327
01d68c9b
DS
328/*
329 * 4.4.2 Receiving Register Messages at the RP
330 *
331 * When an RP receives a Register message, the course of action is
332 * decided according to the following pseudocode:
333 *
334 * packet_arrives_on_rp_tunnel( pkt ) {
335 * if( outer.dst is not one of my addresses ) {
336 * drop the packet silently.
337 * # Note: this may be a spoofing attempt
338 * }
339 * if( I_am_RP(G) AND outer.dst == RP(G) ) {
2951a7a4
QY
340 * sentRegisterStop = false;
341 * if ( register.borderbit == true ) {
01d68c9b
DS
342 * if ( PMBR(S,G) == unknown ) {
343 * PMBR(S,G) = outer.src
344 * } else if ( outer.src != PMBR(S,G) ) {
345 * send Register-Stop(S,G) to outer.src
346 * drop the packet silently.
347 * }
348 * }
349 * if ( SPTbit(S,G) OR
350 * ( SwitchToSptDesired(S,G) AND
351 * ( inherited_olist(S,G) == NULL ))) {
352 * send Register-Stop(S,G) to outer.src
2951a7a4 353 * sentRegisterStop = true;
01d68c9b
DS
354 * }
355 * if ( SPTbit(S,G) OR SwitchToSptDesired(S,G) ) {
2951a7a4 356 * if ( sentRegisterStop == true ) {
01d68c9b
DS
357 * set KeepaliveTimer(S,G) to RP_Keepalive_Period;
358 * } else {
359 * set KeepaliveTimer(S,G) to Keepalive_Period;
360 * }
361 * }
362 * if( !SPTbit(S,G) AND ! pkt.NullRegisterBit ) {
363 * decapsulate and forward the inner packet to
364 * inherited_olist(S,G,rpt) # Note (+)
365 * }
366 * } else {
367 * send Register-Stop(S,G) to outer.src
368 * # Note (*)
369 * }
370 * }
371 */
c7842d24
MR
372int pim_register_recv(struct interface *ifp, pim_addr dest_addr,
373 pim_addr src_addr, uint8_t *tlv_buf, int tlv_buf_size)
01d68c9b 374{
d62a17ae 375 int sentRegisterStop = 0;
c7842d24 376 const void *ip_hdr;
6fff2cc6 377 pim_sgaddr sg;
d62a17ae 378 uint32_t *bits;
379 int i_am_rp = 0;
2ca35b64
DS
380 struct pim_interface *pim_ifp = ifp->info;
381 struct pim_instance *pim = pim_ifp->pim;
c7842d24 382 pim_addr rp_addr;
fec883d9 383
75a26779 384#define PIM_MSG_REGISTER_BIT_RESERVED_LEN 4
c7842d24 385 ip_hdr = (tlv_buf + PIM_MSG_REGISTER_BIT_RESERVED_LEN);
d62a17ae 386
c7842d24
MR
387 if (!if_address_is_local(&dest_addr, PIM_AF, pim->vrf->vrf_id)) {
388 if (PIM_DEBUG_PIM_REG)
d62a17ae 389 zlog_debug(
c7842d24
MR
390 "%s: Received Register message for destination address: %pPA that I do not own",
391 __func__, &dest_addr);
d62a17ae 392 return 0;
393 }
394
d62a17ae 395 ++pim_ifp->pim_ifstat_reg_recv;
396
397 /*
398 * Please note this is not drawn to get the correct bit/data size
399 *
400 * The entirety of the REGISTER packet looks like this:
401 * -------------------------------------------------------------
402 * | Ver | Type | Reserved | Checksum |
403 * |-----------------------------------------------------------|
404 * |B|N| Reserved 2 |
405 * |-----------------------------------------------------------|
406 * | Encap | IP HDR |
407 * | Mcast | |
408 * | Packet |--------------------------------------------------|
409 * | | Mcast Data |
410 * | | |
411 * ...
412 *
413 * tlv_buf when received from the caller points at the B bit
414 * We need to know the inner source and dest
415 */
416 bits = (uint32_t *)tlv_buf;
417
418 /*
419 * tlv_buf points to the start of the |B|N|... Reserved
420 * Line above. So we need to add 4 bytes to get to the
421 * start of the actual Encapsulated data.
422 */
6fff2cc6 423 memset(&sg, 0, sizeof(sg));
c7842d24 424 sg = pim_sgaddr_from_iphdr(ip_hdr);
d62a17ae 425
2ca35b64 426 i_am_rp = I_am_RP(pim, sg.grp);
d62a17ae 427
c7842d24
MR
428 if (PIM_DEBUG_PIM_REG)
429 zlog_debug(
430 "Received Register message%pSG from %pPA on %s, rp: %d",
431 &sg, &src_addr, ifp->name, i_am_rp);
d62a17ae 432
34abbcc4 433 if (pim_is_grp_ssm(pim_ifp->pim, sg.grp)) {
2a27f13b 434 if (pim_addr_is_any(sg.src)) {
34abbcc4 435 zlog_warn(
6d7bf748 436 "%s: Received Register message for Group(%pPA) is now in SSM, dropping the packet",
38c848c9 437 __func__, &sg.grp);
34abbcc4
SG
438 /* Drop Packet Silently */
439 return 0;
440 }
441 }
442
c7842d24
MR
443 rp_addr = pim_addr_from_prefix(&(RP(pim, sg.grp))->rpf_addr);
444 if (i_am_rp && (!pim_addr_cmp(dest_addr, rp_addr))) {
d62a17ae 445 sentRegisterStop = 0;
446
f4e74bd0
DS
447 if (pim->register_plist) {
448 struct prefix_list *plist;
449 struct prefix src;
450
c631920c
DL
451 plist = prefix_list_lookup(PIM_AFI,
452 pim->register_plist);
f4e74bd0 453
c631920c 454 pim_addr_to_prefix(&src, sg.src);
f4e74bd0
DS
455
456 if (prefix_list_apply(plist, &src) == PREFIX_DENY) {
457 pim_register_stop_send(ifp, &sg, dest_addr,
458 src_addr);
c7842d24 459 if (PIM_DEBUG_PIM_PACKETS)
d51f8b0f 460 zlog_debug(
c7842d24
MR
461 "%s: Sending register-stop to %pPA for %pSG due to prefix-list denial, dropping packet",
462 __func__, &src_addr, &sg);
f4e74bd0
DS
463
464 return 0;
465 }
466 }
467
d62a17ae 468 if (*bits & PIM_REGISTER_BORDER_BIT) {
a141ea61 469 pim_addr pimbr = pim_br_get_pmbr(&sg);
d62a17ae 470 if (PIM_DEBUG_PIM_PACKETS)
471 zlog_debug(
472 "%s: Received Register message with Border bit set",
473 __func__);
474
e782863d 475 if (pim_addr_is_any(pimbr))
d62a17ae 476 pim_br_set_pmbr(&sg, src_addr);
a141ea61 477 else if (pim_addr_cmp(src_addr, pimbr)) {
d62a17ae 478 pim_register_stop_send(ifp, &sg, dest_addr,
479 src_addr);
480 if (PIM_DEBUG_PIM_PACKETS)
481 zlog_debug(
482 "%s: Sending register-Stop to %s and dropping mr. packet",
483 __func__, "Sender");
484 /* Drop Packet Silently */
485 return 0;
486 }
487 }
488
2ca35b64 489 struct pim_upstream *upstream = pim_upstream_find(pim, &sg);
d62a17ae 490 /*
491 * If we don't have a place to send ignore the packet
492 */
493 if (!upstream) {
494 upstream = pim_upstream_add(
2ca35b64 495 pim, &sg, ifp,
15569c58
DA
496 PIM_UPSTREAM_FLAG_MASK_SRC_STREAM, __func__,
497 NULL);
d62a17ae 498 if (!upstream) {
499 zlog_warn("Failure to create upstream state");
500 return 1;
501 }
502
503 upstream->upstream_register = src_addr;
cc61055f
DS
504 } else {
505 /*
506 * If the FHR has set a very very fast register timer
507 * there exists a possibility that the incoming NULL
508 * register
509 * is happening before we set the spt bit. If so
510 * Do a quick check to update the counters and
511 * then set the spt bit as appropriate
512 */
513 if (upstream->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) {
514 pim_mroute_update_counters(
515 upstream->channel_oil);
516 /*
517 * Have we seen packets?
518 */
519 if (upstream->channel_oil->cc.oldpktcnt
520 < upstream->channel_oil->cc.pktcnt)
521 pim_upstream_set_sptbit(
522 upstream,
523 upstream->rpf.source_nexthop
524 .interface);
525 }
d62a17ae 526 }
527
528 if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE)
2ca35b64
DS
529 || ((SwitchToSptDesiredOnRp(pim, &sg))
530 && pim_upstream_inherited_olist(pim, upstream) == 0)) {
d62a17ae 531 pim_register_stop_send(ifp, &sg, dest_addr, src_addr);
532 sentRegisterStop = 1;
533 } else {
534 if (PIM_DEBUG_PIM_REG)
535 zlog_debug("(%s) sptbit: %d", upstream->sg_str,
536 upstream->sptbit);
537 }
538 if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE)
2ca35b64 539 || (SwitchToSptDesiredOnRp(pim, &sg))) {
d62a17ae 540 if (sentRegisterStop) {
541 pim_upstream_keep_alive_timer_start(
2ca35b64 542 upstream, pim->rp_keep_alive_time);
d62a17ae 543 } else {
544 pim_upstream_keep_alive_timer_start(
2ca35b64 545 upstream, pim->keep_alive_time);
d62a17ae 546 }
547 }
548
549 if (!(upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE)
550 && !(*bits & PIM_REGISTER_NR_BIT)) {
551 // decapsulate and forward the iner packet to
552 // inherited_olist(S,G,rpt)
553 // This is taken care of by the kernel for us
554 }
555 pim_upstream_msdp_reg_timer_start(upstream);
556 } else {
557 if (PIM_DEBUG_PIM_REG) {
558 if (!i_am_rp)
98a81d2b
DL
559 zlog_debug("Received Register packet for %pSG, Rejecting packet because I am not the RP configured for group",
560 &sg);
d62a17ae 561 else
98a81d2b
DL
562 zlog_debug("Received Register packet for %pSG, Rejecting packet because the dst ip address is not the actual RP",
563 &sg);
d62a17ae 564 }
565 pim_register_stop_send(ifp, &sg, dest_addr, src_addr);
566 }
567
8dc60b69 568 return 0;
01d68c9b 569}
46a9ea8b 570
571/*
572 * This routine scan all upstream and update register state and remove pimreg
573 * when couldreg becomes false.
574 */
575void pim_reg_del_on_couldreg_fail(struct interface *ifp)
576{
577 struct pim_interface *pim_ifp = ifp->info;
578 struct pim_instance *pim;
579 struct pim_upstream *up;
580
581 if (!pim_ifp)
582 return;
583
584 pim = pim_ifp->pim;
585
586 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
587 if (ifp != up->rpf.source_nexthop.interface)
588 continue;
589
590 if (!pim_upstream_could_register(up)
591 && (up->reg_state != PIM_REG_NOINFO)) {
592 pim_channel_del_oif(up->channel_oil, pim->regiface,
593 PIM_OIF_FLAG_PROTO_PIM, __func__);
594 THREAD_OFF(up->t_rs_timer);
595 up->reg_state = PIM_REG_NOINFO;
596 }
597 }
598}