]>
Commit | Line | Data |
---|---|---|
acddc0ed | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
01d68c9b DS |
2 | /* |
3 | * PIM for Quagga | |
4 | * Copyright (C) 2015 Cumulus Networks, Inc. | |
5 | * Donald Sharp | |
01d68c9b DS |
6 | */ |
7 | ||
8 | #include <zebra.h> | |
9 | ||
10 | #include "log.h" | |
11 | #include "if.h" | |
24a58196 | 12 | #include "frrevent.h" |
13c2408c | 13 | #include "prefix.h" |
dfe43e25 DW |
14 | #include "vty.h" |
15 | #include "plist.h" | |
01d68c9b DS |
16 | |
17 | #include "pimd.h" | |
998af219 DS |
18 | #include "pim_mroute.h" |
19 | #include "pim_iface.h" | |
20 | #include "pim_msg.h" | |
21 | #include "pim_pim.h" | |
01d68c9b DS |
22 | #include "pim_str.h" |
23 | #include "pim_rp.h" | |
24 | #include "pim_register.h" | |
80c0d168 | 25 | #include "pim_upstream.h" |
2ca35b3d DS |
26 | #include "pim_rpf.h" |
27 | #include "pim_oil.h" | |
28 | #include "pim_zebra.h" | |
29 | #include "pim_join.h" | |
13c2408c | 30 | #include "pim_util.h" |
15a5dafe | 31 | #include "pim_ssm.h" |
b9f3a51c | 32 | #include "pim_vxlan.h" |
30b277e1 | 33 | #include "pim_addr.h" |
01d68c9b | 34 | |
e6685141 | 35 | struct event *send_test_packet_timer = NULL; |
01d68c9b | 36 | |
d62a17ae | 37 | void pim_register_join(struct pim_upstream *up) |
15a5dafe | 38 | { |
ac7eaeb4 DS |
39 | struct pim_instance *pim = up->channel_oil->pim; |
40 | ||
6f439a70 | 41 | if (pim_is_grp_ssm(pim, up->sg.grp)) { |
d62a17ae | 42 | if (PIM_DEBUG_PIM_EVENTS) |
43 | zlog_debug("%s register setup skipped as group is SSM", | |
44 | up->sg_str); | |
45 | return; | |
46 | } | |
47 | ||
ac7eaeb4 | 48 | pim_channel_add_oif(up->channel_oil, pim->regiface, |
1b249e70 | 49 | PIM_OIF_FLAG_PROTO_PIM, __func__); |
d62a17ae | 50 | up->reg_state = PIM_REG_JOIN; |
03f9d812 | 51 | pim_vxlan_update_sg_reg_state(pim, up, true); |
15a5dafe | 52 | } |
53 | ||
30b277e1 | 54 | void pim_register_stop_send(struct interface *ifp, pim_sgaddr *sg, pim_addr src, |
55 | pim_addr originator) | |
01d68c9b | 56 | { |
d62a17ae | 57 | struct pim_interface *pinfo; |
58 | unsigned char buffer[10000]; | |
59 | unsigned int b1length = 0; | |
60 | unsigned int length; | |
61 | uint8_t *b1; | |
d62a17ae | 62 | |
63 | if (PIM_DEBUG_PIM_REG) { | |
30b277e1 | 64 | zlog_debug("Sending Register stop for %pSG to %pPA on %s", sg, |
98a81d2b | 65 | &originator, ifp->name); |
d62a17ae | 66 | } |
67 | ||
68 | memset(buffer, 0, 10000); | |
69 | b1 = (uint8_t *)buffer + PIM_MSG_REGISTER_STOP_LEN; | |
70 | ||
71 | length = pim_encode_addr_group(b1, AFI_IP, 0, 0, sg->grp); | |
72 | b1length += length; | |
73 | b1 += length; | |
74 | ||
0d360092 | 75 | length = pim_encode_addr_ucast(b1, sg->src); |
d62a17ae | 76 | b1length += length; |
77 | ||
145e4c38 DL |
78 | pim_msg_build_header(src, originator, buffer, |
79 | b1length + PIM_MSG_REGISTER_STOP_LEN, | |
d57a8bbf | 80 | PIM_MSG_TYPE_REG_STOP, false); |
d62a17ae | 81 | |
82 | pinfo = (struct pim_interface *)ifp->info; | |
83 | if (!pinfo) { | |
84 | if (PIM_DEBUG_PIM_TRACE) | |
15569c58 | 85 | zlog_debug("%s: No pinfo!", __func__); |
d62a17ae | 86 | return; |
13c2408c | 87 | } |
d62a17ae | 88 | if (pim_msg_send(pinfo->pim_sock_fd, src, originator, buffer, |
6dd493b8 | 89 | b1length + PIM_MSG_REGISTER_STOP_LEN, ifp)) { |
d62a17ae | 90 | if (PIM_DEBUG_PIM_TRACE) { |
91 | zlog_debug( | |
92 | "%s: could not send PIM register stop message on interface %s", | |
15569c58 | 93 | __func__, ifp->name); |
d62a17ae | 94 | } |
95 | } | |
6dd493b8 | 96 | |
97 | if (!pinfo->pim_passive_enable) | |
98 | ++pinfo->pim_ifstat_reg_stop_send; | |
01d68c9b DS |
99 | } |
100 | ||
03f9d812 | 101 | static void pim_reg_stop_upstream(struct pim_instance *pim, |
102 | struct pim_upstream *up) | |
103 | { | |
104 | switch (up->reg_state) { | |
105 | case PIM_REG_NOINFO: | |
106 | case PIM_REG_PRUNE: | |
107 | return; | |
108 | case PIM_REG_JOIN: | |
109 | up->reg_state = PIM_REG_PRUNE; | |
110 | pim_channel_del_oif(up->channel_oil, pim->regiface, | |
111 | PIM_OIF_FLAG_PROTO_PIM, __func__); | |
112 | pim_upstream_start_register_stop_timer(up, 0); | |
113 | pim_vxlan_update_sg_reg_state(pim, up, false); | |
114 | break; | |
115 | case PIM_REG_JOIN_PENDING: | |
116 | up->reg_state = PIM_REG_PRUNE; | |
117 | pim_upstream_start_register_stop_timer(up, 0); | |
118 | return; | |
119 | } | |
120 | } | |
121 | ||
b206566b | 122 | int pim_register_stop_recv(struct interface *ifp, uint8_t *buf, int buf_size) |
4dffc880 | 123 | { |
b206566b DS |
124 | struct pim_interface *pim_ifp = ifp->info; |
125 | struct pim_instance *pim = pim_ifp->pim; | |
03f9d812 | 126 | struct pim_upstream *up = NULL; |
127 | struct pim_rpf *rp; | |
6fff2cc6 | 128 | pim_sgaddr sg; |
03f9d812 | 129 | struct listnode *up_node; |
130 | struct pim_upstream *child; | |
0d360092 | 131 | bool wrong_af = false; |
03f9d812 | 132 | bool handling_star = false; |
d62a17ae | 133 | int l; |
134 | ||
1e8f260c | 135 | if (pim_ifp->pim_passive_enable) { |
136 | if (PIM_DEBUG_PIM_PACKETS) | |
137 | zlog_debug( | |
138 | "skip receiving PIM message on passive interface %s", | |
139 | ifp->name); | |
140 | return 0; | |
141 | } | |
142 | ||
25ed72fe SP |
143 | ++pim_ifp->pim_ifstat_reg_stop_recv; |
144 | ||
6fff2cc6 | 145 | memset(&sg, 0, sizeof(sg)); |
d62a17ae | 146 | l = pim_parse_addr_group(&sg, buf, buf_size); |
147 | buf += l; | |
148 | buf_size -= l; | |
0d360092 DL |
149 | pim_parse_addr_ucast(&sg.src, buf, buf_size, &wrong_af); |
150 | ||
151 | if (wrong_af) { | |
152 | zlog_err("invalid AF in Register-Stop on %s", ifp->name); | |
1aa3f6b1 | 153 | return -1; |
0d360092 | 154 | } |
d62a17ae | 155 | |
d62a17ae | 156 | |
157 | if (PIM_DEBUG_PIM_REG) | |
03f9d812 | 158 | zlog_debug("Received Register stop for %pSG", &sg); |
159 | ||
160 | rp = RP(pim_ifp->pim, sg.grp); | |
161 | if (rp) { | |
e502ecad MR |
162 | /* As per RFC 7761, Section 4.9.4: |
163 | * A special wildcard value consisting of an address field of | |
164 | * all zeros can be used to indicate any source. | |
165 | */ | |
5d58abc1 | 166 | if ((pim_addr_cmp(sg.src, rp->rpf_addr) == 0) || |
e502ecad | 167 | pim_addr_is_any(sg.src)) { |
03f9d812 | 168 | handling_star = true; |
169 | sg.src = PIMADDR_ANY; | |
170 | } | |
171 | } | |
d62a17ae | 172 | |
03f9d812 | 173 | /* |
174 | * RFC 7761 Sec 4.4.1 | |
175 | * Handling Register-Stop(*,G) Messages at the DR: | |
176 | * A Register-Stop(*,G) should be treated as a | |
177 | * Register-Stop(S,G) for all (S,G) Register state | |
178 | * machines that are not in the NoInfo state. | |
179 | */ | |
180 | up = pim_upstream_find(pim, &sg); | |
181 | if (up) { | |
182 | /* | |
183 | * If the upstream find actually found a particular | |
184 | * S,G then we *know* that the following for loop | |
185 | * is not going to execute and this is ok | |
186 | */ | |
187 | for (ALL_LIST_ELEMENTS_RO(up->sources, up_node, child)) { | |
188 | if (PIM_DEBUG_PIM_REG) | |
189 | zlog_debug("Executing Reg stop for %s", | |
190 | child->sg_str); | |
191 | ||
192 | pim_reg_stop_upstream(pim, child); | |
193 | } | |
194 | ||
195 | if (PIM_DEBUG_PIM_REG) | |
196 | zlog_debug("Executing Reg stop for %s", up->sg_str); | |
197 | pim_reg_stop_upstream(pim, up); | |
198 | } else { | |
199 | if (!handling_star) | |
200 | return 0; | |
201 | /* | |
202 | * Unfortunately pim was unable to find a *,G | |
203 | * but pim may still actually have individual | |
204 | * S,G's that need to be processed. In that | |
205 | * case pim must do the expensive walk to find | |
206 | * and stop | |
207 | */ | |
208 | frr_each (rb_pim_upstream, &pim->upstream_head, up) { | |
209 | if (pim_addr_cmp(up->sg.grp, sg.grp) == 0) { | |
210 | if (PIM_DEBUG_PIM_REG) | |
211 | zlog_debug("Executing Reg stop for %s", | |
212 | up->sg_str); | |
213 | pim_reg_stop_upstream(pim, up); | |
214 | } | |
215 | } | |
d62a17ae | 216 | } |
217 | ||
218 | return 0; | |
4dffc880 DS |
219 | } |
220 | ||
4b603761 MR |
221 | #if PIM_IPV == 6 |
222 | struct in6_addr pim_register_get_unicast_v6_addr(struct pim_interface *p_ifp) | |
223 | { | |
224 | struct listnode *node; | |
225 | struct listnode *nextnode; | |
226 | struct pim_secondary_addr *sec_addr; | |
227 | struct pim_interface *pim_ifp; | |
228 | struct interface *ifp; | |
229 | struct pim_instance *pim = p_ifp->pim; | |
230 | ||
231 | /* Trying to get the unicast address from the RPF interface first */ | |
232 | for (ALL_LIST_ELEMENTS(p_ifp->sec_addr_list, node, nextnode, | |
233 | sec_addr)) { | |
234 | if (!is_ipv6_global_unicast(&sec_addr->addr.u.prefix6)) | |
235 | continue; | |
236 | ||
237 | return sec_addr->addr.u.prefix6; | |
238 | } | |
239 | ||
240 | /* Loop through all the pim interface and try to return a global | |
241 | * unicast ipv6 address | |
242 | */ | |
243 | FOR_ALL_INTERFACES (pim->vrf, ifp) { | |
244 | pim_ifp = ifp->info; | |
245 | ||
246 | if (!pim_ifp) | |
247 | continue; | |
248 | ||
249 | for (ALL_LIST_ELEMENTS(pim_ifp->sec_addr_list, node, nextnode, | |
250 | sec_addr)) { | |
251 | if (!is_ipv6_global_unicast(&sec_addr->addr.u.prefix6)) | |
252 | continue; | |
253 | ||
254 | return sec_addr->addr.u.prefix6; | |
255 | } | |
256 | } | |
257 | ||
258 | zlog_warn("No global address found for use to send register message"); | |
259 | return PIMADDR_ANY; | |
260 | } | |
261 | #endif | |
262 | ||
30b277e1 | 263 | void pim_register_send(const uint8_t *buf, int buf_size, pim_addr src, |
d62a17ae | 264 | struct pim_rpf *rpg, int null_register, |
265 | struct pim_upstream *up) | |
998af219 | 266 | { |
d62a17ae | 267 | unsigned char buffer[10000]; |
268 | unsigned char *b1; | |
269 | struct pim_interface *pinfo; | |
270 | struct interface *ifp; | |
271 | ||
272 | if (PIM_DEBUG_PIM_REG) { | |
30b277e1 | 273 | zlog_debug("Sending %s %sRegister Packet to %pPA", up->sg_str, |
5d58abc1 | 274 | null_register ? "NULL " : "", &rpg->rpf_addr); |
d62a17ae | 275 | } |
276 | ||
277 | ifp = rpg->source_nexthop.interface; | |
278 | if (!ifp) { | |
279 | if (PIM_DEBUG_PIM_REG) | |
280 | zlog_debug("%s: No interface to transmit register on", | |
15569c58 | 281 | __func__); |
d62a17ae | 282 | return; |
283 | } | |
284 | pinfo = (struct pim_interface *)ifp->info; | |
285 | if (!pinfo) { | |
286 | if (PIM_DEBUG_PIM_REG) | |
287 | zlog_debug( | |
63efca0e | 288 | "%s: Interface: %s not configured for pim to transmit on!", |
15569c58 | 289 | __func__, ifp->name); |
d62a17ae | 290 | return; |
291 | } | |
292 | ||
293 | if (PIM_DEBUG_PIM_REG) { | |
30b277e1 | 294 | zlog_debug("%s: Sending %s %sRegister Packet to %pPA on %s", |
15569c58 | 295 | __func__, up->sg_str, null_register ? "NULL " : "", |
5d58abc1 | 296 | &rpg->rpf_addr, ifp->name); |
d62a17ae | 297 | } |
298 | ||
299 | memset(buffer, 0, 10000); | |
300 | b1 = buffer + PIM_MSG_HEADER_LEN; | |
301 | *b1 |= null_register << 6; | |
302 | b1 = buffer + PIM_MSG_REGISTER_LEN; | |
303 | ||
304 | memcpy(b1, (const unsigned char *)buf, buf_size); | |
305 | ||
4b603761 MR |
306 | #if PIM_IPV == 6 |
307 | /* While sending Register message to RP, we cannot use link-local | |
308 | * address therefore using unicast ipv6 address here, choosing it | |
309 | * from the RPF Interface | |
310 | */ | |
311 | src = pim_register_get_unicast_v6_addr(pinfo); | |
312 | #endif | |
5d58abc1 | 313 | pim_msg_build_header(src, rpg->rpf_addr, buffer, |
314 | buf_size + PIM_MSG_REGISTER_LEN, | |
d57a8bbf | 315 | PIM_MSG_TYPE_REGISTER, false); |
d62a17ae | 316 | |
6dd493b8 | 317 | if (!pinfo->pim_passive_enable) |
318 | ++pinfo->pim_ifstat_reg_send; | |
d62a17ae | 319 | |
94619539 | 320 | if (pim_msg_send(pinfo->pim->reg_sock, src, rpg->rpf_addr, buffer, |
6dd493b8 | 321 | buf_size + PIM_MSG_REGISTER_LEN, ifp)) { |
d62a17ae | 322 | if (PIM_DEBUG_PIM_TRACE) { |
323 | zlog_debug( | |
324 | "%s: could not send PIM register message on interface %s", | |
15569c58 | 325 | __func__, ifp->name); |
d62a17ae | 326 | } |
327 | return; | |
328 | } | |
998af219 DS |
329 | } |
330 | ||
30b277e1 | 331 | #if PIM_IPV == 4 |
aea1f845 AK |
332 | void pim_null_register_send(struct pim_upstream *up) |
333 | { | |
334 | struct ip ip_hdr; | |
335 | struct pim_interface *pim_ifp; | |
336 | struct pim_rpf *rpg; | |
30b277e1 | 337 | pim_addr src; |
aea1f845 AK |
338 | |
339 | pim_ifp = up->rpf.source_nexthop.interface->info; | |
340 | if (!pim_ifp) { | |
23fc858a | 341 | if (PIM_DEBUG_PIM_TRACE) |
aea1f845 AK |
342 | zlog_debug( |
343 | "%s: Cannot send null-register for %s no valid iif", | |
15569c58 | 344 | __func__, up->sg_str); |
aea1f845 AK |
345 | return; |
346 | } | |
347 | ||
348 | rpg = RP(pim_ifp->pim, up->sg.grp); | |
349 | if (!rpg) { | |
23fc858a | 350 | if (PIM_DEBUG_PIM_TRACE) |
aea1f845 AK |
351 | zlog_debug( |
352 | "%s: Cannot send null-register for %s no RPF to the RP", | |
15569c58 | 353 | __func__, up->sg_str); |
aea1f845 AK |
354 | return; |
355 | } | |
356 | ||
6006b807 | 357 | memset(&ip_hdr, 0, sizeof(ip_hdr)); |
aea1f845 AK |
358 | ip_hdr.ip_p = PIM_IP_PROTO_PIM; |
359 | ip_hdr.ip_hl = 5; | |
360 | ip_hdr.ip_v = 4; | |
361 | ip_hdr.ip_src = up->sg.src; | |
362 | ip_hdr.ip_dst = up->sg.grp; | |
363 | ip_hdr.ip_len = htons(20); | |
364 | ||
365 | /* checksum is broken */ | |
366 | src = pim_ifp->primary_address; | |
d9e75668 AK |
367 | if (PIM_UPSTREAM_FLAG_TEST_SRC_VXLAN_ORIG(up->flags)) { |
368 | if (!pim_vxlan_get_register_src(pim_ifp->pim, up, &src)) { | |
23fc858a | 369 | if (PIM_DEBUG_PIM_TRACE) |
d9e75668 AK |
370 | zlog_debug( |
371 | "%s: Cannot send null-register for %s vxlan-aa PIP unavailable", | |
15569c58 | 372 | __func__, up->sg_str); |
d9e75668 AK |
373 | return; |
374 | } | |
375 | } | |
30b277e1 | 376 | pim_register_send((uint8_t *)&ip_hdr, sizeof(struct ip), src, rpg, 1, |
377 | up); | |
aea1f845 | 378 | } |
30b277e1 | 379 | #else |
380 | void pim_null_register_send(struct pim_upstream *up) | |
381 | { | |
382 | struct ip6_hdr ip6_hdr; | |
383 | struct pim_msg_header pim_msg_header; | |
384 | struct pim_interface *pim_ifp; | |
385 | struct pim_rpf *rpg; | |
386 | pim_addr src; | |
387 | unsigned char buffer[sizeof(ip6_hdr) + sizeof(pim_msg_header)]; | |
388 | struct ipv6_ph ph; | |
389 | ||
390 | pim_ifp = up->rpf.source_nexthop.interface->info; | |
391 | if (!pim_ifp) { | |
392 | if (PIM_DEBUG_PIM_TRACE) | |
393 | zlog_debug( | |
394 | "Cannot send null-register for %s no valid iif", | |
395 | up->sg_str); | |
396 | return; | |
397 | } | |
398 | ||
399 | rpg = RP(pim_ifp->pim, up->sg.grp); | |
400 | if (!rpg) { | |
401 | if (PIM_DEBUG_PIM_TRACE) | |
402 | zlog_debug( | |
403 | "Cannot send null-register for %s no RPF to the RP", | |
404 | up->sg_str); | |
405 | return; | |
406 | } | |
407 | ||
408 | memset(&ip6_hdr, 0, sizeof(ip6_hdr)); | |
409 | ip6_hdr.ip6_nxt = PIM_IP_PROTO_PIM; | |
410 | ip6_hdr.ip6_plen = PIM_MSG_HEADER_LEN; | |
411 | ip6_hdr.ip6_vfc = 6 << 4; | |
412 | ip6_hdr.ip6_hlim = MAXTTL; | |
413 | ip6_hdr.ip6_src = up->sg.src; | |
414 | ip6_hdr.ip6_dst = up->sg.grp; | |
415 | ||
416 | memset(buffer, 0, (sizeof(ip6_hdr) + sizeof(pim_msg_header))); | |
417 | memcpy(buffer, &ip6_hdr, sizeof(ip6_hdr)); | |
418 | ||
419 | pim_msg_header.ver = 0; | |
420 | pim_msg_header.type = 0; | |
421 | pim_msg_header.reserved = 0; | |
422 | ||
423 | pim_msg_header.checksum = 0; | |
424 | ||
425 | ph.src = up->sg.src; | |
426 | ph.dst = up->sg.grp; | |
427 | ph.ulpl = htonl(PIM_MSG_HEADER_LEN); | |
428 | ph.next_hdr = IPPROTO_PIM; | |
429 | pim_msg_header.checksum = | |
430 | in_cksum_with_ph6(&ph, &pim_msg_header, PIM_MSG_HEADER_LEN); | |
431 | ||
432 | memcpy(buffer + sizeof(ip6_hdr), &pim_msg_header, PIM_MSG_HEADER_LEN); | |
433 | ||
434 | ||
435 | src = pim_ifp->primary_address; | |
436 | pim_register_send((uint8_t *)buffer, | |
437 | sizeof(ip6_hdr) + PIM_MSG_HEADER_LEN, src, rpg, 1, | |
438 | up); | |
439 | } | |
440 | #endif | |
aea1f845 | 441 | |
01d68c9b DS |
442 | /* |
443 | * 4.4.2 Receiving Register Messages at the RP | |
444 | * | |
445 | * When an RP receives a Register message, the course of action is | |
446 | * decided according to the following pseudocode: | |
447 | * | |
448 | * packet_arrives_on_rp_tunnel( pkt ) { | |
449 | * if( outer.dst is not one of my addresses ) { | |
450 | * drop the packet silently. | |
451 | * # Note: this may be a spoofing attempt | |
452 | * } | |
453 | * if( I_am_RP(G) AND outer.dst == RP(G) ) { | |
2951a7a4 QY |
454 | * sentRegisterStop = false; |
455 | * if ( register.borderbit == true ) { | |
01d68c9b DS |
456 | * if ( PMBR(S,G) == unknown ) { |
457 | * PMBR(S,G) = outer.src | |
458 | * } else if ( outer.src != PMBR(S,G) ) { | |
459 | * send Register-Stop(S,G) to outer.src | |
460 | * drop the packet silently. | |
461 | * } | |
462 | * } | |
463 | * if ( SPTbit(S,G) OR | |
464 | * ( SwitchToSptDesired(S,G) AND | |
465 | * ( inherited_olist(S,G) == NULL ))) { | |
466 | * send Register-Stop(S,G) to outer.src | |
2951a7a4 | 467 | * sentRegisterStop = true; |
01d68c9b DS |
468 | * } |
469 | * if ( SPTbit(S,G) OR SwitchToSptDesired(S,G) ) { | |
2951a7a4 | 470 | * if ( sentRegisterStop == true ) { |
01d68c9b DS |
471 | * set KeepaliveTimer(S,G) to RP_Keepalive_Period; |
472 | * } else { | |
473 | * set KeepaliveTimer(S,G) to Keepalive_Period; | |
474 | * } | |
475 | * } | |
476 | * if( !SPTbit(S,G) AND ! pkt.NullRegisterBit ) { | |
477 | * decapsulate and forward the inner packet to | |
478 | * inherited_olist(S,G,rpt) # Note (+) | |
479 | * } | |
480 | * } else { | |
481 | * send Register-Stop(S,G) to outer.src | |
482 | * # Note (*) | |
483 | * } | |
484 | * } | |
485 | */ | |
c7842d24 MR |
486 | int pim_register_recv(struct interface *ifp, pim_addr dest_addr, |
487 | pim_addr src_addr, uint8_t *tlv_buf, int tlv_buf_size) | |
01d68c9b | 488 | { |
d62a17ae | 489 | int sentRegisterStop = 0; |
c7842d24 | 490 | const void *ip_hdr; |
6fff2cc6 | 491 | pim_sgaddr sg; |
d62a17ae | 492 | uint32_t *bits; |
493 | int i_am_rp = 0; | |
2ca35b64 DS |
494 | struct pim_interface *pim_ifp = ifp->info; |
495 | struct pim_instance *pim = pim_ifp->pim; | |
c7842d24 | 496 | pim_addr rp_addr; |
fec883d9 | 497 | |
b4afc283 | 498 | if (pim_ifp->pim_passive_enable) { |
499 | if (PIM_DEBUG_PIM_PACKETS) | |
500 | zlog_debug( | |
501 | "skip receiving PIM message on passive interface %s", | |
502 | ifp->name); | |
503 | return 0; | |
504 | } | |
505 | ||
75a26779 | 506 | #define PIM_MSG_REGISTER_BIT_RESERVED_LEN 4 |
c7842d24 | 507 | ip_hdr = (tlv_buf + PIM_MSG_REGISTER_BIT_RESERVED_LEN); |
d62a17ae | 508 | |
c7842d24 MR |
509 | if (!if_address_is_local(&dest_addr, PIM_AF, pim->vrf->vrf_id)) { |
510 | if (PIM_DEBUG_PIM_REG) | |
d62a17ae | 511 | zlog_debug( |
c7842d24 MR |
512 | "%s: Received Register message for destination address: %pPA that I do not own", |
513 | __func__, &dest_addr); | |
d62a17ae | 514 | return 0; |
515 | } | |
516 | ||
d62a17ae | 517 | ++pim_ifp->pim_ifstat_reg_recv; |
518 | ||
519 | /* | |
520 | * Please note this is not drawn to get the correct bit/data size | |
521 | * | |
522 | * The entirety of the REGISTER packet looks like this: | |
523 | * ------------------------------------------------------------- | |
524 | * | Ver | Type | Reserved | Checksum | | |
525 | * |-----------------------------------------------------------| | |
526 | * |B|N| Reserved 2 | | |
527 | * |-----------------------------------------------------------| | |
528 | * | Encap | IP HDR | | |
529 | * | Mcast | | | |
530 | * | Packet |--------------------------------------------------| | |
531 | * | | Mcast Data | | |
532 | * | | | | |
533 | * ... | |
534 | * | |
535 | * tlv_buf when received from the caller points at the B bit | |
536 | * We need to know the inner source and dest | |
537 | */ | |
538 | bits = (uint32_t *)tlv_buf; | |
539 | ||
540 | /* | |
541 | * tlv_buf points to the start of the |B|N|... Reserved | |
542 | * Line above. So we need to add 4 bytes to get to the | |
543 | * start of the actual Encapsulated data. | |
544 | */ | |
6fff2cc6 | 545 | memset(&sg, 0, sizeof(sg)); |
c7842d24 | 546 | sg = pim_sgaddr_from_iphdr(ip_hdr); |
d62a17ae | 547 | |
30b277e1 | 548 | #if PIM_IPV == 6 |
549 | /* | |
550 | * According to RFC section 4.9.3, If Dummy PIM Header is included | |
551 | * in NULL Register as a payload there would be two PIM headers. | |
552 | * The inner PIM Header's checksum field should also be validated | |
553 | * in addition to the outer PIM Header's checksum. Validation of | |
554 | * inner PIM header checksum is done here. | |
555 | */ | |
556 | if ((*bits & PIM_REGISTER_NR_BIT) && | |
557 | ((tlv_buf_size - PIM_MSG_REGISTER_BIT_RESERVED_LEN) > | |
558 | (int)sizeof(struct ip6_hdr))) { | |
559 | uint16_t computed_checksum; | |
560 | uint16_t received_checksum; | |
561 | struct ipv6_ph ph; | |
562 | struct pim_msg_header *header; | |
563 | ||
564 | header = (struct pim_msg_header | |
565 | *)(tlv_buf + | |
566 | PIM_MSG_REGISTER_BIT_RESERVED_LEN + | |
567 | sizeof(struct ip6_hdr)); | |
568 | ph.src = sg.src; | |
569 | ph.dst = sg.grp; | |
570 | ph.ulpl = htonl(PIM_MSG_HEADER_LEN); | |
571 | ph.next_hdr = IPPROTO_PIM; | |
572 | ||
573 | received_checksum = header->checksum; | |
574 | ||
575 | header->checksum = 0; | |
576 | computed_checksum = in_cksum_with_ph6( | |
577 | &ph, header, htonl(PIM_MSG_HEADER_LEN)); | |
578 | ||
579 | if (computed_checksum != received_checksum) { | |
580 | if (PIM_DEBUG_PIM_PACKETS) | |
581 | zlog_debug( | |
582 | "Ignoring Null Register message%pSG from %pPA due to bad checksum in Encapsulated dummy PIM header", | |
583 | &sg, &src_addr); | |
584 | return 0; | |
585 | } | |
586 | } | |
587 | #endif | |
2ca35b64 | 588 | i_am_rp = I_am_RP(pim, sg.grp); |
d62a17ae | 589 | |
c7842d24 MR |
590 | if (PIM_DEBUG_PIM_REG) |
591 | zlog_debug( | |
592 | "Received Register message%pSG from %pPA on %s, rp: %d", | |
593 | &sg, &src_addr, ifp->name, i_am_rp); | |
d62a17ae | 594 | |
34abbcc4 | 595 | if (pim_is_grp_ssm(pim_ifp->pim, sg.grp)) { |
2a27f13b | 596 | if (pim_addr_is_any(sg.src)) { |
34abbcc4 | 597 | zlog_warn( |
6d7bf748 | 598 | "%s: Received Register message for Group(%pPA) is now in SSM, dropping the packet", |
38c848c9 | 599 | __func__, &sg.grp); |
34abbcc4 SG |
600 | /* Drop Packet Silently */ |
601 | return 0; | |
602 | } | |
603 | } | |
604 | ||
5d58abc1 | 605 | rp_addr = (RP(pim, sg.grp))->rpf_addr; |
c7842d24 | 606 | if (i_am_rp && (!pim_addr_cmp(dest_addr, rp_addr))) { |
d62a17ae | 607 | sentRegisterStop = 0; |
608 | ||
f4e74bd0 DS |
609 | if (pim->register_plist) { |
610 | struct prefix_list *plist; | |
611 | struct prefix src; | |
612 | ||
c631920c DL |
613 | plist = prefix_list_lookup(PIM_AFI, |
614 | pim->register_plist); | |
f4e74bd0 | 615 | |
c631920c | 616 | pim_addr_to_prefix(&src, sg.src); |
f4e74bd0 | 617 | |
ab2f9e89 DL |
618 | if (prefix_list_apply_ext(plist, NULL, &src, true) == |
619 | PREFIX_DENY) { | |
f4e74bd0 DS |
620 | pim_register_stop_send(ifp, &sg, dest_addr, |
621 | src_addr); | |
c7842d24 | 622 | if (PIM_DEBUG_PIM_PACKETS) |
d51f8b0f | 623 | zlog_debug( |
c7842d24 MR |
624 | "%s: Sending register-stop to %pPA for %pSG due to prefix-list denial, dropping packet", |
625 | __func__, &src_addr, &sg); | |
f4e74bd0 DS |
626 | |
627 | return 0; | |
628 | } | |
629 | } | |
630 | ||
d62a17ae | 631 | if (*bits & PIM_REGISTER_BORDER_BIT) { |
d62a17ae | 632 | if (PIM_DEBUG_PIM_PACKETS) |
633 | zlog_debug( | |
d139e9e8 | 634 | "%s: Received Register message with Border bit set, ignoring", |
d62a17ae | 635 | __func__); |
636 | ||
d62a17ae | 637 | /* Drop Packet Silently */ |
d139e9e8 | 638 | return 0; |
d62a17ae | 639 | } |
640 | ||
2ca35b64 | 641 | struct pim_upstream *upstream = pim_upstream_find(pim, &sg); |
d62a17ae | 642 | /* |
643 | * If we don't have a place to send ignore the packet | |
644 | */ | |
645 | if (!upstream) { | |
646 | upstream = pim_upstream_add( | |
2ca35b64 | 647 | pim, &sg, ifp, |
15569c58 DA |
648 | PIM_UPSTREAM_FLAG_MASK_SRC_STREAM, __func__, |
649 | NULL); | |
d62a17ae | 650 | if (!upstream) { |
651 | zlog_warn("Failure to create upstream state"); | |
652 | return 1; | |
653 | } | |
654 | ||
655 | upstream->upstream_register = src_addr; | |
cc61055f DS |
656 | } else { |
657 | /* | |
658 | * If the FHR has set a very very fast register timer | |
659 | * there exists a possibility that the incoming NULL | |
660 | * register | |
661 | * is happening before we set the spt bit. If so | |
662 | * Do a quick check to update the counters and | |
663 | * then set the spt bit as appropriate | |
664 | */ | |
665 | if (upstream->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) { | |
666 | pim_mroute_update_counters( | |
667 | upstream->channel_oil); | |
668 | /* | |
669 | * Have we seen packets? | |
670 | */ | |
671 | if (upstream->channel_oil->cc.oldpktcnt | |
672 | < upstream->channel_oil->cc.pktcnt) | |
673 | pim_upstream_set_sptbit( | |
674 | upstream, | |
675 | upstream->rpf.source_nexthop | |
676 | .interface); | |
677 | } | |
d62a17ae | 678 | } |
679 | ||
680 | if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) | |
2ca35b64 DS |
681 | || ((SwitchToSptDesiredOnRp(pim, &sg)) |
682 | && pim_upstream_inherited_olist(pim, upstream) == 0)) { | |
d62a17ae | 683 | pim_register_stop_send(ifp, &sg, dest_addr, src_addr); |
684 | sentRegisterStop = 1; | |
685 | } else { | |
686 | if (PIM_DEBUG_PIM_REG) | |
687 | zlog_debug("(%s) sptbit: %d", upstream->sg_str, | |
688 | upstream->sptbit); | |
689 | } | |
690 | if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) | |
2ca35b64 | 691 | || (SwitchToSptDesiredOnRp(pim, &sg))) { |
d62a17ae | 692 | if (sentRegisterStop) { |
693 | pim_upstream_keep_alive_timer_start( | |
2ca35b64 | 694 | upstream, pim->rp_keep_alive_time); |
d62a17ae | 695 | } else { |
696 | pim_upstream_keep_alive_timer_start( | |
2ca35b64 | 697 | upstream, pim->keep_alive_time); |
d62a17ae | 698 | } |
699 | } | |
700 | ||
701 | if (!(upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) | |
702 | && !(*bits & PIM_REGISTER_NR_BIT)) { | |
703 | // decapsulate and forward the iner packet to | |
704 | // inherited_olist(S,G,rpt) | |
705 | // This is taken care of by the kernel for us | |
706 | } | |
707 | pim_upstream_msdp_reg_timer_start(upstream); | |
708 | } else { | |
709 | if (PIM_DEBUG_PIM_REG) { | |
710 | if (!i_am_rp) | |
98a81d2b DL |
711 | zlog_debug("Received Register packet for %pSG, Rejecting packet because I am not the RP configured for group", |
712 | &sg); | |
d62a17ae | 713 | else |
98a81d2b DL |
714 | zlog_debug("Received Register packet for %pSG, Rejecting packet because the dst ip address is not the actual RP", |
715 | &sg); | |
d62a17ae | 716 | } |
717 | pim_register_stop_send(ifp, &sg, dest_addr, src_addr); | |
718 | } | |
719 | ||
8dc60b69 | 720 | return 0; |
01d68c9b | 721 | } |
46a9ea8b | 722 | |
723 | /* | |
724 | * This routine scan all upstream and update register state and remove pimreg | |
725 | * when couldreg becomes false. | |
726 | */ | |
727 | void pim_reg_del_on_couldreg_fail(struct interface *ifp) | |
728 | { | |
729 | struct pim_interface *pim_ifp = ifp->info; | |
730 | struct pim_instance *pim; | |
731 | struct pim_upstream *up; | |
732 | ||
733 | if (!pim_ifp) | |
734 | return; | |
735 | ||
736 | pim = pim_ifp->pim; | |
737 | ||
738 | frr_each (rb_pim_upstream, &pim->upstream_head, up) { | |
739 | if (ifp != up->rpf.source_nexthop.interface) | |
740 | continue; | |
741 | ||
742 | if (!pim_upstream_could_register(up) | |
743 | && (up->reg_state != PIM_REG_NOINFO)) { | |
744 | pim_channel_del_oif(up->channel_oil, pim->regiface, | |
745 | PIM_OIF_FLAG_PROTO_PIM, __func__); | |
e16d030c | 746 | EVENT_OFF(up->t_rs_timer); |
46a9ea8b | 747 | up->reg_state = PIM_REG_NOINFO; |
748 | } | |
749 | } | |
750 | } |