Coverage Report

Created: 2025-08-26 06:20

/src/frr/pimd/pim_pim.c
Line
Count
Source (jump to first uncovered line)
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 * PIM for Quagga
4
 * Copyright (C) 2008  Everton da Silva Marques
5
 */
6
7
#include <zebra.h>
8
9
#include "log.h"
10
#include "frrevent.h"
11
#include "memory.h"
12
#include "if.h"
13
#include "network.h"
14
15
#include "pimd.h"
16
#include "pim_instance.h"
17
#include "pim_pim.h"
18
#include "pim_time.h"
19
#include "pim_iface.h"
20
#include "pim_sock.h"
21
#include "pim_str.h"
22
#include "pim_util.h"
23
#include "pim_tlv.h"
24
#include "pim_neighbor.h"
25
#include "pim_hello.h"
26
#include "pim_join.h"
27
#include "pim_assert.h"
28
#include "pim_msg.h"
29
#include "pim_register.h"
30
#include "pim_errors.h"
31
#include "pim_bsm.h"
32
#include <lib/lib_errors.h>
33
34
static void on_pim_hello_send(struct event *t);
35
36
static const char *pim_pim_msgtype2str(enum pim_msg_type type)
37
0
{
38
0
  switch (type) {
39
0
  case PIM_MSG_TYPE_HELLO:
40
0
    return "HELLO";
41
0
  case PIM_MSG_TYPE_REGISTER:
42
0
    return "REGISTER";
43
0
  case PIM_MSG_TYPE_REG_STOP:
44
0
    return "REGSTOP";
45
0
  case PIM_MSG_TYPE_JOIN_PRUNE:
46
0
    return "JOINPRUNE";
47
0
  case PIM_MSG_TYPE_BOOTSTRAP:
48
0
    return "BOOT";
49
0
  case PIM_MSG_TYPE_ASSERT:
50
0
    return "ASSERT";
51
0
  case PIM_MSG_TYPE_GRAFT:
52
0
    return "GRAFT";
53
0
  case PIM_MSG_TYPE_GRAFT_ACK:
54
0
    return "GACK";
55
0
  case PIM_MSG_TYPE_CANDIDATE:
56
0
    return "CANDIDATE";
57
0
  }
58
0
59
0
  return "UNKNOWN";
60
0
}
61
62
static void sock_close(struct interface *ifp)
63
0
{
64
0
  struct pim_interface *pim_ifp = ifp->info;
65
66
0
  if (PIM_DEBUG_PIM_TRACE) {
67
0
    if (pim_ifp->t_pim_sock_read) {
68
0
      zlog_debug(
69
0
        "Cancelling READ event for PIM socket fd=%d on interface %s",
70
0
        pim_ifp->pim_sock_fd, ifp->name);
71
0
    }
72
0
  }
73
0
  EVENT_OFF(pim_ifp->t_pim_sock_read);
74
75
0
  if (PIM_DEBUG_PIM_TRACE) {
76
0
    if (pim_ifp->t_pim_hello_timer) {
77
0
      zlog_debug(
78
0
        "Cancelling PIM hello timer for interface %s",
79
0
        ifp->name);
80
0
    }
81
0
  }
82
0
  EVENT_OFF(pim_ifp->t_pim_hello_timer);
83
84
0
  if (PIM_DEBUG_PIM_TRACE) {
85
0
    zlog_debug("Deleting PIM socket fd=%d on interface %s",
86
0
         pim_ifp->pim_sock_fd, ifp->name);
87
0
  }
88
89
  /*
90
   * If the fd is already deleted no need to do anything here
91
   */
92
0
  if (pim_ifp->pim_sock_fd > 0 && close(pim_ifp->pim_sock_fd)) {
93
0
    zlog_warn(
94
0
      "Failure closing PIM socket fd=%d on interface %s: errno=%d: %s",
95
0
      pim_ifp->pim_sock_fd, ifp->name, errno,
96
0
      safe_strerror(errno));
97
0
  }
98
99
0
  pim_ifp->pim_sock_fd = -1;
100
0
  pim_ifp->pim_sock_creation = 0;
101
0
}
102
103
void pim_sock_delete(struct interface *ifp, const char *delete_message)
104
0
{
105
0
  zlog_info("PIM INTERFACE DOWN: on interface %s: %s", ifp->name,
106
0
      delete_message);
107
108
0
  if (!ifp->info) {
109
0
    flog_err(EC_PIM_CONFIG,
110
0
       "%s: %s: but PIM not enabled on interface %s (!)",
111
0
       __func__, delete_message, ifp->name);
112
0
    return;
113
0
  }
114
115
  /*
116
    RFC 4601: 4.3.1.  Sending Hello Messages
117
118
    Before an interface goes down or changes primary IP address, a Hello
119
    message with a zero HoldTime should be sent immediately (with the
120
    old IP address if the IP address changed).
121
  */
122
0
  pim_hello_send(ifp, 0 /* zero-sec holdtime */);
123
124
0
  pim_neighbor_delete_all(ifp, delete_message);
125
126
0
  sock_close(ifp);
127
0
}
128
129
/* For now check dst address for hello, assrt and join/prune is all pim rtr */
130
static bool pim_pkt_dst_addr_ok(enum pim_msg_type type, pim_addr addr)
131
3.23k
{
132
3.23k
  if ((type == PIM_MSG_TYPE_HELLO) || (type == PIM_MSG_TYPE_ASSERT)
133
3.23k
      || (type == PIM_MSG_TYPE_JOIN_PRUNE)) {
134
1.72k
    if (pim_addr_cmp(addr, qpim_all_pim_routers_addr))
135
13
      return false;
136
1.72k
  }
137
138
3.22k
  return true;
139
3.23k
}
140
141
int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len,
142
       pim_sgaddr sg)
