]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_join.c
pimd: Track oil list totals a bit better.
[mirror_frr.git] / pimd / pim_join.c
CommitLineData
12e41d03
DL
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
12e41d03
DL
19*/
20
21#include <zebra.h>
22
23#include "log.h"
24#include "prefix.h"
744d91b3 25#include "if.h"
dfe43e25
DW
26#include "vty.h"
27#include "plist.h"
12e41d03
DL
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"
3667b0bc 35#include "pim_oil.h"
12e41d03
DL
36#include "pim_iface.h"
37#include "pim_hello.h"
38#include "pim_ifchannel.h"
6c629103
DS
39#include "pim_rpf.h"
40#include "pim_rp.h"
12e41d03 41
4950938e
DS
42static void
43on_trace (const char *label,
44 struct interface *ifp, struct in_addr src)
12e41d03
DL
45{
46 if (PIM_DEBUG_PIM_TRACE) {
eaa54bdb 47 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
48 pim_inet4_dump("<src?>", src, src_str, sizeof(src_str));
49 zlog_debug("%s: from %s on %s",
50 label, src_str, ifp->name);
51 }
52}
53
54static void recv_join(struct interface *ifp,
55 struct pim_neighbor *neigh,
56 uint16_t holdtime,
57 struct in_addr upstream,
cf4ea1c4 58 struct prefix_sg *sg,
12e41d03
DL
59 uint8_t source_flags)
60{
61 if (PIM_DEBUG_PIM_TRACE) {
eaa54bdb
DW
62 char up_str[INET_ADDRSTRLEN];
63 char neigh_str[INET_ADDRSTRLEN];
12e41d03 64 pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
12e41d03 65 pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, sizeof(neigh_str));
ee1a477a 66 zlog_warn("%s: join (S,G)=%s rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
12e41d03 67 __PRETTY_FUNCTION__,
cf4ea1c4 68 pim_str_sg_dump (sg),
12e41d03
DL
69 source_flags & PIM_RPT_BIT_MASK,
70 source_flags & PIM_WILDCARD_BIT_MASK,
71 up_str, holdtime, neigh_str, ifp->name);
72 }
346cffe3
DS
73
74 /*
75 * If the RPT and WC are set it's a (*,G)
76 * and the source is the RP
77 */
78 if ((source_flags & PIM_RPT_BIT_MASK) &&
79 (source_flags & PIM_WILDCARD_BIT_MASK))
80 {
cf4ea1c4 81 struct pim_rpf *rp = RP (sg->grp);
346cffe3
DS
82
83 /*
84 * If the RP sent in the message is not
85 * our RP for the group, drop the message
86 */
cf4ea1c4 87 if (sg->src.s_addr != rp->rpf_addr.u.prefix4.s_addr)
346cffe3
DS
88 return;
89
cf4ea1c4 90 sg->src.s_addr = INADDR_ANY;
346cffe3
DS
91 }
92
12e41d03
DL
93 /* Restart join expiry timer */
94 pim_ifchannel_join_add(ifp, neigh->source_addr, upstream,
cf4ea1c4 95 sg, source_flags, holdtime);
6c629103 96
12e41d03
DL
97}
98
99static void recv_prune(struct interface *ifp,
100 struct pim_neighbor *neigh,
101 uint16_t holdtime,
102 struct in_addr upstream,
cf4ea1c4 103 struct prefix_sg *sg,
12e41d03
DL
104 uint8_t source_flags)
105{
106 if (PIM_DEBUG_PIM_TRACE) {
eaa54bdb
DW
107 char up_str[INET_ADDRSTRLEN];
108 char neigh_str[INET_ADDRSTRLEN];
12e41d03 109 pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
12e41d03 110 pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, sizeof(neigh_str));
7bd2c6fa 111 zlog_warn("%s: prune (S,G)=%s rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
12e41d03 112 __PRETTY_FUNCTION__,
cf4ea1c4 113 pim_str_sg_dump (sg),
12e41d03
DL
114 source_flags & PIM_RPT_BIT_MASK,
115 source_flags & PIM_WILDCARD_BIT_MASK,
116 up_str, holdtime, neigh_str, ifp->name);
117 }
035f28f6
DS
118
119 if ((source_flags & PIM_RPT_BIT_MASK) &&
120 (source_flags & PIM_WILDCARD_BIT_MASK))
121 {
cf4ea1c4 122 struct pim_rpf *rp = RP (sg->grp);
035f28f6
DS
123
124 // Ignoring Prune *,G's at the moment.
cf4ea1c4 125 if (sg->src.s_addr != rp->rpf_addr.u.prefix4.s_addr)
035f28f6
DS
126 return;
127
cf4ea1c4 128 sg->src.s_addr = INADDR_ANY;
035f28f6 129 }
dc686f82 130
cf4ea1c4 131 pim_ifchannel_prune(ifp, upstream, sg, source_flags, holdtime);
6c629103 132
12e41d03
DL
133}
134
135int pim_joinprune_recv(struct interface *ifp,
136 struct pim_neighbor *neigh,
137 struct in_addr src_addr,
138 uint8_t *tlv_buf, int tlv_buf_size)
139{
140 struct prefix msg_upstream_addr;
141 uint8_t msg_num_groups;
142 uint16_t msg_holdtime;
143 int addr_offset;
144 uint8_t *buf;
145 uint8_t *pastend;
146 int remain;
147 int group;
148
12e41d03
DL
149 buf = tlv_buf;
150 pastend = tlv_buf + tlv_buf_size;
151
152 /*
153 Parse ucast addr
154 */
4416b1f6
DS
155 addr_offset = pim_parse_addr_ucast (&msg_upstream_addr,
156 buf, pastend - buf);
12e41d03 157 if (addr_offset < 1) {
eaa54bdb 158 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
159 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
160 zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
161 __PRETTY_FUNCTION__,
162 src_str, ifp->name);
163 return -1;
164 }
165 buf += addr_offset;
166
167 /*
168 Check upstream address family
169 */
170 if (msg_upstream_addr.family != AF_INET) {
4950938e 171 if (PIM_DEBUG_PIM_J_P) {
eaa54bdb 172 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
173 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
174 zlog_warn("%s: ignoring join/prune directed to unexpected addr family=%d from %s on %s",
175 __PRETTY_FUNCTION__,
176 msg_upstream_addr.family, src_str, ifp->name);
177 }
178 return -2;
179 }
180
181 remain = pastend - buf;
182 if (remain < 4) {
eaa54bdb 183 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
184 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
185 zlog_warn("%s: short join/prune message buffer for group list: size=%d minimum=%d from %s on %s",
186 __PRETTY_FUNCTION__,
187 remain, 4, src_str, ifp->name);
188 return -4;
189 }
190
191 ++buf; /* skip reserved byte */
192 msg_num_groups = *(const uint8_t *) buf;
193 ++buf;
194 msg_holdtime = ntohs(*(const uint16_t *) buf);
195 ++buf;
196 ++buf;
197
4950938e 198 if (PIM_DEBUG_PIM_J_P) {
eaa54bdb
DW
199 char src_str[INET_ADDRSTRLEN];
200 char upstream_str[INET_ADDRSTRLEN];
12e41d03
DL
201 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
202 pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4,
203 upstream_str, sizeof(upstream_str));
4950938e
DS
204 zlog_debug ("%s: join/prune upstream=%s groups=%d holdtime=%d from %s on %s",
205 __PRETTY_FUNCTION__,
206 upstream_str, msg_num_groups, msg_holdtime,
207 src_str, ifp->name);
12e41d03
DL
208 }
209
210 /* Scan groups */
211 for (group = 0; group < msg_num_groups; ++group) {
bce0e645 212 struct prefix_sg sg;
12e41d03
DL
213 uint8_t msg_source_flags;
214 uint16_t msg_num_joined_sources;
215 uint16_t msg_num_pruned_sources;
216 int source;
220d8a49 217 struct pim_ifchannel *ch = NULL;
12e41d03 218
53e39e14 219 memset (&sg, 0, sizeof (struct prefix_sg));
bce0e645 220 addr_offset = pim_parse_addr_group (&sg,
4416b1f6 221 buf, pastend - buf);
12e41d03
DL
222 if (addr_offset < 1) {
223 return -5;
224 }
225 buf += addr_offset;
226
227 remain = pastend - buf;
228 if (remain < 4) {
eaa54bdb 229 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
230 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
231 zlog_warn("%s: short join/prune buffer for source list: size=%d minimum=%d from %s on %s",
232 __PRETTY_FUNCTION__,
233 remain, 4, src_str, ifp->name);
234 return -6;
235 }
236
237 msg_num_joined_sources = ntohs(*(const uint16_t *) buf);
238 buf += 2;
239 msg_num_pruned_sources = ntohs(*(const uint16_t *) buf);
240 buf += 2;
241
4950938e 242 if (PIM_DEBUG_PIM_J_P) {
eaa54bdb
DW
243 char src_str[INET_ADDRSTRLEN];
244 char upstream_str[INET_ADDRSTRLEN];
245 char group_str[INET_ADDRSTRLEN];
12e41d03
DL
246 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
247 pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4,
248 upstream_str, sizeof(upstream_str));
bce0e645 249 pim_inet4_dump("<grp?>", sg.grp,
12e41d03 250 group_str, sizeof(group_str));
bce0e645 251 zlog_warn("%s: join/prune upstream=%s group=%s/32 join_src=%d prune_src=%d from %s on %s",
12e41d03 252 __PRETTY_FUNCTION__,
bce0e645 253 upstream_str, group_str,
12e41d03
DL
254 msg_num_joined_sources, msg_num_pruned_sources,
255 src_str, ifp->name);
256 }
257
258 /* Scan joined sources */
259 for (source = 0; source < msg_num_joined_sources; ++source) {
a7762e07 260 addr_offset = pim_parse_addr_source (&sg,
4416b1f6
DS
261 &msg_source_flags,
262 buf, pastend - buf);
12e41d03
DL
263 if (addr_offset < 1) {
264 return -7;
265 }
266
267 buf += addr_offset;
268
269 recv_join(ifp, neigh, msg_holdtime,
270 msg_upstream_addr.u.prefix4,
cf4ea1c4 271 &sg,
12e41d03 272 msg_source_flags);
220d8a49
DS
273
274 if (sg.src.s_addr == INADDR_ANY)
275 {
276 ch = pim_ifchannel_find (ifp, &sg);
1405c852
DS
277 if (ch)
278 pim_ifchannel_set_star_g_join_state (ch, 0);
220d8a49 279 }
12e41d03
DL
280 }
281
282 /* Scan pruned sources */
283 for (source = 0; source < msg_num_pruned_sources; ++source) {
a7762e07 284 addr_offset = pim_parse_addr_source (&sg,
4416b1f6
DS
285 &msg_source_flags,
286 buf, pastend - buf);
12e41d03
DL
287 if (addr_offset < 1) {
288 return -8;
289 }
290
291 buf += addr_offset;
292
293 recv_prune(ifp, neigh, msg_holdtime,
294 msg_upstream_addr.u.prefix4,
cf4ea1c4 295 &sg,
12e41d03
DL
296 msg_source_flags);
297 }
220d8a49
DS
298 if (ch)
299 pim_ifchannel_set_star_g_join_state (ch, 1);
300 ch = NULL;
12e41d03
DL
301 } /* scan groups */
302
303 return 0;
304}
305
b5e2377c
DS
306int pim_joinprune_send(struct pim_rpf *rpf,
307 struct pim_upstream *up,
308 int send_join)
12e41d03
DL
309{
310 struct pim_interface *pim_ifp;
f99df3e7 311 uint8_t pim_msg[9000];
12e41d03 312 int pim_msg_size;
12e41d03 313
b5e2377c 314 on_trace (__PRETTY_FUNCTION__, rpf->source_nexthop.interface, rpf->rpf_addr.u.prefix4);
4950938e 315
b5e2377c 316 pim_ifp = rpf->source_nexthop.interface->info;
12e41d03
DL
317
318 if (!pim_ifp) {
319 zlog_warn("%s: multicast not enabled on interface %s",
b5e2377c
DS
320 __PRETTY_FUNCTION__,
321 rpf->source_nexthop.interface->name);
12e41d03
DL
322 return -1;
323 }
324
b5e2377c 325 if (PIM_INADDR_IS_ANY(rpf->rpf_addr.u.prefix4)) {
4950938e 326 if (PIM_DEBUG_PIM_J_P) {
eaa54bdb 327 char dst_str[INET_ADDRSTRLEN];
b5e2377c 328 pim_inet4_dump("<dst?>", rpf->rpf_addr.u.prefix4, dst_str, sizeof(dst_str));
05e451f8 329 zlog_debug("%s: %s(S,G)=%s: upstream=%s is myself on interface %s",
12e41d03
DL
330 __PRETTY_FUNCTION__,
331 send_join ? "Join" : "Prune",
b5e2377c 332 up->sg_str, dst_str, rpf->source_nexthop.interface->name);
12e41d03
DL
333 }
334 return 0;
335 }
336
337 /*
338 RFC 4601: 4.3.1. Sending Hello Messages
339
340 Thus, if a router needs to send a Join/Prune or Assert message on
341 an interface on which it has not yet sent a Hello message with the
342 currently configured IP address, then it MUST immediately send the
343 relevant Hello message without waiting for the Hello Timer to
344 expire, followed by the Join/Prune or Assert message.
345 */
b5e2377c 346 pim_hello_require(rpf->source_nexthop.interface);
12e41d03
DL
347
348 /*
349 Build PIM message
350 */
f99df3e7 351 pim_msg_size = pim_msg_join_prune_encode (pim_msg, 9000, send_join,
b5e2377c 352 up, rpf->rpf_addr.u.prefix4, PIM_JP_HOLDTIME);
12e41d03 353
346cffe3
DS
354 if (pim_msg_size < 0)
355 return pim_msg_size;
12e41d03 356
48f6dc2d
CS
357 if (PIM_DEBUG_PIM_J_P) {
358 char dst_str[INET_ADDRSTRLEN];
b5e2377c 359 pim_inet4_dump("<dst?>", rpf->rpf_addr.u.prefix4, dst_str, sizeof(dst_str));
48f6dc2d
CS
360 zlog_debug("%s: sending %s(S,G)=%s to upstream=%s on interface %s",
361 __PRETTY_FUNCTION__,
362 send_join ? "Join" : "Prune",
b5e2377c 363 up->sg_str, dst_str, rpf->source_nexthop.interface->name);
48f6dc2d
CS
364 }
365
12e41d03 366 if (pim_msg_send(pim_ifp->pim_sock_fd,
4df01a4e 367 pim_ifp->primary_address,
12e41d03
DL
368 qpim_all_pim_routers_addr,
369 pim_msg,
370 pim_msg_size,
b5e2377c 371 rpf->source_nexthop.interface->name)) {
12e41d03 372 zlog_warn("%s: could not send PIM message on interface %s",
b5e2377c 373 __PRETTY_FUNCTION__, rpf->source_nexthop.interface->name);
12e41d03
DL
374 return -8;
375 }
376
377 return 0;
378}