2 * This is an implementation of MLAG Functionality
4 * Module name: Zebra MLAG
6 * Author: sathesh Kumar karra <sathk@cumulusnetworks.com>
8 * Copyright (C) 2019 Cumulus Networks http://www.cumulusnetworks.com
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the Free
12 * Software Foundation; either version 2 of the License, or (at your option)
15 * This program is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
20 * You should have received a copy of the GNU General Public License along
21 * with this program; see the file COPYING; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
29 #include "frr_pthread.h"
34 #include "lib/stream.h"
36 #include "zebra/debug.h"
37 #include "zebra/zebra_router.h"
38 #include "zebra/zebra_mlag.h"
44 * This file will have platform specific apis to communicate with MCLAG.
48 static struct thread_master
*zmlag_master
;
49 static int mlag_socket
;
51 static int zebra_mlag_connect(struct thread
*thread
);
52 static int zebra_mlag_read(struct thread
*thread
);
55 * Write the data to MLAGD
57 static int zebra_mlag_private_write_data(uint8_t *data
, uint32_t len
)
61 if (IS_ZEBRA_DEBUG_MLAG
) {
62 zlog_debug("%s: Writing %d length Data to clag", __func__
, len
);
63 zlog_hexdump(data
, len
);
65 rc
= write(mlag_socket
, data
, len
);
69 static void zebra_mlag_sched_read(void)
71 thread_add_read(zmlag_master
, zebra_mlag_read
, NULL
, mlag_socket
,
72 &zrouter
.mlag_info
.t_read
);
75 static int zebra_mlag_read(struct thread
*thread
)
77 static uint32_t mlag_rd_buf_offset
;
80 uint32_t tot_len
, curr_len
= mlag_rd_buf_offset
;
83 * Received message in sock_stream looks like below
84 * | len-1 (4 Bytes) | payload-1 (len-1) |
85 * len-2 (4 Bytes) | payload-2 (len-2) | ..
87 * Idea is read one message completely, then process, until message is
88 * read completely, keep on reading from the socket
90 if (curr_len
< ZEBRA_MLAG_LEN_SIZE
) {
93 data_len
= read(mlag_socket
, mlag_rd_buffer
+ curr_len
,
94 ZEBRA_MLAG_LEN_SIZE
- curr_len
);
95 if (data_len
== 0 || data_len
== -1) {
96 if (IS_ZEBRA_DEBUG_MLAG
)
97 zlog_debug("MLAG connection closed socket : %d",
100 zebra_mlag_handle_process_state(MLAG_DOWN
);
103 mlag_rd_buf_offset
+= data_len
;
104 if (data_len
!= (ssize_t
)(ZEBRA_MLAG_LEN_SIZE
- curr_len
)) {
105 /* Try again later */
106 zebra_mlag_sched_read();
109 curr_len
= ZEBRA_MLAG_LEN_SIZE
;
112 /* Get the actual packet length */
113 msglen
= (uint32_t *)mlag_rd_buffer
;
114 h_msglen
= ntohl(*msglen
);
116 /* This will be the actual length of the packet */
117 tot_len
= h_msglen
+ ZEBRA_MLAG_LEN_SIZE
;
120 * If the buffer read we are about to do is too large
121 * we are really really really not double plus good
123 * I'm not sure what to do here other than to bail
124 * We'll need to revisit this in the future.
126 assert(tot_len
< ZEBRA_MLAG_BUF_LIMIT
);
128 if (curr_len
< tot_len
) {
131 data_len
= read(mlag_socket
, mlag_rd_buffer
+ curr_len
,
133 if (data_len
== 0 || data_len
== -1) {
134 if (IS_ZEBRA_DEBUG_MLAG
)
135 zlog_debug("MLAG connection closed socket : %d",
138 zebra_mlag_handle_process_state(MLAG_DOWN
);
141 mlag_rd_buf_offset
+= data_len
;
142 if (data_len
!= (ssize_t
)(tot_len
- curr_len
)) {
143 /* Try again later */
144 zebra_mlag_sched_read();
149 if (IS_ZEBRA_DEBUG_MLAG
) {
150 zlog_debug("Received a MLAG Message from socket: %d, len:%u ",
151 mlag_socket
, tot_len
);
152 zlog_hexdump(mlag_rd_buffer
, tot_len
);
155 tot_len
-= ZEBRA_MLAG_LEN_SIZE
;
157 /* Process the packet */
158 zebra_mlag_process_mlag_data(mlag_rd_buffer
+ ZEBRA_MLAG_LEN_SIZE
,
161 /* Register read thread. */
162 zebra_mlag_reset_read_buffer();
163 mlag_rd_buf_offset
= 0;
164 zebra_mlag_sched_read();
168 static int zebra_mlag_connect(struct thread
*thread
)
170 struct sockaddr_un svr
= {0};
172 /* Reset the Timer-running flag */
173 zrouter
.mlag_info
.timer_running
= false;
175 svr
.sun_family
= AF_UNIX
;
176 #define MLAG_SOCK_NAME "/var/run/clag-zebra.socket"
177 strlcpy(svr
.sun_path
, MLAG_SOCK_NAME
, sizeof(MLAG_SOCK_NAME
) + 1);
179 mlag_socket
= socket(svr
.sun_family
, SOCK_STREAM
, 0);
183 if (connect(mlag_socket
, (struct sockaddr
*)&svr
, sizeof(svr
)) == -1) {
184 if (IS_ZEBRA_DEBUG_MLAG
)
186 "Unable to connect to %s try again in 10 secs",
189 zrouter
.mlag_info
.timer_running
= true;
190 thread_add_timer(zmlag_master
, zebra_mlag_connect
, NULL
, 10,
191 &zrouter
.mlag_info
.t_read
);
195 set_nonblocking(mlag_socket
);
197 if (IS_ZEBRA_DEBUG_MLAG
)
198 zlog_debug("%s: Connection with MLAG is established ",
201 thread_add_read(zmlag_master
, zebra_mlag_read
, NULL
, mlag_socket
,
202 &zrouter
.mlag_info
.t_read
);
204 * Connection is established with MLAGD, post to clients
206 zebra_mlag_handle_process_state(MLAG_UP
);
211 * Currently we are doing polling later we will look for better options
213 static int zebra_mlag_private_monitor_state(void)
215 thread_add_event(zmlag_master
, zebra_mlag_connect
, NULL
, 0,
216 &zrouter
.mlag_info
.t_read
);
220 static int zebra_mlag_private_open_channel(void)
222 zmlag_master
= zrouter
.mlag_info
.th_master
;
224 if (zrouter
.mlag_info
.connected
== true) {
225 if (IS_ZEBRA_DEBUG_MLAG
)
226 zlog_debug("%s: Zebra already connected to MLAGD",
231 if (zrouter
.mlag_info
.timer_running
== true) {
232 if (IS_ZEBRA_DEBUG_MLAG
)
234 "%s: Connection retry is in progress for MLAGD",
239 if (zrouter
.mlag_info
.clients_interested_cnt
) {
241 * Connect only if any clients are showing interest
243 thread_add_event(zmlag_master
, zebra_mlag_connect
, NULL
, 0,
244 &zrouter
.mlag_info
.t_read
);
249 static int zebra_mlag_private_close_channel(void)
251 if (zmlag_master
== NULL
)
254 if (zrouter
.mlag_info
.clients_interested_cnt
) {
255 if (IS_ZEBRA_DEBUG_MLAG
)
256 zlog_debug("%s: still %d clients are connected, skip",
258 zrouter
.mlag_info
.clients_interested_cnt
);
263 * Post the De-register to MLAG, so that it can do necesasry cleanup
265 zebra_mlag_send_deregister();
270 static int zebra_mlag_private_cleanup_data(void)
273 zrouter
.mlag_info
.connected
= false;
274 zrouter
.mlag_info
.timer_running
= false;
280 static int zebra_mlag_module_init(void)
282 hook_register(zebra_mlag_private_write_data
,
283 zebra_mlag_private_write_data
);
284 hook_register(zebra_mlag_private_monitor_state
,
285 zebra_mlag_private_monitor_state
);
286 hook_register(zebra_mlag_private_open_channel
,
287 zebra_mlag_private_open_channel
);
288 hook_register(zebra_mlag_private_close_channel
,
289 zebra_mlag_private_close_channel
);
290 hook_register(zebra_mlag_private_cleanup_data
,
291 zebra_mlag_private_cleanup_data
);
296 .name
= "zebra_cumulus_mlag",
297 .version
= FRR_VERSION
,
298 .description
= "zebra Cumulus MLAG interface",
299 .init
= zebra_mlag_module_init
,