2 * Copyright (C) 2018 Cumulus Networks, Inc.
5 * This file is part of FRR.
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
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.
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
26 #include "frr_pthread.h"
29 #include "zebra/zebra_mlag.h"
30 #include "zebra/zebra_mlag_private.h"
31 #include "zebra/zebra_router.h"
32 #include "zebra/zebra_memory.h"
33 #include "zebra/zapi_msg.h"
34 #include "zebra/debug.h"
36 #ifndef VTYSH_EXTRACT_PL
37 #include "zebra/zebra_mlag_clippy.c"
40 #define ZEBRA_MLAG_METADATA_LEN 4
41 #define ZEBRA_MLAG_MSG_BCAST 0xFFFFFFFF
43 uint8_t mlag_wr_buffer
[ZEBRA_MLAG_BUF_LIMIT
];
44 uint8_t mlag_rd_buffer
[ZEBRA_MLAG_BUF_LIMIT
];
45 uint32_t mlag_rd_buf_offset
;
47 static bool test_mlag_in_progress
;
49 static int zebra_mlag_signal_write_thread(void);
50 static int zebra_mlag_terminate_pthread(struct thread
*event
);
51 static int zebra_mlag_post_data_from_main_thread(struct thread
*thread
);
52 static void zebra_mlag_publish_process_state(struct zserv
*client
,
53 zebra_message_types_t msg_type
);
55 /**********************MLAG Interaction***************************************/
58 * API to post the Registration to MLAGD
59 * MLAG will not process any messages with out the registration
61 void zebra_mlag_send_register(void)
63 struct stream
*s
= NULL
;
65 s
= stream_new(sizeof(struct mlag_msg
));
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();
73 if (IS_ZEBRA_DEBUG_MLAG
)
74 zlog_debug("%s: Enqueued MLAG Register to MLAG Thread ",
79 * API to post the De-Registration to MLAGD
80 * MLAG will not process any messages after the de-registration
82 void zebra_mlag_send_deregister(void)
84 struct stream
*s
= NULL
;
86 s
= stream_new(sizeof(struct mlag_msg
));
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();
94 if (IS_ZEBRA_DEBUG_MLAG
)
95 zlog_debug("%s: Enqueued MLAG De-Register to MLAG Thread ",
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
104 void zebra_mlag_process_mlag_data(uint8_t *data
, uint32_t len
)
106 struct stream
*s
= NULL
;
107 struct stream
*s1
= NULL
;
110 s
= stream_new(ZEBRA_MAX_PACKET_SIZ
);
111 msg_type
= zebra_mlag_protobuf_decode_message(s
, data
, len
);
114 /* Something went wrong in decoding */
116 zlog_err("%s: failed to process mlag data-%d, %u", __func__
,
122 * additional four bytes are for message type
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
,
132 /**********************End of MLAG Interaction********************************/
134 /************************MLAG Thread Processing*******************************/
137 * after posting every 'ZEBRA_MLAG_POST_LIMIT' packets, MLAG Thread will be
138 * yielded to give CPU for other threads
140 #define ZEBRA_MLAG_POST_LIMIT 100
143 * This thread reads the clients data from the Global queue and encodes with
144 * protobuf and pass on to the MLAG socket.
146 static int zebra_mlag_client_msg_handler(struct thread
*event
)
149 uint32_t wr_count
= 0;
150 uint32_t msg_type
= 0;
151 uint32_t max_count
= 0;
154 wr_count
= stream_fifo_count_safe(zrouter
.mlag_info
.mlag_fifo
);
155 if (IS_ZEBRA_DEBUG_MLAG
)
156 zlog_debug(":%s: Processing MLAG write, %u messages in queue",
159 max_count
= MIN(wr_count
, ZEBRA_MLAG_POST_LIMIT
);
161 for (wr_count
= 0; wr_count
< max_count
; wr_count
++) {
162 s
= stream_fifo_pop_safe(zrouter
.mlag_info
.mlag_fifo
);
164 zlog_debug(":%s: Got a NULL Messages, some thing wrong",
170 * Encode the data now
172 len
= zebra_mlag_protobuf_encode_client_data(s
, &msg_type
);
178 zebra_mlag_private_write_data(mlag_wr_buffer
, len
);
181 * If message type is De-register, send a signal to main
182 * thread, so that necessary cleanup will be done by
185 if (msg_type
== MLAG_DEREGISTER
) {
186 thread_add_event(zrouter
.master
,
187 zebra_mlag_terminate_pthread
,
195 if (IS_ZEBRA_DEBUG_MLAG
)
196 zlog_debug(":%s: Posted %d messages to MLAGD", __func__
,
199 * Currently there is only message write task is enqueued to this
200 * thread, yielding was added for future purpose, so that this thread
201 * can server other tasks also and in case FIFO is empty, this task will
202 * be schedule when main thread adds some messages
204 if (wr_count
>= ZEBRA_MLAG_POST_LIMIT
)
205 zebra_mlag_signal_write_thread();
210 * API to handle the process state.
211 * In case of Down, Zebra keep monitoring the MLAG state.
212 * all the state Notifications will be published to clients
214 void zebra_mlag_handle_process_state(enum zebra_mlag_state state
)
216 if (state
== MLAG_UP
) {
217 zrouter
.mlag_info
.connected
= true;
218 zebra_mlag_publish_process_state(NULL
, ZEBRA_MLAG_PROCESS_UP
);
219 zebra_mlag_send_register();
220 } else if (state
== MLAG_DOWN
) {
221 zrouter
.mlag_info
.connected
= false;
222 zebra_mlag_publish_process_state(NULL
, ZEBRA_MLAG_PROCESS_DOWN
);
223 zebra_mlag_private_monitor_state();
227 /***********************End of MLAG Thread processing*************************/
229 /*************************Multi-entratnt Api's********************************/
232 * Provider api to signal that work/events are available
233 * for the Zebra MLAG Write pthread.
234 * This API is called from 2 pthreads..
235 * 1) by main thread when client posts a MLAG Message
236 * 2) by MLAG Thread, in case of yield
237 * though this api, is called from two threads we don't need any locking
238 * because Thread task enqueue is thread safe means internally it had
239 * necessary protection
241 static int zebra_mlag_signal_write_thread(void)
243 if (IS_ZEBRA_DEBUG_MLAG
)
244 zlog_debug(":%s: Scheduling MLAG write", __func__
);
246 * This api will be called from Both main & MLAG Threads.
247 * main thread writes, "zrouter.mlag_info.th_master" only
248 * during Zebra Init/after MLAG thread is destroyed.
249 * so it is safe to use without any locking
251 thread_add_event(zrouter
.mlag_info
.th_master
,
252 zebra_mlag_client_msg_handler
, NULL
, 0,
253 &zrouter
.mlag_info
.t_write
);
258 * API will be used to publish the MLAG state to interested clients
259 * In case client is passed, state is posted only for that client,
260 * otherwise to all interested clients
261 * this api can be called from two threads.
262 * 1) from main thread: when client is passed
263 * 2) from MLAG Thread: when client is NULL
265 * In second case, to avoid global data access data will be post to Main
266 * thread, so that actual posting to clients will happen from Main thread.
268 static void zebra_mlag_publish_process_state(struct zserv
*client
,
269 zebra_message_types_t msg_type
)
273 if (IS_ZEBRA_DEBUG_MLAG
)
274 zlog_debug("%s: Publishing MLAG process state:%s to %s Client",
276 (msg_type
== ZEBRA_MLAG_PROCESS_UP
) ? "UP" : "DOWN",
277 (client
) ? "one" : "all");
280 s
= stream_new(ZEBRA_HEADER_SIZE
);
281 zclient_create_header(s
, msg_type
, VRF_DEFAULT
);
282 zserv_send_message(client
, s
);
288 * additional four bytes are for mesasge type
290 s
= stream_new(ZEBRA_HEADER_SIZE
+ ZEBRA_MLAG_METADATA_LEN
);
291 stream_putl(s
, ZEBRA_MLAG_MSG_BCAST
);
292 zclient_create_header(s
, msg_type
, VRF_DEFAULT
);
293 thread_add_event(zrouter
.master
, zebra_mlag_post_data_from_main_thread
,
297 /**************************End of Multi-entrant Apis**************************/
299 /***********************Zebra Main thread processing**************************/
302 * To avoid data corruption, messages will be post to clients only from
303 * main thread, because for that access was needed for clients list.
304 * so instead of forcing the locks, messages will be posted from main thread.
306 static int zebra_mlag_post_data_from_main_thread(struct thread
*thread
)
308 struct stream
*s
= THREAD_ARG(thread
);
309 struct stream
*zebra_s
= NULL
;
310 struct listnode
*node
;
311 struct zserv
*client
;
312 uint32_t msg_type
= 0;
313 uint32_t msg_len
= 0;
318 STREAM_GETL(s
, msg_type
);
319 if (IS_ZEBRA_DEBUG_MLAG
)
321 "%s: Posting MLAG data for msg_type:0x%x to interested cleints",
324 msg_len
= s
->endp
- ZEBRA_MLAG_METADATA_LEN
;
325 for (ALL_LIST_ELEMENTS_RO(zrouter
.client_list
, node
, client
)) {
326 if (client
->mlag_updates_interested
== true) {
327 if (msg_type
!= ZEBRA_MLAG_MSG_BCAST
328 && !CHECK_FLAG(client
->mlag_reg_mask1
,
333 if (IS_ZEBRA_DEBUG_MLAG
)
335 "%s: Posting MLAG data of length-%d to client:%d ",
336 __func__
, msg_len
, client
->proto
);
338 zebra_s
= stream_new(msg_len
);
339 STREAM_GET(zebra_s
->data
, s
, msg_len
);
340 zebra_s
->endp
= msg_len
;
341 stream_putw_at(zebra_s
, 0, msg_len
);
344 * This stream will be enqueued to client_obuf, it will
345 * be freed after posting to client socket.
347 zserv_send_message(client
, zebra_s
);
357 stream_free(zebra_s
);
362 * Start the MLAG Thread, this will be used to write client data on to
363 * MLAG Process and to read the data from MLAG and post to cleints.
364 * when all clients are un-registered, this Thread will be
367 static void zebra_mlag_spawn_pthread(void)
369 /* Start MLAG write pthread */
371 struct frr_pthread_attr pattr
= {.start
=
372 frr_pthread_attr_default
.start
,
373 .stop
= frr_pthread_attr_default
.stop
};
375 zrouter
.mlag_info
.zebra_pth_mlag
=
376 frr_pthread_new(&pattr
, "Zebra MLAG thread", "Zebra MLAG");
378 zrouter
.mlag_info
.th_master
= zrouter
.mlag_info
.zebra_pth_mlag
->master
;
381 /* Enqueue an initial event to the Newly spawn MLAG pthread */
382 zebra_mlag_signal_write_thread();
384 frr_pthread_run(zrouter
.mlag_info
.zebra_pth_mlag
, NULL
);
388 * all clients are un-registered for MLAG Updates, terminate the
391 static int zebra_mlag_terminate_pthread(struct thread
*event
)
393 if (IS_ZEBRA_DEBUG_MLAG
)
394 zlog_debug("Zebra MLAG write thread terminate called");
396 if (zrouter
.mlag_info
.clients_interested_cnt
) {
397 if (IS_ZEBRA_DEBUG_MLAG
)
399 "Zebra MLAG: still some clients are interested");
403 frr_pthread_stop(zrouter
.mlag_info
.zebra_pth_mlag
, NULL
);
405 /* Destroy pthread */
406 frr_pthread_destroy(zrouter
.mlag_info
.zebra_pth_mlag
);
407 zrouter
.mlag_info
.zebra_pth_mlag
= NULL
;
408 zrouter
.mlag_info
.th_master
= NULL
;
409 zrouter
.mlag_info
.t_read
= NULL
;
410 zrouter
.mlag_info
.t_write
= NULL
;
413 * Send Notification to clean private data
415 zebra_mlag_private_cleanup_data();
420 * API to register zebra client for MLAG Updates
422 void zebra_mlag_client_register(ZAPI_HANDLER_ARGS
)
425 uint32_t reg_mask
= 0;
428 if (IS_ZEBRA_DEBUG_MLAG
)
429 zlog_debug("Received MLAG Registration from client-proto:%d",
433 /* Get input stream. */
437 STREAM_GETL(s
, reg_mask
);
439 if (client
->mlag_updates_interested
== true) {
441 if (IS_ZEBRA_DEBUG_MLAG
)
443 "Client is registered, existing mask: 0x%x, new mask: 0x%x",
444 client
->mlag_reg_mask1
, reg_mask
);
445 if (client
->mlag_reg_mask1
!= reg_mask
)
446 client
->mlag_reg_mask1
= reg_mask
;
448 * Client might missed MLAG-UP Notification, post-it again
450 zebra_mlag_publish_process_state(client
, ZEBRA_MLAG_PROCESS_UP
);
455 client
->mlag_updates_interested
= true;
456 client
->mlag_reg_mask1
= reg_mask
;
457 if (IS_ZEBRA_DEBUG_MLAG
)
458 zlog_debug("Registering for MLAG Updates with mask: 0x%x, ",
459 client
->mlag_reg_mask1
);
461 zrouter
.mlag_info
.clients_interested_cnt
++;
463 if (zrouter
.mlag_info
.clients_interested_cnt
== 1) {
465 * First-client for MLAG Updates,open the communication channel
468 if (IS_ZEBRA_DEBUG_MLAG
)
470 "First client, opening the channel with MLAG");
472 zebra_mlag_spawn_pthread();
473 rc
= zebra_mlag_private_open_channel();
476 * For some reason, zebra not able to open the
477 * comm-channel with MLAG, so post MLAG-DOWN to client.
478 * later when the channel is open, zebra will send
481 if (IS_ZEBRA_DEBUG_MLAG
)
483 "Fail to open channel with MLAG,rc:%d, post Proto-down",
485 zebra_mlag_publish_process_state(
486 client
, ZEBRA_MLAG_PROCESS_DOWN
);
490 if (IS_ZEBRA_DEBUG_MLAG
)
491 zlog_debug("Client Registered successfully for MLAG Updates");
493 if (zrouter
.mlag_info
.connected
== true)
494 zebra_mlag_publish_process_state(client
, ZEBRA_MLAG_PROCESS_UP
);
500 * API to un-register for MLAG Updates
502 void zebra_mlag_client_unregister(ZAPI_HANDLER_ARGS
)
504 if (IS_ZEBRA_DEBUG_MLAG
)
505 zlog_debug("Received MLAG De-Registration from client-proto:%d",
508 if (client
->mlag_updates_interested
== false)
512 client
->mlag_updates_interested
= false;
513 client
->mlag_reg_mask1
= 0;
514 zrouter
.mlag_info
.clients_interested_cnt
--;
516 if (zrouter
.mlag_info
.clients_interested_cnt
== 0) {
518 * No-client is interested for MLAG Updates,close the
519 * communication channel with MLAG
521 if (IS_ZEBRA_DEBUG_MLAG
)
522 zlog_debug("Last client for MLAG, close the channel ");
527 * 1) main thread calls socket close which posts De-register
528 * to MLAG write thread
529 * 2) after MLAG write thread posts De-register it sends a
530 * signal back to main thread to do the thread cleanup
531 * this was mainly to make sure De-register is posted to MCLAGD.
533 zebra_mlag_private_close_channel();
536 if (IS_ZEBRA_DEBUG_MLAG
)
538 "Client De-Registered successfully for MLAG Updates");
542 * Does following things.
543 * 1) allocated new local stream, and copies the client data and enqueue
545 * 2) MLAG Thread after dequeing, encode the client data using protobuf
546 * and write on to MLAG
548 void zebra_mlag_forward_client_msg(ZAPI_HANDLER_ARGS
)
550 struct stream
*zebra_s
;
551 struct stream
*mlag_s
;
553 if (IS_ZEBRA_DEBUG_MLAG
)
554 zlog_debug("Received Client MLAG Data from client-proto:%d",
557 /* Get input stream. */
559 mlag_s
= stream_new(zebra_s
->endp
);
562 * Client data is | Zebra Header + MLAG Data |
563 * we need to enqueue only the MLAG data, skipping Zebra Header
565 stream_put(mlag_s
, zebra_s
->data
+ zebra_s
->getp
,
566 STREAM_READABLE(zebra_s
));
567 stream_fifo_push_safe(zrouter
.mlag_info
.mlag_fifo
, mlag_s
);
568 zebra_mlag_signal_write_thread();
570 if (IS_ZEBRA_DEBUG_MLAG
)
571 zlog_debug("%s: Enqueued Client:%d data to MLAG Thread ",
572 __func__
, client
->proto
);
575 /***********************End of Zebra Main thread processing*************/
577 enum mlag_role
zebra_mlag_get_role(void)
579 return zrouter
.mlag_info
.role
;
582 DEFUN_HIDDEN (show_mlag
,
587 "The mlag role on this machine\n")
589 char buf
[MLAG_ROLE_STRSIZE
];
591 vty_out(vty
, "MLag is configured to: %s\n",
592 mlag_role2str(zrouter
.mlag_info
.role
, buf
, sizeof(buf
)));
597 DEFPY_HIDDEN(test_mlag
, test_mlag_cmd
,
598 "test zebra mlag <none$none|primary$primary|secondary$secondary>",
601 "Modify the Mlag state\n"
602 "Mlag is not setup on the machine\n"
603 "Mlag is setup to be primary\n"
604 "Mlag is setup to be the secondary\n")
606 enum mlag_role orig
= zrouter
.mlag_info
.role
;
607 char buf1
[MLAG_ROLE_STRSIZE
], buf2
[MLAG_ROLE_STRSIZE
];
610 zrouter
.mlag_info
.role
= MLAG_ROLE_NONE
;
612 zrouter
.mlag_info
.role
= MLAG_ROLE_PRIMARY
;
614 zrouter
.mlag_info
.role
= MLAG_ROLE_SECONDARY
;
616 if (IS_ZEBRA_DEBUG_MLAG
)
617 zlog_debug("Test: Changing role from %s to %s",
618 mlag_role2str(orig
, buf1
, sizeof(buf1
)),
619 mlag_role2str(orig
, buf2
, sizeof(buf2
)));
621 if (orig
!= zrouter
.mlag_info
.role
) {
622 zsend_capabilities_all_clients();
623 if (zrouter
.mlag_info
.role
!= MLAG_ROLE_NONE
) {
624 if (zrouter
.mlag_info
.clients_interested_cnt
== 0
625 && test_mlag_in_progress
== false) {
626 if (zrouter
.mlag_info
.zebra_pth_mlag
== NULL
)
627 zebra_mlag_spawn_pthread();
628 zrouter
.mlag_info
.clients_interested_cnt
++;
629 test_mlag_in_progress
= true;
630 zebra_mlag_private_open_channel();
633 if (test_mlag_in_progress
== true) {
634 test_mlag_in_progress
= false;
635 zrouter
.mlag_info
.clients_interested_cnt
--;
636 zebra_mlag_private_close_channel();
644 void zebra_mlag_init(void)
646 install_element(VIEW_NODE
, &show_mlag_cmd
);
647 install_element(ENABLE_NODE
, &test_mlag_cmd
);
650 * Intialiaze the MLAG Global variables
651 * write thread will be created during actual registration with MCLAG
653 zrouter
.mlag_info
.clients_interested_cnt
= 0;
654 zrouter
.mlag_info
.connected
= false;
655 zrouter
.mlag_info
.timer_running
= false;
656 zrouter
.mlag_info
.mlag_fifo
= stream_fifo_new();
657 zrouter
.mlag_info
.zebra_pth_mlag
= NULL
;
658 zrouter
.mlag_info
.th_master
= NULL
;
659 zrouter
.mlag_info
.t_read
= NULL
;
660 zrouter
.mlag_info
.t_write
= NULL
;
661 test_mlag_in_progress
= false;
662 zebra_mlag_reset_read_buffer();
665 void zebra_mlag_terminate(void)
672 * ProtoBuf Encoding APIs
677 DEFINE_MTYPE_STATIC(ZEBRA
, MLAG_PBUF
, "ZEBRA MLAG PROTOBUF")
679 int zebra_mlag_protobuf_encode_client_data(struct stream
*s
, uint32_t *msg_type
)
681 ZebraMlagHeader hdr
= ZEBRA_MLAG__HEADER__INIT
;
682 struct mlag_msg mlag_msg
;
683 uint8_t tmp_buf
[ZEBRA_MLAG_BUF_LIMIT
];
687 char buf
[ZLOG_FILTER_LENGTH_MAX
];
689 if (IS_ZEBRA_DEBUG_MLAG
)
690 zlog_debug("%s: Entering..", __func__
);
692 rc
= mlag_lib_decode_mlag_hdr(s
, &mlag_msg
);
696 if (IS_ZEBRA_DEBUG_MLAG
)
697 zlog_debug("%s: Mlag ProtoBuf encoding of message:%s, len:%d",
699 mlag_lib_msgid_to_str(mlag_msg
.msg_type
, buf
,
702 *msg_type
= mlag_msg
.msg_type
;
703 switch (mlag_msg
.msg_type
) {
704 case MLAG_MROUTE_ADD
: {
705 struct mlag_mroute_add msg
;
706 ZebraMlagMrouteAdd pay_load
= ZEBRA_MLAG_MROUTE_ADD__INIT
;
707 uint32_t vrf_name_len
= 0;
709 rc
= mlag_lib_decode_mroute_add(s
, &msg
);
712 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
713 pay_load
.vrf_name
= XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
714 strlcpy(pay_load
.vrf_name
, msg
.vrf_name
, vrf_name_len
);
715 pay_load
.source_ip
= msg
.source_ip
;
716 pay_load
.group_ip
= msg
.group_ip
;
717 pay_load
.cost_to_rp
= msg
.cost_to_rp
;
718 pay_load
.owner_id
= msg
.owner_id
;
719 pay_load
.am_i_dr
= msg
.am_i_dr
;
720 pay_load
.am_i_dual_active
= msg
.am_i_dual_active
;
721 pay_load
.vrf_id
= msg
.vrf_id
;
723 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
724 vrf_name_len
= strlen(msg
.intf_name
) + 1;
726 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
727 strlcpy(pay_load
.intf_name
, msg
.intf_name
,
731 len
= zebra_mlag_mroute_add__pack(&pay_load
, tmp_buf
);
732 XFREE(MTYPE_MLAG_PBUF
, pay_load
.vrf_name
);
733 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
)
734 XFREE(MTYPE_MLAG_PBUF
, pay_load
.intf_name
);
736 case MLAG_MROUTE_DEL
: {
737 struct mlag_mroute_del msg
;
738 ZebraMlagMrouteDel pay_load
= ZEBRA_MLAG_MROUTE_DEL__INIT
;
739 uint32_t vrf_name_len
= 0;
741 rc
= mlag_lib_decode_mroute_del(s
, &msg
);
744 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
745 pay_load
.vrf_name
= XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
746 strlcpy(pay_load
.vrf_name
, msg
.vrf_name
, vrf_name_len
);
747 pay_load
.source_ip
= msg
.source_ip
;
748 pay_load
.group_ip
= msg
.group_ip
;
749 pay_load
.owner_id
= msg
.owner_id
;
750 pay_load
.vrf_id
= msg
.vrf_id
;
752 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
753 vrf_name_len
= strlen(msg
.intf_name
) + 1;
755 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
756 strlcpy(pay_load
.intf_name
, msg
.intf_name
,
760 len
= zebra_mlag_mroute_del__pack(&pay_load
, tmp_buf
);
761 XFREE(MTYPE_MLAG_PBUF
, pay_load
.vrf_name
);
762 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
)
763 XFREE(MTYPE_MLAG_PBUF
, pay_load
.intf_name
);
765 case MLAG_MROUTE_ADD_BULK
: {
766 struct mlag_mroute_add msg
;
767 ZebraMlagMrouteAddBulk Bulk_msg
=
768 ZEBRA_MLAG_MROUTE_ADD_BULK__INIT
;
769 ZebraMlagMrouteAdd
**pay_load
= NULL
;
771 bool cleanup
= false;
773 Bulk_msg
.n_mroute_add
= mlag_msg
.msg_cnt
;
774 pay_load
= XMALLOC(MTYPE_MLAG_PBUF
, sizeof(ZebraMlagMrouteAdd
*)
777 for (i
= 0; i
< mlag_msg
.msg_cnt
; i
++) {
779 uint32_t vrf_name_len
= 0;
781 rc
= mlag_lib_decode_mroute_add(s
, &msg
);
786 pay_load
[i
] = XMALLOC(MTYPE_MLAG_PBUF
,
787 sizeof(ZebraMlagMrouteAdd
));
788 zebra_mlag_mroute_add__init(pay_load
[i
]);
790 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
791 pay_load
[i
]->vrf_name
=
792 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
793 strlcpy(pay_load
[i
]->vrf_name
, msg
.vrf_name
,
795 pay_load
[i
]->source_ip
= msg
.source_ip
;
796 pay_load
[i
]->group_ip
= msg
.group_ip
;
797 pay_load
[i
]->cost_to_rp
= msg
.cost_to_rp
;
798 pay_load
[i
]->owner_id
= msg
.owner_id
;
799 pay_load
[i
]->am_i_dr
= msg
.am_i_dr
;
800 pay_load
[i
]->am_i_dual_active
= msg
.am_i_dual_active
;
801 pay_load
[i
]->vrf_id
= msg
.vrf_id
;
802 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
803 vrf_name_len
= strlen(msg
.intf_name
) + 1;
804 pay_load
[i
]->intf_name
=
805 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
807 strlcpy(pay_load
[i
]->intf_name
, msg
.intf_name
,
811 if (cleanup
== false) {
812 Bulk_msg
.mroute_add
= pay_load
;
813 len
= zebra_mlag_mroute_add_bulk__pack(&Bulk_msg
,
817 for (i
= 0; i
< mlag_msg
.msg_cnt
; i
++) {
818 if (pay_load
[i
]->vrf_name
)
819 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->vrf_name
);
820 if (pay_load
[i
]->owner_id
== MLAG_OWNER_INTERFACE
821 && pay_load
[i
]->intf_name
)
822 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->intf_name
);
824 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]);
826 XFREE(MTYPE_MLAG_PBUF
, pay_load
);
830 case MLAG_MROUTE_DEL_BULK
: {
831 struct mlag_mroute_del msg
;
832 ZebraMlagMrouteDelBulk Bulk_msg
=
833 ZEBRA_MLAG_MROUTE_DEL_BULK__INIT
;
834 ZebraMlagMrouteDel
**pay_load
= NULL
;
836 bool cleanup
= false;
838 Bulk_msg
.n_mroute_del
= mlag_msg
.msg_cnt
;
839 pay_load
= XMALLOC(MTYPE_MLAG_PBUF
, sizeof(ZebraMlagMrouteDel
*)
842 for (i
= 0; i
< mlag_msg
.msg_cnt
; i
++) {
844 uint32_t vrf_name_len
= 0;
846 rc
= mlag_lib_decode_mroute_del(s
, &msg
);
852 pay_load
[i
] = XMALLOC(MTYPE_MLAG_PBUF
,
853 sizeof(ZebraMlagMrouteDel
));
854 zebra_mlag_mroute_del__init(pay_load
[i
]);
856 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
857 pay_load
[i
]->vrf_name
=
858 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
860 strlcpy(pay_load
[i
]->vrf_name
, msg
.vrf_name
,
862 pay_load
[i
]->source_ip
= msg
.source_ip
;
863 pay_load
[i
]->group_ip
= msg
.group_ip
;
864 pay_load
[i
]->owner_id
= msg
.owner_id
;
865 pay_load
[i
]->vrf_id
= msg
.vrf_id
;
866 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
867 vrf_name_len
= strlen(msg
.intf_name
) + 1;
868 pay_load
[i
]->intf_name
=
869 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
871 strlcpy(pay_load
[i
]->intf_name
, msg
.intf_name
,
876 Bulk_msg
.mroute_del
= pay_load
;
877 len
= zebra_mlag_mroute_del_bulk__pack(&Bulk_msg
,
881 for (i
= 0; i
< mlag_msg
.msg_cnt
; i
++) {
882 if (pay_load
[i
]->vrf_name
)
883 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->vrf_name
);
884 if (pay_load
[i
]->owner_id
== MLAG_OWNER_INTERFACE
885 && pay_load
[i
]->intf_name
)
886 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->intf_name
);
888 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]);
890 XFREE(MTYPE_MLAG_PBUF
, pay_load
);
898 if (IS_ZEBRA_DEBUG_MLAG
)
899 zlog_debug("%s: length of Mlag ProtoBuf encoded message:%s, %d",
901 mlag_lib_msgid_to_str(mlag_msg
.msg_type
, buf
,
904 hdr
.type
= (ZebraMlagHeader__MessageType
)mlag_msg
.msg_type
;
907 hdr
.data
.data
= XMALLOC(MTYPE_MLAG_PBUF
, len
);
908 memcpy(hdr
.data
.data
, tmp_buf
, len
);
912 * ProtoBuf Infra will not support to demarc the pointers whem multiple
913 * messages are posted inside a single Buffer.
914 * 2 -solutions exist to solve this
915 * 1. add Unenoced length at the beginning of every message, this will
916 * be used to point to next message in the buffer
917 * 2. another solution is defining all messages insides another message
918 * But this will permit only 32 messages. this can be extended with
920 * for simplicity we are going with solution-1.
922 len
= zebra_mlag__header__pack(&hdr
,
923 (mlag_wr_buffer
+ ZEBRA_MLAG_LEN_SIZE
));
925 memcpy(mlag_wr_buffer
, &n_len
, ZEBRA_MLAG_LEN_SIZE
);
926 len
+= ZEBRA_MLAG_LEN_SIZE
;
928 if (IS_ZEBRA_DEBUG_MLAG
)
930 "%s: length of Mlag ProtoBuf message:%s with Header %d",
932 mlag_lib_msgid_to_str(mlag_msg
.msg_type
, buf
,
936 XFREE(MTYPE_MLAG_PBUF
, hdr
.data
.data
);
941 int zebra_mlag_protobuf_decode_message(struct stream
*s
, uint8_t *data
,
945 ZebraMlagHeader
*hdr
;
948 hdr
= zebra_mlag__header__unpack(NULL
, len
, data
);
953 * ADD The MLAG Header
955 zclient_create_header(s
, ZEBRA_MLAG_FORWARD_MSG
, VRF_DEFAULT
);
957 msg_type
= hdr
->type
;
959 if (IS_ZEBRA_DEBUG_MLAG
)
960 zlog_debug("%s: Mlag ProtoBuf decoding of message:%s", __func__
,
961 mlag_lib_msgid_to_str(msg_type
, buf
, 80));
964 * Internal MLAG Message-types & MLAG.proto message types should
965 * always match, otherwise there can be decoding errors
966 * To avoid exposing clients with Protobuf flags, using internal
969 stream_putl(s
, hdr
->type
);
971 if (hdr
->data
.len
== 0) {
973 stream_putw(s
, MLAG_MSG_NULL_PAYLOAD
);
975 stream_putw(s
, MLAG_MSG_NO_BATCH
);
978 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_STATUS_UPDATE
: {
979 ZebraMlagStatusUpdate
*msg
= NULL
;
981 msg
= zebra_mlag_status_update__unpack(
982 NULL
, hdr
->data
.len
, hdr
->data
.data
);
984 zebra_mlag__header__free_unpacked(hdr
, NULL
);
988 stream_putw(s
, sizeof(struct mlag_status
));
990 stream_putw(s
, MLAG_MSG_NO_BATCH
);
992 stream_put(s
, msg
->peerlink
, INTERFACE_NAMSIZ
);
993 stream_putl(s
, msg
->my_role
);
994 stream_putl(s
, msg
->peer_state
);
995 zebra_mlag_status_update__free_unpacked(msg
, NULL
);
997 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_VXLAN_UPDATE
: {
998 ZebraMlagVxlanUpdate
*msg
= NULL
;
1000 msg
= zebra_mlag_vxlan_update__unpack(
1001 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1003 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1007 stream_putw(s
, sizeof(struct mlag_vxlan
));
1009 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1011 stream_putl(s
, msg
->anycast_ip
);
1012 stream_putl(s
, msg
->local_ip
);
1013 zebra_mlag_vxlan_update__free_unpacked(msg
, NULL
);
1015 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_ADD
: {
1016 ZebraMlagMrouteAdd
*msg
= NULL
;
1018 msg
= zebra_mlag_mroute_add__unpack(NULL
, hdr
->data
.len
,
1021 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1025 stream_putw(s
, sizeof(struct mlag_mroute_add
));
1027 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1029 stream_put(s
, msg
->vrf_name
, VRF_NAMSIZ
);
1031 stream_putl(s
, msg
->source_ip
);
1032 stream_putl(s
, msg
->group_ip
);
1033 stream_putl(s
, msg
->cost_to_rp
);
1034 stream_putl(s
, msg
->owner_id
);
1035 stream_putc(s
, msg
->am_i_dr
);
1036 stream_putc(s
, msg
->am_i_dual_active
);
1037 stream_putl(s
, msg
->vrf_id
);
1038 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1039 stream_put(s
, msg
->intf_name
, INTERFACE_NAMSIZ
);
1041 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1042 zebra_mlag_mroute_add__free_unpacked(msg
, NULL
);
1044 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_DEL
: {
1045 ZebraMlagMrouteDel
*msg
= NULL
;
1047 msg
= zebra_mlag_mroute_del__unpack(NULL
, hdr
->data
.len
,
1050 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1054 stream_putw(s
, sizeof(struct mlag_mroute_del
));
1056 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1058 stream_put(s
, msg
->vrf_name
, VRF_NAMSIZ
);
1060 stream_putl(s
, msg
->source_ip
);
1061 stream_putl(s
, msg
->group_ip
);
1062 stream_putl(s
, msg
->group_ip
);
1063 stream_putl(s
, msg
->owner_id
);
1064 stream_putl(s
, msg
->vrf_id
);
1065 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1066 stream_put(s
, msg
->intf_name
, INTERFACE_NAMSIZ
);
1068 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1069 zebra_mlag_mroute_del__free_unpacked(msg
, NULL
);
1071 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_ADD_BULK
: {
1072 ZebraMlagMrouteAddBulk
*Bulk_msg
= NULL
;
1073 ZebraMlagMrouteAdd
*msg
= NULL
;
1076 Bulk_msg
= zebra_mlag_mroute_add_bulk__unpack(
1077 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1078 if (Bulk_msg
== NULL
) {
1079 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1083 stream_putw(s
, (Bulk_msg
->n_mroute_add
1084 * sizeof(struct mlag_mroute_add
)));
1085 /* No. of msgs in Batch */
1086 stream_putw(s
, Bulk_msg
->n_mroute_add
);
1089 for (i
= 0; i
< Bulk_msg
->n_mroute_add
; i
++) {
1091 msg
= Bulk_msg
->mroute_add
[i
];
1093 stream_put(s
, msg
->vrf_name
, VRF_NAMSIZ
);
1094 stream_putl(s
, msg
->source_ip
);
1095 stream_putl(s
, msg
->group_ip
);
1096 stream_putl(s
, msg
->cost_to_rp
);
1097 stream_putl(s
, msg
->owner_id
);
1098 stream_putc(s
, msg
->am_i_dr
);
1099 stream_putc(s
, msg
->am_i_dual_active
);
1100 stream_putl(s
, msg
->vrf_id
);
1101 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1102 stream_put(s
, msg
->intf_name
,
1105 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1107 zebra_mlag_mroute_add_bulk__free_unpacked(Bulk_msg
,
1110 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_DEL_BULK
: {
1111 ZebraMlagMrouteDelBulk
*Bulk_msg
= NULL
;
1112 ZebraMlagMrouteDel
*msg
= NULL
;
1115 Bulk_msg
= zebra_mlag_mroute_del_bulk__unpack(
1116 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1117 if (Bulk_msg
== NULL
) {
1118 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1122 stream_putw(s
, (Bulk_msg
->n_mroute_del
1123 * sizeof(struct mlag_mroute_del
)));
1124 /* No. of msgs in Batch */
1125 stream_putw(s
, Bulk_msg
->n_mroute_del
);
1128 for (i
= 0; i
< Bulk_msg
->n_mroute_del
; i
++) {
1130 msg
= Bulk_msg
->mroute_del
[i
];
1132 stream_put(s
, msg
->vrf_name
, VRF_NAMSIZ
);
1133 stream_putl(s
, msg
->source_ip
);
1134 stream_putl(s
, msg
->group_ip
);
1135 stream_putl(s
, msg
->owner_id
);
1136 stream_putl(s
, msg
->vrf_id
);
1137 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1138 stream_put(s
, msg
->intf_name
,
1141 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1143 zebra_mlag_mroute_del_bulk__free_unpacked(Bulk_msg
,
1146 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_ZEBRA_STATUS_UPDATE
: {
1147 ZebraMlagZebraStatusUpdate
*msg
= NULL
;
1149 msg
= zebra_mlag_zebra_status_update__unpack(
1150 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1152 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1156 stream_putw(s
, sizeof(struct mlag_frr_status
));
1158 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1160 stream_putl(s
, msg
->peer_frrstate
);
1161 zebra_mlag_zebra_status_update__free_unpacked(msg
,
1168 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1173 int zebra_mlag_protobuf_encode_client_data(struct stream
*s
, uint32_t *msg_type
)
1178 int zebra_mlag_protobuf_decode_message(struct stream
*s
, uint8_t *data
,