]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_register.c
pimd: Send Register-Stop from RP
[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
998af219
DS
114void
115pim_register_send (const struct ip *ip_hdr, struct pim_rpf *rpg)
116{
117 unsigned char buffer[3000];
118 unsigned char *b1;
119 struct pim_interface *pinfo;
120 struct interface *ifp;
121 uint32_t plen;
122
123 ifp = rpg->source_nexthop.interface;
124 pinfo = (struct pim_interface *)ifp->info;
125 if (!pinfo) {
126 zlog_debug("%s: No pinfo!\n", __PRETTY_FUNCTION__);
127 return;
128 }
129
130 memset(buffer, 0, 3000);
131 b1 = buffer + PIM_MSG_REGISTER_LEN;
132
133 plen = ntohs(ip_hdr->ip_len);
9f6d6b12 134 memcpy(b1, (const unsigned char *)ip_hdr, plen);
998af219 135
f5e6574b 136 pim_msg_build_header(buffer, plen + PIM_MSG_REGISTER_LEN, PIM_MSG_TYPE_REGISTER);
998af219
DS
137
138 if (pim_msg_send(pinfo->pim_sock_fd,
139 rpg->rpf_addr,
140 buffer,
141 plen + PIM_MSG_REGISTER_LEN,
142 ifp->name)) {
143 if (PIM_DEBUG_PIM_TRACE) {
144 zlog_debug("%s: could not send PIM register message on interface %s",
145 __PRETTY_FUNCTION__, ifp->name);
146 }
147 return;
148 }
149}
150
01d68c9b
DS
151/*
152 * 4.4.2 Receiving Register Messages at the RP
153 *
154 * When an RP receives a Register message, the course of action is
155 * decided according to the following pseudocode:
156 *
157 * packet_arrives_on_rp_tunnel( pkt ) {
158 * if( outer.dst is not one of my addresses ) {
159 * drop the packet silently.
160 * # Note: this may be a spoofing attempt
161 * }
162 * if( I_am_RP(G) AND outer.dst == RP(G) ) {
163 * sentRegisterStop = FALSE;
164 * if ( register.borderbit == TRUE ) {
165 * if ( PMBR(S,G) == unknown ) {
166 * PMBR(S,G) = outer.src
167 * } else if ( outer.src != PMBR(S,G) ) {
168 * send Register-Stop(S,G) to outer.src
169 * drop the packet silently.
170 * }
171 * }
172 * if ( SPTbit(S,G) OR
173 * ( SwitchToSptDesired(S,G) AND
174 * ( inherited_olist(S,G) == NULL ))) {
175 * send Register-Stop(S,G) to outer.src
176 * sentRegisterStop = TRUE;
177 * }
178 * if ( SPTbit(S,G) OR SwitchToSptDesired(S,G) ) {
179 * if ( sentRegisterStop == TRUE ) {
180 * set KeepaliveTimer(S,G) to RP_Keepalive_Period;
181 * } else {
182 * set KeepaliveTimer(S,G) to Keepalive_Period;
183 * }
184 * }
185 * if( !SPTbit(S,G) AND ! pkt.NullRegisterBit ) {
186 * decapsulate and forward the inner packet to
187 * inherited_olist(S,G,rpt) # Note (+)
188 * }
189 * } else {
190 * send Register-Stop(S,G) to outer.src
191 * # Note (*)
192 * }
193 * }
194 */
195int
196pim_register_recv (struct interface *ifp,
197 struct in_addr dest_addr,
198 struct in_addr src_addr,
199 uint8_t *tlv_buf, int tlv_buf_size)
200{
77e390e5
DS
201 int sentRegisterStop = 0;
202 struct ip *ip_hdr;
9f6d6b12 203 //size_t hlen;
01d68c9b
DS
204 struct in_addr group = { .s_addr = 0 };
205 struct in_addr source = { .s_addr = 0 };
9f6d6b12 206 //uint8_t *msg;
77e390e5 207 uint32_t *bits;
01d68c9b
DS
208
209 if (!pim_check_is_my_ip_address (dest_addr)) {
210 if (PIM_DEBUG_PIM_PACKETS) {
211 char dest[100];
212
213 pim_inet4_dump ("<dst?>", dest_addr, dest, sizeof(dest));
214 zlog_debug ("%s: Received Register message for %s that I do not own", __func__,
215 dest);
216 }
217 return 0;
218 }
219
80c0d168 220#define inherited_olist(S,G) NULL
77e390e5
DS
221 /*
222 * Please note this is not drawn to get the correct bit/data size
223 *
224 * The entirety of the REGISTER packet looks like this:
225 * -------------------------------------------------------------
226 * | Ver | Type | Reserved | Checksum |
227 * |-----------------------------------------------------------|
228 * |B|N| Reserved 2 |
229 * |-----------------------------------------------------------|
230 * | Encap | IP HDR |
231 * | Mcast | |
232 * | Packet |--------------------------------------------------|
233 * | | Mcast Data |
234 * | | |
235 * ...
236 *
237 * tlv_buf when received from the caller points at the B bit
238 * We need to know the inner source and dest
239 */
240 bits = (uint32_t *)tlv_buf;
83d8ff00
DS
241
242 /*
243 * tlv_buf points to the start of the |B|N|... Reserved
244 * Line above. So we need to add 4 bytes to get to the
245 * start of the actual Encapsulated data.
246 */
247#define PIM_MSG_REGISTER_BIT_RESERVED_LEN 4
248 ip_hdr = (struct ip *)(tlv_buf + PIM_MSG_REGISTER_BIT_RESERVED_LEN);
83d8ff00
DS
249 source = ip_hdr->ip_src;
250 group = ip_hdr->ip_dst;
77e390e5 251
ed66602c 252 if (I_am_RP (group) && (dest_addr.s_addr == ((RP (group))->rpf_addr.s_addr))) {
77e390e5 253 sentRegisterStop = 0;
01d68c9b 254
9eda95bd 255 if (*bits & PIM_REGISTER_BORDER_BIT) {
01d68c9b
DS
256 struct in_addr pimbr = pim_br_get_pmbr (source, group);
257 if (PIM_DEBUG_PIM_PACKETS)
258 zlog_debug("%s: Received Register message with Border bit set", __func__);
259
260 if (pimbr.s_addr == pim_br_unknown.s_addr)
80c0d168
DS
261 pim_br_set_pmbr(source, group, src_addr);
262 else if (src_addr.s_addr != pimbr.s_addr) {
13c2408c 263 pim_register_stop_send (ifp, source, group, src_addr);
01d68c9b
DS
264 if (PIM_DEBUG_PIM_PACKETS)
265 zlog_debug("%s: Sending register-Stop to %s and dropping mr. packet",
266 __func__, "Sender");
77e390e5
DS
267 /* Drop Packet Silently */
268 return 1;
01d68c9b
DS
269 }
270 }
77e390e5
DS
271
272 struct pim_upstream *upstream = pim_upstream_find (source, group);
273 /*
274 * If we don't have a place to send ignore the packet
275 */
276 if (!upstream)
6352a6cf 277 {
13c2408c 278 pim_register_stop_send (ifp, source, group, src_addr);
6352a6cf
DS
279 return 1;
280 }
77e390e5
DS
281
282 if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) ||
283 ((SwitchToSptDesired(source, group)) &&
80c0d168 284 (inherited_olist(source, group) == NULL))) {
13c2408c 285 pim_register_stop_send (ifp, source, group, src_addr);
77e390e5
DS
286 sentRegisterStop = 1;
287 }
288
289 if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) ||
290 (SwitchToSptDesired(source, group))) {
80c0d168
DS
291 if (sentRegisterStop) {
292 pim_upstream_keep_alive_timer_start (upstream, PIM_RP_KEEPALIVE_PERIOD);
77e390e5 293 } else {
80c0d168 294 pim_upstream_keep_alive_timer_start (upstream, PIM_KEEPALIVE_PERIOD);
77e390e5
DS
295 }
296 }
297
298 if (!(upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) &&
2ca35b3d
DS
299 !(*bits & PIM_REGISTER_NR_BIT))
300 {
301 pim_rp_set_upstream_addr (&upstream->upstream_addr, source);
302 pim_nexthop_lookup (&upstream->rpf.source_nexthop,
303 upstream->upstream_addr, NULL);
304 upstream->rpf.source_nexthop.interface = ifp;
305 upstream->source_addr.s_addr = source.s_addr;
306 upstream->rpf.rpf_addr.s_addr = source.s_addr;
307 upstream->channel_oil->oil.mfcc_origin = source;
308 pim_scan_individual_oil (upstream->channel_oil);
309 pim_joinprune_send(upstream->rpf.source_nexthop.interface,
310 upstream->rpf.source_nexthop.mrib_nexthop_addr,
311 upstream->source_addr,
312 upstream->group_addr,
313 1);
314
315 //decapsulate and forward the iner packet to
316 //inherited_olist(S,G,rpt)
317 }
77e390e5 318 } else {
13c2408c 319 pim_register_stop_send (ifp, source, group, src_addr);
77e390e5 320 }
01d68c9b
DS
321
322 return 1;
323}
324
325
326static int
327pim_register_send_test_packet (struct thread *t)
328{
329 uint8_t *packet;
330
331 packet = THREAD_ARG(t);
332
333 *packet = 4;
334
335 return 1;
336}
337
338/*
339 * pim_register_send_test_packet
340 *
341 * Send a test packet to the RP from source, in group and pps packets per second
342 */
343void
344pim_register_send_test_packet_start (struct in_addr source,
345 struct in_addr group,
346 uint32_t pps)
347{
348 uint8_t *packet = NULL;
349
350 THREAD_TIMER_MSEC_ON(master, send_test_packet_timer,
351 pim_register_send_test_packet, packet, 1000/pps);
352
353 return;
354}