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/zapi_msg.h"
33 #include "zebra/debug.h"
35 #ifdef HAVE_PROTOBUF_VERSION_3
36 #include "mlag/mlag.pb-c.h"
39 DEFINE_HOOK(zebra_mlag_private_write_data
,
40 (uint8_t *data
, uint32_t len
), (data
, len
));
41 DEFINE_HOOK(zebra_mlag_private_monitor_state
, (), ());
42 DEFINE_HOOK(zebra_mlag_private_open_channel
, (), ());
43 DEFINE_HOOK(zebra_mlag_private_close_channel
, (), ());
44 DEFINE_HOOK(zebra_mlag_private_cleanup_data
, (), ());
46 #define ZEBRA_MLAG_METADATA_LEN 4
47 #define ZEBRA_MLAG_MSG_BCAST 0xFFFFFFFF
49 uint8_t mlag_wr_buffer
[ZEBRA_MLAG_BUF_LIMIT
];
50 uint8_t mlag_rd_buffer
[ZEBRA_MLAG_BUF_LIMIT
];
52 static bool test_mlag_in_progress
;
54 static int zebra_mlag_signal_write_thread(void);
55 static int zebra_mlag_terminate_pthread(struct thread
*event
);
56 static int zebra_mlag_post_data_from_main_thread(struct thread
*thread
);
57 static void zebra_mlag_publish_process_state(struct zserv
*client
,
58 zebra_message_types_t msg_type
);
60 /**********************MLAG Interaction***************************************/
63 * API to post the Registration to MLAGD
64 * MLAG will not process any messages with out the registration
66 void zebra_mlag_send_register(void)
68 struct stream
*s
= NULL
;
70 s
= stream_new(sizeof(struct mlag_msg
));
72 stream_putl(s
, MLAG_REGISTER
);
73 stream_putw(s
, MLAG_MSG_NULL_PAYLOAD
);
74 stream_putw(s
, MLAG_MSG_NO_BATCH
);
75 stream_fifo_push_safe(zrouter
.mlag_info
.mlag_fifo
, s
);
76 zebra_mlag_signal_write_thread();
78 if (IS_ZEBRA_DEBUG_MLAG
)
79 zlog_debug("%s: Enqueued MLAG Register to MLAG Thread ",
84 * API to post the De-Registration to MLAGD
85 * MLAG will not process any messages after the de-registration
87 void zebra_mlag_send_deregister(void)
89 struct stream
*s
= NULL
;
91 s
= stream_new(sizeof(struct mlag_msg
));
93 stream_putl(s
, MLAG_DEREGISTER
);
94 stream_putw(s
, MLAG_MSG_NULL_PAYLOAD
);
95 stream_putw(s
, MLAG_MSG_NO_BATCH
);
96 stream_fifo_push_safe(zrouter
.mlag_info
.mlag_fifo
, s
);
97 zebra_mlag_signal_write_thread();
99 if (IS_ZEBRA_DEBUG_MLAG
)
100 zlog_debug("%s: Enqueued MLAG De-Register to MLAG Thread ",
105 * API To handle MLAG Received data
106 * Decodes the data using protobuf and enqueue to main thread
107 * main thread publish this to clients based on client subscription
109 void zebra_mlag_process_mlag_data(uint8_t *data
, uint32_t len
)
111 struct stream
*s
= NULL
;
114 s
= stream_new(ZEBRA_MLAG_BUF_LIMIT
);
116 * Place holder we need the message type first
118 stream_putl(s
, msg_type
);
119 msg_type
= zebra_mlag_protobuf_decode_message(s
, data
, len
);
122 /* Something went wrong in decoding */
124 zlog_err("%s: failed to process mlag data-%d, %u", __func__
,
130 * additional four bytes are for message type
132 stream_putl_at(s
, 0, msg_type
);
133 thread_add_event(zrouter
.master
, zebra_mlag_post_data_from_main_thread
,
137 /**********************End of MLAG Interaction********************************/
139 /************************MLAG Thread Processing*******************************/
142 * after posting every 'ZEBRA_MLAG_POST_LIMIT' packets, MLAG Thread will be
143 * yielded to give CPU for other threads
145 #define ZEBRA_MLAG_POST_LIMIT 100
148 * This thread reads the clients data from the Global queue and encodes with
149 * protobuf and pass on to the MLAG socket.
151 static int zebra_mlag_client_msg_handler(struct thread
*event
)
154 uint32_t wr_count
= 0;
155 uint32_t msg_type
= 0;
156 uint32_t max_count
= 0;
159 wr_count
= stream_fifo_count_safe(zrouter
.mlag_info
.mlag_fifo
);
160 if (IS_ZEBRA_DEBUG_MLAG
)
161 zlog_debug(":%s: Processing MLAG write, %u messages in queue",
164 max_count
= MIN(wr_count
, ZEBRA_MLAG_POST_LIMIT
);
166 for (wr_count
= 0; wr_count
< max_count
; wr_count
++) {
167 s
= stream_fifo_pop_safe(zrouter
.mlag_info
.mlag_fifo
);
169 zlog_debug(":%s: Got a NULL Messages, some thing wrong",
175 * Encode the data now
177 len
= zebra_mlag_protobuf_encode_client_data(s
, &msg_type
);
183 hook_call(zebra_mlag_private_write_data
,
184 mlag_wr_buffer
, len
);
187 * If message type is De-register, send a signal to main
188 * thread, so that necessary cleanup will be done by
191 if (msg_type
== MLAG_DEREGISTER
) {
192 thread_add_event(zrouter
.master
,
193 zebra_mlag_terminate_pthread
,
201 if (IS_ZEBRA_DEBUG_MLAG
)
202 zlog_debug(":%s: Posted %d messages to MLAGD", __func__
,
205 * Currently there is only message write task is enqueued to this
206 * thread, yielding was added for future purpose, so that this thread
207 * can server other tasks also and in case FIFO is empty, this task will
208 * be schedule when main thread adds some messages
210 if (wr_count
>= ZEBRA_MLAG_POST_LIMIT
)
211 zebra_mlag_signal_write_thread();
216 * API to handle the process state.
217 * In case of Down, Zebra keep monitoring the MLAG state.
218 * all the state Notifications will be published to clients
220 void zebra_mlag_handle_process_state(enum zebra_mlag_state state
)
222 if (state
== MLAG_UP
) {
223 zrouter
.mlag_info
.connected
= true;
224 zebra_mlag_publish_process_state(NULL
, ZEBRA_MLAG_PROCESS_UP
);
225 zebra_mlag_send_register();
226 } else if (state
== MLAG_DOWN
) {
227 zrouter
.mlag_info
.connected
= false;
228 zebra_mlag_publish_process_state(NULL
, ZEBRA_MLAG_PROCESS_DOWN
);
229 hook_call(zebra_mlag_private_monitor_state
);
233 /***********************End of MLAG Thread processing*************************/
235 /*************************Multi-entratnt Api's********************************/
238 * Provider api to signal that work/events are available
239 * for the Zebra MLAG Write pthread.
240 * This API is called from 2 pthreads..
241 * 1) by main thread when client posts a MLAG Message
242 * 2) by MLAG Thread, in case of yield
243 * though this api, is called from two threads we don't need any locking
244 * because Thread task enqueue is thread safe means internally it had
245 * necessary protection
247 static int zebra_mlag_signal_write_thread(void)
249 if (IS_ZEBRA_DEBUG_MLAG
)
250 zlog_debug(":%s: Scheduling MLAG write", __func__
);
252 * This api will be called from Both main & MLAG Threads.
253 * main thread writes, "zrouter.mlag_info.th_master" only
254 * during Zebra Init/after MLAG thread is destroyed.
255 * so it is safe to use without any locking
257 thread_add_event(zrouter
.mlag_info
.th_master
,
258 zebra_mlag_client_msg_handler
, NULL
, 0,
259 &zrouter
.mlag_info
.t_write
);
264 * API will be used to publish the MLAG state to interested clients
265 * In case client is passed, state is posted only for that client,
266 * otherwise to all interested clients
267 * this api can be called from two threads.
268 * 1) from main thread: when client is passed
269 * 2) from MLAG Thread: when client is NULL
271 * In second case, to avoid global data access data will be post to Main
272 * thread, so that actual posting to clients will happen from Main thread.
274 static void zebra_mlag_publish_process_state(struct zserv
*client
,
275 zebra_message_types_t msg_type
)
279 if (IS_ZEBRA_DEBUG_MLAG
)
280 zlog_debug("%s: Publishing MLAG process state:%s to %s Client",
282 (msg_type
== ZEBRA_MLAG_PROCESS_UP
) ? "UP" : "DOWN",
283 (client
) ? "one" : "all");
286 s
= stream_new(ZEBRA_HEADER_SIZE
);
287 zclient_create_header(s
, msg_type
, VRF_DEFAULT
);
288 zserv_send_message(client
, s
);
294 * additional four bytes are for mesasge type
296 s
= stream_new(ZEBRA_HEADER_SIZE
+ ZEBRA_MLAG_METADATA_LEN
);
297 stream_putl(s
, ZEBRA_MLAG_MSG_BCAST
);
298 zclient_create_header(s
, msg_type
, VRF_DEFAULT
);
299 thread_add_event(zrouter
.master
, zebra_mlag_post_data_from_main_thread
,
303 /**************************End of Multi-entrant Apis**************************/
305 /***********************Zebra Main thread processing**************************/
308 * To avoid data corruption, messages will be post to clients only from
309 * main thread, because for that access was needed for clients list.
310 * so instead of forcing the locks, messages will be posted from main thread.
312 static int zebra_mlag_post_data_from_main_thread(struct thread
*thread
)
314 struct stream
*s
= THREAD_ARG(thread
);
315 struct stream
*zebra_s
= NULL
;
316 struct listnode
*node
;
317 struct zserv
*client
;
318 uint32_t msg_type
= 0;
319 uint32_t msg_len
= 0;
324 STREAM_GETL(s
, msg_type
);
325 if (IS_ZEBRA_DEBUG_MLAG
)
327 "%s: Posting MLAG data for msg_type:0x%x to interested clients",
330 msg_len
= s
->endp
- ZEBRA_MLAG_METADATA_LEN
;
331 for (ALL_LIST_ELEMENTS_RO(zrouter
.client_list
, node
, client
)) {
332 if (client
->mlag_updates_interested
== true) {
333 if (msg_type
!= ZEBRA_MLAG_MSG_BCAST
334 && !CHECK_FLAG(client
->mlag_reg_mask1
,
339 if (IS_ZEBRA_DEBUG_MLAG
)
341 "%s: Posting MLAG data of length-%d to client:%d ",
342 __func__
, msg_len
, client
->proto
);
344 zebra_s
= stream_new(msg_len
);
345 STREAM_GET(zebra_s
->data
, s
, msg_len
);
346 zebra_s
->endp
= msg_len
;
347 stream_putw_at(zebra_s
, 0, msg_len
);
350 * This stream will be enqueued to client_obuf, it will
351 * be freed after posting to client socket.
353 zserv_send_message(client
, zebra_s
);
363 stream_free(zebra_s
);
368 * Start the MLAG Thread, this will be used to write client data on to
369 * MLAG Process and to read the data from MLAG and post to clients.
370 * when all clients are un-registered, this Thread will be
373 static void zebra_mlag_spawn_pthread(void)
375 /* Start MLAG write pthread */
377 struct frr_pthread_attr pattr
= {.start
=
378 frr_pthread_attr_default
.start
,
379 .stop
= frr_pthread_attr_default
.stop
};
381 zrouter
.mlag_info
.zebra_pth_mlag
=
382 frr_pthread_new(&pattr
, "Zebra MLAG thread", "Zebra MLAG");
384 zrouter
.mlag_info
.th_master
= zrouter
.mlag_info
.zebra_pth_mlag
->master
;
387 /* Enqueue an initial event to the Newly spawn MLAG pthread */
388 zebra_mlag_signal_write_thread();
390 frr_pthread_run(zrouter
.mlag_info
.zebra_pth_mlag
, NULL
);
394 * all clients are un-registered for MLAG Updates, terminate the
397 static int zebra_mlag_terminate_pthread(struct thread
*event
)
399 if (IS_ZEBRA_DEBUG_MLAG
)
400 zlog_debug("Zebra MLAG write thread terminate called");
402 if (zrouter
.mlag_info
.clients_interested_cnt
) {
403 if (IS_ZEBRA_DEBUG_MLAG
)
405 "Zebra MLAG: still some clients are interested");
409 frr_pthread_stop(zrouter
.mlag_info
.zebra_pth_mlag
, NULL
);
411 /* Destroy pthread */
412 frr_pthread_destroy(zrouter
.mlag_info
.zebra_pth_mlag
);
413 zrouter
.mlag_info
.zebra_pth_mlag
= NULL
;
414 zrouter
.mlag_info
.th_master
= NULL
;
415 zrouter
.mlag_info
.t_read
= NULL
;
416 zrouter
.mlag_info
.t_write
= NULL
;
419 * Send Notification to clean private data
421 hook_call(zebra_mlag_private_cleanup_data
);
426 * API to register zebra client for MLAG Updates
428 void zebra_mlag_client_register(ZAPI_HANDLER_ARGS
)
431 uint32_t reg_mask
= 0;
434 if (IS_ZEBRA_DEBUG_MLAG
)
435 zlog_debug("Received MLAG Registration from client-proto:%d",
439 /* Get input stream. */
443 STREAM_GETL(s
, reg_mask
);
445 if (client
->mlag_updates_interested
== true) {
447 if (IS_ZEBRA_DEBUG_MLAG
)
449 "Client is registered, existing mask: 0x%x, new mask: 0x%x",
450 client
->mlag_reg_mask1
, reg_mask
);
451 if (client
->mlag_reg_mask1
!= reg_mask
)
452 client
->mlag_reg_mask1
= reg_mask
;
454 * Client might missed MLAG-UP Notification, post-it again
456 zebra_mlag_publish_process_state(client
, ZEBRA_MLAG_PROCESS_UP
);
461 client
->mlag_updates_interested
= true;
462 client
->mlag_reg_mask1
= reg_mask
;
463 if (IS_ZEBRA_DEBUG_MLAG
)
464 zlog_debug("Registering for MLAG Updates with mask: 0x%x, ",
465 client
->mlag_reg_mask1
);
467 zrouter
.mlag_info
.clients_interested_cnt
++;
469 if (zrouter
.mlag_info
.clients_interested_cnt
== 1) {
471 * First-client for MLAG Updates,open the communication channel
474 if (IS_ZEBRA_DEBUG_MLAG
)
476 "First client, opening the channel with MLAG");
478 zebra_mlag_spawn_pthread();
479 rc
= hook_call(zebra_mlag_private_open_channel
);
482 * For some reason, zebra not able to open the
483 * comm-channel with MLAG, so post MLAG-DOWN to client.
484 * later when the channel is open, zebra will send
487 if (IS_ZEBRA_DEBUG_MLAG
)
489 "Fail to open channel with MLAG,rc:%d, post Proto-down",
491 zebra_mlag_publish_process_state(
492 client
, ZEBRA_MLAG_PROCESS_DOWN
);
496 if (IS_ZEBRA_DEBUG_MLAG
)
497 zlog_debug("Client Registered successfully for MLAG Updates");
499 if (zrouter
.mlag_info
.connected
== true)
500 zebra_mlag_publish_process_state(client
, ZEBRA_MLAG_PROCESS_UP
);
506 * API to un-register for MLAG Updates
508 void zebra_mlag_client_unregister(ZAPI_HANDLER_ARGS
)
510 if (IS_ZEBRA_DEBUG_MLAG
)
511 zlog_debug("Received MLAG De-Registration from client-proto:%d",
514 if (client
->mlag_updates_interested
== false)
518 client
->mlag_updates_interested
= false;
519 client
->mlag_reg_mask1
= 0;
520 zrouter
.mlag_info
.clients_interested_cnt
--;
522 if (zrouter
.mlag_info
.clients_interested_cnt
== 0) {
524 * No-client is interested for MLAG Updates,close the
525 * communication channel with MLAG
527 if (IS_ZEBRA_DEBUG_MLAG
)
528 zlog_debug("Last client for MLAG, close the channel ");
533 * 1) main thread calls socket close which posts De-register
534 * to MLAG write thread
535 * 2) after MLAG write thread posts De-register it sends a
536 * signal back to main thread to do the thread cleanup
537 * this was mainly to make sure De-register is posted to MCLAGD.
539 hook_call(zebra_mlag_private_close_channel
);
542 if (IS_ZEBRA_DEBUG_MLAG
)
544 "Client De-Registered successfully for MLAG Updates");
548 * Does following things.
549 * 1) allocated new local stream, and copies the client data and enqueue
551 * 2) MLAG Thread after dequeing, encode the client data using protobuf
552 * and write on to MLAG
554 void zebra_mlag_forward_client_msg(ZAPI_HANDLER_ARGS
)
556 struct stream
*zebra_s
;
557 struct stream
*mlag_s
;
559 if (IS_ZEBRA_DEBUG_MLAG
)
560 zlog_debug("Received Client MLAG Data from client-proto:%d",
563 /* Get input stream. */
565 mlag_s
= stream_new(zebra_s
->endp
);
568 * Client data is | Zebra Header + MLAG Data |
569 * we need to enqueue only the MLAG data, skipping Zebra Header
571 stream_put(mlag_s
, zebra_s
->data
+ zebra_s
->getp
,
572 STREAM_READABLE(zebra_s
));
573 stream_fifo_push_safe(zrouter
.mlag_info
.mlag_fifo
, mlag_s
);
574 zebra_mlag_signal_write_thread();
576 if (IS_ZEBRA_DEBUG_MLAG
)
577 zlog_debug("%s: Enqueued Client:%d data to MLAG Thread ",
578 __func__
, client
->proto
);
581 /***********************End of Zebra Main thread processing*************/
583 enum mlag_role
zebra_mlag_get_role(void)
585 return zrouter
.mlag_info
.role
;
588 int32_t zebra_mlag_test_mlag_internal(const char *none
, const char *primary
,
589 const char *secondary
)
591 enum mlag_role orig
= zrouter
.mlag_info
.role
;
592 char buf1
[MLAG_ROLE_STRSIZE
], buf2
[MLAG_ROLE_STRSIZE
];
595 zrouter
.mlag_info
.role
= MLAG_ROLE_NONE
;
597 zrouter
.mlag_info
.role
= MLAG_ROLE_PRIMARY
;
599 zrouter
.mlag_info
.role
= MLAG_ROLE_SECONDARY
;
601 if (IS_ZEBRA_DEBUG_MLAG
)
602 zlog_debug("Test: Changing role from %s to %s",
603 mlag_role2str(orig
, buf1
, sizeof(buf1
)),
604 mlag_role2str(orig
, buf2
, sizeof(buf2
)));
606 if (orig
!= zrouter
.mlag_info
.role
) {
607 zsend_capabilities_all_clients();
608 if (zrouter
.mlag_info
.role
!= MLAG_ROLE_NONE
) {
609 if (zrouter
.mlag_info
.clients_interested_cnt
== 0
610 && !test_mlag_in_progress
) {
611 if (zrouter
.mlag_info
.zebra_pth_mlag
== NULL
)
612 zebra_mlag_spawn_pthread();
613 zrouter
.mlag_info
.clients_interested_cnt
++;
614 test_mlag_in_progress
= true;
615 hook_call(zebra_mlag_private_open_channel
);
618 if (test_mlag_in_progress
) {
619 test_mlag_in_progress
= false;
620 zrouter
.mlag_info
.clients_interested_cnt
--;
621 hook_call(zebra_mlag_private_close_channel
);
629 void zebra_mlag_init(void)
631 zebra_mlag_vty_init();
634 * Intialiaze the MLAG Global variables
635 * write thread will be created during actual registration with MCLAG
637 zrouter
.mlag_info
.clients_interested_cnt
= 0;
638 zrouter
.mlag_info
.connected
= false;
639 zrouter
.mlag_info
.timer_running
= false;
640 zrouter
.mlag_info
.mlag_fifo
= stream_fifo_new();
641 zrouter
.mlag_info
.zebra_pth_mlag
= NULL
;
642 zrouter
.mlag_info
.th_master
= NULL
;
643 zrouter
.mlag_info
.t_read
= NULL
;
644 zrouter
.mlag_info
.t_write
= NULL
;
645 test_mlag_in_progress
= false;
646 zebra_mlag_reset_read_buffer();
649 void zebra_mlag_terminate(void)
656 * ProtoBuf Encoding APIs
659 #ifdef HAVE_PROTOBUF_VERSION_3
661 DEFINE_MTYPE_STATIC(ZEBRA
, MLAG_PBUF
, "ZEBRA MLAG PROTOBUF");
663 int zebra_mlag_protobuf_encode_client_data(struct stream
*s
, uint32_t *msg_type
)
665 ZebraMlagHeader hdr
= ZEBRA_MLAG__HEADER__INIT
;
666 struct mlag_msg mlag_msg
;
667 uint8_t tmp_buf
[ZEBRA_MLAG_BUF_LIMIT
];
671 char buf
[ZLOG_FILTER_LENGTH_MAX
];
674 if (IS_ZEBRA_DEBUG_MLAG
)
675 zlog_debug("%s: Entering..", __func__
);
677 rc
= mlag_lib_decode_mlag_hdr(s
, &mlag_msg
, &length
);
681 memset(tmp_buf
, 0, ZEBRA_MLAG_BUF_LIMIT
);
683 if (IS_ZEBRA_DEBUG_MLAG
)
684 zlog_debug("%s: Mlag ProtoBuf encoding of message:%s, len:%d",
686 mlag_lib_msgid_to_str(mlag_msg
.msg_type
, buf
,
689 *msg_type
= mlag_msg
.msg_type
;
690 switch (mlag_msg
.msg_type
) {
691 case MLAG_MROUTE_ADD
: {
692 struct mlag_mroute_add msg
;
693 ZebraMlagMrouteAdd pay_load
= ZEBRA_MLAG_MROUTE_ADD__INIT
;
694 uint32_t vrf_name_len
= 0;
696 rc
= mlag_lib_decode_mroute_add(s
, &msg
, &length
);
700 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
701 pay_load
.vrf_name
= XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
702 strlcpy(pay_load
.vrf_name
, msg
.vrf_name
, vrf_name_len
);
703 pay_load
.source_ip
= msg
.source_ip
;
704 pay_load
.group_ip
= msg
.group_ip
;
705 pay_load
.cost_to_rp
= msg
.cost_to_rp
;
706 pay_load
.owner_id
= msg
.owner_id
;
707 pay_load
.am_i_dr
= msg
.am_i_dr
;
708 pay_load
.am_i_dual_active
= msg
.am_i_dual_active
;
709 pay_load
.vrf_id
= msg
.vrf_id
;
711 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
712 vrf_name_len
= strlen(msg
.intf_name
) + 1;
714 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
715 strlcpy(pay_load
.intf_name
, msg
.intf_name
,
719 len
= zebra_mlag_mroute_add__pack(&pay_load
, tmp_buf
);
720 XFREE(MTYPE_MLAG_PBUF
, pay_load
.vrf_name
);
721 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
)
722 XFREE(MTYPE_MLAG_PBUF
, pay_load
.intf_name
);
724 case MLAG_MROUTE_DEL
: {
725 struct mlag_mroute_del msg
;
726 ZebraMlagMrouteDel pay_load
= ZEBRA_MLAG_MROUTE_DEL__INIT
;
727 uint32_t vrf_name_len
= 0;
729 rc
= mlag_lib_decode_mroute_del(s
, &msg
, &length
);
732 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
733 pay_load
.vrf_name
= XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
734 strlcpy(pay_load
.vrf_name
, msg
.vrf_name
, vrf_name_len
);
735 pay_load
.source_ip
= msg
.source_ip
;
736 pay_load
.group_ip
= msg
.group_ip
;
737 pay_load
.owner_id
= msg
.owner_id
;
738 pay_load
.vrf_id
= msg
.vrf_id
;
740 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
741 vrf_name_len
= strlen(msg
.intf_name
) + 1;
743 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
744 strlcpy(pay_load
.intf_name
, msg
.intf_name
,
748 len
= zebra_mlag_mroute_del__pack(&pay_load
, tmp_buf
);
749 XFREE(MTYPE_MLAG_PBUF
, pay_load
.vrf_name
);
750 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
)
751 XFREE(MTYPE_MLAG_PBUF
, pay_load
.intf_name
);
753 case MLAG_MROUTE_ADD_BULK
: {
754 struct mlag_mroute_add msg
;
755 ZebraMlagMrouteAddBulk Bulk_msg
=
756 ZEBRA_MLAG_MROUTE_ADD_BULK__INIT
;
757 ZebraMlagMrouteAdd
**pay_load
= NULL
;
758 bool cleanup
= false;
761 Bulk_msg
.n_mroute_add
= mlag_msg
.msg_cnt
;
762 pay_load
= XMALLOC(MTYPE_MLAG_PBUF
, sizeof(ZebraMlagMrouteAdd
*)
765 for (i
= 0, actual
= 0; i
< mlag_msg
.msg_cnt
; i
++, actual
++) {
767 uint32_t vrf_name_len
= 0;
769 rc
= mlag_lib_decode_mroute_add(s
, &msg
, &length
);
774 pay_load
[i
] = XMALLOC(MTYPE_MLAG_PBUF
,
775 sizeof(ZebraMlagMrouteAdd
));
776 zebra_mlag_mroute_add__init(pay_load
[i
]);
778 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
779 pay_load
[i
]->vrf_name
=
780 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
781 strlcpy(pay_load
[i
]->vrf_name
, msg
.vrf_name
,
783 pay_load
[i
]->source_ip
= msg
.source_ip
;
784 pay_load
[i
]->group_ip
= msg
.group_ip
;
785 pay_load
[i
]->cost_to_rp
= msg
.cost_to_rp
;
786 pay_load
[i
]->owner_id
= msg
.owner_id
;
787 pay_load
[i
]->am_i_dr
= msg
.am_i_dr
;
788 pay_load
[i
]->am_i_dual_active
= msg
.am_i_dual_active
;
789 pay_load
[i
]->vrf_id
= msg
.vrf_id
;
790 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
791 vrf_name_len
= strlen(msg
.intf_name
) + 1;
792 pay_load
[i
]->intf_name
=
793 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
795 strlcpy(pay_load
[i
]->intf_name
, msg
.intf_name
,
800 Bulk_msg
.mroute_add
= pay_load
;
801 len
= zebra_mlag_mroute_add_bulk__pack(&Bulk_msg
,
805 for (i
= 0; i
< actual
; i
++) {
807 * The mlag_lib_decode_mroute_add can
808 * fail to properly decode and cause nothing
809 * to be allocated. Prevent a crash
814 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->vrf_name
);
815 if (pay_load
[i
]->owner_id
== MLAG_OWNER_INTERFACE
816 && pay_load
[i
]->intf_name
)
817 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->intf_name
);
818 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]);
820 XFREE(MTYPE_MLAG_PBUF
, pay_load
);
824 case MLAG_MROUTE_DEL_BULK
: {
825 struct mlag_mroute_del msg
;
826 ZebraMlagMrouteDelBulk Bulk_msg
=
827 ZEBRA_MLAG_MROUTE_DEL_BULK__INIT
;
828 ZebraMlagMrouteDel
**pay_load
= NULL
;
829 bool cleanup
= false;
832 Bulk_msg
.n_mroute_del
= mlag_msg
.msg_cnt
;
833 pay_load
= XMALLOC(MTYPE_MLAG_PBUF
, sizeof(ZebraMlagMrouteDel
*)
836 for (i
= 0, actual
= 0; i
< mlag_msg
.msg_cnt
; i
++, actual
++) {
838 uint32_t vrf_name_len
= 0;
840 rc
= mlag_lib_decode_mroute_del(s
, &msg
, &length
);
846 pay_load
[i
] = XMALLOC(MTYPE_MLAG_PBUF
,
847 sizeof(ZebraMlagMrouteDel
));
848 zebra_mlag_mroute_del__init(pay_load
[i
]);
850 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
851 pay_load
[i
]->vrf_name
=
852 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
854 strlcpy(pay_load
[i
]->vrf_name
, msg
.vrf_name
,
856 pay_load
[i
]->source_ip
= msg
.source_ip
;
857 pay_load
[i
]->group_ip
= msg
.group_ip
;
858 pay_load
[i
]->owner_id
= msg
.owner_id
;
859 pay_load
[i
]->vrf_id
= msg
.vrf_id
;
860 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
861 vrf_name_len
= strlen(msg
.intf_name
) + 1;
862 pay_load
[i
]->intf_name
=
863 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
865 strlcpy(pay_load
[i
]->intf_name
, msg
.intf_name
,
870 Bulk_msg
.mroute_del
= pay_load
;
871 len
= zebra_mlag_mroute_del_bulk__pack(&Bulk_msg
,
875 for (i
= 0; i
< actual
; i
++) {
877 * The mlag_lib_decode_mroute_add can
878 * fail to properly decode and cause nothing
879 * to be allocated. Prevent a crash
884 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->vrf_name
);
885 if (pay_load
[i
]->owner_id
== MLAG_OWNER_INTERFACE
886 && pay_load
[i
]->intf_name
)
887 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->intf_name
);
888 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]);
890 XFREE(MTYPE_MLAG_PBUF
, pay_load
);
898 if (IS_ZEBRA_DEBUG_MLAG
)
899 zlog_debug("%s: length of Mlag ProtoBuf encoded message:%s, %d",
901 mlag_lib_msgid_to_str(mlag_msg
.msg_type
, buf
,
904 hdr
.type
= (ZebraMlagHeader__MessageType
)mlag_msg
.msg_type
;
907 hdr
.data
.data
= XMALLOC(MTYPE_MLAG_PBUF
, len
);
908 memcpy(hdr
.data
.data
, tmp_buf
, len
);
912 * ProtoBuf Infra will not support to demarc the pointers whem multiple
913 * messages are posted inside a single Buffer.
914 * 2 -solutions exist to solve this
915 * 1. add Unenoced length at the beginning of every message, this will
916 * be used to point to next message in the buffer
917 * 2. another solution is defining all messages insides another message
918 * But this will permit only 32 messages. this can be extended with
920 * for simplicity we are going with solution-1.
922 len
= zebra_mlag__header__pack(&hdr
,
923 (mlag_wr_buffer
+ ZEBRA_MLAG_LEN_SIZE
));
925 memcpy(mlag_wr_buffer
, &n_len
, ZEBRA_MLAG_LEN_SIZE
);
926 len
+= ZEBRA_MLAG_LEN_SIZE
;
928 if (IS_ZEBRA_DEBUG_MLAG
)
930 "%s: length of Mlag ProtoBuf message:%s with Header %d",
932 mlag_lib_msgid_to_str(mlag_msg
.msg_type
, buf
,
935 XFREE(MTYPE_MLAG_PBUF
, hdr
.data
.data
);
940 static void zebra_fill_protobuf_msg(struct stream
*s
, char *name
, int len
)
942 int str_len
= strlen(name
) + 1;
944 stream_put(s
, name
, str_len
);
945 /* Fill the rest with Null Character for aligning */
946 stream_put(s
, NULL
, len
- str_len
);
949 int zebra_mlag_protobuf_decode_message(struct stream
*s
, uint8_t *data
,
953 ZebraMlagHeader
*hdr
;
956 hdr
= zebra_mlag__header__unpack(NULL
, len
, data
);
961 * ADD The MLAG Header
963 zclient_create_header(s
, ZEBRA_MLAG_FORWARD_MSG
, VRF_DEFAULT
);
965 msg_type
= hdr
->type
;
967 if (IS_ZEBRA_DEBUG_MLAG
)
968 zlog_debug("%s: Mlag ProtoBuf decoding of message:%s", __func__
,
969 mlag_lib_msgid_to_str(msg_type
, buf
, 80));
972 * Internal MLAG Message-types & MLAG.proto message types should
973 * always match, otherwise there can be decoding errors
974 * To avoid exposing clients with Protobuf flags, using internal
977 stream_putl(s
, hdr
->type
);
979 if (hdr
->data
.len
== 0) {
981 stream_putw(s
, MLAG_MSG_NULL_PAYLOAD
);
983 stream_putw(s
, MLAG_MSG_NO_BATCH
);
986 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_STATUS_UPDATE
: {
987 ZebraMlagStatusUpdate
*msg
= NULL
;
989 msg
= zebra_mlag_status_update__unpack(
990 NULL
, hdr
->data
.len
, hdr
->data
.data
);
992 zebra_mlag__header__free_unpacked(hdr
, NULL
);
996 stream_putw(s
, sizeof(struct mlag_status
));
998 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1000 zebra_fill_protobuf_msg(s
, msg
->peerlink
,
1002 stream_putl(s
, msg
->my_role
);
1003 stream_putl(s
, msg
->peer_state
);
1004 zebra_mlag_status_update__free_unpacked(msg
, NULL
);
1006 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_VXLAN_UPDATE
: {
1007 ZebraMlagVxlanUpdate
*msg
= NULL
;
1009 msg
= zebra_mlag_vxlan_update__unpack(
1010 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1012 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1016 stream_putw(s
, sizeof(struct mlag_vxlan
));
1018 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1020 stream_putl(s
, msg
->anycast_ip
);
1021 stream_putl(s
, msg
->local_ip
);
1022 zebra_mlag_vxlan_update__free_unpacked(msg
, NULL
);
1024 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_ADD
: {
1025 ZebraMlagMrouteAdd
*msg
= NULL
;
1027 msg
= zebra_mlag_mroute_add__unpack(NULL
, hdr
->data
.len
,
1030 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1034 stream_putw(s
, sizeof(struct mlag_mroute_add
));
1036 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1038 zebra_fill_protobuf_msg(s
, msg
->vrf_name
, VRF_NAMSIZ
);
1040 stream_putl(s
, msg
->source_ip
);
1041 stream_putl(s
, msg
->group_ip
);
1042 stream_putl(s
, msg
->cost_to_rp
);
1043 stream_putl(s
, msg
->owner_id
);
1044 stream_putc(s
, msg
->am_i_dr
);
1045 stream_putc(s
, msg
->am_i_dual_active
);
1046 stream_putl(s
, msg
->vrf_id
);
1047 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1048 zebra_fill_protobuf_msg(s
, msg
->intf_name
,
1051 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1052 zebra_mlag_mroute_add__free_unpacked(msg
, NULL
);
1054 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_DEL
: {
1055 ZebraMlagMrouteDel
*msg
= NULL
;
1057 msg
= zebra_mlag_mroute_del__unpack(NULL
, hdr
->data
.len
,
1060 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1064 stream_putw(s
, sizeof(struct mlag_mroute_del
));
1066 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1068 zebra_fill_protobuf_msg(s
, msg
->vrf_name
, VRF_NAMSIZ
);
1070 stream_putl(s
, msg
->source_ip
);
1071 stream_putl(s
, msg
->group_ip
);
1072 stream_putl(s
, msg
->owner_id
);
1073 stream_putl(s
, msg
->vrf_id
);
1074 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1075 zebra_fill_protobuf_msg(s
, msg
->intf_name
,
1078 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1079 zebra_mlag_mroute_del__free_unpacked(msg
, NULL
);
1081 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_ADD_BULK
: {
1082 ZebraMlagMrouteAddBulk
*Bulk_msg
= NULL
;
1083 ZebraMlagMrouteAdd
*msg
= NULL
;
1084 size_t i
, length_spot
;
1086 Bulk_msg
= zebra_mlag_mroute_add_bulk__unpack(
1087 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1088 if (Bulk_msg
== NULL
) {
1089 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1093 stream_putw(s
, (Bulk_msg
->n_mroute_add
1094 * sizeof(struct mlag_mroute_add
)));
1095 /* No. of msgs in Batch */
1096 length_spot
= stream_putw(s
, Bulk_msg
->n_mroute_add
);
1099 for (i
= 0; i
< Bulk_msg
->n_mroute_add
; i
++) {
1101 < VRF_NAMSIZ
+ 22 + INTERFACE_NAMSIZ
) {
1103 "We have received more messages than we can parse at this point in time: %zu",
1104 Bulk_msg
->n_mroute_add
);
1108 msg
= Bulk_msg
->mroute_add
[i
];
1110 zebra_fill_protobuf_msg(s
, msg
->vrf_name
,
1112 stream_putl(s
, msg
->source_ip
);
1113 stream_putl(s
, msg
->group_ip
);
1114 stream_putl(s
, msg
->cost_to_rp
);
1115 stream_putl(s
, msg
->owner_id
);
1116 stream_putc(s
, msg
->am_i_dr
);
1117 stream_putc(s
, msg
->am_i_dual_active
);
1118 stream_putl(s
, msg
->vrf_id
);
1119 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1120 zebra_fill_protobuf_msg(
1124 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1127 stream_putw_at(s
, length_spot
, i
+ 1);
1129 zebra_mlag_mroute_add_bulk__free_unpacked(Bulk_msg
,
1132 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_DEL_BULK
: {
1133 ZebraMlagMrouteDelBulk
*Bulk_msg
= NULL
;
1134 ZebraMlagMrouteDel
*msg
= NULL
;
1135 size_t i
, length_spot
;
1137 Bulk_msg
= zebra_mlag_mroute_del_bulk__unpack(
1138 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1139 if (Bulk_msg
== NULL
) {
1140 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1144 stream_putw(s
, (Bulk_msg
->n_mroute_del
1145 * sizeof(struct mlag_mroute_del
)));
1146 /* No. of msgs in Batch */
1147 length_spot
= stream_putw(s
, Bulk_msg
->n_mroute_del
);
1150 for (i
= 0; i
< Bulk_msg
->n_mroute_del
; i
++) {
1152 < VRF_NAMSIZ
+ 16 + INTERFACE_NAMSIZ
) {
1154 "We have received more messages than we can parse at this time");
1158 msg
= Bulk_msg
->mroute_del
[i
];
1160 zebra_fill_protobuf_msg(s
, msg
->vrf_name
,
1162 stream_putl(s
, msg
->source_ip
);
1163 stream_putl(s
, msg
->group_ip
);
1164 stream_putl(s
, msg
->owner_id
);
1165 stream_putl(s
, msg
->vrf_id
);
1166 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1167 zebra_fill_protobuf_msg(
1171 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1174 stream_putw_at(s
, length_spot
, i
+ 1);
1176 zebra_mlag_mroute_del_bulk__free_unpacked(Bulk_msg
,
1179 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_ZEBRA_STATUS_UPDATE
: {
1180 ZebraMlagZebraStatusUpdate
*msg
= NULL
;
1182 msg
= zebra_mlag_zebra_status_update__unpack(
1183 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1185 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1189 stream_putw(s
, sizeof(struct mlag_frr_status
));
1191 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1193 stream_putl(s
, msg
->peer_frrstate
);
1194 zebra_mlag_zebra_status_update__free_unpacked(msg
,
1201 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1206 int zebra_mlag_protobuf_encode_client_data(struct stream
*s
, uint32_t *msg_type
)
1211 int zebra_mlag_protobuf_decode_message(struct stream
*s
, uint8_t *data
,