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 #ifdef HAVE_PROTOBUF_VERSION_3
37 #include "mlag/mlag.pb-c.h"
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
, (), ())
47 #define ZEBRA_MLAG_METADATA_LEN 4
48 #define ZEBRA_MLAG_MSG_BCAST 0xFFFFFFFF
50 uint8_t mlag_wr_buffer
[ZEBRA_MLAG_BUF_LIMIT
];
51 uint8_t mlag_rd_buffer
[ZEBRA_MLAG_BUF_LIMIT
];
53 static bool test_mlag_in_progress
;
55 static int zebra_mlag_signal_write_thread(void);
56 static int zebra_mlag_terminate_pthread(struct thread
*event
);
57 static int zebra_mlag_post_data_from_main_thread(struct thread
*thread
);
58 static void zebra_mlag_publish_process_state(struct zserv
*client
,
59 zebra_message_types_t msg_type
);
61 /**********************MLAG Interaction***************************************/
64 * API to post the Registration to MLAGD
65 * MLAG will not process any messages with out the registration
67 void zebra_mlag_send_register(void)
69 struct stream
*s
= NULL
;
71 s
= stream_new(sizeof(struct mlag_msg
));
73 stream_putl(s
, MLAG_REGISTER
);
74 stream_putw(s
, MLAG_MSG_NULL_PAYLOAD
);
75 stream_putw(s
, MLAG_MSG_NO_BATCH
);
76 stream_fifo_push_safe(zrouter
.mlag_info
.mlag_fifo
, s
);
77 zebra_mlag_signal_write_thread();
79 if (IS_ZEBRA_DEBUG_MLAG
)
80 zlog_debug("%s: Enqueued MLAG Register to MLAG Thread ",
85 * API to post the De-Registration to MLAGD
86 * MLAG will not process any messages after the de-registration
88 void zebra_mlag_send_deregister(void)
90 struct stream
*s
= NULL
;
92 s
= stream_new(sizeof(struct mlag_msg
));
94 stream_putl(s
, MLAG_DEREGISTER
);
95 stream_putw(s
, MLAG_MSG_NULL_PAYLOAD
);
96 stream_putw(s
, MLAG_MSG_NO_BATCH
);
97 stream_fifo_push_safe(zrouter
.mlag_info
.mlag_fifo
, s
);
98 zebra_mlag_signal_write_thread();
100 if (IS_ZEBRA_DEBUG_MLAG
)
101 zlog_debug("%s: Enqueued MLAG De-Register to MLAG Thread ",
106 * API To handle MLAG Received data
107 * Decodes the data using protobuf and enqueue to main thread
108 * main thread publish this to clients based on client subscription
110 void zebra_mlag_process_mlag_data(uint8_t *data
, uint32_t len
)
112 struct stream
*s
= NULL
;
115 s
= stream_new(ZEBRA_MAX_PACKET_SIZ
);
117 * Place holder we need the message type first
119 stream_putl(s
, msg_type
);
120 msg_type
= zebra_mlag_protobuf_decode_message(s
, data
, len
);
123 /* Something went wrong in decoding */
125 zlog_err("%s: failed to process mlag data-%d, %u", __func__
,
131 * additional four bytes are for message type
133 stream_putl_at(s
, 0, msg_type
);
134 thread_add_event(zrouter
.master
, zebra_mlag_post_data_from_main_thread
,
138 /**********************End of MLAG Interaction********************************/
140 /************************MLAG Thread Processing*******************************/
143 * after posting every 'ZEBRA_MLAG_POST_LIMIT' packets, MLAG Thread will be
144 * yielded to give CPU for other threads
146 #define ZEBRA_MLAG_POST_LIMIT 100
149 * This thread reads the clients data from the Global queue and encodes with
150 * protobuf and pass on to the MLAG socket.
152 static int zebra_mlag_client_msg_handler(struct thread
*event
)
155 uint32_t wr_count
= 0;
156 uint32_t msg_type
= 0;
157 uint32_t max_count
= 0;
160 wr_count
= stream_fifo_count_safe(zrouter
.mlag_info
.mlag_fifo
);
161 if (IS_ZEBRA_DEBUG_MLAG
)
162 zlog_debug(":%s: Processing MLAG write, %u messages in queue",
165 max_count
= MIN(wr_count
, ZEBRA_MLAG_POST_LIMIT
);
167 for (wr_count
= 0; wr_count
< max_count
; wr_count
++) {
168 s
= stream_fifo_pop_safe(zrouter
.mlag_info
.mlag_fifo
);
170 zlog_debug(":%s: Got a NULL Messages, some thing wrong",
176 * Encode the data now
178 len
= zebra_mlag_protobuf_encode_client_data(s
, &msg_type
);
184 hook_call(zebra_mlag_private_write_data
,
185 mlag_wr_buffer
, len
);
188 * If message type is De-register, send a signal to main
189 * thread, so that necessary cleanup will be done by
192 if (msg_type
== MLAG_DEREGISTER
) {
193 thread_add_event(zrouter
.master
,
194 zebra_mlag_terminate_pthread
,
202 if (IS_ZEBRA_DEBUG_MLAG
)
203 zlog_debug(":%s: Posted %d messages to MLAGD", __func__
,
206 * Currently there is only message write task is enqueued to this
207 * thread, yielding was added for future purpose, so that this thread
208 * can server other tasks also and in case FIFO is empty, this task will
209 * be schedule when main thread adds some messages
211 if (wr_count
>= ZEBRA_MLAG_POST_LIMIT
)
212 zebra_mlag_signal_write_thread();
217 * API to handle the process state.
218 * In case of Down, Zebra keep monitoring the MLAG state.
219 * all the state Notifications will be published to clients
221 void zebra_mlag_handle_process_state(enum zebra_mlag_state state
)
223 if (state
== MLAG_UP
) {
224 zrouter
.mlag_info
.connected
= true;
225 zebra_mlag_publish_process_state(NULL
, ZEBRA_MLAG_PROCESS_UP
);
226 zebra_mlag_send_register();
227 } else if (state
== MLAG_DOWN
) {
228 zrouter
.mlag_info
.connected
= false;
229 zebra_mlag_publish_process_state(NULL
, ZEBRA_MLAG_PROCESS_DOWN
);
230 hook_call(zebra_mlag_private_monitor_state
);
234 /***********************End of MLAG Thread processing*************************/
236 /*************************Multi-entratnt Api's********************************/
239 * Provider api to signal that work/events are available
240 * for the Zebra MLAG Write pthread.
241 * This API is called from 2 pthreads..
242 * 1) by main thread when client posts a MLAG Message
243 * 2) by MLAG Thread, in case of yield
244 * though this api, is called from two threads we don't need any locking
245 * because Thread task enqueue is thread safe means internally it had
246 * necessary protection
248 static int zebra_mlag_signal_write_thread(void)
250 if (IS_ZEBRA_DEBUG_MLAG
)
251 zlog_debug(":%s: Scheduling MLAG write", __func__
);
253 * This api will be called from Both main & MLAG Threads.
254 * main thread writes, "zrouter.mlag_info.th_master" only
255 * during Zebra Init/after MLAG thread is destroyed.
256 * so it is safe to use without any locking
258 thread_add_event(zrouter
.mlag_info
.th_master
,
259 zebra_mlag_client_msg_handler
, NULL
, 0,
260 &zrouter
.mlag_info
.t_write
);
265 * API will be used to publish the MLAG state to interested clients
266 * In case client is passed, state is posted only for that client,
267 * otherwise to all interested clients
268 * this api can be called from two threads.
269 * 1) from main thread: when client is passed
270 * 2) from MLAG Thread: when client is NULL
272 * In second case, to avoid global data access data will be post to Main
273 * thread, so that actual posting to clients will happen from Main thread.
275 static void zebra_mlag_publish_process_state(struct zserv
*client
,
276 zebra_message_types_t msg_type
)
280 if (IS_ZEBRA_DEBUG_MLAG
)
281 zlog_debug("%s: Publishing MLAG process state:%s to %s Client",
283 (msg_type
== ZEBRA_MLAG_PROCESS_UP
) ? "UP" : "DOWN",
284 (client
) ? "one" : "all");
287 s
= stream_new(ZEBRA_HEADER_SIZE
);
288 zclient_create_header(s
, msg_type
, VRF_DEFAULT
);
289 zserv_send_message(client
, s
);
295 * additional four bytes are for mesasge type
297 s
= stream_new(ZEBRA_HEADER_SIZE
+ ZEBRA_MLAG_METADATA_LEN
);
298 stream_putl(s
, ZEBRA_MLAG_MSG_BCAST
);
299 zclient_create_header(s
, msg_type
, VRF_DEFAULT
);
300 thread_add_event(zrouter
.master
, zebra_mlag_post_data_from_main_thread
,
304 /**************************End of Multi-entrant Apis**************************/
306 /***********************Zebra Main thread processing**************************/
309 * To avoid data corruption, messages will be post to clients only from
310 * main thread, because for that access was needed for clients list.
311 * so instead of forcing the locks, messages will be posted from main thread.
313 static int zebra_mlag_post_data_from_main_thread(struct thread
*thread
)
315 struct stream
*s
= THREAD_ARG(thread
);
316 struct stream
*zebra_s
= NULL
;
317 struct listnode
*node
;
318 struct zserv
*client
;
319 uint32_t msg_type
= 0;
320 uint32_t msg_len
= 0;
325 STREAM_GETL(s
, msg_type
);
326 if (IS_ZEBRA_DEBUG_MLAG
)
328 "%s: Posting MLAG data for msg_type:0x%x to interested clients",
331 msg_len
= s
->endp
- ZEBRA_MLAG_METADATA_LEN
;
332 for (ALL_LIST_ELEMENTS_RO(zrouter
.client_list
, node
, client
)) {
333 if (client
->mlag_updates_interested
== true) {
334 if (msg_type
!= ZEBRA_MLAG_MSG_BCAST
335 && !CHECK_FLAG(client
->mlag_reg_mask1
,
340 if (IS_ZEBRA_DEBUG_MLAG
)
342 "%s: Posting MLAG data of length-%d to client:%d ",
343 __func__
, msg_len
, client
->proto
);
345 zebra_s
= stream_new(msg_len
);
346 STREAM_GET(zebra_s
->data
, s
, msg_len
);
347 zebra_s
->endp
= msg_len
;
348 stream_putw_at(zebra_s
, 0, msg_len
);
351 * This stream will be enqueued to client_obuf, it will
352 * be freed after posting to client socket.
354 zserv_send_message(client
, zebra_s
);
364 stream_free(zebra_s
);
369 * Start the MLAG Thread, this will be used to write client data on to
370 * MLAG Process and to read the data from MLAG and post to clients.
371 * when all clients are un-registered, this Thread will be
374 static void zebra_mlag_spawn_pthread(void)
376 /* Start MLAG write pthread */
378 struct frr_pthread_attr pattr
= {.start
=
379 frr_pthread_attr_default
.start
,
380 .stop
= frr_pthread_attr_default
.stop
};
382 zrouter
.mlag_info
.zebra_pth_mlag
=
383 frr_pthread_new(&pattr
, "Zebra MLAG thread", "Zebra MLAG");
385 zrouter
.mlag_info
.th_master
= zrouter
.mlag_info
.zebra_pth_mlag
->master
;
388 /* Enqueue an initial event to the Newly spawn MLAG pthread */
389 zebra_mlag_signal_write_thread();
391 frr_pthread_run(zrouter
.mlag_info
.zebra_pth_mlag
, NULL
);
395 * all clients are un-registered for MLAG Updates, terminate the
398 static int zebra_mlag_terminate_pthread(struct thread
*event
)
400 if (IS_ZEBRA_DEBUG_MLAG
)
401 zlog_debug("Zebra MLAG write thread terminate called");
403 if (zrouter
.mlag_info
.clients_interested_cnt
) {
404 if (IS_ZEBRA_DEBUG_MLAG
)
406 "Zebra MLAG: still some clients are interested");
410 frr_pthread_stop(zrouter
.mlag_info
.zebra_pth_mlag
, NULL
);
412 /* Destroy pthread */
413 frr_pthread_destroy(zrouter
.mlag_info
.zebra_pth_mlag
);
414 zrouter
.mlag_info
.zebra_pth_mlag
= NULL
;
415 zrouter
.mlag_info
.th_master
= NULL
;
416 zrouter
.mlag_info
.t_read
= NULL
;
417 zrouter
.mlag_info
.t_write
= NULL
;
420 * Send Notification to clean private data
422 hook_call(zebra_mlag_private_cleanup_data
);
427 * API to register zebra client for MLAG Updates
429 void zebra_mlag_client_register(ZAPI_HANDLER_ARGS
)
432 uint32_t reg_mask
= 0;
435 if (IS_ZEBRA_DEBUG_MLAG
)
436 zlog_debug("Received MLAG Registration from client-proto:%d",
440 /* Get input stream. */
444 STREAM_GETL(s
, reg_mask
);
446 if (client
->mlag_updates_interested
== true) {
448 if (IS_ZEBRA_DEBUG_MLAG
)
450 "Client is registered, existing mask: 0x%x, new mask: 0x%x",
451 client
->mlag_reg_mask1
, reg_mask
);
452 if (client
->mlag_reg_mask1
!= reg_mask
)
453 client
->mlag_reg_mask1
= reg_mask
;
455 * Client might missed MLAG-UP Notification, post-it again
457 zebra_mlag_publish_process_state(client
, ZEBRA_MLAG_PROCESS_UP
);
462 client
->mlag_updates_interested
= true;
463 client
->mlag_reg_mask1
= reg_mask
;
464 if (IS_ZEBRA_DEBUG_MLAG
)
465 zlog_debug("Registering for MLAG Updates with mask: 0x%x, ",
466 client
->mlag_reg_mask1
);
468 zrouter
.mlag_info
.clients_interested_cnt
++;
470 if (zrouter
.mlag_info
.clients_interested_cnt
== 1) {
472 * First-client for MLAG Updates,open the communication channel
475 if (IS_ZEBRA_DEBUG_MLAG
)
477 "First client, opening the channel with MLAG");
479 zebra_mlag_spawn_pthread();
480 rc
= hook_call(zebra_mlag_private_open_channel
);
483 * For some reason, zebra not able to open the
484 * comm-channel with MLAG, so post MLAG-DOWN to client.
485 * later when the channel is open, zebra will send
488 if (IS_ZEBRA_DEBUG_MLAG
)
490 "Fail to open channel with MLAG,rc:%d, post Proto-down",
492 zebra_mlag_publish_process_state(
493 client
, ZEBRA_MLAG_PROCESS_DOWN
);
497 if (IS_ZEBRA_DEBUG_MLAG
)
498 zlog_debug("Client Registered successfully for MLAG Updates");
500 if (zrouter
.mlag_info
.connected
== true)
501 zebra_mlag_publish_process_state(client
, ZEBRA_MLAG_PROCESS_UP
);
507 * API to un-register for MLAG Updates
509 void zebra_mlag_client_unregister(ZAPI_HANDLER_ARGS
)
511 if (IS_ZEBRA_DEBUG_MLAG
)
512 zlog_debug("Received MLAG De-Registration from client-proto:%d",
515 if (client
->mlag_updates_interested
== false)
519 client
->mlag_updates_interested
= false;
520 client
->mlag_reg_mask1
= 0;
521 zrouter
.mlag_info
.clients_interested_cnt
--;
523 if (zrouter
.mlag_info
.clients_interested_cnt
== 0) {
525 * No-client is interested for MLAG Updates,close the
526 * communication channel with MLAG
528 if (IS_ZEBRA_DEBUG_MLAG
)
529 zlog_debug("Last client for MLAG, close the channel ");
534 * 1) main thread calls socket close which posts De-register
535 * to MLAG write thread
536 * 2) after MLAG write thread posts De-register it sends a
537 * signal back to main thread to do the thread cleanup
538 * this was mainly to make sure De-register is posted to MCLAGD.
540 hook_call(zebra_mlag_private_close_channel
);
543 if (IS_ZEBRA_DEBUG_MLAG
)
545 "Client De-Registered successfully for MLAG Updates");
549 * Does following things.
550 * 1) allocated new local stream, and copies the client data and enqueue
552 * 2) MLAG Thread after dequeing, encode the client data using protobuf
553 * and write on to MLAG
555 void zebra_mlag_forward_client_msg(ZAPI_HANDLER_ARGS
)
557 struct stream
*zebra_s
;
558 struct stream
*mlag_s
;
560 if (IS_ZEBRA_DEBUG_MLAG
)
561 zlog_debug("Received Client MLAG Data from client-proto:%d",
564 /* Get input stream. */
566 mlag_s
= stream_new(zebra_s
->endp
);
569 * Client data is | Zebra Header + MLAG Data |
570 * we need to enqueue only the MLAG data, skipping Zebra Header
572 stream_put(mlag_s
, zebra_s
->data
+ zebra_s
->getp
,
573 STREAM_READABLE(zebra_s
));
574 stream_fifo_push_safe(zrouter
.mlag_info
.mlag_fifo
, mlag_s
);
575 zebra_mlag_signal_write_thread();
577 if (IS_ZEBRA_DEBUG_MLAG
)
578 zlog_debug("%s: Enqueued Client:%d data to MLAG Thread ",
579 __func__
, client
->proto
);
582 /***********************End of Zebra Main thread processing*************/
584 enum mlag_role
zebra_mlag_get_role(void)
586 return zrouter
.mlag_info
.role
;
589 int32_t zebra_mlag_test_mlag_internal(const char *none
, const char *primary
,
590 const char *secondary
)
592 enum mlag_role orig
= zrouter
.mlag_info
.role
;
593 char buf1
[MLAG_ROLE_STRSIZE
], buf2
[MLAG_ROLE_STRSIZE
];
596 zrouter
.mlag_info
.role
= MLAG_ROLE_NONE
;
598 zrouter
.mlag_info
.role
= MLAG_ROLE_PRIMARY
;
600 zrouter
.mlag_info
.role
= MLAG_ROLE_SECONDARY
;
602 if (IS_ZEBRA_DEBUG_MLAG
)
603 zlog_debug("Test: Changing role from %s to %s",
604 mlag_role2str(orig
, buf1
, sizeof(buf1
)),
605 mlag_role2str(orig
, buf2
, sizeof(buf2
)));
607 if (orig
!= zrouter
.mlag_info
.role
) {
608 zsend_capabilities_all_clients();
609 if (zrouter
.mlag_info
.role
!= MLAG_ROLE_NONE
) {
610 if (zrouter
.mlag_info
.clients_interested_cnt
== 0
611 && !test_mlag_in_progress
) {
612 if (zrouter
.mlag_info
.zebra_pth_mlag
== NULL
)
613 zebra_mlag_spawn_pthread();
614 zrouter
.mlag_info
.clients_interested_cnt
++;
615 test_mlag_in_progress
= true;
616 hook_call(zebra_mlag_private_open_channel
);
619 if (test_mlag_in_progress
) {
620 test_mlag_in_progress
= false;
621 zrouter
.mlag_info
.clients_interested_cnt
--;
622 hook_call(zebra_mlag_private_close_channel
);
630 void zebra_mlag_init(void)
632 zebra_mlag_vty_init();
635 * Intialiaze the MLAG Global variables
636 * write thread will be created during actual registration with MCLAG
638 zrouter
.mlag_info
.clients_interested_cnt
= 0;
639 zrouter
.mlag_info
.connected
= false;
640 zrouter
.mlag_info
.timer_running
= false;
641 zrouter
.mlag_info
.mlag_fifo
= stream_fifo_new();
642 zrouter
.mlag_info
.zebra_pth_mlag
= NULL
;
643 zrouter
.mlag_info
.th_master
= NULL
;
644 zrouter
.mlag_info
.t_read
= NULL
;
645 zrouter
.mlag_info
.t_write
= NULL
;
646 test_mlag_in_progress
= false;
647 zebra_mlag_reset_read_buffer();
650 void zebra_mlag_terminate(void)
657 * ProtoBuf Encoding APIs
660 #ifdef HAVE_PROTOBUF_VERSION_3
662 DEFINE_MTYPE_STATIC(ZEBRA
, MLAG_PBUF
, "ZEBRA MLAG PROTOBUF")
664 int zebra_mlag_protobuf_encode_client_data(struct stream
*s
, uint32_t *msg_type
)
666 ZebraMlagHeader hdr
= ZEBRA_MLAG__HEADER__INIT
;
667 struct mlag_msg mlag_msg
;
668 uint8_t tmp_buf
[ZEBRA_MLAG_BUF_LIMIT
];
672 char buf
[ZLOG_FILTER_LENGTH_MAX
];
675 if (IS_ZEBRA_DEBUG_MLAG
)
676 zlog_debug("%s: Entering..", __func__
);
678 rc
= mlag_lib_decode_mlag_hdr(s
, &mlag_msg
, &length
);
682 memset(tmp_buf
, 0, ZEBRA_MLAG_BUF_LIMIT
);
684 if (IS_ZEBRA_DEBUG_MLAG
)
685 zlog_debug("%s: Mlag ProtoBuf encoding of message:%s, len:%d",
687 mlag_lib_msgid_to_str(mlag_msg
.msg_type
, buf
,
690 *msg_type
= mlag_msg
.msg_type
;
691 switch (mlag_msg
.msg_type
) {
692 case MLAG_MROUTE_ADD
: {
693 struct mlag_mroute_add msg
;
694 ZebraMlagMrouteAdd pay_load
= ZEBRA_MLAG_MROUTE_ADD__INIT
;
695 uint32_t vrf_name_len
= 0;
697 rc
= mlag_lib_decode_mroute_add(s
, &msg
, &length
);
701 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
702 pay_load
.vrf_name
= XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
703 strlcpy(pay_load
.vrf_name
, msg
.vrf_name
, vrf_name_len
);
704 pay_load
.source_ip
= msg
.source_ip
;
705 pay_load
.group_ip
= msg
.group_ip
;
706 pay_load
.cost_to_rp
= msg
.cost_to_rp
;
707 pay_load
.owner_id
= msg
.owner_id
;
708 pay_load
.am_i_dr
= msg
.am_i_dr
;
709 pay_load
.am_i_dual_active
= msg
.am_i_dual_active
;
710 pay_load
.vrf_id
= msg
.vrf_id
;
712 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
713 vrf_name_len
= strlen(msg
.intf_name
) + 1;
715 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
716 strlcpy(pay_load
.intf_name
, msg
.intf_name
,
720 len
= zebra_mlag_mroute_add__pack(&pay_load
, tmp_buf
);
721 XFREE(MTYPE_MLAG_PBUF
, pay_load
.vrf_name
);
722 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
)
723 XFREE(MTYPE_MLAG_PBUF
, pay_load
.intf_name
);
725 case MLAG_MROUTE_DEL
: {
726 struct mlag_mroute_del msg
;
727 ZebraMlagMrouteDel pay_load
= ZEBRA_MLAG_MROUTE_DEL__INIT
;
728 uint32_t vrf_name_len
= 0;
730 rc
= mlag_lib_decode_mroute_del(s
, &msg
, &length
);
733 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
734 pay_load
.vrf_name
= XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
735 strlcpy(pay_load
.vrf_name
, msg
.vrf_name
, vrf_name_len
);
736 pay_load
.source_ip
= msg
.source_ip
;
737 pay_load
.group_ip
= msg
.group_ip
;
738 pay_load
.owner_id
= msg
.owner_id
;
739 pay_load
.vrf_id
= msg
.vrf_id
;
741 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
742 vrf_name_len
= strlen(msg
.intf_name
) + 1;
744 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
745 strlcpy(pay_load
.intf_name
, msg
.intf_name
,
749 len
= zebra_mlag_mroute_del__pack(&pay_load
, tmp_buf
);
750 XFREE(MTYPE_MLAG_PBUF
, pay_load
.vrf_name
);
751 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
)
752 XFREE(MTYPE_MLAG_PBUF
, pay_load
.intf_name
);
754 case MLAG_MROUTE_ADD_BULK
: {
755 struct mlag_mroute_add msg
;
756 ZebraMlagMrouteAddBulk Bulk_msg
=
757 ZEBRA_MLAG_MROUTE_ADD_BULK__INIT
;
758 ZebraMlagMrouteAdd
**pay_load
= NULL
;
759 bool cleanup
= false;
762 Bulk_msg
.n_mroute_add
= mlag_msg
.msg_cnt
;
763 pay_load
= XMALLOC(MTYPE_MLAG_PBUF
, sizeof(ZebraMlagMrouteAdd
*)
766 for (i
= 0, actual
= 0; i
< mlag_msg
.msg_cnt
; i
++, actual
++) {
768 uint32_t vrf_name_len
= 0;
770 rc
= mlag_lib_decode_mroute_add(s
, &msg
, &length
);
775 pay_load
[i
] = XMALLOC(MTYPE_MLAG_PBUF
,
776 sizeof(ZebraMlagMrouteAdd
));
777 zebra_mlag_mroute_add__init(pay_load
[i
]);
779 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
780 pay_load
[i
]->vrf_name
=
781 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
782 strlcpy(pay_load
[i
]->vrf_name
, msg
.vrf_name
,
784 pay_load
[i
]->source_ip
= msg
.source_ip
;
785 pay_load
[i
]->group_ip
= msg
.group_ip
;
786 pay_load
[i
]->cost_to_rp
= msg
.cost_to_rp
;
787 pay_load
[i
]->owner_id
= msg
.owner_id
;
788 pay_load
[i
]->am_i_dr
= msg
.am_i_dr
;
789 pay_load
[i
]->am_i_dual_active
= msg
.am_i_dual_active
;
790 pay_load
[i
]->vrf_id
= msg
.vrf_id
;
791 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
792 vrf_name_len
= strlen(msg
.intf_name
) + 1;
793 pay_load
[i
]->intf_name
=
794 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
796 strlcpy(pay_load
[i
]->intf_name
, msg
.intf_name
,
801 Bulk_msg
.mroute_add
= pay_load
;
802 len
= zebra_mlag_mroute_add_bulk__pack(&Bulk_msg
,
806 for (i
= 0; i
< actual
; i
++) {
808 * The mlag_lib_decode_mroute_add can
809 * fail to properly decode and cause nothing
810 * to be allocated. Prevent a crash
815 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->vrf_name
);
816 if (pay_load
[i
]->owner_id
== MLAG_OWNER_INTERFACE
817 && pay_load
[i
]->intf_name
)
818 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->intf_name
);
819 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]);
821 XFREE(MTYPE_MLAG_PBUF
, pay_load
);
825 case MLAG_MROUTE_DEL_BULK
: {
826 struct mlag_mroute_del msg
;
827 ZebraMlagMrouteDelBulk Bulk_msg
=
828 ZEBRA_MLAG_MROUTE_DEL_BULK__INIT
;
829 ZebraMlagMrouteDel
**pay_load
= NULL
;
830 bool cleanup
= false;
833 Bulk_msg
.n_mroute_del
= mlag_msg
.msg_cnt
;
834 pay_load
= XMALLOC(MTYPE_MLAG_PBUF
, sizeof(ZebraMlagMrouteDel
*)
837 for (i
= 0, actual
= 0; i
< mlag_msg
.msg_cnt
; i
++, actual
++) {
839 uint32_t vrf_name_len
= 0;
841 rc
= mlag_lib_decode_mroute_del(s
, &msg
, &length
);
847 pay_load
[i
] = XMALLOC(MTYPE_MLAG_PBUF
,
848 sizeof(ZebraMlagMrouteDel
));
849 zebra_mlag_mroute_del__init(pay_load
[i
]);
851 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
852 pay_load
[i
]->vrf_name
=
853 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
855 strlcpy(pay_load
[i
]->vrf_name
, msg
.vrf_name
,
857 pay_load
[i
]->source_ip
= msg
.source_ip
;
858 pay_load
[i
]->group_ip
= msg
.group_ip
;
859 pay_load
[i
]->owner_id
= msg
.owner_id
;
860 pay_load
[i
]->vrf_id
= msg
.vrf_id
;
861 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
862 vrf_name_len
= strlen(msg
.intf_name
) + 1;
863 pay_load
[i
]->intf_name
=
864 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
866 strlcpy(pay_load
[i
]->intf_name
, msg
.intf_name
,
871 Bulk_msg
.mroute_del
= pay_load
;
872 len
= zebra_mlag_mroute_del_bulk__pack(&Bulk_msg
,
876 for (i
= 0; i
< actual
; i
++) {
878 * The mlag_lib_decode_mroute_add can
879 * fail to properly decode and cause nothing
880 * to be allocated. Prevent a crash
885 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->vrf_name
);
886 if (pay_load
[i
]->owner_id
== MLAG_OWNER_INTERFACE
887 && pay_load
[i
]->intf_name
)
888 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->intf_name
);
889 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]);
891 XFREE(MTYPE_MLAG_PBUF
, pay_load
);
899 if (IS_ZEBRA_DEBUG_MLAG
)
900 zlog_debug("%s: length of Mlag ProtoBuf encoded message:%s, %d",
902 mlag_lib_msgid_to_str(mlag_msg
.msg_type
, buf
,
905 hdr
.type
= (ZebraMlagHeader__MessageType
)mlag_msg
.msg_type
;
908 hdr
.data
.data
= XMALLOC(MTYPE_MLAG_PBUF
, len
);
909 memcpy(hdr
.data
.data
, tmp_buf
, len
);
913 * ProtoBuf Infra will not support to demarc the pointers whem multiple
914 * messages are posted inside a single Buffer.
915 * 2 -solutions exist to solve this
916 * 1. add Unenoced length at the beginning of every message, this will
917 * be used to point to next message in the buffer
918 * 2. another solution is defining all messages insides another message
919 * But this will permit only 32 messages. this can be extended with
921 * for simplicity we are going with solution-1.
923 len
= zebra_mlag__header__pack(&hdr
,
924 (mlag_wr_buffer
+ ZEBRA_MLAG_LEN_SIZE
));
926 memcpy(mlag_wr_buffer
, &n_len
, ZEBRA_MLAG_LEN_SIZE
);
927 len
+= ZEBRA_MLAG_LEN_SIZE
;
929 if (IS_ZEBRA_DEBUG_MLAG
)
931 "%s: length of Mlag ProtoBuf message:%s with Header %d",
933 mlag_lib_msgid_to_str(mlag_msg
.msg_type
, buf
,
936 XFREE(MTYPE_MLAG_PBUF
, hdr
.data
.data
);
941 static void zebra_fill_protobuf_msg(struct stream
*s
, char *name
, int len
)
943 int str_len
= strlen(name
) + 1;
945 stream_put(s
, name
, str_len
);
946 /* Fill the rest with Null Character for aligning */
947 stream_put(s
, NULL
, len
- str_len
);
950 int zebra_mlag_protobuf_decode_message(struct stream
*s
, uint8_t *data
,
954 ZebraMlagHeader
*hdr
;
957 hdr
= zebra_mlag__header__unpack(NULL
, len
, data
);
962 * ADD The MLAG Header
964 zclient_create_header(s
, ZEBRA_MLAG_FORWARD_MSG
, VRF_DEFAULT
);
966 msg_type
= hdr
->type
;
968 if (IS_ZEBRA_DEBUG_MLAG
)
969 zlog_debug("%s: Mlag ProtoBuf decoding of message:%s", __func__
,
970 mlag_lib_msgid_to_str(msg_type
, buf
, 80));
973 * Internal MLAG Message-types & MLAG.proto message types should
974 * always match, otherwise there can be decoding errors
975 * To avoid exposing clients with Protobuf flags, using internal
978 stream_putl(s
, hdr
->type
);
980 if (hdr
->data
.len
== 0) {
982 stream_putw(s
, MLAG_MSG_NULL_PAYLOAD
);
984 stream_putw(s
, MLAG_MSG_NO_BATCH
);
987 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_STATUS_UPDATE
: {
988 ZebraMlagStatusUpdate
*msg
= NULL
;
990 msg
= zebra_mlag_status_update__unpack(
991 NULL
, hdr
->data
.len
, hdr
->data
.data
);
993 zebra_mlag__header__free_unpacked(hdr
, NULL
);
997 stream_putw(s
, sizeof(struct mlag_status
));
999 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1001 zebra_fill_protobuf_msg(s
, msg
->peerlink
,
1003 stream_putl(s
, msg
->my_role
);
1004 stream_putl(s
, msg
->peer_state
);
1005 zebra_mlag_status_update__free_unpacked(msg
, NULL
);
1007 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_VXLAN_UPDATE
: {
1008 ZebraMlagVxlanUpdate
*msg
= NULL
;
1010 msg
= zebra_mlag_vxlan_update__unpack(
1011 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1013 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1017 stream_putw(s
, sizeof(struct mlag_vxlan
));
1019 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1021 stream_putl(s
, msg
->anycast_ip
);
1022 stream_putl(s
, msg
->local_ip
);
1023 zebra_mlag_vxlan_update__free_unpacked(msg
, NULL
);
1025 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_ADD
: {
1026 ZebraMlagMrouteAdd
*msg
= NULL
;
1028 msg
= zebra_mlag_mroute_add__unpack(NULL
, hdr
->data
.len
,
1031 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1035 stream_putw(s
, sizeof(struct mlag_mroute_add
));
1037 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1039 zebra_fill_protobuf_msg(s
, msg
->vrf_name
, VRF_NAMSIZ
);
1041 stream_putl(s
, msg
->source_ip
);
1042 stream_putl(s
, msg
->group_ip
);
1043 stream_putl(s
, msg
->cost_to_rp
);
1044 stream_putl(s
, msg
->owner_id
);
1045 stream_putc(s
, msg
->am_i_dr
);
1046 stream_putc(s
, msg
->am_i_dual_active
);
1047 stream_putl(s
, msg
->vrf_id
);
1048 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1049 zebra_fill_protobuf_msg(s
, msg
->intf_name
,
1052 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1053 zebra_mlag_mroute_add__free_unpacked(msg
, NULL
);
1055 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_DEL
: {
1056 ZebraMlagMrouteDel
*msg
= NULL
;
1058 msg
= zebra_mlag_mroute_del__unpack(NULL
, hdr
->data
.len
,
1061 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1065 stream_putw(s
, sizeof(struct mlag_mroute_del
));
1067 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1069 zebra_fill_protobuf_msg(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
->owner_id
);
1074 stream_putl(s
, msg
->vrf_id
);
1075 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1076 zebra_fill_protobuf_msg(s
, msg
->intf_name
,
1079 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1080 zebra_mlag_mroute_del__free_unpacked(msg
, NULL
);
1082 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_ADD_BULK
: {
1083 ZebraMlagMrouteAddBulk
*Bulk_msg
= NULL
;
1084 ZebraMlagMrouteAdd
*msg
= NULL
;
1087 Bulk_msg
= zebra_mlag_mroute_add_bulk__unpack(
1088 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1089 if (Bulk_msg
== NULL
) {
1090 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1094 stream_putw(s
, (Bulk_msg
->n_mroute_add
1095 * sizeof(struct mlag_mroute_add
)));
1096 /* No. of msgs in Batch */
1097 stream_putw(s
, Bulk_msg
->n_mroute_add
);
1100 for (i
= 0; i
< Bulk_msg
->n_mroute_add
; i
++) {
1102 msg
= Bulk_msg
->mroute_add
[i
];
1104 zebra_fill_protobuf_msg(s
, msg
->vrf_name
,
1106 stream_putl(s
, msg
->source_ip
);
1107 stream_putl(s
, msg
->group_ip
);
1108 stream_putl(s
, msg
->cost_to_rp
);
1109 stream_putl(s
, msg
->owner_id
);
1110 stream_putc(s
, msg
->am_i_dr
);
1111 stream_putc(s
, msg
->am_i_dual_active
);
1112 stream_putl(s
, msg
->vrf_id
);
1113 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1114 zebra_fill_protobuf_msg(
1118 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1120 zebra_mlag_mroute_add_bulk__free_unpacked(Bulk_msg
,
1123 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_DEL_BULK
: {
1124 ZebraMlagMrouteDelBulk
*Bulk_msg
= NULL
;
1125 ZebraMlagMrouteDel
*msg
= NULL
;
1128 Bulk_msg
= zebra_mlag_mroute_del_bulk__unpack(
1129 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1130 if (Bulk_msg
== NULL
) {
1131 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1135 stream_putw(s
, (Bulk_msg
->n_mroute_del
1136 * sizeof(struct mlag_mroute_del
)));
1137 /* No. of msgs in Batch */
1138 stream_putw(s
, Bulk_msg
->n_mroute_del
);
1141 for (i
= 0; i
< Bulk_msg
->n_mroute_del
; i
++) {
1143 msg
= Bulk_msg
->mroute_del
[i
];
1145 zebra_fill_protobuf_msg(s
, msg
->vrf_name
,
1147 stream_putl(s
, msg
->source_ip
);
1148 stream_putl(s
, msg
->group_ip
);
1149 stream_putl(s
, msg
->owner_id
);
1150 stream_putl(s
, msg
->vrf_id
);
1151 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1152 zebra_fill_protobuf_msg(
1156 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1158 zebra_mlag_mroute_del_bulk__free_unpacked(Bulk_msg
,
1161 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_ZEBRA_STATUS_UPDATE
: {
1162 ZebraMlagZebraStatusUpdate
*msg
= NULL
;
1164 msg
= zebra_mlag_zebra_status_update__unpack(
1165 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1167 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1171 stream_putw(s
, sizeof(struct mlag_frr_status
));
1173 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1175 stream_putl(s
, msg
->peer_frrstate
);
1176 zebra_mlag_zebra_status_update__free_unpacked(msg
,
1183 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1188 int zebra_mlag_protobuf_encode_client_data(struct stream
*s
, uint32_t *msg_type
)
1193 int zebra_mlag_protobuf_decode_message(struct stream
*s
, uint8_t *data
,