Coverage Report

Created: 2025-07-14 06:48

/src/frr/zebra/zebra_mlag.c
Line
Count
Source (jump to first uncovered line)
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/* Zebra Mlag Code.
3
 * Copyright (C) 2018 Cumulus Networks, Inc.
4
 *                    Donald Sharp
5
 */
6
#include "zebra.h"
7
8
#include "command.h"
9
#include "hook.h"
10
#include "frr_pthread.h"
11
#include "mlag.h"
12
13
#include "zebra/zebra_mlag.h"
14
#include "zebra/zebra_mlag_vty.h"
15
#include "zebra/zebra_router.h"
16
#include "zebra/zapi_msg.h"
17
#include "zebra/debug.h"
18
19
#ifdef HAVE_PROTOBUF_VERSION_3
20
#include "mlag/mlag.pb-c.h"
21
#endif
22
23
DEFINE_HOOK(zebra_mlag_private_write_data,
24
      (uint8_t *data, uint32_t len), (data, len));
25
DEFINE_HOOK(zebra_mlag_private_monitor_state, (), ());
26
DEFINE_HOOK(zebra_mlag_private_open_channel, (), ());
27
DEFINE_HOOK(zebra_mlag_private_close_channel, (), ());
28
DEFINE_HOOK(zebra_mlag_private_cleanup_data, (), ());
29
30
0
#define ZEBRA_MLAG_METADATA_LEN 4
31
0
#define ZEBRA_MLAG_MSG_BCAST 0xFFFFFFFF
32
33
uint8_t mlag_wr_buffer[ZEBRA_MLAG_BUF_LIMIT];
34
uint8_t mlag_rd_buffer[ZEBRA_MLAG_BUF_LIMIT];
35
36
static bool test_mlag_in_progress;
37
38
static int zebra_mlag_signal_write_thread(void);
39
static void zebra_mlag_terminate_pthread(struct event *event);
40
static void zebra_mlag_post_data_from_main_thread(struct event *thread);
41
static void zebra_mlag_publish_process_state(struct zserv *client,
42
               zebra_message_types_t msg_type);
43
44
/**********************MLAG Interaction***************************************/
45
46
/*
47
 * API to post the Registration to MLAGD
48
 * MLAG will not process any messages with out the registration
49
 */
50
void zebra_mlag_send_register(void)
51
0
{
52
0
  struct stream *s = NULL;
53
54
0
  s = stream_new(sizeof(struct mlag_msg));
55
56
0
  stream_putl(s, MLAG_REGISTER);
57
0
  stream_putw(s, MLAG_MSG_NULL_PAYLOAD);
58
0
  stream_putw(s, MLAG_MSG_NO_BATCH);
59
0
  stream_fifo_push_safe(zrouter.mlag_info.mlag_fifo, s);
60
0
  zebra_mlag_signal_write_thread();
61
62
0
  if (IS_ZEBRA_DEBUG_MLAG)
63
0
    zlog_debug("%s: Enqueued MLAG Register to MLAG Thread ",
64
0
         __func__);
65
0
}
66
67
/*
68
 * API to post the De-Registration to MLAGD
69
 * MLAG will not process any messages after the de-registration
70
 */
71
void zebra_mlag_send_deregister(void)
72
0
{
73
0
  struct stream *s = NULL;
74
75
0
  s = stream_new(sizeof(struct mlag_msg));
76
77
0
  stream_putl(s, MLAG_DEREGISTER);
78
0
  stream_putw(s, MLAG_MSG_NULL_PAYLOAD);
79
0
  stream_putw(s, MLAG_MSG_NO_BATCH);
80
0
  stream_fifo_push_safe(zrouter.mlag_info.mlag_fifo, s);
81
0
  zebra_mlag_signal_write_thread();
82
83
0
  if (IS_ZEBRA_DEBUG_MLAG)
84
0
    zlog_debug("%s: Enqueued MLAG De-Register to MLAG Thread ",
85
0
         __func__);
86
0
}
87
88
/*
89
 * API To handle MLAG Received data
90
 * Decodes the data using protobuf and enqueue to main thread
91
 * main thread publish this to clients based on client subscription
92
 */
93
void zebra_mlag_process_mlag_data(uint8_t *data, uint32_t len)
94
0
{
95
0
  struct stream *s = NULL;
96
0
  int msg_type = 0;
97
98
0
  s = stream_new(ZEBRA_MLAG_BUF_LIMIT);
99
  /*
100
   * Place holder we need the message type first
101
   */
102
0
  stream_putl(s, msg_type);
103
0
  msg_type = zebra_mlag_protobuf_decode_message(s, data, len);
104
105
0
  if (msg_type <= 0) {
106
    /* Something went wrong in decoding */
107
0
    stream_free(s);
108
0
    zlog_err("%s: failed to process mlag data-%d, %u", __func__,
109
0
       msg_type, len);
110
0
    return;
111
0
  }
112
113
  /*
114
   * additional four bytes are for message type
115
   */
116
0
  stream_putl_at(s, 0, msg_type);
117
0
  event_add_event(zrouter.master, zebra_mlag_post_data_from_main_thread,
118
0
      s, 0, NULL);
119
0
}
120
121
/**********************End of MLAG Interaction********************************/
122
123
/************************MLAG Thread Processing*******************************/
124
125
/*
126
 * after posting every 'ZEBRA_MLAG_POST_LIMIT' packets, MLAG Thread will be
127
 * yielded to give CPU for other threads
128
 */
129
#define ZEBRA_MLAG_POST_LIMIT 100
130
131
/*
132
 * This thread reads the clients data from the Global queue and encodes with
133
 * protobuf and pass on to the MLAG socket.
134
 */