143
3.27k
{
144
3.27k
  struct iovec iov[2], *iovp = iov;
145
3.27k
#if PIM_IPV == 4
146
3.27k
  struct ip *ip_hdr = (struct ip *)buf;
147
3.27k
  size_t ip_hlen; /* ip header length in bytes */
148
3.27k
#endif
149
3.27k
  uint8_t *pim_msg;
150
3.27k
  uint32_t pim_msg_len = 0;
151
3.27k
  uint16_t pim_checksum; /* received checksum */
152
3.27k
  uint16_t checksum;     /* computed checksum */
153
3.27k
  struct pim_neighbor *neigh;
154
3.27k
  struct pim_msg_header *header;
155
3.27k
  bool   no_fwd;
156
157
3.27k
#if PIM_IPV == 4
158
3.27k
  if (len <= sizeof(*ip_hdr)) {
159
9
    if (PIM_DEBUG_PIM_PACKETS)
160
0
      zlog_debug(
161
9
        "PIM packet size=%zu shorter than minimum=%zu",
162
9
        len, sizeof(*ip_hdr));
163
9
    return -1;
164
9
  }
165
166
3.26k
  ip_hlen = ip_hdr->ip_hl << 2; /* ip_hl gives length in 4-byte words */
167
3.26k
#ifdef FUZZING
168
  /*
169
   * Ensure that the header length is 20 or 24 bytes as is appropriate
170
   * The kernel typically ensures that the passed up ip header meets
171
   * standards, and would actually drop the packet if it didn't meet
172
   * them.  So since we are fuzzing and faking the header bits/bobs
173
   * then let's ensure that we don't get into a weird situation
174
   * where a bad ip_hlen here causes pim_msg_len to wrap around into
175
   * the high billions and then we have an issue later
176
   */
177
3.26k
  if (ip_hlen != 20 && ip_hlen != 24)
178
14
    return -1;
179
3.24k
#endif
180
3.24k
  sg = pim_sgaddr_from_iphdr(ip_hdr);
181
182
3.24k
  pim_msg = buf + ip_hlen;
183
3.24k
  pim_msg_len = len - ip_hlen;
184
#else
185
  struct ipv6_ph phdr = {
186
    .src = sg.src,
187
    .dst = sg.grp,
188
    .ulpl = htonl(len),
189
    .next_hdr = IPPROTO_PIM,
190
  };
191
192
  iovp->iov_base = &phdr;
193
  iovp->iov_len = sizeof(phdr);
194
  iovp++;
195
196
  /* NB: header is not included in IPv6 RX */
197
  pim_msg = buf;
198
  pim_msg_len = len;
199
#endif
200
201
3.24k
  iovp->iov_base = pim_msg;
202
3.24k
  iovp->iov_len = pim_msg_len;
203
3.24k
  iovp++;
204
205
3.24k
  if (pim_msg_len < PIM_PIM_MIN_LEN) {
206
7
    if (PIM_DEBUG_PIM_PACKETS)
207
0
      zlog_debug(
208
7
        "PIM message size=%d shorter than minimum=%d",
209
7
        pim_msg_len, PIM_PIM_MIN_LEN);
210
7
    return -1;
211
7
  }
212
3.24k
  header = (struct pim_msg_header *)pim_msg;
213
214
3.24k
  if (header->ver != PIM_PROTO_VERSION) {
215
5
    if (PIM_DEBUG_PIM_PACKETS)
216
0
      zlog_debug(
217
5
        "Ignoring PIM pkt from %s with unsupported version: %d",
218
5
        ifp->name, header->ver);
219
5
    return -1;
220
5
  }
221
222
  /* save received checksum */
223
3.23k
  pim_checksum = header->checksum;
224
225
  /* for computing checksum */
226
3.23k
  header->checksum = 0;
227
3.23k
  no_fwd = header->Nbit;
228
229
3.23k
  if (header->type == PIM_MSG_TYPE_REGISTER) {
230
152
    if (pim_msg_len < PIM_MSG_REGISTER_LEN) {
231
3
      if (PIM_DEBUG_PIM_PACKETS)
232
0
        zlog_debug("PIM Register Message size=%d shorther than min length %d",
233
3
             pim_msg_len, PIM_MSG_REGISTER_LEN);
234
3
      return -1;
235
3
    }
236
237
#if PIM_IPV == 6
238
    phdr.ulpl = htonl(PIM_MSG_REGISTER_LEN);
239
#endif
240
    /* First 8 byte header checksum */
241
149
    iovp[-1].iov_len = PIM_MSG_REGISTER_LEN;
242
149
    checksum = in_cksumv(iov, iovp - iov);
243
244
149
    if (checksum != pim_checksum) {
245
#if PIM_IPV == 6
246
      phdr.ulpl = htonl(pim_msg_len);
247
#endif
248
148
      iovp[-1].iov_len = pim_msg_len;
249
250
148
      checksum = in_cksumv(iov, iovp - iov);
251
148
      if (checksum != pim_checksum) {
252
148
        if (PIM_DEBUG_PIM_PACKETS)
253
0
          zlog_debug(
254
148
            "Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
255
148
            ifp->name, pim_checksum,
256
148
            checksum);
257
#ifndef FUZZING
258
        return -1;
259
#endif
260
148
      }
261
148
    }
262
3.08k
  } else {
263
3.08k
    checksum = in_cksumv(iov, iovp - iov);
264
3.08k
    if (checksum != pim_checksum) {
265
3.08k
      if (PIM_DEBUG_PIM_PACKETS)
266
0
        zlog_debug(
267
3.08k
          "Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
268
3.08k
          ifp->name, pim_checksum, checksum);
269
#ifndef FUZZING
270
      return -1;
271
#endif
272
3.08k
    }
273
3.08k
  }
274
275
3.23k
  if (PIM_DEBUG_PIM_PACKETS) {
276
0
    zlog_debug(
277
0
      "Recv PIM %s packet from %pPA to %pPA on %s: pim_version=%d pim_msg_size=%d checksum=%x",
278
0
      pim_pim_msgtype2str(header->type), &sg.src, &sg.grp,
279
0
      ifp->name, header->ver, pim_msg_len, checksum);
280
0
    if (PIM_DEBUG_PIM_PACKETDUMP_RECV)
281
0
      pim_pkt_dump(__func__, pim_msg, pim_msg_len);
282
0
  }
283
284
3.23k
  if (!pim_pkt_dst_addr_ok(header->type, sg.grp)) {
285
13
    zlog_warn(
286
13
      "%s: Ignoring Pkt. Unexpected IP destination %pPA for %s (Expected: all_pim_routers_addr) from %pPA",
287
13
      __func__, &sg.grp, pim_pim_msgtype2str(header->type),
288
13
      &sg.src);
289
13
    return -1;
290
13
  }
291
292
3.22k
  switch (header->type) {
293
616
  case PIM_MSG_TYPE_HELLO:
294
616
    return pim_hello_recv(ifp, sg.src, pim_msg + PIM_MSG_HEADER_LEN,
295
616
              pim_msg_len - PIM_MSG_HEADER_LEN);
296
0
    break;
297
149
  case PIM_MSG_TYPE_REGISTER:
298
149
    return pim_register_recv(ifp, sg.grp, sg.src,
299
149
           pim_msg + PIM_MSG_HEADER_LEN,
300
149
           pim_msg_len - PIM_MSG_HEADER_LEN);
301
0
    break;
302
89
  case PIM_MSG_TYPE_REG_STOP:
303
89
    return pim_register_stop_recv(ifp, pim_msg + PIM_MSG_HEADER_LEN,
304
89
                pim_msg_len - PIM_MSG_HEADER_LEN);
305
0
    break;
306
883
  case PIM_MSG_TYPE_JOIN_PRUNE:
307
883
    neigh = pim_neighbor_find(ifp, sg.src, false);
308
883
    if (!neigh) {
309
1
      if (PIM_DEBUG_PIM_PACKETS)
310
0
        zlog_debug(
311
1
          "%s %s: non-hello PIM message type=%d from non-neighbor %pPA on %s",
312
1
          __FILE__, __func__, header->type,
313
1
          &sg.src, ifp->name);
314
1
      return -1;
315
1
    }
316
882
    pim_neighbor_timer_reset(neigh, neigh->holdtime);
317
882
    return pim_joinprune_recv(ifp, neigh, sg.src,
318
882
            pim_msg + PIM_MSG_HEADER_LEN,
319
882
            pim_msg_len - PIM_MSG_HEADER_LEN);
320
0
    break;
321
211
  case PIM_MSG_TYPE_ASSERT:
322
211
    neigh = pim_neighbor_find(ifp, sg.src, false);
323
211
    if (!neigh) {
324
2
      if (PIM_DEBUG_PIM_PACKETS)
325
0
        zlog_debug(
326
2
          "%s %s: non-hello PIM message type=%d from non-neighbor %pPA on %s",
327
2
          __FILE__, __func__, header->type,
328
2
          &sg.src, ifp->name);
329
2
      return -1;
330
2
    }
331
209
    pim_neighbor_timer_reset(neigh, neigh->holdtime);
332
209
    return pim_assert_recv(ifp, neigh, sg.src,
333
209
               pim_msg + PIM_MSG_HEADER_LEN,
334
209
               pim_msg_len - PIM_MSG_HEADER_LEN);
335
0
    break;
336
1.26k
  case PIM_MSG_TYPE_BOOTSTRAP:
337
1.26k
    return pim_bsm_process(ifp, &sg, pim_msg, pim_msg_len, no_fwd);
338
0
    break;
339
340
7
  default:
341
7
    if (PIM_DEBUG_PIM_PACKETS) {
342
0
      zlog_debug(
343
0
        "Recv PIM packet type %d which is not currently understood",
344
0
        header->type);
345
0
    }
346
7
    return -1;
347
3.22k
  }
348
3.22k
}
349
350
static void pim_sock_read_on(struct interface *ifp);
351
352
static void pim_sock_read(struct event *t)
353
0
{
354
0
  struct interface *ifp, *orig_ifp;
355
0
  struct pim_interface *pim_ifp;
356
0
  int fd;
357
0
  struct sockaddr_storage from;
358
0
  struct sockaddr_storage to;
359
0
  socklen_t fromlen = sizeof(from);
360
0
  socklen_t tolen = sizeof(to);
361
0
  uint8_t buf[PIM_PIM_BUFSIZE_READ];
362
0
  int len;
363
0
  ifindex_t ifindex = -1;
364
0
  int result = -1; /* defaults to bad */
365
0
  static long long count = 0;
366
0
  int cont = 1;
367
0
368
0
  orig_ifp = ifp = EVENT_ARG(t);
369
0
  fd = EVENT_FD(t);
370
0
371
0
  pim_ifp = ifp->info;
372
0
373
0
  while (cont) {
374
0
    pim_sgaddr sg;
375
0
376
0
    len = pim_socket_recvfromto(fd, buf, sizeof(buf), &from,
377
0
              &fromlen, &to, &tolen, &ifindex);
378
0
    if (len < 0) {
379
0
      if (errno == EINTR)
380
0
        continue;
381
0
      if (errno == EWOULDBLOCK || errno == EAGAIN)
382
0
        break;
383
0
384
0
      if (PIM_DEBUG_PIM_PACKETS)
385
0
        zlog_debug("Received errno: %d %s", errno,
386
0
             safe_strerror(errno));
387
0
      goto done;
388
0
    }
389
0
390
0
    /*
391
0
     * What?  So with vrf's the incoming packet is received
392
0
     * on the vrf interface but recvfromto above returns
393
0
     * the right ifindex, so just use it.  We know
394
0
     * it's the right interface because we bind to it
395
0
     */
396
0
    ifp = if_lookup_by_index(ifindex, pim_ifp->pim->vrf->vrf_id);
397
0
    if (!ifp || !ifp->info) {
398
0
      if (PIM_DEBUG_PIM_PACKETS)
399
0
        zlog_debug(
400
0
          "%s: Received incoming pim packet on interface(%s:%d) not yet configured for pim",
401
0
          __func__, ifp ? ifp->name : "Unknown",
402
0
          ifindex);
403
0
      goto done;
404
0
    }
405
0
#if PIM_IPV == 4
406
0
    sg.src = ((struct sockaddr_in *)&from)->sin_addr;
407
0
    sg.grp = ((struct sockaddr_in *)&to)->sin_addr;
408
0
#else
409
0
    sg.src = ((struct sockaddr_in6 *)&from)->sin6_addr;
410
0
    sg.grp = ((struct sockaddr_in6 *)&to)->sin6_addr;
411
0
#endif
412
0
413
0
    int fail = pim_pim_packet(ifp, buf, len, sg);
414
0
    if (fail) {
415
0
      if (PIM_DEBUG_PIM_PACKETS)
416
0
        zlog_debug("%s: pim_pim_packet() return=%d",
417
0
             __func__, fail);
418
0
      goto done;
419
0
    }
420
0
421
0
    count++;
422
0
    if (count % router->packet_process == 0)
423
0
      cont = 0;
424
0
  }
425
0
426
0
  result = 0; /* good */
427
0
428
0
done:
429
0
  pim_sock_read_on(orig_ifp);
430
0
431
0
  if (result) {
432
0
    ++pim_ifp->pim_ifstat_hello_recvfail;
433
0
  }
434
0
}
435
436
static void pim_sock_read_on(struct interface *ifp)
437
0
{
438
0
  struct pim_interface *pim_ifp;
439
440
0
  assert(ifp);
441
0
  assert(ifp->info);
442
443
0
  pim_ifp = ifp->info;
444
445
0
  if (PIM_DEBUG_PIM_TRACE_DETAIL) {
446
0
    zlog_debug("Scheduling READ event on PIM socket fd=%d",
447
0
         pim_ifp->pim_sock_fd);
448
0
  }
449
0
  event_add_read(router->master, pim_sock_read, ifp, pim_ifp->pim_sock_fd,
450
0
           &pim_ifp->t_pim_sock_read);
451
0
}
452
453
static int pim_sock_open(struct interface *ifp)
454
0
{
455
0
  int fd;
456
0
  struct pim_interface *pim_ifp = ifp->info;
457
458
0
  fd = pim_socket_mcast(IPPROTO_PIM, pim_ifp->primary_address, ifp,
459
0
            0 /* loop=false */);
460
0
  if (fd < 0)
461
0
    return -1;
462
463
0
  if (pim_socket_join(fd, qpim_all_pim_routers_addr,
464
0
          pim_ifp->primary_address, ifp->ifindex, pim_ifp)) {
465
0
    close(fd);
466
0
    return -2;
467
0
  }
468
469
0
  return fd;
470
0
}
471
472
void pim_ifstat_reset(struct interface *ifp)
473
2
{
474
2
  struct pim_interface *pim_ifp;
475
476
2
  assert(ifp);
477
478
2
  pim_ifp = ifp->info;
479
2
  if (!pim_ifp) {
480
0
    return;
481
0
  }
482
483
2
  pim_ifp->pim_ifstat_start = pim_time_monotonic_sec();
484
2
  pim_ifp->pim_ifstat_hello_sent = 0;
485
2
  pim_ifp->pim_ifstat_hello_sendfail = 0;
486
2
  pim_ifp->pim_ifstat_hello_recv = 0;
487
2
  pim_ifp->pim_ifstat_hello_recvfail = 0;
488
2
  pim_ifp->pim_ifstat_bsm_rx = 0;
489
2
  pim_ifp->pim_ifstat_bsm_tx = 0;
490
2
  pim_ifp->pim_ifstat_join_recv = 0;
491
2
  pim_ifp->pim_ifstat_join_send = 0;
492
2
  pim_ifp->pim_ifstat_prune_recv = 0;
493
2
  pim_ifp->pim_ifstat_prune_send = 0;
494
2
  pim_ifp->pim_ifstat_reg_recv = 0;
495
2
  pim_ifp->pim_ifstat_reg_send = 0;
496
2
  pim_ifp->pim_ifstat_reg_stop_recv = 0;
497
2
  pim_ifp->pim_ifstat_reg_stop_send = 0;
498
2
  pim_ifp->pim_ifstat_assert_recv = 0;
499
2
  pim_ifp->pim_ifstat_assert_send = 0;
500
2
  pim_ifp->pim_ifstat_bsm_cfg_miss = 0;
501
2
  pim_ifp->pim_ifstat_ucast_bsm_cfg_miss = 0;
502
2
  pim_ifp->pim_ifstat_bsm_invalid_sz = 0;
503
2
  pim_ifp->igmp_ifstat_joins_sent = 0;
504
2
  pim_ifp->igmp_ifstat_joins_failed = 0;
505
2
  pim_ifp->igmp_peak_group_count = 0;
506
2
}
507
508
void pim_sock_reset(struct interface *ifp)
509
2
{
510
2
  struct pim_interface *pim_ifp;
511
512
2
  assert(ifp);
513
2
  assert(ifp->info);
514
515
2
  pim_ifp = ifp->info;
516
517
2
  pim_ifp->primary_address = pim_find_primary_addr(ifp);
518
519
2
  pim_ifp->pim_sock_fd = -1;
520
2
  pim_ifp->pim_sock_creation = 0;
521
2
  pim_ifp->t_pim_sock_read = NULL;
522
523
2
  pim_ifp->t_pim_hello_timer = NULL;
524
2
  pim_ifp->pim_hello_period = PIM_DEFAULT_HELLO_PERIOD;
525
2
  pim_ifp->pim_default_holdtime =
526
2
    -1; /* unset: means 3.5 * pim_hello_period */
527
2
  pim_ifp->pim_triggered_hello_delay = PIM_DEFAULT_TRIGGERED_HELLO_DELAY;
528
2
  pim_ifp->pim_dr_priority = PIM_DEFAULT_DR_PRIORITY;
529
2
  pim_ifp->pim_propagation_delay_msec =
530
2
    PIM_DEFAULT_PROPAGATION_DELAY_MSEC;
531
2
  pim_ifp->pim_override_interval_msec =
532
2
    PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC;
533
2
  pim_ifp->pim_can_disable_join_suppression =
534
2
    PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION;
535
536
  /* neighbors without lan_delay */
537
2
  pim_ifp->pim_number_of_nonlandelay_neighbors = 0;
538
2
  pim_ifp->pim_neighbors_highest_propagation_delay_msec = 0;
539
2
  pim_ifp->pim_neighbors_highest_override_interval_msec = 0;
540
541
  /* DR Election */
542
2
  pim_ifp->pim_dr_election_last = 0; /* timestamp */
543
2
  pim_ifp->pim_dr_election_count = 0;
544
2
  pim_ifp->pim_dr_election_changes = 0;
545
2
  pim_ifp->pim_dr_num_nondrpri_neighbors =
546
2
    0; /* neighbors without dr_pri */
547
2
  pim_ifp->pim_dr_addr = pim_ifp->primary_address;
548
2
  pim_ifp->am_i_dr = true;
549
550
2
  pim_ifstat_reset(ifp);
551
2
}
552
553
#if PIM_IPV == 4
554
static uint16_t ip_id = 0;
555
#endif
556
557
#if PIM_IPV == 4
558
static int pim_msg_send_frame(int fd, char *buf, size_t len,
559
            struct sockaddr *dst, size_t salen,
560
            const char *ifname)
