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
];
52 uint32_t mlag_rd_buf_offset
;
54 static bool test_mlag_in_progress
;
56 static int zebra_mlag_signal_write_thread(void);
57 static int zebra_mlag_terminate_pthread(struct thread
*event
);
58 static int zebra_mlag_post_data_from_main_thread(struct thread
*thread
);
59 static void zebra_mlag_publish_process_state(struct zserv
*client
,
60 zebra_message_types_t msg_type
);
62 /**********************MLAG Interaction***************************************/
65 * API to post the Registration to MLAGD
66 * MLAG will not process any messages with out the registration
68 void zebra_mlag_send_register(void)
70 struct stream
*s
= NULL
;
72 s
= stream_new(sizeof(struct mlag_msg
));
74 stream_putl(s
, MLAG_REGISTER
);
75 stream_putw(s
, MLAG_MSG_NULL_PAYLOAD
);
76 stream_putw(s
, MLAG_MSG_NO_BATCH
);
77 stream_fifo_push_safe(zrouter
.mlag_info
.mlag_fifo
, s
);
78 zebra_mlag_signal_write_thread();
80 if (IS_ZEBRA_DEBUG_MLAG
)
81 zlog_debug("%s: Enqueued MLAG Register to MLAG Thread ",
86 * API to post the De-Registration to MLAGD
87 * MLAG will not process any messages after the de-registration
89 void zebra_mlag_send_deregister(void)
91 struct stream
*s
= NULL
;
93 s
= stream_new(sizeof(struct mlag_msg
));
95 stream_putl(s
, MLAG_DEREGISTER
);
96 stream_putw(s
, MLAG_MSG_NULL_PAYLOAD
);
97 stream_putw(s
, MLAG_MSG_NO_BATCH
);
98 stream_fifo_push_safe(zrouter
.mlag_info
.mlag_fifo
, s
);
99 zebra_mlag_signal_write_thread();
101 if (IS_ZEBRA_DEBUG_MLAG
)
102 zlog_debug("%s: Enqueued MLAG De-Register to MLAG Thread ",
107 * API To handle MLAG Received data
108 * Decodes the data using protobuf and enqueue to main thread
109 * main thread publish this to clients based on client subscription
111 void zebra_mlag_process_mlag_data(uint8_t *data
, uint32_t len
)
113 struct stream
*s
= NULL
;
114 struct stream
*s1
= NULL
;
117 s
= stream_new(ZEBRA_MAX_PACKET_SIZ
);
118 msg_type
= zebra_mlag_protobuf_decode_message(s
, data
, len
);
121 /* Something went wrong in decoding */
123 zlog_err("%s: failed to process mlag data-%d, %u", __func__
,
129 * additional four bytes are for message type
131 s1
= stream_new(stream_get_endp(s
) + ZEBRA_MLAG_METADATA_LEN
);
132 stream_putl(s1
, msg_type
);
133 stream_put(s1
, s
->data
, stream_get_endp(s
));
134 thread_add_event(zrouter
.master
, zebra_mlag_post_data_from_main_thread
,
139 /**********************End of MLAG Interaction********************************/
141 /************************MLAG Thread Processing*******************************/
144 * after posting every 'ZEBRA_MLAG_POST_LIMIT' packets, MLAG Thread will be
145 * yielded to give CPU for other threads
147 #define ZEBRA_MLAG_POST_LIMIT 100
150 * This thread reads the clients data from the Global queue and encodes with
151 * protobuf and pass on to the MLAG socket.
153 static int zebra_mlag_client_msg_handler(struct thread
*event
)
156 uint32_t wr_count
= 0;
157 uint32_t msg_type
= 0;
158 uint32_t max_count
= 0;
161 wr_count
= stream_fifo_count_safe(zrouter
.mlag_info
.mlag_fifo
);
162 if (IS_ZEBRA_DEBUG_MLAG
)
163 zlog_debug(":%s: Processing MLAG write, %u messages in queue",
166 max_count
= MIN(wr_count
, ZEBRA_MLAG_POST_LIMIT
);
168 for (wr_count
= 0; wr_count
< max_count
; wr_count
++) {
169 s
= stream_fifo_pop_safe(zrouter
.mlag_info
.mlag_fifo
);
171 zlog_debug(":%s: Got a NULL Messages, some thing wrong",
177 * Encode the data now
179 len
= zebra_mlag_protobuf_encode_client_data(s
, &msg_type
);
185 hook_call(zebra_mlag_private_write_data
,
186 mlag_wr_buffer
, len
);
189 * If message type is De-register, send a signal to main
190 * thread, so that necessary cleanup will be done by
193 if (msg_type
== MLAG_DEREGISTER
) {
194 thread_add_event(zrouter
.master
,
195 zebra_mlag_terminate_pthread
,
203 if (IS_ZEBRA_DEBUG_MLAG
)
204 zlog_debug(":%s: Posted %d messages to MLAGD", __func__
,
207 * Currently there is only message write task is enqueued to this
208 * thread, yielding was added for future purpose, so that this thread
209 * can server other tasks also and in case FIFO is empty, this task will
210 * be schedule when main thread adds some messages
212 if (wr_count
>= ZEBRA_MLAG_POST_LIMIT
)
213 zebra_mlag_signal_write_thread();
218 * API to handle the process state.
219 * In case of Down, Zebra keep monitoring the MLAG state.
220 * all the state Notifications will be published to clients
222 void zebra_mlag_handle_process_state(enum zebra_mlag_state state
)
224 if (state
== MLAG_UP
) {
225 zrouter
.mlag_info
.connected
= true;
226 zebra_mlag_publish_process_state(NULL
, ZEBRA_MLAG_PROCESS_UP
);
227 zebra_mlag_send_register();
228 } else if (state
== MLAG_DOWN
) {
229 zrouter
.mlag_info
.connected
= false;
230 zebra_mlag_publish_process_state(NULL
, ZEBRA_MLAG_PROCESS_DOWN
);
231 hook_call(zebra_mlag_private_monitor_state
);
235 /***********************End of MLAG Thread processing*************************/
237 /*************************Multi-entratnt Api's********************************/
240 * Provider api to signal that work/events are available
241 * for the Zebra MLAG Write pthread.
242 * This API is called from 2 pthreads..
243 * 1) by main thread when client posts a MLAG Message
244 * 2) by MLAG Thread, in case of yield
245 * though this api, is called from two threads we don't need any locking
246 * because Thread task enqueue is thread safe means internally it had
247 * necessary protection
249 static int zebra_mlag_signal_write_thread(void)
251 if (IS_ZEBRA_DEBUG_MLAG
)
252 zlog_debug(":%s: Scheduling MLAG write", __func__
);
254 * This api will be called from Both main & MLAG Threads.
255 * main thread writes, "zrouter.mlag_info.th_master" only
256 * during Zebra Init/after MLAG thread is destroyed.
257 * so it is safe to use without any locking
259 thread_add_event(zrouter
.mlag_info
.th_master
,
260 zebra_mlag_client_msg_handler
, NULL
, 0,
261 &zrouter
.mlag_info
.t_write
);
266 * API will be used to publish the MLAG state to interested clients
267 * In case client is passed, state is posted only for that client,
268 * otherwise to all interested clients
269 * this api can be called from two threads.
270 * 1) from main thread: when client is passed
271 * 2) from MLAG Thread: when client is NULL
273 * In second case, to avoid global data access data will be post to Main
274 * thread, so that actual posting to clients will happen from Main thread.
276 static void zebra_mlag_publish_process_state(struct zserv
*client
,
277 zebra_message_types_t msg_type
)
281 if (IS_ZEBRA_DEBUG_MLAG
)
282 zlog_debug("%s: Publishing MLAG process state:%s to %s Client",
284 (msg_type
== ZEBRA_MLAG_PROCESS_UP
) ? "UP" : "DOWN",
285 (client
) ? "one" : "all");
288 s
= stream_new(ZEBRA_HEADER_SIZE
);
289 zclient_create_header(s
, msg_type
, VRF_DEFAULT
);
290 zserv_send_message(client
, s
);
296 * additional four bytes are for mesasge type
298 s
= stream_new(ZEBRA_HEADER_SIZE
+ ZEBRA_MLAG_METADATA_LEN
);
299 stream_putl(s
, ZEBRA_MLAG_MSG_BCAST
);
300 zclient_create_header(s
, msg_type
, VRF_DEFAULT
);
301 thread_add_event(zrouter
.master
, zebra_mlag_post_data_from_main_thread
,
305 /**************************End of Multi-entrant Apis**************************/
307 /***********************Zebra Main thread processing**************************/
310 * To avoid data corruption, messages will be post to clients only from
311 * main thread, because for that access was needed for clients list.
312 * so instead of forcing the locks, messages will be posted from main thread.
314 static int zebra_mlag_post_data_from_main_thread(struct thread
*thread
)
316 struct stream
*s
= THREAD_ARG(thread
);
317 struct stream
*zebra_s
= NULL
;
318 struct listnode
*node
;
319 struct zserv
*client
;
320 uint32_t msg_type
= 0;
321 uint32_t msg_len
= 0;
326 STREAM_GETL(s
, msg_type
);
327 if (IS_ZEBRA_DEBUG_MLAG
)
329 "%s: Posting MLAG data for msg_type:0x%x to interested clients",
332 msg_len
= s
->endp
- ZEBRA_MLAG_METADATA_LEN
;
333 for (ALL_LIST_ELEMENTS_RO(zrouter
.client_list
, node
, client
)) {
334 if (client
->mlag_updates_interested
== true) {
335 if (msg_type
!= ZEBRA_MLAG_MSG_BCAST
336 && !CHECK_FLAG(client
->mlag_reg_mask1
,
341 if (IS_ZEBRA_DEBUG_MLAG
)
343 "%s: Posting MLAG data of length-%d to client:%d ",
344 __func__
, msg_len
, client
->proto
);
346 zebra_s
= stream_new(msg_len
);
347 STREAM_GET(zebra_s
->data
, s
, msg_len
);
348 zebra_s
->endp
= msg_len
;
349 stream_putw_at(zebra_s
, 0, msg_len
);
352 * This stream will be enqueued to client_obuf, it will
353 * be freed after posting to client socket.
355 zserv_send_message(client
, zebra_s
);
365 stream_free(zebra_s
);
370 * Start the MLAG Thread, this will be used to write client data on to
371 * MLAG Process and to read the data from MLAG and post to clients.
372 * when all clients are un-registered, this Thread will be
375 static void zebra_mlag_spawn_pthread(void)
377 /* Start MLAG write pthread */
379 struct frr_pthread_attr pattr
= {.start
=
380 frr_pthread_attr_default
.start
,
381 .stop
= frr_pthread_attr_default
.stop
};
383 zrouter
.mlag_info
.zebra_pth_mlag
=
384 frr_pthread_new(&pattr
, "Zebra MLAG thread", "Zebra MLAG");
386 zrouter
.mlag_info
.th_master
= zrouter
.mlag_info
.zebra_pth_mlag
->master
;
389 /* Enqueue an initial event to the Newly spawn MLAG pthread */
390 zebra_mlag_signal_write_thread();
392 frr_pthread_run(zrouter
.mlag_info
.zebra_pth_mlag
, NULL
);
396 * all clients are un-registered for MLAG Updates, terminate the
399 static int zebra_mlag_terminate_pthread(struct thread
*event
)
401 if (IS_ZEBRA_DEBUG_MLAG
)
402 zlog_debug("Zebra MLAG write thread terminate called");
404 if (zrouter
.mlag_info
.clients_interested_cnt
) {
405 if (IS_ZEBRA_DEBUG_MLAG
)
407 "Zebra MLAG: still some clients are interested");
411 frr_pthread_stop(zrouter
.mlag_info
.zebra_pth_mlag
, NULL
);
413 /* Destroy pthread */
414 frr_pthread_destroy(zrouter
.mlag_info
.zebra_pth_mlag
);
415 zrouter
.mlag_info
.zebra_pth_mlag
= NULL
;
416 zrouter
.mlag_info
.th_master
= NULL
;
417 zrouter
.mlag_info
.t_read
= NULL
;
418 zrouter
.mlag_info
.t_write
= NULL
;
421 * Send Notification to clean private data
423 hook_call(zebra_mlag_private_cleanup_data
);
428 * API to register zebra client for MLAG Updates
430 void zebra_mlag_client_register(ZAPI_HANDLER_ARGS
)
433 uint32_t reg_mask
= 0;
436 if (IS_ZEBRA_DEBUG_MLAG
)
437 zlog_debug("Received MLAG Registration from client-proto:%d",
441 /* Get input stream. */
445 STREAM_GETL(s
, reg_mask
);
447 if (client
->mlag_updates_interested
== true) {
449 if (IS_ZEBRA_DEBUG_MLAG
)
451 "Client is registered, existing mask: 0x%x, new mask: 0x%x",
452 client
->mlag_reg_mask1
, reg_mask
);
453 if (client
->mlag_reg_mask1
!= reg_mask
)
454 client
->mlag_reg_mask1
= reg_mask
;
456 * Client might missed MLAG-UP Notification, post-it again
458 zebra_mlag_publish_process_state(client
, ZEBRA_MLAG_PROCESS_UP
);
463 client
->mlag_updates_interested
= true;
464 client
->mlag_reg_mask1
= reg_mask
;
465 if (IS_ZEBRA_DEBUG_MLAG
)
466 zlog_debug("Registering for MLAG Updates with mask: 0x%x, ",
467 client
->mlag_reg_mask1
);
469 zrouter
.mlag_info
.clients_interested_cnt
++;
471 if (zrouter
.mlag_info
.clients_interested_cnt
== 1) {
473 * First-client for MLAG Updates,open the communication channel
476 if (IS_ZEBRA_DEBUG_MLAG
)
478 "First client, opening the channel with MLAG");
480 zebra_mlag_spawn_pthread();
481 rc
= hook_call(zebra_mlag_private_open_channel
);
484 * For some reason, zebra not able to open the
485 * comm-channel with MLAG, so post MLAG-DOWN to client.
486 * later when the channel is open, zebra will send
489 if (IS_ZEBRA_DEBUG_MLAG
)
491 "Fail to open channel with MLAG,rc:%d, post Proto-down",
493 zebra_mlag_publish_process_state(
494 client
, ZEBRA_MLAG_PROCESS_DOWN
);
498 if (IS_ZEBRA_DEBUG_MLAG
)
499 zlog_debug("Client Registered successfully for MLAG Updates");
501 if (zrouter
.mlag_info
.connected
== true)
502 zebra_mlag_publish_process_state(client
, ZEBRA_MLAG_PROCESS_UP
);
508 * API to un-register for MLAG Updates
510 void zebra_mlag_client_unregister(ZAPI_HANDLER_ARGS
)
512 if (IS_ZEBRA_DEBUG_MLAG
)
513 zlog_debug("Received MLAG De-Registration from client-proto:%d",
516 if (client
->mlag_updates_interested
== false)
520 client
->mlag_updates_interested
= false;
521 client
->mlag_reg_mask1
= 0;
522 zrouter
.mlag_info
.clients_interested_cnt
--;
524 if (zrouter
.mlag_info
.clients_interested_cnt
== 0) {
526 * No-client is interested for MLAG Updates,close the
527 * communication channel with MLAG
529 if (IS_ZEBRA_DEBUG_MLAG
)
530 zlog_debug("Last client for MLAG, close the channel ");
535 * 1) main thread calls socket close which posts De-register
536 * to MLAG write thread
537 * 2) after MLAG write thread posts De-register it sends a
538 * signal back to main thread to do the thread cleanup
539 * this was mainly to make sure De-register is posted to MCLAGD.
541 hook_call(zebra_mlag_private_close_channel
);
544 if (IS_ZEBRA_DEBUG_MLAG
)
546 "Client De-Registered successfully for MLAG Updates");
550 * Does following things.
551 * 1) allocated new local stream, and copies the client data and enqueue
553 * 2) MLAG Thread after dequeing, encode the client data using protobuf
554 * and write on to MLAG
556 void zebra_mlag_forward_client_msg(ZAPI_HANDLER_ARGS
)
558 struct stream
*zebra_s
;
559 struct stream
*mlag_s
;
561 if (IS_ZEBRA_DEBUG_MLAG
)
562 zlog_debug("Received Client MLAG Data from client-proto:%d",
565 /* Get input stream. */
567 mlag_s
= stream_new(zebra_s
->endp
);
570 * Client data is | Zebra Header + MLAG Data |
571 * we need to enqueue only the MLAG data, skipping Zebra Header
573 stream_put(mlag_s
, zebra_s
->data
+ zebra_s
->getp
,
574 STREAM_READABLE(zebra_s
));
575 stream_fifo_push_safe(zrouter
.mlag_info
.mlag_fifo
, mlag_s
);
576 zebra_mlag_signal_write_thread();
578 if (IS_ZEBRA_DEBUG_MLAG
)
579 zlog_debug("%s: Enqueued Client:%d data to MLAG Thread ",
580 __func__
, client
->proto
);
583 /***********************End of Zebra Main thread processing*************/
585 enum mlag_role
zebra_mlag_get_role(void)
587 return zrouter
.mlag_info
.role
;
590 int32_t zebra_mlag_test_mlag_internal(const char *none
, const char *primary
,
591 const char *secondary
)
593 enum mlag_role orig
= zrouter
.mlag_info
.role
;
594 char buf1
[MLAG_ROLE_STRSIZE
], buf2
[MLAG_ROLE_STRSIZE
];
597 zrouter
.mlag_info
.role
= MLAG_ROLE_NONE
;
599 zrouter
.mlag_info
.role
= MLAG_ROLE_PRIMARY
;
601 zrouter
.mlag_info
.role
= MLAG_ROLE_SECONDARY
;
603 if (IS_ZEBRA_DEBUG_MLAG
)
604 zlog_debug("Test: Changing role from %s to %s",
605 mlag_role2str(orig
, buf1
, sizeof(buf1
)),
606 mlag_role2str(orig
, buf2
, sizeof(buf2
)));
608 if (orig
!= zrouter
.mlag_info
.role
) {
609 zsend_capabilities_all_clients();
610 if (zrouter
.mlag_info
.role
!= MLAG_ROLE_NONE
) {
611 if (zrouter
.mlag_info
.clients_interested_cnt
== 0
612 && !test_mlag_in_progress
) {
613 if (zrouter
.mlag_info
.zebra_pth_mlag
== NULL
)
614 zebra_mlag_spawn_pthread();
615 zrouter
.mlag_info
.clients_interested_cnt
++;
616 test_mlag_in_progress
= true;
617 hook_call(zebra_mlag_private_open_channel
);
620 if (test_mlag_in_progress
) {
621 test_mlag_in_progress
= false;
622 zrouter
.mlag_info
.clients_interested_cnt
--;
623 hook_call(zebra_mlag_private_close_channel
);
631 void zebra_mlag_init(void)
633 zebra_mlag_vty_init();
636 * Intialiaze the MLAG Global variables
637 * write thread will be created during actual registration with MCLAG
639 zrouter
.mlag_info
.clients_interested_cnt
= 0;
640 zrouter
.mlag_info
.connected
= false;
641 zrouter
.mlag_info
.timer_running
= false;
642 zrouter
.mlag_info
.mlag_fifo
= stream_fifo_new();
643 zrouter
.mlag_info
.zebra_pth_mlag
= NULL
;
644 zrouter
.mlag_info
.th_master
= NULL
;
645 zrouter
.mlag_info
.t_read
= NULL
;
646 zrouter
.mlag_info
.t_write
= NULL
;
647 test_mlag_in_progress
= false;
648 zebra_mlag_reset_read_buffer();
651 void zebra_mlag_terminate(void)
658 * ProtoBuf Encoding APIs
661 #ifdef HAVE_PROTOBUF_VERSION_3
663 DEFINE_MTYPE_STATIC(ZEBRA
, MLAG_PBUF
, "ZEBRA MLAG PROTOBUF")
665 int zebra_mlag_protobuf_encode_client_data(struct stream
*s
, uint32_t *msg_type
)
667 ZebraMlagHeader hdr
= ZEBRA_MLAG__HEADER__INIT
;
668 struct mlag_msg mlag_msg
;
669 uint8_t tmp_buf
[ZEBRA_MLAG_BUF_LIMIT
];
673 char buf
[ZLOG_FILTER_LENGTH_MAX
];
676 if (IS_ZEBRA_DEBUG_MLAG
)
677 zlog_debug("%s: Entering..", __func__
);
679 rc
= mlag_lib_decode_mlag_hdr(s
, &mlag_msg
, &length
);
683 memset(tmp_buf
, 0, ZEBRA_MLAG_BUF_LIMIT
);
685 if (IS_ZEBRA_DEBUG_MLAG
)
686 zlog_debug("%s: Mlag ProtoBuf encoding of message:%s, len:%d",
688 mlag_lib_msgid_to_str(mlag_msg
.msg_type
, buf
,
691 *msg_type
= mlag_msg
.msg_type
;
692 switch (mlag_msg
.msg_type
) {
693 case MLAG_MROUTE_ADD
: {
694 struct mlag_mroute_add msg
;
695 ZebraMlagMrouteAdd pay_load
= ZEBRA_MLAG_MROUTE_ADD__INIT
;
696 uint32_t vrf_name_len
= 0;
698 rc
= mlag_lib_decode_mroute_add(s
, &msg
, &length
);
702 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
703 pay_load
.vrf_name
= XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
704 strlcpy(pay_load
.vrf_name
, msg
.vrf_name
, vrf_name_len
);
705 pay_load
.source_ip
= msg
.source_ip
;
706 pay_load
.group_ip
= msg
.group_ip
;
707 pay_load
.cost_to_rp
= msg
.cost_to_rp
;
708 pay_load
.owner_id
= msg
.owner_id
;
709 pay_load
.am_i_dr
= msg
.am_i_dr
;
710 pay_load
.am_i_dual_active
= msg
.am_i_dual_active
;
711 pay_load
.vrf_id
= msg
.vrf_id
;
713 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
714 vrf_name_len
= strlen(msg
.intf_name
) + 1;
716 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
717 strlcpy(pay_load
.intf_name
, msg
.intf_name
,
721 len
= zebra_mlag_mroute_add__pack(&pay_load
, tmp_buf
);
722 XFREE(MTYPE_MLAG_PBUF
, pay_load
.vrf_name
);
723 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
)
724 XFREE(MTYPE_MLAG_PBUF
, pay_load
.intf_name
);
726 case MLAG_MROUTE_DEL
: {
727 struct mlag_mroute_del msg
;
728 ZebraMlagMrouteDel pay_load
= ZEBRA_MLAG_MROUTE_DEL__INIT
;
729 uint32_t vrf_name_len
= 0;
731 rc
= mlag_lib_decode_mroute_del(s
, &msg
, &length
);
734 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
735 pay_load
.vrf_name
= XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
736 strlcpy(pay_load
.vrf_name
, msg
.vrf_name
, vrf_name_len
);
737 pay_load
.source_ip
= msg
.source_ip
;
738 pay_load
.group_ip
= msg
.group_ip
;
739 pay_load
.owner_id
= msg
.owner_id
;
740 pay_load
.vrf_id
= msg
.vrf_id
;
742 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
743 vrf_name_len
= strlen(msg
.intf_name
) + 1;
745 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
746 strlcpy(pay_load
.intf_name
, msg
.intf_name
,
750 len
= zebra_mlag_mroute_del__pack(&pay_load
, tmp_buf
);
751 XFREE(MTYPE_MLAG_PBUF
, pay_load
.vrf_name
);
752 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
)
753 XFREE(MTYPE_MLAG_PBUF
, pay_load
.intf_name
);
755 case MLAG_MROUTE_ADD_BULK
: {
756 struct mlag_mroute_add msg
;
757 ZebraMlagMrouteAddBulk Bulk_msg
=
758 ZEBRA_MLAG_MROUTE_ADD_BULK__INIT
;
759 ZebraMlagMrouteAdd
**pay_load
= NULL
;
760 bool cleanup
= false;
763 Bulk_msg
.n_mroute_add
= mlag_msg
.msg_cnt
;
764 pay_load
= XMALLOC(MTYPE_MLAG_PBUF
, sizeof(ZebraMlagMrouteAdd
*)
767 for (i
= 0, actual
= 0; i
< mlag_msg
.msg_cnt
; i
++, actual
++) {
769 uint32_t vrf_name_len
= 0;
771 rc
= mlag_lib_decode_mroute_add(s
, &msg
, &length
);
776 pay_load
[i
] = XMALLOC(MTYPE_MLAG_PBUF
,
777 sizeof(ZebraMlagMrouteAdd
));
778 zebra_mlag_mroute_add__init(pay_load
[i
]);
780 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
781 pay_load
[i
]->vrf_name
=
782 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
783 strlcpy(pay_load
[i
]->vrf_name
, msg
.vrf_name
,
785 pay_load
[i
]->source_ip
= msg
.source_ip
;
786 pay_load
[i
]->group_ip
= msg
.group_ip
;
787 pay_load
[i
]->cost_to_rp
= msg
.cost_to_rp
;
788 pay_load
[i
]->owner_id
= msg
.owner_id
;
789 pay_load
[i
]->am_i_dr
= msg
.am_i_dr
;
790 pay_load
[i
]->am_i_dual_active
= msg
.am_i_dual_active
;
791 pay_load
[i
]->vrf_id
= msg
.vrf_id
;
792 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
793 vrf_name_len
= strlen(msg
.intf_name
) + 1;
794 pay_load
[i
]->intf_name
=
795 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
797 strlcpy(pay_load
[i
]->intf_name
, msg
.intf_name
,
802 Bulk_msg
.mroute_add
= pay_load
;
803 len
= zebra_mlag_mroute_add_bulk__pack(&Bulk_msg
,
807 for (i
= 0; i
< actual
; i
++) {
809 * The mlag_lib_decode_mroute_add can
810 * fail to properly decode and cause nothing
811 * to be allocated. Prevent a crash
816 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->vrf_name
);
817 if (pay_load
[i
]->owner_id
== MLAG_OWNER_INTERFACE
818 && pay_load
[i
]->intf_name
)
819 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->intf_name
);
820 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]);
822 XFREE(MTYPE_MLAG_PBUF
, pay_load
);
826 case MLAG_MROUTE_DEL_BULK
: {
827 struct mlag_mroute_del msg
;
828 ZebraMlagMrouteDelBulk Bulk_msg
=
829 ZEBRA_MLAG_MROUTE_DEL_BULK__INIT
;
830 ZebraMlagMrouteDel
**pay_load
= NULL
;
831 bool cleanup
= false;
834 Bulk_msg
.n_mroute_del
= mlag_msg
.msg_cnt
;
835 pay_load
= XMALLOC(MTYPE_MLAG_PBUF
, sizeof(ZebraMlagMrouteDel
*)
838 for (i
= 0, actual
= 0; i
< mlag_msg
.msg_cnt
; i
++, actual
++) {
840 uint32_t vrf_name_len
= 0;
842 rc
= mlag_lib_decode_mroute_del(s
, &msg
, &length
);
848 pay_load
[i
] = XMALLOC(MTYPE_MLAG_PBUF
,
849 sizeof(ZebraMlagMrouteDel
));
850 zebra_mlag_mroute_del__init(pay_load
[i
]);
852 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
853 pay_load
[i
]->vrf_name
=
854 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
856 strlcpy(pay_load
[i
]->vrf_name
, msg
.vrf_name
,
858 pay_load
[i
]->source_ip
= msg
.source_ip
;
859 pay_load
[i
]->group_ip
= msg
.group_ip
;
860 pay_load
[i
]->owner_id
= msg
.owner_id
;
861 pay_load
[i
]->vrf_id
= msg
.vrf_id
;
862 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
863 vrf_name_len
= strlen(msg
.intf_name
) + 1;
864 pay_load
[i
]->intf_name
=
865 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
867 strlcpy(pay_load
[i
]->intf_name
, msg
.intf_name
,
872 Bulk_msg
.mroute_del
= pay_load
;
873 len
= zebra_mlag_mroute_del_bulk__pack(&Bulk_msg
,
877 for (i
= 0; i
< actual
; i
++) {
879 * The mlag_lib_decode_mroute_add can
880 * fail to properly decode and cause nothing
881 * to be allocated. Prevent a crash
886 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->vrf_name
);
887 if (pay_load
[i
]->owner_id
== MLAG_OWNER_INTERFACE
888 && pay_load
[i
]->intf_name
)
889 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->intf_name
);
890 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]);
892 XFREE(MTYPE_MLAG_PBUF
, pay_load
);
900 if (IS_ZEBRA_DEBUG_MLAG
)
901 zlog_debug("%s: length of Mlag ProtoBuf encoded message:%s, %d",
903 mlag_lib_msgid_to_str(mlag_msg
.msg_type
, buf
,
906 hdr
.type
= (ZebraMlagHeader__MessageType
)mlag_msg
.msg_type
;
909 hdr
.data
.data
= XMALLOC(MTYPE_MLAG_PBUF
, len
);
910 memcpy(hdr
.data
.data
, tmp_buf
, len
);
914 * ProtoBuf Infra will not support to demarc the pointers whem multiple
915 * messages are posted inside a single Buffer.
916 * 2 -solutions exist to solve this
917 * 1. add Unenoced length at the beginning of every message, this will
918 * be used to point to next message in the buffer
919 * 2. another solution is defining all messages insides another message
920 * But this will permit only 32 messages. this can be extended with
922 * for simplicity we are going with solution-1.
924 len
= zebra_mlag__header__pack(&hdr
,
925 (mlag_wr_buffer
+ ZEBRA_MLAG_LEN_SIZE
));
927 memcpy(mlag_wr_buffer
, &n_len
, ZEBRA_MLAG_LEN_SIZE
);
928 len
+= ZEBRA_MLAG_LEN_SIZE
;
930 if (IS_ZEBRA_DEBUG_MLAG
)
932 "%s: length of Mlag ProtoBuf message:%s with Header %d",
934 mlag_lib_msgid_to_str(mlag_msg
.msg_type
, buf
,
937 XFREE(MTYPE_MLAG_PBUF
, hdr
.data
.data
);
942 static void zebra_fill_protobuf_msg(struct stream
*s
, char *name
, int len
)
944 int str_len
= strlen(name
) + 1;
946 stream_put(s
, name
, str_len
);
947 /* Fill the rest with Null Character for aligning */
948 stream_put(s
, NULL
, len
- str_len
);
951 int zebra_mlag_protobuf_decode_message(struct stream
*s
, uint8_t *data
,
955 ZebraMlagHeader
*hdr
;
958 hdr
= zebra_mlag__header__unpack(NULL
, len
, data
);
963 * ADD The MLAG Header
965 zclient_create_header(s
, ZEBRA_MLAG_FORWARD_MSG
, VRF_DEFAULT
);
967 msg_type
= hdr
->type
;
969 if (IS_ZEBRA_DEBUG_MLAG
)
970 zlog_debug("%s: Mlag ProtoBuf decoding of message:%s", __func__
,
971 mlag_lib_msgid_to_str(msg_type
, buf
, 80));
974 * Internal MLAG Message-types & MLAG.proto message types should
975 * always match, otherwise there can be decoding errors
976 * To avoid exposing clients with Protobuf flags, using internal
979 stream_putl(s
, hdr
->type
);
981 if (hdr
->data
.len
== 0) {
983 stream_putw(s
, MLAG_MSG_NULL_PAYLOAD
);
985 stream_putw(s
, MLAG_MSG_NO_BATCH
);
988 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_STATUS_UPDATE
: {
989 ZebraMlagStatusUpdate
*msg
= NULL
;
991 msg
= zebra_mlag_status_update__unpack(
992 NULL
, hdr
->data
.len
, hdr
->data
.data
);
994 zebra_mlag__header__free_unpacked(hdr
, NULL
);
998 stream_putw(s
, sizeof(struct mlag_status
));
1000 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1002 zebra_fill_protobuf_msg(s
, msg
->peerlink
,
1004 stream_putl(s
, msg
->my_role
);
1005 stream_putl(s
, msg
->peer_state
);
1006 zebra_mlag_status_update__free_unpacked(msg
, NULL
);
1008 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_VXLAN_UPDATE
: {
1009 ZebraMlagVxlanUpdate
*msg
= NULL
;
1011 msg
= zebra_mlag_vxlan_update__unpack(
1012 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1014 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1018 stream_putw(s
, sizeof(struct mlag_vxlan
));
1020 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1022 stream_putl(s
, msg
->anycast_ip
);
1023 stream_putl(s
, msg
->local_ip
);
1024 zebra_mlag_vxlan_update__free_unpacked(msg
, NULL
);
1026 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_ADD
: {
1027 ZebraMlagMrouteAdd
*msg
= NULL
;
1029 msg
= zebra_mlag_mroute_add__unpack(NULL
, hdr
->data
.len
,
1032 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1036 stream_putw(s
, sizeof(struct mlag_mroute_add
));
1038 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1040 zebra_fill_protobuf_msg(s
, msg
->vrf_name
, VRF_NAMSIZ
);
1042 stream_putl(s
, msg
->source_ip
);
1043 stream_putl(s
, msg
->group_ip
);
1044 stream_putl(s
, msg
->cost_to_rp
);
1045 stream_putl(s
, msg
->owner_id
);
1046 stream_putc(s
, msg
->am_i_dr
);
1047 stream_putc(s
, msg
->am_i_dual_active
);
1048 stream_putl(s
, msg
->vrf_id
);
1049 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1050 zebra_fill_protobuf_msg(s
, msg
->intf_name
,
1053 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1054 zebra_mlag_mroute_add__free_unpacked(msg
, NULL
);
1056 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_DEL
: {
1057 ZebraMlagMrouteDel
*msg
= NULL
;
1059 msg
= zebra_mlag_mroute_del__unpack(NULL
, hdr
->data
.len
,
1062 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1066 stream_putw(s
, sizeof(struct mlag_mroute_del
));
1068 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1070 zebra_fill_protobuf_msg(s
, msg
->vrf_name
, VRF_NAMSIZ
);
1072 stream_putl(s
, msg
->source_ip
);
1073 stream_putl(s
, msg
->group_ip
);
1074 stream_putl(s
, msg
->owner_id
);
1075 stream_putl(s
, msg
->vrf_id
);
1076 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1077 zebra_fill_protobuf_msg(s
, msg
->intf_name
,
1080 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1081 zebra_mlag_mroute_del__free_unpacked(msg
, NULL
);
1083 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_ADD_BULK
: {
1084 ZebraMlagMrouteAddBulk
*Bulk_msg
= NULL
;
1085 ZebraMlagMrouteAdd
*msg
= NULL
;
1088 Bulk_msg
= zebra_mlag_mroute_add_bulk__unpack(
1089 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1090 if (Bulk_msg
== NULL
) {
1091 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1095 stream_putw(s
, (Bulk_msg
->n_mroute_add
1096 * sizeof(struct mlag_mroute_add
)));
1097 /* No. of msgs in Batch */
1098 stream_putw(s
, Bulk_msg
->n_mroute_add
);
1101 for (i
= 0; i
< Bulk_msg
->n_mroute_add
; i
++) {
1103 msg
= Bulk_msg
->mroute_add
[i
];
1105 zebra_fill_protobuf_msg(s
, msg
->vrf_name
,
1107 stream_putl(s
, msg
->source_ip
);
1108 stream_putl(s
, msg
->group_ip
);
1109 stream_putl(s
, msg
->cost_to_rp
);
1110 stream_putl(s
, msg
->owner_id
);
1111 stream_putc(s
, msg
->am_i_dr
);
1112 stream_putc(s
, msg
->am_i_dual_active
);
1113 stream_putl(s
, msg
->vrf_id
);
1114 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1115 zebra_fill_protobuf_msg(
1119 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1121 zebra_mlag_mroute_add_bulk__free_unpacked(Bulk_msg
,
1124 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_DEL_BULK
: {
1125 ZebraMlagMrouteDelBulk
*Bulk_msg
= NULL
;
1126 ZebraMlagMrouteDel
*msg
= NULL
;
1129 Bulk_msg
= zebra_mlag_mroute_del_bulk__unpack(
1130 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1131 if (Bulk_msg
== NULL
) {
1132 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1136 stream_putw(s
, (Bulk_msg
->n_mroute_del
1137 * sizeof(struct mlag_mroute_del
)));
1138 /* No. of msgs in Batch */
1139 stream_putw(s
, Bulk_msg
->n_mroute_del
);
1142 for (i
= 0; i
< Bulk_msg
->n_mroute_del
; i
++) {
1144 msg
= Bulk_msg
->mroute_del
[i
];
1146 zebra_fill_protobuf_msg(s
, msg
->vrf_name
,
1148 stream_putl(s
, msg
->source_ip
);
1149 stream_putl(s
, msg
->group_ip
);
1150 stream_putl(s
, msg
->owner_id
);
1151 stream_putl(s
, msg
->vrf_id
);
1152 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1153 zebra_fill_protobuf_msg(
1157 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1159 zebra_mlag_mroute_del_bulk__free_unpacked(Bulk_msg
,
1162 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_ZEBRA_STATUS_UPDATE
: {
1163 ZebraMlagZebraStatusUpdate
*msg
= NULL
;
1165 msg
= zebra_mlag_zebra_status_update__unpack(
1166 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1168 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1172 stream_putw(s
, sizeof(struct mlag_frr_status
));
1174 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1176 stream_putl(s
, msg
->peer_frrstate
);
1177 zebra_mlag_zebra_status_update__free_unpacked(msg
,
1184 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1189 int zebra_mlag_protobuf_encode_client_data(struct stream
*s
, uint32_t *msg_type
)
1194 int zebra_mlag_protobuf_decode_message(struct stream
*s
, uint8_t *data
,