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_router.h"
31 #include "zebra/zebra_memory.h"
32 #include "zebra/zapi_msg.h"
33 #include "zebra/debug.h"
35 #ifndef VTYSH_EXTRACT_PL
36 #include "zebra/zebra_mlag_clippy.c"
39 DEFINE_HOOK(zebra_mlag_private_write_data
,
40 (uint8_t *data
, uint32_t len
), (data
, len
))
41 DEFINE_HOOK(zebra_mlag_private_monitor_state
, (), ())
42 DEFINE_HOOK(zebra_mlag_private_open_channel
, (), ())
43 DEFINE_HOOK(zebra_mlag_private_close_channel
, (), ())
44 DEFINE_HOOK(zebra_mlag_private_cleanup_data
, (), ())
46 #define ZEBRA_MLAG_METADATA_LEN 4
47 #define ZEBRA_MLAG_MSG_BCAST 0xFFFFFFFF
49 uint8_t mlag_wr_buffer
[ZEBRA_MLAG_BUF_LIMIT
];
50 uint8_t mlag_rd_buffer
[ZEBRA_MLAG_BUF_LIMIT
];
51 uint32_t mlag_rd_buf_offset
;
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
;
113 struct stream
*s1
= NULL
;
116 s
= stream_new(ZEBRA_MAX_PACKET_SIZ
);
117 msg_type
= zebra_mlag_protobuf_decode_message(s
, data
, len
);
120 /* Something went wrong in decoding */
122 zlog_err("%s: failed to process mlag data-%d, %u", __func__
,
128 * additional four bytes are for message type
130 s1
= stream_new(stream_get_endp(s
) + ZEBRA_MLAG_METADATA_LEN
);
131 stream_putl(s1
, msg_type
);
132 stream_put(s1
, s
->data
, stream_get_endp(s
));
133 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 cleints",
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 cleints.
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 DEFUN_HIDDEN (show_mlag
,
594 "The mlag role on this machine\n")
596 char buf
[MLAG_ROLE_STRSIZE
];
598 vty_out(vty
, "MLag is configured to: %s\n",
599 mlag_role2str(zrouter
.mlag_info
.role
, buf
, sizeof(buf
)));
604 DEFPY_HIDDEN(test_mlag
, test_mlag_cmd
,
605 "test zebra mlag <none$none|primary$primary|secondary$secondary>",
608 "Modify the Mlag state\n"
609 "Mlag is not setup on the machine\n"
610 "Mlag is setup to be primary\n"
611 "Mlag is setup to be the secondary\n")
613 enum mlag_role orig
= zrouter
.mlag_info
.role
;
614 char buf1
[MLAG_ROLE_STRSIZE
], buf2
[MLAG_ROLE_STRSIZE
];
617 zrouter
.mlag_info
.role
= MLAG_ROLE_NONE
;
619 zrouter
.mlag_info
.role
= MLAG_ROLE_PRIMARY
;
621 zrouter
.mlag_info
.role
= MLAG_ROLE_SECONDARY
;
623 if (IS_ZEBRA_DEBUG_MLAG
)
624 zlog_debug("Test: Changing role from %s to %s",
625 mlag_role2str(orig
, buf1
, sizeof(buf1
)),
626 mlag_role2str(orig
, buf2
, sizeof(buf2
)));
628 if (orig
!= zrouter
.mlag_info
.role
) {
629 zsend_capabilities_all_clients();
630 if (zrouter
.mlag_info
.role
!= MLAG_ROLE_NONE
) {
631 if (zrouter
.mlag_info
.clients_interested_cnt
== 0
632 && test_mlag_in_progress
== false) {
633 if (zrouter
.mlag_info
.zebra_pth_mlag
== NULL
)
634 zebra_mlag_spawn_pthread();
635 zrouter
.mlag_info
.clients_interested_cnt
++;
636 test_mlag_in_progress
= true;
637 hook_call(zebra_mlag_private_open_channel
);
640 if (test_mlag_in_progress
== true) {
641 test_mlag_in_progress
= false;
642 zrouter
.mlag_info
.clients_interested_cnt
--;
643 hook_call(zebra_mlag_private_close_channel
);
651 void zebra_mlag_init(void)
653 install_element(VIEW_NODE
, &show_mlag_cmd
);
654 install_element(ENABLE_NODE
, &test_mlag_cmd
);
657 * Intialiaze the MLAG Global variables
658 * write thread will be created during actual registration with MCLAG
660 zrouter
.mlag_info
.clients_interested_cnt
= 0;
661 zrouter
.mlag_info
.connected
= false;
662 zrouter
.mlag_info
.timer_running
= false;
663 zrouter
.mlag_info
.mlag_fifo
= stream_fifo_new();
664 zrouter
.mlag_info
.zebra_pth_mlag
= NULL
;
665 zrouter
.mlag_info
.th_master
= NULL
;
666 zrouter
.mlag_info
.t_read
= NULL
;
667 zrouter
.mlag_info
.t_write
= NULL
;
668 test_mlag_in_progress
= false;
669 zebra_mlag_reset_read_buffer();
672 void zebra_mlag_terminate(void)
679 * ProtoBuf Encoding APIs
684 DEFINE_MTYPE_STATIC(ZEBRA
, MLAG_PBUF
, "ZEBRA MLAG PROTOBUF")
686 int zebra_mlag_protobuf_encode_client_data(struct stream
*s
, uint32_t *msg_type
)
688 ZebraMlagHeader hdr
= ZEBRA_MLAG__HEADER__INIT
;
689 struct mlag_msg mlag_msg
;
690 uint8_t tmp_buf
[ZEBRA_MLAG_BUF_LIMIT
];
694 char buf
[ZLOG_FILTER_LENGTH_MAX
];
696 if (IS_ZEBRA_DEBUG_MLAG
)
697 zlog_debug("%s: Entering..", __func__
);
699 rc
= mlag_lib_decode_mlag_hdr(s
, &mlag_msg
);
703 if (IS_ZEBRA_DEBUG_MLAG
)
704 zlog_debug("%s: Mlag ProtoBuf encoding of message:%s, len:%d",
706 mlag_lib_msgid_to_str(mlag_msg
.msg_type
, buf
,
709 *msg_type
= mlag_msg
.msg_type
;
710 switch (mlag_msg
.msg_type
) {
711 case MLAG_MROUTE_ADD
: {
712 struct mlag_mroute_add msg
;
713 ZebraMlagMrouteAdd pay_load
= ZEBRA_MLAG_MROUTE_ADD__INIT
;
714 uint32_t vrf_name_len
= 0;
716 rc
= mlag_lib_decode_mroute_add(s
, &msg
);
719 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
720 pay_load
.vrf_name
= XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
721 strlcpy(pay_load
.vrf_name
, msg
.vrf_name
, vrf_name_len
);
722 pay_load
.source_ip
= msg
.source_ip
;
723 pay_load
.group_ip
= msg
.group_ip
;
724 pay_load
.cost_to_rp
= msg
.cost_to_rp
;
725 pay_load
.owner_id
= msg
.owner_id
;
726 pay_load
.am_i_dr
= msg
.am_i_dr
;
727 pay_load
.am_i_dual_active
= msg
.am_i_dual_active
;
728 pay_load
.vrf_id
= msg
.vrf_id
;
730 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
731 vrf_name_len
= strlen(msg
.intf_name
) + 1;
733 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
734 strlcpy(pay_load
.intf_name
, msg
.intf_name
,
738 len
= zebra_mlag_mroute_add__pack(&pay_load
, tmp_buf
);
739 XFREE(MTYPE_MLAG_PBUF
, pay_load
.vrf_name
);
740 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
)
741 XFREE(MTYPE_MLAG_PBUF
, pay_load
.intf_name
);
743 case MLAG_MROUTE_DEL
: {
744 struct mlag_mroute_del msg
;
745 ZebraMlagMrouteDel pay_load
= ZEBRA_MLAG_MROUTE_DEL__INIT
;
746 uint32_t vrf_name_len
= 0;
748 rc
= mlag_lib_decode_mroute_del(s
, &msg
);
751 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
752 pay_load
.vrf_name
= XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
753 strlcpy(pay_load
.vrf_name
, msg
.vrf_name
, vrf_name_len
);
754 pay_load
.source_ip
= msg
.source_ip
;
755 pay_load
.group_ip
= msg
.group_ip
;
756 pay_load
.owner_id
= msg
.owner_id
;
757 pay_load
.vrf_id
= msg
.vrf_id
;
759 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
760 vrf_name_len
= strlen(msg
.intf_name
) + 1;
762 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
763 strlcpy(pay_load
.intf_name
, msg
.intf_name
,
767 len
= zebra_mlag_mroute_del__pack(&pay_load
, tmp_buf
);
768 XFREE(MTYPE_MLAG_PBUF
, pay_load
.vrf_name
);
769 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
)
770 XFREE(MTYPE_MLAG_PBUF
, pay_load
.intf_name
);
772 case MLAG_MROUTE_ADD_BULK
: {
773 struct mlag_mroute_add msg
;
774 ZebraMlagMrouteAddBulk Bulk_msg
=
775 ZEBRA_MLAG_MROUTE_ADD_BULK__INIT
;
776 ZebraMlagMrouteAdd
**pay_load
= NULL
;
778 bool cleanup
= false;
780 Bulk_msg
.n_mroute_add
= mlag_msg
.msg_cnt
;
781 pay_load
= XMALLOC(MTYPE_MLAG_PBUF
, sizeof(ZebraMlagMrouteAdd
*)
784 for (i
= 0; i
< mlag_msg
.msg_cnt
; i
++) {
786 uint32_t vrf_name_len
= 0;
788 rc
= mlag_lib_decode_mroute_add(s
, &msg
);
793 pay_load
[i
] = XMALLOC(MTYPE_MLAG_PBUF
,
794 sizeof(ZebraMlagMrouteAdd
));
795 zebra_mlag_mroute_add__init(pay_load
[i
]);
797 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
798 pay_load
[i
]->vrf_name
=
799 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
800 strlcpy(pay_load
[i
]->vrf_name
, msg
.vrf_name
,
802 pay_load
[i
]->source_ip
= msg
.source_ip
;
803 pay_load
[i
]->group_ip
= msg
.group_ip
;
804 pay_load
[i
]->cost_to_rp
= msg
.cost_to_rp
;
805 pay_load
[i
]->owner_id
= msg
.owner_id
;
806 pay_load
[i
]->am_i_dr
= msg
.am_i_dr
;
807 pay_load
[i
]->am_i_dual_active
= msg
.am_i_dual_active
;
808 pay_load
[i
]->vrf_id
= msg
.vrf_id
;
809 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
810 vrf_name_len
= strlen(msg
.intf_name
) + 1;
811 pay_load
[i
]->intf_name
=
812 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
814 strlcpy(pay_load
[i
]->intf_name
, msg
.intf_name
,
818 if (cleanup
== false) {
819 Bulk_msg
.mroute_add
= pay_load
;
820 len
= zebra_mlag_mroute_add_bulk__pack(&Bulk_msg
,
824 for (i
= 0; i
< mlag_msg
.msg_cnt
; i
++) {
825 if (pay_load
[i
]->vrf_name
)
826 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->vrf_name
);
827 if (pay_load
[i
]->owner_id
== MLAG_OWNER_INTERFACE
828 && pay_load
[i
]->intf_name
)
829 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->intf_name
);
831 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]);
833 XFREE(MTYPE_MLAG_PBUF
, pay_load
);
837 case MLAG_MROUTE_DEL_BULK
: {
838 struct mlag_mroute_del msg
;
839 ZebraMlagMrouteDelBulk Bulk_msg
=
840 ZEBRA_MLAG_MROUTE_DEL_BULK__INIT
;
841 ZebraMlagMrouteDel
**pay_load
= NULL
;
843 bool cleanup
= false;
845 Bulk_msg
.n_mroute_del
= mlag_msg
.msg_cnt
;
846 pay_load
= XMALLOC(MTYPE_MLAG_PBUF
, sizeof(ZebraMlagMrouteDel
*)
849 for (i
= 0; i
< mlag_msg
.msg_cnt
; i
++) {
851 uint32_t vrf_name_len
= 0;
853 rc
= mlag_lib_decode_mroute_del(s
, &msg
);
859 pay_load
[i
] = XMALLOC(MTYPE_MLAG_PBUF
,
860 sizeof(ZebraMlagMrouteDel
));
861 zebra_mlag_mroute_del__init(pay_load
[i
]);
863 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
864 pay_load
[i
]->vrf_name
=
865 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
867 strlcpy(pay_load
[i
]->vrf_name
, msg
.vrf_name
,
869 pay_load
[i
]->source_ip
= msg
.source_ip
;
870 pay_load
[i
]->group_ip
= msg
.group_ip
;
871 pay_load
[i
]->owner_id
= msg
.owner_id
;
872 pay_load
[i
]->vrf_id
= msg
.vrf_id
;
873 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
874 vrf_name_len
= strlen(msg
.intf_name
) + 1;
875 pay_load
[i
]->intf_name
=
876 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
878 strlcpy(pay_load
[i
]->intf_name
, msg
.intf_name
,
883 Bulk_msg
.mroute_del
= pay_load
;
884 len
= zebra_mlag_mroute_del_bulk__pack(&Bulk_msg
,
888 for (i
= 0; i
< mlag_msg
.msg_cnt
; i
++) {
889 if (pay_load
[i
]->vrf_name
)
890 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->vrf_name
);
891 if (pay_load
[i
]->owner_id
== MLAG_OWNER_INTERFACE
892 && pay_load
[i
]->intf_name
)
893 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->intf_name
);
895 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]);
897 XFREE(MTYPE_MLAG_PBUF
, pay_load
);
905 if (IS_ZEBRA_DEBUG_MLAG
)
906 zlog_debug("%s: length of Mlag ProtoBuf encoded message:%s, %d",
908 mlag_lib_msgid_to_str(mlag_msg
.msg_type
, buf
,
911 hdr
.type
= (ZebraMlagHeader__MessageType
)mlag_msg
.msg_type
;
914 hdr
.data
.data
= XMALLOC(MTYPE_MLAG_PBUF
, len
);
915 memcpy(hdr
.data
.data
, tmp_buf
, len
);
919 * ProtoBuf Infra will not support to demarc the pointers whem multiple
920 * messages are posted inside a single Buffer.
921 * 2 -solutions exist to solve this
922 * 1. add Unenoced length at the beginning of every message, this will
923 * be used to point to next message in the buffer
924 * 2. another solution is defining all messages insides another message
925 * But this will permit only 32 messages. this can be extended with
927 * for simplicity we are going with solution-1.
929 len
= zebra_mlag__header__pack(&hdr
,
930 (mlag_wr_buffer
+ ZEBRA_MLAG_LEN_SIZE
));
932 memcpy(mlag_wr_buffer
, &n_len
, ZEBRA_MLAG_LEN_SIZE
);
933 len
+= ZEBRA_MLAG_LEN_SIZE
;
935 if (IS_ZEBRA_DEBUG_MLAG
)
937 "%s: length of Mlag ProtoBuf message:%s with Header %d",
939 mlag_lib_msgid_to_str(mlag_msg
.msg_type
, buf
,
943 XFREE(MTYPE_MLAG_PBUF
, hdr
.data
.data
);
948 int zebra_mlag_protobuf_decode_message(struct stream
*s
, uint8_t *data
,
952 ZebraMlagHeader
*hdr
;
955 hdr
= zebra_mlag__header__unpack(NULL
, len
, data
);
960 * ADD The MLAG Header
962 zclient_create_header(s
, ZEBRA_MLAG_FORWARD_MSG
, VRF_DEFAULT
);
964 msg_type
= hdr
->type
;
966 if (IS_ZEBRA_DEBUG_MLAG
)
967 zlog_debug("%s: Mlag ProtoBuf decoding of message:%s", __func__
,
968 mlag_lib_msgid_to_str(msg_type
, buf
, 80));
971 * Internal MLAG Message-types & MLAG.proto message types should
972 * always match, otherwise there can be decoding errors
973 * To avoid exposing clients with Protobuf flags, using internal
976 stream_putl(s
, hdr
->type
);
978 if (hdr
->data
.len
== 0) {
980 stream_putw(s
, MLAG_MSG_NULL_PAYLOAD
);
982 stream_putw(s
, MLAG_MSG_NO_BATCH
);
985 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_STATUS_UPDATE
: {
986 ZebraMlagStatusUpdate
*msg
= NULL
;
988 msg
= zebra_mlag_status_update__unpack(
989 NULL
, hdr
->data
.len
, hdr
->data
.data
);
991 zebra_mlag__header__free_unpacked(hdr
, NULL
);
995 stream_putw(s
, sizeof(struct mlag_status
));
997 stream_putw(s
, MLAG_MSG_NO_BATCH
);
999 stream_put(s
, msg
->peerlink
, INTERFACE_NAMSIZ
);
1000 stream_putl(s
, msg
->my_role
);
1001 stream_putl(s
, msg
->peer_state
);
1002 zebra_mlag_status_update__free_unpacked(msg
, NULL
);
1004 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_VXLAN_UPDATE
: {
1005 ZebraMlagVxlanUpdate
*msg
= NULL
;
1007 msg
= zebra_mlag_vxlan_update__unpack(
1008 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1010 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1014 stream_putw(s
, sizeof(struct mlag_vxlan
));
1016 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1018 stream_putl(s
, msg
->anycast_ip
);
1019 stream_putl(s
, msg
->local_ip
);
1020 zebra_mlag_vxlan_update__free_unpacked(msg
, NULL
);
1022 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_ADD
: {
1023 ZebraMlagMrouteAdd
*msg
= NULL
;
1025 msg
= zebra_mlag_mroute_add__unpack(NULL
, hdr
->data
.len
,
1028 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1032 stream_putw(s
, sizeof(struct mlag_mroute_add
));
1034 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1036 stream_put(s
, msg
->vrf_name
, VRF_NAMSIZ
);
1038 stream_putl(s
, msg
->source_ip
);
1039 stream_putl(s
, msg
->group_ip
);
1040 stream_putl(s
, msg
->cost_to_rp
);
1041 stream_putl(s
, msg
->owner_id
);
1042 stream_putc(s
, msg
->am_i_dr
);
1043 stream_putc(s
, msg
->am_i_dual_active
);
1044 stream_putl(s
, msg
->vrf_id
);
1045 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1046 stream_put(s
, msg
->intf_name
, INTERFACE_NAMSIZ
);
1048 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1049 zebra_mlag_mroute_add__free_unpacked(msg
, NULL
);
1051 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_DEL
: {
1052 ZebraMlagMrouteDel
*msg
= NULL
;
1054 msg
= zebra_mlag_mroute_del__unpack(NULL
, hdr
->data
.len
,
1057 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1061 stream_putw(s
, sizeof(struct mlag_mroute_del
));
1063 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1065 stream_put(s
, msg
->vrf_name
, VRF_NAMSIZ
);
1067 stream_putl(s
, msg
->source_ip
);
1068 stream_putl(s
, msg
->group_ip
);
1069 stream_putl(s
, msg
->group_ip
);
1070 stream_putl(s
, msg
->owner_id
);
1071 stream_putl(s
, msg
->vrf_id
);
1072 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1073 stream_put(s
, msg
->intf_name
, INTERFACE_NAMSIZ
);
1075 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1076 zebra_mlag_mroute_del__free_unpacked(msg
, NULL
);
1078 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_ADD_BULK
: {
1079 ZebraMlagMrouteAddBulk
*Bulk_msg
= NULL
;
1080 ZebraMlagMrouteAdd
*msg
= NULL
;
1083 Bulk_msg
= zebra_mlag_mroute_add_bulk__unpack(
1084 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1085 if (Bulk_msg
== NULL
) {
1086 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1090 stream_putw(s
, (Bulk_msg
->n_mroute_add
1091 * sizeof(struct mlag_mroute_add
)));
1092 /* No. of msgs in Batch */
1093 stream_putw(s
, Bulk_msg
->n_mroute_add
);
1096 for (i
= 0; i
< Bulk_msg
->n_mroute_add
; i
++) {
1098 msg
= Bulk_msg
->mroute_add
[i
];
1100 stream_put(s
, msg
->vrf_name
, VRF_NAMSIZ
);
1101 stream_putl(s
, msg
->source_ip
);
1102 stream_putl(s
, msg
->group_ip
);
1103 stream_putl(s
, msg
->cost_to_rp
);
1104 stream_putl(s
, msg
->owner_id
);
1105 stream_putc(s
, msg
->am_i_dr
);
1106 stream_putc(s
, msg
->am_i_dual_active
);
1107 stream_putl(s
, msg
->vrf_id
);
1108 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1109 stream_put(s
, msg
->intf_name
,
1112 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1114 zebra_mlag_mroute_add_bulk__free_unpacked(Bulk_msg
,
1117 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_DEL_BULK
: {
1118 ZebraMlagMrouteDelBulk
*Bulk_msg
= NULL
;
1119 ZebraMlagMrouteDel
*msg
= NULL
;
1122 Bulk_msg
= zebra_mlag_mroute_del_bulk__unpack(
1123 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1124 if (Bulk_msg
== NULL
) {
1125 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1129 stream_putw(s
, (Bulk_msg
->n_mroute_del
1130 * sizeof(struct mlag_mroute_del
)));
1131 /* No. of msgs in Batch */
1132 stream_putw(s
, Bulk_msg
->n_mroute_del
);
1135 for (i
= 0; i
< Bulk_msg
->n_mroute_del
; i
++) {
1137 msg
= Bulk_msg
->mroute_del
[i
];
1139 stream_put(s
, msg
->vrf_name
, VRF_NAMSIZ
);
1140 stream_putl(s
, msg
->source_ip
);
1141 stream_putl(s
, msg
->group_ip
);
1142 stream_putl(s
, msg
->owner_id
);
1143 stream_putl(s
, msg
->vrf_id
);
1144 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1145 stream_put(s
, msg
->intf_name
,
1148 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1150 zebra_mlag_mroute_del_bulk__free_unpacked(Bulk_msg
,
1153 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_ZEBRA_STATUS_UPDATE
: {
1154 ZebraMlagZebraStatusUpdate
*msg
= NULL
;
1156 msg
= zebra_mlag_zebra_status_update__unpack(
1157 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1159 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1163 stream_putw(s
, sizeof(struct mlag_frr_status
));
1165 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1167 stream_putl(s
, msg
->peer_frrstate
);
1168 zebra_mlag_zebra_status_update__free_unpacked(msg
,
1175 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1180 int zebra_mlag_protobuf_encode_client_data(struct stream
*s
, uint32_t *msg_type
)
1185 int zebra_mlag_protobuf_decode_message(struct stream
*s
, uint8_t *data
,