Coverage Report

Created: 2026-01-01 06:18

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