Coverage Report

Created: 2025-12-12 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/frr/pimd/pim_assert.c
Line
Count
Source
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 "prefix.h"
11
#include "if.h"
12
13
#include "pimd.h"
14
#include "pim_instance.h"
15
#include "pim_str.h"
16
#include "pim_tlv.h"
17
#include "pim_msg.h"
18
#include "pim_pim.h"
19
#include "pim_int.h"
20
#include "pim_time.h"
21
#include "pim_iface.h"
22
#include "pim_hello.h"
23
#include "pim_macro.h"
24
#include "pim_assert.h"
25
#include "pim_zebra.h"
26
#include "pim_ifchannel.h"
27
28
static int assert_action_a3(struct pim_ifchannel *ch);
29
static void assert_action_a2(struct pim_ifchannel *ch,
30
           struct pim_assert_metric winner_metric);
31
static void assert_action_a6(struct pim_ifchannel *ch,
32
           struct pim_assert_metric winner_metric);
33
34
void pim_ifassert_winner_set(struct pim_ifchannel *ch,
35
           enum pim_ifassert_state new_state, pim_addr winner,
36
           struct pim_assert_metric winner_metric)
37
52.2k
{
38
52.2k
  struct pim_interface *pim_ifp = ch->interface->info;
39
52.2k
  int winner_changed = !!pim_addr_cmp(ch->ifassert_winner, winner);
40
52.2k
  int metric_changed = !pim_assert_metric_match(
41
52.2k
    &ch->ifassert_winner_metric, &winner_metric);
42
52.2k
  enum pim_rpf_result rpf_result;
43
52.2k
  struct pim_rpf old_rpf;
44
45
52.2k
  if (PIM_DEBUG_PIM_EVENTS) {
46
0
    if (ch->ifassert_state != new_state) {
47
0
      zlog_debug(
48
0
        "%s: (S,G)=%s assert state changed from %s to %s on interface %s",
49
0
        __func__, ch->sg_str,
50
0
        pim_ifchannel_ifassert_name(ch->ifassert_state),
51
0
        pim_ifchannel_ifassert_name(new_state),
52
0
        ch->interface->name);
53
0
    }
54
55
0
    if (winner_changed)
56
0
      zlog_debug(
57
0
        "%s: (S,G)=%s assert winner changed from %pPAs to %pPAs on interface %s",
58
0
        __func__, ch->sg_str, &ch->ifassert_winner,
59
0
        &winner, ch->interface->name);
60
0
  } /* PIM_DEBUG_PIM_EVENTS */
61
62
52.2k
  ch->ifassert_state = new_state;
63
52.2k
  ch->ifassert_winner = winner;
64
52.2k
  ch->ifassert_winner_metric = winner_metric;
65
52.2k
  ch->ifassert_creation = pim_time_monotonic_sec();
66
67
52.2k
  if (winner_changed || metric_changed) {
68
7
    if (winner_changed) {
69
4
      old_rpf.source_nexthop.interface =
70
4
        ch->upstream->rpf.source_nexthop.interface;
71
4
      rpf_result = pim_rpf_update(pim_ifp->pim, ch->upstream,
72
4
                &old_rpf, __func__);
73
4
      if (rpf_result == PIM_RPF_CHANGED ||
74
4
          (rpf_result == PIM_RPF_FAILURE &&
75
2
           old_rpf.source_nexthop.interface))
76
0
        pim_zebra_upstream_rpf_changed(
77
0
          pim_ifp->pim, ch->upstream, &old_rpf);
78
      /* update kernel multicast forwarding cache (MFC) */
79
4
      if (ch->upstream->rpf.source_nexthop.interface &&
80
0
          ch->upstream->channel_oil)
81
0
        pim_upstream_mroute_iif_update(
82
0
          ch->upstream->channel_oil, __func__);
83
4
    }
84
7
    pim_upstream_update_join_desired(pim_ifp->pim, ch->upstream);
85
7
    pim_ifchannel_update_could_assert(ch);
86
7
    pim_ifchannel_update_assert_tracking_desired(ch);
87
7
  }
88
52.2k
}
89
90
static void on_trace(const char *label, struct interface *ifp, pim_addr src)
91
135
{
92
135
  if (PIM_DEBUG_PIM_TRACE)
93
0
    zlog_debug("%s: from %pPAs on %s", label, &src, ifp->name);
94
135
}
95
96
static int preferred_assert(const struct pim_ifchannel *ch,
97
          const struct pim_assert_metric *recv_metric)