561
228
{
562
228
  if (sendto(fd, buf, len, MSG_DONTWAIT, dst, salen) >= 0)
563
0
    return 0;
564
565
228
  if (errno == EMSGSIZE) {
566
0
    struct ip *ip = (struct ip *)buf;
567
0
    size_t hdrsize = sizeof(struct ip);
568
0
    size_t newlen1 = ((len - hdrsize) / 2) & 0xFFF8;
569
0
    size_t sendlen = newlen1 + hdrsize;
570
0
    size_t offset = ntohs(ip->ip_off);
571
0
    int ret;
572
573
0
    ip->ip_len = htons(sendlen);
574
0
    ip->ip_off = htons(offset | IP_MF);
575
576
0
    ret = pim_msg_send_frame(fd, buf, sendlen, dst, salen, ifname);
577
0
    if (ret)
578
0
      return ret;
579
580
0
    struct ip *ip2 = (struct ip *)(buf + newlen1);
581
0
    size_t newlen2 = len - sendlen;
582
583
0
    sendlen = newlen2 + hdrsize;
584
585
0
    memcpy(ip2, ip, hdrsize);
586
0
    ip2->ip_len = htons(sendlen);
587
0
    ip2->ip_off = htons(offset + (newlen1 >> 3));
588
0
    return pim_msg_send_frame(fd, (char *)ip2, sendlen, dst, salen,
589
0
            ifname);
590
0
  }
591
592
228
  zlog_warn(
593
228
    "%s: sendto() failure to %pSU: iface=%s fd=%d msg_size=%zd: %m",
594
228
    __func__, dst, ifname, fd, len);
595
228
  return -1;
596
228
}
597
598
#else
599
static int pim_msg_send_frame(pim_addr src, pim_addr dst, ifindex_t ifindex,
600
            struct iovec *message, int fd)
