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 DEFINE_HOOK(zebra_mlag_private_write_data
,
36 (uint8_t *data
, uint32_t len
), (data
, len
))
37 DEFINE_HOOK(zebra_mlag_private_monitor_state
, (), ())
38 DEFINE_HOOK(zebra_mlag_private_open_channel
, (), ())
39 DEFINE_HOOK(zebra_mlag_private_close_channel
, (), ())
40 DEFINE_HOOK(zebra_mlag_private_cleanup_data
, (), ())
42 #define ZEBRA_MLAG_METADATA_LEN 4
43 #define ZEBRA_MLAG_MSG_BCAST 0xFFFFFFFF
45 uint8_t mlag_wr_buffer
[ZEBRA_MLAG_BUF_LIMIT
];
46 uint8_t mlag_rd_buffer
[ZEBRA_MLAG_BUF_LIMIT
];
47 uint32_t mlag_rd_buf_offset
;
49 static bool test_mlag_in_progress
;
51 static int zebra_mlag_signal_write_thread(void);
52 static int zebra_mlag_terminate_pthread(struct thread
*event
);
53 static int zebra_mlag_post_data_from_main_thread(struct thread
*thread
);
54 static void zebra_mlag_publish_process_state(struct zserv
*client
,
55 zebra_message_types_t msg_type
);
57 /**********************MLAG Interaction***************************************/
60 * API to post the Registration to MLAGD
61 * MLAG will not process any messages with out the registration
63 void zebra_mlag_send_register(void)
65 struct stream
*s
= NULL
;
67 s
= stream_new(sizeof(struct mlag_msg
));
69 stream_putl(s
, MLAG_REGISTER
);
70 stream_putw(s
, MLAG_MSG_NULL_PAYLOAD
);
71 stream_putw(s
, MLAG_MSG_NO_BATCH
);
72 stream_fifo_push_safe(zrouter
.mlag_info
.mlag_fifo
, s
);
73 zebra_mlag_signal_write_thread();
75 if (IS_ZEBRA_DEBUG_MLAG
)
76 zlog_debug("%s: Enqueued MLAG Register to MLAG Thread ",
81 * API to post the De-Registration to MLAGD
82 * MLAG will not process any messages after the de-registration
84 void zebra_mlag_send_deregister(void)
86 struct stream
*s
= NULL
;
88 s
= stream_new(sizeof(struct mlag_msg
));
90 stream_putl(s
, MLAG_DEREGISTER
);
91 stream_putw(s
, MLAG_MSG_NULL_PAYLOAD
);
92 stream_putw(s
, MLAG_MSG_NO_BATCH
);
93 stream_fifo_push_safe(zrouter
.mlag_info
.mlag_fifo
, s
);
94 zebra_mlag_signal_write_thread();
96 if (IS_ZEBRA_DEBUG_MLAG
)
97 zlog_debug("%s: Enqueued MLAG De-Register to MLAG Thread ",
102 * API To handle MLAG Received data
103 * Decodes the data using protobuf and enqueue to main thread
104 * main thread publish this to clients based on client subscription
106 void zebra_mlag_process_mlag_data(uint8_t *data
, uint32_t len
)
108 struct stream
*s
= NULL
;
109 struct stream
*s1
= NULL
;
112 s
= stream_new(ZEBRA_MAX_PACKET_SIZ
);
113 msg_type
= zebra_mlag_protobuf_decode_message(s
, data
, len
);
116 /* Something went wrong in decoding */
118 zlog_err("%s: failed to process mlag data-%d, %u", __func__
,
124 * additional four bytes are for message type
126 s1
= stream_new(stream_get_endp(s
) + ZEBRA_MLAG_METADATA_LEN
);
127 stream_putl(s1
, msg_type
);
128 stream_put(s1
, s
->data
, stream_get_endp(s
));
129 thread_add_event(zrouter
.master
, zebra_mlag_post_data_from_main_thread
,
134 /**********************End of MLAG Interaction********************************/
136 /************************MLAG Thread Processing*******************************/
139 * after posting every 'ZEBRA_MLAG_POST_LIMIT' packets, MLAG Thread will be
140 * yielded to give CPU for other threads
142 #define ZEBRA_MLAG_POST_LIMIT 100
145 * This thread reads the clients data from the Global queue and encodes with
146 * protobuf and pass on to the MLAG socket.
148 static int zebra_mlag_client_msg_handler(struct thread
*event
)
151 uint32_t wr_count
= 0;
152 uint32_t msg_type
= 0;
153 uint32_t max_count
= 0;
156 wr_count
= stream_fifo_count_safe(zrouter
.mlag_info
.mlag_fifo
);
157 if (IS_ZEBRA_DEBUG_MLAG
)
158 zlog_debug(":%s: Processing MLAG write, %u messages in queue",
161 max_count
= MIN(wr_count
, ZEBRA_MLAG_POST_LIMIT
);
163 for (wr_count
= 0; wr_count
< max_count
; wr_count
++) {
164 s
= stream_fifo_pop_safe(zrouter
.mlag_info
.mlag_fifo
);
166 zlog_debug(":%s: Got a NULL Messages, some thing wrong",
172 * Encode the data now
174 len
= zebra_mlag_protobuf_encode_client_data(s
, &msg_type
);
180 hook_call(zebra_mlag_private_write_data
,
181 mlag_wr_buffer
, len
);
184 * If message type is De-register, send a signal to main
185 * thread, so that necessary cleanup will be done by
188 if (msg_type
== MLAG_DEREGISTER
) {
189 thread_add_event(zrouter
.master
,
190 zebra_mlag_terminate_pthread
,
198 if (IS_ZEBRA_DEBUG_MLAG
)
199 zlog_debug(":%s: Posted %d messages to MLAGD", __func__
,
202 * Currently there is only message write task is enqueued to this
203 * thread, yielding was added for future purpose, so that this thread
204 * can server other tasks also and in case FIFO is empty, this task will
205 * be schedule when main thread adds some messages
207 if (wr_count
>= ZEBRA_MLAG_POST_LIMIT
)
208 zebra_mlag_signal_write_thread();
213 * API to handle the process state.
214 * In case of Down, Zebra keep monitoring the MLAG state.
215 * all the state Notifications will be published to clients
217 void zebra_mlag_handle_process_state(enum zebra_mlag_state state
)
219 if (state
== MLAG_UP
) {
220 zrouter
.mlag_info
.connected
= true;
221 zebra_mlag_publish_process_state(NULL
, ZEBRA_MLAG_PROCESS_UP
);
222 zebra_mlag_send_register();
223 } else if (state
== MLAG_DOWN
) {
224 zrouter
.mlag_info
.connected
= false;
225 zebra_mlag_publish_process_state(NULL
, ZEBRA_MLAG_PROCESS_DOWN
);
226 hook_call(zebra_mlag_private_monitor_state
);
230 /***********************End of MLAG Thread processing*************************/
232 /*************************Multi-entratnt Api's********************************/
235 * Provider api to signal that work/events are available
236 * for the Zebra MLAG Write pthread.
237 * This API is called from 2 pthreads..
238 * 1) by main thread when client posts a MLAG Message
239 * 2) by MLAG Thread, in case of yield
240 * though this api, is called from two threads we don't need any locking
241 * because Thread task enqueue is thread safe means internally it had
242 * necessary protection
244 static int zebra_mlag_signal_write_thread(void)
246 if (IS_ZEBRA_DEBUG_MLAG
)
247 zlog_debug(":%s: Scheduling MLAG write", __func__
);
249 * This api will be called from Both main & MLAG Threads.
250 * main thread writes, "zrouter.mlag_info.th_master" only
251 * during Zebra Init/after MLAG thread is destroyed.
252 * so it is safe to use without any locking
254 thread_add_event(zrouter
.mlag_info
.th_master
,
255 zebra_mlag_client_msg_handler
, NULL
, 0,
256 &zrouter
.mlag_info
.t_write
);
261 * API will be used to publish the MLAG state to interested clients
262 * In case client is passed, state is posted only for that client,
263 * otherwise to all interested clients
264 * this api can be called from two threads.
265 * 1) from main thread: when client is passed
266 * 2) from MLAG Thread: when client is NULL
268 * In second case, to avoid global data access data will be post to Main
269 * thread, so that actual posting to clients will happen from Main thread.
271 static void zebra_mlag_publish_process_state(struct zserv
*client
,
272 zebra_message_types_t msg_type
)
276 if (IS_ZEBRA_DEBUG_MLAG
)
277 zlog_debug("%s: Publishing MLAG process state:%s to %s Client",
279 (msg_type
== ZEBRA_MLAG_PROCESS_UP
) ? "UP" : "DOWN",
280 (client
) ? "one" : "all");
283 s
= stream_new(ZEBRA_HEADER_SIZE
);
284 zclient_create_header(s
, msg_type
, VRF_DEFAULT
);
285 zserv_send_message(client
, s
);
291 * additional four bytes are for mesasge type
293 s
= stream_new(ZEBRA_HEADER_SIZE
+ ZEBRA_MLAG_METADATA_LEN
);
294 stream_putl(s
, ZEBRA_MLAG_MSG_BCAST
);
295 zclient_create_header(s
, msg_type
, VRF_DEFAULT
);
296 thread_add_event(zrouter
.master
, zebra_mlag_post_data_from_main_thread
,
300 /**************************End of Multi-entrant Apis**************************/
302 /***********************Zebra Main thread processing**************************/
305 * To avoid data corruption, messages will be post to clients only from
306 * main thread, because for that access was needed for clients list.
307 * so instead of forcing the locks, messages will be posted from main thread.
309 static int zebra_mlag_post_data_from_main_thread(struct thread
*thread
)
311 struct stream
*s
= THREAD_ARG(thread
);
312 struct stream
*zebra_s
= NULL
;
313 struct listnode
*node
;
314 struct zserv
*client
;
315 uint32_t msg_type
= 0;
316 uint32_t msg_len
= 0;
321 STREAM_GETL(s
, msg_type
);
322 if (IS_ZEBRA_DEBUG_MLAG
)
324 "%s: Posting MLAG data for msg_type:0x%x to interested cleints",
327 msg_len
= s
->endp
- ZEBRA_MLAG_METADATA_LEN
;
328 for (ALL_LIST_ELEMENTS_RO(zrouter
.client_list
, node
, client
)) {
329 if (client
->mlag_updates_interested
== true) {
330 if (msg_type
!= ZEBRA_MLAG_MSG_BCAST
331 && !CHECK_FLAG(client
->mlag_reg_mask1
,
336 if (IS_ZEBRA_DEBUG_MLAG
)
338 "%s: Posting MLAG data of length-%d to client:%d ",
339 __func__
, msg_len
, client
->proto
);
341 zebra_s
= stream_new(msg_len
);
342 STREAM_GET(zebra_s
->data
, s
, msg_len
);
343 zebra_s
->endp
= msg_len
;
344 stream_putw_at(zebra_s
, 0, msg_len
);
347 * This stream will be enqueued to client_obuf, it will
348 * be freed after posting to client socket.
350 zserv_send_message(client
, zebra_s
);
360 stream_free(zebra_s
);
365 * Start the MLAG Thread, this will be used to write client data on to
366 * MLAG Process and to read the data from MLAG and post to cleints.
367 * when all clients are un-registered, this Thread will be
370 static void zebra_mlag_spawn_pthread(void)
372 /* Start MLAG write pthread */
374 struct frr_pthread_attr pattr
= {.start
=
375 frr_pthread_attr_default
.start
,
376 .stop
= frr_pthread_attr_default
.stop
};
378 zrouter
.mlag_info
.zebra_pth_mlag
=
379 frr_pthread_new(&pattr
, "Zebra MLAG thread", "Zebra MLAG");
381 zrouter
.mlag_info
.th_master
= zrouter
.mlag_info
.zebra_pth_mlag
->master
;
384 /* Enqueue an initial event to the Newly spawn MLAG pthread */
385 zebra_mlag_signal_write_thread();
387 frr_pthread_run(zrouter
.mlag_info
.zebra_pth_mlag
, NULL
);
391 * all clients are un-registered for MLAG Updates, terminate the
394 static int zebra_mlag_terminate_pthread(struct thread
*event
)
396 if (IS_ZEBRA_DEBUG_MLAG
)
397 zlog_debug("Zebra MLAG write thread terminate called");
399 if (zrouter
.mlag_info
.clients_interested_cnt
) {
400 if (IS_ZEBRA_DEBUG_MLAG
)
402 "Zebra MLAG: still some clients are interested");
406 frr_pthread_stop(zrouter
.mlag_info
.zebra_pth_mlag
, NULL
);
408 /* Destroy pthread */
409 frr_pthread_destroy(zrouter
.mlag_info
.zebra_pth_mlag
);
410 zrouter
.mlag_info
.zebra_pth_mlag
= NULL
;
411 zrouter
.mlag_info
.th_master
= NULL
;
412 zrouter
.mlag_info
.t_read
= NULL
;
413 zrouter
.mlag_info
.t_write
= NULL
;
416 * Send Notification to clean private data
418 hook_call(zebra_mlag_private_cleanup_data
);
423 * API to register zebra client for MLAG Updates
425 void zebra_mlag_client_register(ZAPI_HANDLER_ARGS
)
428 uint32_t reg_mask
= 0;
431 if (IS_ZEBRA_DEBUG_MLAG
)
432 zlog_debug("Received MLAG Registration from client-proto:%d",
436 /* Get input stream. */
440 STREAM_GETL(s
, reg_mask
);
442 if (client
->mlag_updates_interested
== true) {
444 if (IS_ZEBRA_DEBUG_MLAG
)
446 "Client is registered, existing mask: 0x%x, new mask: 0x%x",
447 client
->mlag_reg_mask1
, reg_mask
);
448 if (client
->mlag_reg_mask1
!= reg_mask
)
449 client
->mlag_reg_mask1
= reg_mask
;
451 * Client might missed MLAG-UP Notification, post-it again
453 zebra_mlag_publish_process_state(client
, ZEBRA_MLAG_PROCESS_UP
);
458 client
->mlag_updates_interested
= true;
459 client
->mlag_reg_mask1
= reg_mask
;
460 if (IS_ZEBRA_DEBUG_MLAG
)
461 zlog_debug("Registering for MLAG Updates with mask: 0x%x, ",
462 client
->mlag_reg_mask1
);
464 zrouter
.mlag_info
.clients_interested_cnt
++;
466 if (zrouter
.mlag_info
.clients_interested_cnt
== 1) {
468 * First-client for MLAG Updates,open the communication channel
471 if (IS_ZEBRA_DEBUG_MLAG
)
473 "First client, opening the channel with MLAG");
475 zebra_mlag_spawn_pthread();
476 rc
= hook_call(zebra_mlag_private_open_channel
);
479 * For some reason, zebra not able to open the
480 * comm-channel with MLAG, so post MLAG-DOWN to client.
481 * later when the channel is open, zebra will send
484 if (IS_ZEBRA_DEBUG_MLAG
)
486 "Fail to open channel with MLAG,rc:%d, post Proto-down",
488 zebra_mlag_publish_process_state(
489 client
, ZEBRA_MLAG_PROCESS_DOWN
);
493 if (IS_ZEBRA_DEBUG_MLAG
)
494 zlog_debug("Client Registered successfully for MLAG Updates");
496 if (zrouter
.mlag_info
.connected
== true)
497 zebra_mlag_publish_process_state(client
, ZEBRA_MLAG_PROCESS_UP
);
503 * API to un-register for MLAG Updates
505 void zebra_mlag_client_unregister(ZAPI_HANDLER_ARGS
)
507 if (IS_ZEBRA_DEBUG_MLAG
)
508 zlog_debug("Received MLAG De-Registration from client-proto:%d",
511 if (client
->mlag_updates_interested
== false)
515 client
->mlag_updates_interested
= false;
516 client
->mlag_reg_mask1
= 0;
517 zrouter
.mlag_info
.clients_interested_cnt
--;
519 if (zrouter
.mlag_info
.clients_interested_cnt
== 0) {
521 * No-client is interested for MLAG Updates,close the
522 * communication channel with MLAG
524 if (IS_ZEBRA_DEBUG_MLAG
)
525 zlog_debug("Last client for MLAG, close the channel ");
530 * 1) main thread calls socket close which posts De-register
531 * to MLAG write thread
532 * 2) after MLAG write thread posts De-register it sends a
533 * signal back to main thread to do the thread cleanup
534 * this was mainly to make sure De-register is posted to MCLAGD.
536 hook_call(zebra_mlag_private_close_channel
);
539 if (IS_ZEBRA_DEBUG_MLAG
)
541 "Client De-Registered successfully for MLAG Updates");
545 * Does following things.
546 * 1) allocated new local stream, and copies the client data and enqueue
548 * 2) MLAG Thread after dequeing, encode the client data using protobuf
549 * and write on to MLAG
551 void zebra_mlag_forward_client_msg(ZAPI_HANDLER_ARGS
)
553 struct stream
*zebra_s
;
554 struct stream
*mlag_s
;
556 if (IS_ZEBRA_DEBUG_MLAG
)
557 zlog_debug("Received Client MLAG Data from client-proto:%d",
560 /* Get input stream. */
562 mlag_s
= stream_new(zebra_s
->endp
);
565 * Client data is | Zebra Header + MLAG Data |
566 * we need to enqueue only the MLAG data, skipping Zebra Header
568 stream_put(mlag_s
, zebra_s
->data
+ zebra_s
->getp
,
569 STREAM_READABLE(zebra_s
));
570 stream_fifo_push_safe(zrouter
.mlag_info
.mlag_fifo
, mlag_s
);
571 zebra_mlag_signal_write_thread();
573 if (IS_ZEBRA_DEBUG_MLAG
)
574 zlog_debug("%s: Enqueued Client:%d data to MLAG Thread ",
575 __func__
, client
->proto
);
578 /***********************End of Zebra Main thread processing*************/
580 enum mlag_role
zebra_mlag_get_role(void)
582 return zrouter
.mlag_info
.role
;
585 int32_t zebra_mlag_test_mlag_internal(const char *none
, const char *primary
,
586 const char *secondary
)
588 enum mlag_role orig
= zrouter
.mlag_info
.role
;
589 char buf1
[MLAG_ROLE_STRSIZE
], buf2
[MLAG_ROLE_STRSIZE
];
592 zrouter
.mlag_info
.role
= MLAG_ROLE_NONE
;
594 zrouter
.mlag_info
.role
= MLAG_ROLE_PRIMARY
;
596 zrouter
.mlag_info
.role
= MLAG_ROLE_SECONDARY
;
598 if (IS_ZEBRA_DEBUG_MLAG
)
599 zlog_debug("Test: Changing role from %s to %s",
600 mlag_role2str(orig
, buf1
, sizeof(buf1
)),
601 mlag_role2str(orig
, buf2
, sizeof(buf2
)));
603 if (orig
!= zrouter
.mlag_info
.role
) {
604 zsend_capabilities_all_clients();
605 if (zrouter
.mlag_info
.role
!= MLAG_ROLE_NONE
) {
606 if (zrouter
.mlag_info
.clients_interested_cnt
== 0
607 && test_mlag_in_progress
== false) {
608 if (zrouter
.mlag_info
.zebra_pth_mlag
== NULL
)
609 zebra_mlag_spawn_pthread();
610 zrouter
.mlag_info
.clients_interested_cnt
++;
611 test_mlag_in_progress
= true;
612 hook_call(zebra_mlag_private_open_channel
);
615 if (test_mlag_in_progress
== true) {
616 test_mlag_in_progress
= false;
617 zrouter
.mlag_info
.clients_interested_cnt
--;
618 hook_call(zebra_mlag_private_close_channel
);
626 void zebra_mlag_init(void)
628 zebra_mlag_vty_init();
631 * Intialiaze the MLAG Global variables
632 * write thread will be created during actual registration with MCLAG
634 zrouter
.mlag_info
.clients_interested_cnt
= 0;
635 zrouter
.mlag_info
.connected
= false;
636 zrouter
.mlag_info
.timer_running
= false;
637 zrouter
.mlag_info
.mlag_fifo
= stream_fifo_new();
638 zrouter
.mlag_info
.zebra_pth_mlag
= NULL
;
639 zrouter
.mlag_info
.th_master
= NULL
;
640 zrouter
.mlag_info
.t_read
= NULL
;
641 zrouter
.mlag_info
.t_write
= NULL
;
642 test_mlag_in_progress
= false;
643 zebra_mlag_reset_read_buffer();
646 void zebra_mlag_terminate(void)
653 * ProtoBuf Encoding APIs
658 DEFINE_MTYPE_STATIC(ZEBRA
, MLAG_PBUF
, "ZEBRA MLAG PROTOBUF")
660 int zebra_mlag_protobuf_encode_client_data(struct stream
*s
, uint32_t *msg_type
)
662 ZebraMlagHeader hdr
= ZEBRA_MLAG__HEADER__INIT
;
663 struct mlag_msg mlag_msg
;
664 uint8_t tmp_buf
[ZEBRA_MLAG_BUF_LIMIT
];
668 char buf
[ZLOG_FILTER_LENGTH_MAX
];
670 if (IS_ZEBRA_DEBUG_MLAG
)
671 zlog_debug("%s: Entering..", __func__
);
673 rc
= mlag_lib_decode_mlag_hdr(s
, &mlag_msg
);
677 if (IS_ZEBRA_DEBUG_MLAG
)
678 zlog_debug("%s: Mlag ProtoBuf encoding of message:%s, len:%d",
680 mlag_lib_msgid_to_str(mlag_msg
.msg_type
, buf
,
683 *msg_type
= mlag_msg
.msg_type
;
684 switch (mlag_msg
.msg_type
) {
685 case MLAG_MROUTE_ADD
: {
686 struct mlag_mroute_add msg
;
687 ZebraMlagMrouteAdd pay_load
= ZEBRA_MLAG_MROUTE_ADD__INIT
;
688 uint32_t vrf_name_len
= 0;
690 rc
= mlag_lib_decode_mroute_add(s
, &msg
);
693 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
694 pay_load
.vrf_name
= XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
695 strlcpy(pay_load
.vrf_name
, msg
.vrf_name
, vrf_name_len
);
696 pay_load
.source_ip
= msg
.source_ip
;
697 pay_load
.group_ip
= msg
.group_ip
;
698 pay_load
.cost_to_rp
= msg
.cost_to_rp
;
699 pay_load
.owner_id
= msg
.owner_id
;
700 pay_load
.am_i_dr
= msg
.am_i_dr
;
701 pay_load
.am_i_dual_active
= msg
.am_i_dual_active
;
702 pay_load
.vrf_id
= msg
.vrf_id
;
704 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
705 vrf_name_len
= strlen(msg
.intf_name
) + 1;
707 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
708 strlcpy(pay_load
.intf_name
, msg
.intf_name
,
712 len
= zebra_mlag_mroute_add__pack(&pay_load
, tmp_buf
);
713 XFREE(MTYPE_MLAG_PBUF
, pay_load
.vrf_name
);
714 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
)
715 XFREE(MTYPE_MLAG_PBUF
, pay_load
.intf_name
);
717 case MLAG_MROUTE_DEL
: {
718 struct mlag_mroute_del msg
;
719 ZebraMlagMrouteDel pay_load
= ZEBRA_MLAG_MROUTE_DEL__INIT
;
720 uint32_t vrf_name_len
= 0;
722 rc
= mlag_lib_decode_mroute_del(s
, &msg
);
725 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
726 pay_load
.vrf_name
= XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
727 strlcpy(pay_load
.vrf_name
, msg
.vrf_name
, vrf_name_len
);
728 pay_load
.source_ip
= msg
.source_ip
;
729 pay_load
.group_ip
= msg
.group_ip
;
730 pay_load
.owner_id
= msg
.owner_id
;
731 pay_load
.vrf_id
= msg
.vrf_id
;
733 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
734 vrf_name_len
= strlen(msg
.intf_name
) + 1;
736 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
737 strlcpy(pay_load
.intf_name
, msg
.intf_name
,
741 len
= zebra_mlag_mroute_del__pack(&pay_load
, tmp_buf
);
742 XFREE(MTYPE_MLAG_PBUF
, pay_load
.vrf_name
);
743 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
)
744 XFREE(MTYPE_MLAG_PBUF
, pay_load
.intf_name
);
746 case MLAG_MROUTE_ADD_BULK
: {
747 struct mlag_mroute_add msg
;
748 ZebraMlagMrouteAddBulk Bulk_msg
=
749 ZEBRA_MLAG_MROUTE_ADD_BULK__INIT
;
750 ZebraMlagMrouteAdd
**pay_load
= NULL
;
752 bool cleanup
= false;
754 Bulk_msg
.n_mroute_add
= mlag_msg
.msg_cnt
;
755 pay_load
= XMALLOC(MTYPE_MLAG_PBUF
, sizeof(ZebraMlagMrouteAdd
*)
758 for (i
= 0; i
< mlag_msg
.msg_cnt
; i
++) {
760 uint32_t vrf_name_len
= 0;
762 rc
= mlag_lib_decode_mroute_add(s
, &msg
);
767 pay_load
[i
] = XMALLOC(MTYPE_MLAG_PBUF
,
768 sizeof(ZebraMlagMrouteAdd
));
769 zebra_mlag_mroute_add__init(pay_load
[i
]);
771 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
772 pay_load
[i
]->vrf_name
=
773 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
774 strlcpy(pay_load
[i
]->vrf_name
, msg
.vrf_name
,
776 pay_load
[i
]->source_ip
= msg
.source_ip
;
777 pay_load
[i
]->group_ip
= msg
.group_ip
;
778 pay_load
[i
]->cost_to_rp
= msg
.cost_to_rp
;
779 pay_load
[i
]->owner_id
= msg
.owner_id
;
780 pay_load
[i
]->am_i_dr
= msg
.am_i_dr
;
781 pay_load
[i
]->am_i_dual_active
= msg
.am_i_dual_active
;
782 pay_load
[i
]->vrf_id
= msg
.vrf_id
;
783 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
784 vrf_name_len
= strlen(msg
.intf_name
) + 1;
785 pay_load
[i
]->intf_name
=
786 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
788 strlcpy(pay_load
[i
]->intf_name
, msg
.intf_name
,
792 if (cleanup
== false) {
793 Bulk_msg
.mroute_add
= pay_load
;
794 len
= zebra_mlag_mroute_add_bulk__pack(&Bulk_msg
,
798 for (i
= 0; i
< mlag_msg
.msg_cnt
; i
++) {
799 if (pay_load
[i
]->vrf_name
)
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
);
805 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]);
807 XFREE(MTYPE_MLAG_PBUF
, pay_load
);
811 case MLAG_MROUTE_DEL_BULK
: {
812 struct mlag_mroute_del msg
;
813 ZebraMlagMrouteDelBulk Bulk_msg
=
814 ZEBRA_MLAG_MROUTE_DEL_BULK__INIT
;
815 ZebraMlagMrouteDel
**pay_load
= NULL
;
817 bool cleanup
= false;
819 Bulk_msg
.n_mroute_del
= mlag_msg
.msg_cnt
;
820 pay_load
= XMALLOC(MTYPE_MLAG_PBUF
, sizeof(ZebraMlagMrouteDel
*)
823 for (i
= 0; i
< mlag_msg
.msg_cnt
; i
++) {
825 uint32_t vrf_name_len
= 0;
827 rc
= mlag_lib_decode_mroute_del(s
, &msg
);
833 pay_load
[i
] = XMALLOC(MTYPE_MLAG_PBUF
,
834 sizeof(ZebraMlagMrouteDel
));
835 zebra_mlag_mroute_del__init(pay_load
[i
]);
837 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
838 pay_load
[i
]->vrf_name
=
839 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
841 strlcpy(pay_load
[i
]->vrf_name
, msg
.vrf_name
,
843 pay_load
[i
]->source_ip
= msg
.source_ip
;
844 pay_load
[i
]->group_ip
= msg
.group_ip
;
845 pay_load
[i
]->owner_id
= msg
.owner_id
;
846 pay_load
[i
]->vrf_id
= msg
.vrf_id
;
847 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
848 vrf_name_len
= strlen(msg
.intf_name
) + 1;
849 pay_load
[i
]->intf_name
=
850 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
852 strlcpy(pay_load
[i
]->intf_name
, msg
.intf_name
,
857 Bulk_msg
.mroute_del
= pay_load
;
858 len
= zebra_mlag_mroute_del_bulk__pack(&Bulk_msg
,
862 for (i
= 0; i
< mlag_msg
.msg_cnt
; i
++) {
863 if (pay_load
[i
]->vrf_name
)
864 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->vrf_name
);
865 if (pay_load
[i
]->owner_id
== MLAG_OWNER_INTERFACE
866 && pay_load
[i
]->intf_name
)
867 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->intf_name
);
869 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]);
871 XFREE(MTYPE_MLAG_PBUF
, pay_load
);
879 if (IS_ZEBRA_DEBUG_MLAG
)
880 zlog_debug("%s: length of Mlag ProtoBuf encoded message:%s, %d",
882 mlag_lib_msgid_to_str(mlag_msg
.msg_type
, buf
,
885 hdr
.type
= (ZebraMlagHeader__MessageType
)mlag_msg
.msg_type
;
888 hdr
.data
.data
= XMALLOC(MTYPE_MLAG_PBUF
, len
);
889 memcpy(hdr
.data
.data
, tmp_buf
, len
);
893 * ProtoBuf Infra will not support to demarc the pointers whem multiple
894 * messages are posted inside a single Buffer.
895 * 2 -solutions exist to solve this
896 * 1. add Unenoced length at the beginning of every message, this will
897 * be used to point to next message in the buffer
898 * 2. another solution is defining all messages insides another message
899 * But this will permit only 32 messages. this can be extended with
901 * for simplicity we are going with solution-1.
903 len
= zebra_mlag__header__pack(&hdr
,
904 (mlag_wr_buffer
+ ZEBRA_MLAG_LEN_SIZE
));
906 memcpy(mlag_wr_buffer
, &n_len
, ZEBRA_MLAG_LEN_SIZE
);
907 len
+= ZEBRA_MLAG_LEN_SIZE
;
909 if (IS_ZEBRA_DEBUG_MLAG
)
911 "%s: length of Mlag ProtoBuf message:%s with Header %d",
913 mlag_lib_msgid_to_str(mlag_msg
.msg_type
, buf
,
917 XFREE(MTYPE_MLAG_PBUF
, hdr
.data
.data
);
922 int zebra_mlag_protobuf_decode_message(struct stream
*s
, uint8_t *data
,
926 ZebraMlagHeader
*hdr
;
929 hdr
= zebra_mlag__header__unpack(NULL
, len
, data
);
934 * ADD The MLAG Header
936 zclient_create_header(s
, ZEBRA_MLAG_FORWARD_MSG
, VRF_DEFAULT
);
938 msg_type
= hdr
->type
;
940 if (IS_ZEBRA_DEBUG_MLAG
)
941 zlog_debug("%s: Mlag ProtoBuf decoding of message:%s", __func__
,
942 mlag_lib_msgid_to_str(msg_type
, buf
, 80));
945 * Internal MLAG Message-types & MLAG.proto message types should
946 * always match, otherwise there can be decoding errors
947 * To avoid exposing clients with Protobuf flags, using internal
950 stream_putl(s
, hdr
->type
);
952 if (hdr
->data
.len
== 0) {
954 stream_putw(s
, MLAG_MSG_NULL_PAYLOAD
);
956 stream_putw(s
, MLAG_MSG_NO_BATCH
);
959 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_STATUS_UPDATE
: {
960 ZebraMlagStatusUpdate
*msg
= NULL
;
962 msg
= zebra_mlag_status_update__unpack(
963 NULL
, hdr
->data
.len
, hdr
->data
.data
);
965 zebra_mlag__header__free_unpacked(hdr
, NULL
);
969 stream_putw(s
, sizeof(struct mlag_status
));
971 stream_putw(s
, MLAG_MSG_NO_BATCH
);
973 stream_put(s
, msg
->peerlink
, INTERFACE_NAMSIZ
);
974 stream_putl(s
, msg
->my_role
);
975 stream_putl(s
, msg
->peer_state
);
976 zebra_mlag_status_update__free_unpacked(msg
, NULL
);
978 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_VXLAN_UPDATE
: {
979 ZebraMlagVxlanUpdate
*msg
= NULL
;
981 msg
= zebra_mlag_vxlan_update__unpack(
982 NULL
, hdr
->data
.len
, hdr
->data
.data
);
984 zebra_mlag__header__free_unpacked(hdr
, NULL
);
988 stream_putw(s
, sizeof(struct mlag_vxlan
));
990 stream_putw(s
, MLAG_MSG_NO_BATCH
);
992 stream_putl(s
, msg
->anycast_ip
);
993 stream_putl(s
, msg
->local_ip
);
994 zebra_mlag_vxlan_update__free_unpacked(msg
, NULL
);
996 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_ADD
: {
997 ZebraMlagMrouteAdd
*msg
= NULL
;
999 msg
= zebra_mlag_mroute_add__unpack(NULL
, hdr
->data
.len
,
1002 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1006 stream_putw(s
, sizeof(struct mlag_mroute_add
));
1008 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1010 stream_put(s
, msg
->vrf_name
, VRF_NAMSIZ
);
1012 stream_putl(s
, msg
->source_ip
);
1013 stream_putl(s
, msg
->group_ip
);
1014 stream_putl(s
, msg
->cost_to_rp
);
1015 stream_putl(s
, msg
->owner_id
);
1016 stream_putc(s
, msg
->am_i_dr
);
1017 stream_putc(s
, msg
->am_i_dual_active
);
1018 stream_putl(s
, msg
->vrf_id
);
1019 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1020 stream_put(s
, msg
->intf_name
, INTERFACE_NAMSIZ
);
1022 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1023 zebra_mlag_mroute_add__free_unpacked(msg
, NULL
);
1025 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_DEL
: {
1026 ZebraMlagMrouteDel
*msg
= NULL
;
1028 msg
= zebra_mlag_mroute_del__unpack(NULL
, hdr
->data
.len
,
1031 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1035 stream_putw(s
, sizeof(struct mlag_mroute_del
));
1037 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1039 stream_put(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
->group_ip
);
1044 stream_putl(s
, msg
->owner_id
);
1045 stream_putl(s
, msg
->vrf_id
);
1046 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1047 stream_put(s
, msg
->intf_name
, INTERFACE_NAMSIZ
);
1049 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1050 zebra_mlag_mroute_del__free_unpacked(msg
, NULL
);
1052 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_ADD_BULK
: {
1053 ZebraMlagMrouteAddBulk
*Bulk_msg
= NULL
;
1054 ZebraMlagMrouteAdd
*msg
= NULL
;
1057 Bulk_msg
= zebra_mlag_mroute_add_bulk__unpack(
1058 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1059 if (Bulk_msg
== NULL
) {
1060 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1064 stream_putw(s
, (Bulk_msg
->n_mroute_add
1065 * sizeof(struct mlag_mroute_add
)));
1066 /* No. of msgs in Batch */
1067 stream_putw(s
, Bulk_msg
->n_mroute_add
);
1070 for (i
= 0; i
< Bulk_msg
->n_mroute_add
; i
++) {
1072 msg
= Bulk_msg
->mroute_add
[i
];
1074 stream_put(s
, msg
->vrf_name
, VRF_NAMSIZ
);
1075 stream_putl(s
, msg
->source_ip
);
1076 stream_putl(s
, msg
->group_ip
);
1077 stream_putl(s
, msg
->cost_to_rp
);
1078 stream_putl(s
, msg
->owner_id
);
1079 stream_putc(s
, msg
->am_i_dr
);
1080 stream_putc(s
, msg
->am_i_dual_active
);
1081 stream_putl(s
, msg
->vrf_id
);
1082 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1083 stream_put(s
, msg
->intf_name
,
1086 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1088 zebra_mlag_mroute_add_bulk__free_unpacked(Bulk_msg
,
1091 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_DEL_BULK
: {
1092 ZebraMlagMrouteDelBulk
*Bulk_msg
= NULL
;
1093 ZebraMlagMrouteDel
*msg
= NULL
;
1096 Bulk_msg
= zebra_mlag_mroute_del_bulk__unpack(
1097 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1098 if (Bulk_msg
== NULL
) {
1099 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1103 stream_putw(s
, (Bulk_msg
->n_mroute_del
1104 * sizeof(struct mlag_mroute_del
)));
1105 /* No. of msgs in Batch */
1106 stream_putw(s
, Bulk_msg
->n_mroute_del
);
1109 for (i
= 0; i
< Bulk_msg
->n_mroute_del
; i
++) {
1111 msg
= Bulk_msg
->mroute_del
[i
];
1113 stream_put(s
, msg
->vrf_name
, VRF_NAMSIZ
);
1114 stream_putl(s
, msg
->source_ip
);
1115 stream_putl(s
, msg
->group_ip
);
1116 stream_putl(s
, msg
->owner_id
);
1117 stream_putl(s
, msg
->vrf_id
);
1118 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1119 stream_put(s
, msg
->intf_name
,
1122 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1124 zebra_mlag_mroute_del_bulk__free_unpacked(Bulk_msg
,
1127 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_ZEBRA_STATUS_UPDATE
: {
1128 ZebraMlagZebraStatusUpdate
*msg
= NULL
;
1130 msg
= zebra_mlag_zebra_status_update__unpack(
1131 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1133 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1137 stream_putw(s
, sizeof(struct mlag_frr_status
));
1139 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1141 stream_putl(s
, msg
->peer_frrstate
);
1142 zebra_mlag_zebra_status_update__free_unpacked(msg
,
1149 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1154 int zebra_mlag_protobuf_encode_client_data(struct stream
*s
, uint32_t *msg_type
)
1159 int zebra_mlag_protobuf_decode_message(struct stream
*s
, uint8_t *data
,