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