601
{
602
  int retval;
603
  struct msghdr smsghdr = {};
604
  struct cmsghdr *scmsgp;
605
  union cmsgbuf {
606
    struct cmsghdr hdr;
607
    uint8_t buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
608
  };
609
  struct in6_pktinfo *pktinfo;
610
  struct sockaddr_in6 dst_sin6 = {};
611
612
  union cmsgbuf cmsg_buf = {};
613
614
  /* destination address */
615
  dst_sin6.sin6_family = AF_INET6;
616
#ifdef SIN6_LEN
617
  dst_sin6.sin6_len = sizeof(struct sockaddr_in6);
618
#endif /*SIN6_LEN*/
619
  dst_sin6.sin6_addr = dst;
620
  dst_sin6.sin6_scope_id = ifindex;
621
622
  /* send msg hdr */
623
  smsghdr.msg_iov = message;
624
  smsghdr.msg_iovlen = 1;
625
  smsghdr.msg_name = (caddr_t)&dst_sin6;
626
  smsghdr.msg_namelen = sizeof(dst_sin6);
627
  smsghdr.msg_control = (caddr_t)&cmsg_buf.buf;
628
  smsghdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
629
  smsghdr.msg_flags = 0;
630
631
  scmsgp = CMSG_FIRSTHDR(&smsghdr);
632
  scmsgp->cmsg_level = IPPROTO_IPV6;
633
  scmsgp->cmsg_type = IPV6_PKTINFO;
634
  scmsgp->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
635
636
  pktinfo = (struct in6_pktinfo *)(CMSG_DATA(scmsgp));
637
  pktinfo->ipi6_ifindex = ifindex;
638
  pktinfo->ipi6_addr = src;
639
640
  retval = sendmsg(fd, &smsghdr, 0);
641
  if (retval < 0)
642
    flog_err(
643
      EC_LIB_SOCKET,
644
      "sendmsg failed: source: %pI6 Dest: %pI6 ifindex: %d: %s (%d)",
645
      &src, &dst, ifindex, safe_strerror(errno), errno);
646
647
  return retval;
648
}
649
#endif
650
651
int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg,
652
     int pim_msg_size, struct interface *ifp)