98
0
{
99
0
  return pim_assert_metric_better(recv_metric,
100
0
          &ch->ifassert_winner_metric);
101
0
}
102
103
static int acceptable_assert(const struct pim_assert_metric *my_metric,
104
           const struct pim_assert_metric *recv_metric)
105
77
{
106
77
  return pim_assert_metric_better(recv_metric, my_metric);
107
77
}
108
109
static int inferior_assert(const struct pim_assert_metric *my_metric,
110
         const struct pim_assert_metric *recv_metric)
111
77
{
112
77
  return pim_assert_metric_better(my_metric, recv_metric);
113
77
}
114
115
static int cancel_assert(const struct pim_assert_metric *recv_metric)
116
3
{
117
3
  return (recv_metric->metric_preference
118
3
    == PIM_ASSERT_METRIC_PREFERENCE_MAX)
119
0
         && (recv_metric->route_metric == PIM_ASSERT_ROUTE_METRIC_MAX);
120
3
}
121
122
static void if_could_assert_do_a1(const char *caller, struct pim_ifchannel *ch)
123
41
{
124
41
  if (PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) {
125
0
    if (assert_action_a1(ch)) {
126
0
      zlog_warn(
127
0
        "%s: %s: (S,G)=%s assert_action_a1 failure on interface %s",
128
0
        __func__, caller, ch->sg_str,
129
0
        ch->interface->name);
130
      /* log warning only */
131
0
    }
132
0
  }
133
41
}
134
135
static int dispatch_assert(struct interface *ifp, pim_addr source_addr,
136
         pim_addr group_addr,
137
         struct pim_assert_metric recv_metric)
138
118
{
139
118
  struct pim_ifchannel *ch;
140
118
  pim_sgaddr sg;
141
142
118
  memset(&sg, 0, sizeof(sg));
143
118
  sg.src = source_addr;
144
118
  sg.grp = group_addr;
145
118
  ch = pim_ifchannel_add(ifp, &sg, 0, 0);
146
147
118
  switch (ch->ifassert_state) {
148
115
  case PIM_IFASSERT_NOINFO:
149
115
    if (recv_metric.rpt_bit_flag) {
150
      /* RPT bit set */
151
41
      if_could_assert_do_a1(__func__, ch);
152
74
    } else {
153
      /* RPT bit clear */
154
74
      if (inferior_assert(&ch->ifassert_my_metric,
155
74
              &recv_metric)) {
156
0
        if_could_assert_do_a1(__func__, ch);
157
74
      } else if (acceptable_assert(&ch->ifassert_my_metric,
158
74
                 &recv_metric)) {
159
74
        if (PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(
160
74
              ch->flags)) {
161
2
          assert_action_a6(ch, recv_metric);
162
2
        }
163
74
      }
164
74
    }
165
115
    break;
166
0
  case PIM_IFASSERT_I_AM_WINNER:
167
0
    if (preferred_assert(ch, &recv_metric)) {
168
0
      assert_action_a2(ch, recv_metric);
169
0
    } else {
170
0
      if (inferior_assert(&ch->ifassert_my_metric,
171
0
              &recv_metric)) {
172
0
        assert_action_a3(ch);
173
0
      }
174
0
    }
175
0
    break;
176
3
  case PIM_IFASSERT_I_AM_LOSER:
177
3
    if (!pim_addr_cmp(recv_metric.ip_address,
178
3
          ch->ifassert_winner)) {
179
      /* Assert from current winner */
180
181
3
      if (cancel_assert(&recv_metric)) {
182
0
        assert_action_a5(ch);
183
3
      } else {
184
3
        if (inferior_assert(&ch->ifassert_my_metric,
185
3
                &recv_metric)) {
186
0
          assert_action_a5(ch);
187
3
        } else if (acceptable_assert(
188
3
               &ch->ifassert_my_metric,
189
3
               &recv_metric)) {
190
3
          if (!recv_metric.rpt_bit_flag) {
191
3
            assert_action_a2(ch,
192
3
                 recv_metric);
193
3
          }
194
3
        }
195
3
      }
196
3
    } else if (preferred_assert(ch, &recv_metric)) {
197
0
      assert_action_a2(ch, recv_metric);
198
0
    }
199
3
    break;
200
0
  default: {
201
0
    zlog_warn(
202
0
      "%s: (S,G)=%s invalid assert state %d on interface %s",
203
0
      __func__, ch->sg_str, ch->ifassert_state, ifp->name);
204
0
  }
205
0
    return -2;
206
118
  }
207
208
118
  return 0;
209
118
}
210
211
int pim_assert_recv(struct interface *ifp, struct pim_neighbor *neigh,
212
        pim_addr src_addr, uint8_t *buf, int buf_size)
