]>
Commit | Line | Data |
---|---|---|
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 | |
45 | struct thread *send_test_packet_timer = NULL; | |
46 | ||
47 | /* | |
48 | * This seems stupidly expensive. A list lookup. Why is this | |
49 | * not a hash? | |
50 | */ | |
51 | static int | |
52 | pim_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 | ||
69 | static void | |
13c2408c DS |
70 | pim_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 | 114 | int |
56638739 | 115 | pim_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 | 157 | void |
b100a4f5 | 158 | pim_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 | */ | |
238 | int | |
239 | pim_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 | ||
373 | static int | |
374 | pim_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 | */ | |
390 | void | |
391 | pim_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 | } |