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_private.h"
31 #include "zebra/zebra_router.h"
32 #include "zebra/zebra_memory.h"
33 #include "zebra/zapi_msg.h"
34 #include "zebra/debug.h"
36 #ifndef VTYSH_EXTRACT_PL
37 #include "zebra/zebra_mlag_clippy.c"
40 #define ZEBRA_MLAG_METADATA_LEN 4
41 #define ZEBRA_MLAG_MSG_BCAST 0xFFFFFFFF
43 uint8_t mlag_wr_buffer
[ZEBRA_MLAG_BUF_LIMIT
];
44 uint8_t mlag_rd_buffer
[ZEBRA_MLAG_BUF_LIMIT
];
45 uint32_t mlag_rd_buf_offset
;
47 static bool test_mlag_in_progress
;
49 static int zebra_mlag_signal_write_thread(void);
50 static int zebra_mlag_terminate_pthread(struct thread
*event
);
51 static int zebra_mlag_post_data_from_main_thread(struct thread
*thread
);
52 static void zebra_mlag_publish_process_state(struct zserv
*client
,
53 zebra_message_types_t msg_type
);
55 /**********************MLAG Interaction***************************************/
58 * API to post the Registration to MLAGD
59 * MLAG will not process any messages with out the registration
61 void zebra_mlag_send_register(void)
63 struct stream
*s
= NULL
;
65 s
= stream_new(sizeof(struct mlag_msg
));
67 stream_putl(s
, MLAG_REGISTER
);
68 stream_putw(s
, MLAG_MSG_NULL_PAYLOAD
);
69 stream_putw(s
, MLAG_MSG_NO_BATCH
);
70 stream_fifo_push_safe(zrouter
.mlag_info
.mlag_fifo
, s
);
71 zebra_mlag_signal_write_thread();
73 if (IS_ZEBRA_DEBUG_MLAG
)
74 zlog_debug("%s: Enqueued MLAG Register to MLAG Thread ",
79 * API to post the De-Registration to MLAGD
80 * MLAG will not process any messages after the de-registration
82 void zebra_mlag_send_deregister(void)
84 struct stream
*s
= NULL
;
86 s
= stream_new(sizeof(struct mlag_msg
));
88 stream_putl(s
, MLAG_DEREGISTER
);
89 stream_putw(s
, MLAG_MSG_NULL_PAYLOAD
);
90 stream_putw(s
, MLAG_MSG_NO_BATCH
);
91 stream_fifo_push_safe(zrouter
.mlag_info
.mlag_fifo
, s
);
92 zebra_mlag_signal_write_thread();
94 if (IS_ZEBRA_DEBUG_MLAG
)
95 zlog_debug("%s: Enqueued MLAG De-Register to MLAG Thread ",
100 * API To handle MLAG Received data
101 * Decodes the data using protobuf and enqueue to main thread
102 * main thread publish this to clients based on client subscription
104 void zebra_mlag_process_mlag_data(uint8_t *data
, uint32_t len
)
106 struct stream
*s
= NULL
;
107 struct stream
*s1
= NULL
;
110 s
= stream_new(ZEBRA_MAX_PACKET_SIZ
);
111 msg_type
= zebra_mlag_protobuf_decode_message(s
, data
, len
);
114 /* Something went wrong in decoding */
116 zlog_err("%s: failed to process mlag data-%d, %u", __func__
,
122 * additional four bytes are for message type
124 s1
= stream_new(stream_get_endp(s
) + ZEBRA_MLAG_METADATA_LEN
);
125 stream_putl(s1
, msg_type
);
126 stream_put(s1
, s
->data
, stream_get_endp(s
));
127 thread_add_event(zrouter
.master
, zebra_mlag_post_data_from_main_thread
,
132 /**********************End of MLAG Interaction********************************/
134 /************************MLAG Thread Processing*******************************/
137 * after posting every 'ZEBRA_MLAG_POST_LIMIT' packets, MLAG Thread will be
138 * yielded to give CPU for other threads
140 #define ZEBRA_MLAG_POST_LIMIT 100
143 * This thread reads the clients data from the Global queue and encodes with
144 * protobuf and pass on to the MLAG socket.
146 static int zebra_mlag_client_msg_handler(struct thread
*event
)
149 uint32_t wr_count
= 0;
150 uint32_t msg_type
= 0;
151 uint32_t max_count
= 0;
154 wr_count
= stream_fifo_count_safe(zrouter
.mlag_info
.mlag_fifo
);
155 if (IS_ZEBRA_DEBUG_MLAG
)
156 zlog_debug(":%s: Processing MLAG write, %d messages in queue",
159 max_count
= MIN(wr_count
, ZEBRA_MLAG_POST_LIMIT
);
161 for (wr_count
= 0; wr_count
< max_count
; wr_count
++) {
162 s
= stream_fifo_pop_safe(zrouter
.mlag_info
.mlag_fifo
);
164 zlog_debug(":%s: Got a NULL Messages, some thing wrong",
170 * Encode the data now
172 len
= zebra_mlag_protobuf_encode_client_data(s
, &msg_type
);
178 zebra_mlag_private_write_data(mlag_wr_buffer
, len
);
181 * If message type is De-register, send a signal to main
182 * thread, so that necessary cleanup will be done by
185 if (msg_type
== MLAG_DEREGISTER
) {
186 thread_add_event(zrouter
.master
,
187 zebra_mlag_terminate_pthread
,
195 if (IS_ZEBRA_DEBUG_MLAG
)
196 zlog_debug(":%s: Posted %d messages to MLAGD", __func__
,
199 * Currently there is only message write task is enqueued to this
200 * thread, yielding was added for future purpose, so that this thread
201 * can server other tasks also and in case FIFO is empty, this task will
202 * be schedule when main thread adds some messages
204 if (wr_count
>= ZEBRA_MLAG_POST_LIMIT
)
205 zebra_mlag_signal_write_thread();
210 * API to handle the process state.
211 * In case of Down, Zebra keep monitoring the MLAG state.
212 * all the state Notifications will be published to clients
214 void zebra_mlag_handle_process_state(enum zebra_mlag_state state
)
216 if (state
== MLAG_UP
) {
217 zrouter
.mlag_info
.connected
= true;
218 zebra_mlag_publish_process_state(NULL
, ZEBRA_MLAG_PROCESS_UP
);
219 zebra_mlag_send_register();
220 } else if (state
== MLAG_DOWN
) {
221 zrouter
.mlag_info
.connected
= false;
222 zebra_mlag_publish_process_state(NULL
, ZEBRA_MLAG_PROCESS_DOWN
);
223 zebra_mlag_private_monitor_state();
227 /***********************End of MLAG Thread processing*************************/
229 /*************************Multi-entratnt Api's********************************/
232 * Provider api to signal that work/events are available
233 * for the Zebra MLAG Write pthread.
234 * This API is called from 2 pthreads..
235 * 1) by main thread when client posts a MLAG Message
236 * 2) by MLAG Thread, in case of yield
237 * though this api, is called from two threads we don't need any locking
238 * because Thread task enqueue is thread safe means internally it had
239 * necessary protection
241 static int zebra_mlag_signal_write_thread(void)
243 frr_with_mutex (&zrouter
.mlag_info
.mlag_th_mtx
) {
244 if (zrouter
.mlag_info
.zebra_pth_mlag
) {
245 if (IS_ZEBRA_DEBUG_MLAG
)
246 zlog_debug(":%s: Scheduling MLAG write",
248 thread_add_event(zrouter
.mlag_info
.th_master
,
249 zebra_mlag_client_msg_handler
, NULL
, 0,
250 &zrouter
.mlag_info
.t_write
);
257 * API will be used to publish the MLAG state to interested clients
258 * In case client is passed, state is posted only for that client,
259 * otherwise to all interested clients
260 * this api can be called from two threads.
261 * 1) from main thread: when client is passed
262 * 2) from MLAG Thread: when client is NULL
264 * In second case, to avoid global data access data will be post to Main
265 * thread, so that actual posting to clients will happen from Main thread.
267 static void zebra_mlag_publish_process_state(struct zserv
*client
,
268 zebra_message_types_t msg_type
)
272 if (IS_ZEBRA_DEBUG_MLAG
)
273 zlog_debug("%s: Publishing MLAG process state:%s to %s Client",
275 (msg_type
== ZEBRA_MLAG_PROCESS_UP
) ? "UP" : "DOWN",
276 (client
) ? "one" : "all");
279 s
= stream_new(ZEBRA_HEADER_SIZE
);
280 zclient_create_header(s
, msg_type
, VRF_DEFAULT
);
281 zserv_send_message(client
, s
);
287 * additional four bytes are for mesasge type
289 s
= stream_new(ZEBRA_HEADER_SIZE
+ ZEBRA_MLAG_METADATA_LEN
);
290 stream_putl(s
, ZEBRA_MLAG_MSG_BCAST
);
291 zclient_create_header(s
, msg_type
, VRF_DEFAULT
);
292 thread_add_event(zrouter
.master
, zebra_mlag_post_data_from_main_thread
,
296 /**************************End of Multi-entrant Apis**************************/
298 /***********************Zebra Main thread processing**************************/
301 * To avoid data corruption, messages will be post to clients only from
302 * main thread, because for that access was needed for clients list.
303 * so instead of forcing the locks, messages will be posted from main thread.
305 static int zebra_mlag_post_data_from_main_thread(struct thread
*thread
)
307 struct stream
*s
= THREAD_ARG(thread
);
308 struct stream
*zebra_s
= NULL
;
309 struct listnode
*node
;
310 struct zserv
*client
;
311 uint32_t msg_type
= 0;
312 uint32_t msg_len
= 0;
317 STREAM_GETL(s
, msg_type
);
318 if (IS_ZEBRA_DEBUG_MLAG
)
320 "%s: Posting MLAG data for msg_type:0x%x to interested cleints",
323 msg_len
= s
->endp
- ZEBRA_MLAG_METADATA_LEN
;
324 for (ALL_LIST_ELEMENTS_RO(zrouter
.client_list
, node
, client
)) {
325 if (client
->mlag_updates_interested
== true) {
326 if (msg_type
!= ZEBRA_MLAG_MSG_BCAST
327 && !CHECK_FLAG(client
->mlag_reg_mask1
,
332 if (IS_ZEBRA_DEBUG_MLAG
)
334 "%s: Posting MLAG data of length-%d to client:%d ",
335 __func__
, msg_len
, client
->proto
);
337 zebra_s
= stream_new(msg_len
);
338 STREAM_GET(zebra_s
->data
, s
, msg_len
);
339 zebra_s
->endp
= msg_len
;
340 stream_putw_at(zebra_s
, 0, msg_len
);
343 * This stream will be enqueued to client_obuf, it will
344 * be freed after posting to client socket.
346 zserv_send_message(client
, zebra_s
);
356 stream_free(zebra_s
);
361 * Start the MLAG Thread, this will be used to write client data on to
362 * MLAG Process and to read the data from MLAG and post to cleints.
363 * when all clients are un-registered, this Thread will be
366 static void zebra_mlag_spawn_pthread(void)
368 /* Start MLAG write pthread */
370 struct frr_pthread_attr pattr
= {.start
=
371 frr_pthread_attr_default
.start
,
372 .stop
= frr_pthread_attr_default
.stop
};
374 zrouter
.mlag_info
.zebra_pth_mlag
=
375 frr_pthread_new(&pattr
, "Zebra MLAG thread", "Zebra MLAG");
377 zrouter
.mlag_info
.th_master
= zrouter
.mlag_info
.zebra_pth_mlag
->master
;
380 /* Enqueue an initial event to the Newly spawn MLAG pthread */
381 zebra_mlag_signal_write_thread();
383 frr_pthread_run(zrouter
.mlag_info
.zebra_pth_mlag
, NULL
);
387 * all clients are un-registered for MLAG Updates, terminate the
390 static int zebra_mlag_terminate_pthread(struct thread
*event
)
392 if (IS_ZEBRA_DEBUG_MLAG
)
393 zlog_debug("Zebra MLAG write thread terminate called");
395 if (zrouter
.mlag_info
.clients_interested_cnt
) {
396 if (IS_ZEBRA_DEBUG_MLAG
)
398 "Zebra MLAG: still some clients are interested");
402 frr_pthread_stop(zrouter
.mlag_info
.zebra_pth_mlag
, NULL
);
404 /* Destroy pthread */
405 frr_pthread_destroy(zrouter
.mlag_info
.zebra_pth_mlag
);
406 zrouter
.mlag_info
.zebra_pth_mlag
= NULL
;
407 zrouter
.mlag_info
.th_master
= NULL
;
408 zrouter
.mlag_info
.t_read
= NULL
;
409 zrouter
.mlag_info
.t_write
= NULL
;
412 * Send Notification to clean private data
414 zebra_mlag_private_cleanup_data();
419 * API to register zebra client for MLAG Updates
421 void zebra_mlag_client_register(ZAPI_HANDLER_ARGS
)
424 uint32_t reg_mask
= 0;
427 if (IS_ZEBRA_DEBUG_MLAG
)
428 zlog_debug("Received MLAG Registration from client-proto:%d",
432 /* Get input stream. */
436 STREAM_GETL(s
, reg_mask
);
438 if (client
->mlag_updates_interested
== true) {
440 if (IS_ZEBRA_DEBUG_MLAG
)
442 "Client is registered, existing mask: 0x%x, new mask: 0x%x",
443 client
->mlag_reg_mask1
, reg_mask
);
444 if (client
->mlag_reg_mask1
!= reg_mask
)
445 client
->mlag_reg_mask1
= reg_mask
;
447 * Client might missed MLAG-UP Notification, post-it again
449 zebra_mlag_publish_process_state(client
, ZEBRA_MLAG_PROCESS_UP
);
454 client
->mlag_updates_interested
= true;
455 client
->mlag_reg_mask1
= reg_mask
;
456 if (IS_ZEBRA_DEBUG_MLAG
)
457 zlog_debug("Registering for MLAG Updates with mask: 0x%x, ",
458 client
->mlag_reg_mask1
);
460 zrouter
.mlag_info
.clients_interested_cnt
++;
462 if (zrouter
.mlag_info
.clients_interested_cnt
== 1) {
464 * First-client for MLAG Updates,open the communication channel
467 if (IS_ZEBRA_DEBUG_MLAG
)
469 "First client, opening the channel with MLAG");
471 zebra_mlag_spawn_pthread();
472 rc
= zebra_mlag_private_open_channel();
475 * For some reason, zebra not able to open the
476 * comm-channel with MLAG, so post MLAG-DOWN to client.
477 * later when the channel is open, zebra will send
480 if (IS_ZEBRA_DEBUG_MLAG
)
482 "Fail to open channel with MLAG,rc:%d, post Proto-down",
484 zebra_mlag_publish_process_state(
485 client
, ZEBRA_MLAG_PROCESS_DOWN
);
489 if (IS_ZEBRA_DEBUG_MLAG
)
490 zlog_debug("Client Registered successfully for MLAG Updates");
492 if (zrouter
.mlag_info
.connected
== true)
493 zebra_mlag_publish_process_state(client
, ZEBRA_MLAG_PROCESS_UP
);
499 * API to un-register for MLAG Updates
501 void zebra_mlag_client_unregister(ZAPI_HANDLER_ARGS
)
503 if (IS_ZEBRA_DEBUG_MLAG
)
504 zlog_debug("Received MLAG De-Registration from client-proto:%d",
507 if (client
->mlag_updates_interested
== false)
511 client
->mlag_updates_interested
= false;
512 client
->mlag_reg_mask1
= 0;
513 zrouter
.mlag_info
.clients_interested_cnt
--;
515 if (zrouter
.mlag_info
.clients_interested_cnt
== 0) {
517 * No-client is interested for MLAG Updates,close the
518 * communication channel with MLAG
520 if (IS_ZEBRA_DEBUG_MLAG
)
521 zlog_debug("Last client for MLAG, close the channel ");
526 * 1) main thread calls socket close which posts De-register
527 * to MLAG write thread
528 * 2) after MLAG write thread posts De-register it sends a
529 * signal back to main thread to do the thread cleanup
530 * this was mainly to make sure De-register is posted to MCLAGD.
532 zebra_mlag_private_close_channel();
535 if (IS_ZEBRA_DEBUG_MLAG
)
537 "Client De-Registered successfully for MLAG Updates");
541 * Does following things.
542 * 1) allocated new local stream, and copies the client data and enqueue
544 * 2) MLAG Thread after dequeing, encode the client data using protobuf
545 * and write on to MLAG
547 void zebra_mlag_forward_client_msg(ZAPI_HANDLER_ARGS
)
549 struct stream
*zebra_s
;
550 struct stream
*mlag_s
;
552 if (IS_ZEBRA_DEBUG_MLAG
)
553 zlog_debug("Received Client MLAG Data from client-proto:%d",
556 /* Get input stream. */
558 mlag_s
= stream_new(zebra_s
->endp
);
561 * Client data is | Zebra Header + MLAG Data |
562 * we need to enqueue only the MLAG data, skipping Zebra Header
564 stream_put(mlag_s
, zebra_s
->data
+ zebra_s
->getp
,
565 STREAM_READABLE(zebra_s
));
566 stream_fifo_push_safe(zrouter
.mlag_info
.mlag_fifo
, mlag_s
);
567 zebra_mlag_signal_write_thread();
569 if (IS_ZEBRA_DEBUG_MLAG
)
570 zlog_debug("%s: Enqueued Client:%d data to MLAG Thread ",
571 __func__
, client
->proto
);
574 /***********************End of Zebra Main thread processing*************/
576 enum mlag_role
zebra_mlag_get_role(void)
578 return zrouter
.mlag_info
.role
;
581 DEFUN_HIDDEN (show_mlag
,
586 "The mlag role on this machine\n")
588 char buf
[MLAG_ROLE_STRSIZE
];
590 vty_out(vty
, "MLag is configured to: %s\n",
591 mlag_role2str(zrouter
.mlag_info
.role
, buf
, sizeof(buf
)));
596 DEFPY(test_mlag
, test_mlag_cmd
,
597 "test zebra mlag <none$none|primary$primary|secondary$secondary>",
598 "Test code\n" ZEBRA_STR
599 "Modify the Mlag state\n"
600 "Mlag is not setup on the machine\n"
601 "Mlag is setup to be primary\n"
602 "Mlag is setup to be the secondary\n")
604 enum mlag_role orig
= zrouter
.mlag_info
.role
;
605 char buf1
[MLAG_ROLE_STRSIZE
], buf2
[MLAG_ROLE_STRSIZE
];
608 zrouter
.mlag_info
.role
= MLAG_ROLE_NONE
;
610 zrouter
.mlag_info
.role
= MLAG_ROLE_PRIMARY
;
612 zrouter
.mlag_info
.role
= MLAG_ROLE_SECONDARY
;
614 if (IS_ZEBRA_DEBUG_MLAG
)
615 zlog_debug("Test: Changing role from %s to %s",
616 mlag_role2str(orig
, buf1
, sizeof(buf1
)),
617 mlag_role2str(orig
, buf2
, sizeof(buf2
)));
619 if (orig
!= zrouter
.mlag_info
.role
) {
620 zsend_capabilities_all_clients();
621 if (zrouter
.mlag_info
.role
!= MLAG_ROLE_NONE
) {
622 if (zrouter
.mlag_info
.clients_interested_cnt
== 0
623 && test_mlag_in_progress
== false) {
625 &zrouter
.mlag_info
.mlag_th_mtx
) {
626 if (zrouter
.mlag_info
.zebra_pth_mlag
628 zebra_mlag_spawn_pthread();
630 zrouter
.mlag_info
.clients_interested_cnt
++;
631 test_mlag_in_progress
= true;
632 zebra_mlag_private_open_channel();
635 if (test_mlag_in_progress
== true) {
636 test_mlag_in_progress
= false;
637 zrouter
.mlag_info
.clients_interested_cnt
--;
638 zebra_mlag_private_close_channel();
646 void zebra_mlag_init(void)
648 install_element(VIEW_NODE
, &show_mlag_cmd
);
649 install_element(ENABLE_NODE
, &test_mlag_cmd
);
652 * Intialiaze teh MLAG Global variableis
653 * write thread will be craeted during actual registration with MCLAG
655 zrouter
.mlag_info
.clients_interested_cnt
= 0;
656 zrouter
.mlag_info
.connected
= false;
657 zrouter
.mlag_info
.timer_running
= false;
658 zrouter
.mlag_info
.mlag_fifo
= stream_fifo_new();
659 zrouter
.mlag_info
.zebra_pth_mlag
= NULL
;
660 zrouter
.mlag_info
.th_master
= NULL
;
661 zrouter
.mlag_info
.t_read
= NULL
;
662 zrouter
.mlag_info
.t_write
= NULL
;
663 test_mlag_in_progress
= false;
664 zebra_mlag_reset_read_buffer();
665 pthread_mutex_init(&zrouter
.mlag_info
.mlag_th_mtx
, NULL
);
668 void zebra_mlag_terminate(void)
675 * ProtoBuf Encoding APIs
680 DEFINE_MTYPE_STATIC(ZEBRA
, MLAG_PBUF
, "ZEBRA MLAG PROTOBUF")
682 int zebra_mlag_protobuf_encode_client_data(struct stream
*s
, uint32_t *msg_type
)
684 ZebraMlagHeader hdr
= ZEBRA_MLAG__HEADER__INIT
;
685 struct mlag_msg mlag_msg
;
686 uint8_t tmp_buf
[ZEBRA_MLAG_BUF_LIMIT
];
690 char buf
[ZLOG_FILTER_LENGTH_MAX
];
692 if (IS_ZEBRA_DEBUG_MLAG
)
693 zlog_debug("%s: Entering..", __func__
);
695 rc
= zebra_mlag_lib_decode_mlag_hdr(s
, &mlag_msg
);
699 if (IS_ZEBRA_DEBUG_MLAG
)
700 zlog_debug("%s: Decoded msg length:%d..", __func__
,
703 if (IS_ZEBRA_DEBUG_MLAG
)
704 zlog_debug("%s: Mlag ProtoBuf encoding of message:%s", __func__
,
705 zebra_mlag_lib_msgid_to_str(mlag_msg
.msg_type
, buf
,
707 *msg_type
= mlag_msg
.msg_type
;
708 switch (mlag_msg
.msg_type
) {
709 case MLAG_MROUTE_ADD
: {
710 struct mlag_mroute_add msg
;
711 ZebraMlagMrouteAdd pay_load
= ZEBRA_MLAG_MROUTE_ADD__INIT
;
712 uint32_t vrf_name_len
= 0;
714 rc
= zebra_mlag_lib_decode_mroute_add(s
, &msg
);
717 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
718 pay_load
.vrf_name
= XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
719 strlcpy(pay_load
.vrf_name
, msg
.vrf_name
, vrf_name_len
);
720 pay_load
.source_ip
= msg
.source_ip
;
721 pay_load
.group_ip
= msg
.group_ip
;
722 pay_load
.cost_to_rp
= msg
.cost_to_rp
;
723 pay_load
.owner_id
= msg
.owner_id
;
724 pay_load
.am_i_dr
= msg
.am_i_dr
;
725 pay_load
.am_i_dual_active
= msg
.am_i_dual_active
;
726 pay_load
.vrf_id
= msg
.vrf_id
;
728 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
729 vrf_name_len
= strlen(msg
.intf_name
) + 1;
731 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
732 strlcpy(pay_load
.intf_name
, msg
.intf_name
,
736 len
= zebra_mlag_mroute_add__pack(&pay_load
, tmp_buf
);
737 XFREE(MTYPE_MLAG_PBUF
, pay_load
.vrf_name
);
738 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
)
739 XFREE(MTYPE_MLAG_PBUF
, pay_load
.intf_name
);
741 case MLAG_MROUTE_DEL
: {
742 struct mlag_mroute_del msg
;
743 ZebraMlagMrouteDel pay_load
= ZEBRA_MLAG_MROUTE_DEL__INIT
;
744 uint32_t vrf_name_len
= 0;
746 rc
= zebra_mlag_lib_decode_mroute_del(s
, &msg
);
749 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
750 pay_load
.vrf_name
= XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
751 strlcpy(pay_load
.vrf_name
, msg
.vrf_name
, vrf_name_len
);
752 pay_load
.source_ip
= msg
.source_ip
;
753 pay_load
.group_ip
= msg
.group_ip
;
754 pay_load
.owner_id
= msg
.owner_id
;
755 pay_load
.vrf_id
= msg
.vrf_id
;
757 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
758 vrf_name_len
= strlen(msg
.intf_name
) + 1;
760 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
761 strlcpy(pay_load
.intf_name
, msg
.intf_name
,
765 len
= zebra_mlag_mroute_del__pack(&pay_load
, tmp_buf
);
766 XFREE(MTYPE_MLAG_PBUF
, pay_load
.vrf_name
);
767 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
)
768 XFREE(MTYPE_MLAG_PBUF
, pay_load
.intf_name
);
770 case MLAG_MROUTE_ADD_BULK
: {
771 struct mlag_mroute_add msg
;
772 ZebraMlagMrouteAddBulk Bulk_msg
=
773 ZEBRA_MLAG_MROUTE_ADD_BULK__INIT
;
774 ZebraMlagMrouteAdd
**pay_load
= NULL
;
776 bool cleanup
= false;
778 Bulk_msg
.n_mroute_add
= mlag_msg
.msg_cnt
;
779 pay_load
= XMALLOC(MTYPE_MLAG_PBUF
, sizeof(ZebraMlagMrouteAdd
*)
782 for (i
= 0; i
< mlag_msg
.msg_cnt
; i
++) {
784 uint32_t vrf_name_len
= 0;
786 rc
= zebra_mlag_lib_decode_mroute_add(s
, &msg
);
791 pay_load
[i
] = XMALLOC(MTYPE_MLAG_PBUF
,
792 sizeof(ZebraMlagMrouteAdd
));
793 zebra_mlag_mroute_add__init(pay_load
[i
]);
795 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
796 pay_load
[i
]->vrf_name
=
797 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
798 strlcpy(pay_load
[i
]->vrf_name
, msg
.vrf_name
,
800 pay_load
[i
]->source_ip
= msg
.source_ip
;
801 pay_load
[i
]->group_ip
= msg
.group_ip
;
802 pay_load
[i
]->cost_to_rp
= msg
.cost_to_rp
;
803 pay_load
[i
]->owner_id
= msg
.owner_id
;
804 pay_load
[i
]->am_i_dr
= msg
.am_i_dr
;
805 pay_load
[i
]->am_i_dual_active
= msg
.am_i_dual_active
;
806 pay_load
[i
]->vrf_id
= msg
.vrf_id
;
807 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
808 vrf_name_len
= strlen(msg
.intf_name
) + 1;
809 pay_load
[i
]->intf_name
=
810 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
812 strlcpy(pay_load
[i
]->intf_name
, msg
.intf_name
,
816 if (cleanup
== false) {
817 Bulk_msg
.mroute_add
= pay_load
;
818 len
= zebra_mlag_mroute_add_bulk__pack(&Bulk_msg
,
822 for (i
= 0; i
< mlag_msg
.msg_cnt
; i
++) {
823 if (pay_load
[i
]->vrf_name
)
824 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->vrf_name
);
825 if (pay_load
[i
]->owner_id
== MLAG_OWNER_INTERFACE
826 && pay_load
[i
]->intf_name
)
827 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->intf_name
);
829 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]);
831 XFREE(MTYPE_MLAG_PBUF
, pay_load
);
835 case MLAG_MROUTE_DEL_BULK
: {
836 struct mlag_mroute_del msg
;
837 ZebraMlagMrouteDelBulk Bulk_msg
=
838 ZEBRA_MLAG_MROUTE_DEL_BULK__INIT
;
839 ZebraMlagMrouteDel
**pay_load
= NULL
;
841 bool cleanup
= false;
843 Bulk_msg
.n_mroute_del
= mlag_msg
.msg_cnt
;
844 pay_load
= XMALLOC(MTYPE_MLAG_PBUF
, sizeof(ZebraMlagMrouteDel
*)
847 for (i
= 0; i
< mlag_msg
.msg_cnt
; i
++) {
849 uint32_t vrf_name_len
= 0;
851 rc
= zebra_mlag_lib_decode_mroute_del(s
, &msg
);
857 pay_load
[i
] = XMALLOC(MTYPE_MLAG_PBUF
,
858 sizeof(ZebraMlagMrouteDel
));
859 zebra_mlag_mroute_del__init(pay_load
[i
]);
861 vrf_name_len
= strlen(msg
.vrf_name
) + 1;
862 pay_load
[i
]->vrf_name
=
863 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
865 strlcpy(pay_load
[i
]->vrf_name
, msg
.vrf_name
,
867 pay_load
[i
]->source_ip
= msg
.source_ip
;
868 pay_load
[i
]->group_ip
= msg
.group_ip
;
869 pay_load
[i
]->owner_id
= msg
.owner_id
;
870 pay_load
[i
]->vrf_id
= msg
.vrf_id
;
871 if (msg
.owner_id
== MLAG_OWNER_INTERFACE
) {
872 vrf_name_len
= strlen(msg
.intf_name
) + 1;
873 pay_load
[i
]->intf_name
=
874 XMALLOC(MTYPE_MLAG_PBUF
, vrf_name_len
);
876 strlcpy(pay_load
[i
]->intf_name
, msg
.intf_name
,
881 Bulk_msg
.mroute_del
= pay_load
;
882 len
= zebra_mlag_mroute_del_bulk__pack(&Bulk_msg
,
886 for (i
= 0; i
< mlag_msg
.msg_cnt
; i
++) {
887 if (pay_load
[i
]->vrf_name
)
888 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->vrf_name
);
889 if (pay_load
[i
]->owner_id
== MLAG_OWNER_INTERFACE
890 && pay_load
[i
]->intf_name
)
891 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]->intf_name
);
893 XFREE(MTYPE_MLAG_PBUF
, pay_load
[i
]);
895 XFREE(MTYPE_MLAG_PBUF
, pay_load
);
903 if (IS_ZEBRA_DEBUG_MLAG
)
904 zlog_debug("%s: length of Mlag ProtoBuf encoded message:%s, %d",
906 zebra_mlag_lib_msgid_to_str(mlag_msg
.msg_type
, buf
,
909 hdr
.type
= (ZebraMlagHeader__MessageType
)mlag_msg
.msg_type
;
912 hdr
.data
.data
= XMALLOC(MTYPE_MLAG_PBUF
, len
);
913 memcpy(hdr
.data
.data
, tmp_buf
, len
);
917 * ProtoBuf Infra will not support to demarc the pointers whem multiple
918 * messages are posted inside a single Buffer.
919 * 2 -solutions exist to solve this
920 * 1. add Unenoced length at the beginning of every message, this will
921 * be used to point to next message in the buffer
922 * 2. another solution is defining all messages insides another message
923 * But this will permit only 32 messages. this can be extended with
925 * for simplicity we are going with solution-1.
927 len
= zebra_mlag__header__pack(&hdr
,
928 (mlag_wr_buffer
+ ZEBRA_MLAG_LEN_SIZE
));
930 memcpy(mlag_wr_buffer
, &n_len
, ZEBRA_MLAG_LEN_SIZE
);
931 len
+= ZEBRA_MLAG_LEN_SIZE
;
933 if (IS_ZEBRA_DEBUG_MLAG
)
935 "%s: length of Mlag ProtoBuf message:%s with Header %d",
937 zebra_mlag_lib_msgid_to_str(mlag_msg
.msg_type
, buf
,
941 XFREE(MTYPE_MLAG_PBUF
, hdr
.data
.data
);
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 zebra_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 stream_put(s
, msg
->peerlink
, INTERFACE_NAMSIZ
);
998 stream_putl(s
, msg
->my_role
);
999 stream_putl(s
, msg
->peer_state
);
1000 zebra_mlag_status_update__free_unpacked(msg
, NULL
);
1002 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_VXLAN_UPDATE
: {
1003 ZebraMlagVxlanUpdate
*msg
= NULL
;
1005 msg
= zebra_mlag_vxlan_update__unpack(
1006 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1008 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1012 stream_putw(s
, sizeof(struct mlag_vxlan
));
1014 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1016 stream_putl(s
, msg
->anycast_ip
);
1017 stream_putl(s
, msg
->local_ip
);
1018 zebra_mlag_vxlan_update__free_unpacked(msg
, NULL
);
1020 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_ADD
: {
1021 ZebraMlagMrouteAdd
*msg
= NULL
;
1023 msg
= zebra_mlag_mroute_add__unpack(NULL
, hdr
->data
.len
,
1026 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1030 stream_putw(s
, sizeof(struct mlag_mroute_add
));
1032 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1034 stream_put(s
, msg
->vrf_name
, VRF_NAMSIZ
);
1036 stream_putl(s
, msg
->source_ip
);
1037 stream_putl(s
, msg
->group_ip
);
1038 stream_putl(s
, msg
->cost_to_rp
);
1039 stream_putl(s
, msg
->owner_id
);
1040 stream_putc(s
, msg
->am_i_dr
);
1041 stream_putc(s
, msg
->am_i_dual_active
);
1042 stream_putl(s
, msg
->vrf_id
);
1043 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1044 stream_put(s
, msg
->intf_name
, INTERFACE_NAMSIZ
);
1046 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1047 zebra_mlag_mroute_add__free_unpacked(msg
, NULL
);
1049 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_DEL
: {
1050 ZebraMlagMrouteDel
*msg
= NULL
;
1052 msg
= zebra_mlag_mroute_del__unpack(NULL
, hdr
->data
.len
,
1055 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1059 stream_putw(s
, sizeof(struct mlag_mroute_del
));
1061 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1063 stream_put(s
, msg
->vrf_name
, VRF_NAMSIZ
);
1065 stream_putl(s
, msg
->source_ip
);
1066 stream_putl(s
, msg
->group_ip
);
1067 stream_putl(s
, msg
->group_ip
);
1068 stream_putl(s
, msg
->owner_id
);
1069 stream_putl(s
, msg
->vrf_id
);
1070 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1071 stream_put(s
, msg
->intf_name
, INTERFACE_NAMSIZ
);
1073 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1074 zebra_mlag_mroute_del__free_unpacked(msg
, NULL
);
1076 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_ADD_BULK
: {
1077 ZebraMlagMrouteAddBulk
*Bulk_msg
= NULL
;
1078 ZebraMlagMrouteAdd
*msg
= NULL
;
1081 Bulk_msg
= zebra_mlag_mroute_add_bulk__unpack(
1082 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1083 if (Bulk_msg
== NULL
) {
1084 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1088 stream_putw(s
, (Bulk_msg
->n_mroute_add
1089 * sizeof(struct mlag_mroute_add
)));
1090 /* No. of msgs in Batch */
1091 stream_putw(s
, Bulk_msg
->n_mroute_add
);
1094 for (i
= 0; i
< Bulk_msg
->n_mroute_add
; i
++) {
1096 msg
= Bulk_msg
->mroute_add
[i
];
1098 stream_put(s
, msg
->vrf_name
, VRF_NAMSIZ
);
1099 stream_putl(s
, msg
->source_ip
);
1100 stream_putl(s
, msg
->group_ip
);
1101 stream_putl(s
, msg
->cost_to_rp
);
1102 stream_putl(s
, msg
->owner_id
);
1103 stream_putc(s
, msg
->am_i_dr
);
1104 stream_putc(s
, msg
->am_i_dual_active
);
1105 stream_putl(s
, msg
->vrf_id
);
1106 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1107 stream_put(s
, msg
->intf_name
,
1110 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1112 zebra_mlag_mroute_add_bulk__free_unpacked(Bulk_msg
,
1115 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_DEL_BULK
: {
1116 ZebraMlagMrouteDelBulk
*Bulk_msg
= NULL
;
1117 ZebraMlagMrouteDel
*msg
= NULL
;
1120 Bulk_msg
= zebra_mlag_mroute_del_bulk__unpack(
1121 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1122 if (Bulk_msg
== NULL
) {
1123 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1127 stream_putw(s
, (Bulk_msg
->n_mroute_del
1128 * sizeof(struct mlag_mroute_del
)));
1129 /* No. of msgs in Batch */
1130 stream_putw(s
, Bulk_msg
->n_mroute_del
);
1133 for (i
= 0; i
< Bulk_msg
->n_mroute_del
; i
++) {
1135 msg
= Bulk_msg
->mroute_del
[i
];
1137 stream_put(s
, msg
->vrf_name
, VRF_NAMSIZ
);
1138 stream_putl(s
, msg
->source_ip
);
1139 stream_putl(s
, msg
->group_ip
);
1140 stream_putl(s
, msg
->owner_id
);
1141 stream_putl(s
, msg
->vrf_id
);
1142 if (msg
->owner_id
== MLAG_OWNER_INTERFACE
)
1143 stream_put(s
, msg
->intf_name
,
1146 stream_put(s
, NULL
, INTERFACE_NAMSIZ
);
1148 zebra_mlag_mroute_del_bulk__free_unpacked(Bulk_msg
,
1151 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_ZEBRA_STATUS_UPDATE
: {
1152 ZebraMlagZebraStatusUpdate
*msg
= NULL
;
1154 msg
= zebra_mlag_zebra_status_update__unpack(
1155 NULL
, hdr
->data
.len
, hdr
->data
.data
);
1157 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1161 stream_putw(s
, sizeof(struct mlag_frr_status
));
1163 stream_putw(s
, MLAG_MSG_NO_BATCH
);
1165 stream_putl(s
, msg
->peer_frrstate
);
1166 zebra_mlag_zebra_status_update__free_unpacked(msg
,
1173 zebra_mlag__header__free_unpacked(hdr
, NULL
);
1178 int zebra_mlag_protobuf_encode_client_data(struct stream
*s
, uint32_t *msg_type
)
1183 int zebra_mlag_protobuf_decode_message(struct stream
*s
, uint8_t *data
,