213
135
{
214
135
  pim_sgaddr sg;
215
135
  pim_addr msg_source_addr;
216
135
  bool wrong_af = false;
217
135
  struct pim_assert_metric msg_metric;
218
135
  int offset;
219
135
  uint8_t *curr;
220
135
  int curr_size;
221
135
  struct pim_interface *pim_ifp = NULL;
222
223
135
  on_trace(__func__, ifp, src_addr);
224
225
135
  curr = buf;
226
135
  curr_size = buf_size;
227
228
  /*
229
    Parse assert group addr
230
   */
231
135
  memset(&sg, 0, sizeof(sg));
232
135
  offset = pim_parse_addr_group(&sg, curr, curr_size);
233
135
  if (offset < 1) {
234
5
    zlog_warn(
235
5
      "%s: pim_parse_addr_group() failure: from %pPAs on %s",
236
5
      __func__, &src_addr, ifp->name);
237
5
    return -1;
238
5
  }
239
130
  curr += offset;
240
130
  curr_size -= offset;
241
242
  /*
243
    Parse assert source addr
244
  */
245
130
  offset = pim_parse_addr_ucast(&msg_source_addr, curr, curr_size,
246
130
              &wrong_af);
247
130
  if (offset < 1 || wrong_af) {
248
7
    zlog_warn(
249
7
      "%s: pim_parse_addr_ucast() failure: from %pPAs on %s",
250
7
      __func__, &src_addr, ifp->name);
251
7
    return -2;
252
7
  }
253
123
  curr += offset;
254
123
  curr_size -= offset;
255
256
123
  if (curr_size < 8) {
257
5
    zlog_warn(
258
5
      "%s: preference/metric size is less than 8 bytes: size=%d from %pPAs on interface %s",
259
5
      __func__, curr_size, &src_addr, ifp->name);
260
5
    return -3;
261
5
  }
262
263
  /*
264
    Parse assert metric preference
265
  */
266
267
118
  msg_metric.metric_preference = pim_read_uint32_host(curr);
268
269
118
  msg_metric.rpt_bit_flag = msg_metric.metric_preference
270
118
          & 0x80000000;      /* save highest bit */
271
118
  msg_metric.metric_preference &= ~0x80000000; /* clear highest bit */
272
273
118
  curr += 4;
274
275
  /*
276
    Parse assert route metric
277
  */
278
279
118
  msg_metric.route_metric = pim_read_uint32_host(curr);
280
281
118
  if (PIM_DEBUG_PIM_TRACE)
282
0
    zlog_debug(
283
118
      "%s: from %pPAs on %s: (S,G)=(%pPAs,%pPAs) pref=%u metric=%u rpt_bit=%u",
284
118
      __func__, &src_addr, ifp->name, &msg_source_addr,
285
118
      &sg.grp, msg_metric.metric_preference,
286
118
      msg_metric.route_metric,
287
118
      PIM_FORCE_BOOLEAN(msg_metric.rpt_bit_flag));
288
289
118
  msg_metric.ip_address = src_addr;
290
291
118
  pim_ifp = ifp->info;
292
118
  assert(pim_ifp);
293
294
118
  if (pim_ifp->pim_passive_enable) {
295
0
    if (PIM_DEBUG_PIM_PACKETS)
296
0
      zlog_debug(
297
0
        "skip receiving PIM message on passive interface %s",
298
0
        ifp->name);
299
0
    return 0;
300
0
  }
301
302
118
  ++pim_ifp->pim_ifstat_assert_recv;
303
304
118
  return dispatch_assert(ifp, msg_source_addr, sg.grp, msg_metric);
305
118
}
306
307
/*
308
  RFC 4601: 4.6.3.  Assert Metrics
309
310
   Assert metrics are defined as:
311
312
   When comparing assert_metrics, the rpt_bit_flag, metric_preference,
313
   and route_metric field are compared in order, where the first lower
314
   value wins.  If all fields are equal, the primary IP address of the
315
   router that sourced the Assert message is used as a tie-breaker,
316
   with the highest IP address winning.
317
*/
318
int pim_assert_metric_better(const struct pim_assert_metric *m1,
319
           const struct pim_assert_metric *m2)
