]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_mlag_private.c
Merge pull request #8471 from idryzhov/cleanup-num-named-lists
[mirror_frr.git] / zebra / zebra_mlag_private.c
1 /*
2 * This is an implementation of MLAG Functionality
3 *
4 * Module name: Zebra MLAG
5 *
6 * Author: sathesh Kumar karra <sathk@cumulusnetworks.com>
7 *
8 * Copyright (C) 2019 Cumulus Networks http://www.cumulusnetworks.com
9 *
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)
13 * any later version.
14 *
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
18 * more details.
19 *
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
23 */
24 #include "zebra.h"
25
26 #include "hook.h"
27 #include "module.h"
28 #include "thread.h"
29 #include "frr_pthread.h"
30 #include "libfrr.h"
31 #include "lib/version.h"
32 #include "network.h"
33
34 #include "lib/stream.h"
35
36 #include "zebra/debug.h"
37 #include "zebra/zebra_router.h"
38 #include "zebra/zebra_mlag.h"
39
40 #include <sys/un.h>
41
42
43 /*
44 * This file will have platform specific apis to communicate with MCLAG.
45 *
46 */
47
48 static struct thread_master *zmlag_master;
49 static int mlag_socket;
50
51 static int zebra_mlag_connect(struct thread *thread);
52 static int zebra_mlag_read(struct thread *thread);
53
54 /*
55 * Write the data to MLAGD
56 */
57 static int zebra_mlag_private_write_data(uint8_t *data, uint32_t len)
58 {
59 int rc = 0;
60
61 if (IS_ZEBRA_DEBUG_MLAG) {
62 zlog_debug("%s: Writing %d length Data to clag", __func__, len);
63 zlog_hexdump(data, len);
64 }
65 rc = write(mlag_socket, data, len);
66 return rc;
67 }
68
69 static void zebra_mlag_sched_read(void)
70 {
71 thread_add_read(zmlag_master, zebra_mlag_read, NULL, mlag_socket,
72 &zrouter.mlag_info.t_read);
73 }
74
75 static int zebra_mlag_read(struct thread *thread)
76 {
77 static uint32_t mlag_rd_buf_offset;
78 uint32_t *msglen;
79 uint32_t h_msglen;
80 uint32_t tot_len, curr_len = mlag_rd_buf_offset;
81
82 /*
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) | ..
86 *
87 * Idea is read one message completely, then process, until message is
88 * read completely, keep on reading from the socket
89 */
90 if (curr_len < ZEBRA_MLAG_LEN_SIZE) {
91 ssize_t data_len;
92
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",
98 mlag_socket);
99 close(mlag_socket);
100 zebra_mlag_handle_process_state(MLAG_DOWN);
101 return -1;
102 }
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();
107 return 0;
108 }
109 curr_len = ZEBRA_MLAG_LEN_SIZE;
110 }
111
112 /* Get the actual packet length */
113 msglen = (uint32_t *)mlag_rd_buffer;
114 h_msglen = ntohl(*msglen);
115
116 /* This will be the actual length of the packet */
117 tot_len = h_msglen + ZEBRA_MLAG_LEN_SIZE;
118
119 /*
120 * If the buffer read we are about to do is too large
121 * we are really really really not double plus good
122 *
123 * I'm not sure what to do here other than to bail
124 * We'll need to revisit this in the future.
125 */
126 assert(tot_len < ZEBRA_MLAG_BUF_LIMIT);
127
128 if (curr_len < tot_len) {
129 ssize_t data_len;
130
131 data_len = read(mlag_socket, mlag_rd_buffer + curr_len,
132 tot_len - curr_len);
133 if (data_len == 0 || data_len == -1) {
134 if (IS_ZEBRA_DEBUG_MLAG)
135 zlog_debug("MLAG connection closed socket : %d",
136 mlag_socket);
137 close(mlag_socket);
138 zebra_mlag_handle_process_state(MLAG_DOWN);
139 return -1;
140 }
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();
145 return 0;
146 }
147 }
148
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);
153 }
154
155 tot_len -= ZEBRA_MLAG_LEN_SIZE;
156
157 /* Process the packet */
158 zebra_mlag_process_mlag_data(mlag_rd_buffer + ZEBRA_MLAG_LEN_SIZE,
159 tot_len);
160
161 /* Register read thread. */
162 zebra_mlag_reset_read_buffer();
163 mlag_rd_buf_offset = 0;
164 zebra_mlag_sched_read();
165 return 0;
166 }
167
168 static int zebra_mlag_connect(struct thread *thread)
169 {
170 struct sockaddr_un svr = {0};
171
172 /* Reset the Timer-running flag */
173 zrouter.mlag_info.timer_running = false;
174
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);
178
179 mlag_socket = socket(svr.sun_family, SOCK_STREAM, 0);
180 if (mlag_socket < 0)
181 return -1;
182
183 if (connect(mlag_socket, (struct sockaddr *)&svr, sizeof(svr)) == -1) {
184 if (IS_ZEBRA_DEBUG_MLAG)
185 zlog_debug(
186 "Unable to connect to %s try again in 10 secs",
187 svr.sun_path);
188 close(mlag_socket);
189 zrouter.mlag_info.timer_running = true;
190 thread_add_timer(zmlag_master, zebra_mlag_connect, NULL, 10,
191 &zrouter.mlag_info.t_read);
192 return 0;
193 }
194
195 set_nonblocking(mlag_socket);
196
197 if (IS_ZEBRA_DEBUG_MLAG)
198 zlog_debug("%s: Connection with MLAG is established ",
199 __func__);
200
201 thread_add_read(zmlag_master, zebra_mlag_read, NULL, mlag_socket,
202 &zrouter.mlag_info.t_read);
203 /*
204 * Connection is established with MLAGD, post to clients
205 */
206 zebra_mlag_handle_process_state(MLAG_UP);
207 return 0;
208 }
209
210 /*
211 * Currently we are doing polling later we will look for better options
212 */
213 static int zebra_mlag_private_monitor_state(void)
214 {
215 thread_add_event(zmlag_master, zebra_mlag_connect, NULL, 0,
216 &zrouter.mlag_info.t_read);
217 return 0;
218 }
219
220 static int zebra_mlag_private_open_channel(void)
221 {
222 zmlag_master = zrouter.mlag_info.th_master;
223
224 if (zrouter.mlag_info.connected == true) {
225 if (IS_ZEBRA_DEBUG_MLAG)
226 zlog_debug("%s: Zebra already connected to MLAGD",
227 __func__);
228 return 0;
229 }
230
231 if (zrouter.mlag_info.timer_running == true) {
232 if (IS_ZEBRA_DEBUG_MLAG)
233 zlog_debug(
234 "%s: Connection retry is in progress for MLAGD",
235 __func__);
236 return 0;
237 }
238
239 if (zrouter.mlag_info.clients_interested_cnt) {
240 /*
241 * Connect only if any clients are showing interest
242 */
243 thread_add_event(zmlag_master, zebra_mlag_connect, NULL, 0,
244 &zrouter.mlag_info.t_read);
245 }
246 return 0;
247 }
248
249 static int zebra_mlag_private_close_channel(void)
250 {
251 if (zmlag_master == NULL)
252 return -1;
253
254 if (zrouter.mlag_info.clients_interested_cnt) {
255 if (IS_ZEBRA_DEBUG_MLAG)
256 zlog_debug("%s: still %d clients are connected, skip",
257 __func__,
258 zrouter.mlag_info.clients_interested_cnt);
259 return -1;
260 }
261
262 /*
263 * Post the De-register to MLAG, so that it can do necesasry cleanup
264 */
265 zebra_mlag_send_deregister();
266
267 return 0;
268 }
269
270 static int zebra_mlag_private_cleanup_data(void)
271 {
272 zmlag_master = NULL;
273 zrouter.mlag_info.connected = false;
274 zrouter.mlag_info.timer_running = false;
275
276 close(mlag_socket);
277 return 0;
278 }
279
280 static int zebra_mlag_module_init(void)
281 {
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);
292 return 0;
293 }
294
295 FRR_MODULE_SETUP(
296 .name = "zebra_cumulus_mlag",
297 .version = FRR_VERSION,
298 .description = "zebra Cumulus MLAG interface",
299 .init = zebra_mlag_module_init,
300 );