]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_register.c
Merge pull request #429 from hwchiu/fix_clang_sa
[mirror_frr.git] / pimd / pim_register.c
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"
27
28 #include "pimd.h"
29 #include "pim_mroute.h"
30 #include "pim_iface.h"
31 #include "pim_msg.h"
32 #include "pim_pim.h"
33 #include "pim_str.h"
34 #include "pim_rp.h"
35 #include "pim_register.h"
36 #include "pim_upstream.h"
37 #include "pim_br.h"
38 #include "pim_rpf.h"
39 #include "pim_oil.h"
40 #include "pim_zebra.h"
41 #include "pim_join.h"
42
43 struct thread *send_test_packet_timer = NULL;
44
45 /*
46 * This seems stupidly expensive. A list lookup. Why is this
47 * not a hash?
48 */
49 static int
50 pim_check_is_my_ip_address (struct in_addr dest_addr)
51 {
52 /*
53 * See if we can short-cut some?
54 * This might not make sense if we ever leave a static RP
55 * type of configuration.
56 * Note - Premature optimization might bite our patooeys' here.
57 */
58 if (I_am_RP(dest_addr) && (dest_addr.s_addr == qpim_rp.rpf_addr.s_addr))
59 return 1;
60
61 if (if_lookup_exact_address (&dest_addr, AF_INET))
62 return 1;
63
64 return 0;
65 }
66
67 static void
68 pim_register_stop_send (struct in_addr src)
69 {
70 return;
71 }
72
73 void
74 pim_register_send (const struct ip *ip_hdr, struct pim_rpf *rpg)
75 {
76 unsigned char buffer[3000];
77 unsigned char *b1;
78 struct pim_interface *pinfo;
79 struct interface *ifp;
80 uint32_t plen;
81
82 ifp = rpg->source_nexthop.interface;
83 pinfo = (struct pim_interface *)ifp->info;
84 if (!pinfo) {
85 zlog_debug("%s: No pinfo!\n", __PRETTY_FUNCTION__);
86 return;
87 }
88
89 memset(buffer, 0, 3000);
90 b1 = buffer + PIM_MSG_REGISTER_LEN;
91
92 plen = ntohs(ip_hdr->ip_len);
93 memcpy(b1, (const unsigned char *)ip_hdr, plen);
94
95 pim_msg_build_header(buffer, plen + PIM_MSG_REGISTER_LEN, PIM_MSG_TYPE_REGISTER);
96
97 if (pim_msg_send(pinfo->pim_sock_fd,
98 rpg->rpf_addr,
99 buffer,
100 plen + PIM_MSG_REGISTER_LEN,
101 ifp->name)) {
102 if (PIM_DEBUG_PIM_TRACE) {
103 zlog_debug("%s: could not send PIM register message on interface %s",
104 __PRETTY_FUNCTION__, ifp->name);
105 }
106 return;
107 }
108 }
109
110 /*
111 * 4.4.2 Receiving Register Messages at the RP
112 *
113 * When an RP receives a Register message, the course of action is
114 * decided according to the following pseudocode:
115 *
116 * packet_arrives_on_rp_tunnel( pkt ) {
117 * if( outer.dst is not one of my addresses ) {
118 * drop the packet silently.
119 * # Note: this may be a spoofing attempt
120 * }
121 * if( I_am_RP(G) AND outer.dst == RP(G) ) {
122 * sentRegisterStop = FALSE;
123 * if ( register.borderbit == TRUE ) {
124 * if ( PMBR(S,G) == unknown ) {
125 * PMBR(S,G) = outer.src
126 * } else if ( outer.src != PMBR(S,G) ) {
127 * send Register-Stop(S,G) to outer.src
128 * drop the packet silently.
129 * }
130 * }
131 * if ( SPTbit(S,G) OR
132 * ( SwitchToSptDesired(S,G) AND
133 * ( inherited_olist(S,G) == NULL ))) {
134 * send Register-Stop(S,G) to outer.src
135 * sentRegisterStop = TRUE;
136 * }
137 * if ( SPTbit(S,G) OR SwitchToSptDesired(S,G) ) {
138 * if ( sentRegisterStop == TRUE ) {
139 * set KeepaliveTimer(S,G) to RP_Keepalive_Period;
140 * } else {
141 * set KeepaliveTimer(S,G) to Keepalive_Period;
142 * }
143 * }
144 * if( !SPTbit(S,G) AND ! pkt.NullRegisterBit ) {
145 * decapsulate and forward the inner packet to
146 * inherited_olist(S,G,rpt) # Note (+)
147 * }
148 * } else {
149 * send Register-Stop(S,G) to outer.src
150 * # Note (*)
151 * }
152 * }
153 */
154 int
155 pim_register_recv (struct interface *ifp,
156 struct in_addr dest_addr,
157 struct in_addr src_addr,
158 uint8_t *tlv_buf, int tlv_buf_size)
159 {
160 int sentRegisterStop = 0;
161 struct ip *ip_hdr;
162 //size_t hlen;
163 struct in_addr group;
164 struct in_addr source;
165 //uint8_t *msg;
166 uint32_t *bits;
167
168 if (!pim_check_is_my_ip_address (dest_addr)) {
169 if (PIM_DEBUG_PIM_PACKETS) {
170 char dest[100];
171
172 pim_inet4_dump ("<dst?>", dest_addr, dest, sizeof(dest));
173 zlog_debug ("%s: Received Register message for %s that I do not own", __func__,
174 dest);
175 }
176 return 0;
177 }
178
179 #define inherited_olist(S,G) NULL
180 /*
181 * Please note this is not drawn to get the correct bit/data size
182 *
183 * The entirety of the REGISTER packet looks like this:
184 * -------------------------------------------------------------
185 * | Ver | Type | Reserved | Checksum |
186 * |-----------------------------------------------------------|
187 * |B|N| Reserved 2 |
188 * |-----------------------------------------------------------|
189 * | Encap | IP HDR |
190 * | Mcast | |
191 * | Packet |--------------------------------------------------|
192 * | | Mcast Data |
193 * | | |
194 * ...
195 *
196 * tlv_buf when received from the caller points at the B bit
197 * We need to know the inner source and dest
198 */
199 bits = (uint32_t *)tlv_buf;
200
201 /*
202 * tlv_buf points to the start of the |B|N|... Reserved
203 * Line above. So we need to add 4 bytes to get to the
204 * start of the actual Encapsulated data.
205 */
206 #define PIM_MSG_REGISTER_BIT_RESERVED_LEN 4
207 ip_hdr = (struct ip *)(tlv_buf + PIM_MSG_REGISTER_BIT_RESERVED_LEN);
208 //hlen = (ip_hdr->ip_hl << 2) | PIM_MSG_REGISTER_LEN;
209 //msg = (uint8_t *)tlv_buf + hlen;
210 source = ip_hdr->ip_src;
211 group = ip_hdr->ip_dst;
212
213 if (I_am_RP (group) && (dest_addr.s_addr == ((RP (group))->rpf_addr.s_addr))) {
214 sentRegisterStop = 0;
215
216 if (*bits & PIM_REGISTER_BORDER_BIT) {
217 struct in_addr pimbr = pim_br_get_pmbr (source, group);
218 if (PIM_DEBUG_PIM_PACKETS)
219 zlog_debug("%s: Received Register message with Border bit set", __func__);
220
221 if (pimbr.s_addr == pim_br_unknown.s_addr)
222 pim_br_set_pmbr(source, group, src_addr);
223 else if (src_addr.s_addr != pimbr.s_addr) {
224 pim_register_stop_send(src_addr);
225 if (PIM_DEBUG_PIM_PACKETS)
226 zlog_debug("%s: Sending register-Stop to %s and dropping mr. packet",
227 __func__, "Sender");
228 /* Drop Packet Silently */
229 return 1;
230 }
231 }
232
233 struct pim_upstream *upstream = pim_upstream_find (source, group);
234 /*
235 * If we don't have a place to send ignore the packet
236 */
237 if (!upstream)
238 return 1;
239
240 if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) ||
241 ((SwitchToSptDesired(source, group)) &&
242 (inherited_olist(source, group) == NULL))) {
243 pim_register_stop_send(src_addr);
244 sentRegisterStop = 1;
245 }
246
247 if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) ||
248 (SwitchToSptDesired(source, group))) {
249 if (sentRegisterStop) {
250 pim_upstream_keep_alive_timer_start (upstream, PIM_RP_KEEPALIVE_PERIOD);
251 } else {
252 pim_upstream_keep_alive_timer_start (upstream, PIM_KEEPALIVE_PERIOD);
253 }
254 }
255
256 if (!(upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) &&
257 !(*bits & PIM_REGISTER_NR_BIT))
258 {
259 pim_rp_set_upstream_addr (&upstream->upstream_addr, source);
260 pim_nexthop_lookup (&upstream->rpf.source_nexthop,
261 upstream->upstream_addr, NULL);
262 upstream->rpf.source_nexthop.interface = ifp;
263 upstream->source_addr.s_addr = source.s_addr;
264 upstream->rpf.rpf_addr.s_addr = source.s_addr;
265 upstream->channel_oil->oil.mfcc_origin = source;
266 pim_scan_individual_oil (upstream->channel_oil);
267 pim_joinprune_send(upstream->rpf.source_nexthop.interface,
268 upstream->rpf.source_nexthop.mrib_nexthop_addr,
269 upstream->source_addr,
270 upstream->group_addr,
271 1);
272
273 //decapsulate and forward the iner packet to
274 //inherited_olist(S,G,rpt)
275 }
276 } else {
277 pim_register_stop_send(src_addr);
278 }
279
280 return 1;
281 }
282
283
284 static int
285 pim_register_send_test_packet (struct thread *t)
286 {
287 uint8_t *packet;
288
289 packet = THREAD_ARG(t);
290
291 *packet = 4;
292
293 return 1;
294 }
295
296 /*
297 * pim_register_send_test_packet
298 *
299 * Send a test packet to the RP from source, in group and pps packets per second
300 */
301 void
302 pim_register_send_test_packet_start (struct in_addr source,
303 struct in_addr group,
304 uint32_t pps)
305 {
306 uint8_t *packet = NULL;
307
308 THREAD_TIMER_MSEC_ON(master, send_test_packet_timer,
309 pim_register_send_test_packet, packet, 1000/pps);
310
311 return;
312 }