320
158
{
321
158
  if (m1->rpt_bit_flag < m2->rpt_bit_flag)
322
77
    return 1;
323
81
  if (m1->rpt_bit_flag > m2->rpt_bit_flag)
324
77
    return 0;
325
326
4
  if (m1->metric_preference < m2->metric_preference)
327
4
    return 1;
328
0
  if (m1->metric_preference > m2->metric_preference)
329
0
    return 0;
330
331
0
  if (m1->route_metric < m2->route_metric)
332
0
    return 1;
333
0
  if (m1->route_metric > m2->route_metric)
334
0
    return 0;
335
336
0
  return pim_addr_cmp(m1->ip_address, m2->ip_address) > 0;
337
0
}
338
339
int pim_assert_metric_match(const struct pim_assert_metric *m1,
340
          const struct pim_assert_metric *m2)
341
52.2k
{
342
52.2k
  if (m1->rpt_bit_flag != m2->rpt_bit_flag)
343
4
    return 0;
344
52.2k
  if (m1->metric_preference != m2->metric_preference)
345
3
    return 0;
346
52.2k
  if (m1->route_metric != m2->route_metric)
347
0
    return 0;
348
349
52.2k
  return !pim_addr_cmp(m1->ip_address, m2->ip_address);
350
52.2k
}
351
352
int pim_assert_build_msg(uint8_t *pim_msg, int buf_size, struct interface *ifp,
353
       pim_addr group_addr, pim_addr source_addr,
354
       uint32_t metric_preference, uint32_t route_metric,
355
       uint32_t rpt_bit_flag)
