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 void zebra_mlag_terminate_pthread(struct thread
*event
);
56 static void 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 void 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();
215 * API to handle the process state.
216 * In case of Down, Zebra keep monitoring the MLAG state.
217 * all the state Notifications will be published to clients
219 void zebra_mlag_handle_process_state(enum zebra_mlag_state state
)
221 if (state
== MLAG_UP
) {
222 zrouter
.mlag_info
.connected
= true;
223 zebra_mlag_publish_process_state(NULL
, ZEBRA_MLAG_PROCESS_UP
);
224 zebra_mlag_send_register();
225 } else if (state
== MLAG_DOWN
) {
226 zrouter
.mlag_info
.connected
= false;
227 zebra_mlag_publish_process_state(NULL
, ZEBRA_MLAG_PROCESS_DOWN
);
228 hook_call(zebra_mlag_private_monitor_state
);
232 /***********************End of MLAG Thread processing*************************/
234 /*************************Multi-entratnt Api's********************************/
237 * Provider api to signal that work/events are available
238 * for the Zebra MLAG Write pthread.
239 * This API is called from 2 pthreads..
240 * 1) by main thread when client posts a MLAG Message
241 * 2) by MLAG Thread, in case of yield
242 * though this api, is called from two threads we don't need any locking
243 * because Thread task enqueue is thread safe means internally it had
244 * necessary protection
246 static int zebra_mlag_signal_write_thread(void)
248 if (IS_ZEBRA_DEBUG_MLAG
)
249 zlog_debug(":%s: Scheduling MLAG write", __func__
);
251 * This api will be called from Both main & MLAG Threads.
252 * main thread writes, "zrouter.mlag_info.th_master" only
253 * during Zebra Init/after MLAG thread is destroyed.
254 * so it is safe to use without any locking
256 thread_add_event(zrouter
.mlag_info
.th_master
,
257 zebra_mlag_client_msg_handler
, NULL
, 0,
258 &zrouter
.mlag_info
.t_write
);
263 * API will be used to publish the MLAG state to interested clients
264 * In case client is passed, state is posted only for that client,
265 * otherwise to all interested clients
266 * this api can be called from two threads.
267 * 1) from main thread: when client is passed
268 * 2) from MLAG Thread: when client is NULL
270 * In second case, to avoid global data access data will be post to Main
271 * thread, so that actual posting to clients will happen from Main thread.
273 static void zebra_mlag_publish_process_state(struct zserv
*client
,
274 zebra_message_types_t msg_type
)
278 if (IS_ZEBRA_DEBUG_MLAG
)
279 zlog_debug("%s: Publishing MLAG process state:%s to %s Client",
281 (msg_type
== ZEBRA_MLAG_PROCESS_UP
) ? "UP" : "DOWN",
282 (client
) ? "one" : "all");
285 s
= stream_new(ZEBRA_HEADER_SIZE
);
286 zclient_create_header(s
, msg_type
, VRF_DEFAULT
);
287 zserv_send_message(client
, s
);
293 * additional four bytes are for mesasge type
295 s
= stream_new(ZEBRA_HEADER_SIZE
+ ZEBRA_MLAG_METADATA_LEN
);
296 stream_putl(s
, ZEBRA_MLAG_MSG_BCAST
);
297 zclient_create_header(s
, msg_type
, VRF_DEFAULT
);
298 thread_add_event(zrouter
.master
, zebra_mlag_post_data_from_main_thread
,
302 /**************************End of Multi-entrant Apis**************************/
304 /***********************Zebra Main thread processing**************************/
307 * To avoid data corruption, messages will be post to clients only from
308 * main thread, because for that access was needed for clients list.
309 * so instead of forcing the locks, messages will be posted from main thread.
311 static void zebra_mlag_post_data_from_main_thread(struct thread
*thread
)
313 struct stream
*s
= THREAD_ARG(thread
);
314 struct stream
*zebra_s
= NULL
;
315 struct listnode
*node
;
316 struct zserv
*client
;
317 uint32_t msg_type
= 0;
318 uint32_t msg_len
= 0;
323 STREAM_GETL(s
, msg_type
);
324 if (IS_ZEBRA_DEBUG_MLAG
)
326 "%s: Posting MLAG data for msg_type:0x%x to interested clients",
329 msg_len
= s
->endp
- ZEBRA_MLAG_METADATA_LEN
;
330 for (ALL_LIST_ELEMENTS_RO(zrouter
.client_list
, node
, client
)) {
331 if (client
->mlag_updates_interested
== true) {
332 if (msg_type
!= ZEBRA_MLAG_MSG_BCAST
333 && !CHECK_FLAG(client
->mlag_reg_mask1
,
338 if (IS_ZEBRA_DEBUG_MLAG
)
340 "%s: Posting MLAG data of length-%d to client:%d ",
341 __func__
, msg_len
, client
->proto
);
343 zebra_s
= stream_new(msg_len
);
344 STREAM_GET(zebra_s
->data
, s
, msg_len
);
345 zebra_s
->endp
= msg_len
;
346 stream_putw_at(zebra_s
, 0, msg_len
);
349 * This stream will be enqueued to client_obuf, it will
350 * be freed after posting to client socket.
352 zserv_send_message(client
, zebra_s
);
362 stream_free(zebra_s
);
366 * Start the MLAG Thread, this will be used to write client data on to
367 * MLAG Process and to read the data from MLAG and post to clients.
368 * when all clients are un-registered, this Thread will be
371 static void zebra_mlag_spawn_pthread(void)
373 /* Start MLAG write pthread */
375 struct frr_pthread_attr pattr
= {.start
=
376 frr_pthread_attr_default
.start
,
377 .stop
= frr_pthread_attr_default
.stop
};
379 zrouter
.mlag_info
.zebra_pth_mlag
=
380 frr_pthread_new(&pattr
, "Zebra MLAG thread", "Zebra MLAG");
382 zrouter
.mlag_info
.th_master
= zrouter
.mlag_info
.zebra_pth_mlag
->master
;
385 /* Enqueue an initial event to the Newly spawn MLAG pthread */
386 zebra_mlag_signal_write_thread();
388 frr_pthread_run(zrouter
.mlag_info
.zebra_pth_mlag
, NULL
);
392 * all clients are un-registered for MLAG Updates, terminate the
395 static void zebra_mlag_terminate_pthread(struct thread
*event
)
397 if (IS_ZEBRA_DEBUG_MLAG
)
398 zlog_debug("Zebra MLAG write thread terminate called");
400 if (zrouter
.mlag_info
.clients_interested_cnt
) {
401 if (IS_ZEBRA_DEBUG_MLAG
)
403 "Zebra MLAG: still some clients are interested");
407 frr_pthread_stop(zrouter
.mlag_info
.zebra_pth_mlag
, NULL
);
409 /* Destroy pthread */
410 frr_pthread_destroy(zrouter
.mlag_info
.zebra_pth_mlag
);
411 zrouter
.mlag_info
.zebra_pth_mlag
= NULL
;
412 zrouter
.mlag_info
.th_master
= NULL
;
413 zrouter
.mlag_info
.t_read
= NULL
;
414 zrouter
.mlag_info
.t_write
= NULL
;
417 * Send Notification to clean private data
419 hook_call(zebra_mlag_private_cleanup_data
);
423 * API to register zebra client for MLAG Updates
425 void zebra_mlag_client_register(ZAPI_HANDLER_ARGS
)
428 uint32_t reg_mask
= 0;
431 if (IS_ZEBRA_DEBUG_MLAG
)
432 zlog_debug("Received MLAG Registration from client-proto:%d",
436 /* Get input stream. */
440 STREAM_GETL(s
, reg_mask
);
442 if (client
->mlag_updates_interested
== true) {
444 if (IS_ZEBRA_DEBUG_MLAG
)
446 "Client is registered, existing mask: 0x%x, new mask: 0x%x",
447 client
->mlag_reg_mask1
, reg_mask
);
448 if (client
->mlag_reg_mask1
!= reg_mask
)
449 client
->mlag_reg_mask1
= reg_mask
;
451 * Client might missed MLAG-UP Notification, post-it again
453 zebra_mlag_publish_process_state(client
, ZEBRA_MLAG_PROCESS_UP
);
458 client
->mlag_updates_interested
= true;
459 client
->mlag_reg_mask1
= reg_mask
;
460 if (IS_ZEBRA_DEBUG_MLAG
)
461 zlog_debug("Registering for MLAG Updates with mask: 0x%x, ",
462 client
->mlag_reg_mask1
);
464 zrouter
.mlag_info
.clients_interested_cnt
++;
466 if (zrouter
.mlag_info
.clients_interested_cnt
== 1) {
468 * First-client for MLAG Updates,open the communication channel
471 if (IS_ZEBRA_DEBUG_MLAG
)
473 "First client, opening the channel with MLAG");
475 zebra_mlag_spawn_pthread();
476 rc
= hook_call(zebra_mlag_private_open_channel
);
479 * For some reason, zebra not able to open the
480 * comm-channel with MLAG, so post MLAG-DOWN to client.
481 * later when the channel is open, zebra will send
484 if (IS_ZEBRA_DEBUG_MLAG
)
486 "Fail to open channel with MLAG,rc:%d, post Proto-down",
488 zebra_mlag_publish_process_state(
489 client
, ZEBRA_MLAG_PROCESS_DOWN
);
493 if (IS_ZEBRA_DEBUG_MLAG
)
494 zlog_debug("Client Registered successfully for MLAG Updates");
496 if (zrouter
.mlag_info
.connected
== true)
497 zebra_mlag_publish_process_state(client
, ZEBRA_MLAG_PROCESS_UP
);
503 * API to un-register for MLAG Updates
505 void zebra_mlag_client_unregister(ZAPI_HANDLER_ARGS
)
507 if (IS_ZEBRA_DEBUG_MLAG
)
508 zlog_debug("Received MLAG De-Registration from client-proto:%d",
511 if (client
->mlag_updates_interested
== false)
515 client
->mlag_updates_interested
= false;
516 client
->mlag_reg_mask1
= 0;
517 zrouter
.mlag_info
.clients_interested_cnt
--;
519 if (zrouter
.mlag_info
.clients_interested_cnt
== 0) {
521 * No-client is interested for MLAG Updates,close the
522 * communication channel with MLAG
524 if (IS_ZEBRA_DEBUG_MLAG
)
525 zlog_debug("Last client for MLAG, close the channel ");
530 * 1) main thread calls socket close which posts De-register
531 * to MLAG write thread
532 * 2) after MLAG write thread posts De-register it sends a
533 * signal back to main thread to do the thread cleanup
534 * this was mainly to make sure De-register is posted to MCLAGD.
536 hook_call(zebra_mlag_private_close_channel
);
539 if (IS_ZEBRA_DEBUG_MLAG
)
541 "Client De-Registered successfully for MLAG Updates");
545 * Does following things.
546 * 1) allocated new local stream, and copies the client data and enqueue
548 * 2) MLAG Thread after dequeing, encode the client data using protobuf
549 * and write on to MLAG
551 void zebra_mlag_forward_client_msg(ZAPI_HANDLER_ARGS
)
553 struct stream
*zebra_s
;
554 struct stream
*mlag_s
;
556 if (IS_ZEBRA_DEBUG_MLAG
)
557 zlog_debug("Received Client MLAG Data from client-proto:%d",
560 /* Get input stream. */
562 mlag_s
= stream_new(zebra_s
->endp
);
565 * Client data is | Zebra Header + MLAG Data |
566 * we need to enqueue only the MLAG data, skipping Zebra Header
568 stream_put(mlag_s
, zebra_s
->data
+ zebra_s
->getp
,
569 STREAM_READABLE(zebra_s
));
570 stream_fifo_push_safe(zrouter
.mlag_info
.mlag_fifo
, mlag_s
);
571 zebra_mlag_signal_write_thread();
573 if (IS_ZEBRA_DEBUG_MLAG
)
574 zlog_debug("%s: Enqueued Client:%d data to MLAG Thread ",
575 __func__
, client
->proto
);
578 /***********************End of Zebra Main thread processing*************/
580 enum mlag_role
zebra_mlag_get_role(void)
582 return zrouter
.mlag_info
.role
;
585 int32_t zebra_mlag_test_mlag_internal(const char *none
, const char *primary
,
586 const char *secondary
)
588 enum mlag_role orig
= zrouter
.mlag_info
.role
;
589 char buf1
[MLAG_ROLE_STRSIZE
], buf2
[MLAG_ROLE_STRSIZE
];
592 zrouter
.mlag_info
.role
= MLAG_ROLE_NONE
;
594 zrouter
.mlag_info
.role
= MLAG_ROLE_PRIMARY
;
596 zrouter
.mlag_info
.role
= MLAG_ROLE_SECONDARY
;
598 if (IS_ZEBRA_DEBUG_MLAG
)
599 zlog_debug("Test: Changing role from %s to %s",
600 mlag_role2str(orig
, buf1
, sizeof(buf1
)),
601 mlag_role2str(orig
, buf2
, sizeof(buf2
)));
603 if (orig
!= zrouter
.mlag_info
.role
) {
604 zsend_capabilities_all_clients();
605 if (zrouter
.mlag_info
.role
!= MLAG_ROLE_NONE
) {
606 if (zrouter
.mlag_info
.clients_interested_cnt
== 0
607 && !test_mlag_in_progress
) {
608 if (zrouter
.mlag_info
.zebra_pth_mlag
== NULL
)
609 zebra_mlag_spawn_pthread();
610 zrouter
.mlag_info
.clients_interested_cnt
++;
611 test_mlag_in_progress
= true;
612 hook_call(zebra_mlag_private_open_channel
);
615 if (test_mlag_in_progress
) {
616 test_mlag_in_progress
= false;
617 zrouter
.mlag_info
.clients_interested_cnt
--;
618 hook_call(zebra_mlag_private_close_channel
);
626 void zebra_mlag_init(void)
628 zebra_mlag_vty_init();
631 * Intialiaze the MLAG Global variables
632 * write thread will be created during actual registration with MCLAG
634 zrouter
.mlag_info
.clients_interested_cnt
= 0;
635 zrouter
.mlag_info
.connected
= false;
636 zrouter
.mlag_info
.timer_running
= false;
637 zrouter
.mlag_info
.mlag_fifo
= stream_fifo_new();
638 zrouter
.mlag_info
.zebra_pth_mlag
= NULL
;
639 zrouter
.mlag_info
.th_master
= NULL
;
640 zrouter
.mlag_info
.t_read
= NULL
;
641 zrouter
.mlag_info
.t_write
= NULL
;
642 test_mlag_in_progress
= false;
643 zebra_mlag_reset_read_buffer();
646 void zebra_mlag_terminate(void)
653 * ProtoBuf Encoding APIs
656 #ifdef HAVE_PROTOBUF_VERSION_3
658 DEFINE_MTYPE_STATIC(ZEBRA
, MLAG_PBUF
, "ZEBRA MLAG PROTOBUF");
660 int zebra_mlag_protobuf_encode_client_data(struct stream
*s
, uint32_t *msg_type
)
662 ZebraMlagHeader hdr
= ZEBRA_MLAG__HEADER__INIT
;
663 struct mlag_msg mlag_msg
;
664 uint8_t tmp_buf
[ZEBRA_MLAG_BUF_LIMIT
];
668 char buf
[ZLOG_FILTER_LENGTH_MAX
];
671 if (IS_ZEBRA_DEBUG_MLAG
)
672 zlog_debug("%s: Entering..", __func__
);
674 rc
= mlag_lib_decode_mlag_hdr(s
, &mlag_msg
, &length
);
678 memset(tmp_buf
, 0, ZEBRA_MLAG_BUF_LIMIT
);
680 if (IS_ZEBRA_DEBUG_MLAG
)
681 zlog_debug("%s: Mlag ProtoBuf encoding of message:%s, len:%d",
683 mlag_lib_msgid_to_str(mlag_msg
.msg_type
, buf
,
686 *msg_type
= mlag_msg
.msg_type
;
687 switch (mlag_msg
.msg_type
) {
688 case MLAG_MROUTE_ADD
: {
689 struct mlag_mroute_add msg
;
690 ZebraMlagMrouteAdd pay_load
= ZEBRA_MLAG_MROUTE_ADD__INIT
;
691 uint32_t vrf_name_len
= 0;
693 rc
= mlag_lib_decode_mroute_add(s
, &msg
, &length
);
697 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
698 pay_load
.vrf_name
= XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
699 strlcpy(pay_load
.vrf_name
, msg
.vrf_name
, vrf_name_len
);
700 pay_load
.source_ip
= msg
.source_ip
;
701 pay_load
.group_ip
= msg
.group_ip
;
702 pay_load
.cost_to_rp
= msg
.cost_to_rp
;
703 pay_load
.owner_id
= msg
.owner_id
;
704 pay_load
.am_i_dr
= msg
.am_i_dr
;
705 pay_load
.am_i_dual_active
= msg
.am_i_dual_active
;
706 pay_load
.vrf_id
= msg
.vrf_id
;
708 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
709 vrf_name_len
= strlen(msg
.intf_name
) + 1;
711 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
712 strlcpy(pay_load
.intf_name
, msg
.intf_name
,
716 len
= zebra_mlag_mroute_add__pack(&pay_load
, tmp_buf
);
717 XFREE(MTYPE_MLAG_PBUF
, pay_load
.vrf_name
);
718 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
)
719 XFREE(MTYPE_MLAG_PBUF
, pay_load
.intf_name
);
721 case MLAG_MROUTE_DEL
: {
722 struct mlag_mroute_del msg
;
723 ZebraMlagMrouteDel pay_load
= ZEBRA_MLAG_MROUTE_DEL__INIT
;
724 uint32_t vrf_name_len
= 0;
726 rc
= mlag_lib_decode_mroute_del(s
, &msg
, &length
);
729 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
730 pay_load
.vrf_name
= XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
731 strlcpy(pay_load
.vrf_name
, msg
.vrf_name
, vrf_name_len
);
732 pay_load
.source_ip
= msg
.source_ip
;
733 pay_load
.group_ip
= msg
.group_ip
;
734 pay_load
.owner_id
= msg
.owner_id
;
735 pay_load
.vrf_id
= msg
.vrf_id
;
737 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
738 vrf_name_len
= strlen(msg
.intf_name
) + 1;
740 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
741 strlcpy(pay_load
.intf_name
, msg
.intf_name
,
745 len
= zebra_mlag_mroute_del__pack(&pay_load
, tmp_buf
);
746 XFREE(MTYPE_MLAG_PBUF
, pay_load
.vrf_name
);
747 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
)
748 XFREE(MTYPE_MLAG_PBUF
, pay_load
.intf_name
);
750 case MLAG_MROUTE_ADD_BULK
: {
751 struct mlag_mroute_add msg
;
752 ZebraMlagMrouteAddBulk Bulk_msg
=
753 ZEBRA_MLAG_MROUTE_ADD_BULK__INIT
;
754 ZebraMlagMrouteAdd
**pay_load
= NULL
;
755 bool cleanup
= false;
758 Bulk_msg
.n_mroute_add
= mlag_msg
.msg_cnt
;
759 pay_load
= XMALLOC(MTYPE_MLAG_PBUF
, sizeof(ZebraMlagMrouteAdd
*)
762 for (i
= 0, actual
= 0; i
< mlag_msg
.msg_cnt
; i
++, actual
++) {
764 uint32_t vrf_name_len
= 0;
766 rc
= mlag_lib_decode_mroute_add(s
, &msg
, &length
);
771 pay_load
[i
] = XMALLOC(MTYPE_MLAG_PBUF
,
772 sizeof(ZebraMlagMrouteAdd
));
773 zebra_mlag_mroute_add__init(pay_load
[i
]);
775 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
776 pay_load
[i
]->vrf_name
=
777 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
778 strlcpy(pay_load
[i
]->vrf_name
, msg
.vrf_name
,
780 pay_load
[i
]->source_ip
= msg
.source_ip
;
781 pay_load
[i
]->group_ip
= msg
.group_ip
;
782 pay_load
[i
]->cost_to_rp
= msg
.cost_to_rp
;
783 pay_load
[i
]->owner_id
= msg
.owner_id
;
784 pay_load
[i
]->am_i_dr
= msg
.am_i_dr
;
785 pay_load
[i
]->am_i_dual_active
= msg
.am_i_dual_active
;
786 pay_load
[i
]->vrf_id
= msg
.vrf_id
;
787 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
788 vrf_name_len
= strlen(msg
.intf_name
) + 1;
789 pay_load
[i
]->intf_name
=
790 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
792 strlcpy(pay_load
[i
]->intf_name
, msg
.intf_name
,
797 Bulk_msg
.mroute_add
= pay_load
;
798 len
= zebra_mlag_mroute_add_bulk__pack(&Bulk_msg
,
802 for (i
= 0; i
< actual
; i
++) {
804 * The mlag_lib_decode_mroute_add can
805 * fail to properly decode and cause nothing
806 * to be allocated. Prevent a crash
811 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->vrf_name
);
812 if (pay_load
[i
]->owner_id
== MLAG_OWNER_INTERFACE
813 && pay_load
[i
]->intf_name
)
814 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->intf_name
);
815 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]);
817 XFREE(MTYPE_MLAG_PBUF
, pay_load
);
821 case MLAG_MROUTE_DEL_BULK
: {
822 struct mlag_mroute_del msg
;
823 ZebraMlagMrouteDelBulk Bulk_msg
=
824 ZEBRA_MLAG_MROUTE_DEL_BULK__INIT
;
825 ZebraMlagMrouteDel
**pay_load
= NULL
;
826 bool cleanup
= false;
829 Bulk_msg
.n_mroute_del
= mlag_msg
.msg_cnt
;
830 pay_load
= XMALLOC(MTYPE_MLAG_PBUF
, sizeof(ZebraMlagMrouteDel
*)
833 for (i
= 0, actual
= 0; i
< mlag_msg
.msg_cnt
; i
++, actual
++) {
835 uint32_t vrf_name_len
= 0;
837 rc
= mlag_lib_decode_mroute_del(s
, &msg
, &length
);
843 pay_load
[i
] = XMALLOC(MTYPE_MLAG_PBUF
,
844 sizeof(ZebraMlagMrouteDel
));
845 zebra_mlag_mroute_del__init(pay_load
[i
]);
847 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
848 pay_load
[i
]->vrf_name
=
849 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
851 strlcpy(pay_load
[i
]->vrf_name
, msg
.vrf_name
,
853 pay_load
[i
]->source_ip
= msg
.source_ip
;
854 pay_load
[i
]->group_ip
= msg
.group_ip
;
855 pay_load
[i
]->owner_id
= msg
.owner_id
;
856 pay_load
[i
]->vrf_id
= msg
.vrf_id
;
857 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
858 vrf_name_len
= strlen(msg
.intf_name
) + 1;
859 pay_load
[i
]->intf_name
=
860 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
862 strlcpy(pay_load
[i
]->intf_name
, msg
.intf_name
,
867 Bulk_msg
.mroute_del
= pay_load
;
868 len
= zebra_mlag_mroute_del_bulk__pack(&Bulk_msg
,
872 for (i
= 0; i
< actual
; i
++) {
874 * The mlag_lib_decode_mroute_add can
875 * fail to properly decode and cause nothing
876 * to be allocated. Prevent a crash
881 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->vrf_name
);
882 if (pay_load
[i
]->owner_id
== MLAG_OWNER_INTERFACE
883 && pay_load
[i
]->intf_name
)
884 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->intf_name
);
885 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]);
887 XFREE(MTYPE_MLAG_PBUF
, pay_load
);
895 if (IS_ZEBRA_DEBUG_MLAG
)
896 zlog_debug("%s: length of Mlag ProtoBuf encoded message:%s, %d",
898 mlag_lib_msgid_to_str(mlag_msg
.msg_type
, buf
,
901 hdr
.type
= (ZebraMlagHeader__MessageType
)mlag_msg
.msg_type
;
904 hdr
.data
.data
= XMALLOC(MTYPE_MLAG_PBUF
, len
);
905 memcpy(hdr
.data
.data
, tmp_buf
, len
);
909 * ProtoBuf Infra will not support to demarc the pointers whem multiple
910 * messages are posted inside a single Buffer.
911 * 2 -solutions exist to solve this
912 * 1. add Unenoced length at the beginning of every message, this will
913 * be used to point to next message in the buffer
914 * 2. another solution is defining all messages insides another message
915 * But this will permit only 32 messages. this can be extended with
917 * for simplicity we are going with solution-1.
919 len
= zebra_mlag__header__pack(&hdr
,
920 (mlag_wr_buffer
+ ZEBRA_MLAG_LEN_SIZE
));
922 memcpy(mlag_wr_buffer
, &n_len
, ZEBRA_MLAG_LEN_SIZE
);
923 len
+= ZEBRA_MLAG_LEN_SIZE
;
925 if (IS_ZEBRA_DEBUG_MLAG
)
927 "%s: length of Mlag ProtoBuf message:%s with Header %d",
929 mlag_lib_msgid_to_str(mlag_msg
.msg_type
, buf
,
932 XFREE(MTYPE_MLAG_PBUF
, hdr
.data
.data
);
937 static void zebra_fill_protobuf_msg(struct stream
*s
, char *name
, int len
)
939 int str_len
= strlen(name
) + 1;
941 stream_put(s
, name
, str_len
);
942 /* Fill the rest with Null Character for aligning */
943 stream_put(s
, NULL
, len
- str_len
);
946 int zebra_mlag_protobuf_decode_message(struct stream
*s
, uint8_t *data
,
950 ZebraMlagHeader
*hdr
;
953 hdr
= zebra_mlag__header__unpack(NULL
, len
, data
);
958 * ADD The MLAG Header
960 zclient_create_header(s
, ZEBRA_MLAG_FORWARD_MSG
, VRF_DEFAULT
);
962 msg_type
= hdr
->type
;
964 if (IS_ZEBRA_DEBUG_MLAG
)
965 zlog_debug("%s: Mlag ProtoBuf decoding of message:%s", __func__
,
966 mlag_lib_msgid_to_str(msg_type
, buf
, 80));
969 * Internal MLAG Message-types & MLAG.proto message types should
970 * always match, otherwise there can be decoding errors
971 * To avoid exposing clients with Protobuf flags, using internal
974 stream_putl(s
, hdr
->type
);
976 if (hdr
->data
.len
== 0) {
978 stream_putw(s
, MLAG_MSG_NULL_PAYLOAD
);
980 stream_putw(s
, MLAG_MSG_NO_BATCH
);
983 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_STATUS_UPDATE
: {
984 ZebraMlagStatusUpdate
*msg
= NULL
;
986 msg
= zebra_mlag_status_update__unpack(
987 NULL
, hdr
->data
.len
, hdr
->data
.data
);
989 zebra_mlag__header__free_unpacked(hdr
, NULL
);
993 stream_putw(s
, sizeof(struct mlag_status
));
995 stream_putw(s
, MLAG_MSG_NO_BATCH
);
997 zebra_fill_protobuf_msg(s
, msg
->peerlink
,
999 stream_putl(s
, msg
->my_role
);
1000 stream_putl(s
, msg
->peer_state
);
1001 zebra_mlag_status_update__free_unpacked(msg
, NULL
);
1003 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_VXLAN_UPDATE
: {
1004 ZebraMlagVxlanUpdate
*msg
= NULL
;
1006 msg
= zebra_mlag_vxlan_update__unpack(
1007 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1009 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1013 stream_putw(s
, sizeof(struct mlag_vxlan
));
1015 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1017 stream_putl(s
, msg
->anycast_ip
);
1018 stream_putl(s
, msg
->local_ip
);
1019 zebra_mlag_vxlan_update__free_unpacked(msg
, NULL
);
1021 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_ADD
: {
1022 ZebraMlagMrouteAdd
*msg
= NULL
;
1024 msg
= zebra_mlag_mroute_add__unpack(NULL
, hdr
->data
.len
,
1027 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1031 stream_putw(s
, sizeof(struct mlag_mroute_add
));
1033 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1035 zebra_fill_protobuf_msg(s
, msg
->vrf_name
, VRF_NAMSIZ
);
1037 stream_putl(s
, msg
->source_ip
);
1038 stream_putl(s
, msg
->group_ip
);
1039 stream_putl(s
, msg
->cost_to_rp
);
1040 stream_putl(s
, msg
->owner_id
);
1041 stream_putc(s
, msg
->am_i_dr
);
1042 stream_putc(s
, msg
->am_i_dual_active
);
1043 stream_putl(s
, msg
->vrf_id
);
1044 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1045 zebra_fill_protobuf_msg(s
, msg
->intf_name
,
1048 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1049 zebra_mlag_mroute_add__free_unpacked(msg
, NULL
);
1051 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_DEL
: {
1052 ZebraMlagMrouteDel
*msg
= NULL
;
1054 msg
= zebra_mlag_mroute_del__unpack(NULL
, hdr
->data
.len
,
1057 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1061 stream_putw(s
, sizeof(struct mlag_mroute_del
));
1063 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1065 zebra_fill_protobuf_msg(s
, msg
->vrf_name
, VRF_NAMSIZ
);
1067 stream_putl(s
, msg
->source_ip
);
1068 stream_putl(s
, msg
->group_ip
);
1069 stream_putl(s
, msg
->owner_id
);
1070 stream_putl(s
, msg
->vrf_id
);
1071 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1072 zebra_fill_protobuf_msg(s
, msg
->intf_name
,
1075 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1076 zebra_mlag_mroute_del__free_unpacked(msg
, NULL
);
1078 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_ADD_BULK
: {
1079 ZebraMlagMrouteAddBulk
*Bulk_msg
= NULL
;
1080 ZebraMlagMrouteAdd
*msg
= NULL
;
1081 size_t i
, length_spot
;
1083 Bulk_msg
= zebra_mlag_mroute_add_bulk__unpack(
1084 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1085 if (Bulk_msg
== NULL
) {
1086 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1090 stream_putw(s
, (Bulk_msg
->n_mroute_add
1091 * sizeof(struct mlag_mroute_add
)));
1092 /* No. of msgs in Batch */
1093 length_spot
= stream_putw(s
, Bulk_msg
->n_mroute_add
);
1096 for (i
= 0; i
< Bulk_msg
->n_mroute_add
; i
++) {
1098 < VRF_NAMSIZ
+ 22 + INTERFACE_NAMSIZ
) {
1100 "We have received more messages than we can parse at this point in time: %zu",
1101 Bulk_msg
->n_mroute_add
);
1105 msg
= Bulk_msg
->mroute_add
[i
];
1107 zebra_fill_protobuf_msg(s
, msg
->vrf_name
,
1109 stream_putl(s
, msg
->source_ip
);
1110 stream_putl(s
, msg
->group_ip
);
1111 stream_putl(s
, msg
->cost_to_rp
);
1112 stream_putl(s
, msg
->owner_id
);
1113 stream_putc(s
, msg
->am_i_dr
);
1114 stream_putc(s
, msg
->am_i_dual_active
);
1115 stream_putl(s
, msg
->vrf_id
);
1116 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1117 zebra_fill_protobuf_msg(
1121 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1124 stream_putw_at(s
, length_spot
, i
+ 1);
1126 zebra_mlag_mroute_add_bulk__free_unpacked(Bulk_msg
,
1129 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_DEL_BULK
: {
1130 ZebraMlagMrouteDelBulk
*Bulk_msg
= NULL
;
1131 ZebraMlagMrouteDel
*msg
= NULL
;
1132 size_t i
, length_spot
;
1134 Bulk_msg
= zebra_mlag_mroute_del_bulk__unpack(
1135 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1136 if (Bulk_msg
== NULL
) {
1137 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1141 stream_putw(s
, (Bulk_msg
->n_mroute_del
1142 * sizeof(struct mlag_mroute_del
)));
1143 /* No. of msgs in Batch */
1144 length_spot
= stream_putw(s
, Bulk_msg
->n_mroute_del
);
1147 for (i
= 0; i
< Bulk_msg
->n_mroute_del
; i
++) {
1149 < VRF_NAMSIZ
+ 16 + INTERFACE_NAMSIZ
) {
1151 "We have received more messages than we can parse at this time");
1155 msg
= Bulk_msg
->mroute_del
[i
];
1157 zebra_fill_protobuf_msg(s
, msg
->vrf_name
,
1159 stream_putl(s
, msg
->source_ip
);
1160 stream_putl(s
, msg
->group_ip
);
1161 stream_putl(s
, msg
->owner_id
);
1162 stream_putl(s
, msg
->vrf_id
);
1163 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1164 zebra_fill_protobuf_msg(
1168 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1171 stream_putw_at(s
, length_spot
, i
+ 1);
1173 zebra_mlag_mroute_del_bulk__free_unpacked(Bulk_msg
,
1176 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_ZEBRA_STATUS_UPDATE
: {
1177 ZebraMlagZebraStatusUpdate
*msg
= NULL
;
1179 msg
= zebra_mlag_zebra_status_update__unpack(
1180 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1182 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1186 stream_putw(s
, sizeof(struct mlag_frr_status
));
1188 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1190 stream_putl(s
, msg
->peer_frrstate
);
1191 zebra_mlag_zebra_status_update__free_unpacked(msg
,
1198 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1203 int zebra_mlag_protobuf_encode_client_data(struct stream
*s
, uint32_t *msg_type
)
1208 int zebra_mlag_protobuf_decode_message(struct stream
*s
, uint8_t *data
,