/src/frr/pimd/pim_zpthread.c
Line | Count | Source |
1 | | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | | /* |
3 | | * PIM for Quagga |
4 | | * Copyright (C) 2008 Everton da Silva Marques |
5 | | */ |
6 | | |
7 | | #include <zebra.h> |
8 | | #include <lib/log.h> |
9 | | #include <lib/lib_errors.h> |
10 | | |
11 | | #include "pimd.h" |
12 | | #include "pim_instance.h" |
13 | | #include "pim_mlag.h" |
14 | | #include "pim_zebra.h" |
15 | | |
16 | | extern struct zclient *zclient; |
17 | | |
18 | | #define PIM_MLAG_POST_LIMIT 100 |
19 | | |
20 | | int32_t mlag_bulk_cnt; |
21 | | |
22 | | static void pim_mlag_zebra_fill_header(enum mlag_msg_type msg_type) |
23 | 0 | { |
24 | 0 | uint32_t fill_msg_type = msg_type; |
25 | 0 | uint16_t data_len = 0; |
26 | 0 | uint16_t msg_cnt = 1; |
27 | 0 |
|
28 | 0 | switch (msg_type) { |
29 | 0 | case MLAG_REGISTER: |
30 | 0 | case MLAG_DEREGISTER: |
31 | 0 | data_len = sizeof(struct mlag_msg); |
32 | 0 | break; |
33 | 0 | case MLAG_MROUTE_ADD: |
34 | 0 | data_len = sizeof(struct mlag_mroute_add); |
35 | 0 | fill_msg_type = MLAG_MROUTE_ADD_BULK; |
36 | 0 | break; |
37 | 0 | case MLAG_MROUTE_DEL: |
38 | 0 | data_len = sizeof(struct mlag_mroute_del); |
39 | 0 | fill_msg_type = MLAG_MROUTE_DEL_BULK; |
40 | 0 | break; |
41 | 0 | case MLAG_MSG_NONE: |
42 | 0 | return; |
43 | 0 | case MLAG_STATUS_UPDATE: |
44 | 0 | case MLAG_DUMP: |
45 | 0 | case MLAG_MROUTE_ADD_BULK: |
46 | 0 | case MLAG_MROUTE_DEL_BULK: |
47 | 0 | case MLAG_PIM_CFG_DUMP: |
48 | 0 | case MLAG_VXLAN_UPDATE: |
49 | 0 | case MLAG_PEER_FRR_STATUS: |
50 | 0 | data_len = 0; |
51 | 0 | break; |
52 | 0 | } |
53 | 0 |
|
54 | 0 | stream_reset(router->mlag_stream); |
55 | 0 | /* ADD Hedaer */ |
56 | 0 | stream_putl(router->mlag_stream, fill_msg_type); |
57 | 0 | /* |
58 | 0 | * In case of Bulk actual size & msg_cnt will be updated |
59 | 0 | * just before writing onto zebra |
60 | 0 | */ |
61 | 0 | stream_putw(router->mlag_stream, data_len); |
62 | 0 | stream_putw(router->mlag_stream, msg_cnt); |
63 | 0 |
|
64 | 0 | if (PIM_DEBUG_MLAG) |
65 | 0 | zlog_debug(":%s: msg_type: %d/%d len %d", |
66 | 0 | __func__, msg_type, fill_msg_type, data_len); |
67 | 0 | } |
68 | | |
69 | | static void pim_mlag_zebra_flush_buffer(void) |
70 | 0 | { |
71 | 0 | uint32_t msg_type; |
72 | 0 |
|
73 | 0 | /* Stream had bulk messages update the Hedaer */ |
74 | 0 | if (mlag_bulk_cnt > 1) { |
75 | 0 | /* |
76 | 0 | * No need to reset the pointer, below api reads from data[0] |
77 | 0 | */ |
78 | 0 | STREAM_GETL(router->mlag_stream, msg_type); |
79 | 0 | if (msg_type == MLAG_MROUTE_ADD_BULK) { |
80 | 0 | stream_putw_at( |
81 | 0 | router->mlag_stream, 4, |
82 | 0 | (mlag_bulk_cnt * sizeof(struct mlag_mroute_add))); |
83 | 0 | stream_putw_at(router->mlag_stream, 6, mlag_bulk_cnt); |
84 | 0 | } else if (msg_type == MLAG_MROUTE_DEL_BULK) { |
85 | 0 | stream_putw_at( |
86 | 0 | router->mlag_stream, 4, |
87 | 0 | (mlag_bulk_cnt * sizeof(struct mlag_mroute_del))); |
88 | 0 | stream_putw_at(router->mlag_stream, 6, mlag_bulk_cnt); |
89 | 0 | } else { |
90 | 0 | flog_err(EC_LIB_ZAPI_ENCODE, |
91 | 0 | "unknown bulk message type %d bulk_count %d", |
92 | 0 | msg_type, mlag_bulk_cnt); |
93 | 0 | stream_reset(router->mlag_stream); |
94 | 0 | mlag_bulk_cnt = 0; |
95 | 0 | return; |
96 | 0 | } |
97 | 0 | } |
98 | 0 |
|
99 | 0 | zclient_send_mlag_data(zclient, router->mlag_stream); |
100 | 0 | stream_failure: |
101 | 0 | stream_reset(router->mlag_stream); |
102 | 0 | mlag_bulk_cnt = 0; |
103 | 0 | } |
104 | | |
105 | | /* |
106 | | * Only ROUTE add & Delete will be bulked. |
107 | | * Buffer will be flushed, when |
108 | | * 1) there were no messages in the queue |
109 | | * 2) Curr_msg_type != prev_msg_type |
110 | | */ |
111 | | |
112 | | static void pim_mlag_zebra_check_for_buffer_flush(uint32_t curr_msg_type, |
113 | | uint32_t prev_msg_type) |
114 | 0 | { |
115 | 0 | /* First Message, keep bulking */ |
116 | 0 | if (prev_msg_type == MLAG_MSG_NONE) { |
117 | 0 | mlag_bulk_cnt = 1; |
118 | 0 | return; |
119 | 0 | } |
120 | 0 |
|
121 | 0 | /*msg type is route add & delete, keep bulking */ |
122 | 0 | if (curr_msg_type == prev_msg_type |
123 | 0 | && (curr_msg_type == MLAG_MROUTE_ADD |
124 | 0 | || curr_msg_type == MLAG_MROUTE_DEL)) { |
125 | 0 | mlag_bulk_cnt++; |
126 | 0 | return; |
127 | 0 | } |
128 | 0 |
|
129 | 0 | pim_mlag_zebra_flush_buffer(); |
130 | 0 | } |
131 | | |
132 | | /* |
133 | | * Thsi thread reads the clients data from the Gloabl queue and encodes with |
134 | | * protobuf and pass on to the MLAG socket. |
135 | | */ |
136 | | static void pim_mlag_zthread_handler(struct event *event) |
137 | 0 | { |
138 | 0 | struct stream *read_s; |
139 | 0 | uint32_t wr_count = 0; |
140 | 0 | uint32_t prev_msg_type = MLAG_MSG_NONE; |
141 | 0 | uint32_t curr_msg_type = MLAG_MSG_NONE; |
142 | 0 |
|
143 | 0 | router->zpthread_mlag_write = NULL; |
144 | 0 | wr_count = stream_fifo_count_safe(router->mlag_fifo); |
145 | 0 |
|
146 | 0 | if (PIM_DEBUG_MLAG) |
147 | 0 | zlog_debug(":%s: Processing MLAG write, %d messages in queue", |
148 | 0 | __func__, wr_count); |
149 | 0 |
|
150 | 0 | if (wr_count == 0) |
151 | 0 | return; |
152 | 0 |
|
153 | 0 | for (wr_count = 0; wr_count < PIM_MLAG_POST_LIMIT; wr_count++) { |
154 | 0 | /* FIFO is empty,wait for teh message to be add */ |
155 | 0 | if (stream_fifo_count_safe(router->mlag_fifo) == 0) |
156 | 0 | break; |
157 | 0 |
|
158 | 0 | read_s = stream_fifo_pop_safe(router->mlag_fifo); |
159 | 0 | if (!read_s) { |
160 | 0 | zlog_debug(":%s: Got a NULL Messages, some thing wrong", |
161 | 0 | __func__); |
162 | 0 | break; |
163 | 0 | } |
164 | 0 | STREAM_GETL(read_s, curr_msg_type); |
165 | 0 | /* |
166 | 0 | * Check for Buffer Overflow, |
167 | 0 | * MLAG Can't process more than 'PIM_MLAG_BUF_LIMIT' bytes |
168 | 0 | */ |
169 | 0 | if (router->mlag_stream->endp + read_s->endp + ZEBRA_HEADER_SIZE |
170 | 0 | > MLAG_BUF_LIMIT) |
171 | 0 | pim_mlag_zebra_flush_buffer(); |
172 | 0 |
|
173 | 0 | pim_mlag_zebra_check_for_buffer_flush(curr_msg_type, |
174 | 0 | prev_msg_type); |
175 | 0 |
|
176 | 0 | /* |
177 | 0 | * First message to Buffer, fill the Header |
178 | 0 | */ |
179 | 0 | if (router->mlag_stream->endp == 0) |
180 | 0 | pim_mlag_zebra_fill_header(curr_msg_type); |
181 | 0 |
|
182 | 0 | /* |
183 | 0 | * add the data now |
184 | 0 | */ |
185 | 0 | stream_put(router->mlag_stream, read_s->data + read_s->getp, |
186 | 0 | read_s->endp - read_s->getp); |
187 | 0 |
|
188 | 0 | stream_free(read_s); |
189 | 0 | prev_msg_type = curr_msg_type; |
190 | 0 | } |
191 | 0 |
|
192 | 0 | stream_failure: |
193 | 0 | /* |
194 | 0 | * we are here , because |
195 | 0 | * 1. Queue might be empty |
196 | 0 | * 2. we crossed the max Q Read limit |
197 | 0 | * In any acse flush the buffer towards zebra |
198 | 0 | */ |
199 | 0 | pim_mlag_zebra_flush_buffer(); |
200 | 0 |
|
201 | 0 | if (wr_count >= PIM_MLAG_POST_LIMIT) |
202 | 0 | pim_mlag_signal_zpthread(); |
203 | 0 | } |
204 | | |
205 | | |
206 | | int pim_mlag_signal_zpthread(void) |
207 | 0 | { |
208 | 0 | if (router->master) { |
209 | 0 | if (PIM_DEBUG_MLAG) |
210 | 0 | zlog_debug(":%s: Scheduling PIM MLAG write Thread", |
211 | 0 | __func__); |
212 | 0 | event_add_event(router->master, pim_mlag_zthread_handler, NULL, |
213 | 0 | 0, &router->zpthread_mlag_write); |
214 | 0 | } |
215 | 0 | return (0); |
216 | 0 | } |