]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_mlag_private.c
zebra,pim : Fixing Review comments in PIM_MLAG
[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 "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 #include "zebra/zebra_mlag_private.h"
40
41 #include <sys/un.h>
42
43
44 /*
45 * This file will have platform specific apis to communicate with MCLAG.
46 *
47 */
48
49 #ifdef HAVE_CUMULUS
50
51 static struct thread_master *zmlag_master;
52 static int mlag_socket;
53
54 static int zebra_mlag_connect(struct thread *thread);
55 static int zebra_mlag_read(struct thread *thread);
56
57 /*
58 * Write the data to MLAGD
59 */
60 int zebra_mlag_private_write_data(uint8_t *data, uint32_t len)
61 {
62 int rc = 0;
63
64 if (IS_ZEBRA_DEBUG_MLAG) {
65 zlog_debug("%s: Writing %d length Data to clag", __func__, len);
66 zlog_hexdump(data, len);
67 }
68 rc = write(mlag_socket, data, len);
69 return rc;
70 }
71
72 static void zebra_mlag_sched_read(void)
73 {
74 thread_add_read(zmlag_master, zebra_mlag_read, NULL, mlag_socket,
75 &zrouter.mlag_info.t_read);
76 }
77
78 static int zebra_mlag_read(struct thread *thread)
79 {
80 uint32_t *msglen;
81 uint32_t h_msglen;
82 uint32_t tot_len, curr_len = mlag_rd_buf_offset;
83
84 /*
85 * Received message in sock_stream looks like below
86 * | len-1 (4 Bytes) | payload-1 (len-1) |
87 * len-2 (4 Bytes) | payload-2 (len-2) | ..
88 *
89 * Idea is read one message completely, then process, until message is
90 * read completely, keep on reading from the socket
91 */
92 if (curr_len < ZEBRA_MLAG_LEN_SIZE) {
93 ssize_t data_len;
94
95 data_len = read(mlag_socket, mlag_rd_buffer + curr_len,
96 ZEBRA_MLAG_LEN_SIZE - curr_len);
97 if (data_len == 0 || data_len == -1) {
98 if (IS_ZEBRA_DEBUG_MLAG)
99 zlog_debug("MLAG connection closed socket : %d",
100 mlag_socket);
101 close(mlag_socket);
102 zebra_mlag_handle_process_state(MLAG_DOWN);
103 return -1;
104 }
105 mlag_rd_buf_offset += data_len;
106 if (data_len != (ssize_t)ZEBRA_MLAG_LEN_SIZE - curr_len) {
107 /* Try again later */
108 zebra_mlag_sched_read();
109 return 0;
110 }
111 curr_len = ZEBRA_MLAG_LEN_SIZE;
112 }
113
114 /* Get the actual packet length */
115 msglen = (uint32_t *)mlag_rd_buffer;
116 h_msglen = ntohl(*msglen);
117
118 /* This will be the actual length of the packet */
119 tot_len = h_msglen + ZEBRA_MLAG_LEN_SIZE;
120
121 if (curr_len < tot_len) {
122 ssize_t data_len;
123
124 data_len = read(mlag_socket, mlag_rd_buffer + curr_len,
125 tot_len - curr_len);
126 if (data_len == 0 || data_len == -1) {
127 if (IS_ZEBRA_DEBUG_MLAG)
128 zlog_debug("MLAG connection closed socket : %d",
129 mlag_socket);
130 close(mlag_socket);
131 zebra_mlag_handle_process_state(MLAG_DOWN);
132 return -1;
133 }
134 mlag_rd_buf_offset += data_len;
135 if (data_len != (ssize_t)tot_len - curr_len) {
136 /* Try again later */
137 zebra_mlag_sched_read();
138 return 0;
139 }
140 }
141
142 if (IS_ZEBRA_DEBUG_MLAG) {
143 zlog_debug("Received a MLAG Message from socket: %d, len:%u ",
144 mlag_socket, tot_len);
145 zlog_hexdump(mlag_rd_buffer, tot_len);
146 }
147
148 tot_len -= ZEBRA_MLAG_LEN_SIZE;
149
150 /* Process the packet */
151 zebra_mlag_process_mlag_data(mlag_rd_buffer + ZEBRA_MLAG_LEN_SIZE,
152 tot_len);
153
154 /* Register read thread. */
155 zebra_mlag_reset_read_buffer();
156 zebra_mlag_sched_read();
157 return 0;
158 }
159
160 static int zebra_mlag_connect(struct thread *thread)
161 {
162 struct sockaddr_un svr = {0};
163 struct ucred ucred;
164 socklen_t len = 0;
165
166 /* Reset the Timer-running flag */
167 zrouter.mlag_info.timer_running = false;
168
169 /* Reset, sothat Next task can be scheduled */
170 zrouter.mlag_info.t_read = NULL;
171 svr.sun_family = AF_UNIX;
172 #define MLAG_SOCK_NAME "/var/run/clag-zebra.socket"
173 strlcpy(svr.sun_path, MLAG_SOCK_NAME, sizeof(MLAG_SOCK_NAME) + 1);
174
175 mlag_socket = socket(svr.sun_family, SOCK_STREAM, 0);
176 if (mlag_socket < 0)
177 return -1;
178
179 if (connect(mlag_socket, (struct sockaddr *)&svr, sizeof(svr)) == -1) {
180 if (IS_ZEBRA_DEBUG_MLAG)
181 zlog_debug(
182 "Unable to connect to %s try again in 10 secs",
183 svr.sun_path);
184 close(mlag_socket);
185 zrouter.mlag_info.timer_running = true;
186 thread_add_timer(zmlag_master, zebra_mlag_connect, NULL, 10,
187 &zrouter.mlag_info.t_read);
188 return 0;
189 }
190 len = sizeof(struct ucred);
191 ucred.pid = getpid();
192
193 set_nonblocking(mlag_socket);
194 setsockopt(mlag_socket, SOL_SOCKET, SO_PEERCRED, &ucred, len);
195
196 if (IS_ZEBRA_DEBUG_MLAG)
197 zlog_debug("%s: Connection with MLAG is established ",
198 __func__);
199
200 thread_add_read(zmlag_master, zebra_mlag_read, NULL, mlag_socket,
201 &zrouter.mlag_info.t_read);
202 /*
203 * Connection is established with MLAGD, post to clients
204 */
205 zebra_mlag_handle_process_state(MLAG_UP);
206 return 0;
207 }
208
209 /*
210 * Currently we are doing polling later we will look for better options
211 */
212 void zebra_mlag_private_monitor_state(void)
213 {
214 thread_add_event(zmlag_master, zebra_mlag_connect, NULL, 0,
215 &zrouter.mlag_info.t_read);
216 }
217
218 int zebra_mlag_private_open_channel(void)
219 {
220 zmlag_master = zrouter.mlag_info.th_master;
221
222 if (zrouter.mlag_info.connected == true) {
223 if (IS_ZEBRA_DEBUG_MLAG)
224 zlog_debug("%s: Zebra already connected to MLAGD",
225 __func__);
226 return 0;
227 }
228
229 if (zrouter.mlag_info.timer_running == true) {
230 if (IS_ZEBRA_DEBUG_MLAG)
231 zlog_debug(
232 "%s: Connection retry is in progress for MLAGD",
233 __func__);
234 return 0;
235 }
236
237 if (zrouter.mlag_info.clients_interested_cnt) {
238 /*
239 * Connect only if any clients are showing interest
240 */
241 thread_add_event(zmlag_master, zebra_mlag_connect, NULL, 0,
242 &zrouter.mlag_info.t_read);
243 }
244 return 0;
245 }
246
247 int zebra_mlag_private_close_channel(void)
248 {
249 if (zmlag_master == NULL)
250 return -1;
251
252 if (zrouter.mlag_info.clients_interested_cnt) {
253 if (IS_ZEBRA_DEBUG_MLAG)
254 zlog_debug("%s: still %d clients are connected, skip",
255 __func__,
256 zrouter.mlag_info.clients_interested_cnt);
257 return -1;
258 }
259
260 /*
261 * Post the De-register to MLAG, so that it can do necesasry cleanup
262 */
263 zebra_mlag_send_deregister();
264
265 return 0;
266 }
267
268 void zebra_mlag_private_cleanup_data(void)
269 {
270 zmlag_master = NULL;
271 zrouter.mlag_info.connected = false;
272 zrouter.mlag_info.timer_running = false;
273
274 close(mlag_socket);
275 }
276
277 #else /*HAVE_CUMULUS */
278
279 int zebra_mlag_private_write_data(uint8_t *data, uint32_t len)
280 {
281 return 0;
282 }
283
284 void zebra_mlag_private_monitor_state(void)
285 {
286 }
287
288 int zebra_mlag_private_open_channel(void)
289 {
290 return 0;
291 }
292
293 int zebra_mlag_private_close_channel(void)
294 {
295 return 0;
296 }
297
298 void zebra_mlag_private_cleanup_data(void)
299 {
300 }
301 #endif /*HAVE_CUMULUS*/