356
0
{
357
0
  struct pim_interface *pim_ifp = ifp->info;
358
0
  uint8_t *buf_pastend = pim_msg + buf_size;
359
0
  uint8_t *pim_msg_curr;
360
0
  int pim_msg_size;
361
0
  int remain;
362
363
0
  pim_msg_curr =
364
0
    pim_msg + PIM_MSG_HEADER_LEN; /* skip room for pim header */
365
366
  /* Encode group */
367
0
  remain = buf_pastend - pim_msg_curr;
368
0
  pim_msg_curr = pim_msg_addr_encode_group(pim_msg_curr, group_addr);
369
0
  if (!pim_msg_curr) {
370
0
    zlog_warn(
371
0
      "%s: failure encoding group address %pPA: space left=%d",
372
0
      __func__, &group_addr, remain);
373
0
    return -1;
374
0
  }
375
376
  /* Encode source */
377
0
  remain = buf_pastend - pim_msg_curr;
378
0
  pim_msg_curr = pim_msg_addr_encode_ucast(pim_msg_curr, source_addr);
379
0
  if (!pim_msg_curr) {
380
0
    zlog_warn(
381
0
      "%s: failure encoding source address %pPA: space left=%d",
382
0
      __func__, &source_addr, remain);
383
0
    return -2;
384
0
  }
385
386
  /* Metric preference */
387
0
  pim_write_uint32(pim_msg_curr,
388
0
       rpt_bit_flag ? metric_preference | 0x80000000
389
0
              : metric_preference);
390
0
  pim_msg_curr += 4;
391
392
  /* Route metric */
393
0
  pim_write_uint32(pim_msg_curr, route_metric);
394
0
  pim_msg_curr += 4;
395
396
  /*
397
    Add PIM header
398
  */
399
0
  pim_msg_size = pim_msg_curr - pim_msg;
400
0
  pim_msg_build_header(pim_ifp->primary_address,
401
0
           qpim_all_pim_routers_addr, pim_msg, pim_msg_size,
402
0
           PIM_MSG_TYPE_ASSERT, false);
403
404
0
  return pim_msg_size;
405
0
}
406
407
static int pim_assert_do(struct pim_ifchannel *ch,
408
       struct pim_assert_metric metric)
409
0
{
410
0
  struct interface *ifp;
411
0
  struct pim_interface *pim_ifp;
412
0
  uint8_t pim_msg[1000];
413
0
  int pim_msg_size;
414
415
0
  ifp = ch->interface;
416
0
  if (!ifp) {
417
0
    if (PIM_DEBUG_PIM_TRACE)
418
0
      zlog_debug("%s: channel%s has no associated interface!",
419
0
           __func__, ch->sg_str);
420
0
    return -1;
421
0
  }
422
0
  pim_ifp = ifp->info;
423
0
  if (!pim_ifp) {
424
0
    if (PIM_DEBUG_PIM_TRACE)
425
0
      zlog_debug(
426
0
        "%s: channel %s pim not enabled on interface: %s",
427
0
        __func__, ch->sg_str, ifp->name);
428
0
    return -1;
429
0
  }
430
431
0
  pim_msg_size =
432
0
    pim_assert_build_msg(pim_msg, sizeof(pim_msg), ifp, ch->sg.grp,
433
0
             ch->sg.src, metric.metric_preference,
434
0
             metric.route_metric, metric.rpt_bit_flag);
435
0
  if (pim_msg_size < 1) {
436
0
    zlog_warn(
437
0
      "%s: failure building PIM assert message: msg_size=%d",
438
0
      __func__, pim_msg_size);
439
0
    return -2;
440
0
  }
441
442
  /*
443
    RFC 4601: 4.3.1.  Sending Hello Messages
444
445
    Thus, if a router needs to send a Join/Prune or Assert message on
446
    an interface on which it has not yet sent a Hello message with the
447
    currently configured IP address, then it MUST immediately send the
448
    relevant Hello message without waiting for the Hello Timer to
449
    expire, followed by the Join/Prune or Assert message.
450
  */
451
0
  pim_hello_require(ifp);
452
453
0
  if (PIM_DEBUG_PIM_TRACE) {
454
0
    zlog_debug("%s: to %s: (S,G)=%s pref=%u metric=%u rpt_bit=%u",
455
0
         __func__, ifp->name, ch->sg_str,
456
0
         metric.metric_preference, metric.route_metric,
457
0
         PIM_FORCE_BOOLEAN(metric.rpt_bit_flag));
458
0
  }
459
0
  if (!pim_ifp->pim_passive_enable)
460
0
    ++pim_ifp->pim_ifstat_assert_send;
461
462
0
  if (pim_msg_send(pim_ifp->pim_sock_fd, pim_ifp->primary_address,
463
0
       qpim_all_pim_routers_addr, pim_msg, pim_msg_size,
464
0
       ifp)) {
465
0
    zlog_warn("%s: could not send PIM message on interface %s",
466
0
        __func__, ifp->name);
467
0
    return -3;
468
0
  }
469
470
0
  return 0;
471
0
}
472
473
int pim_assert_send(struct pim_ifchannel *ch)
474
0
{
475
0
  return pim_assert_do(ch, ch->ifassert_my_metric);
476
0
}
477
478
/*
479
  RFC 4601: 4.6.4.  AssertCancel Messages
480
481
  An AssertCancel(S,G) is an infinite metric assert with the RPT bit
482
  set that names S as the source.
483
 */
