1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2018 Cumulus Networks, Inc.
10 #include "frr_pthread.h"
13 #include "zebra/zebra_mlag.h"
14 #include "zebra/zebra_mlag_vty.h"
15 #include "zebra/zebra_router.h"
16 #include "zebra/zapi_msg.h"
17 #include "zebra/debug.h"
19 #ifdef HAVE_PROTOBUF_VERSION_3
20 #include "mlag/mlag.pb-c.h"
23 DEFINE_HOOK(zebra_mlag_private_write_data
,
24 (uint8_t *data
, uint32_t len
), (data
, len
));
25 DEFINE_HOOK(zebra_mlag_private_monitor_state
, (), ());
26 DEFINE_HOOK(zebra_mlag_private_open_channel
, (), ());
27 DEFINE_HOOK(zebra_mlag_private_close_channel
, (), ());
28 DEFINE_HOOK(zebra_mlag_private_cleanup_data
, (), ());
30 #define ZEBRA_MLAG_METADATA_LEN 4
31 #define ZEBRA_MLAG_MSG_BCAST 0xFFFFFFFF
33 uint8_t mlag_wr_buffer
[ZEBRA_MLAG_BUF_LIMIT
];
34 uint8_t mlag_rd_buffer
[ZEBRA_MLAG_BUF_LIMIT
];
36 static bool test_mlag_in_progress
;
38 static int zebra_mlag_signal_write_thread(void);
39 static void zebra_mlag_terminate_pthread(struct thread
*event
);
40 static void zebra_mlag_post_data_from_main_thread(struct thread
*thread
);
41 static void zebra_mlag_publish_process_state(struct zserv
*client
,
42 zebra_message_types_t msg_type
);
44 /**********************MLAG Interaction***************************************/
47 * API to post the Registration to MLAGD
48 * MLAG will not process any messages with out the registration
50 void zebra_mlag_send_register(void)
52 struct stream
*s
= NULL
;
54 s
= stream_new(sizeof(struct mlag_msg
));
56 stream_putl(s
, MLAG_REGISTER
);
57 stream_putw(s
, MLAG_MSG_NULL_PAYLOAD
);
58 stream_putw(s
, MLAG_MSG_NO_BATCH
);
59 stream_fifo_push_safe(zrouter
.mlag_info
.mlag_fifo
, s
);
60 zebra_mlag_signal_write_thread();
62 if (IS_ZEBRA_DEBUG_MLAG
)
63 zlog_debug("%s: Enqueued MLAG Register to MLAG Thread ",
68 * API to post the De-Registration to MLAGD
69 * MLAG will not process any messages after the de-registration
71 void zebra_mlag_send_deregister(void)
73 struct stream
*s
= NULL
;
75 s
= stream_new(sizeof(struct mlag_msg
));
77 stream_putl(s
, MLAG_DEREGISTER
);
78 stream_putw(s
, MLAG_MSG_NULL_PAYLOAD
);
79 stream_putw(s
, MLAG_MSG_NO_BATCH
);
80 stream_fifo_push_safe(zrouter
.mlag_info
.mlag_fifo
, s
);
81 zebra_mlag_signal_write_thread();
83 if (IS_ZEBRA_DEBUG_MLAG
)
84 zlog_debug("%s: Enqueued MLAG De-Register to MLAG Thread ",
89 * API To handle MLAG Received data
90 * Decodes the data using protobuf and enqueue to main thread
91 * main thread publish this to clients based on client subscription
93 void zebra_mlag_process_mlag_data(uint8_t *data
, uint32_t len
)
95 struct stream
*s
= NULL
;
98 s
= stream_new(ZEBRA_MLAG_BUF_LIMIT
);
100 * Place holder we need the message type first
102 stream_putl(s
, msg_type
);
103 msg_type
= zebra_mlag_protobuf_decode_message(s
, data
, len
);
106 /* Something went wrong in decoding */
108 zlog_err("%s: failed to process mlag data-%d, %u", __func__
,
114 * additional four bytes are for message type
116 stream_putl_at(s
, 0, msg_type
);
117 thread_add_event(zrouter
.master
, zebra_mlag_post_data_from_main_thread
,
121 /**********************End of MLAG Interaction********************************/
123 /************************MLAG Thread Processing*******************************/
126 * after posting every 'ZEBRA_MLAG_POST_LIMIT' packets, MLAG Thread will be
127 * yielded to give CPU for other threads
129 #define ZEBRA_MLAG_POST_LIMIT 100
132 * This thread reads the clients data from the Global queue and encodes with
133 * protobuf and pass on to the MLAG socket.
135 static void zebra_mlag_client_msg_handler(struct thread
*event
)
138 uint32_t wr_count
= 0;
139 uint32_t msg_type
= 0;
140 uint32_t max_count
= 0;
143 wr_count
= stream_fifo_count_safe(zrouter
.mlag_info
.mlag_fifo
);
144 if (IS_ZEBRA_DEBUG_MLAG
)
145 zlog_debug(":%s: Processing MLAG write, %u messages in queue",
148 max_count
= MIN(wr_count
, ZEBRA_MLAG_POST_LIMIT
);
150 for (wr_count
= 0; wr_count
< max_count
; wr_count
++) {
151 s
= stream_fifo_pop_safe(zrouter
.mlag_info
.mlag_fifo
);
153 zlog_debug(":%s: Got a NULL Messages, some thing wrong",
159 * Encode the data now
161 len
= zebra_mlag_protobuf_encode_client_data(s
, &msg_type
);
167 hook_call(zebra_mlag_private_write_data
,
168 mlag_wr_buffer
, len
);
171 * If message type is De-register, send a signal to main
172 * thread, so that necessary cleanup will be done by
175 if (msg_type
== MLAG_DEREGISTER
) {
176 thread_add_event(zrouter
.master
,
177 zebra_mlag_terminate_pthread
,
185 if (IS_ZEBRA_DEBUG_MLAG
)
186 zlog_debug(":%s: Posted %d messages to MLAGD", __func__
,
189 * Currently there is only message write task is enqueued to this
190 * thread, yielding was added for future purpose, so that this thread
191 * can server other tasks also and in case FIFO is empty, this task will
192 * be schedule when main thread adds some messages
194 if (wr_count
>= ZEBRA_MLAG_POST_LIMIT
)
195 zebra_mlag_signal_write_thread();
199 * API to handle the process state.
200 * In case of Down, Zebra keep monitoring the MLAG state.
201 * all the state Notifications will be published to clients
203 void zebra_mlag_handle_process_state(enum zebra_mlag_state state
)
205 if (state
== MLAG_UP
) {
206 zrouter
.mlag_info
.connected
= true;
207 zebra_mlag_publish_process_state(NULL
, ZEBRA_MLAG_PROCESS_UP
);
208 zebra_mlag_send_register();
209 } else if (state
== MLAG_DOWN
) {
210 zrouter
.mlag_info
.connected
= false;
211 zebra_mlag_publish_process_state(NULL
, ZEBRA_MLAG_PROCESS_DOWN
);
212 hook_call(zebra_mlag_private_monitor_state
);
216 /***********************End of MLAG Thread processing*************************/
218 /*************************Multi-entratnt Api's********************************/
221 * Provider api to signal that work/events are available
222 * for the Zebra MLAG Write pthread.
223 * This API is called from 2 pthreads..
224 * 1) by main thread when client posts a MLAG Message
225 * 2) by MLAG Thread, in case of yield
226 * though this api, is called from two threads we don't need any locking
227 * because Thread task enqueue is thread safe means internally it had
228 * necessary protection
230 static int zebra_mlag_signal_write_thread(void)
232 if (IS_ZEBRA_DEBUG_MLAG
)
233 zlog_debug(":%s: Scheduling MLAG write", __func__
);
235 * This api will be called from Both main & MLAG Threads.
236 * main thread writes, "zrouter.mlag_info.th_master" only
237 * during Zebra Init/after MLAG thread is destroyed.
238 * so it is safe to use without any locking
240 thread_add_event(zrouter
.mlag_info
.th_master
,
241 zebra_mlag_client_msg_handler
, NULL
, 0,
242 &zrouter
.mlag_info
.t_write
);
247 * API will be used to publish the MLAG state to interested clients
248 * In case client is passed, state is posted only for that client,
249 * otherwise to all interested clients
250 * this api can be called from two threads.
251 * 1) from main thread: when client is passed
252 * 2) from MLAG Thread: when client is NULL
254 * In second case, to avoid global data access data will be post to Main
255 * thread, so that actual posting to clients will happen from Main thread.
257 static void zebra_mlag_publish_process_state(struct zserv
*client
,
258 zebra_message_types_t msg_type
)
262 if (IS_ZEBRA_DEBUG_MLAG
)
263 zlog_debug("%s: Publishing MLAG process state:%s to %s Client",
265 (msg_type
== ZEBRA_MLAG_PROCESS_UP
) ? "UP" : "DOWN",
266 (client
) ? "one" : "all");
269 s
= stream_new(ZEBRA_HEADER_SIZE
);
270 zclient_create_header(s
, msg_type
, VRF_DEFAULT
);
271 zserv_send_message(client
, s
);
277 * additional four bytes are for mesasge type
279 s
= stream_new(ZEBRA_HEADER_SIZE
+ ZEBRA_MLAG_METADATA_LEN
);
280 stream_putl(s
, ZEBRA_MLAG_MSG_BCAST
);
281 zclient_create_header(s
, msg_type
, VRF_DEFAULT
);
282 thread_add_event(zrouter
.master
, zebra_mlag_post_data_from_main_thread
,
286 /**************************End of Multi-entrant Apis**************************/
288 /***********************Zebra Main thread processing**************************/
291 * To avoid data corruption, messages will be post to clients only from
292 * main thread, because for that access was needed for clients list.
293 * so instead of forcing the locks, messages will be posted from main thread.
295 static void zebra_mlag_post_data_from_main_thread(struct thread
*thread
)
297 struct stream
*s
= THREAD_ARG(thread
);
298 struct stream
*zebra_s
= NULL
;
299 struct listnode
*node
;
300 struct zserv
*client
;
301 uint32_t msg_type
= 0;
302 uint32_t msg_len
= 0;
307 STREAM_GETL(s
, msg_type
);
308 if (IS_ZEBRA_DEBUG_MLAG
)
310 "%s: Posting MLAG data for msg_type:0x%x to interested clients",
313 msg_len
= s
->endp
- ZEBRA_MLAG_METADATA_LEN
;
314 for (ALL_LIST_ELEMENTS_RO(zrouter
.client_list
, node
, client
)) {
315 if (client
->mlag_updates_interested
== true) {
316 if (msg_type
!= ZEBRA_MLAG_MSG_BCAST
317 && !CHECK_FLAG(client
->mlag_reg_mask1
,
322 if (IS_ZEBRA_DEBUG_MLAG
)
324 "%s: Posting MLAG data of length-%d to client:%d ",
325 __func__
, msg_len
, client
->proto
);
327 zebra_s
= stream_new(msg_len
);
328 STREAM_GET(zebra_s
->data
, s
, msg_len
);
329 zebra_s
->endp
= msg_len
;
330 stream_putw_at(zebra_s
, 0, msg_len
);
333 * This stream will be enqueued to client_obuf, it will
334 * be freed after posting to client socket.
336 zserv_send_message(client
, zebra_s
);
346 stream_free(zebra_s
);
350 * Start the MLAG Thread, this will be used to write client data on to
351 * MLAG Process and to read the data from MLAG and post to clients.
352 * when all clients are un-registered, this Thread will be
355 static void zebra_mlag_spawn_pthread(void)
357 /* Start MLAG write pthread */
359 struct frr_pthread_attr pattr
= {.start
=
360 frr_pthread_attr_default
.start
,
361 .stop
= frr_pthread_attr_default
.stop
};
363 zrouter
.mlag_info
.zebra_pth_mlag
=
364 frr_pthread_new(&pattr
, "Zebra MLAG thread", "Zebra MLAG");
366 zrouter
.mlag_info
.th_master
= zrouter
.mlag_info
.zebra_pth_mlag
->master
;
369 /* Enqueue an initial event to the Newly spawn MLAG pthread */
370 zebra_mlag_signal_write_thread();
372 frr_pthread_run(zrouter
.mlag_info
.zebra_pth_mlag
, NULL
);
376 * all clients are un-registered for MLAG Updates, terminate the
379 static void zebra_mlag_terminate_pthread(struct thread
*event
)
381 if (IS_ZEBRA_DEBUG_MLAG
)
382 zlog_debug("Zebra MLAG write thread terminate called");
384 if (zrouter
.mlag_info
.clients_interested_cnt
) {
385 if (IS_ZEBRA_DEBUG_MLAG
)
387 "Zebra MLAG: still some clients are interested");
391 frr_pthread_stop(zrouter
.mlag_info
.zebra_pth_mlag
, NULL
);
393 /* Destroy pthread */
394 frr_pthread_destroy(zrouter
.mlag_info
.zebra_pth_mlag
);
395 zrouter
.mlag_info
.zebra_pth_mlag
= NULL
;
396 zrouter
.mlag_info
.th_master
= NULL
;
397 zrouter
.mlag_info
.t_read
= NULL
;
398 zrouter
.mlag_info
.t_write
= NULL
;
401 * Send Notification to clean private data
403 hook_call(zebra_mlag_private_cleanup_data
);
407 * API to register zebra client for MLAG Updates
409 void zebra_mlag_client_register(ZAPI_HANDLER_ARGS
)
412 uint32_t reg_mask
= 0;
415 if (IS_ZEBRA_DEBUG_MLAG
)
416 zlog_debug("Received MLAG Registration from client-proto:%d",
420 /* Get input stream. */
424 STREAM_GETL(s
, reg_mask
);
426 if (client
->mlag_updates_interested
== true) {
428 if (IS_ZEBRA_DEBUG_MLAG
)
430 "Client is registered, existing mask: 0x%x, new mask: 0x%x",
431 client
->mlag_reg_mask1
, reg_mask
);
432 if (client
->mlag_reg_mask1
!= reg_mask
)
433 client
->mlag_reg_mask1
= reg_mask
;
435 * Client might missed MLAG-UP Notification, post-it again
437 zebra_mlag_publish_process_state(client
, ZEBRA_MLAG_PROCESS_UP
);
442 client
->mlag_updates_interested
= true;
443 client
->mlag_reg_mask1
= reg_mask
;
444 if (IS_ZEBRA_DEBUG_MLAG
)
445 zlog_debug("Registering for MLAG Updates with mask: 0x%x, ",
446 client
->mlag_reg_mask1
);
448 zrouter
.mlag_info
.clients_interested_cnt
++;
450 if (zrouter
.mlag_info
.clients_interested_cnt
== 1) {
452 * First-client for MLAG Updates,open the communication channel
455 if (IS_ZEBRA_DEBUG_MLAG
)
457 "First client, opening the channel with MLAG");
459 zebra_mlag_spawn_pthread();
460 rc
= hook_call(zebra_mlag_private_open_channel
);
463 * For some reason, zebra not able to open the
464 * comm-channel with MLAG, so post MLAG-DOWN to client.
465 * later when the channel is open, zebra will send
468 if (IS_ZEBRA_DEBUG_MLAG
)
470 "Fail to open channel with MLAG,rc:%d, post Proto-down",
472 zebra_mlag_publish_process_state(
473 client
, ZEBRA_MLAG_PROCESS_DOWN
);
477 if (IS_ZEBRA_DEBUG_MLAG
)
478 zlog_debug("Client Registered successfully for MLAG Updates");
480 if (zrouter
.mlag_info
.connected
== true)
481 zebra_mlag_publish_process_state(client
, ZEBRA_MLAG_PROCESS_UP
);
487 * API to un-register for MLAG Updates
489 void zebra_mlag_client_unregister(ZAPI_HANDLER_ARGS
)
491 if (IS_ZEBRA_DEBUG_MLAG
)
492 zlog_debug("Received MLAG De-Registration from client-proto:%d",
495 if (client
->mlag_updates_interested
== false)
499 client
->mlag_updates_interested
= false;
500 client
->mlag_reg_mask1
= 0;
501 zrouter
.mlag_info
.clients_interested_cnt
--;
503 if (zrouter
.mlag_info
.clients_interested_cnt
== 0) {
505 * No-client is interested for MLAG Updates,close the
506 * communication channel with MLAG
508 if (IS_ZEBRA_DEBUG_MLAG
)
509 zlog_debug("Last client for MLAG, close the channel ");
514 * 1) main thread calls socket close which posts De-register
515 * to MLAG write thread
516 * 2) after MLAG write thread posts De-register it sends a
517 * signal back to main thread to do the thread cleanup
518 * this was mainly to make sure De-register is posted to MCLAGD.
520 hook_call(zebra_mlag_private_close_channel
);
523 if (IS_ZEBRA_DEBUG_MLAG
)
525 "Client De-Registered successfully for MLAG Updates");
529 * Does following things.
530 * 1) allocated new local stream, and copies the client data and enqueue
532 * 2) MLAG Thread after dequeing, encode the client data using protobuf
533 * and write on to MLAG
535 void zebra_mlag_forward_client_msg(ZAPI_HANDLER_ARGS
)
537 struct stream
*zebra_s
;
538 struct stream
*mlag_s
;
540 if (IS_ZEBRA_DEBUG_MLAG
)
541 zlog_debug("Received Client MLAG Data from client-proto:%d",
544 /* Get input stream. */
546 mlag_s
= stream_new(zebra_s
->endp
);
549 * Client data is | Zebra Header + MLAG Data |
550 * we need to enqueue only the MLAG data, skipping Zebra Header
552 stream_put(mlag_s
, zebra_s
->data
+ zebra_s
->getp
,
553 STREAM_READABLE(zebra_s
));
554 stream_fifo_push_safe(zrouter
.mlag_info
.mlag_fifo
, mlag_s
);
555 zebra_mlag_signal_write_thread();
557 if (IS_ZEBRA_DEBUG_MLAG
)
558 zlog_debug("%s: Enqueued Client:%d data to MLAG Thread ",
559 __func__
, client
->proto
);
562 /***********************End of Zebra Main thread processing*************/
564 enum mlag_role
zebra_mlag_get_role(void)
566 return zrouter
.mlag_info
.role
;
569 int32_t zebra_mlag_test_mlag_internal(const char *none
, const char *primary
,
570 const char *secondary
)
572 enum mlag_role orig
= zrouter
.mlag_info
.role
;
573 char buf1
[MLAG_ROLE_STRSIZE
], buf2
[MLAG_ROLE_STRSIZE
];
576 zrouter
.mlag_info
.role
= MLAG_ROLE_NONE
;
578 zrouter
.mlag_info
.role
= MLAG_ROLE_PRIMARY
;
580 zrouter
.mlag_info
.role
= MLAG_ROLE_SECONDARY
;
582 if (IS_ZEBRA_DEBUG_MLAG
)
583 zlog_debug("Test: Changing role from %s to %s",
584 mlag_role2str(orig
, buf1
, sizeof(buf1
)),
585 mlag_role2str(orig
, buf2
, sizeof(buf2
)));
587 if (orig
!= zrouter
.mlag_info
.role
) {
588 zsend_capabilities_all_clients();
589 if (zrouter
.mlag_info
.role
!= MLAG_ROLE_NONE
) {
590 if (zrouter
.mlag_info
.clients_interested_cnt
== 0
591 && !test_mlag_in_progress
) {
592 if (zrouter
.mlag_info
.zebra_pth_mlag
== NULL
)
593 zebra_mlag_spawn_pthread();
594 zrouter
.mlag_info
.clients_interested_cnt
++;
595 test_mlag_in_progress
= true;
596 hook_call(zebra_mlag_private_open_channel
);
599 if (test_mlag_in_progress
) {
600 test_mlag_in_progress
= false;
601 zrouter
.mlag_info
.clients_interested_cnt
--;
602 hook_call(zebra_mlag_private_close_channel
);
610 void zebra_mlag_init(void)
612 zebra_mlag_vty_init();
615 * Intialiaze the MLAG Global variables
616 * write thread will be created during actual registration with MCLAG
618 zrouter
.mlag_info
.clients_interested_cnt
= 0;
619 zrouter
.mlag_info
.connected
= false;
620 zrouter
.mlag_info
.timer_running
= false;
621 zrouter
.mlag_info
.mlag_fifo
= stream_fifo_new();
622 zrouter
.mlag_info
.zebra_pth_mlag
= NULL
;
623 zrouter
.mlag_info
.th_master
= NULL
;
624 zrouter
.mlag_info
.t_read
= NULL
;
625 zrouter
.mlag_info
.t_write
= NULL
;
626 test_mlag_in_progress
= false;
627 zebra_mlag_reset_read_buffer();
630 void zebra_mlag_terminate(void)
637 * ProtoBuf Encoding APIs
640 #ifdef HAVE_PROTOBUF_VERSION_3
642 DEFINE_MTYPE_STATIC(ZEBRA
, MLAG_PBUF
, "ZEBRA MLAG PROTOBUF");
644 int zebra_mlag_protobuf_encode_client_data(struct stream
*s
, uint32_t *msg_type
)
646 ZebraMlagHeader hdr
= ZEBRA_MLAG__HEADER__INIT
;
647 struct mlag_msg mlag_msg
;
648 uint8_t tmp_buf
[ZEBRA_MLAG_BUF_LIMIT
];
652 char buf
[ZLOG_FILTER_LENGTH_MAX
];
655 if (IS_ZEBRA_DEBUG_MLAG
)
656 zlog_debug("%s: Entering..", __func__
);
658 rc
= mlag_lib_decode_mlag_hdr(s
, &mlag_msg
, &length
);
662 memset(tmp_buf
, 0, ZEBRA_MLAG_BUF_LIMIT
);
664 if (IS_ZEBRA_DEBUG_MLAG
)
665 zlog_debug("%s: Mlag ProtoBuf encoding of message:%s, len:%d",
667 mlag_lib_msgid_to_str(mlag_msg
.msg_type
, buf
,
670 *msg_type
= mlag_msg
.msg_type
;
671 switch (mlag_msg
.msg_type
) {
672 case MLAG_MROUTE_ADD
: {
673 struct mlag_mroute_add msg
;
674 ZebraMlagMrouteAdd pay_load
= ZEBRA_MLAG_MROUTE_ADD__INIT
;
675 uint32_t vrf_name_len
= 0;
677 rc
= mlag_lib_decode_mroute_add(s
, &msg
, &length
);
681 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
682 pay_load
.vrf_name
= XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
683 strlcpy(pay_load
.vrf_name
, msg
.vrf_name
, vrf_name_len
);
684 pay_load
.source_ip
= msg
.source_ip
;
685 pay_load
.group_ip
= msg
.group_ip
;
686 pay_load
.cost_to_rp
= msg
.cost_to_rp
;
687 pay_load
.owner_id
= msg
.owner_id
;
688 pay_load
.am_i_dr
= msg
.am_i_dr
;
689 pay_load
.am_i_dual_active
= msg
.am_i_dual_active
;
690 pay_load
.vrf_id
= msg
.vrf_id
;
692 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
693 vrf_name_len
= strlen(msg
.intf_name
) + 1;
695 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
696 strlcpy(pay_load
.intf_name
, msg
.intf_name
,
700 len
= zebra_mlag_mroute_add__pack(&pay_load
, tmp_buf
);
701 XFREE(MTYPE_MLAG_PBUF
, pay_load
.vrf_name
);
702 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
)
703 XFREE(MTYPE_MLAG_PBUF
, pay_load
.intf_name
);
705 case MLAG_MROUTE_DEL
: {
706 struct mlag_mroute_del msg
;
707 ZebraMlagMrouteDel pay_load
= ZEBRA_MLAG_MROUTE_DEL__INIT
;
708 uint32_t vrf_name_len
= 0;
710 rc
= mlag_lib_decode_mroute_del(s
, &msg
, &length
);
713 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
714 pay_load
.vrf_name
= XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
715 strlcpy(pay_load
.vrf_name
, msg
.vrf_name
, vrf_name_len
);
716 pay_load
.source_ip
= msg
.source_ip
;
717 pay_load
.group_ip
= msg
.group_ip
;
718 pay_load
.owner_id
= msg
.owner_id
;
719 pay_load
.vrf_id
= msg
.vrf_id
;
721 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
722 vrf_name_len
= strlen(msg
.intf_name
) + 1;
724 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
725 strlcpy(pay_load
.intf_name
, msg
.intf_name
,
729 len
= zebra_mlag_mroute_del__pack(&pay_load
, tmp_buf
);
730 XFREE(MTYPE_MLAG_PBUF
, pay_load
.vrf_name
);
731 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
)
732 XFREE(MTYPE_MLAG_PBUF
, pay_load
.intf_name
);
734 case MLAG_MROUTE_ADD_BULK
: {
735 struct mlag_mroute_add msg
;
736 ZebraMlagMrouteAddBulk Bulk_msg
=
737 ZEBRA_MLAG_MROUTE_ADD_BULK__INIT
;
738 ZebraMlagMrouteAdd
**pay_load
= NULL
;
739 bool cleanup
= false;
742 Bulk_msg
.n_mroute_add
= mlag_msg
.msg_cnt
;
743 pay_load
= XMALLOC(MTYPE_MLAG_PBUF
, sizeof(ZebraMlagMrouteAdd
*)
746 for (i
= 0, actual
= 0; i
< mlag_msg
.msg_cnt
; i
++, actual
++) {
748 uint32_t vrf_name_len
= 0;
750 rc
= mlag_lib_decode_mroute_add(s
, &msg
, &length
);
755 pay_load
[i
] = XMALLOC(MTYPE_MLAG_PBUF
,
756 sizeof(ZebraMlagMrouteAdd
));
757 zebra_mlag_mroute_add__init(pay_load
[i
]);
759 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
760 pay_load
[i
]->vrf_name
=
761 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
762 strlcpy(pay_load
[i
]->vrf_name
, msg
.vrf_name
,
764 pay_load
[i
]->source_ip
= msg
.source_ip
;
765 pay_load
[i
]->group_ip
= msg
.group_ip
;
766 pay_load
[i
]->cost_to_rp
= msg
.cost_to_rp
;
767 pay_load
[i
]->owner_id
= msg
.owner_id
;
768 pay_load
[i
]->am_i_dr
= msg
.am_i_dr
;
769 pay_load
[i
]->am_i_dual_active
= msg
.am_i_dual_active
;
770 pay_load
[i
]->vrf_id
= msg
.vrf_id
;
771 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
772 vrf_name_len
= strlen(msg
.intf_name
) + 1;
773 pay_load
[i
]->intf_name
=
774 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
776 strlcpy(pay_load
[i
]->intf_name
, msg
.intf_name
,
781 Bulk_msg
.mroute_add
= pay_load
;
782 len
= zebra_mlag_mroute_add_bulk__pack(&Bulk_msg
,
786 for (i
= 0; i
< actual
; i
++) {
788 * The mlag_lib_decode_mroute_add can
789 * fail to properly decode and cause nothing
790 * to be allocated. Prevent a crash
795 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->vrf_name
);
796 if (pay_load
[i
]->owner_id
== MLAG_OWNER_INTERFACE
797 && pay_load
[i
]->intf_name
)
798 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->intf_name
);
799 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]);
801 XFREE(MTYPE_MLAG_PBUF
, pay_load
);
805 case MLAG_MROUTE_DEL_BULK
: {
806 struct mlag_mroute_del msg
;
807 ZebraMlagMrouteDelBulk Bulk_msg
=
808 ZEBRA_MLAG_MROUTE_DEL_BULK__INIT
;
809 ZebraMlagMrouteDel
**pay_load
= NULL
;
810 bool cleanup
= false;
813 Bulk_msg
.n_mroute_del
= mlag_msg
.msg_cnt
;
814 pay_load
= XMALLOC(MTYPE_MLAG_PBUF
, sizeof(ZebraMlagMrouteDel
*)
817 for (i
= 0, actual
= 0; i
< mlag_msg
.msg_cnt
; i
++, actual
++) {
819 uint32_t vrf_name_len
= 0;
821 rc
= mlag_lib_decode_mroute_del(s
, &msg
, &length
);
827 pay_load
[i
] = XMALLOC(MTYPE_MLAG_PBUF
,
828 sizeof(ZebraMlagMrouteDel
));
829 zebra_mlag_mroute_del__init(pay_load
[i
]);
831 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
832 pay_load
[i
]->vrf_name
=
833 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
835 strlcpy(pay_load
[i
]->vrf_name
, msg
.vrf_name
,
837 pay_load
[i
]->source_ip
= msg
.source_ip
;
838 pay_load
[i
]->group_ip
= msg
.group_ip
;
839 pay_load
[i
]->owner_id
= msg
.owner_id
;
840 pay_load
[i
]->vrf_id
= msg
.vrf_id
;
841 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
842 vrf_name_len
= strlen(msg
.intf_name
) + 1;
843 pay_load
[i
]->intf_name
=
844 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
846 strlcpy(pay_load
[i
]->intf_name
, msg
.intf_name
,
851 Bulk_msg
.mroute_del
= pay_load
;
852 len
= zebra_mlag_mroute_del_bulk__pack(&Bulk_msg
,
856 for (i
= 0; i
< actual
; i
++) {
858 * The mlag_lib_decode_mroute_add can
859 * fail to properly decode and cause nothing
860 * to be allocated. Prevent a crash
865 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->vrf_name
);
866 if (pay_load
[i
]->owner_id
== MLAG_OWNER_INTERFACE
867 && pay_load
[i
]->intf_name
)
868 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->intf_name
);
869 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]);
871 XFREE(MTYPE_MLAG_PBUF
, pay_load
);
876 case MLAG_DEREGISTER
:
877 case MLAG_STATUS_UPDATE
:
879 case MLAG_PIM_CFG_DUMP
:
880 case MLAG_VXLAN_UPDATE
:
881 case MLAG_PEER_FRR_STATUS
:
886 if (IS_ZEBRA_DEBUG_MLAG
)
887 zlog_debug("%s: length of Mlag ProtoBuf encoded message:%s, %d",
889 mlag_lib_msgid_to_str(mlag_msg
.msg_type
, buf
,
892 hdr
.type
= (ZebraMlagHeader__MessageType
)mlag_msg
.msg_type
;
895 hdr
.data
.data
= XMALLOC(MTYPE_MLAG_PBUF
, len
);
896 memcpy(hdr
.data
.data
, tmp_buf
, len
);
900 * ProtoBuf Infra will not support to demarc the pointers whem multiple
901 * messages are posted inside a single Buffer.
902 * 2 -solutions exist to solve this
903 * 1. add Unenoced length at the beginning of every message, this will
904 * be used to point to next message in the buffer
905 * 2. another solution is defining all messages insides another message
906 * But this will permit only 32 messages. this can be extended with
908 * for simplicity we are going with solution-1.
910 len
= zebra_mlag__header__pack(&hdr
,
911 (mlag_wr_buffer
+ ZEBRA_MLAG_LEN_SIZE
));
913 memcpy(mlag_wr_buffer
, &n_len
, ZEBRA_MLAG_LEN_SIZE
);
914 len
+= ZEBRA_MLAG_LEN_SIZE
;
916 if (IS_ZEBRA_DEBUG_MLAG
)
918 "%s: length of Mlag ProtoBuf message:%s with Header %d",
920 mlag_lib_msgid_to_str(mlag_msg
.msg_type
, buf
,
923 XFREE(MTYPE_MLAG_PBUF
, hdr
.data
.data
);
928 static void zebra_fill_protobuf_msg(struct stream
*s
, char *name
, int len
)
930 int str_len
= strlen(name
) + 1;
932 stream_put(s
, name
, str_len
);
933 /* Fill the rest with Null Character for aligning */
934 stream_put(s
, NULL
, len
- str_len
);
937 int zebra_mlag_protobuf_decode_message(struct stream
*s
, uint8_t *data
,
941 ZebraMlagHeader
*hdr
;
944 hdr
= zebra_mlag__header__unpack(NULL
, len
, data
);
949 * ADD The MLAG Header
951 zclient_create_header(s
, ZEBRA_MLAG_FORWARD_MSG
, VRF_DEFAULT
);
953 msg_type
= hdr
->type
;
955 if (IS_ZEBRA_DEBUG_MLAG
)
956 zlog_debug("%s: Mlag ProtoBuf decoding of message:%s", __func__
,
957 mlag_lib_msgid_to_str(msg_type
, buf
, 80));
960 * Internal MLAG Message-types & MLAG.proto message types should
961 * always match, otherwise there can be decoding errors
962 * To avoid exposing clients with Protobuf flags, using internal
965 stream_putl(s
, hdr
->type
);
967 if (hdr
->data
.len
== 0) {
969 stream_putw(s
, MLAG_MSG_NULL_PAYLOAD
);
971 stream_putw(s
, MLAG_MSG_NO_BATCH
);
974 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_STATUS_UPDATE
: {
975 ZebraMlagStatusUpdate
*msg
= NULL
;
977 msg
= zebra_mlag_status_update__unpack(
978 NULL
, hdr
->data
.len
, hdr
->data
.data
);
980 zebra_mlag__header__free_unpacked(hdr
, NULL
);
984 stream_putw(s
, sizeof(struct mlag_status
));
986 stream_putw(s
, MLAG_MSG_NO_BATCH
);
988 zebra_fill_protobuf_msg(s
, msg
->peerlink
,
990 stream_putl(s
, msg
->my_role
);
991 stream_putl(s
, msg
->peer_state
);
992 zebra_mlag_status_update__free_unpacked(msg
, NULL
);
994 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_VXLAN_UPDATE
: {
995 ZebraMlagVxlanUpdate
*msg
= NULL
;
997 msg
= zebra_mlag_vxlan_update__unpack(
998 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1000 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1004 stream_putw(s
, sizeof(struct mlag_vxlan
));
1006 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1008 stream_putl(s
, msg
->anycast_ip
);
1009 stream_putl(s
, msg
->local_ip
);
1010 zebra_mlag_vxlan_update__free_unpacked(msg
, NULL
);
1012 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_ADD
: {
1013 ZebraMlagMrouteAdd
*msg
= NULL
;
1015 msg
= zebra_mlag_mroute_add__unpack(NULL
, hdr
->data
.len
,
1018 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1022 stream_putw(s
, sizeof(struct mlag_mroute_add
));
1024 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1026 zebra_fill_protobuf_msg(s
, msg
->vrf_name
, VRF_NAMSIZ
);
1028 stream_putl(s
, msg
->source_ip
);
1029 stream_putl(s
, msg
->group_ip
);
1030 stream_putl(s
, msg
->cost_to_rp
);
1031 stream_putl(s
, msg
->owner_id
);
1032 stream_putc(s
, msg
->am_i_dr
);
1033 stream_putc(s
, msg
->am_i_dual_active
);
1034 stream_putl(s
, msg
->vrf_id
);
1035 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1036 zebra_fill_protobuf_msg(s
, msg
->intf_name
,
1039 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1040 zebra_mlag_mroute_add__free_unpacked(msg
, NULL
);
1042 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_DEL
: {
1043 ZebraMlagMrouteDel
*msg
= NULL
;
1045 msg
= zebra_mlag_mroute_del__unpack(NULL
, hdr
->data
.len
,
1048 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1052 stream_putw(s
, sizeof(struct mlag_mroute_del
));
1054 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1056 zebra_fill_protobuf_msg(s
, msg
->vrf_name
, VRF_NAMSIZ
);
1058 stream_putl(s
, msg
->source_ip
);
1059 stream_putl(s
, msg
->group_ip
);
1060 stream_putl(s
, msg
->owner_id
);
1061 stream_putl(s
, msg
->vrf_id
);
1062 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1063 zebra_fill_protobuf_msg(s
, msg
->intf_name
,
1066 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1067 zebra_mlag_mroute_del__free_unpacked(msg
, NULL
);
1069 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_ADD_BULK
: {
1070 ZebraMlagMrouteAddBulk
*Bulk_msg
= NULL
;
1071 ZebraMlagMrouteAdd
*msg
= NULL
;
1072 size_t i
, length_spot
;
1074 Bulk_msg
= zebra_mlag_mroute_add_bulk__unpack(
1075 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1076 if (Bulk_msg
== NULL
) {
1077 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1081 stream_putw(s
, (Bulk_msg
->n_mroute_add
1082 * sizeof(struct mlag_mroute_add
)));
1083 /* No. of msgs in Batch */
1084 length_spot
= stream_putw(s
, Bulk_msg
->n_mroute_add
);
1087 for (i
= 0; i
< Bulk_msg
->n_mroute_add
; i
++) {
1089 < VRF_NAMSIZ
+ 22 + INTERFACE_NAMSIZ
) {
1091 "We have received more messages than we can parse at this point in time: %zu",
1092 Bulk_msg
->n_mroute_add
);
1096 msg
= Bulk_msg
->mroute_add
[i
];
1098 zebra_fill_protobuf_msg(s
, msg
->vrf_name
,
1100 stream_putl(s
, msg
->source_ip
);
1101 stream_putl(s
, msg
->group_ip
);
1102 stream_putl(s
, msg
->cost_to_rp
);
1103 stream_putl(s
, msg
->owner_id
);
1104 stream_putc(s
, msg
->am_i_dr
);
1105 stream_putc(s
, msg
->am_i_dual_active
);
1106 stream_putl(s
, msg
->vrf_id
);
1107 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1108 zebra_fill_protobuf_msg(
1112 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1115 stream_putw_at(s
, length_spot
, i
+ 1);
1117 zebra_mlag_mroute_add_bulk__free_unpacked(Bulk_msg
,
1120 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_DEL_BULK
: {
1121 ZebraMlagMrouteDelBulk
*Bulk_msg
= NULL
;
1122 ZebraMlagMrouteDel
*msg
= NULL
;
1123 size_t i
, length_spot
;
1125 Bulk_msg
= zebra_mlag_mroute_del_bulk__unpack(
1126 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1127 if (Bulk_msg
== NULL
) {
1128 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1132 stream_putw(s
, (Bulk_msg
->n_mroute_del
1133 * sizeof(struct mlag_mroute_del
)));
1134 /* No. of msgs in Batch */
1135 length_spot
= stream_putw(s
, Bulk_msg
->n_mroute_del
);
1138 for (i
= 0; i
< Bulk_msg
->n_mroute_del
; i
++) {
1140 < VRF_NAMSIZ
+ 16 + INTERFACE_NAMSIZ
) {
1142 "We have received more messages than we can parse at this time");
1146 msg
= Bulk_msg
->mroute_del
[i
];
1148 zebra_fill_protobuf_msg(s
, msg
->vrf_name
,
1150 stream_putl(s
, msg
->source_ip
);
1151 stream_putl(s
, msg
->group_ip
);
1152 stream_putl(s
, msg
->owner_id
);
1153 stream_putl(s
, msg
->vrf_id
);
1154 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1155 zebra_fill_protobuf_msg(
1159 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1162 stream_putw_at(s
, length_spot
, i
+ 1);
1164 zebra_mlag_mroute_del_bulk__free_unpacked(Bulk_msg
,
1167 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_ZEBRA_STATUS_UPDATE
: {
1168 ZebraMlagZebraStatusUpdate
*msg
= NULL
;
1170 msg
= zebra_mlag_zebra_status_update__unpack(
1171 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1173 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1177 stream_putw(s
, sizeof(struct mlag_frr_status
));
1179 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1181 stream_putl(s
, msg
->peer_frrstate
);
1182 zebra_mlag_zebra_status_update__free_unpacked(msg
,
1189 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1194 int zebra_mlag_protobuf_encode_client_data(struct stream
*s
, uint32_t *msg_type
)
1199 int zebra_mlag_protobuf_decode_message(struct stream
*s
, uint8_t *data
,