]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_mlag_private.c
Merge pull request #4885 from satheeshkarra/pim_mlag
[mirror_frr.git] / zebra / zebra_mlag_private.c
1 /* Zebra Mlag Code.
2 * Copyright (C) 2019 Cumulus Networks, Inc.
3 * Donald Sharp
4 *
5 * This file is part of FRR.
6 *
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
10 * later version.
11 *
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.
16 *
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
20 * 02111-1307, USA.
21 */
22 #include "zebra.h"
23
24 #include "hook.h"
25 #include "module.h"
26 #include "thread.h"
27 #include "libfrr.h"
28 #include "version.h"
29 #include "network.h"
30
31 #include "lib/stream.h"
32
33 #include "zebra/debug.h"
34 #include "zebra/zebra_router.h"
35 #include "zebra/zebra_mlag.h"
36 #include "zebra/zebra_mlag_private.h"
37
38 #include <sys/un.h>
39
40
41 /*
42 * This file will have platform specific apis to communicate with MCLAG.
43 *
44 */
45
46 #ifdef HAVE_CUMULUS
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 teh data to MLAGD
56 */
57 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 pthread_mutex_lock(&zrouter.mlag_info.mlag_th_mtx);
72 thread_add_read(zmlag_master, zebra_mlag_read, NULL, mlag_socket,
73 &zrouter.mlag_info.t_read);
74 pthread_mutex_unlock(&zrouter.mlag_info.mlag_th_mtx);
75 }
76
77 static int zebra_mlag_read(struct thread *thread)
78 {
79 uint32_t *msglen;
80 uint32_t h_msglen;
81 uint32_t tot_len, curr_len = mlag_rd_buf_offset;
82
83 pthread_mutex_lock(&zrouter.mlag_info.mlag_th_mtx);
84 zrouter.mlag_info.t_read = NULL;
85 pthread_mutex_unlock(&zrouter.mlag_info.mlag_th_mtx);
86
87 /*
88 * Received message in sock_stream looks like below
89 * | len-1 (4 Bytes) | payload-1 (len-1) |
90 * len-2 (4 Bytes) | payload-2 (len-2) | ..
91 *
92 * Idea is read one message completely, then process, until message is
93 * read completely, keep on reading from the socket
94 */
95 if (curr_len < ZEBRA_MLAG_LEN_SIZE) {
96 ssize_t data_len;
97
98 data_len = read(mlag_socket, mlag_rd_buffer + curr_len,
99 ZEBRA_MLAG_LEN_SIZE - curr_len);
100 if (data_len == 0 || data_len == -1) {
101 if (IS_ZEBRA_DEBUG_MLAG)
102 zlog_debug("MLAG connection closed socket : %d",
103 mlag_socket);
104 close(mlag_socket);
105 zebra_mlag_handle_process_state(MLAG_DOWN);
106 return -1;
107 }
108 if (data_len != (ssize_t)ZEBRA_MLAG_LEN_SIZE - curr_len) {
109 /* Try again later */
110 zebra_mlag_sched_read();
111 return 0;
112 }
113 curr_len = ZEBRA_MLAG_LEN_SIZE;
114 }
115
116 /* Get the actual packet length */
117 msglen = (uint32_t *)mlag_rd_buffer;
118 h_msglen = ntohl(*msglen);
119
120 /* This will be the actual length of the packet */
121 tot_len = h_msglen + ZEBRA_MLAG_LEN_SIZE;
122
123 if (curr_len < tot_len) {
124 ssize_t data_len;
125
126 data_len = read(mlag_socket, mlag_rd_buffer + curr_len,
127 tot_len - curr_len);
128 if (data_len == 0 || data_len == -1) {
129 if (IS_ZEBRA_DEBUG_MLAG)
130 zlog_debug("MLAG connection closed socket : %d",
131 mlag_socket);
132 close(mlag_socket);
133 zebra_mlag_handle_process_state(MLAG_DOWN);
134 return -1;
135 }
136 if (data_len != (ssize_t)tot_len - curr_len) {
137 /* Try again later */
138 zebra_mlag_sched_read();
139 return 0;
140 }
141 }
142
143 if (IS_ZEBRA_DEBUG_MLAG) {
144 zlog_debug("Received a MLAG Message from socket: %d, len:%u ",
145 mlag_socket, tot_len);
146 zlog_hexdump(mlag_rd_buffer, tot_len);
147 }
148
149 tot_len -= ZEBRA_MLAG_LEN_SIZE;
150
151 /* Process the packet */
152 zebra_mlag_process_mlag_data(mlag_rd_buffer + ZEBRA_MLAG_LEN_SIZE,
153 tot_len);
154
155 /* Register read thread. */
156 zebra_mlag_reset_read_buffer();
157 zebra_mlag_sched_read();
158 return 0;
159 }
160
161 static int zebra_mlag_connect(struct thread *thread)
162 {
163 struct sockaddr_un svr;
164 struct ucred ucred;
165 socklen_t len = 0;
166
167 /* Reset the Timer-running flag */
168 zrouter.mlag_info.timer_running = false;
169
170 zrouter.mlag_info.t_read = NULL;
171 memset(&svr, 0, sizeof(svr));
172 svr.sun_family = AF_UNIX;
173 #define MLAG_SOCK_NAME "/var/run/clag-zebra.socket"
174 strlcpy(svr.sun_path, MLAG_SOCK_NAME, sizeof(MLAG_SOCK_NAME) + 1);
175
176 mlag_socket = socket(svr.sun_family, SOCK_STREAM, 0);
177 if (mlag_socket < 0)
178 return -1;
179
180 if (connect(mlag_socket, (struct sockaddr *)&svr, sizeof(svr)) == -1) {
181 if (IS_ZEBRA_DEBUG_MLAG)
182 zlog_debug(
183 "Unable to connect to %s try again in 10 secs",
184 svr.sun_path);
185 close(mlag_socket);
186 zrouter.mlag_info.timer_running = true;
187 thread_add_timer(zmlag_master, zebra_mlag_connect, NULL, 10,
188 &zrouter.mlag_info.t_read);
189 return 0;
190 }
191 len = sizeof(struct ucred);
192 ucred.pid = getpid();
193
194 set_nonblocking(mlag_socket);
195 setsockopt(mlag_socket, SOL_SOCKET, SO_PEERCRED, &ucred, len);
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 void 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 }
218
219 int zebra_mlag_private_open_channel(void)
220 {
221 zmlag_master = zrouter.mlag_info.th_master;
222
223 if (zrouter.mlag_info.connected == true) {
224 if (IS_ZEBRA_DEBUG_MLAG)
225 zlog_debug("%s: Zebra already connected to MLAGD",
226 __func__);
227 return 0;
228 }
229
230 if (zrouter.mlag_info.timer_running == true) {
231 if (IS_ZEBRA_DEBUG_MLAG)
232 zlog_debug(
233 "%s: Connection retry is in progress for MLAGD",
234 __func__);
235 return 0;
236 }
237
238 if (zrouter.mlag_info.clients_interested_cnt) {
239 /*
240 * Connect only if any clients are showing interest
241 */
242 thread_add_event(zmlag_master, zebra_mlag_connect, NULL, 0,
243 &zrouter.mlag_info.t_read);
244 }
245 return 0;
246 }
247
248 int zebra_mlag_private_close_channel(void)
249 {
250 if (zmlag_master == NULL)
251 return -1;
252
253 if (zrouter.mlag_info.clients_interested_cnt) {
254 if (IS_ZEBRA_DEBUG_MLAG)
255 zlog_debug("%s: still %d clients are connected, skip",
256 __func__,
257 zrouter.mlag_info.clients_interested_cnt);
258 return -1;
259 }
260
261 /*
262 * Post the De-register to MLAG, so that it can do necesasry cleanup
263 */
264 zebra_mlag_send_deregister();
265
266 return 0;
267 }
268
269 void zebra_mlag_private_cleanup_data(void)
270 {
271 zmlag_master = NULL;
272 zrouter.mlag_info.connected = false;
273 zrouter.mlag_info.timer_running = false;
274
275 close(mlag_socket);
276 }
277
278 #else /*HAVE_CUMULUS */
279
280 int zebra_mlag_private_write_data(uint8_t *data, uint32_t len)
281 {
282 return 0;
283 }
284
285 void zebra_mlag_private_monitor_state(void)
286 {
287 }
288
289 int zebra_mlag_private_open_channel(void)
290 {
291 return 0;
292 }
293
294 int zebra_mlag_private_close_channel(void)
295 {
296 return 0;
297 }
298
299 void zebra_mlag_private_cleanup_data(void)
300 {
301 }
302 #endif /*HAVE_CUMULUS*/