]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_join.c
Merge pull request #478 from opensourcerouting/test-extension
[mirror_frr.git] / pimd / pim_join.c
1 /*
2 PIM for Quagga
3 Copyright (C) 2008 Everton da Silva Marques
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; see the file COPYING; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
18 MA 02110-1301 USA
19 */
20
21 #include <zebra.h>
22
23 #include "log.h"
24 #include "prefix.h"
25 #include "if.h"
26 #include "vty.h"
27 #include "plist.h"
28
29 #include "pimd.h"
30 #include "pim_str.h"
31 #include "pim_tlv.h"
32 #include "pim_msg.h"
33 #include "pim_pim.h"
34 #include "pim_join.h"
35 #include "pim_oil.h"
36 #include "pim_iface.h"
37 #include "pim_hello.h"
38 #include "pim_ifchannel.h"
39 #include "pim_rpf.h"
40 #include "pim_rp.h"
41 #include "pim_jp_agg.h"
42
43 static void
44 on_trace (const char *label,
45 struct interface *ifp, struct in_addr src)
46 {
47 if (PIM_DEBUG_PIM_TRACE) {
48 char src_str[INET_ADDRSTRLEN];
49 pim_inet4_dump("<src?>", src, src_str, sizeof(src_str));
50 zlog_debug("%s: from %s on %s",
51 label, src_str, ifp->name);
52 }
53 }
54
55 static void recv_join(struct interface *ifp,
56 struct pim_neighbor *neigh,
57 uint16_t holdtime,
58 struct in_addr upstream,
59 struct prefix_sg *sg,
60 uint8_t source_flags)
61 {
62 struct pim_interface *pim_ifp = NULL;
63
64 if (PIM_DEBUG_PIM_TRACE) {
65 char up_str[INET_ADDRSTRLEN];
66 char neigh_str[INET_ADDRSTRLEN];
67 pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
68 pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, sizeof(neigh_str));
69 zlog_warn("%s: join (S,G)=%s rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
70 __PRETTY_FUNCTION__,
71 pim_str_sg_dump (sg),
72 source_flags & PIM_RPT_BIT_MASK,
73 source_flags & PIM_WILDCARD_BIT_MASK,
74 up_str, holdtime, neigh_str, ifp->name);
75 }
76
77 pim_ifp = ifp->info;
78 zassert(pim_ifp);
79
80 ++pim_ifp->pim_ifstat_join_recv;
81
82 /*
83 * If the RPT and WC are set it's a (*,G)
84 * and the source is the RP
85 */
86 if ((source_flags & PIM_RPT_BIT_MASK) &&
87 (source_flags & PIM_WILDCARD_BIT_MASK))
88 {
89 struct pim_rpf *rp = RP (sg->grp);
90
91 /*
92 * If the RP sent in the message is not
93 * our RP for the group, drop the message
94 */
95 if (sg->src.s_addr != rp->rpf_addr.u.prefix4.s_addr)
96 return;
97
98 sg->src.s_addr = INADDR_ANY;
99 }
100
101 /* Restart join expiry timer */
102 pim_ifchannel_join_add(ifp, neigh->source_addr, upstream,
103 sg, source_flags, holdtime);
104
105 }
106
107 static void recv_prune(struct interface *ifp,
108 struct pim_neighbor *neigh,
109 uint16_t holdtime,
110 struct in_addr upstream,
111 struct prefix_sg *sg,
112 uint8_t source_flags)
113 {
114 struct pim_interface *pim_ifp = NULL;
115
116 if (PIM_DEBUG_PIM_TRACE) {
117 char up_str[INET_ADDRSTRLEN];
118 char neigh_str[INET_ADDRSTRLEN];
119 pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
120 pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, sizeof(neigh_str));
121 zlog_warn("%s: prune (S,G)=%s rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
122 __PRETTY_FUNCTION__,
123 pim_str_sg_dump (sg),
124 source_flags & PIM_RPT_BIT_MASK,
125 source_flags & PIM_WILDCARD_BIT_MASK,
126 up_str, holdtime, neigh_str, ifp->name);
127 }
128
129 pim_ifp = ifp->info;
130 zassert(pim_ifp);
131
132 ++pim_ifp->pim_ifstat_prune_recv;
133
134 if ((source_flags & PIM_RPT_BIT_MASK) &&
135 (source_flags & PIM_WILDCARD_BIT_MASK))
136 {
137 struct pim_rpf *rp = RP (sg->grp);
138
139 // Ignoring Prune *,G's at the moment.
140 if (sg->src.s_addr != rp->rpf_addr.u.prefix4.s_addr)
141 return;
142
143 sg->src.s_addr = INADDR_ANY;
144 }
145
146 pim_ifchannel_prune(ifp, upstream, sg, source_flags, holdtime);
147
148 }
149
150 int pim_joinprune_recv(struct interface *ifp,
151 struct pim_neighbor *neigh,
152 struct in_addr src_addr,
153 uint8_t *tlv_buf, int tlv_buf_size)
154 {
155 struct prefix msg_upstream_addr;
156 uint8_t msg_num_groups;
157 uint16_t msg_holdtime;
158 int addr_offset;
159 uint8_t *buf;
160 uint8_t *pastend;
161 int remain;
162 int group;
163
164 buf = tlv_buf;
165 pastend = tlv_buf + tlv_buf_size;
166
167 /*
168 Parse ucast addr
169 */
170 addr_offset = pim_parse_addr_ucast (&msg_upstream_addr,
171 buf, pastend - buf);
172 if (addr_offset < 1) {
173 char src_str[INET_ADDRSTRLEN];
174 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
175 zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
176 __PRETTY_FUNCTION__,
177 src_str, ifp->name);
178 return -1;
179 }
180 buf += addr_offset;
181
182 /*
183 Check upstream address family
184 */
185 if (msg_upstream_addr.family != AF_INET) {
186 if (PIM_DEBUG_PIM_J_P) {
187 char src_str[INET_ADDRSTRLEN];
188 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
189 zlog_warn("%s: ignoring join/prune directed to unexpected addr family=%d from %s on %s",
190 __PRETTY_FUNCTION__,
191 msg_upstream_addr.family, src_str, ifp->name);
192 }
193 return -2;
194 }
195
196 remain = pastend - buf;
197 if (remain < 4) {
198 char src_str[INET_ADDRSTRLEN];
199 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
200 zlog_warn("%s: short join/prune message buffer for group list: size=%d minimum=%d from %s on %s",
201 __PRETTY_FUNCTION__,
202 remain, 4, src_str, ifp->name);
203 return -4;
204 }
205
206 ++buf; /* skip reserved byte */
207 msg_num_groups = *(const uint8_t *) buf;
208 ++buf;
209 msg_holdtime = ntohs(*(const uint16_t *) buf);
210 ++buf;
211 ++buf;
212
213 if (PIM_DEBUG_PIM_J_P) {
214 char src_str[INET_ADDRSTRLEN];
215 char upstream_str[INET_ADDRSTRLEN];
216 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
217 pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4,
218 upstream_str, sizeof(upstream_str));
219 zlog_debug ("%s: join/prune upstream=%s groups=%d holdtime=%d from %s on %s",
220 __PRETTY_FUNCTION__,
221 upstream_str, msg_num_groups, msg_holdtime,
222 src_str, ifp->name);
223 }
224
225 /* Scan groups */
226 for (group = 0; group < msg_num_groups; ++group) {
227 struct prefix_sg sg;
228 uint8_t msg_source_flags;
229 uint16_t msg_num_joined_sources;
230 uint16_t msg_num_pruned_sources;
231 int source;
232 struct pim_ifchannel *ch = NULL;
233
234 memset (&sg, 0, sizeof (struct prefix_sg));
235 addr_offset = pim_parse_addr_group (&sg,
236 buf, pastend - buf);
237 if (addr_offset < 1) {
238 return -5;
239 }
240 buf += addr_offset;
241
242 remain = pastend - buf;
243 if (remain < 4) {
244 char src_str[INET_ADDRSTRLEN];
245 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
246 zlog_warn("%s: short join/prune buffer for source list: size=%d minimum=%d from %s on %s",
247 __PRETTY_FUNCTION__,
248 remain, 4, src_str, ifp->name);
249 return -6;
250 }
251
252 msg_num_joined_sources = ntohs(*(const uint16_t *) buf);
253 buf += 2;
254 msg_num_pruned_sources = ntohs(*(const uint16_t *) buf);
255 buf += 2;
256
257 if (PIM_DEBUG_PIM_J_P) {
258 char src_str[INET_ADDRSTRLEN];
259 char upstream_str[INET_ADDRSTRLEN];
260 char group_str[INET_ADDRSTRLEN];
261 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
262 pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4,
263 upstream_str, sizeof(upstream_str));
264 pim_inet4_dump("<grp?>", sg.grp,
265 group_str, sizeof(group_str));
266 zlog_warn("%s: join/prune upstream=%s group=%s/32 join_src=%d prune_src=%d from %s on %s",
267 __PRETTY_FUNCTION__,
268 upstream_str, group_str,
269 msg_num_joined_sources, msg_num_pruned_sources,
270 src_str, ifp->name);
271 }
272
273 /* Scan joined sources */
274 for (source = 0; source < msg_num_joined_sources; ++source) {
275 addr_offset = pim_parse_addr_source (&sg,
276 &msg_source_flags,
277 buf, pastend - buf);
278 if (addr_offset < 1) {
279 return -7;
280 }
281
282 buf += addr_offset;
283
284 recv_join(ifp, neigh, msg_holdtime,
285 msg_upstream_addr.u.prefix4,
286 &sg,
287 msg_source_flags);
288
289 if (sg.src.s_addr == INADDR_ANY)
290 {
291 ch = pim_ifchannel_find (ifp, &sg);
292 if (ch)
293 pim_ifchannel_set_star_g_join_state (ch, 0, msg_source_flags, 1);
294 }
295 }
296
297 /* Scan pruned sources */
298 for (source = 0; source < msg_num_pruned_sources; ++source) {
299 addr_offset = pim_parse_addr_source (&sg,
300 &msg_source_flags,
301 buf, pastend - buf);
302 if (addr_offset < 1) {
303 return -8;
304 }
305
306 buf += addr_offset;
307
308 recv_prune(ifp, neigh, msg_holdtime,
309 msg_upstream_addr.u.prefix4,
310 &sg,
311 msg_source_flags);
312 }
313 if (ch)
314 pim_ifchannel_set_star_g_join_state (ch, 1, msg_source_flags, 0);
315 ch = NULL;
316 } /* scan groups */
317
318 return 0;
319 }
320
321 /*
322 * J/P Message Format
323 *
324 * While the RFC clearly states that this is 32 bits wide, it
325 * is cheating. These fields:
326 * Encoded-Unicast format (6 bytes MIN)
327 * Encoded-Group format (8 bytes MIN)
328 * Encoded-Source format (8 bytes MIN)
329 * are *not* 32 bits wide.
330 *
331 * Nor does the RFC explicitly call out the size for:
332 * Reserved (1 byte)
333 * Num Groups (1 byte)
334 * Holdtime (2 bytes)
335 * Number of Joined Sources (2 bytes)
336 * Number of Pruned Sources (2 bytes)
337 *
338 * This leads to a missleading representation from casual
339 * reading and making assumptions. Be careful!
340 *
341 * 0 1 2 3
342 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
343 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
344 * |PIM Ver| Type | Reserved | Checksum |
345 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
346 * | Upstream Neighbor Address (Encoded-Unicast format) |
347 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
348 * | Reserved | Num groups | Holdtime |
349 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
350 * | Multicast Group Address 1 (Encoded-Group format) |
351 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
352 * | Number of Joined Sources | Number of Pruned Sources |
353 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
354 * | Joined Source Address 1 (Encoded-Source format) |
355 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
356 * | . |
357 * | . |
358 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
359 * | Joined Source Address n (Encoded-Source format) |
360 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
361 * | Pruned Source Address 1 (Encoded-Source format) |
362 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
363 * | . |
364 * | . |
365 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
366 * | Pruned Source Address n (Encoded-Source format) |
367 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
368 * | Multicast Group Address m (Encoded-Group format) |
369 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
370 * | Number of Joined Sources | Number of Pruned Sources |
371 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
372 * | Joined Source Address 1 (Encoded-Source format) |
373 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
374 * | . |
375 * | . |
376 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
377 * | Joined Source Address n (Encoded-Source format) |
378 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
379 * | Pruned Source Address 1 (Encoded-Source format) |
380 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
381 * | . |
382 * | . |
383 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
384 * | Pruned Source Address n (Encoded-Source format) |
385 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
386 */
387 int pim_joinprune_send(struct pim_rpf *rpf,
388 struct list *groups)
389 {
390 struct pim_jp_agg_group *group;
391 struct pim_interface *pim_ifp = NULL;
392 struct pim_jp_groups *grp = NULL;
393 struct pim_jp *msg;
394 struct listnode *node, *nnode;
395 uint8_t pim_msg[10000];
396 uint8_t *curr_ptr = pim_msg;
397 bool new_packet = true;
398 size_t packet_left = 0;
399 size_t packet_size = 0;
400 size_t group_size = 0;
401
402 on_trace (__PRETTY_FUNCTION__, rpf->source_nexthop.interface, rpf->rpf_addr.u.prefix4);
403
404 if (rpf->source_nexthop.interface)
405 pim_ifp = rpf->source_nexthop.interface->info;
406 else
407 {
408 zlog_warn ("%s: RPF interface is not present", __PRETTY_FUNCTION__);
409 return -1;
410 }
411
412 if (!pim_ifp)
413 {
414 zlog_warn ("%s: multicast not enabled on interface %s",
415 __PRETTY_FUNCTION__,
416 rpf->source_nexthop.interface->name);
417 return -1;
418 }
419
420 if (PIM_INADDR_IS_ANY(rpf->rpf_addr.u.prefix4))
421 {
422 if (PIM_DEBUG_PIM_J_P) {
423 char dst_str[INET_ADDRSTRLEN];
424 pim_inet4_dump("<dst?>", rpf->rpf_addr.u.prefix4, dst_str, sizeof(dst_str));
425 zlog_debug("%s: upstream=%s is myself on interface %s",
426 __PRETTY_FUNCTION__,
427 dst_str, rpf->source_nexthop.interface->name);
428 }
429 return 0;
430 }
431
432 /*
433 RFC 4601: 4.3.1. Sending Hello Messages
434
435 Thus, if a router needs to send a Join/Prune or Assert message on
436 an interface on which it has not yet sent a Hello message with the
437 currently configured IP address, then it MUST immediately send the
438 relevant Hello message without waiting for the Hello Timer to
439 expire, followed by the Join/Prune or Assert message.
440 */
441 pim_hello_require(rpf->source_nexthop.interface);
442
443 for (ALL_LIST_ELEMENTS(groups, node, nnode, group))
444 {
445 if (new_packet)
446 {
447 msg = (struct pim_jp *)pim_msg;
448
449 memset(msg, 0, sizeof (*msg));
450
451 pim_msg_addr_encode_ipv4_ucast ((uint8_t *)&msg->addr, rpf->rpf_addr.u.prefix4);
452 msg->reserved = 0;
453 msg->holdtime = htons(PIM_JP_HOLDTIME);
454
455 new_packet = false;
456
457 grp = &msg->groups[0];
458 curr_ptr = (uint8_t *)grp;
459 packet_size = sizeof (struct pim_msg_header);
460 packet_size += sizeof (struct pim_encoded_ipv4_unicast);
461 packet_size += 4; // reserved (1) + groups (1) + holdtime (2)
462
463 packet_left = rpf->source_nexthop.interface->mtu - 24;
464 packet_left -= packet_size;
465 }
466 if (PIM_DEBUG_PIM_J_P) {
467 char dst_str[INET_ADDRSTRLEN];
468 char grp_str[INET_ADDRSTRLEN];
469 pim_inet4_dump("<dst?>", rpf->rpf_addr.u.prefix4, dst_str, sizeof(dst_str));
470 pim_inet4_dump("<grp?>", group->group, grp_str, sizeof(grp_str));
471 zlog_debug("%s: sending (G)=%s to upstream=%s on interface %s",
472 __PRETTY_FUNCTION__,
473 grp_str, dst_str, rpf->source_nexthop.interface->name);
474 }
475
476 group_size = pim_msg_get_jp_group_size (group->sources);
477 if (group_size > packet_left)
478 {
479 pim_msg_build_header (pim_msg, packet_size, PIM_MSG_TYPE_JOIN_PRUNE);
480 if (pim_msg_send(pim_ifp->pim_sock_fd,
481 pim_ifp->primary_address,
482 qpim_all_pim_routers_addr,
483 pim_msg,
484 packet_size,
485 rpf->source_nexthop.interface->name)) {
486 zlog_warn("%s: could not send PIM message on interface %s",
487 __PRETTY_FUNCTION__, rpf->source_nexthop.interface->name);
488 }
489
490 msg = (struct pim_jp *)pim_msg;
491 memset(msg, 0, sizeof (*msg));
492
493 pim_msg_addr_encode_ipv4_ucast ((uint8_t *)&msg->addr, rpf->rpf_addr.u.prefix4);
494 msg->reserved = 0;
495 msg->holdtime = htons(PIM_JP_HOLDTIME);
496
497 new_packet = false;
498
499 grp = &msg->groups[0];
500 curr_ptr = (uint8_t *)grp;
501 packet_size = sizeof (struct pim_msg_header);
502 packet_size += sizeof (struct pim_encoded_ipv4_unicast);
503 packet_size += 4; // reserved (1) + groups (1) + holdtime (2)
504
505 packet_left = rpf->source_nexthop.interface->mtu - 24;
506 packet_left -= packet_size;
507 }
508
509 msg->num_groups++;
510 /*
511 Build PIM message
512 */
513
514 curr_ptr += group_size;
515 packet_left -= group_size;
516 packet_size += group_size;
517 pim_msg_build_jp_groups (grp, group, group_size);
518
519 pim_ifp->pim_ifstat_join_send += ntohs(grp->joins);
520 pim_ifp->pim_ifstat_prune_send += ntohs(grp->prunes);
521
522 grp = (struct pim_jp_groups *)curr_ptr;
523 if (packet_left < sizeof (struct pim_jp_groups) || msg->num_groups == 255)
524 {
525 pim_msg_build_header (pim_msg, packet_size, PIM_MSG_TYPE_JOIN_PRUNE);
526 if (pim_msg_send(pim_ifp->pim_sock_fd,
527 pim_ifp->primary_address,
528 qpim_all_pim_routers_addr,
529 pim_msg,
530 packet_size,
531 rpf->source_nexthop.interface->name)) {
532 zlog_warn("%s: could not send PIM message on interface %s",
533 __PRETTY_FUNCTION__, rpf->source_nexthop.interface->name);
534 }
535
536 new_packet = true;
537 }
538 }
539
540
541 if (!new_packet)
542 {
543 //msg->num_groups = htons (msg->num_groups);
544 pim_msg_build_header (pim_msg, packet_size, PIM_MSG_TYPE_JOIN_PRUNE);
545 if (pim_msg_send(pim_ifp->pim_sock_fd,
546 pim_ifp->primary_address,
547 qpim_all_pim_routers_addr,
548 pim_msg,
549 packet_size,
550 rpf->source_nexthop.interface->name)) {
551 zlog_warn("%s: could not send PIM message on interface %s",
552 __PRETTY_FUNCTION__, rpf->source_nexthop.interface->name);
553 }
554 }
555 return 0;
556 }