]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_mlag.c
lib,mlag : Defining MLAG Proto file
[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"
ee235396 30#include "zebra/zebra_mlag_private.h"
e96ba9da 31#include "zebra/zebra_router.h"
ee235396 32#include "zebra/zebra_memory.h"
b120fe3b
DS
33#include "zebra/zapi_msg.h"
34#include "zebra/debug.h"
df395600 35
763ec244
DS
36#ifndef VTYSH_EXTRACT_PL
37#include "zebra/zebra_mlag_clippy.c"
38#endif
39
ee235396
SK
40#define ZEBRA_MLAG_METADATA_LEN 4
41#define ZEBRA_MLAG_MSG_BCAST 0xFFFFFFFF
42
43uint8_t mlag_wr_buffer[ZEBRA_MLAG_BUF_LIMIT];
44uint8_t mlag_rd_buffer[ZEBRA_MLAG_BUF_LIMIT];
45uint32_t mlag_rd_buf_offset;
46
47static bool test_mlag_in_progress;
48
49static int zebra_mlag_signal_write_thread(void);
50static int zebra_mlag_terminate_pthread(struct thread *event);
51static int zebra_mlag_post_data_from_main_thread(struct thread *thread);
52static void zebra_mlag_publish_process_state(struct zserv *client,
53 zebra_message_types_t msg_type);
54
55/**********************MLAG Interaction***************************************/
56
57/*
58 * API to post the Registration to MLAGD
59 * MLAG will not process any messages with out the registration
60 */
61void zebra_mlag_send_register(void)
62{
63 struct stream *s = NULL;
64
65 s = stream_new(sizeof(struct mlag_msg));
66
67 stream_putl(s, MLAG_REGISTER);
68 stream_putw(s, MLAG_MSG_NULL_PAYLOAD);
69 stream_putw(s, MLAG_MSG_NO_BATCH);
70 stream_fifo_push_safe(zrouter.mlag_info.mlag_fifo, s);
71 zebra_mlag_signal_write_thread();
72
73 if (IS_ZEBRA_DEBUG_MLAG)
74 zlog_debug("%s: Enqueued MLAG Register to MLAG Thread ",
75 __func__);
76}
77
78/*
79 * API to post the De-Registration to MLAGD
80 * MLAG will not process any messages after the de-registration
81 */
82void zebra_mlag_send_deregister(void)
83{
84 struct stream *s = NULL;
85
86 s = stream_new(sizeof(struct mlag_msg));
87
88 stream_putl(s, MLAG_DEREGISTER);
89 stream_putw(s, MLAG_MSG_NULL_PAYLOAD);
90 stream_putw(s, MLAG_MSG_NO_BATCH);
91 stream_fifo_push_safe(zrouter.mlag_info.mlag_fifo, s);
92 zebra_mlag_signal_write_thread();
93
94 if (IS_ZEBRA_DEBUG_MLAG)
95 zlog_debug("%s: Enqueued MLAG De-Register to MLAG Thread ",
96 __func__);
97}
98
99/*
100 * API To handle MLAG Received data
101 * Decodes the data using protobuf and enqueue to main thread
102 * main thread publish this to clients based on client subscription
103 */
104void zebra_mlag_process_mlag_data(uint8_t *data, uint32_t len)
105{
106 struct stream *s = NULL;
107 struct stream *s1 = NULL;
108 int msg_type = 0;
109
110 s = stream_new(ZEBRA_MAX_PACKET_SIZ);
111 msg_type = zebra_mlag_protobuf_decode_message(&s, data, len);
112
113 if (msg_type <= 0) {
114 /* Something went wrong in decoding */
115 stream_free(s);
116 zlog_err("%s: failed to process mlag data-%d, %u", __func__,
117 msg_type, len);
118 return;
119 }
120
121 /*
122 * additional four bytes are for message type
123 */
124 s1 = stream_new(stream_get_endp(s) + ZEBRA_MLAG_METADATA_LEN);
125 stream_putl(s1, msg_type);
126 stream_put(s1, s->data, stream_get_endp(s));
127 thread_add_event(zrouter.master, zebra_mlag_post_data_from_main_thread,
128 s1, 0, NULL);
129 stream_free(s);
130}
131
132/**********************End of MLAG Interaction********************************/
133
134/************************MLAG Thread Processing*******************************/
135
136/*
137 * after posting every 'ZEBRA_MLAG_POST_LIMIT' packets, MLAG Thread will be
138 * yielded to give CPU for other threads
139 */
140#define ZEBRA_MLAG_POST_LIMIT 100
141
142/*
143 * This thread reads the clients data from the Global queue and encodes with
144 * protobuf and pass on to the MLAG socket.
145 */
146static int zebra_mlag_client_msg_handler(struct thread *event)
147{
148 struct stream *s;
149 uint32_t wr_count = 0;
150 uint32_t msg_type = 0;
151 int len = 0;
152
153 wr_count = stream_fifo_count_safe(zrouter.mlag_info.mlag_fifo);
154 if (IS_ZEBRA_DEBUG_MLAG)
155 zlog_debug(":%s: Processing MLAG write, %d messages in queue",
156 __func__, wr_count);
157
158 zrouter.mlag_info.t_write = NULL;
159 for (wr_count = 0; wr_count < ZEBRA_MLAG_POST_LIMIT; wr_count++) {
160 /* FIFO is empty,wait for teh message to be add */
161 if (stream_fifo_count_safe(zrouter.mlag_info.mlag_fifo) == 0)
162 break;
163
164 s = stream_fifo_pop_safe(zrouter.mlag_info.mlag_fifo);
165 if (!s) {
166 zlog_debug(":%s: Got a NULL Messages, some thing wrong",
167 __func__);
168 break;
169 }
170
171 zebra_mlag_reset_write_buffer();
172 /*
173 * Encode the data now
174 */
175 len = zebra_mlag_protobuf_encode_client_data(s, &msg_type);
176
177 /*
178 * write to MCLAGD
179 */
180 if (len > 0)
181 zebra_mlag_private_write_data(mlag_wr_buffer, len);
182
183 /*
184 * If message type is De-register, send a signal to main thread,
185 * so that necessary cleanup will be done by main thread.
186 */
187 if (msg_type == MLAG_DEREGISTER) {
188 thread_add_event(zrouter.master,
189 zebra_mlag_terminate_pthread, NULL, 0,
190 NULL);
191 }
192
193 stream_free(s);
194 }
195
196 if (IS_ZEBRA_DEBUG_MLAG)
197 zlog_debug(":%s: Posted %d messages to MLAGD", __func__,
198 wr_count);
199 /*
200 * Currently there is only message write task is enqueued to this
201 * thread, yielding was added for future purpose, so that this thread
202 * can server other tasks also and in case FIFO is empty, this task will
203 * be schedule when main thread adds some messages
204 */
205 if (wr_count >= ZEBRA_MLAG_POST_LIMIT)
206 zebra_mlag_signal_write_thread();
207 return 0;
208}
209
210/*
211 * API to handle the process state.
212 * In case of Down, Zebra keep monitoring the MLAG state.
213 * all the state Notifications will be published to clients
214 */
215void zebra_mlag_handle_process_state(enum zebra_mlag_state state)
216{
217 if (state == MLAG_UP) {
218 zrouter.mlag_info.connected = true;
219 zebra_mlag_publish_process_state(NULL, ZEBRA_MLAG_PROCESS_UP);
220 zebra_mlag_send_register();
221 } else if (state == MLAG_DOWN) {
222 zrouter.mlag_info.connected = false;
223 zebra_mlag_publish_process_state(NULL, ZEBRA_MLAG_PROCESS_DOWN);
224 zebra_mlag_private_monitor_state();
225 }
226}
227
228/***********************End of MLAG Thread processing*************************/
229
230/*************************Multi-entratnt Api's********************************/
231
232/*
233 * Provider api to signal that work/events are available
234 * for the Zebra MLAG Write pthread.
235 * This API is called from 2 pthreads..
236 * 1) by main thread when client posts a MLAG Message
237 * 2) by MLAG Thread, in case of yield
238 * though this api, is called from two threads we don't need any locking
239 * because Thread task enqueue is thread safe means internally it had
240 * necessary protection
241 */
242static int zebra_mlag_signal_write_thread(void)
243{
244 if (zrouter.mlag_info.zebra_pth_mlag) {
245 if (IS_ZEBRA_DEBUG_MLAG)
246 zlog_debug(":%s: Scheduling MLAG write", __func__);
247 thread_add_event(zrouter.mlag_info.th_master,
248 zebra_mlag_client_msg_handler, NULL, 0,
249 &zrouter.mlag_info.t_write);
250 }
251 return 0;
252}
253
254/*
255 * API will be used to publish the MLAG state to interested clients
256 * In case client is passed, state is posted only for that client,
257 * otherwise to all interested clients
258 * this api can be called from two threads.
259 * 1) from main thread: when client is passed
260 * 2) from MLAG Thread: when client is NULL
261 *
262 * In second case, to avoid global data access data will be post to Main
263 * thread, so that actual posting to clients will happen from Main thread.
264 */
265static void zebra_mlag_publish_process_state(struct zserv *client,
266 zebra_message_types_t msg_type)
267{
268 struct stream *s;
269
270 if (IS_ZEBRA_DEBUG_MLAG)
271 zlog_debug("%s: Publishing MLAG process state:%s to %s Client",
272 __func__,
273 (msg_type == ZEBRA_MLAG_PROCESS_UP) ? "UP" : "DOWN",
274 (client) ? "one" : "all");
275
276 if (client) {
277 s = stream_new(ZEBRA_HEADER_SIZE);
278 zclient_create_header(s, msg_type, VRF_DEFAULT);
279 zserv_send_message(client, s);
280 return;
281 }
282
283
284 /*
285 * additional four bytes are for mesasge type
286 */
287 s = stream_new(ZEBRA_HEADER_SIZE + ZEBRA_MLAG_METADATA_LEN);
288 stream_putl(s, ZEBRA_MLAG_MSG_BCAST);
289 zclient_create_header(s, msg_type, VRF_DEFAULT);
290 thread_add_event(zrouter.master, zebra_mlag_post_data_from_main_thread,
291 s, 0, NULL);
292}
293
294/**************************End of Multi-entrant Apis**************************/
295
296/***********************Zebra Main thread processing**************************/
297
298/*
299 * To avoid data corruption, messages will be post to clients only from
300 * main thread, because for that access was needed for clients list.
301 * so instead of forcing the locks, messages will be posted from main thread.
302 */
303static int zebra_mlag_post_data_from_main_thread(struct thread *thread)
304{
305 struct stream *s = THREAD_ARG(thread);
306 struct stream *zebra_s = NULL;
307 struct listnode *node;
308 struct zserv *client;
309 uint32_t msg_type = 0;
310 uint32_t msg_len = 0;
311
312 if (!s)
313 return -1;
314
315 STREAM_GETL(s, msg_type);
316 if (IS_ZEBRA_DEBUG_MLAG)
317 zlog_debug(
318 "%s: Posting MLAG data for msg_type:0x%x to interested cleints",
319 __func__, msg_type);
320
321 msg_len = s->endp - ZEBRA_MLAG_METADATA_LEN;
322 for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) {
323 if (client->mlag_updates_interested == true) {
324 if (msg_type != ZEBRA_MLAG_MSG_BCAST
325 && !CHECK_FLAG(client->mlag_reg_mask1,
326 (1 << msg_type))) {
327 continue;
328 }
329
330 if (IS_ZEBRA_DEBUG_MLAG)
331 zlog_debug(
332 "%s: Posting MLAG data of length-%d to client:%d ",
333 __func__, msg_len, client->proto);
334
335 zebra_s = stream_new(msg_len);
336 STREAM_GET(zebra_s->data, s, msg_len);
337 zebra_s->endp = msg_len;
338 stream_putw_at(zebra_s, 0, msg_len);
339
340 /*
341 * This stream will be enqueued to client_obuf, it will
342 * be freed after posting to client socket.
343 */
344 zserv_send_message(client, zebra_s);
345 zebra_s = NULL;
346 }
347 }
348
349 stream_free(s);
350 return 0;
351stream_failure:
352 stream_free(s);
353 if (zebra_s)
354 stream_free(zebra_s);
355 return 0;
356}
357
358/*
359 * Start the MLAG Thread, this will be used to write client data on to
360 * MLAG Process and to read the data from MLAG and post to cleints.
361 * when all clients are un-registered, this Thread will be
362 * suspended.
363 */
364static void zebra_mlag_spawn_pthread(void)
365{
366 /* Start MLAG write pthread */
367
368 struct frr_pthread_attr pattr = {.start =
369 frr_pthread_attr_default.start,
370 .stop = frr_pthread_attr_default.stop};
371
372 zrouter.mlag_info.zebra_pth_mlag =
373 frr_pthread_new(&pattr, "Zebra MLAG thread", "Zebra MLAG");
374
375 zrouter.mlag_info.th_master = zrouter.mlag_info.zebra_pth_mlag->master;
376
377
378 /* Enqueue an initial event for the dataplane pthread */
379 zebra_mlag_signal_write_thread();
380
381 frr_pthread_run(zrouter.mlag_info.zebra_pth_mlag, NULL);
382}
383
384/*
385 * all clients are un-registered for MLAG Updates, terminate the
386 * MLAG write thread
387 */
388static int zebra_mlag_terminate_pthread(struct thread *event)
389{
390 if (IS_ZEBRA_DEBUG_MLAG)
391 zlog_debug("Zebra MLAG write thread terminate called");
392
393 if (zrouter.mlag_info.clients_interested_cnt) {
394 if (IS_ZEBRA_DEBUG_MLAG)
395 zlog_debug(
396 "Zebra MLAG: still some clients are interested");
397 return 0;
398 }
399
400 frr_pthread_stop(zrouter.mlag_info.zebra_pth_mlag, NULL);
401
402 /* Destroy pthread */
403 frr_pthread_destroy(zrouter.mlag_info.zebra_pth_mlag);
404 zrouter.mlag_info.zebra_pth_mlag = NULL;
405 zrouter.mlag_info.th_master = NULL;
406 zrouter.mlag_info.t_read = NULL;
407 zrouter.mlag_info.t_write = NULL;
408
409 /*
410 * Send Notification to clean private data
411 */
412 zebra_mlag_private_cleanup_data();
413 return 0;
414}
415
416/*
417 * API to register zebra client for MLAG Updates
418 */
419void zebra_mlag_client_register(ZAPI_HANDLER_ARGS)
420{
421 struct stream *s;
422 uint32_t reg_mask = 0;
423 int rc = 0;
424
425 if (IS_ZEBRA_DEBUG_MLAG)
426 zlog_debug("Received MLAG Registration from client-proto:%d",
427 client->proto);
428
429
430 /* Get input stream. */
431 s = msg;
432
433 /* Get data. */
434 STREAM_GETL(s, reg_mask);
435
436 if (client->mlag_updates_interested == true) {
437
438 if (IS_ZEBRA_DEBUG_MLAG)
439 zlog_debug(
440 "Client is registered, existing mask: 0x%x, new mask: 0x%x",
441 client->mlag_reg_mask1, reg_mask);
442 if (client->mlag_reg_mask1 != reg_mask)
443 client->mlag_reg_mask1 = reg_mask;
444 /*
445 * Client might missed MLAG-UP Notification, post-it again
446 */
447 zebra_mlag_publish_process_state(client, ZEBRA_MLAG_PROCESS_UP);
448 return;
449 }
450
451
452 client->mlag_updates_interested = true;
453 client->mlag_reg_mask1 = reg_mask;
454 if (IS_ZEBRA_DEBUG_MLAG)
455 zlog_debug("Registering for MLAG Updates with mask: 0x%x, ",
456 client->mlag_reg_mask1);
457
458 zrouter.mlag_info.clients_interested_cnt++;
459
460 if (zrouter.mlag_info.clients_interested_cnt == 1) {
461 /*
462 * First-client for MLAG Updates,open the communication channel
463 * with MLAG
464 */
465 if (IS_ZEBRA_DEBUG_MLAG)
466 zlog_debug(
467 "First client, opening the channel with MLAG");
468
469 zebra_mlag_spawn_pthread();
470 rc = zebra_mlag_private_open_channel();
471 if (rc < 0) {
472 /*
473 * For some reason, zebra not able to open the
474 * comm-channel with MLAG, so post MLAG-DOWN to client.
475 * later when the channel is open, zebra will send
476 * MLAG-UP
477 */
478 if (IS_ZEBRA_DEBUG_MLAG)
479 zlog_debug(
480 "Fail to open channel with MLAG,rc:%d, post Proto-down",
481 rc);
482 zebra_mlag_publish_process_state(
483 client, ZEBRA_MLAG_PROCESS_DOWN);
484 }
485 }
486
487 if (IS_ZEBRA_DEBUG_MLAG)
488 zlog_debug("Client Registered successfully for MLAG Updates");
489
490 if (zrouter.mlag_info.connected == true)
491 zebra_mlag_publish_process_state(client, ZEBRA_MLAG_PROCESS_UP);
492stream_failure:
493 return;
494}
495
496/*
497 * API to un-register for MLAG Updates
498 */
499void zebra_mlag_client_unregister(ZAPI_HANDLER_ARGS)
500{
501 if (IS_ZEBRA_DEBUG_MLAG)
502 zlog_debug("Received MLAG De-Registration from client-proto:%d",
503 client->proto);
504
505 if (client->mlag_updates_interested == false)
506 /* Unexpected */
507 return;
508
509 client->mlag_updates_interested = false;
510 client->mlag_reg_mask1 = 0;
511 zrouter.mlag_info.clients_interested_cnt--;
512
513 if (zrouter.mlag_info.clients_interested_cnt == 0) {
514 /*
515 * No-client is interested for MLAG Updates,close the
516 * communication channel with MLAG
517 */
518 if (IS_ZEBRA_DEBUG_MLAG)
519 zlog_debug("Last client for MLAG, close the channel ");
520
521 /*
522 * Clean up flow:
523 * =============
524 * 1) main thread calls socket close which posts De-register
525 * to MLAG write thread
526 * 2) after MLAG write thread posts De-register it sends a
527 * signal back to main thread to do the thread cleanup
528 * this was mainly to make sure De-register is posted to MCLAGD.
529 */
530 zebra_mlag_private_close_channel();
531 }
532
533 if (IS_ZEBRA_DEBUG_MLAG)
534 zlog_debug(
535 "Client De-Registered successfully for MLAG Updates");
536}
537
538/*
539 * Does following things.
540 * 1) allocated new local stream, and copies the client data and enqueue
541 * to MLAG Thread
542 * 2) MLAG Thread after dequeing, encode the client data using protobuf
543 * and write on to MLAG
544 */
545void zebra_mlag_forward_client_msg(ZAPI_HANDLER_ARGS)
546{
547 struct stream *zebra_s;
548 struct stream *mlag_s;
549
550 if (IS_ZEBRA_DEBUG_MLAG)
551 zlog_debug("Received Client MLAG Data from client-proto:%d",
552 client->proto);
553
554 /* Get input stream. */
555 zebra_s = msg;
556 mlag_s = stream_new(zebra_s->endp);
557
558 /*
559 * Client data is | Zebra Header + MLAG Data |
560 * we need to enqueue only the MLAG data, skipping Zebra Header
561 */
562 stream_put(mlag_s, zebra_s->data + zebra_s->getp,
563 STREAM_READABLE(zebra_s));
564 stream_fifo_push_safe(zrouter.mlag_info.mlag_fifo, mlag_s);
565 zebra_mlag_signal_write_thread();
566
567 if (IS_ZEBRA_DEBUG_MLAG)
568 zlog_debug("%s: Enqueued Client:%d data to MLAG Thread ",
569 __func__, client->proto);
570}
571
572/***********************End of Zebra Main thread processing*************/
573
ff1fb8d5
DS
574enum mlag_role zebra_mlag_get_role(void)
575{
e96ba9da 576 return zrouter.mlag_info.role;
ff1fb8d5
DS
577}
578
763ec244
DS
579DEFUN_HIDDEN (show_mlag,
580 show_mlag_cmd,
581 "show zebra mlag",
582 SHOW_STR
583 ZEBRA_STR
584 "The mlag role on this machine\n")
585{
6a597223 586 char buf[80];
763ec244
DS
587
588 vty_out(vty, "MLag is configured to: %s\n",
e96ba9da 589 mlag_role2str(zrouter.mlag_info.role, buf, sizeof(buf)));
763ec244
DS
590
591 return CMD_SUCCESS;
592}
593
ee235396
SK
594DEFPY(test_mlag, test_mlag_cmd,
595 "test zebra mlag <none$none|primary$primary|secondary$secondary>",
596 "Test code\n" ZEBRA_STR
597 "Modify the Mlag state\n"
598 "Mlag is not setup on the machine\n"
599 "Mlag is setup to be primary\n"
600 "Mlag is setup to be the secondary\n")
763ec244 601{
b120fe3b 602 enum mlag_role orig = zrouter.mlag_info.role;
6a597223 603 char buf1[80], buf2[80];
b120fe3b 604
763ec244 605 if (none)
e96ba9da 606 zrouter.mlag_info.role = MLAG_ROLE_NONE;
763ec244 607 if (primary)
e96ba9da 608 zrouter.mlag_info.role = MLAG_ROLE_PRIMARY;
763ec244 609 if (secondary)
e96ba9da 610 zrouter.mlag_info.role = MLAG_ROLE_SECONDARY;
763ec244 611
b120fe3b
DS
612 if (IS_ZEBRA_DEBUG_MLAG)
613 zlog_debug("Test: Changing role from %s to %s",
614 mlag_role2str(orig, buf1, sizeof(buf1)),
615 mlag_role2str(orig, buf2, sizeof(buf2)));
616
ee235396 617 if (orig != zrouter.mlag_info.role) {
b120fe3b 618 zsend_capabilities_all_clients();
ee235396
SK
619 if (zrouter.mlag_info.role != MLAG_ROLE_NONE) {
620 if (zrouter.mlag_info.clients_interested_cnt == 0
621 && test_mlag_in_progress == false) {
622 if (zrouter.mlag_info.zebra_pth_mlag == NULL)
623 zebra_mlag_spawn_pthread();
624 zrouter.mlag_info.clients_interested_cnt++;
625 test_mlag_in_progress = true;
626 zebra_mlag_private_open_channel();
627 }
628 } else {
629 if (test_mlag_in_progress == true) {
630 test_mlag_in_progress = false;
631 zrouter.mlag_info.clients_interested_cnt--;
632 zebra_mlag_private_close_channel();
633 }
634 }
635 }
b120fe3b 636
763ec244
DS
637 return CMD_SUCCESS;
638}
639
df395600
DS
640void zebra_mlag_init(void)
641{
763ec244
DS
642 install_element(VIEW_NODE, &show_mlag_cmd);
643 install_element(ENABLE_NODE, &test_mlag_cmd);
ee235396
SK
644
645 /*
646 * Intialiaze teh MLAG Global variableis
647 * write thread will be craeted during actual registration with MCLAG
648 */
649 zrouter.mlag_info.clients_interested_cnt = 0;
650 zrouter.mlag_info.connected = false;
651 zrouter.mlag_info.timer_running = false;
652 zrouter.mlag_info.mlag_fifo = stream_fifo_new();
653 zrouter.mlag_info.zebra_pth_mlag = NULL;
654 zrouter.mlag_info.th_master = NULL;
655 zrouter.mlag_info.t_read = NULL;
656 zrouter.mlag_info.t_write = NULL;
657 test_mlag_in_progress = false;
658 zebra_mlag_reset_write_buffer();
659 zebra_mlag_reset_read_buffer();
df395600
DS
660}
661
662void zebra_mlag_terminate(void)
663{
664}
ee235396
SK
665
666
667/*
668 *
669 * ProtoBuf Encoding APIs
670 */
671
672int zebra_mlag_protobuf_encode_client_data(struct stream *s, uint32_t *msg_type)
673{
674 return 0;
675}
676
677int zebra_mlag_protobuf_decode_message(struct stream **s, uint8_t *data,
678 uint32_t len)
679{
680 return 0;
681}