3 * Copyright (C) 2015 Cumulus Networks, Inc.
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.
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.
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,
29 #include "pim_mroute.h"
30 #include "pim_iface.h"
35 #include "pim_register.h"
36 #include "pim_upstream.h"
40 #include "pim_zebra.h"
43 struct thread
*send_test_packet_timer
= NULL
;
46 * This seems stupidly expensive. A list lookup. Why is this
50 pim_check_is_my_ip_address (struct in_addr dest_addr
)
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.
58 if (I_am_RP(dest_addr
) && (dest_addr
.s_addr
== qpim_rp
.rpf_addr
.s_addr
))
61 if (if_lookup_exact_address (&dest_addr
, AF_INET
))
68 pim_register_stop_send (struct in_addr src
)
74 pim_register_send (const struct ip
*ip_hdr
, struct pim_rpf
*rpg
)
76 unsigned char buffer
[3000];
78 struct pim_interface
*pinfo
;
79 struct interface
*ifp
;
82 ifp
= rpg
->source_nexthop
.interface
;
83 pinfo
= (struct pim_interface
*)ifp
->info
;
85 zlog_debug("%s: No pinfo!\n", __PRETTY_FUNCTION__
);
89 memset(buffer
, 0, 3000);
90 b1
= buffer
+ PIM_MSG_REGISTER_LEN
;
92 plen
= ntohs(ip_hdr
->ip_len
);
93 memcpy(b1
, (const unsigned char *)ip_hdr
, plen
);
95 pim_msg_build_header(buffer
, plen
+ PIM_MSG_REGISTER_LEN
, PIM_MSG_TYPE_REGISTER
);
97 if (pim_msg_send(pinfo
->pim_sock_fd
,
100 plen
+ PIM_MSG_REGISTER_LEN
,
102 if (PIM_DEBUG_PIM_TRACE
) {
103 zlog_debug("%s: could not send PIM register message on interface %s",
104 __PRETTY_FUNCTION__
, ifp
->name
);
111 * 4.4.2 Receiving Register Messages at the RP
113 * When an RP receives a Register message, the course of action is
114 * decided according to the following pseudocode:
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
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.
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;
137 * if ( SPTbit(S,G) OR SwitchToSptDesired(S,G) ) {
138 * if ( sentRegisterStop == TRUE ) {
139 * set KeepaliveTimer(S,G) to RP_Keepalive_Period;
141 * set KeepaliveTimer(S,G) to Keepalive_Period;
144 * if( !SPTbit(S,G) AND ! pkt.NullRegisterBit ) {
145 * decapsulate and forward the inner packet to
146 * inherited_olist(S,G,rpt) # Note (+)
149 * send Register-Stop(S,G) to outer.src
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
)
160 int sentRegisterStop
= 0;
163 struct in_addr group
= { .s_addr
= 0 };
164 struct in_addr source
= { .s_addr
= 0 };
168 if (!pim_check_is_my_ip_address (dest_addr
)) {
169 if (PIM_DEBUG_PIM_PACKETS
) {
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__
,
179 #define inherited_olist(S,G) NULL
181 * Please note this is not drawn to get the correct bit/data size
183 * The entirety of the REGISTER packet looks like this:
184 * -------------------------------------------------------------
185 * | Ver | Type | Reserved | Checksum |
186 * |-----------------------------------------------------------|
188 * |-----------------------------------------------------------|
191 * | Packet |--------------------------------------------------|
196 * tlv_buf when received from the caller points at the B bit
197 * We need to know the inner source and dest
199 bits
= (uint32_t *)tlv_buf
;
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.
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
;
213 if (I_am_RP (group
) && (dest_addr
.s_addr
== ((RP (group
))->rpf_addr
.s_addr
))) {
214 sentRegisterStop
= 0;
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__
);
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",
228 /* Drop Packet Silently */
233 struct pim_upstream
*upstream
= pim_upstream_find (source
, group
);
235 * If we don't have a place to send ignore the packet
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;
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
);
252 pim_upstream_keep_alive_timer_start (upstream
, PIM_KEEPALIVE_PERIOD
);
256 if (!(upstream
->sptbit
== PIM_UPSTREAM_SPTBIT_TRUE
) &&
257 !(*bits
& PIM_REGISTER_NR_BIT
))
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
,
273 //decapsulate and forward the iner packet to
274 //inherited_olist(S,G,rpt)
277 pim_register_stop_send(src_addr
);
285 pim_register_send_test_packet (struct thread
*t
)
289 packet
= THREAD_ARG(t
);
297 * pim_register_send_test_packet
299 * Send a test packet to the RP from source, in group and pps packets per second
302 pim_register_send_test_packet_start (struct in_addr source
,
303 struct in_addr group
,
306 uint8_t *packet
= NULL
;
308 THREAD_TIMER_MSEC_ON(master
, send_test_packet_timer
,
309 pim_register_send_test_packet
, packet
, 1000/pps
);