]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_msg.c
Merge pull request #101 from LabNConsulting/working/master/patch-set/3-vrf
[mirror_frr.git] / pimd / pim_msg.c
1 /*
2 PIM for Quagga
3 Copyright (C) 2008 Everton da Silva Marques
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; see the file COPYING; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
18 MA 02110-1301 USA
19 */
20
21 #include <zebra.h>
22
23 #include "if.h"
24 #include "log.h"
25 #include "prefix.h"
26 #include "vty.h"
27 #include "plist.h"
28
29 #include "pimd.h"
30 #include "pim_vty.h"
31 #include "pim_pim.h"
32 #include "pim_msg.h"
33 #include "pim_util.h"
34 #include "pim_str.h"
35 #include "pim_iface.h"
36 #include "pim_rp.h"
37 #include "pim_rpf.h"
38
39 void pim_msg_build_header(uint8_t *pim_msg, int pim_msg_size,
40 uint8_t pim_msg_type)
41 {
42 uint16_t checksum;
43
44 zassert(pim_msg_size >= PIM_PIM_MIN_LEN);
45
46 /*
47 * Write header
48 */
49
50 *(uint8_t *) PIM_MSG_HDR_OFFSET_VERSION(pim_msg) = (PIM_PROTO_VERSION << 4) | pim_msg_type;
51 *(uint8_t *) PIM_MSG_HDR_OFFSET_RESERVED(pim_msg) = 0;
52
53 /*
54 * Compute checksum
55 */
56
57 *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) = 0;
58 checksum = in_cksum(pim_msg, pim_msg_size);
59 *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) = checksum;
60 }
61
62 uint8_t *pim_msg_addr_encode_ipv4_ucast(uint8_t *buf,
63 int buf_size,
64 struct in_addr addr)
65 {
66 const int ENCODED_IPV4_UCAST_SIZE = 6;
67
68 if (buf_size < ENCODED_IPV4_UCAST_SIZE) {
69 return 0;
70 }
71
72 buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */
73 buf[1] = '\0'; /* native encoding */
74 memcpy(buf+2, &addr, sizeof(struct in_addr));
75
76 return buf + ENCODED_IPV4_UCAST_SIZE;
77 }
78
79 uint8_t *pim_msg_addr_encode_ipv4_group(uint8_t *buf,
80 int buf_size,
81 struct in_addr addr)
82 {
83 const int ENCODED_IPV4_GROUP_SIZE = 8;
84
85 if (buf_size < ENCODED_IPV4_GROUP_SIZE) {
86 return 0;
87 }
88
89 buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */
90 buf[1] = '\0'; /* native encoding */
91 buf[2] = '\0'; /* reserved */
92 buf[3] = 32; /* mask len */
93 memcpy(buf+4, &addr, sizeof(struct in_addr));
94
95 return buf + ENCODED_IPV4_GROUP_SIZE;
96 }
97
98 uint8_t *
99 pim_msg_addr_encode_ipv4_source(uint8_t *buf, int buf_size,
100 struct in_addr addr, uint8_t bits)
101 {
102 const int ENCODED_IPV4_SOURCE_SIZE = 8;
103
104 if (buf_size < ENCODED_IPV4_SOURCE_SIZE) {
105 return 0;
106 }
107
108 buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */
109 buf[1] = '\0'; /* native encoding */
110 buf[2] = bits;
111 buf[3] = 32; /* mask len */
112 memcpy(buf+4, &addr, sizeof(struct in_addr));
113
114 return buf + ENCODED_IPV4_SOURCE_SIZE;
115 }
116
117 int
118 pim_msg_join_prune_encode (uint8_t *buf, int buf_size, int is_join,
119 struct pim_upstream *up,
120 struct in_addr upstream, int holdtime)
121 {
122 uint8_t *pim_msg = buf;
123 uint8_t *pim_msg_curr = buf + PIM_MSG_HEADER_LEN;
124 uint8_t *end = buf + buf_size;
125 uint16_t *prunes = NULL;
126 uint16_t *joins = NULL;
127 struct in_addr stosend;
128 uint8_t bits;
129 int remain;
130
131 remain = end - pim_msg_curr;
132 pim_msg_curr = pim_msg_addr_encode_ipv4_ucast (pim_msg_curr, buf_size - PIM_MSG_HEADER_LEN, upstream);
133 if (!pim_msg_curr) {
134 char dst_str[INET_ADDRSTRLEN];
135 pim_inet4_dump("<dst?>", upstream, dst_str, sizeof(dst_str));
136 zlog_warn("%s: failure encoding destination address %s: space left=%d",
137 __PRETTY_FUNCTION__, dst_str, remain);
138 return -3;
139 }
140
141 remain = end - pim_msg_curr;
142 if (remain < 4) {
143 zlog_warn("%s: group will not fit: space left=%d",
144 __PRETTY_FUNCTION__, remain);
145 return -4;
146 }
147
148 *pim_msg_curr = 0; /* reserved */
149 ++pim_msg_curr;
150 *pim_msg_curr = 1; /* number of groups */
151 ++pim_msg_curr;
152
153 *((uint16_t *) pim_msg_curr) = htons(holdtime);
154 ++pim_msg_curr;
155 ++pim_msg_curr;
156
157 remain = end - pim_msg_curr;
158 pim_msg_curr = pim_msg_addr_encode_ipv4_group (pim_msg_curr, remain,
159 up->sg.grp);
160 if (!pim_msg_curr) {
161 char group_str[INET_ADDRSTRLEN];
162 pim_inet4_dump("<grp?>", up->sg.grp, group_str, sizeof(group_str));
163 zlog_warn("%s: failure encoding group address %s: space left=%d",
164 __PRETTY_FUNCTION__, group_str, remain);
165 return -5;
166 }
167
168 remain = end - pim_msg_curr;
169 if (remain < 4) {
170 zlog_warn("%s: sources will not fit: space left=%d",
171 __PRETTY_FUNCTION__, remain);
172 return -6;
173 }
174
175 /* number of joined sources */
176 joins = (uint16_t *)pim_msg_curr;
177 *joins = htons(is_join ? 1 : 0);
178 ++pim_msg_curr;
179 ++pim_msg_curr;
180
181 /* number of pruned sources */
182 prunes = (uint16_t *)pim_msg_curr;
183 *prunes = htons(is_join ? 0 : 1);
184 ++pim_msg_curr;
185 ++pim_msg_curr;
186
187 remain = end - pim_msg_curr;
188 if (up->sg.src.s_addr == INADDR_ANY)
189 {
190 struct pim_rpf *rpf = pim_rp_g (up->sg.grp);
191 bits = PIM_ENCODE_SPARSE_BIT | PIM_ENCODE_WC_BIT | PIM_ENCODE_RPT_BIT;
192 stosend = rpf->rpf_addr.u.prefix4;
193 }
194 else
195 {
196 bits = PIM_ENCODE_SPARSE_BIT;
197 stosend = up->sg.src;
198 }
199 pim_msg_curr = pim_msg_addr_encode_ipv4_source (pim_msg_curr, remain, stosend, bits);
200 if (!pim_msg_curr) {
201 char source_str[INET_ADDRSTRLEN];
202 pim_inet4_dump("<src?>", up->sg.src, source_str, sizeof(source_str));
203 zlog_warn("%s: failure encoding source address %s: space left=%d",
204 __PRETTY_FUNCTION__, source_str, remain);
205 return -7;
206 }
207 remain = pim_msg_curr - pim_msg;
208
209 /*
210 * This is not implemented correctly at this point in time
211 * Make it stop.
212 */
213 #if 0
214 if (up->sg.src.s_addr == INADDR_ANY)
215 {
216 struct pim_upstream *child;
217 struct listnode *up_node;
218 int send_prune = 0;
219
220 zlog_debug ("%s: Considering (%s) children for (S,G,rpt) prune",
221 __PRETTY_FUNCTION__, up->sg_str);
222 for (ALL_LIST_ELEMENTS_RO (up->sources, up_node, child))
223 {
224 if (child->sptbit == PIM_UPSTREAM_SPTBIT_TRUE)
225 {
226 if (!pim_rpf_is_same(&up->rpf, &child->rpf))
227 {
228 send_prune = 1;
229 if (PIM_DEBUG_PIM_PACKETS)
230 zlog_debug ("%s: SPT Bit and RPF'(%s) != RPF'(S,G): Add Prune (%s,rpt) to compound message",
231 __PRETTY_FUNCTION__, up->sg_str, child->sg_str);
232 }
233 else
234 if (PIM_DEBUG_PIM_PACKETS)
235 zlog_debug ("%s: SPT Bit and RPF'(%s) == RPF'(S,G): Not adding Prune for (%s,rpt)",
236 __PRETTY_FUNCTION__, up->sg_str, child->sg_str);
237 }
238 else if (pim_upstream_is_sg_rpt (child))
239 {
240 if (pim_upstream_empty_inherited_olist (child))
241 {
242 send_prune = 1;
243 if (PIM_DEBUG_PIM_PACKETS)
244 zlog_debug ("%s: inherited_olist(%s,rpt) is NULL, Add Prune to compound message",
245 __PRETTY_FUNCTION__, child->sg_str);
246 }
247 else if (!pim_rpf_is_same (&up->rpf, &child->rpf))
248 {
249 send_prune = 1;
250 if (PIM_DEBUG_PIM_PACKETS)
251 zlog_debug ("%s: RPF'(%s) != RPF'(%s,rpt), Add Prune to compound message",
252 __PRETTY_FUNCTION__, up->sg_str, child->sg_str);
253 }
254 else
255 if (PIM_DEBUG_PIM_PACKETS)
256 zlog_debug ("%s: RPF'(%s) == RPF'(%s,rpt), Do not add Prune to compound message",
257 __PRETTY_FUNCTION__, up->sg_str, child->sg_str);
258 }
259 else
260 if (PIM_DEBUG_PIM_PACKETS)
261 zlog_debug ("%s: SPT bit is not set for (%s)",
262 __PRETTY_FUNCTION__, child->sg_str);
263 if (send_prune)
264 {
265 pim_msg_curr = pim_msg_addr_encode_ipv4_source (pim_msg_curr, remain,
266 child->sg.src,
267 PIM_ENCODE_SPARSE_BIT | PIM_ENCODE_RPT_BIT);
268 remain = pim_msg_curr - pim_msg;
269 *prunes = htons(ntohs(*prunes) + 1);
270 send_prune = 0;
271 }
272 }
273 }
274 #endif
275 pim_msg_build_header (pim_msg, remain, PIM_MSG_TYPE_JOIN_PRUNE);
276
277 return remain;
278 }