653
228
{
654
228
  struct pim_interface *pim_ifp;
655
656
657
228
  pim_ifp = ifp->info;
658
659
228
  if (pim_ifp->pim_passive_enable) {
660
0
    if (PIM_DEBUG_PIM_PACKETS)
661
0
      zlog_debug(
662
0
        "skip sending PIM message on passive interface %s",
663
0
        ifp->name);
664
0
    return 0;
665
0
  }
666
667
228
#if PIM_IPV == 4
668
228
  uint8_t ttl;
669
228
  struct pim_msg_header *header;
670
228
  unsigned char buffer[10000];
671
672
228
  memset(buffer, 0, 10000);
673
674
228
  header = (struct pim_msg_header *)pim_msg;
675
676
/*
677
 * Omnios apparently doesn't have a #define for IP default
678
 * ttl that is the same as all other platforms.
679
 */
680
#ifndef IPDEFTTL
681
#define IPDEFTTL   64
682
#endif
683
  /* TTL for packets destine to ALL-PIM-ROUTERS is 1 */
684
228
  switch (header->type) {
685
220
  case PIM_MSG_TYPE_HELLO:
686
220
  case PIM_MSG_TYPE_JOIN_PRUNE:
687
220
  case PIM_MSG_TYPE_BOOTSTRAP:
688
220
  case PIM_MSG_TYPE_ASSERT:
689
220
    ttl = 1;
690
220
    break;
691
0
  case PIM_MSG_TYPE_REGISTER:
692
8
  case PIM_MSG_TYPE_REG_STOP:
693
8
  case PIM_MSG_TYPE_GRAFT:
694
8
  case PIM_MSG_TYPE_GRAFT_ACK:
695
8
  case PIM_MSG_TYPE_CANDIDATE:
696
8
    ttl = IPDEFTTL;
697
8
    break;
698
0
  default:
699
0
    ttl = MAXTTL;
700
0
    break;
701
228
  }
702
703
228
  struct ip *ip = (struct ip *)buffer;
704
228
  struct sockaddr_in to = {};
705
228
  int sendlen = sizeof(*ip) + pim_msg_size;
706
228
  socklen_t tolen;
707
228
  unsigned char *msg_start;
708
709
228
  ip->ip_id = htons(++ip_id);
710
228
  ip->ip_hl = 5;
711
228
  ip->ip_v = 4;
712
228
  ip->ip_tos = IPTOS_PREC_INTERNETCONTROL;
713
228
  ip->ip_p = PIM_IP_PROTO_PIM;
714
228
  ip->ip_src = src;
715
228
  ip->ip_dst = dst;
716
228
  ip->ip_ttl = ttl;
717
228
  ip->ip_len = htons(sendlen);
718
719
228
  to.sin_family = AF_INET;
720
228
  to.sin_addr = dst;
721
228
  tolen = sizeof(to);
722
723
228
  msg_start = buffer + sizeof(*ip);
724
228
  memcpy(msg_start, pim_msg, pim_msg_size);
725
726
228
  if (PIM_DEBUG_PIM_PACKETS)
727
0
    zlog_debug("%s: to %pPA on %s: msg_size=%d checksum=%x",
728
228
         __func__, &dst, ifp->name, pim_msg_size,
729
228
         header->checksum);
730
731
228
  if (PIM_DEBUG_PIM_PACKETDUMP_SEND) {
732
0
    pim_pkt_dump(__func__, pim_msg, pim_msg_size);
733
0
  }
734
735
228
  pim_msg_send_frame(fd, (char *)buffer, sendlen, (struct sockaddr *)&to,
736
228
         tolen, ifp->name);
737
228
  return 0;
738
739
#else
740
  struct iovec iovector[2];
741
742
  iovector[0].iov_base = pim_msg;
743
  iovector[0].iov_len = pim_msg_size;
744
745
  pim_msg_send_frame(src, dst, ifp->ifindex, &iovector[0], fd);
746
747
  return 0;
748
#endif
749
228
}
750
751
static int hello_send(struct interface *ifp, uint16_t holdtime)
752
220
{
753
220
  uint8_t pim_msg[PIM_PIM_BUFSIZE_WRITE];
754
220
  struct pim_interface *pim_ifp;
755
220
  int pim_tlv_size;
756
220
  int pim_msg_size;
757
758
220
  pim_ifp = ifp->info;
759
760
220
  if (PIM_DEBUG_PIM_HELLO)
761
0
    zlog_debug(
762
220
      "%s: to %pPA on %s: holdt=%u prop_d=%u overr_i=%u dis_join_supp=%d dr_prio=%u gen_id=%08x addrs=%d",
763
220
      __func__, &qpim_all_pim_routers_addr, ifp->name,
764
220
      holdtime, pim_ifp->pim_propagation_delay_msec,
765
220
      pim_ifp->pim_override_interval_msec,
766
220
      pim_ifp->pim_can_disable_join_suppression,
767
220
      pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id,
768
220
      listcount(ifp->connected));
769
770
220
  pim_tlv_size = pim_hello_build_tlv(
771
220
    ifp, pim_msg + PIM_PIM_MIN_LEN,
772
220
    sizeof(pim_msg) - PIM_PIM_MIN_LEN, holdtime,
773
220
    pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id,
774
220
    pim_ifp->pim_propagation_delay_msec,
775
220
    pim_ifp->pim_override_interval_msec,
776
220
    pim_ifp->pim_can_disable_join_suppression);
777
220
  if (pim_tlv_size < 0) {
778
0
    return -1;
779
0
  }
780
781
220
  pim_msg_size = pim_tlv_size + PIM_PIM_MIN_LEN;
782
783
220
  assert(pim_msg_size >= PIM_PIM_MIN_LEN);
784
220
  assert(pim_msg_size <= PIM_PIM_BUFSIZE_WRITE);
785
786
220
  pim_msg_build_header(pim_ifp->primary_address,
787
220
           qpim_all_pim_routers_addr, pim_msg, pim_msg_size,
788
220
           PIM_MSG_TYPE_HELLO, false);
789
790
220
  if (pim_msg_send(pim_ifp->pim_sock_fd, pim_ifp->primary_address,
791
220
       qpim_all_pim_routers_addr, pim_msg, pim_msg_size,
792
220
       ifp)) {
793
0
    if (PIM_DEBUG_PIM_HELLO) {
794
0
      zlog_debug(
795
0
        "%s: could not send PIM message on interface %s",
796
0
        __func__, ifp->name);
797
0
    }
798
0
    return -2;
799
0
  }
800
801
220
  return 0;
802
220
}
803
804
int pim_hello_send(struct interface *ifp, uint16_t holdtime)
805
220
{
806
220
  struct pim_interface *pim_ifp = ifp->info;
807
808
220
  if (if_is_loopback(ifp))
809
0
    return 0;
810
811
220
  if (hello_send(ifp, holdtime)) {
812
0
    ++pim_ifp->pim_ifstat_hello_sendfail;
813
814
0
    if (PIM_DEBUG_PIM_HELLO) {
815
0
      zlog_warn("Could not send PIM hello on interface %s",
816
0
          ifp->name);
817
0
    }
818
0
    return -1;
819
0
  }
820
821
220
  if (!pim_ifp->pim_passive_enable) {
822
220
    ++pim_ifp->pim_ifstat_hello_sent;
823
220
    PIM_IF_FLAG_SET_HELLO_SENT(pim_ifp->flags);
824
220
  }
825
826
220
  return 0;
827
220
}
828
829
static void hello_resched(struct interface *ifp)
830
220
{
831
220
  struct pim_interface *pim_ifp;
832
833
220
  pim_ifp = ifp->info;
834
835
220
  if (PIM_DEBUG_PIM_HELLO) {
836
0
    zlog_debug("Rescheduling %d sec hello on interface %s",
837
0
         pim_ifp->pim_hello_period, ifp->name);
838
0
  }
839
220
  EVENT_OFF(pim_ifp->t_pim_hello_timer);
840
220
  event_add_timer(router->master, on_pim_hello_send, ifp,
841
220
      pim_ifp->pim_hello_period, &pim_ifp->t_pim_hello_timer);
842
220
}
843
844
/*
845
  Periodic hello timer
846
 */
