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