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