847
static void on_pim_hello_send(struct event *t)
848
0
{
849
0
  struct pim_interface *pim_ifp;
850
0
  struct interface *ifp;
851
0
852
0
  ifp = EVENT_ARG(t);
853
0
  pim_ifp = ifp->info;
854
0
855
0
  /*
856
0
   * Schedule next hello
857
0
   */
858
0
  hello_resched(ifp);
859
0
860
0
  /*
861
0
   * Send hello
862
0
   */
863
0
  pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
864
0
}
865
866
/*
867
  RFC 4601: 4.3.1.  Sending Hello Messages
868
869
  Thus, if a router needs to send a Join/Prune or Assert message on an
870
  interface on which it has not yet sent a Hello message with the
871
  currently configured IP address, then it MUST immediately send the
872
  relevant Hello message without waiting for the Hello Timer to
873
  expire, followed by the Join/Prune or Assert message.
874
 */
875
void pim_hello_restart_now(struct interface *ifp)
876
220
{
877
220
  struct pim_interface *pim_ifp;
878
879
220
  pim_ifp = ifp->info;
880
881
  /*
882
   * Reset next hello timer
883
   */
884
220
  hello_resched(ifp);
885
886
  /*
887
   * Immediately send hello
888
   */
889
220
  pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
890
220
}
891
892
/*
893
  RFC 4601: 4.3.1.  Sending Hello Messages
894
895
  To allow new or rebooting routers to learn of PIM neighbors quickly,
896
  when a Hello message is received from a new neighbor, or a Hello
897
  message with a new GenID is received from an existing neighbor, a
898
  new Hello message should be sent on this interface after a
899
  randomized delay between 0 and Triggered_Hello_Delay.
900
 */
