/src/frr/pimd/pim_register.c
Line | Count | Source |
1 | | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | | /* |
3 | | * PIM for Quagga |
4 | | * Copyright (C) 2015 Cumulus Networks, Inc. |
5 | | * Donald Sharp |
6 | | */ |
7 | | |
8 | | #include <zebra.h> |
9 | | |
10 | | #include "log.h" |
11 | | #include "if.h" |
12 | | #include "frrevent.h" |
13 | | #include "prefix.h" |
14 | | #include "vty.h" |
15 | | #include "plist.h" |
16 | | |
17 | | #include "pimd.h" |
18 | | #include "pim_mroute.h" |
19 | | #include "pim_iface.h" |
20 | | #include "pim_msg.h" |
21 | | #include "pim_pim.h" |
22 | | #include "pim_str.h" |
23 | | #include "pim_rp.h" |
24 | | #include "pim_register.h" |
25 | | #include "pim_upstream.h" |
26 | | #include "pim_rpf.h" |
27 | | #include "pim_oil.h" |
28 | | #include "pim_zebra.h" |
29 | | #include "pim_join.h" |
30 | | #include "pim_util.h" |
31 | | #include "pim_ssm.h" |
32 | | #include "pim_vxlan.h" |
33 | | #include "pim_addr.h" |
34 | | |
35 | | struct event *send_test_packet_timer = NULL; |
36 | | |
37 | | void pim_register_join(struct pim_upstream *up) |
38 | 0 | { |
39 | 0 | struct pim_instance *pim = up->channel_oil->pim; |
40 | |
|
41 | 0 | if (pim_is_grp_ssm(pim, up->sg.grp)) { |
42 | 0 | if (PIM_DEBUG_PIM_EVENTS) |
43 | 0 | zlog_debug("%s register setup skipped as group is SSM", |
44 | 0 | up->sg_str); |
45 | 0 | return; |
46 | 0 | } |
47 | | |
48 | 0 | pim_channel_add_oif(up->channel_oil, pim->regiface, |
49 | 0 | PIM_OIF_FLAG_PROTO_PIM, __func__); |
50 | 0 | up->reg_state = PIM_REG_JOIN; |
51 | 0 | pim_vxlan_update_sg_reg_state(pim, up, true); |
52 | 0 | } |
53 | | |
54 | | void pim_register_stop_send(struct interface *ifp, pim_sgaddr *sg, pim_addr src, |
55 | | pim_addr originator) |
56 | 6 | { |
57 | 6 | struct pim_interface *pinfo; |
58 | 6 | unsigned char buffer[10000]; |
59 | 6 | unsigned int b1length = 0; |
60 | 6 | unsigned int length; |
61 | 6 | uint8_t *b1; |
62 | | |
63 | 6 | if (PIM_DEBUG_PIM_REG) { |
64 | 0 | zlog_debug("Sending Register stop for %pSG to %pPA on %s", sg, |
65 | 0 | &originator, ifp->name); |
66 | 0 | } |
67 | | |
68 | 6 | memset(buffer, 0, 10000); |
69 | 6 | b1 = (uint8_t *)buffer + PIM_MSG_REGISTER_STOP_LEN; |
70 | | |
71 | 6 | length = pim_encode_addr_group(b1, AFI_IP, 0, 0, sg->grp); |
72 | 6 | b1length += length; |
73 | 6 | b1 += length; |
74 | | |
75 | 6 | length = pim_encode_addr_ucast(b1, sg->src); |
76 | 6 | b1length += length; |
77 | | |
78 | 6 | pim_msg_build_header(src, originator, buffer, |
79 | 6 | b1length + PIM_MSG_REGISTER_STOP_LEN, |
80 | 6 | PIM_MSG_TYPE_REG_STOP, false); |
81 | | |
82 | 6 | pinfo = (struct pim_interface *)ifp->info; |
83 | 6 | if (!pinfo) { |
84 | 0 | if (PIM_DEBUG_PIM_TRACE) |
85 | 0 | zlog_debug("%s: No pinfo!", __func__); |
86 | 0 | return; |
87 | 0 | } |
88 | 6 | if (pim_msg_send(pinfo->pim_sock_fd, src, originator, buffer, |
89 | 6 | b1length + PIM_MSG_REGISTER_STOP_LEN, ifp)) { |
90 | 0 | if (PIM_DEBUG_PIM_TRACE) { |
91 | 0 | zlog_debug( |
92 | 0 | "%s: could not send PIM register stop message on interface %s", |
93 | 0 | __func__, ifp->name); |
94 | 0 | } |
95 | 0 | } |
96 | | |
97 | 6 | if (!pinfo->pim_passive_enable) |
98 | 6 | ++pinfo->pim_ifstat_reg_stop_send; |
99 | 6 | } |
100 | | |
101 | | static void pim_reg_stop_upstream(struct pim_instance *pim, |
102 | | struct pim_upstream *up) |
103 | 118 | { |
104 | 118 | switch (up->reg_state) { |
105 | 118 | case PIM_REG_NOINFO: |
106 | 118 | case PIM_REG_PRUNE: |
107 | 118 | return; |
108 | 0 | case PIM_REG_JOIN: |
109 | 0 | up->reg_state = PIM_REG_PRUNE; |
110 | 0 | pim_channel_del_oif(up->channel_oil, pim->regiface, |
111 | 0 | PIM_OIF_FLAG_PROTO_PIM, __func__); |
112 | 0 | pim_upstream_start_register_stop_timer(up, 0); |
113 | 0 | pim_vxlan_update_sg_reg_state(pim, up, false); |
114 | 0 | break; |
115 | 0 | case PIM_REG_JOIN_PENDING: |
116 | 0 | up->reg_state = PIM_REG_PRUNE; |
117 | 0 | pim_upstream_start_register_stop_timer(up, 0); |
118 | 0 | return; |
119 | 118 | } |
120 | 118 | } |
121 | | |
122 | | int pim_register_stop_recv(struct interface *ifp, uint8_t *buf, int buf_size) |
123 | 144 | { |
124 | 144 | struct pim_interface *pim_ifp = ifp->info; |
125 | 144 | struct pim_instance *pim = pim_ifp->pim; |
126 | 144 | struct pim_upstream *up = NULL; |
127 | 144 | struct pim_rpf *rp; |
128 | 144 | pim_sgaddr sg; |
129 | 144 | struct listnode *up_node; |
130 | 144 | struct pim_upstream *child; |
131 | 144 | bool wrong_af = false; |
132 | 144 | bool handling_star = false; |
133 | 144 | int l; |
134 | | |
135 | 144 | if (pim_ifp->pim_passive_enable) { |
136 | 0 | if (PIM_DEBUG_PIM_PACKETS) |
137 | 0 | zlog_debug( |
138 | 0 | "skip receiving PIM message on passive interface %s", |
139 | 0 | ifp->name); |
140 | 0 | return 0; |
141 | 0 | } |
142 | | |
143 | 144 | ++pim_ifp->pim_ifstat_reg_stop_recv; |
144 | | |
145 | 144 | memset(&sg, 0, sizeof(sg)); |
146 | 144 | l = pim_parse_addr_group(&sg, buf, buf_size); |
147 | 144 | buf += l; |
148 | 144 | buf_size -= l; |
149 | 144 | pim_parse_addr_ucast(&sg.src, buf, buf_size, &wrong_af); |
150 | | |
151 | 144 | if (wrong_af) { |
152 | 1 | zlog_err("invalid AF in Register-Stop on %s", ifp->name); |
153 | 1 | return -1; |
154 | 1 | } |
155 | | |
156 | | |
157 | 143 | if (PIM_DEBUG_PIM_REG) |
158 | 0 | zlog_debug("Received Register stop for %pSG", &sg); |
159 | | |
160 | 143 | rp = RP(pim_ifp->pim, sg.grp); |
161 | 143 | if (rp) { |
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 | | */ |
166 | 17 | if ((pim_addr_cmp(sg.src, rp->rpf_addr) == 0) || |
167 | 15 | pim_addr_is_any(sg.src)) { |
168 | 15 | handling_star = true; |
169 | 15 | sg.src = PIMADDR_ANY; |
170 | 15 | } |
171 | 17 | } |
172 | | |
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 | 143 | up = pim_upstream_find(pim, &sg); |
181 | 143 | 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 | 90 | for (ALL_LIST_ELEMENTS_RO(up->sources, up_node, child)) { |
188 | 90 | if (PIM_DEBUG_PIM_REG) |
189 | 0 | zlog_debug("Executing Reg stop for %s", |
190 | 90 | child->sg_str); |
191 | | |
192 | 90 | pim_reg_stop_upstream(pim, child); |
193 | 90 | } |
194 | | |
195 | 24 | if (PIM_DEBUG_PIM_REG) |
196 | 0 | zlog_debug("Executing Reg stop for %s", up->sg_str); |
197 | 24 | pim_reg_stop_upstream(pim, up); |
198 | 119 | } else { |
199 | 119 | if (!handling_star) |
200 | 111 | 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 | 383 | frr_each (rb_pim_upstream, &pim->upstream_head, up) { |
209 | 383 | if (pim_addr_cmp(up->sg.grp, sg.grp) == 0) { |
210 | 4 | if (PIM_DEBUG_PIM_REG) |
211 | 0 | zlog_debug("Executing Reg stop for %s", |
212 | 4 | up->sg_str); |
213 | 4 | pim_reg_stop_upstream(pim, up); |
214 | 4 | } |
215 | 383 | } |
216 | 8 | } |
217 | | |
218 | 32 | return 0; |
219 | 143 | } |
220 | | |
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 | | |
263 | | void pim_register_send(const uint8_t *buf, int buf_size, pim_addr src, |
264 | | struct pim_rpf *rpg, int null_register, |
265 | | struct pim_upstream *up) |
266 | 0 | { |
267 | 0 | unsigned char buffer[10000]; |
268 | 0 | unsigned char *b1; |
269 | 0 | struct pim_interface *pinfo; |
270 | 0 | struct interface *ifp; |
271 | |
|
272 | 0 | if (PIM_DEBUG_PIM_REG) { |
273 | 0 | zlog_debug("Sending %s %sRegister Packet to %pPA", up->sg_str, |
274 | 0 | null_register ? "NULL " : "", &rpg->rpf_addr); |
275 | 0 | } |
276 | |
|
277 | 0 | ifp = rpg->source_nexthop.interface; |
278 | 0 | if (!ifp) { |
279 | 0 | if (PIM_DEBUG_PIM_REG) |
280 | 0 | zlog_debug("%s: No interface to transmit register on", |
281 | 0 | __func__); |
282 | 0 | return; |
283 | 0 | } |
284 | 0 | pinfo = (struct pim_interface *)ifp->info; |
285 | 0 | if (!pinfo) { |
286 | 0 | if (PIM_DEBUG_PIM_REG) |
287 | 0 | zlog_debug( |
288 | 0 | "%s: Interface: %s not configured for pim to transmit on!", |
289 | 0 | __func__, ifp->name); |
290 | 0 | return; |
291 | 0 | } |
292 | | |
293 | 0 | if (PIM_DEBUG_PIM_REG) { |
294 | 0 | zlog_debug("%s: Sending %s %sRegister Packet to %pPA on %s", |
295 | 0 | __func__, up->sg_str, null_register ? "NULL " : "", |
296 | 0 | &rpg->rpf_addr, ifp->name); |
297 | 0 | } |
298 | |
|
299 | 0 | memset(buffer, 0, 10000); |
300 | 0 | b1 = buffer + PIM_MSG_HEADER_LEN; |
301 | 0 | *b1 |= null_register << 6; |
302 | 0 | b1 = buffer + PIM_MSG_REGISTER_LEN; |
303 | |
|
304 | 0 | memcpy(b1, (const unsigned char *)buf, buf_size); |
305 | |
|
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 |
313 | 0 | pim_msg_build_header(src, rpg->rpf_addr, buffer, |
314 | 0 | buf_size + PIM_MSG_REGISTER_LEN, |
315 | 0 | PIM_MSG_TYPE_REGISTER, false); |
316 | |
|
317 | 0 | if (!pinfo->pim_passive_enable) |
318 | 0 | ++pinfo->pim_ifstat_reg_send; |
319 | |
|
320 | 0 | if (pim_msg_send(pinfo->pim->reg_sock, src, rpg->rpf_addr, buffer, |
321 | 0 | buf_size + PIM_MSG_REGISTER_LEN, ifp)) { |
322 | 0 | if (PIM_DEBUG_PIM_TRACE) { |
323 | 0 | zlog_debug( |
324 | 0 | "%s: could not send PIM register message on interface %s", |
325 | 0 | __func__, ifp->name); |
326 | 0 | } |
327 | 0 | return; |
328 | 0 | } |
329 | 0 | } |
330 | | |
331 | | #if PIM_IPV == 4 |
332 | | void pim_null_register_send(struct pim_upstream *up) |
333 | 0 | { |
334 | 0 | struct ip ip_hdr; |
335 | 0 | struct pim_interface *pim_ifp; |
336 | 0 | struct pim_rpf *rpg; |
337 | 0 | pim_addr src; |
338 | |
|
339 | 0 | pim_ifp = up->rpf.source_nexthop.interface->info; |
340 | 0 | if (!pim_ifp) { |
341 | 0 | if (PIM_DEBUG_PIM_TRACE) |
342 | 0 | zlog_debug( |
343 | 0 | "%s: Cannot send null-register for %s no valid iif", |
344 | 0 | __func__, up->sg_str); |
345 | 0 | return; |
346 | 0 | } |
347 | | |
348 | 0 | rpg = RP(pim_ifp->pim, up->sg.grp); |
349 | 0 | if (!rpg) { |
350 | 0 | if (PIM_DEBUG_PIM_TRACE) |
351 | 0 | zlog_debug( |
352 | 0 | "%s: Cannot send null-register for %s no RPF to the RP", |
353 | 0 | __func__, up->sg_str); |
354 | 0 | return; |
355 | 0 | } |
356 | | |
357 | 0 | memset(&ip_hdr, 0, sizeof(ip_hdr)); |
358 | 0 | ip_hdr.ip_p = PIM_IP_PROTO_PIM; |
359 | 0 | ip_hdr.ip_hl = 5; |
360 | 0 | ip_hdr.ip_v = 4; |
361 | 0 | ip_hdr.ip_src = up->sg.src; |
362 | 0 | ip_hdr.ip_dst = up->sg.grp; |
363 | 0 | ip_hdr.ip_len = htons(20); |
364 | | |
365 | | /* checksum is broken */ |
366 | 0 | src = pim_ifp->primary_address; |
367 | 0 | if (PIM_UPSTREAM_FLAG_TEST_SRC_VXLAN_ORIG(up->flags)) { |
368 | 0 | if (!pim_vxlan_get_register_src(pim_ifp->pim, up, &src)) { |
369 | 0 | if (PIM_DEBUG_PIM_TRACE) |
370 | 0 | zlog_debug( |
371 | 0 | "%s: Cannot send null-register for %s vxlan-aa PIP unavailable", |
372 | 0 | __func__, up->sg_str); |
373 | 0 | return; |
374 | 0 | } |
375 | 0 | } |
376 | 0 | pim_register_send((uint8_t *)&ip_hdr, sizeof(struct ip), src, rpg, 1, |
377 | 0 | up); |
378 | 0 | } |
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 |
441 | | |
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) ) { |
454 | | * sentRegisterStop = false; |
455 | | * if ( register.borderbit == true ) { |
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 |
467 | | * sentRegisterStop = true; |
468 | | * } |
469 | | * if ( SPTbit(S,G) OR SwitchToSptDesired(S,G) ) { |
470 | | * if ( sentRegisterStop == true ) { |
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 | | */ |
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) |
488 | 142 | { |
489 | 142 | int sentRegisterStop = 0; |
490 | 142 | const void *ip_hdr; |
491 | 142 | pim_sgaddr sg; |
492 | 142 | uint32_t *bits; |
493 | 142 | int i_am_rp = 0; |
494 | 142 | struct pim_interface *pim_ifp = ifp->info; |
495 | 142 | struct pim_instance *pim = pim_ifp->pim; |
496 | 142 | pim_addr rp_addr; |
497 | 142 | struct pim_rpf *rpg; |
498 | | |
499 | 142 | if (pim_ifp->pim_passive_enable) { |
500 | 0 | if (PIM_DEBUG_PIM_PACKETS) |
501 | 0 | zlog_debug( |
502 | 0 | "skip receiving PIM message on passive interface %s", |
503 | 0 | ifp->name); |
504 | 0 | return 0; |
505 | 0 | } |
506 | | |
507 | 201 | #define PIM_MSG_REGISTER_BIT_RESERVED_LEN 4 |
508 | | |
509 | 142 | if (tlv_buf_size |
510 | 142 | < (int)(PIM_MSG_REGISTER_BIT_RESERVED_LEN + sizeof(struct ip))) { |
511 | 83 | return 0; |
512 | 83 | } |
513 | 59 | ip_hdr = (tlv_buf + PIM_MSG_REGISTER_BIT_RESERVED_LEN); |
514 | | |
515 | 59 | if (!if_address_is_local(&dest_addr, PIM_AF, pim->vrf->vrf_id)) { |
516 | 41 | if (PIM_DEBUG_PIM_REG) |
517 | 0 | zlog_debug( |
518 | 41 | "%s: Received Register message for destination address: %pPA that I do not own", |
519 | 41 | __func__, &dest_addr); |
520 | 41 | return 0; |
521 | 41 | } |
522 | | |
523 | 18 | ++pim_ifp->pim_ifstat_reg_recv; |
524 | | |
525 | | /* |
526 | | * Please note this is not drawn to get the correct bit/data size |
527 | | * |
528 | | * The entirety of the REGISTER packet looks like this: |
529 | | * ------------------------------------------------------------- |
530 | | * | Ver | Type | Reserved | Checksum | |
531 | | * |-----------------------------------------------------------| |
532 | | * |B|N| Reserved 2 | |
533 | | * |-----------------------------------------------------------| |
534 | | * | Encap | IP HDR | |
535 | | * | Mcast | | |
536 | | * | Packet |--------------------------------------------------| |
537 | | * | | Mcast Data | |
538 | | * | | | |
539 | | * ... |
540 | | * |
541 | | * tlv_buf when received from the caller points at the B bit |
542 | | * We need to know the inner source and dest |
543 | | */ |
544 | 18 | bits = (uint32_t *)tlv_buf; |
545 | | |
546 | | /* |
547 | | * tlv_buf points to the start of the |B|N|... Reserved |
548 | | * Line above. So we need to add 4 bytes to get to the |
549 | | * start of the actual Encapsulated data. |
550 | | */ |
551 | 18 | memset(&sg, 0, sizeof(sg)); |
552 | 18 | sg = pim_sgaddr_from_iphdr(ip_hdr); |
553 | | |
554 | | #if PIM_IPV == 6 |
555 | | /* |
556 | | * According to RFC section 4.9.3, If Dummy PIM Header is included |
557 | | * in NULL Register as a payload there would be two PIM headers. |
558 | | * The inner PIM Header's checksum field should also be validated |
559 | | * in addition to the outer PIM Header's checksum. Validation of |
560 | | * inner PIM header checksum is done here. |
561 | | */ |
562 | | if ((*bits & PIM_REGISTER_NR_BIT) && |
563 | | ((tlv_buf_size - PIM_MSG_REGISTER_BIT_RESERVED_LEN) > |
564 | | (int)sizeof(struct ip6_hdr))) { |
565 | | uint16_t computed_checksum; |
566 | | uint16_t received_checksum; |
567 | | struct ipv6_ph ph; |
568 | | struct pim_msg_header *header; |
569 | | |
570 | | header = (struct pim_msg_header |
571 | | *)(tlv_buf + |
572 | | PIM_MSG_REGISTER_BIT_RESERVED_LEN + |
573 | | sizeof(struct ip6_hdr)); |
574 | | ph.src = sg.src; |
575 | | ph.dst = sg.grp; |
576 | | ph.ulpl = htonl(PIM_MSG_HEADER_LEN); |
577 | | ph.next_hdr = IPPROTO_PIM; |
578 | | |
579 | | received_checksum = header->checksum; |
580 | | |
581 | | header->checksum = 0; |
582 | | computed_checksum = in_cksum_with_ph6( |
583 | | &ph, header, htonl(PIM_MSG_HEADER_LEN)); |
584 | | |
585 | | if (computed_checksum != received_checksum) { |
586 | | if (PIM_DEBUG_PIM_PACKETS) |
587 | | zlog_debug( |
588 | | "Ignoring Null Register message%pSG from %pPA due to bad checksum in Encapsulated dummy PIM header", |
589 | | &sg, &src_addr); |
590 | | return 0; |
591 | | } |
592 | | } |
593 | | #endif |
594 | 18 | i_am_rp = I_am_RP(pim, sg.grp); |
595 | | |
596 | 18 | if (PIM_DEBUG_PIM_REG) |
597 | 0 | zlog_debug( |
598 | 18 | "Received Register message%pSG from %pPA on %s, rp: %d", |
599 | 18 | &sg, &src_addr, ifp->name, i_am_rp); |
600 | | |
601 | 18 | if (pim_is_grp_ssm(pim_ifp->pim, sg.grp)) { |
602 | 2 | if (pim_addr_is_any(sg.src)) { |
603 | 1 | zlog_warn( |
604 | 1 | "%s: Received Register message for Group(%pPA) is now in SSM, dropping the packet", |
605 | 1 | __func__, &sg.grp); |
606 | | /* Drop Packet Silently */ |
607 | 1 | return 0; |
608 | 1 | } |
609 | 2 | } |
610 | | |
611 | 17 | rpg = RP(pim, sg.grp); |
612 | 17 | if (!rpg) { |
613 | 11 | zlog_warn("%s: Received Register Message %pSG from %pPA on %s where the RP could not be looked up", |
614 | 11 | __func__, &sg, &src_addr, ifp->name); |
615 | 11 | return 0; |
616 | 11 | } |
617 | | |
618 | 6 | rp_addr = rpg->rpf_addr; |
619 | 6 | if (i_am_rp && (!pim_addr_cmp(dest_addr, rp_addr))) { |
620 | 0 | sentRegisterStop = 0; |
621 | |
|
622 | 0 | if (pim->register_plist) { |
623 | 0 | struct prefix_list *plist; |
624 | 0 | struct prefix src; |
625 | |
|
626 | 0 | plist = prefix_list_lookup(PIM_AFI, |
627 | 0 | pim->register_plist); |
628 | |
|
629 | 0 | pim_addr_to_prefix(&src, sg.src); |
630 | |
|
631 | 0 | if (prefix_list_apply_ext(plist, NULL, &src, true) == |
632 | 0 | PREFIX_DENY) { |
633 | 0 | pim_register_stop_send(ifp, &sg, dest_addr, |
634 | 0 | src_addr); |
635 | 0 | if (PIM_DEBUG_PIM_PACKETS) |
636 | 0 | zlog_debug( |
637 | 0 | "%s: Sending register-stop to %pPA for %pSG due to prefix-list denial, dropping packet", |
638 | 0 | __func__, &src_addr, &sg); |
639 | |
|
640 | 0 | return 0; |
641 | 0 | } |
642 | 0 | } |
643 | | |
644 | 0 | if (*bits & PIM_REGISTER_BORDER_BIT) { |
645 | 0 | if (PIM_DEBUG_PIM_PACKETS) |
646 | 0 | zlog_debug( |
647 | 0 | "%s: Received Register message with Border bit set, ignoring", |
648 | 0 | __func__); |
649 | | |
650 | | /* Drop Packet Silently */ |
651 | 0 | return 0; |
652 | 0 | } |
653 | | |
654 | 0 | struct pim_upstream *upstream = pim_upstream_find(pim, &sg); |
655 | | /* |
656 | | * If we don't have a place to send ignore the packet |
657 | | */ |
658 | 0 | if (!upstream) { |
659 | 0 | upstream = pim_upstream_add( |
660 | 0 | pim, &sg, ifp, |
661 | 0 | PIM_UPSTREAM_FLAG_MASK_SRC_STREAM, __func__, |
662 | 0 | NULL); |
663 | 0 | if (!upstream) { |
664 | 0 | zlog_warn("Failure to create upstream state"); |
665 | 0 | return 1; |
666 | 0 | } |
667 | | |
668 | 0 | upstream->upstream_register = src_addr; |
669 | 0 | } else { |
670 | | /* |
671 | | * If the FHR has set a very very fast register timer |
672 | | * there exists a possibility that the incoming NULL |
673 | | * register |
674 | | * is happening before we set the spt bit. If so |
675 | | * Do a quick check to update the counters and |
676 | | * then set the spt bit as appropriate |
677 | | */ |
678 | 0 | if (upstream->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) { |
679 | 0 | pim_mroute_update_counters( |
680 | 0 | upstream->channel_oil); |
681 | | /* |
682 | | * Have we seen packets? |
683 | | */ |
684 | 0 | if (upstream->channel_oil->cc.oldpktcnt |
685 | 0 | < upstream->channel_oil->cc.pktcnt) |
686 | 0 | pim_upstream_set_sptbit( |
687 | 0 | upstream, |
688 | 0 | upstream->rpf.source_nexthop |
689 | 0 | .interface); |
690 | 0 | } |
691 | 0 | } |
692 | | |
693 | 0 | if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) |
694 | 0 | || ((SwitchToSptDesiredOnRp(pim, &sg)) |
695 | 0 | && pim_upstream_inherited_olist(pim, upstream) == 0)) { |
696 | 0 | pim_register_stop_send(ifp, &sg, dest_addr, src_addr); |
697 | 0 | sentRegisterStop = 1; |
698 | 0 | } else { |
699 | 0 | if (PIM_DEBUG_PIM_REG) |
700 | 0 | zlog_debug("(%s) sptbit: %d", upstream->sg_str, |
701 | 0 | upstream->sptbit); |
702 | 0 | } |
703 | 0 | if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) |
704 | 0 | || (SwitchToSptDesiredOnRp(pim, &sg))) { |
705 | 0 | if (sentRegisterStop) { |
706 | 0 | pim_upstream_keep_alive_timer_start( |
707 | 0 | upstream, pim->rp_keep_alive_time); |
708 | 0 | } else { |
709 | 0 | pim_upstream_keep_alive_timer_start( |
710 | 0 | upstream, pim->keep_alive_time); |
711 | 0 | } |
712 | 0 | } |
713 | |
|
714 | 0 | if (!(upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) |
715 | 0 | && !(*bits & PIM_REGISTER_NR_BIT)) { |
716 | | // decapsulate and forward the iner packet to |
717 | | // inherited_olist(S,G,rpt) |
718 | | // This is taken care of by the kernel for us |
719 | 0 | } |
720 | 0 | pim_upstream_msdp_reg_timer_start(upstream); |
721 | 6 | } else { |
722 | 6 | if (PIM_DEBUG_PIM_REG) { |
723 | 0 | if (!i_am_rp) |
724 | 0 | zlog_debug("Received Register packet for %pSG, Rejecting packet because I am not the RP configured for group", |
725 | 0 | &sg); |
726 | 0 | else |
727 | 0 | zlog_debug("Received Register packet for %pSG, Rejecting packet because the dst ip address is not the actual RP", |
728 | 0 | &sg); |
729 | 0 | } |
730 | 6 | pim_register_stop_send(ifp, &sg, dest_addr, src_addr); |
731 | 6 | } |
732 | | |
733 | 6 | return 0; |
734 | 6 | } |
735 | | |
736 | | /* |
737 | | * This routine scan all upstream and update register state and remove pimreg |
738 | | * when couldreg becomes false. |
739 | | */ |
740 | | void pim_reg_del_on_couldreg_fail(struct interface *ifp) |
741 | 1 | { |
742 | 1 | struct pim_interface *pim_ifp = ifp->info; |
743 | 1 | struct pim_instance *pim; |
744 | 1 | struct pim_upstream *up; |
745 | | |
746 | 1 | if (!pim_ifp) |
747 | 0 | return; |
748 | | |
749 | 1 | pim = pim_ifp->pim; |
750 | | |
751 | 1 | frr_each (rb_pim_upstream, &pim->upstream_head, up) { |
752 | 0 | if (ifp != up->rpf.source_nexthop.interface) |
753 | 0 | continue; |
754 | | |
755 | 0 | if (!pim_upstream_could_register(up) |
756 | 0 | && (up->reg_state != PIM_REG_NOINFO)) { |
757 | 0 | pim_channel_del_oif(up->channel_oil, pim->regiface, |
758 | 0 | PIM_OIF_FLAG_PROTO_PIM, __func__); |
759 | 0 | EVENT_OFF(up->t_rs_timer); |
760 | 0 | up->reg_state = PIM_REG_NOINFO; |
761 | 0 | } |
762 | 0 | } |
763 | 1 | } |