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