135
static void zebra_mlag_client_msg_handler(struct event *event)
136
0
{
137
0
  struct stream *s;
138
0
  uint32_t wr_count = 0;
139
0
  uint32_t msg_type = 0;
140
0
  uint32_t max_count = 0;
141
0
  int len = 0;
142
0
143
0
  wr_count = stream_fifo_count_safe(zrouter.mlag_info.mlag_fifo);
144
0
  if (IS_ZEBRA_DEBUG_MLAG)
145
0
    zlog_debug(":%s: Processing MLAG write, %u messages in queue",
146
0
         __func__, wr_count);
147
0
148
0
  max_count = MIN(wr_count, ZEBRA_MLAG_POST_LIMIT);
149
0
150
0
  for (wr_count = 0; wr_count < max_count; wr_count++) {
151
0
    s = stream_fifo_pop_safe(zrouter.mlag_info.mlag_fifo);
152
0
    if (!s) {
153
0
      zlog_debug(":%s: Got a NULL Messages, some thing wrong",
154
0
           __func__);
155
0
      break;
156
0
    }
157
0
158
0
    /*
159
0
     * Encode the data now
160
0
     */
161
0
    len = zebra_mlag_protobuf_encode_client_data(s, &msg_type);
162
0
163
0
    /*
164
0
     * write to MCLAGD
165
0
     */
166
0
    if (len > 0) {
167
0
      hook_call(zebra_mlag_private_write_data,
168
0
          mlag_wr_buffer, len);
169
0
170
0
      /*
171
0
       * If message type is De-register, send a signal to main
172
0
       * thread, so that necessary cleanup will be done by
173
0
       * main thread.
174
0
       */
175
0
      if (msg_type == MLAG_DEREGISTER) {
176
0
        event_add_event(zrouter.master,
177
0
            zebra_mlag_terminate_pthread,
178
0
            NULL, 0, NULL);
179
0
      }
180
0
    }
181
0
182
0
    stream_free(s);
183
0
  }
184
0
185
0
  if (IS_ZEBRA_DEBUG_MLAG)
186
0
    zlog_debug(":%s: Posted  %d messages to MLAGD", __func__,
187
0
         wr_count);
188
0
  /*
189
0
   * Currently there is only message write task is enqueued to this
190
0
   * thread, yielding was added for future purpose, so that this thread
191
0
   * can server other tasks also and in case FIFO is empty, this task will
192
0
   * be schedule when main thread adds some messages
193
0
   */
194
0
  if (wr_count >= ZEBRA_MLAG_POST_LIMIT)
195
0
    zebra_mlag_signal_write_thread();
196
0
}
197
198
/*
199
 * API to handle the process state.
200
 * In case of Down, Zebra keep monitoring the MLAG state.
201
 * all the state Notifications will be published to clients
202
 */
203
void zebra_mlag_handle_process_state(enum zebra_mlag_state state)
204
0
{
205
0
  if (state == MLAG_UP) {
206
0
    zrouter.mlag_info.connected = true;
207
0
    zebra_mlag_publish_process_state(NULL, ZEBRA_MLAG_PROCESS_UP);
208
0
    zebra_mlag_send_register();
209
0
  } else if (state == MLAG_DOWN) {
210
0
    zrouter.mlag_info.connected = false;
211
0
    zebra_mlag_publish_process_state(NULL, ZEBRA_MLAG_PROCESS_DOWN);
212
0
    hook_call(zebra_mlag_private_monitor_state);
213
0
  }
214
0
}
215
216
/***********************End of MLAG Thread processing*************************/
217
218
/*************************Multi-entratnt Api's********************************/
219
220
/*
221
 * Provider api to signal that work/events are available
222
 * for the Zebra MLAG Write pthread.
223
 * This API is called from 2 pthreads..
224
 * 1) by main thread when client posts a MLAG Message
225
 * 2) by MLAG Thread, in case of yield
226
 * though this api, is called from two threads we don't need any locking
227
 * because Thread task enqueue is thread safe means internally it had
228
 * necessary protection
229
 */
230
static int zebra_mlag_signal_write_thread(void)
231
0
{
232
0
  if (IS_ZEBRA_DEBUG_MLAG)
233
0
    zlog_debug(":%s: Scheduling MLAG write", __func__);
234
  /*
235
   * This api will be called from Both main & MLAG Threads.
236
   * main thread writes, "zrouter.mlag_info.th_master" only
237
   * during Zebra Init/after MLAG thread is destroyed.
238
   * so it is safe to use without any locking
239
   */
240
0
  event_add_event(zrouter.mlag_info.th_master,
241
0
      zebra_mlag_client_msg_handler, NULL, 0,
242
0
      &zrouter.mlag_info.t_write);
243
0
  return 0;
244
0
}
245
246
/*
247
 * API will be used to publish the MLAG state to interested clients
248
 * In case client is passed, state is posted only for that client,
249
 * otherwise to all interested clients
250
 * this api can be called from two threads.
251
 * 1) from main thread: when client is passed
252
 * 2) from MLAG Thread: when client is NULL
253
 *
254
 * In second case, to avoid global data access data will be post to Main
255
 * thread, so that actual posting to clients will happen from Main thread.
256
 */
257
static void zebra_mlag_publish_process_state(struct zserv *client,
258
               zebra_message_types_t msg_type)
259
0
{
260
0
  struct stream *s;
261
262
0
  if (IS_ZEBRA_DEBUG_MLAG)
263
0
    zlog_debug("%s: Publishing MLAG process state:%s to %s Client",
264
0
         __func__,
265
0
         (msg_type == ZEBRA_MLAG_PROCESS_UP) ? "UP" : "DOWN",
266
0
         (client) ? "one" : "all");
267
268
0
  if (client) {
269
0
    s = stream_new(ZEBRA_HEADER_SIZE);
270
0
    zclient_create_header(s, msg_type, VRF_DEFAULT);
271
0
    zserv_send_message(client, s);
272
0
    return;
273
0
  }
274
275
276
  /*
277
   * additional four bytes are for mesasge type
278
   */
279
0
  s = stream_new(ZEBRA_HEADER_SIZE + ZEBRA_MLAG_METADATA_LEN);
280
0
  stream_putl(s, ZEBRA_MLAG_MSG_BCAST);
281
0
  zclient_create_header(s, msg_type, VRF_DEFAULT);
282
0
  event_add_event(zrouter.master, zebra_mlag_post_data_from_main_thread,
283
0
      s, 0, NULL);
284
0
}
285
286
/**************************End of Multi-entrant Apis**************************/
287
288
/***********************Zebra Main thread processing**************************/
289
290
/*
291
 * To avoid data corruption, messages will be post to clients only from
292
 * main thread, because for that access was needed for clients list.
293
 * so instead of forcing the locks, messages will be posted from main thread.
294
 */
