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,
20 $QuaggaId: $Format:%an, %ai, %h$ $
34 #include "pim_iface.h"
35 #include "pim_hello.h"
36 #include "pim_ifchannel.h"
38 static void on_trace(const char *label,
39 struct interface *ifp, struct in_addr src)
41 if (PIM_DEBUG_PIM_TRACE) {
43 pim_inet4_dump("<src?>", src, src_str, sizeof(src_str));
44 zlog_debug("%s: from %s on %s",
45 label, src_str, ifp->name);
49 static void recv_join(struct interface *ifp,
50 struct pim_neighbor *neigh,
52 struct in_addr upstream,
54 struct in_addr source,
57 if (PIM_DEBUG_PIM_TRACE) {
62 pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
63 pim_inet4_dump("<src?>", source, src_str, sizeof(src_str));
64 pim_inet4_dump("<grp?>", group, grp_str, sizeof(grp_str));
65 pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, sizeof(neigh_str));
66 zlog_warn("%s: join (S,G)=(%s,%s) rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
69 source_flags & PIM_RPT_BIT_MASK,
70 source_flags & PIM_WILDCARD_BIT_MASK,
71 up_str, holdtime, neigh_str, ifp->name);
74 /* Restart join expiry timer */
75 pim_ifchannel_join_add(ifp, neigh->source_addr, upstream,
76 source, group, source_flags, holdtime);
79 static void recv_prune(struct interface *ifp,
80 struct pim_neighbor *neigh,
82 struct in_addr upstream,
84 struct in_addr source,
87 if (PIM_DEBUG_PIM_TRACE) {
92 pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
93 pim_inet4_dump("<src?>", source, src_str, sizeof(src_str));
94 pim_inet4_dump("<grp?>", group, grp_str, sizeof(grp_str));
95 pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, sizeof(neigh_str));
96 zlog_warn("%s: prune (S,G)=(%s,%s) rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
99 source_flags & PIM_RPT_BIT_MASK,
100 source_flags & PIM_WILDCARD_BIT_MASK,
101 up_str, holdtime, neigh_str, ifp->name);
104 pim_ifchannel_prune(ifp, upstream, source, group, source_flags, holdtime);
107 int pim_joinprune_recv(struct interface *ifp,
108 struct pim_neighbor *neigh,
109 struct in_addr src_addr,
110 uint8_t *tlv_buf, int tlv_buf_size)
112 struct prefix msg_upstream_addr;
113 uint8_t msg_num_groups;
114 uint16_t msg_holdtime;
121 on_trace(__PRETTY_FUNCTION__, ifp, src_addr);
124 pastend = tlv_buf + tlv_buf_size;
129 addr_offset = pim_parse_addr_ucast(ifp->name, src_addr,
133 zlog_warn("%s: pim_parse_addr_ucast addr_offset=%d",
137 if (addr_offset < 1) {
139 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
140 zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
148 Check upstream address family
150 if (msg_upstream_addr.family != AF_INET) {
151 if (PIM_DEBUG_PIM_TRACE) {
153 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
154 zlog_warn("%s: ignoring join/prune directed to unexpected addr family=%d from %s on %s",
156 msg_upstream_addr.family, src_str, ifp->name);
161 remain = pastend - buf;
164 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
165 zlog_warn("%s: short join/prune message buffer for group list: size=%d minimum=%d from %s on %s",
167 remain, 4, src_str, ifp->name);
171 ++buf; /* skip reserved byte */
172 msg_num_groups = *(const uint8_t *) buf;
174 msg_holdtime = ntohs(*(const uint16_t *) buf);
178 if (PIM_DEBUG_PIM_TRACE) {
180 char upstream_str[100];
181 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
182 pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4,
183 upstream_str, sizeof(upstream_str));
184 zlog_warn("%s: join/prune upstream=%s groups=%d holdtime=%d from %s on %s",
186 upstream_str, msg_num_groups, msg_holdtime,
191 for (group = 0; group < msg_num_groups; ++group) {
192 struct prefix msg_group_addr;
193 struct prefix msg_source_addr;
194 uint8_t msg_source_flags;
195 uint16_t msg_num_joined_sources;
196 uint16_t msg_num_pruned_sources;
199 addr_offset = pim_parse_addr_group(ifp->name, src_addr,
203 zlog_warn("%s: pim_parse_addr_group addr_offset=%d",
207 if (addr_offset < 1) {
212 remain = pastend - buf;
215 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
216 zlog_warn("%s: short join/prune buffer for source list: size=%d minimum=%d from %s on %s",
218 remain, 4, src_str, ifp->name);
222 msg_num_joined_sources = ntohs(*(const uint16_t *) buf);
224 msg_num_pruned_sources = ntohs(*(const uint16_t *) buf);
227 if (PIM_DEBUG_PIM_TRACE) {
229 char upstream_str[100];
231 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
232 pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4,
233 upstream_str, sizeof(upstream_str));
234 pim_inet4_dump("<grp?>", msg_group_addr.u.prefix4,
235 group_str, sizeof(group_str));
236 zlog_warn("%s: join/prune upstream=%s group=%s/%d join_src=%d prune_src=%d from %s on %s",
238 upstream_str, group_str, msg_group_addr.prefixlen,
239 msg_num_joined_sources, msg_num_pruned_sources,
243 /* Scan joined sources */
244 for (source = 0; source < msg_num_joined_sources; ++source) {
245 addr_offset = pim_parse_addr_source(ifp->name, src_addr,
250 zlog_warn("%s: pim_parse_addr_source addr_offset=%d",
254 if (addr_offset < 1) {
260 recv_join(ifp, neigh, msg_holdtime,
261 msg_upstream_addr.u.prefix4,
262 msg_group_addr.u.prefix4,
263 msg_source_addr.u.prefix4,
267 /* Scan pruned sources */
268 for (source = 0; source < msg_num_pruned_sources; ++source) {
269 addr_offset = pim_parse_addr_source(ifp->name, src_addr,
273 if (addr_offset < 1) {
279 recv_prune(ifp, neigh, msg_holdtime,
280 msg_upstream_addr.u.prefix4,
281 msg_group_addr.u.prefix4,
282 msg_source_addr.u.prefix4,
291 int pim_joinprune_send(struct interface *ifp,
292 struct in_addr upstream_addr,
293 struct in_addr source_addr,
294 struct in_addr group_addr,
297 struct pim_interface *pim_ifp;
298 uint8_t pim_msg[1000];
299 const uint8_t *pastend = pim_msg + sizeof(pim_msg);
300 uint8_t *pim_msg_curr = pim_msg + PIM_MSG_HEADER_LEN; /* room for pim header */
309 zlog_warn("%s: multicast not enabled on interface %s",
315 if (PIM_DEBUG_PIM_TRACE) {
316 char source_str[100];
319 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
320 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
321 pim_inet4_dump("<dst?>", upstream_addr, dst_str, sizeof(dst_str));
322 zlog_debug("%s: sending %s(S,G)=(%s,%s) to upstream=%s on interface %s",
324 send_join ? "Join" : "Prune",
325 source_str, group_str, dst_str, ifp->name);
328 if (PIM_INADDR_IS_ANY(upstream_addr)) {
329 if (PIM_DEBUG_PIM_TRACE) {
330 char source_str[100];
333 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
334 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
335 pim_inet4_dump("<dst?>", upstream_addr, dst_str, sizeof(dst_str));
336 zlog_debug("%s: %s(S,G)=(%s,%s): upstream=%s is myself on interface %s",
338 send_join ? "Join" : "Prune",
339 source_str, group_str, dst_str, ifp->name);
345 RFC 4601: 4.3.1. Sending Hello Messages
347 Thus, if a router needs to send a Join/Prune or Assert message on
348 an interface on which it has not yet sent a Hello message with the
349 currently configured IP address, then it MUST immediately send the
350 relevant Hello message without waiting for the Hello Timer to
351 expire, followed by the Join/Prune or Assert message.
353 pim_hello_require(ifp);
359 remain = pastend - pim_msg_curr;
360 pim_msg_curr = pim_msg_addr_encode_ipv4_ucast(pim_msg_curr,
365 pim_inet4_dump("<dst?>", upstream_addr, dst_str, sizeof(dst_str));
366 zlog_warn("%s: failure encoding destination address %s: space left=%d",
367 __PRETTY_FUNCTION__, dst_str, remain);
371 remain = pastend - pim_msg_curr;
373 zlog_warn("%s: group will not fit: space left=%d",
374 __PRETTY_FUNCTION__, remain);
378 *pim_msg_curr = 0; /* reserved */
380 *pim_msg_curr = 1; /* number of groups */
382 *((uint16_t *) pim_msg_curr) = htons(PIM_JP_HOLDTIME);
386 remain = pastend - pim_msg_curr;
387 pim_msg_curr = pim_msg_addr_encode_ipv4_group(pim_msg_curr,
392 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
393 zlog_warn("%s: failure encoding group address %s: space left=%d",
394 __PRETTY_FUNCTION__, group_str, remain);
398 remain = pastend - pim_msg_curr;
400 zlog_warn("%s: sources will not fit: space left=%d",
401 __PRETTY_FUNCTION__, remain);
405 /* number of joined sources */
406 *((uint16_t *) pim_msg_curr) = htons(send_join ? 1 : 0);
410 /* number of pruned sources */
411 *((uint16_t *) pim_msg_curr) = htons(send_join ? 0 : 1);
415 remain = pastend - pim_msg_curr;
416 pim_msg_curr = pim_msg_addr_encode_ipv4_source(pim_msg_curr,
420 char source_str[100];
421 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
422 zlog_warn("%s: failure encoding source address %s: space left=%d",
423 __PRETTY_FUNCTION__, source_str, remain);
429 pim_msg_size = pim_msg_curr - pim_msg;
431 pim_msg_build_header(pim_msg, pim_msg_size,
432 PIM_MSG_TYPE_JOIN_PRUNE);
434 if (pim_msg_send(pim_ifp->pim_sock_fd,
435 qpim_all_pim_routers_addr,
439 zlog_warn("%s: could not send PIM message on interface %s",
440 __PRETTY_FUNCTION__, ifp->name);