1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * This is an implementation of MLAG Functionality
5 * Module name: Zebra MLAG
7 * Author: sathesh Kumar karra <sathk@cumulusnetworks.com>
9 * Copyright (C) 2019 Cumulus Networks http://www.cumulusnetworks.com
16 #include "frr_pthread.h"
18 #include "lib/version.h"
21 #include "lib/stream.h"
23 #include "zebra/debug.h"
24 #include "zebra/zebra_router.h"
25 #include "zebra/zebra_mlag.h"
31 * This file will have platform specific apis to communicate with MCLAG.
35 static struct event_loop
*zmlag_master
;
36 static int mlag_socket
;
38 static void zebra_mlag_connect(struct event
*thread
);
39 static void zebra_mlag_read(struct event
*thread
);
42 * Write the data to MLAGD
44 static int zebra_mlag_private_write_data(uint8_t *data
, uint32_t len
)
48 if (IS_ZEBRA_DEBUG_MLAG
) {
49 zlog_debug("%s: Writing %d length Data to clag", __func__
, len
);
50 zlog_hexdump(data
, len
);
52 rc
= write(mlag_socket
, data
, len
);
56 static void zebra_mlag_sched_read(void)
58 event_add_read(zmlag_master
, zebra_mlag_read
, NULL
, mlag_socket
,
59 &zrouter
.mlag_info
.t_read
);
62 static void zebra_mlag_read(struct event
*thread
)
64 static uint32_t mlag_rd_buf_offset
;
67 uint32_t tot_len
, curr_len
= mlag_rd_buf_offset
;
70 * Received message in sock_stream looks like below
71 * | len-1 (4 Bytes) | payload-1 (len-1) |
72 * len-2 (4 Bytes) | payload-2 (len-2) | ..
74 * Idea is read one message completely, then process, until message is
75 * read completely, keep on reading from the socket
77 if (curr_len
< ZEBRA_MLAG_LEN_SIZE
) {
80 data_len
= read(mlag_socket
, mlag_rd_buffer
+ curr_len
,
81 ZEBRA_MLAG_LEN_SIZE
- curr_len
);
82 if (data_len
== 0 || data_len
== -1) {
83 if (IS_ZEBRA_DEBUG_MLAG
)
84 zlog_debug("MLAG connection closed socket : %d",
87 zebra_mlag_handle_process_state(MLAG_DOWN
);
90 mlag_rd_buf_offset
+= data_len
;
91 if (data_len
!= (ssize_t
)(ZEBRA_MLAG_LEN_SIZE
- curr_len
)) {
93 zebra_mlag_sched_read();
96 curr_len
= ZEBRA_MLAG_LEN_SIZE
;
99 /* Get the actual packet length */
100 msglen
= (uint32_t *)mlag_rd_buffer
;
101 h_msglen
= ntohl(*msglen
);
103 /* This will be the actual length of the packet */
104 tot_len
= h_msglen
+ ZEBRA_MLAG_LEN_SIZE
;
107 * If the buffer read we are about to do is too large
108 * we are really really really not double plus good
110 * I'm not sure what to do here other than to bail
111 * We'll need to revisit this in the future.
113 assert(tot_len
< ZEBRA_MLAG_BUF_LIMIT
);
115 if (curr_len
< tot_len
) {
118 data_len
= read(mlag_socket
, mlag_rd_buffer
+ curr_len
,
120 if (data_len
== 0 || data_len
== -1) {
121 if (IS_ZEBRA_DEBUG_MLAG
)
122 zlog_debug("MLAG connection closed socket : %d",
125 zebra_mlag_handle_process_state(MLAG_DOWN
);
128 mlag_rd_buf_offset
+= data_len
;
129 if (data_len
!= (ssize_t
)(tot_len
- curr_len
)) {
130 /* Try again later */
131 zebra_mlag_sched_read();
136 if (IS_ZEBRA_DEBUG_MLAG
) {
137 zlog_debug("Received a MLAG Message from socket: %d, len:%u ",
138 mlag_socket
, tot_len
);
139 zlog_hexdump(mlag_rd_buffer
, tot_len
);
142 tot_len
-= ZEBRA_MLAG_LEN_SIZE
;
144 /* Process the packet */
145 zebra_mlag_process_mlag_data(mlag_rd_buffer
+ ZEBRA_MLAG_LEN_SIZE
,
148 /* Register read thread. */
149 zebra_mlag_reset_read_buffer();
150 mlag_rd_buf_offset
= 0;
151 zebra_mlag_sched_read();
154 static void zebra_mlag_connect(struct event
*thread
)
156 struct sockaddr_un svr
= {0};
158 /* Reset the Timer-running flag */
159 zrouter
.mlag_info
.timer_running
= false;
161 svr
.sun_family
= AF_UNIX
;
162 #define MLAG_SOCK_NAME "/var/run/clag-zebra.socket"
163 strlcpy(svr
.sun_path
, MLAG_SOCK_NAME
, sizeof(MLAG_SOCK_NAME
) + 1);
165 mlag_socket
= socket(svr
.sun_family
, SOCK_STREAM
, 0);
169 if (connect(mlag_socket
, (struct sockaddr
*)&svr
, sizeof(svr
)) == -1) {
170 if (IS_ZEBRA_DEBUG_MLAG
)
172 "Unable to connect to %s try again in 10 secs",
175 zrouter
.mlag_info
.timer_running
= true;
176 event_add_timer(zmlag_master
, zebra_mlag_connect
, NULL
, 10,
177 &zrouter
.mlag_info
.t_read
);
181 set_nonblocking(mlag_socket
);
183 if (IS_ZEBRA_DEBUG_MLAG
)
184 zlog_debug("%s: Connection with MLAG is established ",
187 event_add_read(zmlag_master
, zebra_mlag_read
, NULL
, mlag_socket
,
188 &zrouter
.mlag_info
.t_read
);
190 * Connection is established with MLAGD, post to clients
192 zebra_mlag_handle_process_state(MLAG_UP
);
196 * Currently we are doing polling later we will look for better options
198 static int zebra_mlag_private_monitor_state(void)
200 event_add_event(zmlag_master
, zebra_mlag_connect
, NULL
, 0,
201 &zrouter
.mlag_info
.t_read
);
205 static int zebra_mlag_private_open_channel(void)
207 zmlag_master
= zrouter
.mlag_info
.th_master
;
209 if (zrouter
.mlag_info
.connected
== true) {
210 if (IS_ZEBRA_DEBUG_MLAG
)
211 zlog_debug("%s: Zebra already connected to MLAGD",
216 if (zrouter
.mlag_info
.timer_running
== true) {
217 if (IS_ZEBRA_DEBUG_MLAG
)
219 "%s: Connection retry is in progress for MLAGD",
224 if (zrouter
.mlag_info
.clients_interested_cnt
) {
226 * Connect only if any clients are showing interest
228 event_add_event(zmlag_master
, zebra_mlag_connect
, NULL
, 0,
229 &zrouter
.mlag_info
.t_read
);
234 static int zebra_mlag_private_close_channel(void)
236 if (zmlag_master
== NULL
)
239 if (zrouter
.mlag_info
.clients_interested_cnt
) {
240 if (IS_ZEBRA_DEBUG_MLAG
)
241 zlog_debug("%s: still %d clients are connected, skip",
243 zrouter
.mlag_info
.clients_interested_cnt
);
248 * Post the De-register to MLAG, so that it can do necesasry cleanup
250 zebra_mlag_send_deregister();
255 static int zebra_mlag_private_cleanup_data(void)
258 zrouter
.mlag_info
.connected
= false;
259 zrouter
.mlag_info
.timer_running
= false;
265 static int zebra_mlag_module_init(void)
267 hook_register(zebra_mlag_private_write_data
,
268 zebra_mlag_private_write_data
);
269 hook_register(zebra_mlag_private_monitor_state
,
270 zebra_mlag_private_monitor_state
);
271 hook_register(zebra_mlag_private_open_channel
,
272 zebra_mlag_private_open_channel
);
273 hook_register(zebra_mlag_private_close_channel
,
274 zebra_mlag_private_close_channel
);
275 hook_register(zebra_mlag_private_cleanup_data
,
276 zebra_mlag_private_cleanup_data
);
281 .name
= "zebra_cumulus_mlag",
282 .version
= FRR_VERSION
,
283 .description
= "zebra Cumulus MLAG interface",
284 .init
= zebra_mlag_module_init
,