295
static void zebra_mlag_post_data_from_main_thread(struct event *thread)
296
0
{
297
0
  struct stream *s = EVENT_ARG(thread);
298
0
  struct stream *zebra_s = NULL;
299
0
  struct listnode *node;
300
0
  struct zserv *client;
301
0
  uint32_t msg_type = 0;
302
0
  uint32_t msg_len = 0;
303
0
304
0
  if (!s)
305
0
    return;
306
0
307
0
  STREAM_GETL(s, msg_type);
308
0
  if (IS_ZEBRA_DEBUG_MLAG)
309
0
    zlog_debug(
310
0
      "%s: Posting MLAG data for msg_type:0x%x to interested clients",
311
0
      __func__, msg_type);
312
0
313
0
  msg_len = s->endp - ZEBRA_MLAG_METADATA_LEN;
314
0
  for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) {
315
0
    if (client->mlag_updates_interested == true) {
316
0
      if (msg_type != ZEBRA_MLAG_MSG_BCAST
317
0
          && !CHECK_FLAG(client->mlag_reg_mask1,
318
0
             (1 << msg_type))) {
319
0
        continue;
320
0
      }
321
0
322
0
      if (IS_ZEBRA_DEBUG_MLAG)
323
0
        zlog_debug(
324
0
          "%s: Posting MLAG data of length-%d to client:%d ",
325
0
          __func__, msg_len, client->proto);
326
0
327
0
      zebra_s = stream_new(msg_len);
328
0
      STREAM_GET(zebra_s->data, s, msg_len);
329
0
      zebra_s->endp = msg_len;
330
0
      stream_putw_at(zebra_s, 0, msg_len);
331
0
332
0
      /*
333
0
       * This stream will be enqueued to client_obuf, it will
334
0
       * be freed after posting to client socket.
335
0
       */
336
0
      zserv_send_message(client, zebra_s);
337
0
      zebra_s = NULL;
338
0
    }
339
0
  }
340
0
341
0
stream_failure:
342
0
  stream_free(s);
343
0
  if (zebra_s)
344
0
    stream_free(zebra_s);
345
0
}
346
347
/*
348
 * Start the MLAG Thread, this will be used to write client data on to
349
 * MLAG Process and to read the data from MLAG and post to clients.
350
 * when all clients are un-registered, this Thread will be
351
 * suspended.
352
 */
353
static void zebra_mlag_spawn_pthread(void)
354
0
{
355
  /* Start MLAG write pthread */
356
0
#ifdef FUZZING
357
0
  return;
358
0
#endif
359
360
0
  struct frr_pthread_attr pattr = {.start =
361
0
             frr_pthread_attr_default.start,
362
0
           .stop = frr_pthread_attr_default.stop};
363
364
0
  zrouter.mlag_info.zebra_pth_mlag =
365
0
    frr_pthread_new(&pattr, "Zebra MLAG thread", "Zebra MLAG");
366
367
0
  zrouter.mlag_info.th_master = zrouter.mlag_info.zebra_pth_mlag->master;
368
369
370
  /* Enqueue an initial event to the Newly spawn MLAG pthread */
371
0
  zebra_mlag_signal_write_thread();
372
373
0
  frr_pthread_run(zrouter.mlag_info.zebra_pth_mlag, NULL);
374
0
}
375
376
/*
377
 * all clients are un-registered for MLAG Updates, terminate the
378
 * MLAG write thread
379
 */
380
static void zebra_mlag_terminate_pthread(struct event *event)
381
0
{
382
0
  if (IS_ZEBRA_DEBUG_MLAG)
383
0
    zlog_debug("Zebra MLAG write thread terminate called");
384
0
385
0
  if (zrouter.mlag_info.clients_interested_cnt) {
386
0
    if (IS_ZEBRA_DEBUG_MLAG)
387
0
      zlog_debug(
388
0
        "Zebra MLAG: still some clients are interested");
389
0
    return;
390
0
  }
391
0
392
0
  frr_pthread_stop(zrouter.mlag_info.zebra_pth_mlag, NULL);
393
0
394
0
  /* Destroy pthread */
395
0
  frr_pthread_destroy(zrouter.mlag_info.zebra_pth_mlag);
396
0
  zrouter.mlag_info.zebra_pth_mlag = NULL;
397
0
  zrouter.mlag_info.th_master = NULL;
398
0
  zrouter.mlag_info.t_read = NULL;
399
0
  zrouter.mlag_info.t_write = NULL;
400
0
401
0
  /*
402
0
   * Send Notification to clean private data
403
0
   */
404
0
  hook_call(zebra_mlag_private_cleanup_data);
405
0
}
406
407
/*
408
 * API to register zebra client for MLAG Updates
409
 */
410
void zebra_mlag_client_register(ZAPI_HANDLER_ARGS)
411
0
{
412
0
  struct stream *s;
413
0
  uint32_t reg_mask = 0;
414
0
  int rc = 0;
415
416
0
  if (IS_ZEBRA_DEBUG_MLAG)
417
0
    zlog_debug("Received MLAG Registration from client-proto:%d",
418
0
         client->proto);
419
420
421
  /* Get input stream.  */
422
0
  s = msg;
423
424
  /* Get data. */
425
0
  STREAM_GETL(s, reg_mask);
426
427
0
  if (client->mlag_updates_interested == true) {
428
429
0
    if (IS_ZEBRA_DEBUG_MLAG)
430
0
      zlog_debug(
431
0
        "Client is registered, existing mask: 0x%x, new mask: 0x%x",
432
0
        client->mlag_reg_mask1, reg_mask);
433
0
    if (client->mlag_reg_mask1 != reg_mask)
434
0
      client->mlag_reg_mask1 = reg_mask;
435
    /*
436
     * Client might missed MLAG-UP Notification, post-it again
437
     */
438
0
    zebra_mlag_publish_process_state(client, ZEBRA_MLAG_PROCESS_UP);
439
0
    return;
440
0
  }
441
442
443
0
  client->mlag_updates_interested = true;
444
0
  client->mlag_reg_mask1 = reg_mask;
445
0
  if (IS_ZEBRA_DEBUG_MLAG)
446
0
    zlog_debug("Registering for MLAG Updates with mask: 0x%x, ",
447
0
         client->mlag_reg_mask1);
448
449
0
  zrouter.mlag_info.clients_interested_cnt++;
450
451
0
  if (zrouter.mlag_info.clients_interested_cnt == 1) {
452
    /*
453
     * First-client for MLAG Updates,open the communication channel
454
     * with MLAG
455
     */
456
0
    if (IS_ZEBRA_DEBUG_MLAG)
457
0
      zlog_debug(
458
0
        "First client, opening the channel with MLAG");
459
#ifndef FUZZING
460
    zebra_mlag_spawn_pthread();
461
#endif
462
0
    rc = hook_call(zebra_mlag_private_open_channel);
463
0
    if (rc < 0) {
464
      /*
465
       * For some reason, zebra not able to open the
466
       * comm-channel with MLAG, so post MLAG-DOWN to client.
467
       * later when the channel is open, zebra will send
468
       * MLAG-UP
469
       */
470
0
      if (IS_ZEBRA_DEBUG_MLAG)
471
0
        zlog_debug(
472
0
          "Fail to open channel with MLAG,rc:%d, post Proto-down",
473
0
          rc);
474
0
      zebra_mlag_publish_process_state(
475
0
        client, ZEBRA_MLAG_PROCESS_DOWN);
476
0
    }
477
0
  }
478
479
0
  if (IS_ZEBRA_DEBUG_MLAG)
480
0
    zlog_debug("Client Registered successfully for MLAG Updates");
481
482
0
  if (zrouter.mlag_info.connected == true)
483
0
    zebra_mlag_publish_process_state(client, ZEBRA_MLAG_PROCESS_UP);
484
0
stream_failure:
485
0
  return;
486
0
}
487
488
/*
489
 * API to un-register for MLAG Updates
490
 */
