Coverage Report

Created: 2026-09-14 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/frr/pimd/pim_zpthread.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
#include <lib/log.h>
9
#include <lib/lib_errors.h>
10
11
#include "pimd.h"
12
#include "pim_instance.h"
13
#include "pim_mlag.h"
14
#include "pim_zebra.h"
15
16
extern struct zclient *zclient;
17
18
#define PIM_MLAG_POST_LIMIT 100
19
20
int32_t mlag_bulk_cnt;
21
22
static void pim_mlag_zebra_fill_header(enum mlag_msg_type msg_type)
23
0
{
24
0
  uint32_t fill_msg_type = msg_type;
25
0
  uint16_t data_len = 0;
26
0
  uint16_t msg_cnt = 1;
27
0
28
0
  switch (msg_type) {
29
0
  case MLAG_REGISTER:
30
0
  case MLAG_DEREGISTER:
31
0
    data_len = sizeof(struct mlag_msg);
32
0
    break;
33
0
  case MLAG_MROUTE_ADD:
34
0
    data_len = sizeof(struct mlag_mroute_add);
35
0
    fill_msg_type = MLAG_MROUTE_ADD_BULK;
36
0
    break;
37
0
  case MLAG_MROUTE_DEL:
38
0
    data_len = sizeof(struct mlag_mroute_del);
39
0
    fill_msg_type = MLAG_MROUTE_DEL_BULK;
40
0
    break;
41
0
  case MLAG_MSG_NONE:
42
0
    return;
43
0
  case MLAG_STATUS_UPDATE:
44
0
  case MLAG_DUMP:
45
0
  case MLAG_MROUTE_ADD_BULK:
46
0
  case MLAG_MROUTE_DEL_BULK:
47
0
  case MLAG_PIM_CFG_DUMP:
48
0
  case MLAG_VXLAN_UPDATE:
49
0
  case MLAG_PEER_FRR_STATUS:
50
0
    data_len = 0;
51
0
    break;
52
0
  }
53
0
54
0
  stream_reset(router->mlag_stream);
55
0
  /* ADD Hedaer */
56
0
  stream_putl(router->mlag_stream, fill_msg_type);
57
0
  /*
58
0
   * In case of Bulk actual size & msg_cnt will be updated
59
0
   * just before writing onto zebra
60
0
   */
61
0
  stream_putw(router->mlag_stream, data_len);
62
0
  stream_putw(router->mlag_stream, msg_cnt);
63
0
64
0
  if (PIM_DEBUG_MLAG)
65
0
    zlog_debug(":%s: msg_type: %d/%d len %d",
66
0
         __func__, msg_type, fill_msg_type, data_len);
67
0
}
68
69
static void pim_mlag_zebra_flush_buffer(void)
70
0
{
71
0
  uint32_t msg_type;
72
0
73
0
  /* Stream had bulk messages update the Hedaer */
74
0
  if (mlag_bulk_cnt > 1) {
75
0
    /*
76
0
     * No need to reset the pointer, below api reads from data[0]
77
0
     */
78
0
    STREAM_GETL(router->mlag_stream, msg_type);
79
0
    if (msg_type == MLAG_MROUTE_ADD_BULK) {
80
0
      stream_putw_at(
81
0
        router->mlag_stream, 4,
82
0
        (mlag_bulk_cnt * sizeof(struct mlag_mroute_add)));
83
0
      stream_putw_at(router->mlag_stream, 6, mlag_bulk_cnt);
84
0
    } else if (msg_type == MLAG_MROUTE_DEL_BULK) {
85
0
      stream_putw_at(
86
0
        router->mlag_stream, 4,
87
0
        (mlag_bulk_cnt * sizeof(struct mlag_mroute_del)));
88
0
      stream_putw_at(router->mlag_stream, 6, mlag_bulk_cnt);
89
0
    } else {
90
0
      flog_err(EC_LIB_ZAPI_ENCODE,
91
0
        "unknown bulk message type %d bulk_count %d",
92
0
        msg_type, mlag_bulk_cnt);
93
0
      stream_reset(router->mlag_stream);
94
0
      mlag_bulk_cnt = 0;
95
0
      return;
96
0
    }
97
0
  }
98
0
99
0
  zclient_send_mlag_data(zclient, router->mlag_stream);
100
0
stream_failure:
101
0
  stream_reset(router->mlag_stream);
102
0
  mlag_bulk_cnt = 0;
103
0
}
104
105
/*
106
 * Only ROUTE add & Delete will be bulked.
107
 * Buffer will be flushed, when
108
 * 1) there were no messages in the queue
109
 * 2) Curr_msg_type != prev_msg_type
110
 */
