]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_register.c
pimd: Fixup some broken code for the register receive
[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"
27
28#include "pimd.h"
29#include "pim_str.h"
30#include "pim_rp.h"
31#include "pim_register.h"
80c0d168 32#include "pim_upstream.h"
01d68c9b
DS
33#include "pim_br.h"
34
35struct thread *send_test_packet_timer = NULL;
36
37/*
38 * This seems stupidly expensive. A list lookup. Why is this
39 * not a hash?
40 */
41static int
42pim_check_is_my_ip_address (struct in_addr dest_addr)
43{
44 /*
45 * See if we can short-cut some?
46 * This might not make sense if we ever leave a static RP
47 * type of configuration.
48 * Note - Premature optimization might bite our patooeys' here.
49 */
50 if (I_am_RP(dest_addr) && (dest_addr.s_addr == qpim_rp.s_addr))
51 return 1;
52
53 if (if_lookup_exact_address (&dest_addr, AF_INET))
54 return 1;
55
56 return 0;
57}
58
59static void
60pim_register_stop_send (struct in_addr src)
61{
62 return;
63}
64
65/*
66 * 4.4.2 Receiving Register Messages at the RP
67 *
68 * When an RP receives a Register message, the course of action is
69 * decided according to the following pseudocode:
70 *
71 * packet_arrives_on_rp_tunnel( pkt ) {
72 * if( outer.dst is not one of my addresses ) {
73 * drop the packet silently.
74 * # Note: this may be a spoofing attempt
75 * }
76 * if( I_am_RP(G) AND outer.dst == RP(G) ) {
77 * sentRegisterStop = FALSE;
78 * if ( register.borderbit == TRUE ) {
79 * if ( PMBR(S,G) == unknown ) {
80 * PMBR(S,G) = outer.src
81 * } else if ( outer.src != PMBR(S,G) ) {
82 * send Register-Stop(S,G) to outer.src
83 * drop the packet silently.
84 * }
85 * }
86 * if ( SPTbit(S,G) OR
87 * ( SwitchToSptDesired(S,G) AND
88 * ( inherited_olist(S,G) == NULL ))) {
89 * send Register-Stop(S,G) to outer.src
90 * sentRegisterStop = TRUE;
91 * }
92 * if ( SPTbit(S,G) OR SwitchToSptDesired(S,G) ) {
93 * if ( sentRegisterStop == TRUE ) {
94 * set KeepaliveTimer(S,G) to RP_Keepalive_Period;
95 * } else {
96 * set KeepaliveTimer(S,G) to Keepalive_Period;
97 * }
98 * }
99 * if( !SPTbit(S,G) AND ! pkt.NullRegisterBit ) {
100 * decapsulate and forward the inner packet to
101 * inherited_olist(S,G,rpt) # Note (+)
102 * }
103 * } else {
104 * send Register-Stop(S,G) to outer.src
105 * # Note (*)
106 * }
107 * }
108 */
109int
110pim_register_recv (struct interface *ifp,
111 struct in_addr dest_addr,
112 struct in_addr src_addr,
113 uint8_t *tlv_buf, int tlv_buf_size)
114{
77e390e5
DS
115 int sentRegisterStop = 0;
116 struct ip *ip_hdr;
117 size_t hlen;
01d68c9b
DS
118 struct in_addr group = { .s_addr = 0 };
119 struct in_addr source = { .s_addr = 0 };
77e390e5
DS
120 uint8_t *msg;
121 uint32_t *bits;
01d68c9b
DS
122
123 if (!pim_check_is_my_ip_address (dest_addr)) {
124 if (PIM_DEBUG_PIM_PACKETS) {
125 char dest[100];
126
127 pim_inet4_dump ("<dst?>", dest_addr, dest, sizeof(dest));
128 zlog_debug ("%s: Received Register message for %s that I do not own", __func__,
129 dest);
130 }
131 return 0;
132 }
133
80c0d168 134#define inherited_olist(S,G) NULL
77e390e5
DS
135 /*
136 * Please note this is not drawn to get the correct bit/data size
137 *
138 * The entirety of the REGISTER packet looks like this:
139 * -------------------------------------------------------------
140 * | Ver | Type | Reserved | Checksum |
141 * |-----------------------------------------------------------|
142 * |B|N| Reserved 2 |
143 * |-----------------------------------------------------------|
144 * | Encap | IP HDR |
145 * | Mcast | |
146 * | Packet |--------------------------------------------------|
147 * | | Mcast Data |
148 * | | |
149 * ...
150 *
151 * tlv_buf when received from the caller points at the B bit
152 * We need to know the inner source and dest
153 */
154 bits = (uint32_t *)tlv_buf;
155 ip_hdr = (struct ip *)(tlv_buf + PIM_MSG_REGISTER_LEN);
156 hlen = (ip_hdr->ip_hl << 2) | PIM_MSG_REGISTER_LEN;
157 msg = (uint8_t *)tlv_buf + hlen;
158 source = ip_hdr->ip_src;
159 group = ip_hdr->ip_dst;
160
01d68c9b 161 if (I_am_RP (group) && (dest_addr.s_addr == (RP (group).s_addr))) {
77e390e5 162 sentRegisterStop = 0;
01d68c9b
DS
163
164 if (*bits && PIM_REGISTER_BORDER_BIT) {
165 struct in_addr pimbr = pim_br_get_pmbr (source, group);
166 if (PIM_DEBUG_PIM_PACKETS)
167 zlog_debug("%s: Received Register message with Border bit set", __func__);
168
169 if (pimbr.s_addr == pim_br_unknown.s_addr)
80c0d168
DS
170 pim_br_set_pmbr(source, group, src_addr);
171 else if (src_addr.s_addr != pimbr.s_addr) {
172 pim_register_stop_send(src_addr);
01d68c9b
DS
173 if (PIM_DEBUG_PIM_PACKETS)
174 zlog_debug("%s: Sending register-Stop to %s and dropping mr. packet",
175 __func__, "Sender");
77e390e5
DS
176 /* Drop Packet Silently */
177 return 1;
01d68c9b
DS
178 }
179 }
77e390e5
DS
180
181 struct pim_upstream *upstream = pim_upstream_find (source, group);
182 /*
183 * If we don't have a place to send ignore the packet
184 */
185 if (!upstream)
186 return 1;
187
188 if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) ||
189 ((SwitchToSptDesired(source, group)) &&
80c0d168
DS
190 (inherited_olist(source, group) == NULL))) {
191 pim_register_stop_send(src_addr);
77e390e5
DS
192 sentRegisterStop = 1;
193 }
194
195 if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) ||
196 (SwitchToSptDesired(source, group))) {
80c0d168
DS
197 if (sentRegisterStop) {
198 pim_upstream_keep_alive_timer_start (upstream, PIM_RP_KEEPALIVE_PERIOD);
77e390e5 199 } else {
80c0d168 200 pim_upstream_keep_alive_timer_start (upstream, PIM_KEEPALIVE_PERIOD);
77e390e5
DS
201 }
202 }
203
204 if (!(upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) &&
205 !(*bits && PIM_REGISTER_NR_BIT)) {
206 //decapsulate and forward the iner packet to
207 //inherited_olist(S,G,rpt)
01d68c9b 208 }
77e390e5 209 } else {
80c0d168 210 pim_register_stop_send(src_addr);
77e390e5 211 }
01d68c9b
DS
212
213 return 1;
214}
215
216
217static int
218pim_register_send_test_packet (struct thread *t)
219{
220 uint8_t *packet;
221
222 packet = THREAD_ARG(t);
223
224 *packet = 4;
225
226 return 1;
227}
228
229/*
230 * pim_register_send_test_packet
231 *
232 * Send a test packet to the RP from source, in group and pps packets per second
233 */
234void
235pim_register_send_test_packet_start (struct in_addr source,
236 struct in_addr group,
237 uint32_t pps)
238{
239 uint8_t *packet = NULL;
240
241 THREAD_TIMER_MSEC_ON(master, send_test_packet_timer,
242 pim_register_send_test_packet, packet, 1000/pps);
243
244 return;
245}