491
void zebra_mlag_client_unregister(ZAPI_HANDLER_ARGS)
492
0
{
493
0
  if (IS_ZEBRA_DEBUG_MLAG)
494
0
    zlog_debug("Received MLAG De-Registration from client-proto:%d",
495
0
         client->proto);
496
497
0
  if (client->mlag_updates_interested == false)
498
    /* Unexpected */
499
0
    return;
500
501
0
  client->mlag_updates_interested = false;
502
0
  client->mlag_reg_mask1 = 0;
503
0
  zrouter.mlag_info.clients_interested_cnt--;
504
505
0
  if (zrouter.mlag_info.clients_interested_cnt == 0) {
506
    /*
507
     * No-client is interested for MLAG Updates,close the
508
     * communication channel with MLAG
509
     */
510
0
    if (IS_ZEBRA_DEBUG_MLAG)
511
0
      zlog_debug("Last client for MLAG, close the channel ");
512
513
    /*
514
     * Clean up flow:
515
     * =============
516
     * 1) main thread calls socket close which posts De-register
517
     * to MLAG write thread
518
     * 2) after MLAG write thread posts De-register it sends a
519
     * signal back to main thread to do the thread cleanup
520
     * this was mainly to make sure De-register is posted to MCLAGD.
521
     */
522
0
    hook_call(zebra_mlag_private_close_channel);
523
0
  }
524
525
0
  if (IS_ZEBRA_DEBUG_MLAG)
526
0
    zlog_debug(
527
0
      "Client De-Registered successfully for MLAG Updates");
528
0
}
529
530
/*
531
 * Does following things.
532
 * 1) allocated new local stream, and copies the client data and enqueue
533
 *    to MLAG Thread
534
 *  2) MLAG Thread after dequeing, encode the client data using protobuf
535
 *     and write on to MLAG
536
 */
537
void zebra_mlag_forward_client_msg(ZAPI_HANDLER_ARGS)
538
0
{
539
0
  struct stream *zebra_s;
540
0
  struct stream *mlag_s;
541
542
0
  if (IS_ZEBRA_DEBUG_MLAG)
543
0
    zlog_debug("Received Client MLAG Data from client-proto:%d",
544
0
         client->proto);
545
546
  /* Get input stream.  */
547
0
  zebra_s = msg;
548
0
  mlag_s = stream_new(zebra_s->endp);
549
550
  /*
551
   * Client data is | Zebra Header + MLAG Data |
552
   * we need to enqueue only the MLAG data, skipping Zebra Header
553
   */
554
0
  stream_put(mlag_s, zebra_s->data + zebra_s->getp,
555
0
       STREAM_READABLE(zebra_s));
556
0
  stream_fifo_push_safe(zrouter.mlag_info.mlag_fifo, mlag_s);
557
0
  zebra_mlag_signal_write_thread();
558
559
0
  if (IS_ZEBRA_DEBUG_MLAG)
560
0
    zlog_debug("%s: Enqueued Client:%d data to MLAG Thread ",
561
0
         __func__, client->proto);
562
0
}
563
564
/***********************End of Zebra Main thread processing*************/
565
566
enum mlag_role zebra_mlag_get_role(void)
567
0
{
568
0
  return zrouter.mlag_info.role;
569
0
}
570
571
int32_t zebra_mlag_test_mlag_internal(const char *none, const char *primary,
572
              const char *secondary)
573
0
{
574
0
  enum mlag_role orig = zrouter.mlag_info.role;
575
0
  char buf1[MLAG_ROLE_STRSIZE], buf2[MLAG_ROLE_STRSIZE];
576
577
0
  if (none)
578
0
    zrouter.mlag_info.role = MLAG_ROLE_NONE;
579
0
  if (primary)
580
0
    zrouter.mlag_info.role = MLAG_ROLE_PRIMARY;
581
0
  if (secondary)
582
0
    zrouter.mlag_info.role = MLAG_ROLE_SECONDARY;
583
584
0
  if (IS_ZEBRA_DEBUG_MLAG)
585
0
    zlog_debug("Test: Changing role from %s to %s",
586
0
         mlag_role2str(orig, buf1, sizeof(buf1)),
587
0
         mlag_role2str(orig, buf2, sizeof(buf2)));
588
589
0
  if (orig != zrouter.mlag_info.role) {
590
0
    zsend_capabilities_all_clients();
591
0
    if (zrouter.mlag_info.role != MLAG_ROLE_NONE) {
592
0
      if (zrouter.mlag_info.clients_interested_cnt == 0
593
0
          && !test_mlag_in_progress) {
594
0
        if (zrouter.mlag_info.zebra_pth_mlag == NULL)
595
0
          zebra_mlag_spawn_pthread();
596
0
        zrouter.mlag_info.clients_interested_cnt++;
597
0
        test_mlag_in_progress = true;
598
0
        hook_call(zebra_mlag_private_open_channel);
599
0
      }
600
0
    } else {
601
0
      if (test_mlag_in_progress) {
602
0
        test_mlag_in_progress = false;
603
0
        zrouter.mlag_info.clients_interested_cnt--;
604
0
        hook_call(zebra_mlag_private_close_channel);
605
0
      }
606
0
    }
607
0
  }
608
609
0
  return CMD_SUCCESS;
610
0
}
611
612
void zebra_mlag_init(void)
613
0
{
614
0
  zebra_mlag_vty_init();
615
616
  /*
617
   * Intialiaze the MLAG Global variables
618
   * write thread will be created during actual registration with MCLAG
619
   */
620
0
  zrouter.mlag_info.clients_interested_cnt = 0;
621
0
  zrouter.mlag_info.connected = false;
622
0
  zrouter.mlag_info.timer_running = false;
623
0
  zrouter.mlag_info.mlag_fifo = stream_fifo_new();
624
0
  zrouter.mlag_info.zebra_pth_mlag = NULL;
625
0
  zrouter.mlag_info.th_master = NULL;
626
0
  zrouter.mlag_info.t_read = NULL;
627
0
  zrouter.mlag_info.t_write = NULL;
628
0
  test_mlag_in_progress = false;
629
0
  zebra_mlag_reset_read_buffer();
630
0
}
631
632
void zebra_mlag_terminate(void)
633
0
{
634
0
}
635
636
637
/*
638
 *
639
 *  ProtoBuf Encoding APIs
640
 */