484
static int pim_assert_cancel(struct pim_ifchannel *ch)
485
0
{
486
0
  struct pim_assert_metric metric;
487
488
0
  metric.rpt_bit_flag = 0;
489
0
  metric.metric_preference = PIM_ASSERT_METRIC_PREFERENCE_MAX;
490
0
  metric.route_metric = PIM_ASSERT_ROUTE_METRIC_MAX;
491
0
  metric.ip_address = ch->sg.src;
492
493
0
  return pim_assert_do(ch, metric);
494
0
}
495
496
static void on_assert_timer(struct event *t)
497
0
{
498
0
  struct pim_ifchannel *ch;
499
0
  struct interface *ifp;
500
0
501
0
  ch = EVENT_ARG(t);
502
0
503
0
  ifp = ch->interface;
504
0
505
0
  if (PIM_DEBUG_PIM_TRACE) {
506
0
    zlog_debug("%s: (S,G)=%s timer expired on interface %s",
507
0
         __func__, ch->sg_str, ifp->name);
508
0
  }
509
0
510
0
  ch->t_ifassert_timer = NULL;
511
0
512
0
  switch (ch->ifassert_state) {
513
0
  case PIM_IFASSERT_I_AM_WINNER:
514
0
    assert_action_a3(ch);
515
0
    break;
516
0
  case PIM_IFASSERT_I_AM_LOSER:
517
0
    assert_action_a5(ch);
518
0
    break;
519
0
  case PIM_IFASSERT_NOINFO: {
520
0
    if (PIM_DEBUG_PIM_EVENTS)
521
0
      zlog_warn(
522
0
        "%s: (S,G)=%s invalid assert state %d on interface %s",
523
0
        __func__, ch->sg_str, ch->ifassert_state,
524
0
        ifp->name);
525
0
  }
526
0
  }
527
0
}
528
529
static void assert_timer_off(struct pim_ifchannel *ch)
530
5
{
531
5
  if (PIM_DEBUG_PIM_TRACE) {
532
0
    if (ch->t_ifassert_timer) {
533
0
      zlog_debug(
534
0
        "%s: (S,G)=%s cancelling timer on interface %s",
535
0
        __func__, ch->sg_str, ch->interface->name);
536
0
    }
537
0
  }
538
5
  EVENT_OFF(ch->t_ifassert_timer);
539
5
}
540
541
static void pim_assert_timer_set(struct pim_ifchannel *ch, int interval)
542
5
{
543
5
  assert_timer_off(ch);
544
545
5
  if (PIM_DEBUG_PIM_TRACE) {
546
0
    zlog_debug("%s: (S,G)=%s starting %u sec timer on interface %s",
547
0
         __func__, ch->sg_str, interval, ch->interface->name);
548
0
  }
549
550
5
  event_add_timer(router->master, on_assert_timer, ch, interval,
551
5
      &ch->t_ifassert_timer);
552
5
}
553
554
static void pim_assert_timer_reset(struct pim_ifchannel *ch)
555
0
{
556
0
  pim_assert_timer_set(ch,
557
0
           PIM_ASSERT_TIME - PIM_ASSERT_OVERRIDE_INTERVAL);
558
0
}
559
560
/*
561
  RFC 4601: 4.6.1.  (S,G) Assert Message State Machine
562
563
  (S,G) Assert State machine Actions
564
565
  A1:  Send Assert(S,G).
566
  Set Assert Timer to (Assert_Time - Assert_Override_Interval).
567
  Store self as AssertWinner(S,G,I).
568
  Store spt_assert_metric(S,I) as AssertWinnerMetric(S,G,I).
569
*/
570
int assert_action_a1(struct pim_ifchannel *ch)
571
0
{
572
0
  struct interface *ifp = ch->interface;
573
0
  struct pim_interface *pim_ifp;
574
575
0
  pim_ifp = ifp->info;
576
0
  if (!pim_ifp) {
577
0
    zlog_warn("%s: (S,G)=%s multicast not enabled on interface %s",
578
0
        __func__, ch->sg_str, ifp->name);
579
0
    return -1; /* must return since pim_ifp is used below */
580
0
  }
581
582
  /* Switch to I_AM_WINNER before performing action_a3 below */
583
0
  pim_ifassert_winner_set(
584
0
    ch, PIM_IFASSERT_I_AM_WINNER, pim_ifp->primary_address,
585
0
    pim_macro_spt_assert_metric(&ch->upstream->rpf,
586
0
              pim_ifp->primary_address));
587
588
0
  if (assert_action_a3(ch)) {
589
0
    zlog_warn(
590
0
      "%s: (S,G)=%s assert_action_a3 failure on interface %s",
591
0
      __func__, ch->sg_str, ifp->name);
592
    /* warning only */
593
0
  }
594
595
0
  if (ch->ifassert_state != PIM_IFASSERT_I_AM_WINNER) {
596
0
    if (PIM_DEBUG_PIM_EVENTS)
597
0
      zlog_warn(
598
0
        "%s: channel%s not in expected PIM_IFASSERT_I_AM_WINNER state",
599
0
        __func__, ch->sg_str);
600
0
  }
601
602
0
  return 0;
603
0
}
604
605
/*
606
  RFC 4601: 4.6.1.  (S,G) Assert Message State Machine
607
608
  (S,G) Assert State machine Actions
609
610
     A2:  Store new assert winner as AssertWinner(S,G,I) and assert
611
    winner metric as AssertWinnerMetric(S,G,I).
612
    Set Assert Timer to Assert_Time.
613
*/
614
static void assert_action_a2(struct pim_ifchannel *ch,
615
           struct pim_assert_metric winner_metric)
