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_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"
36 DEFINE_HOOK(zebra_mlag_private_write_data
,
37 (uint8_t *data
, uint32_t len
), (data
, len
))
38 DEFINE_HOOK(zebra_mlag_private_monitor_state
, (), ())
39 DEFINE_HOOK(zebra_mlag_private_open_channel
, (), ())
40 DEFINE_HOOK(zebra_mlag_private_close_channel
, (), ())
41 DEFINE_HOOK(zebra_mlag_private_cleanup_data
, (), ())
43 #define ZEBRA_MLAG_METADATA_LEN 4
44 #define ZEBRA_MLAG_MSG_BCAST 0xFFFFFFFF
46 uint8_t mlag_wr_buffer
[ZEBRA_MLAG_BUF_LIMIT
];
47 uint8_t mlag_rd_buffer
[ZEBRA_MLAG_BUF_LIMIT
];
48 uint32_t mlag_rd_buf_offset
;
50 static bool test_mlag_in_progress
;
52 static int zebra_mlag_signal_write_thread(void);
53 static int zebra_mlag_terminate_pthread(struct thread
*event
);
54 static int zebra_mlag_post_data_from_main_thread(struct thread
*thread
);
55 static void zebra_mlag_publish_process_state(struct zserv
*client
,
56 zebra_message_types_t msg_type
);
58 /**********************MLAG Interaction***************************************/
61 * API to post the Registration to MLAGD
62 * MLAG will not process any messages with out the registration
64 void zebra_mlag_send_register(void)
66 struct stream
*s
= NULL
;
68 s
= stream_new(sizeof(struct mlag_msg
));
70 stream_putl(s
, MLAG_REGISTER
);
71 stream_putw(s
, MLAG_MSG_NULL_PAYLOAD
);
72 stream_putw(s
, MLAG_MSG_NO_BATCH
);
73 stream_fifo_push_safe(zrouter
.mlag_info
.mlag_fifo
, s
);
74 zebra_mlag_signal_write_thread();
76 if (IS_ZEBRA_DEBUG_MLAG
)
77 zlog_debug("%s: Enqueued MLAG Register to MLAG Thread ",
82 * API to post the De-Registration to MLAGD
83 * MLAG will not process any messages after the de-registration
85 void zebra_mlag_send_deregister(void)
87 struct stream
*s
= NULL
;
89 s
= stream_new(sizeof(struct mlag_msg
));
91 stream_putl(s
, MLAG_DEREGISTER
);
92 stream_putw(s
, MLAG_MSG_NULL_PAYLOAD
);
93 stream_putw(s
, MLAG_MSG_NO_BATCH
);
94 stream_fifo_push_safe(zrouter
.mlag_info
.mlag_fifo
, s
);
95 zebra_mlag_signal_write_thread();
97 if (IS_ZEBRA_DEBUG_MLAG
)
98 zlog_debug("%s: Enqueued MLAG De-Register to MLAG Thread ",
103 * API To handle MLAG Received data
104 * Decodes the data using protobuf and enqueue to main thread
105 * main thread publish this to clients based on client subscription
107 void zebra_mlag_process_mlag_data(uint8_t *data
, uint32_t len
)
109 struct stream
*s
= NULL
;
110 struct stream
*s1
= NULL
;
113 s
= stream_new(ZEBRA_MAX_PACKET_SIZ
);
114 msg_type
= zebra_mlag_protobuf_decode_message(s
, data
, len
);
117 /* Something went wrong in decoding */
119 zlog_err("%s: failed to process mlag data-%d, %u", __func__
,
125 * additional four bytes are for message type
127 s1
= stream_new(stream_get_endp(s
) + ZEBRA_MLAG_METADATA_LEN
);
128 stream_putl(s1
, msg_type
);
129 stream_put(s1
, s
->data
, stream_get_endp(s
));
130 thread_add_event(zrouter
.master
, zebra_mlag_post_data_from_main_thread
,
135 /**********************End of MLAG Interaction********************************/
137 /************************MLAG Thread Processing*******************************/
140 * after posting every 'ZEBRA_MLAG_POST_LIMIT' packets, MLAG Thread will be
141 * yielded to give CPU for other threads
143 #define ZEBRA_MLAG_POST_LIMIT 100
146 * This thread reads the clients data from the Global queue and encodes with
147 * protobuf and pass on to the MLAG socket.
149 static int zebra_mlag_client_msg_handler(struct thread
*event
)
152 uint32_t wr_count
= 0;
153 uint32_t msg_type
= 0;
154 uint32_t max_count
= 0;
157 wr_count
= stream_fifo_count_safe(zrouter
.mlag_info
.mlag_fifo
);
158 if (IS_ZEBRA_DEBUG_MLAG
)
159 zlog_debug(":%s: Processing MLAG write, %u messages in queue",
162 max_count
= MIN(wr_count
, ZEBRA_MLAG_POST_LIMIT
);
164 for (wr_count
= 0; wr_count
< max_count
; wr_count
++) {
165 s
= stream_fifo_pop_safe(zrouter
.mlag_info
.mlag_fifo
);
167 zlog_debug(":%s: Got a NULL Messages, some thing wrong",
173 * Encode the data now
175 len
= zebra_mlag_protobuf_encode_client_data(s
, &msg_type
);
181 hook_call(zebra_mlag_private_write_data
,
182 mlag_wr_buffer
, len
);
185 * If message type is De-register, send a signal to main
186 * thread, so that necessary cleanup will be done by
189 if (msg_type
== MLAG_DEREGISTER
) {
190 thread_add_event(zrouter
.master
,
191 zebra_mlag_terminate_pthread
,
199 if (IS_ZEBRA_DEBUG_MLAG
)
200 zlog_debug(":%s: Posted %d messages to MLAGD", __func__
,
203 * Currently there is only message write task is enqueued to this
204 * thread, yielding was added for future purpose, so that this thread
205 * can server other tasks also and in case FIFO is empty, this task will
206 * be schedule when main thread adds some messages
208 if (wr_count
>= ZEBRA_MLAG_POST_LIMIT
)
209 zebra_mlag_signal_write_thread();
214 * API to handle the process state.
215 * In case of Down, Zebra keep monitoring the MLAG state.
216 * all the state Notifications will be published to clients
218 void zebra_mlag_handle_process_state(enum zebra_mlag_state state
)
220 if (state
== MLAG_UP
) {
221 zrouter
.mlag_info
.connected
= true;
222 zebra_mlag_publish_process_state(NULL
, ZEBRA_MLAG_PROCESS_UP
);
223 zebra_mlag_send_register();
224 } else if (state
== MLAG_DOWN
) {
225 zrouter
.mlag_info
.connected
= false;
226 zebra_mlag_publish_process_state(NULL
, ZEBRA_MLAG_PROCESS_DOWN
);
227 hook_call(zebra_mlag_private_monitor_state
);
231 /***********************End of MLAG Thread processing*************************/
233 /*************************Multi-entratnt Api's********************************/
236 * Provider api to signal that work/events are available
237 * for the Zebra MLAG Write pthread.
238 * This API is called from 2 pthreads..
239 * 1) by main thread when client posts a MLAG Message
240 * 2) by MLAG Thread, in case of yield
241 * though this api, is called from two threads we don't need any locking
242 * because Thread task enqueue is thread safe means internally it had
243 * necessary protection
245 static int zebra_mlag_signal_write_thread(void)
247 if (IS_ZEBRA_DEBUG_MLAG
)
248 zlog_debug(":%s: Scheduling MLAG write", __func__
);
250 * This api will be called from Both main & MLAG Threads.
251 * main thread writes, "zrouter.mlag_info.th_master" only
252 * during Zebra Init/after MLAG thread is destroyed.
253 * so it is safe to use without any locking
255 thread_add_event(zrouter
.mlag_info
.th_master
,
256 zebra_mlag_client_msg_handler
, NULL
, 0,
257 &zrouter
.mlag_info
.t_write
);
262 * API will be used to publish the MLAG state to interested clients
263 * In case client is passed, state is posted only for that client,
264 * otherwise to all interested clients
265 * this api can be called from two threads.
266 * 1) from main thread: when client is passed
267 * 2) from MLAG Thread: when client is NULL
269 * In second case, to avoid global data access data will be post to Main
270 * thread, so that actual posting to clients will happen from Main thread.
272 static void zebra_mlag_publish_process_state(struct zserv
*client
,
273 zebra_message_types_t msg_type
)
277 if (IS_ZEBRA_DEBUG_MLAG
)
278 zlog_debug("%s: Publishing MLAG process state:%s to %s Client",
280 (msg_type
== ZEBRA_MLAG_PROCESS_UP
) ? "UP" : "DOWN",
281 (client
) ? "one" : "all");
284 s
= stream_new(ZEBRA_HEADER_SIZE
);
285 zclient_create_header(s
, msg_type
, VRF_DEFAULT
);
286 zserv_send_message(client
, s
);
292 * additional four bytes are for mesasge type
294 s
= stream_new(ZEBRA_HEADER_SIZE
+ ZEBRA_MLAG_METADATA_LEN
);
295 stream_putl(s
, ZEBRA_MLAG_MSG_BCAST
);
296 zclient_create_header(s
, msg_type
, VRF_DEFAULT
);
297 thread_add_event(zrouter
.master
, zebra_mlag_post_data_from_main_thread
,
301 /**************************End of Multi-entrant Apis**************************/
303 /***********************Zebra Main thread processing**************************/
306 * To avoid data corruption, messages will be post to clients only from
307 * main thread, because for that access was needed for clients list.
308 * so instead of forcing the locks, messages will be posted from main thread.
310 static int zebra_mlag_post_data_from_main_thread(struct thread
*thread
)
312 struct stream
*s
= THREAD_ARG(thread
);
313 struct stream
*zebra_s
= NULL
;
314 struct listnode
*node
;
315 struct zserv
*client
;
316 uint32_t msg_type
= 0;
317 uint32_t msg_len
= 0;
322 STREAM_GETL(s
, msg_type
);
323 if (IS_ZEBRA_DEBUG_MLAG
)
325 "%s: Posting MLAG data for msg_type:0x%x to interested cleints",
328 msg_len
= s
->endp
- ZEBRA_MLAG_METADATA_LEN
;
329 for (ALL_LIST_ELEMENTS_RO(zrouter
.client_list
, node
, client
)) {
330 if (client
->mlag_updates_interested
== true) {
331 if (msg_type
!= ZEBRA_MLAG_MSG_BCAST
332 && !CHECK_FLAG(client
->mlag_reg_mask1
,
337 if (IS_ZEBRA_DEBUG_MLAG
)
339 "%s: Posting MLAG data of length-%d to client:%d ",
340 __func__
, msg_len
, client
->proto
);
342 zebra_s
= stream_new(msg_len
);
343 STREAM_GET(zebra_s
->data
, s
, msg_len
);
344 zebra_s
->endp
= msg_len
;
345 stream_putw_at(zebra_s
, 0, msg_len
);
348 * This stream will be enqueued to client_obuf, it will
349 * be freed after posting to client socket.
351 zserv_send_message(client
, zebra_s
);
361 stream_free(zebra_s
);
366 * Start the MLAG Thread, this will be used to write client data on to
367 * MLAG Process and to read the data from MLAG and post to cleints.
368 * when all clients are un-registered, this Thread will be
371 static void zebra_mlag_spawn_pthread(void)
373 /* Start MLAG write pthread */
375 struct frr_pthread_attr pattr
= {.start
=
376 frr_pthread_attr_default
.start
,
377 .stop
= frr_pthread_attr_default
.stop
};
379 zrouter
.mlag_info
.zebra_pth_mlag
=
380 frr_pthread_new(&pattr
, "Zebra MLAG thread", "Zebra MLAG");
382 zrouter
.mlag_info
.th_master
= zrouter
.mlag_info
.zebra_pth_mlag
->master
;
385 /* Enqueue an initial event to the Newly spawn MLAG pthread */
386 zebra_mlag_signal_write_thread();
388 frr_pthread_run(zrouter
.mlag_info
.zebra_pth_mlag
, NULL
);
392 * all clients are un-registered for MLAG Updates, terminate the
395 static int zebra_mlag_terminate_pthread(struct thread
*event
)
397 if (IS_ZEBRA_DEBUG_MLAG
)
398 zlog_debug("Zebra MLAG write thread terminate called");
400 if (zrouter
.mlag_info
.clients_interested_cnt
) {
401 if (IS_ZEBRA_DEBUG_MLAG
)
403 "Zebra MLAG: still some clients are interested");
407 frr_pthread_stop(zrouter
.mlag_info
.zebra_pth_mlag
, NULL
);
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
;
417 * Send Notification to clean private data
419 hook_call(zebra_mlag_private_cleanup_data
);
424 * API to register zebra client for MLAG Updates
426 void zebra_mlag_client_register(ZAPI_HANDLER_ARGS
)
429 uint32_t reg_mask
= 0;
432 if (IS_ZEBRA_DEBUG_MLAG
)
433 zlog_debug("Received MLAG Registration from client-proto:%d",
437 /* Get input stream. */
441 STREAM_GETL(s
, reg_mask
);
443 if (client
->mlag_updates_interested
== true) {
445 if (IS_ZEBRA_DEBUG_MLAG
)
447 "Client is registered, existing mask: 0x%x, new mask: 0x%x",
448 client
->mlag_reg_mask1
, reg_mask
);
449 if (client
->mlag_reg_mask1
!= reg_mask
)
450 client
->mlag_reg_mask1
= reg_mask
;
452 * Client might missed MLAG-UP Notification, post-it again
454 zebra_mlag_publish_process_state(client
, ZEBRA_MLAG_PROCESS_UP
);
459 client
->mlag_updates_interested
= true;
460 client
->mlag_reg_mask1
= reg_mask
;
461 if (IS_ZEBRA_DEBUG_MLAG
)
462 zlog_debug("Registering for MLAG Updates with mask: 0x%x, ",
463 client
->mlag_reg_mask1
);
465 zrouter
.mlag_info
.clients_interested_cnt
++;
467 if (zrouter
.mlag_info
.clients_interested_cnt
== 1) {
469 * First-client for MLAG Updates,open the communication channel
472 if (IS_ZEBRA_DEBUG_MLAG
)
474 "First client, opening the channel with MLAG");
476 zebra_mlag_spawn_pthread();
477 rc
= hook_call(zebra_mlag_private_open_channel
);
480 * For some reason, zebra not able to open the
481 * comm-channel with MLAG, so post MLAG-DOWN to client.
482 * later when the channel is open, zebra will send
485 if (IS_ZEBRA_DEBUG_MLAG
)
487 "Fail to open channel with MLAG,rc:%d, post Proto-down",
489 zebra_mlag_publish_process_state(
490 client
, ZEBRA_MLAG_PROCESS_DOWN
);
494 if (IS_ZEBRA_DEBUG_MLAG
)
495 zlog_debug("Client Registered successfully for MLAG Updates");
497 if (zrouter
.mlag_info
.connected
== true)
498 zebra_mlag_publish_process_state(client
, ZEBRA_MLAG_PROCESS_UP
);
504 * API to un-register for MLAG Updates
506 void zebra_mlag_client_unregister(ZAPI_HANDLER_ARGS
)
508 if (IS_ZEBRA_DEBUG_MLAG
)
509 zlog_debug("Received MLAG De-Registration from client-proto:%d",
512 if (client
->mlag_updates_interested
== false)
516 client
->mlag_updates_interested
= false;
517 client
->mlag_reg_mask1
= 0;
518 zrouter
.mlag_info
.clients_interested_cnt
--;
520 if (zrouter
.mlag_info
.clients_interested_cnt
== 0) {
522 * No-client is interested for MLAG Updates,close the
523 * communication channel with MLAG
525 if (IS_ZEBRA_DEBUG_MLAG
)
526 zlog_debug("Last client for MLAG, close the channel ");
531 * 1) main thread calls socket close which posts De-register
532 * to MLAG write thread
533 * 2) after MLAG write thread posts De-register it sends a
534 * signal back to main thread to do the thread cleanup
535 * this was mainly to make sure De-register is posted to MCLAGD.
537 hook_call(zebra_mlag_private_close_channel
);
540 if (IS_ZEBRA_DEBUG_MLAG
)
542 "Client De-Registered successfully for MLAG Updates");
546 * Does following things.
547 * 1) allocated new local stream, and copies the client data and enqueue
549 * 2) MLAG Thread after dequeing, encode the client data using protobuf
550 * and write on to MLAG
552 void zebra_mlag_forward_client_msg(ZAPI_HANDLER_ARGS
)
554 struct stream
*zebra_s
;
555 struct stream
*mlag_s
;
557 if (IS_ZEBRA_DEBUG_MLAG
)
558 zlog_debug("Received Client MLAG Data from client-proto:%d",
561 /* Get input stream. */
563 mlag_s
= stream_new(zebra_s
->endp
);
566 * Client data is | Zebra Header + MLAG Data |
567 * we need to enqueue only the MLAG data, skipping Zebra Header
569 stream_put(mlag_s
, zebra_s
->data
+ zebra_s
->getp
,
570 STREAM_READABLE(zebra_s
));
571 stream_fifo_push_safe(zrouter
.mlag_info
.mlag_fifo
, mlag_s
);
572 zebra_mlag_signal_write_thread();
574 if (IS_ZEBRA_DEBUG_MLAG
)
575 zlog_debug("%s: Enqueued Client:%d data to MLAG Thread ",
576 __func__
, client
->proto
);
579 /***********************End of Zebra Main thread processing*************/
581 enum mlag_role
zebra_mlag_get_role(void)
583 return zrouter
.mlag_info
.role
;
586 int32_t zebra_mlag_test_mlag_internal(const char *none
, const char *primary
,
587 const char *secondary
)
589 enum mlag_role orig
= zrouter
.mlag_info
.role
;
590 char buf1
[MLAG_ROLE_STRSIZE
], buf2
[MLAG_ROLE_STRSIZE
];
593 zrouter
.mlag_info
.role
= MLAG_ROLE_NONE
;
595 zrouter
.mlag_info
.role
= MLAG_ROLE_PRIMARY
;
597 zrouter
.mlag_info
.role
= MLAG_ROLE_SECONDARY
;
599 if (IS_ZEBRA_DEBUG_MLAG
)
600 zlog_debug("Test: Changing role from %s to %s",
601 mlag_role2str(orig
, buf1
, sizeof(buf1
)),
602 mlag_role2str(orig
, buf2
, sizeof(buf2
)));
604 if (orig
!= zrouter
.mlag_info
.role
) {
605 zsend_capabilities_all_clients();
606 if (zrouter
.mlag_info
.role
!= MLAG_ROLE_NONE
) {
607 if (zrouter
.mlag_info
.clients_interested_cnt
== 0
608 && test_mlag_in_progress
== false) {
609 if (zrouter
.mlag_info
.zebra_pth_mlag
== NULL
)
610 zebra_mlag_spawn_pthread();
611 zrouter
.mlag_info
.clients_interested_cnt
++;
612 test_mlag_in_progress
= true;
613 hook_call(zebra_mlag_private_open_channel
);
616 if (test_mlag_in_progress
== true) {
617 test_mlag_in_progress
= false;
618 zrouter
.mlag_info
.clients_interested_cnt
--;
619 hook_call(zebra_mlag_private_close_channel
);
627 void zebra_mlag_init(void)
629 zebra_mlag_vty_init();
632 * Intialiaze the MLAG Global variables
633 * write thread will be created during actual registration with MCLAG
635 zrouter
.mlag_info
.clients_interested_cnt
= 0;
636 zrouter
.mlag_info
.connected
= false;
637 zrouter
.mlag_info
.timer_running
= false;
638 zrouter
.mlag_info
.mlag_fifo
= stream_fifo_new();
639 zrouter
.mlag_info
.zebra_pth_mlag
= NULL
;
640 zrouter
.mlag_info
.th_master
= NULL
;
641 zrouter
.mlag_info
.t_read
= NULL
;
642 zrouter
.mlag_info
.t_write
= NULL
;
643 test_mlag_in_progress
= false;
644 zebra_mlag_reset_read_buffer();
647 void zebra_mlag_terminate(void)
654 * ProtoBuf Encoding APIs
657 #ifdef HAVE_PROTOBUF_VERSION_3
659 DEFINE_MTYPE_STATIC(ZEBRA
, MLAG_PBUF
, "ZEBRA MLAG PROTOBUF")
661 int zebra_mlag_protobuf_encode_client_data(struct stream
*s
, uint32_t *msg_type
)
663 ZebraMlagHeader hdr
= ZEBRA_MLAG__HEADER__INIT
;
664 struct mlag_msg mlag_msg
;
665 uint8_t tmp_buf
[ZEBRA_MLAG_BUF_LIMIT
];
669 char buf
[ZLOG_FILTER_LENGTH_MAX
];
671 if (IS_ZEBRA_DEBUG_MLAG
)
672 zlog_debug("%s: Entering..", __func__
);
674 rc
= mlag_lib_decode_mlag_hdr(s
, &mlag_msg
);
678 if (IS_ZEBRA_DEBUG_MLAG
)
679 zlog_debug("%s: Mlag ProtoBuf encoding of message:%s, len:%d",
681 mlag_lib_msgid_to_str(mlag_msg
.msg_type
, buf
,
684 *msg_type
= mlag_msg
.msg_type
;
685 switch (mlag_msg
.msg_type
) {
686 case MLAG_MROUTE_ADD
: {
687 struct mlag_mroute_add msg
;
688 ZebraMlagMrouteAdd pay_load
= ZEBRA_MLAG_MROUTE_ADD__INIT
;
689 uint32_t vrf_name_len
= 0;
691 rc
= mlag_lib_decode_mroute_add(s
, &msg
);
694 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
695 pay_load
.vrf_name
= XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
696 strlcpy(pay_load
.vrf_name
, msg
.vrf_name
, vrf_name_len
);
697 pay_load
.source_ip
= msg
.source_ip
;
698 pay_load
.group_ip
= msg
.group_ip
;
699 pay_load
.cost_to_rp
= msg
.cost_to_rp
;
700 pay_load
.owner_id
= msg
.owner_id
;
701 pay_load
.am_i_dr
= msg
.am_i_dr
;
702 pay_load
.am_i_dual_active
= msg
.am_i_dual_active
;
703 pay_load
.vrf_id
= msg
.vrf_id
;
705 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
706 vrf_name_len
= strlen(msg
.intf_name
) + 1;
708 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
709 strlcpy(pay_load
.intf_name
, msg
.intf_name
,
713 len
= zebra_mlag_mroute_add__pack(&pay_load
, tmp_buf
);
714 XFREE(MTYPE_MLAG_PBUF
, pay_load
.vrf_name
);
715 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
)
716 XFREE(MTYPE_MLAG_PBUF
, pay_load
.intf_name
);
718 case MLAG_MROUTE_DEL
: {
719 struct mlag_mroute_del msg
;
720 ZebraMlagMrouteDel pay_load
= ZEBRA_MLAG_MROUTE_DEL__INIT
;
721 uint32_t vrf_name_len
= 0;
723 rc
= mlag_lib_decode_mroute_del(s
, &msg
);
726 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
727 pay_load
.vrf_name
= XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
728 strlcpy(pay_load
.vrf_name
, msg
.vrf_name
, vrf_name_len
);
729 pay_load
.source_ip
= msg
.source_ip
;
730 pay_load
.group_ip
= msg
.group_ip
;
731 pay_load
.owner_id
= msg
.owner_id
;
732 pay_load
.vrf_id
= msg
.vrf_id
;
734 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
735 vrf_name_len
= strlen(msg
.intf_name
) + 1;
737 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
738 strlcpy(pay_load
.intf_name
, msg
.intf_name
,
742 len
= zebra_mlag_mroute_del__pack(&pay_load
, tmp_buf
);
743 XFREE(MTYPE_MLAG_PBUF
, pay_load
.vrf_name
);
744 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
)
745 XFREE(MTYPE_MLAG_PBUF
, pay_load
.intf_name
);
747 case MLAG_MROUTE_ADD_BULK
: {
748 struct mlag_mroute_add msg
;
749 ZebraMlagMrouteAddBulk Bulk_msg
=
750 ZEBRA_MLAG_MROUTE_ADD_BULK__INIT
;
751 ZebraMlagMrouteAdd
**pay_load
= NULL
;
753 bool cleanup
= false;
755 Bulk_msg
.n_mroute_add
= mlag_msg
.msg_cnt
;
756 pay_load
= XMALLOC(MTYPE_MLAG_PBUF
, sizeof(ZebraMlagMrouteAdd
*)
759 for (i
= 0; i
< mlag_msg
.msg_cnt
; i
++) {
761 uint32_t vrf_name_len
= 0;
763 rc
= mlag_lib_decode_mroute_add(s
, &msg
);
768 pay_load
[i
] = XMALLOC(MTYPE_MLAG_PBUF
,
769 sizeof(ZebraMlagMrouteAdd
));
770 zebra_mlag_mroute_add__init(pay_load
[i
]);
772 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
773 pay_load
[i
]->vrf_name
=
774 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
775 strlcpy(pay_load
[i
]->vrf_name
, msg
.vrf_name
,
777 pay_load
[i
]->source_ip
= msg
.source_ip
;
778 pay_load
[i
]->group_ip
= msg
.group_ip
;
779 pay_load
[i
]->cost_to_rp
= msg
.cost_to_rp
;
780 pay_load
[i
]->owner_id
= msg
.owner_id
;
781 pay_load
[i
]->am_i_dr
= msg
.am_i_dr
;
782 pay_load
[i
]->am_i_dual_active
= msg
.am_i_dual_active
;
783 pay_load
[i
]->vrf_id
= msg
.vrf_id
;
784 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
785 vrf_name_len
= strlen(msg
.intf_name
) + 1;
786 pay_load
[i
]->intf_name
=
787 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
789 strlcpy(pay_load
[i
]->intf_name
, msg
.intf_name
,
793 if (cleanup
== false) {
794 Bulk_msg
.mroute_add
= pay_load
;
795 len
= zebra_mlag_mroute_add_bulk__pack(&Bulk_msg
,
799 for (i
= 0; i
< mlag_msg
.msg_cnt
; i
++) {
800 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->vrf_name
);
801 if (pay_load
[i
]->owner_id
== MLAG_OWNER_INTERFACE
802 && pay_load
[i
]->intf_name
)
803 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->intf_name
);
804 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]);
806 XFREE(MTYPE_MLAG_PBUF
, pay_load
);
810 case MLAG_MROUTE_DEL_BULK
: {
811 struct mlag_mroute_del msg
;
812 ZebraMlagMrouteDelBulk Bulk_msg
=
813 ZEBRA_MLAG_MROUTE_DEL_BULK__INIT
;
814 ZebraMlagMrouteDel
**pay_load
= NULL
;
816 bool cleanup
= false;
818 Bulk_msg
.n_mroute_del
= mlag_msg
.msg_cnt
;
819 pay_load
= XMALLOC(MTYPE_MLAG_PBUF
, sizeof(ZebraMlagMrouteDel
*)
822 for (i
= 0; i
< mlag_msg
.msg_cnt
; i
++) {
824 uint32_t vrf_name_len
= 0;
826 rc
= mlag_lib_decode_mroute_del(s
, &msg
);
832 pay_load
[i
] = XMALLOC(MTYPE_MLAG_PBUF
,
833 sizeof(ZebraMlagMrouteDel
));
834 zebra_mlag_mroute_del__init(pay_load
[i
]);
836 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
837 pay_load
[i
]->vrf_name
=
838 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
840 strlcpy(pay_load
[i
]->vrf_name
, msg
.vrf_name
,
842 pay_load
[i
]->source_ip
= msg
.source_ip
;
843 pay_load
[i
]->group_ip
= msg
.group_ip
;
844 pay_load
[i
]->owner_id
= msg
.owner_id
;
845 pay_load
[i
]->vrf_id
= msg
.vrf_id
;
846 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
847 vrf_name_len
= strlen(msg
.intf_name
) + 1;
848 pay_load
[i
]->intf_name
=
849 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
851 strlcpy(pay_load
[i
]->intf_name
, msg
.intf_name
,
856 Bulk_msg
.mroute_del
= pay_load
;
857 len
= zebra_mlag_mroute_del_bulk__pack(&Bulk_msg
,
861 for (i
= 0; i
< mlag_msg
.msg_cnt
; i
++) {
862 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->vrf_name
);
863 if (pay_load
[i
]->owner_id
== MLAG_OWNER_INTERFACE
864 && pay_load
[i
]->intf_name
)
865 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->intf_name
);
866 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]);
868 XFREE(MTYPE_MLAG_PBUF
, pay_load
);
876 if (IS_ZEBRA_DEBUG_MLAG
)
877 zlog_debug("%s: length of Mlag ProtoBuf encoded message:%s, %d",
879 mlag_lib_msgid_to_str(mlag_msg
.msg_type
, buf
,
882 hdr
.type
= (ZebraMlagHeader__MessageType
)mlag_msg
.msg_type
;
885 hdr
.data
.data
= XMALLOC(MTYPE_MLAG_PBUF
, len
);
886 memcpy(hdr
.data
.data
, tmp_buf
, len
);
890 * ProtoBuf Infra will not support to demarc the pointers whem multiple
891 * messages are posted inside a single Buffer.
892 * 2 -solutions exist to solve this
893 * 1. add Unenoced length at the beginning of every message, this will
894 * be used to point to next message in the buffer
895 * 2. another solution is defining all messages insides another message
896 * But this will permit only 32 messages. this can be extended with
898 * for simplicity we are going with solution-1.
900 len
= zebra_mlag__header__pack(&hdr
,
901 (mlag_wr_buffer
+ ZEBRA_MLAG_LEN_SIZE
));
903 memcpy(mlag_wr_buffer
, &n_len
, ZEBRA_MLAG_LEN_SIZE
);
904 len
+= ZEBRA_MLAG_LEN_SIZE
;
906 if (IS_ZEBRA_DEBUG_MLAG
)
908 "%s: length of Mlag ProtoBuf message:%s with Header %d",
910 mlag_lib_msgid_to_str(mlag_msg
.msg_type
, buf
,
913 XFREE(MTYPE_MLAG_PBUF
, hdr
.data
.data
);
918 int zebra_mlag_protobuf_decode_message(struct stream
*s
, uint8_t *data
,
922 ZebraMlagHeader
*hdr
;
925 hdr
= zebra_mlag__header__unpack(NULL
, len
, data
);
930 * ADD The MLAG Header
932 zclient_create_header(s
, ZEBRA_MLAG_FORWARD_MSG
, VRF_DEFAULT
);
934 msg_type
= hdr
->type
;
936 if (IS_ZEBRA_DEBUG_MLAG
)
937 zlog_debug("%s: Mlag ProtoBuf decoding of message:%s", __func__
,
938 mlag_lib_msgid_to_str(msg_type
, buf
, 80));
941 * Internal MLAG Message-types & MLAG.proto message types should
942 * always match, otherwise there can be decoding errors
943 * To avoid exposing clients with Protobuf flags, using internal
946 stream_putl(s
, hdr
->type
);
948 if (hdr
->data
.len
== 0) {
950 stream_putw(s
, MLAG_MSG_NULL_PAYLOAD
);
952 stream_putw(s
, MLAG_MSG_NO_BATCH
);
955 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_STATUS_UPDATE
: {
956 ZebraMlagStatusUpdate
*msg
= NULL
;
958 msg
= zebra_mlag_status_update__unpack(
959 NULL
, hdr
->data
.len
, hdr
->data
.data
);
961 zebra_mlag__header__free_unpacked(hdr
, NULL
);
965 stream_putw(s
, sizeof(struct mlag_status
));
967 stream_putw(s
, MLAG_MSG_NO_BATCH
);
969 stream_put(s
, msg
->peerlink
, INTERFACE_NAMSIZ
);
970 stream_putl(s
, msg
->my_role
);
971 stream_putl(s
, msg
->peer_state
);
972 zebra_mlag_status_update__free_unpacked(msg
, NULL
);
974 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_VXLAN_UPDATE
: {
975 ZebraMlagVxlanUpdate
*msg
= NULL
;
977 msg
= zebra_mlag_vxlan_update__unpack(
978 NULL
, hdr
->data
.len
, hdr
->data
.data
);
980 zebra_mlag__header__free_unpacked(hdr
, NULL
);
984 stream_putw(s
, sizeof(struct mlag_vxlan
));
986 stream_putw(s
, MLAG_MSG_NO_BATCH
);
988 stream_putl(s
, msg
->anycast_ip
);
989 stream_putl(s
, msg
->local_ip
);
990 zebra_mlag_vxlan_update__free_unpacked(msg
, NULL
);
992 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_ADD
: {
993 ZebraMlagMrouteAdd
*msg
= NULL
;
995 msg
= zebra_mlag_mroute_add__unpack(NULL
, hdr
->data
.len
,
998 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1002 stream_putw(s
, sizeof(struct mlag_mroute_add
));
1004 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1006 stream_put(s
, msg
->vrf_name
, VRF_NAMSIZ
);
1008 stream_putl(s
, msg
->source_ip
);
1009 stream_putl(s
, msg
->group_ip
);
1010 stream_putl(s
, msg
->cost_to_rp
);
1011 stream_putl(s
, msg
->owner_id
);
1012 stream_putc(s
, msg
->am_i_dr
);
1013 stream_putc(s
, msg
->am_i_dual_active
);
1014 stream_putl(s
, msg
->vrf_id
);
1015 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1016 stream_put(s
, msg
->intf_name
, INTERFACE_NAMSIZ
);
1018 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1019 zebra_mlag_mroute_add__free_unpacked(msg
, NULL
);
1021 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_DEL
: {
1022 ZebraMlagMrouteDel
*msg
= NULL
;
1024 msg
= zebra_mlag_mroute_del__unpack(NULL
, hdr
->data
.len
,
1027 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1031 stream_putw(s
, sizeof(struct mlag_mroute_del
));
1033 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1035 stream_put(s
, msg
->vrf_name
, VRF_NAMSIZ
);
1037 stream_putl(s
, msg
->source_ip
);
1038 stream_putl(s
, msg
->group_ip
);
1039 stream_putl(s
, msg
->group_ip
);
1040 stream_putl(s
, msg
->owner_id
);
1041 stream_putl(s
, msg
->vrf_id
);
1042 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1043 stream_put(s
, msg
->intf_name
, INTERFACE_NAMSIZ
);
1045 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1046 zebra_mlag_mroute_del__free_unpacked(msg
, NULL
);
1048 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_ADD_BULK
: {
1049 ZebraMlagMrouteAddBulk
*Bulk_msg
= NULL
;
1050 ZebraMlagMrouteAdd
*msg
= NULL
;
1053 Bulk_msg
= zebra_mlag_mroute_add_bulk__unpack(
1054 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1055 if (Bulk_msg
== NULL
) {
1056 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1060 stream_putw(s
, (Bulk_msg
->n_mroute_add
1061 * sizeof(struct mlag_mroute_add
)));
1062 /* No. of msgs in Batch */
1063 stream_putw(s
, Bulk_msg
->n_mroute_add
);
1066 for (i
= 0; i
< Bulk_msg
->n_mroute_add
; i
++) {
1068 msg
= Bulk_msg
->mroute_add
[i
];
1070 stream_put(s
, msg
->vrf_name
, VRF_NAMSIZ
);
1071 stream_putl(s
, msg
->source_ip
);
1072 stream_putl(s
, msg
->group_ip
);
1073 stream_putl(s
, msg
->cost_to_rp
);
1074 stream_putl(s
, msg
->owner_id
);
1075 stream_putc(s
, msg
->am_i_dr
);
1076 stream_putc(s
, msg
->am_i_dual_active
);
1077 stream_putl(s
, msg
->vrf_id
);
1078 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1079 stream_put(s
, msg
->intf_name
,
1082 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1084 zebra_mlag_mroute_add_bulk__free_unpacked(Bulk_msg
,
1087 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_DEL_BULK
: {
1088 ZebraMlagMrouteDelBulk
*Bulk_msg
= NULL
;
1089 ZebraMlagMrouteDel
*msg
= NULL
;
1092 Bulk_msg
= zebra_mlag_mroute_del_bulk__unpack(
1093 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1094 if (Bulk_msg
== NULL
) {
1095 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1099 stream_putw(s
, (Bulk_msg
->n_mroute_del
1100 * sizeof(struct mlag_mroute_del
)));
1101 /* No. of msgs in Batch */
1102 stream_putw(s
, Bulk_msg
->n_mroute_del
);
1105 for (i
= 0; i
< Bulk_msg
->n_mroute_del
; i
++) {
1107 msg
= Bulk_msg
->mroute_del
[i
];
1109 stream_put(s
, msg
->vrf_name
, VRF_NAMSIZ
);
1110 stream_putl(s
, msg
->source_ip
);
1111 stream_putl(s
, msg
->group_ip
);
1112 stream_putl(s
, msg
->owner_id
);
1113 stream_putl(s
, msg
->vrf_id
);
1114 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1115 stream_put(s
, msg
->intf_name
,
1118 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1120 zebra_mlag_mroute_del_bulk__free_unpacked(Bulk_msg
,
1123 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_ZEBRA_STATUS_UPDATE
: {
1124 ZebraMlagZebraStatusUpdate
*msg
= NULL
;
1126 msg
= zebra_mlag_zebra_status_update__unpack(
1127 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1129 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1133 stream_putw(s
, sizeof(struct mlag_frr_status
));
1135 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1137 stream_putl(s
, msg
->peer_frrstate
);
1138 zebra_mlag_zebra_status_update__free_unpacked(msg
,
1145 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1150 int zebra_mlag_protobuf_encode_client_data(struct stream
*s
, uint32_t *msg_type
)
1155 int zebra_mlag_protobuf_decode_message(struct stream
*s
, uint8_t *data
,