641
642
#ifdef HAVE_PROTOBUF_VERSION_3
643
644
DEFINE_MTYPE_STATIC(ZEBRA, MLAG_PBUF, "ZEBRA MLAG PROTOBUF");
645
646
int zebra_mlag_protobuf_encode_client_data(struct stream *s, uint32_t *msg_type)
647
{
648
  ZebraMlagHeader hdr = ZEBRA_MLAG__HEADER__INIT;
649
  struct mlag_msg mlag_msg;
650
  uint8_t tmp_buf[ZEBRA_MLAG_BUF_LIMIT];
651
  int len = 0;
652
  int n_len = 0;
653
  int rc = 0;
654
  char buf[ZLOG_FILTER_LENGTH_MAX];
655
  size_t length;
656
657
  if (IS_ZEBRA_DEBUG_MLAG)
658
    zlog_debug("%s: Entering..", __func__);
659
660
  rc = mlag_lib_decode_mlag_hdr(s, &mlag_msg, &length);
661
  if (rc)
662
    return rc;
663
664
  memset(tmp_buf, 0, ZEBRA_MLAG_BUF_LIMIT);
665
666
  if (IS_ZEBRA_DEBUG_MLAG)
667
    zlog_debug("%s: Mlag ProtoBuf encoding of message:%s, len:%d",
668
         __func__,
669
         mlag_lib_msgid_to_str(mlag_msg.msg_type, buf,
670
             sizeof(buf)),
671
         mlag_msg.data_len);
672
  *msg_type = mlag_msg.msg_type;
673
  switch (mlag_msg.msg_type) {
674
  case MLAG_MROUTE_ADD: {
675
    struct mlag_mroute_add msg;
676
    ZebraMlagMrouteAdd pay_load = ZEBRA_MLAG_MROUTE_ADD__INIT;
677
    uint32_t vrf_name_len = 0;
678
679
    rc = mlag_lib_decode_mroute_add(s, &msg, &length);
680
    if (rc)
681
      return rc;
682
683
    vrf_name_len = strlen(msg.vrf_name) + 1;
684
    pay_load.vrf_name = XMALLOC(MTYPE_MLAG_PBUF, vrf_name_len);
685
    strlcpy(pay_load.vrf_name, msg.vrf_name, vrf_name_len);
686
    pay_load.source_ip = msg.source_ip;
687
    pay_load.group_ip = msg.group_ip;
688
    pay_load.cost_to_rp = msg.cost_to_rp;
689
    pay_load.owner_id = msg.owner_id;
690
    pay_load.am_i_dr = msg.am_i_dr;
691
    pay_load.am_i_dual_active = msg.am_i_dual_active;
692
    pay_load.vrf_id = msg.vrf_id;
693
694
    if (msg.owner_id == MLAG_OWNER_INTERFACE) {
695
      vrf_name_len = strlen(msg.intf_name) + 1;
696
      pay_load.intf_name =
697
        XMALLOC(MTYPE_MLAG_PBUF, vrf_name_len);
698
      strlcpy(pay_load.intf_name, msg.intf_name,
699
        vrf_name_len);
700
    }
701
702
    len = zebra_mlag_mroute_add__pack(&pay_load, tmp_buf);
703
    XFREE(MTYPE_MLAG_PBUF, pay_load.vrf_name);
704
    if (msg.owner_id == MLAG_OWNER_INTERFACE)
705
      XFREE(MTYPE_MLAG_PBUF, pay_load.intf_name);
706
  } break;
707
  case MLAG_MROUTE_DEL: {
708
    struct mlag_mroute_del msg;
709
    ZebraMlagMrouteDel pay_load = ZEBRA_MLAG_MROUTE_DEL__INIT;
710
    uint32_t vrf_name_len = 0;
711
712
    rc = mlag_lib_decode_mroute_del(s, &msg, &length);
713
    if (rc)
714
      return rc;
715
    vrf_name_len = strlen(msg.vrf_name) + 1;
716
    pay_load.vrf_name = XMALLOC(MTYPE_MLAG_PBUF, vrf_name_len);
717
    strlcpy(pay_load.vrf_name, msg.vrf_name, vrf_name_len);
718
    pay_load.source_ip = msg.source_ip;
719
    pay_load.group_ip = msg.group_ip;
720
    pay_load.owner_id = msg.owner_id;
721
    pay_load.vrf_id = msg.vrf_id;
722
723
    if (msg.owner_id == MLAG_OWNER_INTERFACE) {
724
      vrf_name_len = strlen(msg.intf_name) + 1;
725
      pay_load.intf_name =
726
        XMALLOC(MTYPE_MLAG_PBUF, vrf_name_len);
727
      strlcpy(pay_load.intf_name, msg.intf_name,
728
        vrf_name_len);
729
    }
730
731
    len = zebra_mlag_mroute_del__pack(&pay_load, tmp_buf);
732
    XFREE(MTYPE_MLAG_PBUF, pay_load.vrf_name);
733
    if (msg.owner_id == MLAG_OWNER_INTERFACE)
734
      XFREE(MTYPE_MLAG_PBUF, pay_load.intf_name);
735
  } break;
736
  case MLAG_MROUTE_ADD_BULK: {
737
    struct mlag_mroute_add msg;
738
    ZebraMlagMrouteAddBulk Bulk_msg =
739
      ZEBRA_MLAG_MROUTE_ADD_BULK__INIT;
740
    ZebraMlagMrouteAdd **pay_load = NULL;
741
    bool cleanup = false;
742
    uint32_t i, actual;
743
744
    Bulk_msg.n_mroute_add = mlag_msg.msg_cnt;
745
    pay_load = XMALLOC(MTYPE_MLAG_PBUF, sizeof(ZebraMlagMrouteAdd *)
746
                  * mlag_msg.msg_cnt);
747
748
    for (i = 0, actual = 0; i < mlag_msg.msg_cnt; i++, actual++) {
749
750
      uint32_t vrf_name_len = 0;
751
752
      rc = mlag_lib_decode_mroute_add(s, &msg, &length);
753
      if (rc) {
754
        cleanup = true;
755
        break;
756
      }
757
      pay_load[i] = XMALLOC(MTYPE_MLAG_PBUF,
758
                sizeof(ZebraMlagMrouteAdd));
759
      zebra_mlag_mroute_add__init(pay_load[i]);
760
761
      vrf_name_len = strlen(msg.vrf_name) + 1;
762
      pay_load[i]->vrf_name =
763
        XMALLOC(MTYPE_MLAG_PBUF, vrf_name_len);
764
      strlcpy(pay_load[i]->vrf_name, msg.vrf_name,
765
        vrf_name_len);
766
      pay_load[i]->source_ip = msg.source_ip;
767
      pay_load[i]->group_ip = msg.group_ip;
768
      pay_load[i]->cost_to_rp = msg.cost_to_rp;
769
      pay_load[i]->owner_id = msg.owner_id;
770
      pay_load[i]->am_i_dr = msg.am_i_dr;
771
      pay_load[i]->am_i_dual_active = msg.am_i_dual_active;
772
      pay_load[i]->vrf_id = msg.vrf_id;
773
      if (msg.owner_id == MLAG_OWNER_INTERFACE) {
774
        vrf_name_len = strlen(msg.intf_name) + 1;
775
        pay_load[i]->intf_name =
776
          XMALLOC(MTYPE_MLAG_PBUF, vrf_name_len);
777
778
        strlcpy(pay_load[i]->intf_name, msg.intf_name,
779
          vrf_name_len);
780
      }
781
    }
782
    if (!cleanup) {
783
      Bulk_msg.mroute_add = pay_load;
784
      len = zebra_mlag_mroute_add_bulk__pack(&Bulk_msg,
785
                     tmp_buf);
786
    }
787
788
    for (i = 0; i < actual; i++) {
789
      /*
790
       * The mlag_lib_decode_mroute_add can
791
       * fail to properly decode and cause nothing
792
       * to be allocated.  Prevent a crash
793
       */
794
      if (!pay_load[i])
795
        continue;
796
797
      XFREE(MTYPE_MLAG_PBUF, pay_load[i]->vrf_name);
798
      if (pay_load[i]->owner_id == MLAG_OWNER_INTERFACE
799
          && pay_load[i]->intf_name)
800
        XFREE(MTYPE_MLAG_PBUF, pay_load[i]->intf_name);
801
      XFREE(MTYPE_MLAG_PBUF, pay_load[i]);
802
    }
803
    XFREE(MTYPE_MLAG_PBUF, pay_load);
804
    if (cleanup)
805
      return -1;
806
  } break;
807
  case MLAG_MROUTE_DEL_BULK: {
808
    struct mlag_mroute_del msg;
809
    ZebraMlagMrouteDelBulk Bulk_msg =
810
      ZEBRA_MLAG_MROUTE_DEL_BULK__INIT;
811
    ZebraMlagMrouteDel **pay_load = NULL;
812
    bool cleanup = false;
813
    uint32_t i, actual;
814
815
    Bulk_msg.n_mroute_del = mlag_msg.msg_cnt;
816
    pay_load = XMALLOC(MTYPE_MLAG_PBUF, sizeof(ZebraMlagMrouteDel *)
817
                  * mlag_msg.msg_cnt);
818
819
    for (i = 0, actual = 0; i < mlag_msg.msg_cnt; i++, actual++) {
820
821
      uint32_t vrf_name_len = 0;
822
823
      rc = mlag_lib_decode_mroute_del(s, &msg, &length);
824
      if (rc) {
825
        cleanup = true;
826
        break;
827
      }
828
829
      pay_load[i] = XMALLOC(MTYPE_MLAG_PBUF,
830
                sizeof(ZebraMlagMrouteDel));
831
      zebra_mlag_mroute_del__init(pay_load[i]);
832
833
      vrf_name_len = strlen(msg.vrf_name) + 1;
834
      pay_load[i]->vrf_name =
835
        XMALLOC(MTYPE_MLAG_PBUF, vrf_name_len);
836
837
      strlcpy(pay_load[i]->vrf_name, msg.vrf_name,
838
        vrf_name_len);
839
      pay_load[i]->source_ip = msg.source_ip;
840
      pay_load[i]->group_ip = msg.group_ip;
841
      pay_load[i]->owner_id = msg.owner_id;
842
      pay_load[i]->vrf_id = msg.vrf_id;
843
      if (msg.owner_id == MLAG_OWNER_INTERFACE) {
844
        vrf_name_len = strlen(msg.intf_name) + 1;
845
        pay_load[i]->intf_name =
846
          XMALLOC(MTYPE_MLAG_PBUF, vrf_name_len);
847
848
        strlcpy(pay_load[i]->intf_name, msg.intf_name,
849
          vrf_name_len);
850
      }
851
    }
852
    if (!cleanup) {
853
      Bulk_msg.mroute_del = pay_load;
854
      len = zebra_mlag_mroute_del_bulk__pack(&Bulk_msg,
855
                     tmp_buf);
856
    }
857
858
    for (i = 0; i < actual; i++) {
859
      /*
860
       * The mlag_lib_decode_mroute_add can
861
       * fail to properly decode and cause nothing
862
       * to be allocated.  Prevent a crash
863
       */
864
      if (!pay_load[i])
865
        continue;
866
867
      XFREE(MTYPE_MLAG_PBUF, pay_load[i]->vrf_name);
868
      if (pay_load[i]->owner_id == MLAG_OWNER_INTERFACE
869
          && pay_load[i]->intf_name)
870
        XFREE(MTYPE_MLAG_PBUF, pay_load[i]->intf_name);
871
      XFREE(MTYPE_MLAG_PBUF, pay_load[i]);
872
    }
873
    XFREE(MTYPE_MLAG_PBUF, pay_load);
874
    if (cleanup)
875
      return -1;
876
  } break;
877
  case MLAG_REGISTER:
878
  case MLAG_DEREGISTER:
879
  case MLAG_STATUS_UPDATE:
880
  case MLAG_DUMP:
881
  case MLAG_PIM_CFG_DUMP:
882
  case MLAG_VXLAN_UPDATE:
883
  case MLAG_PEER_FRR_STATUS:
884
  case MLAG_MSG_NONE:
885
    break;
886
  }
887
888
  if (IS_ZEBRA_DEBUG_MLAG)
889
    zlog_debug("%s: length of Mlag ProtoBuf encoded message:%s, %d",
890
         __func__,
891
         mlag_lib_msgid_to_str(mlag_msg.msg_type, buf,
892
             sizeof(buf)),
893
         len);
894
  hdr.type = (ZebraMlagHeader__MessageType)mlag_msg.msg_type;
895
  if (len != 0) {
896
    hdr.data.len = len;
897
    hdr.data.data = XMALLOC(MTYPE_MLAG_PBUF, len);
898
    memcpy(hdr.data.data, tmp_buf, len);
899
  }
900
901
  /*
902
   * ProtoBuf Infra will not support to demarc the pointers whem multiple
903
   * messages are posted inside a single Buffer.
904
   * 2 -solutions exist to solve this
905
   * 1. add Unenoced length at the beginning of every message, this will
906
   *    be used to point to next message in the buffer
907
   * 2. another solution is defining all messages insides another message
908
   *    But this will permit only 32 messages. this can be extended with
909
   *    multiple levels.
910
   * for simplicity we are going with solution-1.
911
   */
912
  len = zebra_mlag__header__pack(&hdr,
913
               (mlag_wr_buffer + ZEBRA_MLAG_LEN_SIZE));
914
  n_len = htonl(len);
915
  memcpy(mlag_wr_buffer, &n_len, ZEBRA_MLAG_LEN_SIZE);
916
  len += ZEBRA_MLAG_LEN_SIZE;
917
918
  if (IS_ZEBRA_DEBUG_MLAG)
919
    zlog_debug(
920
      "%s: length of Mlag ProtoBuf message:%s with Header  %d",
921
      __func__,
922
      mlag_lib_msgid_to_str(mlag_msg.msg_type, buf,
923
                sizeof(buf)),
924
      len);
925
  XFREE(MTYPE_MLAG_PBUF, hdr.data.data);
926
927
  return len;
928
}
929
930
static void zebra_fill_protobuf_msg(struct stream *s, char *name, int len)
931
{
932
  int str_len = strlen(name) + 1;
933
934
  stream_put(s, name, str_len);
935
  /* Fill the rest with Null Character for aligning */
936
  stream_put(s, NULL, len - str_len);
937
}
938
939
int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data,
940
               uint32_t len)
