3 Copyright (C) 2008 Everton da Silva Marques
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.
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.
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,
33 #include "pim_iface.h"
34 #include "pim_hello.h"
35 #include "pim_ifchannel.h"
37 static void on_trace(const char *label
,
38 struct interface
*ifp
, struct in_addr src
)
40 if (PIM_DEBUG_PIM_TRACE
) {
42 pim_inet4_dump("<src?>", src
, src_str
, sizeof(src_str
));
43 zlog_debug("%s: from %s on %s",
44 label
, src_str
, ifp
->name
);
48 static void recv_join(struct interface
*ifp
,
49 struct pim_neighbor
*neigh
,
51 struct in_addr upstream
,
53 struct in_addr source
,
56 if (PIM_DEBUG_PIM_TRACE
) {
61 pim_inet4_dump("<upstream?>", upstream
, up_str
, sizeof(up_str
));
62 pim_inet4_dump("<src?>", source
, src_str
, sizeof(src_str
));
63 pim_inet4_dump("<grp?>", group
, grp_str
, sizeof(grp_str
));
64 pim_inet4_dump("<neigh?>", neigh
->source_addr
, neigh_str
, sizeof(neigh_str
));
65 zlog_warn("%s: join (S,G)=(%s,%s) rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
68 source_flags
& PIM_RPT_BIT_MASK
,
69 source_flags
& PIM_WILDCARD_BIT_MASK
,
70 up_str
, holdtime
, neigh_str
, ifp
->name
);
73 /* Restart join expiry timer */
74 pim_ifchannel_join_add(ifp
, neigh
->source_addr
, upstream
,
75 source
, group
, source_flags
, holdtime
);
78 static void recv_prune(struct interface
*ifp
,
79 struct pim_neighbor
*neigh
,
81 struct in_addr upstream
,
83 struct in_addr source
,
86 if (PIM_DEBUG_PIM_TRACE
) {
91 pim_inet4_dump("<upstream?>", upstream
, up_str
, sizeof(up_str
));
92 pim_inet4_dump("<src?>", source
, src_str
, sizeof(src_str
));
93 pim_inet4_dump("<grp?>", group
, grp_str
, sizeof(grp_str
));
94 pim_inet4_dump("<neigh?>", neigh
->source_addr
, neigh_str
, sizeof(neigh_str
));
95 zlog_warn("%s: prune (S,G)=(%s,%s) rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
98 source_flags
& PIM_RPT_BIT_MASK
,
99 source_flags
& PIM_WILDCARD_BIT_MASK
,
100 up_str
, holdtime
, neigh_str
, ifp
->name
);
103 pim_ifchannel_prune(ifp
, upstream
, source
, group
, source_flags
, holdtime
);
106 int pim_joinprune_recv(struct interface
*ifp
,
107 struct pim_neighbor
*neigh
,
108 struct in_addr src_addr
,
109 uint8_t *tlv_buf
, int tlv_buf_size
)
111 struct prefix msg_upstream_addr
;
112 uint8_t msg_num_groups
;
113 uint16_t msg_holdtime
;
120 on_trace(__PRETTY_FUNCTION__
, ifp
, src_addr
);
123 pastend
= tlv_buf
+ tlv_buf_size
;
128 addr_offset
= pim_parse_addr_ucast (&msg_upstream_addr
,
130 if (addr_offset
< 1) {
132 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
133 zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
141 Check upstream address family
143 if (msg_upstream_addr
.family
!= AF_INET
) {
144 if (PIM_DEBUG_PIM_TRACE
) {
146 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
147 zlog_warn("%s: ignoring join/prune directed to unexpected addr family=%d from %s on %s",
149 msg_upstream_addr
.family
, src_str
, ifp
->name
);
154 remain
= pastend
- buf
;
157 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
158 zlog_warn("%s: short join/prune message buffer for group list: size=%d minimum=%d from %s on %s",
160 remain
, 4, src_str
, ifp
->name
);
164 ++buf
; /* skip reserved byte */
165 msg_num_groups
= *(const uint8_t *) buf
;
167 msg_holdtime
= ntohs(*(const uint16_t *) buf
);
171 if (PIM_DEBUG_PIM_TRACE
) {
173 char upstream_str
[100];
174 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
175 pim_inet4_dump("<addr?>", msg_upstream_addr
.u
.prefix4
,
176 upstream_str
, sizeof(upstream_str
));
177 zlog_warn("%s: join/prune upstream=%s groups=%d holdtime=%d from %s on %s",
179 upstream_str
, msg_num_groups
, msg_holdtime
,
184 for (group
= 0; group
< msg_num_groups
; ++group
) {
185 struct prefix msg_group_addr
;
186 struct prefix msg_source_addr
;
187 uint8_t msg_source_flags
;
188 uint16_t msg_num_joined_sources
;
189 uint16_t msg_num_pruned_sources
;
192 addr_offset
= pim_parse_addr_group (&msg_group_addr
,
194 if (addr_offset
< 1) {
199 remain
= pastend
- buf
;
202 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
203 zlog_warn("%s: short join/prune buffer for source list: size=%d minimum=%d from %s on %s",
205 remain
, 4, src_str
, ifp
->name
);
209 msg_num_joined_sources
= ntohs(*(const uint16_t *) buf
);
211 msg_num_pruned_sources
= ntohs(*(const uint16_t *) buf
);
214 if (PIM_DEBUG_PIM_TRACE
) {
216 char upstream_str
[100];
218 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
219 pim_inet4_dump("<addr?>", msg_upstream_addr
.u
.prefix4
,
220 upstream_str
, sizeof(upstream_str
));
221 pim_inet4_dump("<grp?>", msg_group_addr
.u
.prefix4
,
222 group_str
, sizeof(group_str
));
223 zlog_warn("%s: join/prune upstream=%s group=%s/%d join_src=%d prune_src=%d from %s on %s",
225 upstream_str
, group_str
, msg_group_addr
.prefixlen
,
226 msg_num_joined_sources
, msg_num_pruned_sources
,
230 /* Scan joined sources */
231 for (source
= 0; source
< msg_num_joined_sources
; ++source
) {
232 addr_offset
= pim_parse_addr_source (&msg_source_addr
,
235 if (addr_offset
< 1) {
241 recv_join(ifp
, neigh
, msg_holdtime
,
242 msg_upstream_addr
.u
.prefix4
,
243 msg_group_addr
.u
.prefix4
,
244 msg_source_addr
.u
.prefix4
,
248 /* Scan pruned sources */
249 for (source
= 0; source
< msg_num_pruned_sources
; ++source
) {
250 addr_offset
= pim_parse_addr_source (&msg_source_addr
,
253 if (addr_offset
< 1) {
259 recv_prune(ifp
, neigh
, msg_holdtime
,
260 msg_upstream_addr
.u
.prefix4
,
261 msg_group_addr
.u
.prefix4
,
262 msg_source_addr
.u
.prefix4
,
271 int pim_joinprune_send(struct interface
*ifp
,
272 struct in_addr upstream_addr
,
273 struct in_addr source_addr
,
274 struct in_addr group_addr
,
277 struct pim_interface
*pim_ifp
;
278 uint8_t pim_msg
[1000];
279 const uint8_t *pastend
= pim_msg
+ sizeof(pim_msg
);
280 uint8_t *pim_msg_curr
= pim_msg
+ PIM_MSG_HEADER_LEN
; /* room for pim header */
289 zlog_warn("%s: multicast not enabled on interface %s",
295 if (PIM_DEBUG_PIM_TRACE
) {
296 char source_str
[100];
299 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
300 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
301 pim_inet4_dump("<dst?>", upstream_addr
, dst_str
, sizeof(dst_str
));
302 zlog_debug("%s: sending %s(S,G)=(%s,%s) to upstream=%s on interface %s",
304 send_join
? "Join" : "Prune",
305 source_str
, group_str
, dst_str
, ifp
->name
);
308 if (PIM_INADDR_IS_ANY(upstream_addr
)) {
309 if (PIM_DEBUG_PIM_TRACE
) {
310 char source_str
[100];
313 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
314 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
315 pim_inet4_dump("<dst?>", upstream_addr
, dst_str
, sizeof(dst_str
));
316 zlog_debug("%s: %s(S,G)=(%s,%s): upstream=%s is myself on interface %s",
318 send_join
? "Join" : "Prune",
319 source_str
, group_str
, dst_str
, ifp
->name
);
325 RFC 4601: 4.3.1. Sending Hello Messages
327 Thus, if a router needs to send a Join/Prune or Assert message on
328 an interface on which it has not yet sent a Hello message with the
329 currently configured IP address, then it MUST immediately send the
330 relevant Hello message without waiting for the Hello Timer to
331 expire, followed by the Join/Prune or Assert message.
333 pim_hello_require(ifp
);
339 remain
= pastend
- pim_msg_curr
;
340 pim_msg_curr
= pim_msg_addr_encode_ipv4_ucast(pim_msg_curr
,
345 pim_inet4_dump("<dst?>", upstream_addr
, dst_str
, sizeof(dst_str
));
346 zlog_warn("%s: failure encoding destination address %s: space left=%d",
347 __PRETTY_FUNCTION__
, dst_str
, remain
);
351 remain
= pastend
- pim_msg_curr
;
353 zlog_warn("%s: group will not fit: space left=%d",
354 __PRETTY_FUNCTION__
, remain
);
358 *pim_msg_curr
= 0; /* reserved */
360 *pim_msg_curr
= 1; /* number of groups */
362 *((uint16_t *) pim_msg_curr
) = htons(PIM_JP_HOLDTIME
);
366 remain
= pastend
- pim_msg_curr
;
367 pim_msg_curr
= pim_msg_addr_encode_ipv4_group(pim_msg_curr
,
372 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
373 zlog_warn("%s: failure encoding group address %s: space left=%d",
374 __PRETTY_FUNCTION__
, group_str
, remain
);
378 remain
= pastend
- pim_msg_curr
;
380 zlog_warn("%s: sources will not fit: space left=%d",
381 __PRETTY_FUNCTION__
, remain
);
385 /* number of joined sources */
386 *((uint16_t *) pim_msg_curr
) = htons(send_join
? 1 : 0);
390 /* number of pruned sources */
391 *((uint16_t *) pim_msg_curr
) = htons(send_join
? 0 : 1);
395 remain
= pastend
- pim_msg_curr
;
396 pim_msg_curr
= pim_msg_addr_encode_ipv4_source(pim_msg_curr
,
400 char source_str
[100];
401 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
402 zlog_warn("%s: failure encoding source address %s: space left=%d",
403 __PRETTY_FUNCTION__
, source_str
, remain
);
409 pim_msg_size
= pim_msg_curr
- pim_msg
;
411 pim_msg_build_header(pim_msg
, pim_msg_size
,
412 PIM_MSG_TYPE_JOIN_PRUNE
);
414 if (pim_msg_send(pim_ifp
->pim_sock_fd
,
415 qpim_all_pim_routers_addr
,
419 zlog_warn("%s: could not send PIM message on interface %s",
420 __PRETTY_FUNCTION__
, ifp
->name
);