Line data Source code
1 : /*
2 : * IP MSDP packet helper
3 : * Copyright (C) 2016 Cumulus Networks, Inc.
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 along
16 : * with this program; see the file COPYING; if not, write to the Free Software
17 : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 : */
19 : #include <zebra.h>
20 :
21 : #include <lib/log.h>
22 : #include <lib/network.h>
23 : #include <lib/stream.h>
24 : #include <lib/thread.h>
25 : #include <lib/vty.h>
26 : #include <lib/lib_errors.h>
27 :
28 : #include "pimd.h"
29 : #include "pim_instance.h"
30 : #include "pim_str.h"
31 : #include "pim_errors.h"
32 :
33 : #include "pim_msdp.h"
34 : #include "pim_msdp_packet.h"
35 : #include "pim_msdp_socket.h"
36 :
37 0 : static char *pim_msdp_pkt_type_dump(enum pim_msdp_tlv type, char *buf,
38 : int buf_size)
39 : {
40 0 : switch (type) {
41 0 : case PIM_MSDP_V4_SOURCE_ACTIVE:
42 0 : snprintf(buf, buf_size, "%s", "SA");
43 0 : break;
44 0 : case PIM_MSDP_V4_SOURCE_ACTIVE_REQUEST:
45 0 : snprintf(buf, buf_size, "%s", "SA_REQ");
46 0 : break;
47 0 : case PIM_MSDP_V4_SOURCE_ACTIVE_RESPONSE:
48 0 : snprintf(buf, buf_size, "%s", "SA_RESP");
49 0 : break;
50 0 : case PIM_MSDP_KEEPALIVE:
51 0 : snprintf(buf, buf_size, "%s", "KA");
52 0 : break;
53 0 : case PIM_MSDP_RESERVED:
54 0 : snprintf(buf, buf_size, "%s", "RSVD");
55 0 : break;
56 0 : case PIM_MSDP_TRACEROUTE_PROGRESS:
57 0 : snprintf(buf, buf_size, "%s", "TRACE_PROG");
58 0 : break;
59 0 : case PIM_MSDP_TRACEROUTE_REPLY:
60 0 : snprintf(buf, buf_size, "%s", "TRACE_REPLY");
61 0 : break;
62 0 : default:
63 0 : snprintf(buf, buf_size, "UNK-%d", type);
64 : }
65 0 : return buf;
66 : }
67 :
68 0 : static void pim_msdp_pkt_sa_dump_one(struct stream *s)
69 : {
70 0 : pim_sgaddr sg;
71 :
72 : /* just throw away the three reserved bytes */
73 0 : stream_get3(s);
74 : /* throw away the prefix length also */
75 0 : stream_getc(s);
76 :
77 0 : memset(&sg, 0, sizeof(sg));
78 0 : sg.grp.s_addr = stream_get_ipv4(s);
79 0 : sg.src.s_addr = stream_get_ipv4(s);
80 :
81 0 : zlog_debug(" sg %pSG", &sg);
82 0 : }
83 :
84 0 : static void pim_msdp_pkt_sa_dump(struct stream *s)
85 : {
86 0 : const size_t header_length = PIM_MSDP_SA_X_SIZE - PIM_MSDP_HEADER_SIZE;
87 0 : size_t payload_length;
88 0 : int entry_cnt;
89 0 : int i;
90 0 : struct in_addr rp; /* Last RP address associated with this SA */
91 :
92 0 : if (header_length > STREAM_READABLE(s)) {
93 0 : zlog_err("BUG MSDP SA bad header (readable %zu expected %zu)",
94 : STREAM_READABLE(s), header_length);
95 0 : return;
96 : }
97 :
98 0 : entry_cnt = stream_getc(s);
99 0 : rp.s_addr = stream_get_ipv4(s);
100 :
101 0 : if (PIM_DEBUG_MSDP_PACKETS) {
102 0 : char rp_str[INET_ADDRSTRLEN];
103 0 : pim_inet4_dump("<rp?>", rp, rp_str, sizeof(rp_str));
104 0 : zlog_debug(" entry_cnt %d rp %s", entry_cnt, rp_str);
105 : }
106 :
107 0 : payload_length = (size_t)entry_cnt * PIM_MSDP_SA_ONE_ENTRY_SIZE;
108 0 : if (payload_length > STREAM_READABLE(s)) {
109 0 : zlog_err("BUG MSDP SA bad length (readable %zu expected %zu)",
110 : STREAM_READABLE(s), payload_length);
111 0 : return;
112 : }
113 :
114 : /* dump SAs */
115 0 : for (i = 0; i < entry_cnt; ++i) {
116 0 : pim_msdp_pkt_sa_dump_one(s);
117 : }
118 : }
119 :
120 0 : static void pim_msdp_pkt_dump(struct pim_msdp_peer *mp, int type, int len,
121 : bool rx, struct stream *s)
122 : {
123 0 : char type_str[PIM_MSDP_PKT_TYPE_STRLEN];
124 :
125 0 : pim_msdp_pkt_type_dump(type, type_str, sizeof(type_str));
126 :
127 0 : zlog_debug("MSDP peer %s pkt %s type %s len %d", mp->key_str,
128 : rx ? "rx" : "tx", type_str, len);
129 :
130 0 : if (!s) {
131 0 : return;
132 : }
133 :
134 0 : if (len < PIM_MSDP_HEADER_SIZE) {
135 0 : zlog_err("invalid MSDP header length");
136 0 : return;
137 : }
138 :
139 0 : switch (type) {
140 0 : case PIM_MSDP_V4_SOURCE_ACTIVE:
141 0 : pim_msdp_pkt_sa_dump(s);
142 0 : break;
143 0 : default:;
144 : }
145 : }
146 :
147 : /* Check file descriptor whether connect is established. */
148 0 : static void pim_msdp_connect_check(struct pim_msdp_peer *mp)
149 : {
150 0 : int status;
151 0 : socklen_t slen;
152 0 : int ret;
153 :
154 0 : if (mp->state != PIM_MSDP_CONNECTING) {
155 : /* if we are here it means we are not in a connecting or
156 : * established state
157 : * for now treat this as a fatal error */
158 0 : pim_msdp_peer_reset_tcp_conn(mp, "invalid-state");
159 0 : return;
160 : }
161 :
162 0 : PIM_MSDP_PEER_READ_OFF(mp);
163 0 : PIM_MSDP_PEER_WRITE_OFF(mp);
164 :
165 : /* Check file descriptor. */
166 0 : slen = sizeof(status);
167 0 : ret = getsockopt(mp->fd, SOL_SOCKET, SO_ERROR, (void *)&status, &slen);
168 :
169 : /* If getsockopt is fail, this is fatal error. */
170 0 : if (ret < 0) {
171 0 : flog_err_sys(EC_LIB_SOCKET,
172 : "can't get sockopt for nonblocking connect");
173 0 : pim_msdp_peer_reset_tcp_conn(mp, "connect-failed");
174 0 : return;
175 : }
176 :
177 : /* When status is 0 then TCP connection is established. */
178 0 : if (PIM_DEBUG_MSDP_INTERNAL) {
179 0 : zlog_debug("MSDP peer %s pim_connect_check %s", mp->key_str,
180 : status ? "fail" : "success");
181 : }
182 0 : if (status == 0) {
183 0 : pim_msdp_peer_established(mp);
184 : } else {
185 0 : pim_msdp_peer_reset_tcp_conn(mp, "connect-failed");
186 : }
187 : }
188 :
189 0 : static void pim_msdp_pkt_delete(struct pim_msdp_peer *mp)
190 : {
191 0 : stream_free(stream_fifo_pop(mp->obuf));
192 0 : }
193 :
194 0 : static void pim_msdp_pkt_add(struct pim_msdp_peer *mp, struct stream *s)
195 : {
196 0 : stream_fifo_push(mp->obuf, s);
197 : }
198 :
199 0 : static void pim_msdp_write_proceed_actions(struct pim_msdp_peer *mp)
200 : {
201 0 : if (stream_fifo_head(mp->obuf)) {
202 0 : PIM_MSDP_PEER_WRITE_ON(mp);
203 : }
204 0 : }
205 :
206 0 : void pim_msdp_write(struct thread *thread)
207 : {
208 0 : struct pim_msdp_peer *mp;
209 0 : struct stream *s;
210 0 : int num;
211 0 : enum pim_msdp_tlv type;
212 0 : int len;
213 0 : int work_cnt = 0;
214 0 : int work_max_cnt = 100;
215 :
216 0 : mp = THREAD_ARG(thread);
217 0 : mp->t_write = NULL;
218 :
219 0 : if (PIM_DEBUG_MSDP_INTERNAL) {
220 0 : zlog_debug("MSDP peer %s pim_msdp_write", mp->key_str);
221 : }
222 0 : if (mp->fd < 0) {
223 : return;
224 : }
225 :
226 : /* check if TCP connection is established */
227 0 : if (mp->state != PIM_MSDP_ESTABLISHED) {
228 0 : pim_msdp_connect_check(mp);
229 0 : return;
230 : }
231 :
232 0 : s = stream_fifo_head(mp->obuf);
233 0 : if (!s) {
234 0 : pim_msdp_write_proceed_actions(mp);
235 0 : return;
236 : }
237 :
238 : /* Nonblocking write until TCP output buffer is full */
239 0 : do {
240 0 : int writenum;
241 :
242 : /* Number of bytes to be sent */
243 0 : writenum = stream_get_endp(s) - stream_get_getp(s);
244 :
245 : /* Call write() system call */
246 0 : num = write(mp->fd, stream_pnt(s), writenum);
247 0 : if (num < 0) {
248 : /* write failed either retry needed or error */
249 0 : if (ERRNO_IO_RETRY(errno)) {
250 0 : if (PIM_DEBUG_MSDP_INTERNAL) {
251 0 : zlog_debug(
252 : "MSDP peer %s pim_msdp_write io retry",
253 : mp->key_str);
254 : }
255 : break;
256 : }
257 :
258 0 : pim_msdp_peer_reset_tcp_conn(mp, "pkt-tx-failed");
259 0 : return;
260 : }
261 :
262 0 : if (num != writenum) {
263 : /* Partial write */
264 0 : stream_forward_getp(s, num);
265 0 : if (PIM_DEBUG_MSDP_INTERNAL) {
266 0 : zlog_debug(
267 : "MSDP peer %s pim_msdp_partial_write",
268 : mp->key_str);
269 : }
270 : break;
271 : }
272 :
273 : /* Retrieve msdp packet type. */
274 0 : stream_set_getp(s, 0);
275 0 : type = stream_getc(s);
276 0 : len = stream_getw(s);
277 0 : switch (type) {
278 0 : case PIM_MSDP_KEEPALIVE:
279 0 : mp->ka_tx_cnt++;
280 0 : break;
281 0 : case PIM_MSDP_V4_SOURCE_ACTIVE:
282 0 : mp->sa_tx_cnt++;
283 0 : break;
284 : case PIM_MSDP_V4_SOURCE_ACTIVE_REQUEST:
285 : case PIM_MSDP_V4_SOURCE_ACTIVE_RESPONSE:
286 : case PIM_MSDP_RESERVED:
287 : case PIM_MSDP_TRACEROUTE_PROGRESS:
288 : case PIM_MSDP_TRACEROUTE_REPLY:
289 : break;
290 : }
291 0 : if (PIM_DEBUG_MSDP_PACKETS) {
292 0 : pim_msdp_pkt_dump(mp, type, len, false /*rx*/, s);
293 : }
294 :
295 : /* packet sent delete it. */
296 0 : pim_msdp_pkt_delete(mp);
297 :
298 0 : ++work_cnt;
299 : /* may need to pause if we have done too much work in this
300 : * loop */
301 0 : if (work_cnt >= work_max_cnt) {
302 : break;
303 : }
304 0 : } while ((s = stream_fifo_head(mp->obuf)) != NULL);
305 0 : pim_msdp_write_proceed_actions(mp);
306 :
307 0 : if (PIM_DEBUG_MSDP_INTERNAL) {
308 0 : zlog_debug("MSDP peer %s pim_msdp_write wrote %d packets",
309 : mp->key_str, work_cnt);
310 : }
311 : }
312 :
313 0 : static void pim_msdp_pkt_send(struct pim_msdp_peer *mp, struct stream *s)
314 : {
315 : /* Add packet to the end of list. */
316 0 : pim_msdp_pkt_add(mp, s);
317 :
318 0 : PIM_MSDP_PEER_WRITE_ON(mp);
319 0 : }
320 :
321 0 : void pim_msdp_pkt_ka_tx(struct pim_msdp_peer *mp)
322 : {
323 0 : struct stream *s;
324 :
325 0 : if (mp->state != PIM_MSDP_ESTABLISHED) {
326 : /* don't tx anything unless a session is established */
327 : return;
328 : }
329 0 : s = stream_new(PIM_MSDP_KA_TLV_MAX_SIZE);
330 0 : stream_putc(s, PIM_MSDP_KEEPALIVE);
331 0 : stream_putw(s, PIM_MSDP_KA_TLV_MAX_SIZE);
332 :
333 0 : pim_msdp_pkt_send(mp, s);
334 : }
335 :
336 0 : static void pim_msdp_pkt_sa_push_to_one_peer(struct pim_instance *pim,
337 : struct pim_msdp_peer *mp)
338 : {
339 0 : struct stream *s;
340 :
341 0 : if (mp->state != PIM_MSDP_ESTABLISHED) {
342 : /* don't tx anything unless a session is established */
343 : return;
344 : }
345 0 : s = stream_dup(pim->msdp.work_obuf);
346 0 : if (s) {
347 0 : pim_msdp_pkt_send(mp, s);
348 0 : mp->flags |= PIM_MSDP_PEERF_SA_JUST_SENT;
349 : }
350 : }
351 :
352 : /* push the stream into the obuf fifo of all the peers */
353 0 : static void pim_msdp_pkt_sa_push(struct pim_instance *pim,
354 : struct pim_msdp_peer *mp)
355 : {
356 0 : struct listnode *mpnode;
357 :
358 0 : if (mp) {
359 0 : pim_msdp_pkt_sa_push_to_one_peer(pim, mp);
360 : } else {
361 0 : for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, mpnode, mp)) {
362 0 : if (PIM_DEBUG_MSDP_INTERNAL) {
363 0 : zlog_debug("MSDP peer %s pim_msdp_pkt_sa_push",
364 : mp->key_str);
365 : }
366 0 : pim_msdp_pkt_sa_push_to_one_peer(pim, mp);
367 : }
368 : }
369 0 : }
370 :
371 0 : static int pim_msdp_pkt_sa_fill_hdr(struct pim_instance *pim, int local_cnt,
372 : struct in_addr rp)
373 : {
374 0 : int curr_tlv_ecnt;
375 :
376 0 : stream_reset(pim->msdp.work_obuf);
377 0 : curr_tlv_ecnt = local_cnt > PIM_MSDP_SA_MAX_ENTRY_CNT
378 : ? PIM_MSDP_SA_MAX_ENTRY_CNT
379 : : local_cnt;
380 0 : local_cnt -= curr_tlv_ecnt;
381 0 : stream_putc(pim->msdp.work_obuf, PIM_MSDP_V4_SOURCE_ACTIVE);
382 0 : stream_putw(pim->msdp.work_obuf,
383 0 : PIM_MSDP_SA_ENTRY_CNT2SIZE(curr_tlv_ecnt));
384 0 : stream_putc(pim->msdp.work_obuf, curr_tlv_ecnt);
385 0 : stream_put_ipv4(pim->msdp.work_obuf, rp.s_addr);
386 :
387 0 : return local_cnt;
388 : }
389 :
390 0 : static void pim_msdp_pkt_sa_fill_one(struct pim_msdp_sa *sa)
391 : {
392 0 : stream_put3(sa->pim->msdp.work_obuf, 0 /* reserved */);
393 0 : stream_putc(sa->pim->msdp.work_obuf, 32 /* sprefix len */);
394 0 : stream_put_ipv4(sa->pim->msdp.work_obuf, sa->sg.grp.s_addr);
395 0 : stream_put_ipv4(sa->pim->msdp.work_obuf, sa->sg.src.s_addr);
396 0 : }
397 :
398 0 : static void pim_msdp_pkt_sa_gen(struct pim_instance *pim,
399 : struct pim_msdp_peer *mp)
400 : {
401 0 : struct listnode *sanode;
402 0 : struct pim_msdp_sa *sa;
403 0 : int sa_count;
404 0 : int local_cnt = pim->msdp.local_cnt;
405 :
406 0 : sa_count = 0;
407 0 : if (PIM_DEBUG_MSDP_INTERNAL) {
408 0 : zlog_debug(" sa gen %d", local_cnt);
409 : }
410 :
411 0 : local_cnt = pim_msdp_pkt_sa_fill_hdr(pim, local_cnt,
412 : pim->msdp.originator_id);
413 :
414 0 : for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) {
415 0 : if (!(sa->flags & PIM_MSDP_SAF_LOCAL)) {
416 : /* current implementation of MSDP is for anycast i.e.
417 : * full mesh. so
418 : * no re-forwarding of SAs that we learnt from other
419 : * peers */
420 0 : continue;
421 : }
422 : /* add sa into scratch pad */
423 0 : pim_msdp_pkt_sa_fill_one(sa);
424 0 : ++sa_count;
425 0 : if (sa_count >= PIM_MSDP_SA_MAX_ENTRY_CNT) {
426 0 : pim_msdp_pkt_sa_push(pim, mp);
427 : /* reset headers */
428 0 : sa_count = 0;
429 0 : if (PIM_DEBUG_MSDP_INTERNAL) {
430 0 : zlog_debug(" sa gen for remainder %d",
431 : local_cnt);
432 : }
433 0 : local_cnt = pim_msdp_pkt_sa_fill_hdr(
434 : pim, local_cnt, pim->msdp.originator_id);
435 : }
436 : }
437 :
438 0 : if (sa_count) {
439 0 : pim_msdp_pkt_sa_push(pim, mp);
440 : }
441 0 : return;
442 : }
443 :
444 0 : static void pim_msdp_pkt_sa_tx_done(struct pim_instance *pim)
445 : {
446 0 : struct listnode *mpnode;
447 0 : struct pim_msdp_peer *mp;
448 :
449 : /* if SA were sent to the peers we restart ka timer and avoid
450 : * unnecessary ka noise */
451 0 : for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, mpnode, mp)) {
452 0 : if (mp->flags & PIM_MSDP_PEERF_SA_JUST_SENT) {
453 0 : mp->flags &= ~PIM_MSDP_PEERF_SA_JUST_SENT;
454 0 : pim_msdp_peer_pkt_txed(mp);
455 : }
456 : }
457 0 : }
458 :
459 0 : void pim_msdp_pkt_sa_tx(struct pim_instance *pim)
460 : {
461 0 : pim_msdp_pkt_sa_gen(pim, NULL /* mp */);
462 0 : pim_msdp_pkt_sa_tx_done(pim);
463 0 : }
464 :
465 0 : void pim_msdp_pkt_sa_tx_one(struct pim_msdp_sa *sa)
466 : {
467 0 : pim_msdp_pkt_sa_fill_hdr(sa->pim, 1 /* cnt */, sa->rp);
468 0 : pim_msdp_pkt_sa_fill_one(sa);
469 0 : pim_msdp_pkt_sa_push(sa->pim, NULL);
470 0 : pim_msdp_pkt_sa_tx_done(sa->pim);
471 0 : }
472 :
473 : /* when a connection is first established we push all SAs immediately */
474 0 : void pim_msdp_pkt_sa_tx_to_one_peer(struct pim_msdp_peer *mp)
475 : {
476 0 : pim_msdp_pkt_sa_gen(mp->pim, mp);
477 0 : pim_msdp_pkt_sa_tx_done(mp->pim);
478 0 : }
479 :
480 0 : void pim_msdp_pkt_sa_tx_one_to_one_peer(struct pim_msdp_peer *mp,
481 : struct in_addr rp, pim_sgaddr sg)
482 : {
483 0 : struct pim_msdp_sa sa;
484 :
485 : /* Fills the SA header. */
486 0 : pim_msdp_pkt_sa_fill_hdr(mp->pim, 1, rp);
487 :
488 : /* Fills the message contents. */
489 0 : sa.pim = mp->pim;
490 0 : sa.sg = sg;
491 0 : pim_msdp_pkt_sa_fill_one(&sa);
492 :
493 : /* Pushes the message. */
494 0 : pim_msdp_pkt_sa_push(sa.pim, mp);
495 0 : pim_msdp_pkt_sa_tx_done(sa.pim);
496 0 : }
497 :
498 0 : static void pim_msdp_pkt_rxed_with_fatal_error(struct pim_msdp_peer *mp)
499 : {
500 0 : pim_msdp_peer_reset_tcp_conn(mp, "invalid-pkt-rx");
501 : }
502 :
503 0 : static void pim_msdp_pkt_ka_rx(struct pim_msdp_peer *mp, int len)
504 : {
505 0 : mp->ka_rx_cnt++;
506 0 : if (len != PIM_MSDP_KA_TLV_MAX_SIZE) {
507 0 : pim_msdp_pkt_rxed_with_fatal_error(mp);
508 0 : return;
509 : }
510 0 : pim_msdp_peer_pkt_rxed(mp);
511 : }
512 :
513 0 : static void pim_msdp_pkt_sa_rx_one(struct pim_msdp_peer *mp, struct in_addr rp)
514 : {
515 0 : int prefix_len;
516 0 : pim_sgaddr sg;
517 0 : struct listnode *peer_node;
518 0 : struct pim_msdp_peer *peer;
519 :
520 : /* just throw away the three reserved bytes */
521 0 : stream_get3(mp->ibuf);
522 0 : prefix_len = stream_getc(mp->ibuf);
523 :
524 0 : memset(&sg, 0, sizeof(sg));
525 0 : sg.grp.s_addr = stream_get_ipv4(mp->ibuf);
526 0 : sg.src.s_addr = stream_get_ipv4(mp->ibuf);
527 :
528 0 : if (prefix_len != IPV4_MAX_BITLEN) {
529 : /* ignore SA update if the prefix length is not 32 */
530 0 : flog_err(EC_PIM_MSDP_PACKET,
531 : "rxed sa update with invalid prefix length %d",
532 : prefix_len);
533 0 : return;
534 : }
535 0 : if (PIM_DEBUG_MSDP_PACKETS) {
536 0 : zlog_debug(" sg %pSG", &sg);
537 : }
538 0 : pim_msdp_sa_ref(mp->pim, mp, &sg, rp);
539 :
540 : /* Forwards the SA to the peers that are not in the RPF to the RP nor in
541 : * the same mesh group as the peer from which we received the message.
542 : * If the message group is not set, i.e. "default", then we assume that
543 : * the message must be forwarded.*/
544 0 : for (ALL_LIST_ELEMENTS_RO(mp->pim->msdp.peer_list, peer_node, peer)) {
545 : /* Not a RPF peer, so skip it. */
546 0 : if (pim_msdp_peer_rpf_check(peer, rp))
547 0 : continue;
548 : /* Don't forward inside the meshed group. */
549 0 : if ((mp->flags & PIM_MSDP_PEERF_IN_GROUP)
550 0 : && strcmp(mp->mesh_group_name, peer->mesh_group_name) == 0)
551 0 : continue;
552 :
553 0 : pim_msdp_pkt_sa_tx_one_to_one_peer(peer, rp, sg);
554 : }
555 : }
556 :
557 0 : static void pim_msdp_pkt_sa_rx(struct pim_msdp_peer *mp, int len)
558 : {
559 0 : int entry_cnt;
560 0 : int i;
561 0 : struct in_addr rp; /* Last RP address associated with this SA */
562 :
563 0 : mp->sa_rx_cnt++;
564 :
565 0 : if (len < PIM_MSDP_SA_TLV_MIN_SIZE) {
566 0 : pim_msdp_pkt_rxed_with_fatal_error(mp);
567 0 : return;
568 : }
569 :
570 0 : entry_cnt = stream_getc(mp->ibuf);
571 : /* some vendors include the actual multicast data in the tlv (at the
572 : * end). we will ignore such data. in the future we may consider pushing
573 : * it down the RPT
574 : */
575 0 : if (len < PIM_MSDP_SA_ENTRY_CNT2SIZE(entry_cnt)) {
576 0 : pim_msdp_pkt_rxed_with_fatal_error(mp);
577 0 : return;
578 : }
579 0 : rp.s_addr = stream_get_ipv4(mp->ibuf);
580 :
581 0 : if (PIM_DEBUG_MSDP_PACKETS) {
582 0 : char rp_str[INET_ADDRSTRLEN];
583 0 : pim_inet4_dump("<rp?>", rp, rp_str, sizeof(rp_str));
584 0 : zlog_debug(" entry_cnt %d rp %s", entry_cnt, rp_str);
585 : }
586 :
587 0 : pim_msdp_peer_pkt_rxed(mp);
588 :
589 0 : if (!pim_msdp_peer_rpf_check(mp, rp)) {
590 : /* if peer-RPF check fails don't process the packet any further
591 : */
592 0 : if (PIM_DEBUG_MSDP_PACKETS) {
593 0 : zlog_debug(" peer RPF check failed");
594 : }
595 0 : return;
596 : }
597 :
598 : /* update SA cache */
599 0 : for (i = 0; i < entry_cnt; ++i) {
600 0 : pim_msdp_pkt_sa_rx_one(mp, rp);
601 : }
602 : }
603 :
604 0 : static void pim_msdp_pkt_rx(struct pim_msdp_peer *mp)
605 : {
606 0 : enum pim_msdp_tlv type;
607 0 : int len;
608 :
609 : /* re-read type and len */
610 0 : type = stream_getc_from(mp->ibuf, 0);
611 0 : len = stream_getw_from(mp->ibuf, 1);
612 0 : if (len < PIM_MSDP_HEADER_SIZE) {
613 0 : pim_msdp_pkt_rxed_with_fatal_error(mp);
614 0 : return;
615 : }
616 :
617 0 : if (len > PIM_MSDP_SA_TLV_MAX_SIZE) {
618 : /* if tlv size if greater than max just ignore the tlv */
619 : return;
620 : }
621 :
622 0 : if (PIM_DEBUG_MSDP_PACKETS) {
623 0 : pim_msdp_pkt_dump(mp, type, len, true /*rx*/, NULL /*s*/);
624 : }
625 :
626 0 : switch (type) {
627 0 : case PIM_MSDP_KEEPALIVE:
628 0 : pim_msdp_pkt_ka_rx(mp, len);
629 0 : break;
630 0 : case PIM_MSDP_V4_SOURCE_ACTIVE:
631 0 : mp->sa_rx_cnt++;
632 0 : pim_msdp_pkt_sa_rx(mp, len);
633 0 : break;
634 0 : case PIM_MSDP_V4_SOURCE_ACTIVE_REQUEST:
635 : case PIM_MSDP_V4_SOURCE_ACTIVE_RESPONSE:
636 : case PIM_MSDP_RESERVED:
637 : case PIM_MSDP_TRACEROUTE_PROGRESS:
638 : case PIM_MSDP_TRACEROUTE_REPLY:
639 0 : mp->unk_rx_cnt++;
640 0 : break;
641 : }
642 : }
643 :
644 : /* pim msdp read utility function. */
645 0 : static int pim_msdp_read_packet(struct pim_msdp_peer *mp)
646 : {
647 0 : int nbytes;
648 0 : int readsize;
649 0 : int old_endp;
650 0 : int new_endp;
651 :
652 0 : old_endp = stream_get_endp(mp->ibuf);
653 0 : readsize = mp->packet_size - old_endp;
654 0 : if (!readsize) {
655 : return 0;
656 : }
657 :
658 : /* Read packet from fd */
659 0 : nbytes = stream_read_try(mp->ibuf, mp->fd, readsize);
660 0 : new_endp = stream_get_endp(mp->ibuf);
661 0 : if (nbytes < 0) {
662 0 : if (PIM_DEBUG_MSDP_INTERNAL) {
663 0 : zlog_debug("MSDP peer %s read failed %d", mp->key_str,
664 : nbytes);
665 : }
666 0 : if (nbytes == -2) {
667 0 : if (PIM_DEBUG_MSDP_INTERNAL) {
668 0 : zlog_debug(
669 : "MSDP peer %s pim_msdp_read io retry old_end: %d new_end: %d",
670 : mp->key_str, old_endp, new_endp);
671 : }
672 : /* transient error retry */
673 0 : return -1;
674 : }
675 0 : pim_msdp_pkt_rxed_with_fatal_error(mp);
676 0 : return -1;
677 : }
678 :
679 0 : if (!nbytes) {
680 0 : if (PIM_DEBUG_MSDP_INTERNAL) {
681 0 : zlog_debug("MSDP peer %s read failed %d", mp->key_str,
682 : nbytes);
683 : }
684 0 : pim_msdp_peer_reset_tcp_conn(mp, "peer-down");
685 0 : return -1;
686 : }
687 :
688 : /* We read partial packet. */
689 0 : if (stream_get_endp(mp->ibuf) != mp->packet_size) {
690 0 : if (PIM_DEBUG_MSDP_INTERNAL) {
691 0 : zlog_debug(
692 : "MSDP peer %s read partial len %d old_endp %d new_endp %d",
693 : mp->key_str, mp->packet_size, old_endp,
694 : new_endp);
695 : }
696 0 : return -1;
697 : }
698 :
699 : return 0;
700 : }
701 :
702 0 : void pim_msdp_read(struct thread *thread)
703 : {
704 0 : struct pim_msdp_peer *mp;
705 0 : int rc;
706 0 : uint32_t len;
707 :
708 0 : mp = THREAD_ARG(thread);
709 0 : mp->t_read = NULL;
710 :
711 0 : if (PIM_DEBUG_MSDP_INTERNAL) {
712 0 : zlog_debug("MSDP peer %s pim_msdp_read", mp->key_str);
713 : }
714 :
715 0 : if (mp->fd < 0) {
716 : return;
717 : }
718 :
719 : /* check if TCP connection is established */
720 0 : if (mp->state != PIM_MSDP_ESTABLISHED) {
721 0 : pim_msdp_connect_check(mp);
722 0 : return;
723 : }
724 :
725 0 : PIM_MSDP_PEER_READ_ON(mp);
726 :
727 0 : if (!mp->packet_size) {
728 0 : mp->packet_size = PIM_MSDP_HEADER_SIZE;
729 : }
730 :
731 0 : if (stream_get_endp(mp->ibuf) < PIM_MSDP_HEADER_SIZE) {
732 : /* start by reading the TLV header */
733 0 : rc = pim_msdp_read_packet(mp);
734 0 : if (rc < 0)
735 : return;
736 :
737 : /* Find TLV type and len */
738 0 : stream_getc(mp->ibuf);
739 0 : len = stream_getw(mp->ibuf);
740 0 : if (len < PIM_MSDP_HEADER_SIZE) {
741 0 : pim_msdp_pkt_rxed_with_fatal_error(mp);
742 0 : return;
743 : }
744 :
745 : /*
746 : * Handle messages with longer than expected TLV size: resize
747 : * the stream to handle reading the whole message.
748 : *
749 : * RFC 3618 Section 12. 'Packet Formats':
750 : * > ... If an implementation receives a TLV whose length
751 : * > exceeds the maximum TLV length specified below, the TLV
752 : * > SHOULD be accepted. Any additional data, including possible
753 : * > next TLV's in the same message, SHOULD be ignored, and the
754 : * > MSDP session should not be reset. ...
755 : */
756 0 : if (len > PIM_MSDP_SA_TLV_MAX_SIZE) {
757 : /* Check if the current buffer is big enough. */
758 0 : if (mp->ibuf->size < len) {
759 0 : if (PIM_DEBUG_MSDP_PACKETS)
760 0 : zlog_debug(
761 : "MSDP peer %s sent TLV with unexpected large length (%d bytes)",
762 : mp->key_str, len);
763 :
764 0 : stream_resize_inplace(&mp->ibuf, len);
765 : }
766 : }
767 :
768 : /* read complete TLV */
769 0 : mp->packet_size = len;
770 : }
771 :
772 0 : rc = pim_msdp_read_packet(mp);
773 0 : if (rc < 0)
774 : return;
775 :
776 0 : pim_msdp_pkt_rx(mp);
777 :
778 : /* reset input buffers and get ready for the next packet */
779 0 : mp->packet_size = 0;
780 0 : stream_reset(mp->ibuf);
781 : }
|