941
{
942
  uint32_t msg_type;
943
  ZebraMlagHeader *hdr;
944
  char buf[80];
945
946
  hdr = zebra_mlag__header__unpack(NULL, len, data);
947
  if (hdr == NULL)
948
    return -1;
949
950
  /*
951
   * ADD The MLAG Header
952
   */
953
  zclient_create_header(s, ZEBRA_MLAG_FORWARD_MSG, VRF_DEFAULT);
954
955
  msg_type = hdr->type;
956
957
  if (IS_ZEBRA_DEBUG_MLAG)
958
    zlog_debug("%s: Mlag ProtoBuf decoding of message:%s", __func__,
959
         mlag_lib_msgid_to_str(msg_type, buf, 80));
960
961
  /*
962
   * Internal MLAG Message-types & MLAG.proto message types should
963
   * always match, otherwise there can be decoding errors
964
   * To avoid exposing clients with Protobuf flags, using internal
965
   * message-types
966
   */
967
  stream_putl(s, hdr->type);
968
969
  if (hdr->data.len == 0) {
970
    /* NULL Payload */
971
    stream_putw(s, MLAG_MSG_NULL_PAYLOAD);
972
    /* No Batching */
973
    stream_putw(s, MLAG_MSG_NO_BATCH);
974
  } else {
975
    switch (msg_type) {
976
    case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_STATUS_UPDATE: {
977
      ZebraMlagStatusUpdate *msg = NULL;
978
979
      msg = zebra_mlag_status_update__unpack(
980
        NULL, hdr->data.len, hdr->data.data);
981
      if (msg == NULL) {
982
        zebra_mlag__header__free_unpacked(hdr, NULL);
983
        return -1;
984
      }
985
      /* Payload len */
986
      stream_putw(s, sizeof(struct mlag_status));
987
      /* No Batching */
988
      stream_putw(s, MLAG_MSG_NO_BATCH);
989
      /* Actual Data */
990
      zebra_fill_protobuf_msg(s, msg->peerlink,
991
            INTERFACE_NAMSIZ);
992
      stream_putl(s, msg->my_role);
993
      stream_putl(s, msg->peer_state);
994
      zebra_mlag_status_update__free_unpacked(msg, NULL);
995
    } break;
996
    case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_VXLAN_UPDATE: {
997
      ZebraMlagVxlanUpdate *msg = NULL;
998
999
      msg = zebra_mlag_vxlan_update__unpack(
1000
        NULL, hdr->data.len, hdr->data.data);
1001
      if (msg == NULL) {
1002
        zebra_mlag__header__free_unpacked(hdr, NULL);
1003
        return -1;
1004
      }
1005
      /* Payload len */
1006
      stream_putw(s, sizeof(struct mlag_vxlan));
1007
      /* No Batching */
1008
      stream_putw(s, MLAG_MSG_NO_BATCH);
1009
      /* Actual Data */
1010
      stream_putl(s, msg->anycast_ip);
1011
      stream_putl(s, msg->local_ip);
1012
      zebra_mlag_vxlan_update__free_unpacked(msg, NULL);
1013
    } break;
1014
    case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_ADD: {
1015
      ZebraMlagMrouteAdd *msg = NULL;
1016
1017
      msg = zebra_mlag_mroute_add__unpack(NULL, hdr->data.len,
1018
                  hdr->data.data);
1019
      if (msg == NULL) {
1020
        zebra_mlag__header__free_unpacked(hdr, NULL);
1021
        return -1;
1022
      }
1023
      /* Payload len */
1024
      stream_putw(s, sizeof(struct mlag_mroute_add));
1025
      /* No Batching */
1026
      stream_putw(s, MLAG_MSG_NO_BATCH);
1027
      /* Actual Data */
1028
      zebra_fill_protobuf_msg(s, msg->vrf_name, VRF_NAMSIZ);
1029
1030
      stream_putl(s, msg->source_ip);
1031
      stream_putl(s, msg->group_ip);
1032
      stream_putl(s, msg->cost_to_rp);
1033
      stream_putl(s, msg->owner_id);
1034
      stream_putc(s, msg->am_i_dr);
1035
      stream_putc(s, msg->am_i_dual_active);
1036
      stream_putl(s, msg->vrf_id);
1037
      if (msg->owner_id == MLAG_OWNER_INTERFACE)
1038
        zebra_fill_protobuf_msg(s, msg->intf_name,
1039
              INTERFACE_NAMSIZ);
1040
      else
1041
        stream_put(s, NULL, INTERFACE_NAMSIZ);
1042
      zebra_mlag_mroute_add__free_unpacked(msg, NULL);
1043
    } break;
1044
    case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_DEL: {
1045
      ZebraMlagMrouteDel *msg = NULL;
1046
1047
      msg = zebra_mlag_mroute_del__unpack(NULL, hdr->data.len,
1048
                  hdr->data.data);
1049
      if (msg == NULL) {
1050
        zebra_mlag__header__free_unpacked(hdr, NULL);
1051
        return -1;
1052
      }
1053
      /* Payload len */
1054
      stream_putw(s, sizeof(struct mlag_mroute_del));
1055
      /* No Batching */
1056
      stream_putw(s, MLAG_MSG_NO_BATCH);
1057
      /* Actual Data */
1058
      zebra_fill_protobuf_msg(s, msg->vrf_name, VRF_NAMSIZ);
1059
1060
      stream_putl(s, msg->source_ip);
1061
      stream_putl(s, msg->group_ip);
1062
      stream_putl(s, msg->owner_id);
1063
      stream_putl(s, msg->vrf_id);
1064
      if (msg->owner_id == MLAG_OWNER_INTERFACE)
1065
        zebra_fill_protobuf_msg(s, msg->intf_name,
1066
              INTERFACE_NAMSIZ);
1067
      else
1068
        stream_put(s, NULL, INTERFACE_NAMSIZ);
1069
      zebra_mlag_mroute_del__free_unpacked(msg, NULL);
1070
    } break;
1071
    case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_ADD_BULK: {
1072
      ZebraMlagMrouteAddBulk *Bulk_msg = NULL;
1073
      ZebraMlagMrouteAdd *msg = NULL;
1074
      size_t i, length_spot;
1075
1076
      Bulk_msg = zebra_mlag_mroute_add_bulk__unpack(
1077
        NULL, hdr->data.len, hdr->data.data);
1078
      if (Bulk_msg == NULL) {
1079
        zebra_mlag__header__free_unpacked(hdr, NULL);
1080
        return -1;
1081
      }
1082
      /* Payload len */
1083
      stream_putw(s, (Bulk_msg->n_mroute_add
1084
          * sizeof(struct mlag_mroute_add)));
1085
      /* No. of msgs in Batch */
1086
      length_spot = stream_putw(s, Bulk_msg->n_mroute_add);
1087
1088
      /* Actual Data */
1089
      for (i = 0; i < Bulk_msg->n_mroute_add; i++) {
1090
        if (STREAM_SIZE(s)
1091
            < VRF_NAMSIZ + 22 + INTERFACE_NAMSIZ) {
1092
          zlog_warn(
1093
            "We have received more messages than we can parse at this point in time: %zu",
1094
            Bulk_msg->n_mroute_add);
1095
          break;
1096
        }
1097
1098
        msg = Bulk_msg->mroute_add[i];
1099
1100
        zebra_fill_protobuf_msg(s, msg->vrf_name,
1101
              VRF_NAMSIZ);
1102
        stream_putl(s, msg->source_ip);
1103
        stream_putl(s, msg->group_ip);
1104
        stream_putl(s, msg->cost_to_rp);
1105
        stream_putl(s, msg->owner_id);
1106
        stream_putc(s, msg->am_i_dr);
1107
        stream_putc(s, msg->am_i_dual_active);
1108
        stream_putl(s, msg->vrf_id);
1109
        if (msg->owner_id == MLAG_OWNER_INTERFACE)
1110
          zebra_fill_protobuf_msg(
1111
            s, msg->intf_name,
1112
            INTERFACE_NAMSIZ);
1113
        else
1114
          stream_put(s, NULL, INTERFACE_NAMSIZ);
1115
      }
1116
1117
      stream_putw_at(s, length_spot, i + 1);
1118
1119
      zebra_mlag_mroute_add_bulk__free_unpacked(Bulk_msg,
1120
                  NULL);
1121
    } break;
1122
    case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_DEL_BULK: {
1123
      ZebraMlagMrouteDelBulk *Bulk_msg = NULL;
1124
      ZebraMlagMrouteDel *msg = NULL;
1125
      size_t i, length_spot;
1126
1127
      Bulk_msg = zebra_mlag_mroute_del_bulk__unpack(
1128
        NULL, hdr->data.len, hdr->data.data);
1129
      if (Bulk_msg == NULL) {
1130
        zebra_mlag__header__free_unpacked(hdr, NULL);
1131
        return -1;
1132
      }
1133
      /* Payload len */
1134
      stream_putw(s, (Bulk_msg->n_mroute_del
1135
          * sizeof(struct mlag_mroute_del)));
1136
      /* No. of msgs in Batch */
1137
      length_spot = stream_putw(s, Bulk_msg->n_mroute_del);
1138
1139
      /* Actual Data */
1140
      for (i = 0; i < Bulk_msg->n_mroute_del; i++) {
1141
        if (STREAM_SIZE(s)
1142
            < VRF_NAMSIZ + 16 + INTERFACE_NAMSIZ) {
1143
          zlog_warn(
1144
            "We have received more messages than we can parse at this time");
1145
          break;
1146
        }
1147
1148
        msg = Bulk_msg->mroute_del[i];
1149
1150
        zebra_fill_protobuf_msg(s, msg->vrf_name,
1151
              VRF_NAMSIZ);
1152
        stream_putl(s, msg->source_ip);
1153
        stream_putl(s, msg->group_ip);
1154
        stream_putl(s, msg->owner_id);
1155
        stream_putl(s, msg->vrf_id);
1156
        if (msg->owner_id == MLAG_OWNER_INTERFACE)
1157
          zebra_fill_protobuf_msg(
1158
            s, msg->intf_name,
1159
            INTERFACE_NAMSIZ);
1160
        else
1161
          stream_put(s, NULL, INTERFACE_NAMSIZ);
1162
      }
1163
1164
      stream_putw_at(s, length_spot, i + 1);
1165
1166
      zebra_mlag_mroute_del_bulk__free_unpacked(Bulk_msg,
1167
                  NULL);
1168
    } break;
1169
    case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_ZEBRA_STATUS_UPDATE: {
1170
      ZebraMlagZebraStatusUpdate *msg = NULL;
1171
1172
      msg = zebra_mlag_zebra_status_update__unpack(
1173
        NULL, hdr->data.len, hdr->data.data);
1174
      if (msg == NULL) {
1175
        zebra_mlag__header__free_unpacked(hdr, NULL);
1176
        return -1;
1177
      }
1178
      /* Payload len */
1179
      stream_putw(s, sizeof(struct mlag_frr_status));
1180
      /* No Batching */
1181
      stream_putw(s, MLAG_MSG_NO_BATCH);
1182
      /* Actual Data */
1183
      stream_putl(s, msg->peer_frrstate);
1184
      zebra_mlag_zebra_status_update__free_unpacked(msg,
1185
                      NULL);
1186
    } break;
1187
    default:
1188
      break;
1189
    }
1190
  }
1191
  zebra_mlag__header__free_unpacked(hdr, NULL);
1192
  return msg_type;
1193
}
1194
1195
#else
1196
int zebra_mlag_protobuf_encode_client_data(struct stream *s, uint32_t *msg_type)
1197
0
{
1198
0
  return 0;
1199
0
}
1200
1201
int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data,
1202
               uint32_t len)
1203
0
{
1204
0
  return 0;
1205
0
}
1206
#endif