111
112
static void pim_mlag_zebra_check_for_buffer_flush(uint32_t curr_msg_type,
113
              uint32_t prev_msg_type)
114
0
{
115
0
  /* First Message, keep bulking */
116
0
  if (prev_msg_type == MLAG_MSG_NONE) {
117
0
    mlag_bulk_cnt = 1;
118
0
    return;
119
0
  }
120
0
121
0
  /*msg type is route add & delete, keep bulking */
122
0
  if (curr_msg_type == prev_msg_type
123
0
      && (curr_msg_type == MLAG_MROUTE_ADD
124
0
    || curr_msg_type == MLAG_MROUTE_DEL)) {
125
0
    mlag_bulk_cnt++;
126
0
    return;
127
0
  }
128
0
129
0
  pim_mlag_zebra_flush_buffer();
130
0
}
131
132
/*
133
 * Thsi thread reads the clients data from the Gloabl queue and encodes with
134
 * protobuf and pass on to the MLAG socket.
135
 */
136
static void pim_mlag_zthread_handler(struct event *event)
137
0
{
138
0
  struct stream *read_s;
139
0
  uint32_t wr_count = 0;
140
0
  uint32_t prev_msg_type = MLAG_MSG_NONE;
141
0
  uint32_t curr_msg_type = MLAG_MSG_NONE;
142
0
143
0
  router->zpthread_mlag_write = NULL;
144
0
  wr_count = stream_fifo_count_safe(router->mlag_fifo);
145
0
146
0
  if (PIM_DEBUG_MLAG)
147
0
    zlog_debug(":%s: Processing MLAG write, %d messages in queue",
148
0
         __func__, wr_count);
149
0
150
0
  if (wr_count == 0)
151
0
    return;
152
0
153
0
  for (wr_count = 0; wr_count < PIM_MLAG_POST_LIMIT; wr_count++) {
154
0
    /* FIFO is empty,wait for teh message to be add */
155
0
    if (stream_fifo_count_safe(router->mlag_fifo) == 0)
156
0
      break;
157
0
158
0
    read_s = stream_fifo_pop_safe(router->mlag_fifo);
159
0
    if (!read_s) {
160
0
      zlog_debug(":%s: Got a NULL Messages, some thing wrong",
161
0
           __func__);
162
0
      break;
163
0
    }
164
0
    STREAM_GETL(read_s, curr_msg_type);
165
0
    /*
166
0
     * Check for Buffer Overflow,
167
0
     * MLAG Can't process more than 'PIM_MLAG_BUF_LIMIT' bytes
168
0
     */
169
0
    if (router->mlag_stream->endp + read_s->endp + ZEBRA_HEADER_SIZE
170
0
        > MLAG_BUF_LIMIT)
171
0
      pim_mlag_zebra_flush_buffer();
172
0
173
0
    pim_mlag_zebra_check_for_buffer_flush(curr_msg_type,
174
0
                  prev_msg_type);
175
0
176
0
    /*
177
0
     * First message to Buffer, fill the Header
178
0
     */
179
0
    if (router->mlag_stream->endp == 0)
180
0
      pim_mlag_zebra_fill_header(curr_msg_type);
181
0
182
0
    /*
183
0
     * add the data now
184
0
     */
185
0
    stream_put(router->mlag_stream, read_s->data + read_s->getp,
186
0
         read_s->endp - read_s->getp);
187
0
188
0
    stream_free(read_s);
189
0
    prev_msg_type = curr_msg_type;
190
0
  }
191
0
192
0
stream_failure:
193
0
  /*
194
0
   * we are here , because
195
0
   * 1. Queue might be empty
196
0
   * 2. we crossed the max Q Read limit
197
0
   * In any acse flush the buffer towards zebra
198
0
   */
199
0
  pim_mlag_zebra_flush_buffer();
200
0
201
0
  if (wr_count >= PIM_MLAG_POST_LIMIT)
202
0
    pim_mlag_signal_zpthread();
203
0
}
204
205
206
int pim_mlag_signal_zpthread(void)
207
0
{
208
0
  if (router->master) {
209
0
    if (PIM_DEBUG_MLAG)
210
0
      zlog_debug(":%s: Scheduling PIM MLAG write Thread",
211
0
           __func__);
212
0
    event_add_event(router->master, pim_mlag_zthread_handler, NULL,
213
0
        0, &router->zpthread_mlag_write);
214
0
  }
215
0
  return (0);
216
0
}