616
5
{
617
5
  pim_ifassert_winner_set(ch, PIM_IFASSERT_I_AM_LOSER,
618
5
        winner_metric.ip_address, winner_metric);
619
620
5
  pim_assert_timer_set(ch, PIM_ASSERT_TIME);
621
622
5
  if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER) {
623
0
    if (PIM_DEBUG_PIM_EVENTS)
624
0
      zlog_warn(
625
0
        "%s: channel%s not in expected PIM_IFASSERT_I_AM_LOSER state",
626
0
        __func__, ch->sg_str);
627
0
  }
628
5
}
629
630
/*
631
  RFC 4601: 4.6.1.  (S,G) Assert Message State Machine
632
633
  (S,G) Assert State machine Actions
634
635
  A3:  Send Assert(S,G).
636
  Set Assert Timer to (Assert_Time - Assert_Override_Interval).
637
*/
638
static int assert_action_a3(struct pim_ifchannel *ch)
639
0
{
640
0
  if (ch->ifassert_state != PIM_IFASSERT_I_AM_WINNER) {
641
0
    if (PIM_DEBUG_PIM_EVENTS)
642
0
      zlog_warn(
643
0
        "%s: channel%s expected to be in PIM_IFASSERT_I_AM_WINNER state",
644
0
        __func__, ch->sg_str);
645
0
    return -1;
646
0
  }
647
648
0
  pim_assert_timer_reset(ch);
649
650
0
  if (pim_assert_send(ch)) {
651
0
    zlog_warn("%s: (S,G)=%s failure sending assert on interface %s",
652
0
        __func__, ch->sg_str, ch->interface->name);
653
0
    return -1;
654
0
  }
655
656
0
  return 0;
657
0
}
658
659
/*
660
  RFC 4601: 4.6.1.  (S,G) Assert Message State Machine
661
662
  (S,G) Assert State machine Actions
663
664
     A4:  Send AssertCancel(S,G).
665
    Delete assert info (AssertWinner(S,G,I) and
666
    AssertWinnerMetric(S,G,I) will then return their default
667
    values).
668
*/
669
void assert_action_a4(struct pim_ifchannel *ch)
670
0
{
671
0
  if (pim_assert_cancel(ch)) {
672
0
    zlog_warn("%s: failure sending AssertCancel%s on interface %s",
673
0
        __func__, ch->sg_str, ch->interface->name);
674
    /* log warning only */
675
0
  }
676
677
0
  assert_action_a5(ch);
678
679
0
  if (ch->ifassert_state != PIM_IFASSERT_NOINFO) {
680
0
    if (PIM_DEBUG_PIM_EVENTS)
681
0
      zlog_warn(
682
0
        "%s: channel%s not in PIM_IFASSERT_NOINFO state as expected",
683
0
        __func__, ch->sg_str);
684
0
  }
685
0
}
686
687
/*
688
  RFC 4601: 4.6.1.  (S,G) Assert Message State Machine
689
690
  (S,G) Assert State machine Actions
691
692
  A5: Delete assert info (AssertWinner(S,G,I) and
693
  AssertWinnerMetric(S,G,I) will then return their default values).
694
*/
695
void assert_action_a5(struct pim_ifchannel *ch)
696
2
{
697
2
  reset_ifassert_state(ch);
698
2
  if (ch->ifassert_state != PIM_IFASSERT_NOINFO) {
699
0
    if (PIM_DEBUG_PIM_EVENTS)
700
0
      zlog_warn(
701
0
        "%s: channel%s not in PIM_IFSSERT_NOINFO state as expected",
702
0
        __func__, ch->sg_str);
703
0
  }
704
2
}
705
706
/*
707
  RFC 4601: 4.6.1.  (S,G) Assert Message State Machine
708
709
  (S,G) Assert State machine Actions
710
711
     A6:  Store new assert winner as AssertWinner(S,G,I) and assert
712
    winner metric as AssertWinnerMetric(S,G,I).
713
    Set Assert Timer to Assert_Time.
714
    If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true)
715
    set SPTbit(S,G) to true.
716
*/
717
static void assert_action_a6(struct pim_ifchannel *ch,
718
           struct pim_assert_metric winner_metric)
719
2
{
720
2
  assert_action_a2(ch, winner_metric);
721
722
  /*
723
    If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true) set
724
    SPTbit(S,G) to true.
725
  */
726
2
  if (ch->upstream->rpf.source_nexthop.interface == ch->interface)
727
0
    if (ch->upstream->join_state == PIM_UPSTREAM_JOINED)
728
0
      ch->upstream->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
729
730
2
  if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER) {
731
0
    if (PIM_DEBUG_PIM_EVENTS)
732
0
      zlog_warn(
733
0
        "%s: channel%s not in PIM_IFASSERT_I_AM_LOSER state as expected",
734
0
        __func__, ch->sg_str);
735
0
  }
736
2
}