901
void pim_hello_restart_triggered(struct interface *ifp)
902
196
{
903
196
  struct pim_interface *pim_ifp;
904
196
  int triggered_hello_delay_msec;
905
196
  int random_msec;
906
907
196
  pim_ifp = ifp->info;
908
909
  /*
910
   * No need to ever start loopback or vrf device hello's
911
   */
912
196
  if (if_is_loopback(ifp))
913
0
    return;
914
915
  /*
916
   * There exists situations where we have the a RPF out this
917
   * interface, but we haven't formed a neighbor yet.  This
918
   * happens especially during interface flaps.  While
919
   * we would like to handle this more gracefully in other
920
   * parts of the code.  In order to get us up and running
921
   * let's just send the hello immediate'ish
922
   * This should be revisited when we get nexthop tracking
923
   * in and when we have a better handle on safely
924
   * handling the rpf information for upstreams that
925
   * we cannot legally reach yet.
926
   */
927
196
  triggered_hello_delay_msec = 1;
928
  // triggered_hello_delay_msec = 1000 *
929
  // pim_ifp->pim_triggered_hello_delay;
930
931
196
  if (pim_ifp->t_pim_hello_timer) {
932
0
    long remain_msec =
933
0
      pim_time_timer_remain_msec(pim_ifp->t_pim_hello_timer);
934
0
    if (remain_msec <= triggered_hello_delay_msec) {
935
      /* Rescheduling hello would increase the delay, then
936
         it's faster
937
         to just wait for the scheduled periodic hello. */
938
0
      return;
939
0
    }
940
941
0
    EVENT_OFF(pim_ifp->t_pim_hello_timer);
942
0
  }
943
944
196
  random_msec = triggered_hello_delay_msec;
945
  // random_msec = random() % (triggered_hello_delay_msec + 1);
946
947
196
  if (PIM_DEBUG_PIM_HELLO) {
948
0
    zlog_debug("Scheduling %d msec triggered hello on interface %s",
949
0
         random_msec, ifp->name);
950
0
  }
951
952
196
  event_add_timer_msec(router->master, on_pim_hello_send, ifp,
953
196
           random_msec, &pim_ifp->t_pim_hello_timer);
954
196
}
955
956
int pim_sock_add(struct interface *ifp)
957
0
{
958
0
  struct pim_interface *pim_ifp;
959
0
  uint32_t old_genid;
960
961
0
  pim_ifp = ifp->info;
962
0
  assert(pim_ifp);
963
964
0
  if (pim_ifp->pim_sock_fd >= 0) {
965
0
    if (PIM_DEBUG_PIM_PACKETS)
966
0
      zlog_debug(
967
0
        "Can't recreate existing PIM socket fd=%d for interface %s",
968
0
        pim_ifp->pim_sock_fd, ifp->name);
969
0
    return -1;
970
0
  }
971
972
0
  pim_ifp->pim_sock_fd = pim_sock_open(ifp);
973
0
  if (pim_ifp->pim_sock_fd < 0) {
974
0
    if (PIM_DEBUG_PIM_PACKETS)
975
0
      zlog_debug("Could not open PIM socket on interface %s",
976
0
           ifp->name);
977
0
    return -2;
978
0
  }
979
980
0
  pim_socket_ip_hdr(pim_ifp->pim_sock_fd);
981
982
0
  pim_ifp->t_pim_sock_read = NULL;
983
0
  pim_ifp->pim_sock_creation = pim_time_monotonic_sec();
984
985
  /*
986
   * Just ensure that the new generation id
987
   * actually chooses something different.
988
   * Actually ran across a case where this
989
   * happened, pre-switch to random().
990
   * While this is unlikely to happen now
991
   * let's make sure it doesn't.
992
   */
993
0
  old_genid = pim_ifp->pim_generation_id;
994
995
0
  while (old_genid == pim_ifp->pim_generation_id)
996
0
    pim_ifp->pim_generation_id = frr_weak_random();
997
998
0
  zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d", ifp->name,
999
0
      ifp->ifindex);
1000
1001
  /*
1002
   * Start receiving PIM messages
1003
   */
1004
0
  pim_sock_read_on(ifp);
1005
1006
  /*
1007
   * Start sending PIM hello's
1008
   */
1009
0
  pim_hello_restart_triggered(ifp);
1010
1011
0
  return 0;
1012
0
}