]>
Commit | Line | Data |
---|---|---|
df395600 | 1 | /* Zebra Mlag Code. |
6a597223 | 2 | * Copyright (C) 2018 Cumulus Networks, Inc. |
df395600 DS |
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 | ||
763ec244 | 24 | #include "command.h" |
df395600 | 25 | #include "hook.h" |
ee235396 SK |
26 | #include "frr_pthread.h" |
27 | #include "mlag.h" | |
df395600 DS |
28 | |
29 | #include "zebra/zebra_mlag.h" | |
ee235396 | 30 | #include "zebra/zebra_mlag_private.h" |
e96ba9da | 31 | #include "zebra/zebra_router.h" |
ee235396 | 32 | #include "zebra/zebra_memory.h" |
b120fe3b DS |
33 | #include "zebra/zapi_msg.h" |
34 | #include "zebra/debug.h" | |
df395600 | 35 | |
763ec244 DS |
36 | #ifndef VTYSH_EXTRACT_PL |
37 | #include "zebra/zebra_mlag_clippy.c" | |
38 | #endif | |
39 | ||
ee235396 SK |
40 | #define ZEBRA_MLAG_METADATA_LEN 4 |
41 | #define ZEBRA_MLAG_MSG_BCAST 0xFFFFFFFF | |
42 | ||
43 | uint8_t mlag_wr_buffer[ZEBRA_MLAG_BUF_LIMIT]; | |
44 | uint8_t mlag_rd_buffer[ZEBRA_MLAG_BUF_LIMIT]; | |
45 | uint32_t mlag_rd_buf_offset; | |
46 | ||
47 | static bool test_mlag_in_progress; | |
48 | ||
49 | static int zebra_mlag_signal_write_thread(void); | |
50 | static int zebra_mlag_terminate_pthread(struct thread *event); | |
51 | static int zebra_mlag_post_data_from_main_thread(struct thread *thread); | |
52 | static void zebra_mlag_publish_process_state(struct zserv *client, | |
53 | zebra_message_types_t msg_type); | |
54 | ||
55 | /**********************MLAG Interaction***************************************/ | |
56 | ||
57 | /* | |
58 | * API to post the Registration to MLAGD | |
59 | * MLAG will not process any messages with out the registration | |
60 | */ | |
61 | void zebra_mlag_send_register(void) | |
62 | { | |
63 | struct stream *s = NULL; | |
64 | ||
65 | s = stream_new(sizeof(struct mlag_msg)); | |
66 | ||
67 | stream_putl(s, MLAG_REGISTER); | |
68 | stream_putw(s, MLAG_MSG_NULL_PAYLOAD); | |
69 | stream_putw(s, MLAG_MSG_NO_BATCH); | |
70 | stream_fifo_push_safe(zrouter.mlag_info.mlag_fifo, s); | |
71 | zebra_mlag_signal_write_thread(); | |
72 | ||
73 | if (IS_ZEBRA_DEBUG_MLAG) | |
74 | zlog_debug("%s: Enqueued MLAG Register to MLAG Thread ", | |
75 | __func__); | |
76 | } | |
77 | ||
78 | /* | |
79 | * API to post the De-Registration to MLAGD | |
80 | * MLAG will not process any messages after the de-registration | |
81 | */ | |
82 | void zebra_mlag_send_deregister(void) | |
83 | { | |
84 | struct stream *s = NULL; | |
85 | ||
86 | s = stream_new(sizeof(struct mlag_msg)); | |
87 | ||
88 | stream_putl(s, MLAG_DEREGISTER); | |
89 | stream_putw(s, MLAG_MSG_NULL_PAYLOAD); | |
90 | stream_putw(s, MLAG_MSG_NO_BATCH); | |
91 | stream_fifo_push_safe(zrouter.mlag_info.mlag_fifo, s); | |
92 | zebra_mlag_signal_write_thread(); | |
93 | ||
94 | if (IS_ZEBRA_DEBUG_MLAG) | |
95 | zlog_debug("%s: Enqueued MLAG De-Register to MLAG Thread ", | |
96 | __func__); | |
97 | } | |
98 | ||
99 | /* | |
100 | * API To handle MLAG Received data | |
101 | * Decodes the data using protobuf and enqueue to main thread | |
102 | * main thread publish this to clients based on client subscription | |
103 | */ | |
104 | void zebra_mlag_process_mlag_data(uint8_t *data, uint32_t len) | |
105 | { | |
106 | struct stream *s = NULL; | |
107 | struct stream *s1 = NULL; | |
108 | int msg_type = 0; | |
109 | ||
110 | s = stream_new(ZEBRA_MAX_PACKET_SIZ); | |
111 | msg_type = zebra_mlag_protobuf_decode_message(&s, data, len); | |
112 | ||
113 | if (msg_type <= 0) { | |
114 | /* Something went wrong in decoding */ | |
115 | stream_free(s); | |
116 | zlog_err("%s: failed to process mlag data-%d, %u", __func__, | |
117 | msg_type, len); | |
118 | return; | |
119 | } | |
120 | ||
121 | /* | |
122 | * additional four bytes are for message type | |
123 | */ | |
124 | s1 = stream_new(stream_get_endp(s) + ZEBRA_MLAG_METADATA_LEN); | |
125 | stream_putl(s1, msg_type); | |
126 | stream_put(s1, s->data, stream_get_endp(s)); | |
127 | thread_add_event(zrouter.master, zebra_mlag_post_data_from_main_thread, | |
128 | s1, 0, NULL); | |
129 | stream_free(s); | |
130 | } | |
131 | ||
132 | /**********************End of MLAG Interaction********************************/ | |
133 | ||
134 | /************************MLAG Thread Processing*******************************/ | |
135 | ||
136 | /* | |
137 | * after posting every 'ZEBRA_MLAG_POST_LIMIT' packets, MLAG Thread will be | |
138 | * yielded to give CPU for other threads | |
139 | */ | |
140 | #define ZEBRA_MLAG_POST_LIMIT 100 | |
141 | ||
142 | /* | |
143 | * This thread reads the clients data from the Global queue and encodes with | |
144 | * protobuf and pass on to the MLAG socket. | |
145 | */ | |
146 | static int zebra_mlag_client_msg_handler(struct thread *event) | |
147 | { | |
148 | struct stream *s; | |
149 | uint32_t wr_count = 0; | |
150 | uint32_t msg_type = 0; | |
151 | int len = 0; | |
152 | ||
153 | wr_count = stream_fifo_count_safe(zrouter.mlag_info.mlag_fifo); | |
154 | if (IS_ZEBRA_DEBUG_MLAG) | |
155 | zlog_debug(":%s: Processing MLAG write, %d messages in queue", | |
156 | __func__, wr_count); | |
157 | ||
158 | zrouter.mlag_info.t_write = NULL; | |
159 | for (wr_count = 0; wr_count < ZEBRA_MLAG_POST_LIMIT; wr_count++) { | |
160 | /* FIFO is empty,wait for teh message to be add */ | |
161 | if (stream_fifo_count_safe(zrouter.mlag_info.mlag_fifo) == 0) | |
162 | break; | |
163 | ||
164 | s = stream_fifo_pop_safe(zrouter.mlag_info.mlag_fifo); | |
165 | if (!s) { | |
166 | zlog_debug(":%s: Got a NULL Messages, some thing wrong", | |
167 | __func__); | |
168 | break; | |
169 | } | |
170 | ||
171 | zebra_mlag_reset_write_buffer(); | |
172 | /* | |
173 | * Encode the data now | |
174 | */ | |
175 | len = zebra_mlag_protobuf_encode_client_data(s, &msg_type); | |
176 | ||
177 | /* | |
178 | * write to MCLAGD | |
179 | */ | |
180 | if (len > 0) | |
181 | zebra_mlag_private_write_data(mlag_wr_buffer, len); | |
182 | ||
183 | /* | |
184 | * If message type is De-register, send a signal to main thread, | |
185 | * so that necessary cleanup will be done by main thread. | |
186 | */ | |
187 | if (msg_type == MLAG_DEREGISTER) { | |
188 | thread_add_event(zrouter.master, | |
189 | zebra_mlag_terminate_pthread, NULL, 0, | |
190 | NULL); | |
191 | } | |
192 | ||
193 | stream_free(s); | |
194 | } | |
195 | ||
196 | if (IS_ZEBRA_DEBUG_MLAG) | |
197 | zlog_debug(":%s: Posted %d messages to MLAGD", __func__, | |
198 | wr_count); | |
199 | /* | |
200 | * Currently there is only message write task is enqueued to this | |
201 | * thread, yielding was added for future purpose, so that this thread | |
202 | * can server other tasks also and in case FIFO is empty, this task will | |
203 | * be schedule when main thread adds some messages | |
204 | */ | |
205 | if (wr_count >= ZEBRA_MLAG_POST_LIMIT) | |
206 | zebra_mlag_signal_write_thread(); | |
207 | return 0; | |
208 | } | |
209 | ||
210 | /* | |
211 | * API to handle the process state. | |
212 | * In case of Down, Zebra keep monitoring the MLAG state. | |
213 | * all the state Notifications will be published to clients | |
214 | */ | |
215 | void zebra_mlag_handle_process_state(enum zebra_mlag_state state) | |
216 | { | |
217 | if (state == MLAG_UP) { | |
218 | zrouter.mlag_info.connected = true; | |
219 | zebra_mlag_publish_process_state(NULL, ZEBRA_MLAG_PROCESS_UP); | |
220 | zebra_mlag_send_register(); | |
221 | } else if (state == MLAG_DOWN) { | |
222 | zrouter.mlag_info.connected = false; | |
223 | zebra_mlag_publish_process_state(NULL, ZEBRA_MLAG_PROCESS_DOWN); | |
224 | zebra_mlag_private_monitor_state(); | |
225 | } | |
226 | } | |
227 | ||
228 | /***********************End of MLAG Thread processing*************************/ | |
229 | ||
230 | /*************************Multi-entratnt Api's********************************/ | |
231 | ||
232 | /* | |
233 | * Provider api to signal that work/events are available | |
234 | * for the Zebra MLAG Write pthread. | |
235 | * This API is called from 2 pthreads.. | |
236 | * 1) by main thread when client posts a MLAG Message | |
237 | * 2) by MLAG Thread, in case of yield | |
238 | * though this api, is called from two threads we don't need any locking | |
239 | * because Thread task enqueue is thread safe means internally it had | |
240 | * necessary protection | |
241 | */ | |
242 | static int zebra_mlag_signal_write_thread(void) | |
243 | { | |
244 | if (zrouter.mlag_info.zebra_pth_mlag) { | |
245 | if (IS_ZEBRA_DEBUG_MLAG) | |
246 | zlog_debug(":%s: Scheduling MLAG write", __func__); | |
247 | thread_add_event(zrouter.mlag_info.th_master, | |
248 | zebra_mlag_client_msg_handler, NULL, 0, | |
249 | &zrouter.mlag_info.t_write); | |
250 | } | |
251 | return 0; | |
252 | } | |
253 | ||
254 | /* | |
255 | * API will be used to publish the MLAG state to interested clients | |
256 | * In case client is passed, state is posted only for that client, | |
257 | * otherwise to all interested clients | |
258 | * this api can be called from two threads. | |
259 | * 1) from main thread: when client is passed | |
260 | * 2) from MLAG Thread: when client is NULL | |
261 | * | |
262 | * In second case, to avoid global data access data will be post to Main | |
263 | * thread, so that actual posting to clients will happen from Main thread. | |
264 | */ | |
265 | static void zebra_mlag_publish_process_state(struct zserv *client, | |
266 | zebra_message_types_t msg_type) | |
267 | { | |
268 | struct stream *s; | |
269 | ||
270 | if (IS_ZEBRA_DEBUG_MLAG) | |
271 | zlog_debug("%s: Publishing MLAG process state:%s to %s Client", | |
272 | __func__, | |
273 | (msg_type == ZEBRA_MLAG_PROCESS_UP) ? "UP" : "DOWN", | |
274 | (client) ? "one" : "all"); | |
275 | ||
276 | if (client) { | |
277 | s = stream_new(ZEBRA_HEADER_SIZE); | |
278 | zclient_create_header(s, msg_type, VRF_DEFAULT); | |
279 | zserv_send_message(client, s); | |
280 | return; | |
281 | } | |
282 | ||
283 | ||
284 | /* | |
285 | * additional four bytes are for mesasge type | |
286 | */ | |
287 | s = stream_new(ZEBRA_HEADER_SIZE + ZEBRA_MLAG_METADATA_LEN); | |
288 | stream_putl(s, ZEBRA_MLAG_MSG_BCAST); | |
289 | zclient_create_header(s, msg_type, VRF_DEFAULT); | |
290 | thread_add_event(zrouter.master, zebra_mlag_post_data_from_main_thread, | |
291 | s, 0, NULL); | |
292 | } | |
293 | ||
294 | /**************************End of Multi-entrant Apis**************************/ | |
295 | ||
296 | /***********************Zebra Main thread processing**************************/ | |
297 | ||
298 | /* | |
299 | * To avoid data corruption, messages will be post to clients only from | |
300 | * main thread, because for that access was needed for clients list. | |
301 | * so instead of forcing the locks, messages will be posted from main thread. | |
302 | */ | |
303 | static int zebra_mlag_post_data_from_main_thread(struct thread *thread) | |
304 | { | |
305 | struct stream *s = THREAD_ARG(thread); | |
306 | struct stream *zebra_s = NULL; | |
307 | struct listnode *node; | |
308 | struct zserv *client; | |
309 | uint32_t msg_type = 0; | |
310 | uint32_t msg_len = 0; | |
311 | ||
312 | if (!s) | |
313 | return -1; | |
314 | ||
315 | STREAM_GETL(s, msg_type); | |
316 | if (IS_ZEBRA_DEBUG_MLAG) | |
317 | zlog_debug( | |
318 | "%s: Posting MLAG data for msg_type:0x%x to interested cleints", | |
319 | __func__, msg_type); | |
320 | ||
321 | msg_len = s->endp - ZEBRA_MLAG_METADATA_LEN; | |
322 | for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) { | |
323 | if (client->mlag_updates_interested == true) { | |
324 | if (msg_type != ZEBRA_MLAG_MSG_BCAST | |
325 | && !CHECK_FLAG(client->mlag_reg_mask1, | |
326 | (1 << msg_type))) { | |
327 | continue; | |
328 | } | |
329 | ||
330 | if (IS_ZEBRA_DEBUG_MLAG) | |
331 | zlog_debug( | |
332 | "%s: Posting MLAG data of length-%d to client:%d ", | |
333 | __func__, msg_len, client->proto); | |
334 | ||
335 | zebra_s = stream_new(msg_len); | |
336 | STREAM_GET(zebra_s->data, s, msg_len); | |
337 | zebra_s->endp = msg_len; | |
338 | stream_putw_at(zebra_s, 0, msg_len); | |
339 | ||
340 | /* | |
341 | * This stream will be enqueued to client_obuf, it will | |
342 | * be freed after posting to client socket. | |
343 | */ | |
344 | zserv_send_message(client, zebra_s); | |
345 | zebra_s = NULL; | |
346 | } | |
347 | } | |
348 | ||
349 | stream_free(s); | |
350 | return 0; | |
351 | stream_failure: | |
352 | stream_free(s); | |
353 | if (zebra_s) | |
354 | stream_free(zebra_s); | |
355 | return 0; | |
356 | } | |
357 | ||
358 | /* | |
359 | * Start the MLAG Thread, this will be used to write client data on to | |
360 | * MLAG Process and to read the data from MLAG and post to cleints. | |
361 | * when all clients are un-registered, this Thread will be | |
362 | * suspended. | |
363 | */ | |
364 | static void zebra_mlag_spawn_pthread(void) | |
365 | { | |
366 | /* Start MLAG write pthread */ | |
367 | ||
368 | struct frr_pthread_attr pattr = {.start = | |
369 | frr_pthread_attr_default.start, | |
370 | .stop = frr_pthread_attr_default.stop}; | |
371 | ||
372 | zrouter.mlag_info.zebra_pth_mlag = | |
373 | frr_pthread_new(&pattr, "Zebra MLAG thread", "Zebra MLAG"); | |
374 | ||
375 | zrouter.mlag_info.th_master = zrouter.mlag_info.zebra_pth_mlag->master; | |
376 | ||
377 | ||
378 | /* Enqueue an initial event for the dataplane pthread */ | |
379 | zebra_mlag_signal_write_thread(); | |
380 | ||
381 | frr_pthread_run(zrouter.mlag_info.zebra_pth_mlag, NULL); | |
382 | } | |
383 | ||
384 | /* | |
385 | * all clients are un-registered for MLAG Updates, terminate the | |
386 | * MLAG write thread | |
387 | */ | |
388 | static int zebra_mlag_terminate_pthread(struct thread *event) | |
389 | { | |
390 | if (IS_ZEBRA_DEBUG_MLAG) | |
391 | zlog_debug("Zebra MLAG write thread terminate called"); | |
392 | ||
393 | if (zrouter.mlag_info.clients_interested_cnt) { | |
394 | if (IS_ZEBRA_DEBUG_MLAG) | |
395 | zlog_debug( | |
396 | "Zebra MLAG: still some clients are interested"); | |
397 | return 0; | |
398 | } | |
399 | ||
400 | frr_pthread_stop(zrouter.mlag_info.zebra_pth_mlag, NULL); | |
401 | ||
402 | /* Destroy pthread */ | |
403 | frr_pthread_destroy(zrouter.mlag_info.zebra_pth_mlag); | |
404 | zrouter.mlag_info.zebra_pth_mlag = NULL; | |
405 | zrouter.mlag_info.th_master = NULL; | |
406 | zrouter.mlag_info.t_read = NULL; | |
407 | zrouter.mlag_info.t_write = NULL; | |
408 | ||
409 | /* | |
410 | * Send Notification to clean private data | |
411 | */ | |
412 | zebra_mlag_private_cleanup_data(); | |
413 | return 0; | |
414 | } | |
415 | ||
416 | /* | |
417 | * API to register zebra client for MLAG Updates | |
418 | */ | |
419 | void zebra_mlag_client_register(ZAPI_HANDLER_ARGS) | |
420 | { | |
421 | struct stream *s; | |
422 | uint32_t reg_mask = 0; | |
423 | int rc = 0; | |
424 | ||
425 | if (IS_ZEBRA_DEBUG_MLAG) | |
426 | zlog_debug("Received MLAG Registration from client-proto:%d", | |
427 | client->proto); | |
428 | ||
429 | ||
430 | /* Get input stream. */ | |
431 | s = msg; | |
432 | ||
433 | /* Get data. */ | |
434 | STREAM_GETL(s, reg_mask); | |
435 | ||
436 | if (client->mlag_updates_interested == true) { | |
437 | ||
438 | if (IS_ZEBRA_DEBUG_MLAG) | |
439 | zlog_debug( | |
440 | "Client is registered, existing mask: 0x%x, new mask: 0x%x", | |
441 | client->mlag_reg_mask1, reg_mask); | |
442 | if (client->mlag_reg_mask1 != reg_mask) | |
443 | client->mlag_reg_mask1 = reg_mask; | |
444 | /* | |
445 | * Client might missed MLAG-UP Notification, post-it again | |
446 | */ | |
447 | zebra_mlag_publish_process_state(client, ZEBRA_MLAG_PROCESS_UP); | |
448 | return; | |
449 | } | |
450 | ||
451 | ||
452 | client->mlag_updates_interested = true; | |
453 | client->mlag_reg_mask1 = reg_mask; | |
454 | if (IS_ZEBRA_DEBUG_MLAG) | |
455 | zlog_debug("Registering for MLAG Updates with mask: 0x%x, ", | |
456 | client->mlag_reg_mask1); | |
457 | ||
458 | zrouter.mlag_info.clients_interested_cnt++; | |
459 | ||
460 | if (zrouter.mlag_info.clients_interested_cnt == 1) { | |
461 | /* | |
462 | * First-client for MLAG Updates,open the communication channel | |
463 | * with MLAG | |
464 | */ | |
465 | if (IS_ZEBRA_DEBUG_MLAG) | |
466 | zlog_debug( | |
467 | "First client, opening the channel with MLAG"); | |
468 | ||
469 | zebra_mlag_spawn_pthread(); | |
470 | rc = zebra_mlag_private_open_channel(); | |
471 | if (rc < 0) { | |
472 | /* | |
473 | * For some reason, zebra not able to open the | |
474 | * comm-channel with MLAG, so post MLAG-DOWN to client. | |
475 | * later when the channel is open, zebra will send | |
476 | * MLAG-UP | |
477 | */ | |
478 | if (IS_ZEBRA_DEBUG_MLAG) | |
479 | zlog_debug( | |
480 | "Fail to open channel with MLAG,rc:%d, post Proto-down", | |
481 | rc); | |
482 | zebra_mlag_publish_process_state( | |
483 | client, ZEBRA_MLAG_PROCESS_DOWN); | |
484 | } | |
485 | } | |
486 | ||
487 | if (IS_ZEBRA_DEBUG_MLAG) | |
488 | zlog_debug("Client Registered successfully for MLAG Updates"); | |
489 | ||
490 | if (zrouter.mlag_info.connected == true) | |
491 | zebra_mlag_publish_process_state(client, ZEBRA_MLAG_PROCESS_UP); | |
492 | stream_failure: | |
493 | return; | |
494 | } | |
495 | ||
496 | /* | |
497 | * API to un-register for MLAG Updates | |
498 | */ | |
499 | void zebra_mlag_client_unregister(ZAPI_HANDLER_ARGS) | |
500 | { | |
501 | if (IS_ZEBRA_DEBUG_MLAG) | |
502 | zlog_debug("Received MLAG De-Registration from client-proto:%d", | |
503 | client->proto); | |
504 | ||
505 | if (client->mlag_updates_interested == false) | |
506 | /* Unexpected */ | |
507 | return; | |
508 | ||
509 | client->mlag_updates_interested = false; | |
510 | client->mlag_reg_mask1 = 0; | |
511 | zrouter.mlag_info.clients_interested_cnt--; | |
512 | ||
513 | if (zrouter.mlag_info.clients_interested_cnt == 0) { | |
514 | /* | |
515 | * No-client is interested for MLAG Updates,close the | |
516 | * communication channel with MLAG | |
517 | */ | |
518 | if (IS_ZEBRA_DEBUG_MLAG) | |
519 | zlog_debug("Last client for MLAG, close the channel "); | |
520 | ||
521 | /* | |
522 | * Clean up flow: | |
523 | * ============= | |
524 | * 1) main thread calls socket close which posts De-register | |
525 | * to MLAG write thread | |
526 | * 2) after MLAG write thread posts De-register it sends a | |
527 | * signal back to main thread to do the thread cleanup | |
528 | * this was mainly to make sure De-register is posted to MCLAGD. | |
529 | */ | |
530 | zebra_mlag_private_close_channel(); | |
531 | } | |
532 | ||
533 | if (IS_ZEBRA_DEBUG_MLAG) | |
534 | zlog_debug( | |
535 | "Client De-Registered successfully for MLAG Updates"); | |
536 | } | |
537 | ||
538 | /* | |
539 | * Does following things. | |
540 | * 1) allocated new local stream, and copies the client data and enqueue | |
541 | * to MLAG Thread | |
542 | * 2) MLAG Thread after dequeing, encode the client data using protobuf | |
543 | * and write on to MLAG | |
544 | */ | |
545 | void zebra_mlag_forward_client_msg(ZAPI_HANDLER_ARGS) | |
546 | { | |
547 | struct stream *zebra_s; | |
548 | struct stream *mlag_s; | |
549 | ||
550 | if (IS_ZEBRA_DEBUG_MLAG) | |
551 | zlog_debug("Received Client MLAG Data from client-proto:%d", | |
552 | client->proto); | |
553 | ||
554 | /* Get input stream. */ | |
555 | zebra_s = msg; | |
556 | mlag_s = stream_new(zebra_s->endp); | |
557 | ||
558 | /* | |
559 | * Client data is | Zebra Header + MLAG Data | | |
560 | * we need to enqueue only the MLAG data, skipping Zebra Header | |
561 | */ | |
562 | stream_put(mlag_s, zebra_s->data + zebra_s->getp, | |
563 | STREAM_READABLE(zebra_s)); | |
564 | stream_fifo_push_safe(zrouter.mlag_info.mlag_fifo, mlag_s); | |
565 | zebra_mlag_signal_write_thread(); | |
566 | ||
567 | if (IS_ZEBRA_DEBUG_MLAG) | |
568 | zlog_debug("%s: Enqueued Client:%d data to MLAG Thread ", | |
569 | __func__, client->proto); | |
570 | } | |
571 | ||
572 | /***********************End of Zebra Main thread processing*************/ | |
573 | ||
ff1fb8d5 DS |
574 | enum mlag_role zebra_mlag_get_role(void) |
575 | { | |
e96ba9da | 576 | return zrouter.mlag_info.role; |
ff1fb8d5 DS |
577 | } |
578 | ||
763ec244 DS |
579 | DEFUN_HIDDEN (show_mlag, |
580 | show_mlag_cmd, | |
581 | "show zebra mlag", | |
582 | SHOW_STR | |
583 | ZEBRA_STR | |
584 | "The mlag role on this machine\n") | |
585 | { | |
6a597223 | 586 | char buf[80]; |
763ec244 DS |
587 | |
588 | vty_out(vty, "MLag is configured to: %s\n", | |
e96ba9da | 589 | mlag_role2str(zrouter.mlag_info.role, buf, sizeof(buf))); |
763ec244 DS |
590 | |
591 | return CMD_SUCCESS; | |
592 | } | |
593 | ||
ee235396 SK |
594 | DEFPY(test_mlag, test_mlag_cmd, |
595 | "test zebra mlag <none$none|primary$primary|secondary$secondary>", | |
596 | "Test code\n" ZEBRA_STR | |
597 | "Modify the Mlag state\n" | |
598 | "Mlag is not setup on the machine\n" | |
599 | "Mlag is setup to be primary\n" | |
600 | "Mlag is setup to be the secondary\n") | |
763ec244 | 601 | { |
b120fe3b | 602 | enum mlag_role orig = zrouter.mlag_info.role; |
6a597223 | 603 | char buf1[80], buf2[80]; |
b120fe3b | 604 | |
763ec244 | 605 | if (none) |
e96ba9da | 606 | zrouter.mlag_info.role = MLAG_ROLE_NONE; |
763ec244 | 607 | if (primary) |
e96ba9da | 608 | zrouter.mlag_info.role = MLAG_ROLE_PRIMARY; |
763ec244 | 609 | if (secondary) |
e96ba9da | 610 | zrouter.mlag_info.role = MLAG_ROLE_SECONDARY; |
763ec244 | 611 | |
b120fe3b DS |
612 | if (IS_ZEBRA_DEBUG_MLAG) |
613 | zlog_debug("Test: Changing role from %s to %s", | |
614 | mlag_role2str(orig, buf1, sizeof(buf1)), | |
615 | mlag_role2str(orig, buf2, sizeof(buf2))); | |
616 | ||
ee235396 | 617 | if (orig != zrouter.mlag_info.role) { |
b120fe3b | 618 | zsend_capabilities_all_clients(); |
ee235396 SK |
619 | if (zrouter.mlag_info.role != MLAG_ROLE_NONE) { |
620 | if (zrouter.mlag_info.clients_interested_cnt == 0 | |
621 | && test_mlag_in_progress == false) { | |
622 | if (zrouter.mlag_info.zebra_pth_mlag == NULL) | |
623 | zebra_mlag_spawn_pthread(); | |
624 | zrouter.mlag_info.clients_interested_cnt++; | |
625 | test_mlag_in_progress = true; | |
626 | zebra_mlag_private_open_channel(); | |
627 | } | |
628 | } else { | |
629 | if (test_mlag_in_progress == true) { | |
630 | test_mlag_in_progress = false; | |
631 | zrouter.mlag_info.clients_interested_cnt--; | |
632 | zebra_mlag_private_close_channel(); | |
633 | } | |
634 | } | |
635 | } | |
b120fe3b | 636 | |
763ec244 DS |
637 | return CMD_SUCCESS; |
638 | } | |
639 | ||
df395600 DS |
640 | void zebra_mlag_init(void) |
641 | { | |
763ec244 DS |
642 | install_element(VIEW_NODE, &show_mlag_cmd); |
643 | install_element(ENABLE_NODE, &test_mlag_cmd); | |
ee235396 SK |
644 | |
645 | /* | |
646 | * Intialiaze teh MLAG Global variableis | |
647 | * write thread will be craeted during actual registration with MCLAG | |
648 | */ | |
649 | zrouter.mlag_info.clients_interested_cnt = 0; | |
650 | zrouter.mlag_info.connected = false; | |
651 | zrouter.mlag_info.timer_running = false; | |
652 | zrouter.mlag_info.mlag_fifo = stream_fifo_new(); | |
653 | zrouter.mlag_info.zebra_pth_mlag = NULL; | |
654 | zrouter.mlag_info.th_master = NULL; | |
655 | zrouter.mlag_info.t_read = NULL; | |
656 | zrouter.mlag_info.t_write = NULL; | |
657 | test_mlag_in_progress = false; | |
658 | zebra_mlag_reset_write_buffer(); | |
659 | zebra_mlag_reset_read_buffer(); | |
df395600 DS |
660 | } |
661 | ||
662 | void zebra_mlag_terminate(void) | |
663 | { | |
664 | } | |
ee235396 SK |
665 | |
666 | ||
667 | /* | |
668 | * | |
669 | * ProtoBuf Encoding APIs | |
670 | */ | |
671 | ||
672 | int zebra_mlag_protobuf_encode_client_data(struct stream *s, uint32_t *msg_type) | |
673 | { | |
674 | return 0; | |
675 | } | |
676 | ||
677 | int zebra_mlag_protobuf_decode_message(struct stream **s, uint8_t *data, | |
678 | uint32_t len) | |
679 | { | |
680 | return 0; | |
681 | } |