]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_register.c
pimd: More conversion of struct prefix *sg
[mirror_frr.git] / pimd / pim_register.c
CommitLineData
01d68c9b
DS
1/*
2 * PIM for Quagga
3 * Copyright (C) 2015 Cumulus Networks, Inc.
4 * Donald Sharp
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; see the file COPYING; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
19 * MA 02110-1301 USA
20 */
21
22#include <zebra.h>
23
24#include "log.h"
25#include "if.h"
26#include "thread.h"
13c2408c 27#include "prefix.h"
01d68c9b
DS
28
29#include "pimd.h"
998af219
DS
30#include "pim_mroute.h"
31#include "pim_iface.h"
32#include "pim_msg.h"
33#include "pim_pim.h"
01d68c9b
DS
34#include "pim_str.h"
35#include "pim_rp.h"
36#include "pim_register.h"
80c0d168 37#include "pim_upstream.h"
01d68c9b 38#include "pim_br.h"
2ca35b3d
DS
39#include "pim_rpf.h"
40#include "pim_oil.h"
41#include "pim_zebra.h"
42#include "pim_join.h"
13c2408c 43#include "pim_util.h"
01d68c9b
DS
44
45struct thread *send_test_packet_timer = NULL;
46
47/*
48 * This seems stupidly expensive. A list lookup. Why is this
49 * not a hash?
50 */
51static int
52pim_check_is_my_ip_address (struct in_addr dest_addr)
53{
54 /*
55 * See if we can short-cut some?
56 * This might not make sense if we ever leave a static RP
57 * type of configuration.
58 * Note - Premature optimization might bite our patooeys' here.
59 */
c8ae3ce8 60 if (I_am_RP(dest_addr) && (dest_addr.s_addr == qpim_rp.rpf_addr.s_addr))
01d68c9b
DS
61 return 1;
62
63 if (if_lookup_exact_address (&dest_addr, AF_INET))
64 return 1;
65
66 return 0;
67}
68
69static void
13c2408c
DS
70pim_register_stop_send (struct interface *ifp, struct in_addr source,
71 struct in_addr group, struct in_addr originator)
01d68c9b 72{
13c2408c
DS
73 struct pim_interface *pinfo;
74 unsigned char buffer[3000];
75 unsigned int b1length = 0;
76 unsigned int length;
77 uint8_t *b1;
78 struct prefix p;
79
80 memset (buffer, 0, 3000);
81 b1 = (uint8_t *)buffer + PIM_MSG_REGISTER_STOP_LEN;
82
83 length = pim_encode_addr_group (b1, AFI_IP, 0, 0, group);
84 b1length += length;
85 b1 += length;
86
87 p.family = AF_INET;
88 p.u.prefix4 = source;
89 p.prefixlen = 32;
90 length = pim_encode_addr_ucast (b1, &p);
91 b1length += length;
92
93 pim_msg_build_header (buffer, b1length + PIM_MSG_REGISTER_STOP_LEN, PIM_MSG_TYPE_REG_STOP);
94
95 pinfo = (struct pim_interface *)ifp->info;
96 if (!pinfo)
97 {
98 if (PIM_DEBUG_PIM_TRACE)
99 zlog_debug ("%s: No pinfo!\n", __PRETTY_FUNCTION__);
100 return;
101 }
102 if (pim_msg_send (pinfo->pim_sock_fd, originator,
103 buffer, b1length + PIM_MSG_REGISTER_STOP_LEN,
104 ifp->name))
105 {
106 if (PIM_DEBUG_PIM_TRACE)
107 {
108 zlog_debug ("%s: could not send PIM register stop message on interface %s",
109 __PRETTY_FUNCTION__, ifp->name);
110 }
111 }
01d68c9b
DS
112}
113
4dffc880 114int
56638739 115pim_register_stop_recv (uint8_t *buf, int buf_size)
4dffc880 116{
56638739
DS
117 struct pim_upstream *upstream = NULL;
118 struct prefix source;
119 struct prefix group;
5074a423 120 struct prefix sg;
56638739
DS
121 int l;
122
0e6ae425 123 if (PIM_DEBUG_PIM_PACKETDUMP_RECV)
56638739
DS
124 pim_pkt_dump ("Received Register Stop", buf, buf_size);
125
126 l = pim_parse_addr_group (&group, buf, buf_size);
127 buf += l;
128 buf_size -= l;
129 l = pim_parse_addr_ucast (&source, buf, buf_size);
5074a423
DS
130 memset (&sg, 0, sizeof (struct prefix));
131 sg.u.sg.src = source.u.prefix4;
132 sg.u.sg.grp = group.u.prefix4;
133 upstream = pim_upstream_find (&sg);
56638739
DS
134 if (!upstream)
135 {
136 return 0;
137 }
138
139 switch (upstream->join_state)
140 {
141 case PIM_UPSTREAM_NOTJOINED:
142 case PIM_UPSTREAM_PRUNE:
143 return 0;
144 break;
145 case PIM_UPSTREAM_JOINED:
146 case PIM_UPSTREAM_JOIN_PENDING:
147 upstream->join_state = PIM_UPSTREAM_PRUNE;
148 pim_upstream_start_register_stop_timer (upstream, 0);
149 pim_channel_del_oif (upstream->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
150 return 0;
151 break;
152 }
153
4dffc880
DS
154 return 0;
155}
156
998af219 157void
b100a4f5 158pim_register_send (const uint8_t *buf, int buf_size, struct pim_rpf *rpg, int null_register)
998af219
DS
159{
160 unsigned char buffer[3000];
161 unsigned char *b1;
162 struct pim_interface *pinfo;
163 struct interface *ifp;
998af219
DS
164
165 ifp = rpg->source_nexthop.interface;
166 pinfo = (struct pim_interface *)ifp->info;
167 if (!pinfo) {
168 zlog_debug("%s: No pinfo!\n", __PRETTY_FUNCTION__);
169 return;
170 }
171
172 memset(buffer, 0, 3000);
b100a4f5
DS
173 b1 = buffer + PIM_MSG_HEADER_LEN;
174 *b1 |= null_register << 31;
998af219
DS
175 b1 = buffer + PIM_MSG_REGISTER_LEN;
176
b100a4f5 177 memcpy(b1, (const unsigned char *)buf, buf_size);
998af219 178
b100a4f5 179 pim_msg_build_header(buffer, buf_size + PIM_MSG_REGISTER_LEN, PIM_MSG_TYPE_REGISTER);
998af219
DS
180
181 if (pim_msg_send(pinfo->pim_sock_fd,
182 rpg->rpf_addr,
183 buffer,
b100a4f5 184 buf_size + PIM_MSG_REGISTER_LEN,
998af219
DS
185 ifp->name)) {
186 if (PIM_DEBUG_PIM_TRACE) {
187 zlog_debug("%s: could not send PIM register message on interface %s",
188 __PRETTY_FUNCTION__, ifp->name);
189 }
190 return;
191 }
192}
193
01d68c9b
DS
194/*
195 * 4.4.2 Receiving Register Messages at the RP
196 *
197 * When an RP receives a Register message, the course of action is
198 * decided according to the following pseudocode:
199 *
200 * packet_arrives_on_rp_tunnel( pkt ) {
201 * if( outer.dst is not one of my addresses ) {
202 * drop the packet silently.
203 * # Note: this may be a spoofing attempt
204 * }
205 * if( I_am_RP(G) AND outer.dst == RP(G) ) {
206 * sentRegisterStop = FALSE;
207 * if ( register.borderbit == TRUE ) {
208 * if ( PMBR(S,G) == unknown ) {
209 * PMBR(S,G) = outer.src
210 * } else if ( outer.src != PMBR(S,G) ) {
211 * send Register-Stop(S,G) to outer.src
212 * drop the packet silently.
213 * }
214 * }
215 * if ( SPTbit(S,G) OR
216 * ( SwitchToSptDesired(S,G) AND
217 * ( inherited_olist(S,G) == NULL ))) {
218 * send Register-Stop(S,G) to outer.src
219 * sentRegisterStop = TRUE;
220 * }
221 * if ( SPTbit(S,G) OR SwitchToSptDesired(S,G) ) {
222 * if ( sentRegisterStop == TRUE ) {
223 * set KeepaliveTimer(S,G) to RP_Keepalive_Period;
224 * } else {
225 * set KeepaliveTimer(S,G) to Keepalive_Period;
226 * }
227 * }
228 * if( !SPTbit(S,G) AND ! pkt.NullRegisterBit ) {
229 * decapsulate and forward the inner packet to
230 * inherited_olist(S,G,rpt) # Note (+)
231 * }
232 * } else {
233 * send Register-Stop(S,G) to outer.src
234 * # Note (*)
235 * }
236 * }
237 */
238int
239pim_register_recv (struct interface *ifp,
240 struct in_addr dest_addr,
241 struct in_addr src_addr,
242 uint8_t *tlv_buf, int tlv_buf_size)
243{
77e390e5
DS
244 int sentRegisterStop = 0;
245 struct ip *ip_hdr;
01d68c9b
DS
246 struct in_addr group = { .s_addr = 0 };
247 struct in_addr source = { .s_addr = 0 };
5074a423 248 struct prefix sg;
77e390e5 249 uint32_t *bits;
01d68c9b
DS
250
251 if (!pim_check_is_my_ip_address (dest_addr)) {
252 if (PIM_DEBUG_PIM_PACKETS) {
253 char dest[100];
254
255 pim_inet4_dump ("<dst?>", dest_addr, dest, sizeof(dest));
256 zlog_debug ("%s: Received Register message for %s that I do not own", __func__,
257 dest);
258 }
259 return 0;
260 }
261
80c0d168 262#define inherited_olist(S,G) NULL
77e390e5
DS
263 /*
264 * Please note this is not drawn to get the correct bit/data size
265 *
266 * The entirety of the REGISTER packet looks like this:
267 * -------------------------------------------------------------
268 * | Ver | Type | Reserved | Checksum |
269 * |-----------------------------------------------------------|
270 * |B|N| Reserved 2 |
271 * |-----------------------------------------------------------|
272 * | Encap | IP HDR |
273 * | Mcast | |
274 * | Packet |--------------------------------------------------|
275 * | | Mcast Data |
276 * | | |
277 * ...
278 *
279 * tlv_buf when received from the caller points at the B bit
280 * We need to know the inner source and dest
281 */
282 bits = (uint32_t *)tlv_buf;
83d8ff00
DS
283
284 /*
285 * tlv_buf points to the start of the |B|N|... Reserved
286 * Line above. So we need to add 4 bytes to get to the
287 * start of the actual Encapsulated data.
288 */
289#define PIM_MSG_REGISTER_BIT_RESERVED_LEN 4
290 ip_hdr = (struct ip *)(tlv_buf + PIM_MSG_REGISTER_BIT_RESERVED_LEN);
83d8ff00
DS
291 source = ip_hdr->ip_src;
292 group = ip_hdr->ip_dst;
77e390e5 293
ed66602c 294 if (I_am_RP (group) && (dest_addr.s_addr == ((RP (group))->rpf_addr.s_addr))) {
77e390e5 295 sentRegisterStop = 0;
01d68c9b 296
9eda95bd 297 if (*bits & PIM_REGISTER_BORDER_BIT) {
01d68c9b
DS
298 struct in_addr pimbr = pim_br_get_pmbr (source, group);
299 if (PIM_DEBUG_PIM_PACKETS)
300 zlog_debug("%s: Received Register message with Border bit set", __func__);
301
302 if (pimbr.s_addr == pim_br_unknown.s_addr)
80c0d168
DS
303 pim_br_set_pmbr(source, group, src_addr);
304 else if (src_addr.s_addr != pimbr.s_addr) {
13c2408c 305 pim_register_stop_send (ifp, source, group, src_addr);
01d68c9b
DS
306 if (PIM_DEBUG_PIM_PACKETS)
307 zlog_debug("%s: Sending register-Stop to %s and dropping mr. packet",
308 __func__, "Sender");
77e390e5
DS
309 /* Drop Packet Silently */
310 return 1;
01d68c9b
DS
311 }
312 }
77e390e5 313
5074a423
DS
314 memset (&sg, 0, sizeof (struct prefix));
315 sg.u.sg.src = source;
316 sg.u.sg.grp = group;
317 struct pim_upstream *upstream = pim_upstream_find (&sg);
77e390e5
DS
318 /*
319 * If we don't have a place to send ignore the packet
320 */
321 if (!upstream)
9fd309db 322 {
5074a423 323 upstream = pim_upstream_add (&sg, ifp);
9fd309db
DS
324 pim_upstream_switch (upstream, PIM_UPSTREAM_PRUNE);
325 }
326
327 if (upstream->join_state == PIM_UPSTREAM_PRUNE)
6352a6cf 328 {
13c2408c 329 pim_register_stop_send (ifp, source, group, src_addr);
6352a6cf
DS
330 return 1;
331 }
77e390e5
DS
332
333 if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) ||
334 ((SwitchToSptDesired(source, group)) &&
80c0d168 335 (inherited_olist(source, group) == NULL))) {
13c2408c 336 pim_register_stop_send (ifp, source, group, src_addr);
77e390e5
DS
337 sentRegisterStop = 1;
338 }
339
340 if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) ||
341 (SwitchToSptDesired(source, group))) {
80c0d168
DS
342 if (sentRegisterStop) {
343 pim_upstream_keep_alive_timer_start (upstream, PIM_RP_KEEPALIVE_PERIOD);
77e390e5 344 } else {
80c0d168 345 pim_upstream_keep_alive_timer_start (upstream, PIM_KEEPALIVE_PERIOD);
77e390e5
DS
346 }
347 }
348
349 if (!(upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) &&
2ca35b3d
DS
350 !(*bits & PIM_REGISTER_NR_BIT))
351 {
352 pim_rp_set_upstream_addr (&upstream->upstream_addr, source);
353 pim_nexthop_lookup (&upstream->rpf.source_nexthop,
354 upstream->upstream_addr, NULL);
355 upstream->rpf.source_nexthop.interface = ifp;
05e451f8 356 upstream->sg.u.sg.src.s_addr = source.s_addr;
f6a1dc2c 357 upstream->rpf.rpf_addr = upstream->rpf.source_nexthop.mrib_nexthop_addr;
2ca35b3d
DS
358 upstream->channel_oil->oil.mfcc_origin = source;
359 pim_scan_individual_oil (upstream->channel_oil);
56638739 360 pim_upstream_send_join (upstream);
2ca35b3d
DS
361
362 //decapsulate and forward the iner packet to
363 //inherited_olist(S,G,rpt)
364 }
77e390e5 365 } else {
13c2408c 366 pim_register_stop_send (ifp, source, group, src_addr);
77e390e5 367 }
01d68c9b
DS
368
369 return 1;
370}
371
372
373static int
374pim_register_send_test_packet (struct thread *t)
375{
376 uint8_t *packet;
377
378 packet = THREAD_ARG(t);
379
380 *packet = 4;
381
382 return 1;
383}
384
385/*
386 * pim_register_send_test_packet
387 *
388 * Send a test packet to the RP from source, in group and pps packets per second
389 */
390void
391pim_register_send_test_packet_start (struct in_addr source,
392 struct in_addr group,
393 uint32_t pps)
394{
395 uint8_t *packet = NULL;
396
397 THREAD_TIMER_MSEC_ON(master, send_test_packet_timer,
398 pim_register_send_test_packet, packet, 1000/pps);
399
400 return;
401}