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