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"
39 struct thread
*send_test_packet_timer
= NULL
;
42 * This seems stupidly expensive. A list lookup. Why is this
46 pim_check_is_my_ip_address (struct in_addr dest_addr
)
49 * See if we can short-cut some?
50 * This might not make sense if we ever leave a static RP
51 * type of configuration.
52 * Note - Premature optimization might bite our patooeys' here.
54 if (I_am_RP(dest_addr
) && (dest_addr
.s_addr
== qpim_rp
.rpf_addr
.s_addr
))
57 if (if_lookup_exact_address (&dest_addr
, AF_INET
))
64 pim_register_stop_send (struct in_addr src
)
70 pim_register_send (const struct ip
*ip_hdr
, struct pim_rpf
*rpg
)
72 unsigned char buffer
[3000];
74 struct pim_interface
*pinfo
;
75 struct interface
*ifp
;
78 ifp
= rpg
->source_nexthop
.interface
;
79 pinfo
= (struct pim_interface
*)ifp
->info
;
81 zlog_debug("%s: No pinfo!\n", __PRETTY_FUNCTION__
);
85 memset(buffer
, 0, 3000);
86 b1
= buffer
+ PIM_MSG_REGISTER_LEN
;
88 plen
= ntohs(ip_hdr
->ip_len
);
89 memcpy(b1
, (const unsigned char *)ip_hdr
, plen
);
91 pim_msg_build_header(buffer
, plen
+ PIM_MSG_HEADER_LEN
, PIM_MSG_TYPE_REGISTER
);
93 if (pim_msg_send(pinfo
->pim_sock_fd
,
96 plen
+ PIM_MSG_REGISTER_LEN
,
98 if (PIM_DEBUG_PIM_TRACE
) {
99 zlog_debug("%s: could not send PIM register message on interface %s",
100 __PRETTY_FUNCTION__
, ifp
->name
);
107 * 4.4.2 Receiving Register Messages at the RP
109 * When an RP receives a Register message, the course of action is
110 * decided according to the following pseudocode:
112 * packet_arrives_on_rp_tunnel( pkt ) {
113 * if( outer.dst is not one of my addresses ) {
114 * drop the packet silently.
115 * # Note: this may be a spoofing attempt
117 * if( I_am_RP(G) AND outer.dst == RP(G) ) {
118 * sentRegisterStop = FALSE;
119 * if ( register.borderbit == TRUE ) {
120 * if ( PMBR(S,G) == unknown ) {
121 * PMBR(S,G) = outer.src
122 * } else if ( outer.src != PMBR(S,G) ) {
123 * send Register-Stop(S,G) to outer.src
124 * drop the packet silently.
127 * if ( SPTbit(S,G) OR
128 * ( SwitchToSptDesired(S,G) AND
129 * ( inherited_olist(S,G) == NULL ))) {
130 * send Register-Stop(S,G) to outer.src
131 * sentRegisterStop = TRUE;
133 * if ( SPTbit(S,G) OR SwitchToSptDesired(S,G) ) {
134 * if ( sentRegisterStop == TRUE ) {
135 * set KeepaliveTimer(S,G) to RP_Keepalive_Period;
137 * set KeepaliveTimer(S,G) to Keepalive_Period;
140 * if( !SPTbit(S,G) AND ! pkt.NullRegisterBit ) {
141 * decapsulate and forward the inner packet to
142 * inherited_olist(S,G,rpt) # Note (+)
145 * send Register-Stop(S,G) to outer.src
151 pim_register_recv (struct interface
*ifp
,
152 struct in_addr dest_addr
,
153 struct in_addr src_addr
,
154 uint8_t *tlv_buf
, int tlv_buf_size
)
156 int sentRegisterStop
= 0;
159 struct in_addr group
= { .s_addr
= 0 };
160 struct in_addr source
= { .s_addr
= 0 };
164 if (!pim_check_is_my_ip_address (dest_addr
)) {
165 if (PIM_DEBUG_PIM_PACKETS
) {
168 pim_inet4_dump ("<dst?>", dest_addr
, dest
, sizeof(dest
));
169 zlog_debug ("%s: Received Register message for %s that I do not own", __func__
,
175 #define inherited_olist(S,G) NULL
177 * Please note this is not drawn to get the correct bit/data size
179 * The entirety of the REGISTER packet looks like this:
180 * -------------------------------------------------------------
181 * | Ver | Type | Reserved | Checksum |
182 * |-----------------------------------------------------------|
184 * |-----------------------------------------------------------|
187 * | Packet |--------------------------------------------------|
192 * tlv_buf when received from the caller points at the B bit
193 * We need to know the inner source and dest
195 bits
= (uint32_t *)tlv_buf
;
196 ip_hdr
= (struct ip
*)(tlv_buf
+ PIM_MSG_REGISTER_LEN
);
197 //hlen = (ip_hdr->ip_hl << 2) | PIM_MSG_REGISTER_LEN;
198 //msg = (uint8_t *)tlv_buf + hlen;
199 source
= ip_hdr
->ip_src
;
200 group
= ip_hdr
->ip_dst
;
202 if (I_am_RP (group
) && (dest_addr
.s_addr
== ((RP (group
))->rpf_addr
.s_addr
))) {
203 sentRegisterStop
= 0;
205 if (*bits
& PIM_REGISTER_BORDER_BIT
) {
206 struct in_addr pimbr
= pim_br_get_pmbr (source
, group
);
207 if (PIM_DEBUG_PIM_PACKETS
)
208 zlog_debug("%s: Received Register message with Border bit set", __func__
);
210 if (pimbr
.s_addr
== pim_br_unknown
.s_addr
)
211 pim_br_set_pmbr(source
, group
, src_addr
);
212 else if (src_addr
.s_addr
!= pimbr
.s_addr
) {
213 pim_register_stop_send(src_addr
);
214 if (PIM_DEBUG_PIM_PACKETS
)
215 zlog_debug("%s: Sending register-Stop to %s and dropping mr. packet",
217 /* Drop Packet Silently */
222 struct pim_upstream
*upstream
= pim_upstream_find (source
, group
);
224 * If we don't have a place to send ignore the packet
229 if ((upstream
->sptbit
== PIM_UPSTREAM_SPTBIT_TRUE
) ||
230 ((SwitchToSptDesired(source
, group
)) &&
231 (inherited_olist(source
, group
) == NULL
))) {
232 pim_register_stop_send(src_addr
);
233 sentRegisterStop
= 1;
236 if ((upstream
->sptbit
== PIM_UPSTREAM_SPTBIT_TRUE
) ||
237 (SwitchToSptDesired(source
, group
))) {
238 if (sentRegisterStop
) {
239 pim_upstream_keep_alive_timer_start (upstream
, PIM_RP_KEEPALIVE_PERIOD
);
241 pim_upstream_keep_alive_timer_start (upstream
, PIM_KEEPALIVE_PERIOD
);
245 if (!(upstream
->sptbit
== PIM_UPSTREAM_SPTBIT_TRUE
) &&
246 !(*bits
& PIM_REGISTER_NR_BIT
)) {
247 //decapsulate and forward the iner packet to
248 //inherited_olist(S,G,rpt)
251 pim_register_stop_send(src_addr
);
259 pim_register_send_test_packet (struct thread
*t
)
263 packet
= THREAD_ARG(t
);
271 * pim_register_send_test_packet
273 * Send a test packet to the RP from source, in group and pps packets per second
276 pim_register_send_test_packet_start (struct in_addr source
,
277 struct in_addr group
,
280 uint8_t *packet
= NULL
;
282 THREAD_TIMER_MSEC_ON(master
, send_test_packet_timer
,
283 pim_register_send_test_packet
, packet
, 1000/pps
);