Line | Count | Source |
1 | | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | | /* Zebra's client library. |
3 | | * Copyright (C) 1999 Kunihiro Ishiguro |
4 | | * Copyright (C) 2005 Andrew J. Schorr |
5 | | */ |
6 | | |
7 | | #include <zebra.h> |
8 | | |
9 | | #include "prefix.h" |
10 | | #include "stream.h" |
11 | | #include "buffer.h" |
12 | | #include "network.h" |
13 | | #include "vrf.h" |
14 | | #include "vrf_int.h" |
15 | | #include "if.h" |
16 | | #include "log.h" |
17 | | #include "frrevent.h" |
18 | | #include "zclient.h" |
19 | | #include "memory.h" |
20 | | #include "table.h" |
21 | | #include "nexthop.h" |
22 | | #include "mpls.h" |
23 | | #include "sockopt.h" |
24 | | #include "pbr.h" |
25 | | #include "tc.h" |
26 | | #include "nexthop_group.h" |
27 | | #include "lib_errors.h" |
28 | | #include "srte.h" |
29 | | #include "printfrr.h" |
30 | | #include "srv6.h" |
31 | | |
32 | 8 | DEFINE_MTYPE_STATIC(LIB, ZCLIENT, "Zclient"); |
33 | 8 | DEFINE_MTYPE_STATIC(LIB, REDIST_INST, "Redistribution instance IDs"); |
34 | 8 | |
35 | 8 | /* Zebra client events. */ |
36 | 8 | enum zclient_event { ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT }; |
37 | 8 | |
38 | 8 | /* Prototype for event manager. */ |
39 | 8 | static void zclient_event(enum zclient_event, struct zclient *); |
40 | 8 | |
41 | 8 | static void zebra_interface_if_set_value(struct stream *s, |
42 | 8 | struct interface *ifp); |
43 | 8 | |
44 | 8 | struct zclient_options zclient_options_default = {.receive_notify = false, |
45 | 8 | .synchronous = false}; |
46 | 8 | |
47 | 8 | struct sockaddr_storage zclient_addr; |
48 | 8 | socklen_t zclient_addr_len; |
49 | 8 | |
50 | 8 | /* This file local debug flag. */ |
51 | 8 | static int zclient_debug; |
52 | 8 | |
53 | 8 | /* Allocate zclient structure. */ |
54 | 8 | struct zclient *zclient_new(struct event_loop *master, |
55 | 8 | struct zclient_options *opt, |
56 | 8 | zclient_handler *const *handlers, size_t n_handlers) |
57 | 8 | { |
58 | 5 | struct zclient *zclient; |
59 | 5 | size_t stream_size = |
60 | 5 | MAX(ZEBRA_MAX_PACKET_SIZ, sizeof(struct zapi_route)); |
61 | | |
62 | 5 | zclient = XCALLOC(MTYPE_ZCLIENT, sizeof(struct zclient)); |
63 | | |
64 | 5 | zclient->ibuf = stream_new(stream_size); |
65 | 5 | zclient->obuf = stream_new(stream_size); |
66 | 5 | zclient->wb = buffer_new(0); |
67 | 5 | zclient->master = master; |
68 | | |
69 | 5 | zclient->handlers = handlers; |
70 | 5 | zclient->n_handlers = n_handlers; |
71 | | |
72 | 5 | zclient->receive_notify = opt->receive_notify; |
73 | 5 | zclient->synchronous = opt->synchronous; |
74 | | |
75 | 5 | return zclient; |
76 | 5 | } |
77 | | |
78 | | /* This function is only called when exiting, because |
79 | | many parts of the code do not check for I/O errors, so they could |
80 | | reference an invalid pointer if the structure was ever freed. |
81 | | |
82 | | Free zclient structure. */ |
83 | | void zclient_free(struct zclient *zclient) |
84 | 0 | { |
85 | 0 | if (zclient->ibuf) |
86 | 0 | stream_free(zclient->ibuf); |
87 | 0 | if (zclient->obuf) |
88 | 0 | stream_free(zclient->obuf); |
89 | 0 | if (zclient->wb) |
90 | 0 | buffer_free(zclient->wb); |
91 | |
|
92 | 0 | XFREE(MTYPE_ZCLIENT, zclient); |
93 | 0 | } |
94 | | |
95 | | unsigned short *redist_check_instance(struct redist_proto *red, |
96 | | unsigned short instance) |
97 | 0 | { |
98 | 0 | struct listnode *node; |
99 | 0 | unsigned short *id; |
100 | |
|
101 | 0 | if (!red->instances) |
102 | 0 | return NULL; |
103 | | |
104 | 0 | for (ALL_LIST_ELEMENTS_RO(red->instances, node, id)) |
105 | 0 | if (*id == instance) |
106 | 0 | return id; |
107 | | |
108 | 0 | return NULL; |
109 | 0 | } |
110 | | |
111 | | void redist_add_instance(struct redist_proto *red, unsigned short instance) |
112 | 9 | { |
113 | 9 | unsigned short *in; |
114 | | |
115 | 9 | red->enabled = 1; |
116 | | |
117 | 9 | if (!red->instances) |
118 | 9 | red->instances = list_new(); |
119 | | |
120 | 9 | in = XMALLOC(MTYPE_REDIST_INST, sizeof(unsigned short)); |
121 | 9 | *in = instance; |
122 | 9 | listnode_add(red->instances, in); |
123 | 9 | } |
124 | | |
125 | | void redist_del_instance(struct redist_proto *red, unsigned short instance) |
126 | 0 | { |
127 | 0 | unsigned short *id; |
128 | |
|
129 | 0 | id = redist_check_instance(red, instance); |
130 | 0 | if (!id) |
131 | 0 | return; |
132 | | |
133 | 0 | listnode_delete(red->instances, id); |
134 | 0 | XFREE(MTYPE_REDIST_INST, id); |
135 | 0 | if (!red->instances->count) { |
136 | 0 | red->enabled = 0; |
137 | 0 | list_delete(&red->instances); |
138 | 0 | } |
139 | 0 | } |
140 | | |
141 | | void redist_del_all_instances(struct redist_proto *red) |
142 | 26.0k | { |
143 | 26.0k | struct listnode *ln, *nn; |
144 | 26.0k | unsigned short *id; |
145 | | |
146 | 26.0k | if (!red->instances) |
147 | 26.0k | return; |
148 | | |
149 | 0 | for (ALL_LIST_ELEMENTS(red->instances, ln, nn, id)) |
150 | 0 | redist_del_instance(red, *id); |
151 | 0 | } |
152 | | |
153 | | /* Stop zebra client services. */ |
154 | | void zclient_stop(struct zclient *zclient) |
155 | 0 | { |
156 | 0 | afi_t afi; |
157 | 0 | int i; |
158 | |
|
159 | 0 | if (zclient_debug) |
160 | 0 | zlog_debug("zclient %p stopped", zclient); |
161 | | |
162 | | /* Stop threads. */ |
163 | 0 | EVENT_OFF(zclient->t_read); |
164 | 0 | EVENT_OFF(zclient->t_connect); |
165 | 0 | EVENT_OFF(zclient->t_write); |
166 | | |
167 | | /* Reset streams. */ |
168 | 0 | stream_reset(zclient->ibuf); |
169 | 0 | stream_reset(zclient->obuf); |
170 | | |
171 | | /* Empty the write buffer. */ |
172 | 0 | buffer_reset(zclient->wb); |
173 | | |
174 | | /* Close socket. */ |
175 | 0 | if (zclient->sock >= 0) { |
176 | 0 | close(zclient->sock); |
177 | 0 | zclient->sock = -1; |
178 | 0 | } |
179 | 0 | zclient->fail = 0; |
180 | |
|
181 | 0 | for (afi = AFI_IP; afi < AFI_MAX; afi++) { |
182 | 0 | for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { |
183 | 0 | vrf_bitmap_free(zclient->redist[afi][i]); |
184 | 0 | zclient->redist[afi][i] = VRF_BITMAP_NULL; |
185 | 0 | } |
186 | 0 | redist_del_instance( |
187 | 0 | &zclient->mi_redist[afi][zclient->redist_default], |
188 | 0 | zclient->instance); |
189 | |
|
190 | 0 | vrf_bitmap_free(zclient->default_information[afi]); |
191 | 0 | zclient->default_information[afi] = VRF_BITMAP_NULL; |
192 | 0 | } |
193 | 0 | } |
194 | | |
195 | | void zclient_reset(struct zclient *zclient) |
196 | 0 | { |
197 | 0 | afi_t afi; |
198 | |
|
199 | 0 | zclient_stop(zclient); |
200 | |
|
201 | 0 | for (afi = AFI_IP; afi < AFI_MAX; afi++) |
202 | 0 | redist_del_instance( |
203 | 0 | &zclient->mi_redist[afi][zclient->redist_default], |
204 | 0 | zclient->instance); |
205 | |
|
206 | 0 | zclient_init(zclient, zclient->redist_default, zclient->instance, |
207 | 0 | zclient->privs); |
208 | 0 | } |
209 | | |
210 | | /** |
211 | | * Connect to zebra daemon. |
212 | | * @param zclient a pointer to zclient structure |
213 | | * @return socket fd just to make sure that connection established |
214 | | * @see zclient_init |
215 | | * @see zclient_new |
216 | | */ |
217 | | int zclient_socket_connect(struct zclient *zclient) |
218 | 0 | { |
219 | 0 | int sock; |
220 | 0 | int ret; |
221 | | |
222 | | /* We should think about IPv6 connection. */ |
223 | 0 | sock = socket(zclient_addr.ss_family, SOCK_STREAM, 0); |
224 | 0 | if (sock < 0) |
225 | 0 | return -1; |
226 | | |
227 | 0 | set_cloexec(sock); |
228 | 0 | setsockopt_so_sendbuf(sock, 1048576); |
229 | | |
230 | | /* Connect to zebra. */ |
231 | 0 | ret = connect(sock, (struct sockaddr *)&zclient_addr, zclient_addr_len); |
232 | 0 | if (ret < 0) { |
233 | 0 | if (zclient_debug) |
234 | 0 | zlog_debug("%s connect failure: %d(%s)", __func__, |
235 | 0 | errno, safe_strerror(errno)); |
236 | 0 | close(sock); |
237 | 0 | return -1; |
238 | 0 | } |
239 | | |
240 | 0 | zclient->sock = sock; |
241 | 0 | return sock; |
242 | 0 | } |
243 | | |
244 | | static enum zclient_send_status zclient_failed(struct zclient *zclient) |
245 | 0 | { |
246 | 0 | zclient->fail++; |
247 | 0 | zclient_stop(zclient); |
248 | 0 | zclient_event(ZCLIENT_CONNECT, zclient); |
249 | 0 | return ZCLIENT_SEND_FAILURE; |
250 | 0 | } |
251 | | |
252 | | static void zclient_flush_data(struct event *thread) |
253 | 0 | { |
254 | 0 | struct zclient *zclient = EVENT_ARG(thread); |
255 | 0 |
|
256 | 0 | zclient->t_write = NULL; |
257 | 0 | if (zclient->sock < 0) |
258 | 0 | return; |
259 | 0 | switch (buffer_flush_available(zclient->wb, zclient->sock)) { |
260 | 0 | case BUFFER_ERROR: |
261 | 0 | flog_err( |
262 | 0 | EC_LIB_ZAPI_SOCKET, |
263 | 0 | "%s: buffer_flush_available failed on zclient fd %d, closing", |
264 | 0 | __func__, zclient->sock); |
265 | 0 | zclient_failed(zclient); |
266 | 0 | return; |
267 | 0 | case BUFFER_PENDING: |
268 | 0 | zclient->t_write = NULL; |
269 | 0 | event_add_write(zclient->master, zclient_flush_data, zclient, |
270 | 0 | zclient->sock, &zclient->t_write); |
271 | 0 | break; |
272 | 0 | case BUFFER_EMPTY: |
273 | 0 | if (zclient->zebra_buffer_write_ready) |
274 | 0 | (*zclient->zebra_buffer_write_ready)(); |
275 | 0 | break; |
276 | 0 | } |
277 | 0 | } |
278 | | |
279 | | /* |
280 | | * Returns: |
281 | | * ZCLIENT_SEND_FAILED - is a failure |
282 | | * ZCLIENT_SEND_SUCCESS - means we sent data to zebra |
283 | | * ZCLIENT_SEND_BUFFERED - means we are buffering |
284 | | */ |
285 | | enum zclient_send_status zclient_send_message(struct zclient *zclient) |
286 | 47.1k | { |
287 | 47.1k | if (zclient->sock < 0) |
288 | 47.1k | return ZCLIENT_SEND_FAILURE; |
289 | 0 | switch (buffer_write(zclient->wb, zclient->sock, |
290 | 0 | STREAM_DATA(zclient->obuf), |
291 | 0 | stream_get_endp(zclient->obuf))) { |
292 | 0 | case BUFFER_ERROR: |
293 | 0 | flog_err(EC_LIB_ZAPI_SOCKET, |
294 | 0 | "%s: buffer_write failed to zclient fd %d, closing", |
295 | 0 | __func__, zclient->sock); |
296 | 0 | return zclient_failed(zclient); |
297 | 0 | case BUFFER_EMPTY: |
298 | 0 | EVENT_OFF(zclient->t_write); |
299 | 0 | return ZCLIENT_SEND_SUCCESS; |
300 | 0 | case BUFFER_PENDING: |
301 | 0 | event_add_write(zclient->master, zclient_flush_data, zclient, |
302 | 0 | zclient->sock, &zclient->t_write); |
303 | 0 | return ZCLIENT_SEND_BUFFERED; |
304 | 0 | } |
305 | | |
306 | | /* should not get here */ |
307 | 0 | return ZCLIENT_SEND_SUCCESS; |
308 | 0 | } |
309 | | |
310 | | /* |
311 | | * If we add more data to this structure please ensure that |
312 | | * struct zmsghdr in lib/zclient.h is updated as appropriate. |
313 | | */ |
314 | | void zclient_create_header(struct stream *s, uint16_t command, vrf_id_t vrf_id) |
315 | 49.6k | { |
316 | | /* length placeholder, caller can update */ |
317 | 49.6k | stream_putw(s, ZEBRA_HEADER_SIZE); |
318 | 49.6k | stream_putc(s, ZEBRA_HEADER_MARKER); |
319 | 49.6k | stream_putc(s, ZSERV_VERSION); |
320 | 49.6k | stream_putl(s, vrf_id); |
321 | 49.6k | stream_putw(s, command); |
322 | 49.6k | } |
323 | | |
324 | | int zclient_read_header(struct stream *s, int sock, uint16_t *size, |
325 | | uint8_t *marker, uint8_t *version, vrf_id_t *vrf_id, |
326 | | uint16_t *cmd) |
327 | 0 | { |
328 | 0 | if (stream_read(s, sock, ZEBRA_HEADER_SIZE) != ZEBRA_HEADER_SIZE) |
329 | 0 | return -1; |
330 | | |
331 | 0 | STREAM_GETW(s, *size); |
332 | 0 | *size -= ZEBRA_HEADER_SIZE; |
333 | 0 | STREAM_GETC(s, *marker); |
334 | 0 | STREAM_GETC(s, *version); |
335 | 0 | STREAM_GETL(s, *vrf_id); |
336 | 0 | STREAM_GETW(s, *cmd); |
337 | | |
338 | 0 | if (*version != ZSERV_VERSION || *marker != ZEBRA_HEADER_MARKER) { |
339 | 0 | flog_err( |
340 | 0 | EC_LIB_ZAPI_MISSMATCH, |
341 | 0 | "%s: socket %d version mismatch, marker %d, version %d", |
342 | 0 | __func__, sock, *marker, *version); |
343 | 0 | return -1; |
344 | 0 | } |
345 | | |
346 | 0 | if (*size && stream_read(s, sock, *size) != *size) |
347 | 0 | return -1; |
348 | | |
349 | 0 | return 0; |
350 | 0 | stream_failure: |
351 | 0 | return -1; |
352 | 0 | } |
353 | | |
354 | | bool zapi_parse_header(struct stream *zmsg, struct zmsghdr *hdr) |
355 | 255 | { |
356 | 255 | STREAM_GETW(zmsg, hdr->length); |
357 | 255 | STREAM_GETC(zmsg, hdr->marker); |
358 | 255 | STREAM_GETC(zmsg, hdr->version); |
359 | 255 | STREAM_GETL(zmsg, hdr->vrf_id); |
360 | 255 | STREAM_GETW(zmsg, hdr->command); |
361 | 255 | return true; |
362 | 0 | stream_failure: |
363 | 0 | return false; |
364 | 255 | } |
365 | | |
366 | | /* Send simple Zebra message. */ |
367 | | static enum zclient_send_status zebra_message_send(struct zclient *zclient, |
368 | | int command, vrf_id_t vrf_id) |
369 | 0 | { |
370 | 0 | struct stream *s; |
371 | | |
372 | | /* Get zclient output buffer. */ |
373 | 0 | s = zclient->obuf; |
374 | 0 | stream_reset(s); |
375 | | |
376 | | /* Send very simple command only Zebra message. */ |
377 | 0 | zclient_create_header(s, command, vrf_id); |
378 | |
|
379 | 0 | return zclient_send_message(zclient); |
380 | 0 | } |
381 | | |
382 | | enum zclient_send_status zclient_send_hello(struct zclient *zclient) |
383 | 0 | { |
384 | 0 | struct stream *s; |
385 | |
|
386 | 0 | if (zclient->redist_default || zclient->synchronous) { |
387 | 0 | s = zclient->obuf; |
388 | 0 | stream_reset(s); |
389 | | |
390 | | /* The VRF ID in the HELLO message is always 0. */ |
391 | 0 | zclient_create_header(s, ZEBRA_HELLO, VRF_DEFAULT); |
392 | 0 | stream_putc(s, zclient->redist_default); |
393 | 0 | stream_putw(s, zclient->instance); |
394 | 0 | stream_putl(s, zclient->session_id); |
395 | 0 | if (zclient->receive_notify) |
396 | 0 | stream_putc(s, 1); |
397 | 0 | else |
398 | 0 | stream_putc(s, 0); |
399 | 0 | if (zclient->synchronous) |
400 | 0 | stream_putc(s, 1); |
401 | 0 | else |
402 | 0 | stream_putc(s, 0); |
403 | |
|
404 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
405 | 0 | return zclient_send_message(zclient); |
406 | 0 | } |
407 | | |
408 | 0 | return ZCLIENT_SEND_SUCCESS; |
409 | 0 | } |
410 | | |
411 | | enum zclient_send_status zclient_send_vrf_label(struct zclient *zclient, |
412 | | vrf_id_t vrf_id, afi_t afi, |
413 | | mpls_label_t label, |
414 | | enum lsp_types_t ltype) |
415 | 0 | { |
416 | 0 | struct stream *s; |
417 | |
|
418 | 0 | s = zclient->obuf; |
419 | 0 | stream_reset(s); |
420 | |
|
421 | 0 | zclient_create_header(s, ZEBRA_VRF_LABEL, vrf_id); |
422 | 0 | stream_putl(s, label); |
423 | 0 | stream_putc(s, afi); |
424 | 0 | stream_putc(s, ltype); |
425 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
426 | 0 | return zclient_send_message(zclient); |
427 | 0 | } |
428 | | |
429 | | enum zclient_send_status zclient_send_localsid(struct zclient *zclient, |
430 | | const struct in6_addr *sid, vrf_id_t vrf_id, |
431 | | enum seg6local_action_t action, |
432 | | const struct seg6local_context *context) |
433 | 0 | { |
434 | 0 | struct prefix_ipv6 p = {}; |
435 | 0 | struct zapi_route api = {}; |
436 | 0 | struct zapi_nexthop *znh; |
437 | 0 | struct interface *ifp; |
438 | |
|
439 | 0 | ifp = if_get_vrf_loopback(vrf_id); |
440 | 0 | if (ifp == NULL) |
441 | 0 | return ZCLIENT_SEND_FAILURE; |
442 | | |
443 | 0 | p.family = AF_INET6; |
444 | 0 | p.prefixlen = IPV6_MAX_BITLEN; |
445 | 0 | p.prefix = *sid; |
446 | |
|
447 | 0 | api.vrf_id = VRF_DEFAULT; |
448 | 0 | api.type = zclient->redist_default; |
449 | 0 | api.instance = 0; |
450 | 0 | api.safi = SAFI_UNICAST; |
451 | 0 | memcpy(&api.prefix, &p, sizeof(p)); |
452 | |
|
453 | 0 | if (action == ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) |
454 | 0 | return zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); |
455 | | |
456 | 0 | SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION); |
457 | 0 | SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); |
458 | |
|
459 | 0 | znh = &api.nexthops[0]; |
460 | |
|
461 | 0 | memset(znh, 0, sizeof(*znh)); |
462 | |
|
463 | 0 | znh->type = NEXTHOP_TYPE_IFINDEX; |
464 | 0 | znh->ifindex = ifp->ifindex; |
465 | 0 | SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_SEG6LOCAL); |
466 | 0 | znh->seg6local_action = action; |
467 | 0 | memcpy(&znh->seg6local_ctx, context, sizeof(struct seg6local_context)); |
468 | |
|
469 | 0 | api.nexthop_num = 1; |
470 | |
|
471 | 0 | return zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api); |
472 | 0 | } |
473 | | |
474 | | /* Send register requests to zebra daemon for the information in a VRF. */ |
475 | | void zclient_send_reg_requests(struct zclient *zclient, vrf_id_t vrf_id) |
476 | 0 | { |
477 | 0 | int i; |
478 | 0 | afi_t afi; |
479 | | |
480 | | /* If not connected to the zebra yet. */ |
481 | 0 | if (zclient->sock < 0) |
482 | 0 | return; |
483 | | |
484 | 0 | if (zclient_debug) |
485 | 0 | zlog_debug("%s: send register messages for VRF %u", __func__, |
486 | 0 | vrf_id); |
487 | | |
488 | | /* We need router-id information. */ |
489 | 0 | zclient_send_router_id_update(zclient, ZEBRA_ROUTER_ID_ADD, AFI_IP, |
490 | 0 | vrf_id); |
491 | | |
492 | | /* We need interface information. */ |
493 | 0 | zebra_message_send(zclient, ZEBRA_INTERFACE_ADD, vrf_id); |
494 | | |
495 | | /* Set unwanted redistribute route. */ |
496 | 0 | for (afi = AFI_IP; afi < AFI_MAX; afi++) |
497 | 0 | vrf_bitmap_set(zclient->redist[afi][zclient->redist_default], |
498 | 0 | vrf_id); |
499 | | |
500 | | /* Flush all redistribute request. */ |
501 | 0 | if (vrf_id == VRF_DEFAULT) { |
502 | 0 | for (afi = AFI_IP; afi < AFI_MAX; afi++) { |
503 | 0 | for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { |
504 | 0 | if (!zclient->mi_redist[afi][i].enabled) |
505 | 0 | continue; |
506 | | |
507 | 0 | struct listnode *node; |
508 | 0 | unsigned short *id; |
509 | |
|
510 | 0 | for (ALL_LIST_ELEMENTS_RO( |
511 | 0 | zclient->mi_redist[afi][i] |
512 | 0 | .instances, |
513 | 0 | node, id)) |
514 | 0 | if (!(i == zclient->redist_default |
515 | 0 | && *id == zclient->instance)) |
516 | 0 | zebra_redistribute_send( |
517 | 0 | ZEBRA_REDISTRIBUTE_ADD, |
518 | 0 | zclient, afi, i, *id, |
519 | 0 | VRF_DEFAULT); |
520 | 0 | } |
521 | 0 | } |
522 | 0 | } |
523 | | |
524 | | /* Resend all redistribute request. */ |
525 | 0 | for (afi = AFI_IP; afi < AFI_MAX; afi++) { |
526 | 0 | for (i = 0; i < ZEBRA_ROUTE_MAX; i++) |
527 | 0 | if (i != zclient->redist_default |
528 | 0 | && vrf_bitmap_check(zclient->redist[afi][i], |
529 | 0 | vrf_id)) |
530 | 0 | zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, |
531 | 0 | zclient, afi, i, 0, |
532 | 0 | vrf_id); |
533 | | |
534 | | /* If default information is needed. */ |
535 | 0 | if (vrf_bitmap_check(zclient->default_information[afi], vrf_id)) |
536 | 0 | zebra_redistribute_default_send( |
537 | 0 | ZEBRA_REDISTRIBUTE_DEFAULT_ADD, zclient, afi, |
538 | 0 | vrf_id); |
539 | 0 | } |
540 | 0 | } |
541 | | |
542 | | /* Send unregister requests to zebra daemon for the information in a VRF. */ |
543 | | void zclient_send_dereg_requests(struct zclient *zclient, vrf_id_t vrf_id) |
544 | 0 | { |
545 | 0 | int i; |
546 | 0 | afi_t afi; |
547 | | |
548 | | /* If not connected to the zebra yet. */ |
549 | 0 | if (zclient->sock < 0) |
550 | 0 | return; |
551 | | |
552 | 0 | if (zclient_debug) |
553 | 0 | zlog_debug("%s: send deregister messages for VRF %u", __func__, |
554 | 0 | vrf_id); |
555 | | |
556 | | /* We need router-id information. */ |
557 | 0 | zclient_send_router_id_update(zclient, ZEBRA_ROUTER_ID_DELETE, AFI_IP, |
558 | 0 | vrf_id); |
559 | |
|
560 | 0 | zebra_message_send(zclient, ZEBRA_INTERFACE_DELETE, vrf_id); |
561 | | |
562 | | /* Set unwanted redistribute route. */ |
563 | 0 | for (afi = AFI_IP; afi < AFI_MAX; afi++) |
564 | 0 | vrf_bitmap_unset(zclient->redist[afi][zclient->redist_default], |
565 | 0 | vrf_id); |
566 | | |
567 | | /* Flush all redistribute request. */ |
568 | 0 | if (vrf_id == VRF_DEFAULT) { |
569 | 0 | for (afi = AFI_IP; afi < AFI_MAX; afi++) { |
570 | 0 | for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { |
571 | 0 | if (!zclient->mi_redist[afi][i].enabled) |
572 | 0 | continue; |
573 | | |
574 | 0 | struct listnode *node; |
575 | 0 | unsigned short *id; |
576 | |
|
577 | 0 | for (ALL_LIST_ELEMENTS_RO( |
578 | 0 | zclient->mi_redist[afi][i] |
579 | 0 | .instances, |
580 | 0 | node, id)) |
581 | 0 | if (!(i == zclient->redist_default |
582 | 0 | && *id == zclient->instance)) |
583 | 0 | zebra_redistribute_send( |
584 | 0 | ZEBRA_REDISTRIBUTE_DELETE, |
585 | 0 | zclient, afi, i, *id, |
586 | 0 | VRF_DEFAULT); |
587 | 0 | } |
588 | 0 | } |
589 | 0 | } |
590 | | |
591 | | /* Flush all redistribute request. */ |
592 | 0 | for (afi = AFI_IP; afi < AFI_MAX; afi++) { |
593 | 0 | for (i = 0; i < ZEBRA_ROUTE_MAX; i++) |
594 | 0 | if (i != zclient->redist_default |
595 | 0 | && vrf_bitmap_check(zclient->redist[afi][i], |
596 | 0 | vrf_id)) |
597 | 0 | zebra_redistribute_send( |
598 | 0 | ZEBRA_REDISTRIBUTE_DELETE, zclient, afi, |
599 | 0 | i, 0, vrf_id); |
600 | | |
601 | | /* If default information is needed. */ |
602 | 0 | if (vrf_bitmap_check(zclient->default_information[afi], vrf_id)) |
603 | 0 | zebra_redistribute_default_send( |
604 | 0 | ZEBRA_REDISTRIBUTE_DEFAULT_DELETE, zclient, afi, |
605 | 0 | vrf_id); |
606 | 0 | } |
607 | 0 | } |
608 | | |
609 | | enum zclient_send_status |
610 | | zclient_send_router_id_update(struct zclient *zclient, |
611 | | zebra_message_types_t type, afi_t afi, |
612 | | vrf_id_t vrf_id) |
613 | 0 | { |
614 | 0 | struct stream *s = zclient->obuf; |
615 | 0 | stream_reset(s); |
616 | 0 | zclient_create_header(s, type, vrf_id); |
617 | 0 | stream_putw(s, afi); |
618 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
619 | 0 | return zclient_send_message(zclient); |
620 | 0 | } |
621 | | |
622 | | /* Send request to zebra daemon to start or stop RA. */ |
623 | | enum zclient_send_status |
624 | | zclient_send_interface_radv_req(struct zclient *zclient, vrf_id_t vrf_id, |
625 | | struct interface *ifp, int enable, |
626 | | uint32_t ra_interval) |
627 | 0 | { |
628 | 0 | struct stream *s; |
629 | | |
630 | | /* If not connected to the zebra yet. */ |
631 | 0 | if (zclient->sock < 0) |
632 | 0 | return ZCLIENT_SEND_FAILURE; |
633 | | |
634 | | /* Form and send message. */ |
635 | 0 | s = zclient->obuf; |
636 | 0 | stream_reset(s); |
637 | |
|
638 | 0 | if (enable) |
639 | 0 | zclient_create_header(s, ZEBRA_INTERFACE_ENABLE_RADV, vrf_id); |
640 | 0 | else |
641 | 0 | zclient_create_header(s, ZEBRA_INTERFACE_DISABLE_RADV, vrf_id); |
642 | |
|
643 | 0 | stream_putl(s, ifp->ifindex); |
644 | 0 | stream_putl(s, ra_interval); |
645 | |
|
646 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
647 | |
|
648 | 0 | return zclient_send_message(zclient); |
649 | 0 | } |
650 | | |
651 | | enum zclient_send_status |
652 | | zclient_send_interface_protodown(struct zclient *zclient, vrf_id_t vrf_id, |
653 | | struct interface *ifp, bool down) |
654 | 0 | { |
655 | 0 | struct stream *s; |
656 | |
|
657 | 0 | if (zclient->sock < 0) |
658 | 0 | return ZCLIENT_SEND_FAILURE; |
659 | | |
660 | 0 | s = zclient->obuf; |
661 | 0 | stream_reset(s); |
662 | 0 | zclient_create_header(s, ZEBRA_INTERFACE_SET_PROTODOWN, vrf_id); |
663 | 0 | stream_putl(s, ifp->ifindex); |
664 | 0 | stream_putc(s, !!down); |
665 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
666 | 0 | return zclient_send_message(zclient); |
667 | 0 | } |
668 | | |
669 | | /* Make connection to zebra daemon. */ |
670 | | int zclient_start(struct zclient *zclient) |
671 | 0 | { |
672 | 0 | if (zclient_debug) |
673 | 0 | zlog_info("zclient_start is called"); |
674 | | |
675 | | /* If already connected to the zebra. */ |
676 | 0 | if (zclient->sock >= 0) |
677 | 0 | return 0; |
678 | | |
679 | | /* Check connect thread. */ |
680 | 0 | if (zclient->t_connect) |
681 | 0 | return 0; |
682 | | |
683 | 0 | if (zclient_socket_connect(zclient) < 0) { |
684 | 0 | if (zclient_debug) |
685 | 0 | zlog_debug("zclient connection fail"); |
686 | 0 | zclient->fail++; |
687 | 0 | zclient_event(ZCLIENT_CONNECT, zclient); |
688 | 0 | return -1; |
689 | 0 | } |
690 | | |
691 | 0 | if (set_nonblocking(zclient->sock) < 0) |
692 | 0 | flog_err(EC_LIB_ZAPI_SOCKET, "%s: set_nonblocking(%d) failed", |
693 | 0 | __func__, zclient->sock); |
694 | | |
695 | | /* Clear fail count. */ |
696 | 0 | zclient->fail = 0; |
697 | 0 | if (zclient_debug) |
698 | 0 | zlog_debug("zclient connect success with socket [%d]", |
699 | 0 | zclient->sock); |
700 | | |
701 | | /* Create read thread. */ |
702 | 0 | zclient_event(ZCLIENT_READ, zclient); |
703 | |
|
704 | 0 | zclient_send_hello(zclient); |
705 | |
|
706 | 0 | zebra_message_send(zclient, ZEBRA_INTERFACE_ADD, VRF_DEFAULT); |
707 | | |
708 | | /* Inform the successful connection. */ |
709 | 0 | if (zclient->zebra_connected) |
710 | 0 | (*zclient->zebra_connected)(zclient); |
711 | |
|
712 | 0 | return 0; |
713 | 0 | } |
714 | | |
715 | | /* Initialize zebra client. Argument redist_default is unwanted |
716 | | redistribute route type. */ |
717 | | void zclient_init(struct zclient *zclient, int redist_default, |
718 | | unsigned short instance, struct zebra_privs_t *privs) |
719 | 3 | { |
720 | 3 | int afi, i; |
721 | | |
722 | | /* Set -1 to the default socket value. */ |
723 | 3 | zclient->sock = -1; |
724 | 3 | zclient->privs = privs; |
725 | | |
726 | | /* Clear redistribution flags. */ |
727 | 12 | for (afi = AFI_IP; afi < AFI_MAX; afi++) |
728 | 288 | for (i = 0; i < ZEBRA_ROUTE_MAX; i++) |
729 | 279 | zclient->redist[afi][i] = vrf_bitmap_init(); |
730 | | |
731 | | /* Set unwanted redistribute route. bgpd does not need BGP route |
732 | | redistribution. */ |
733 | 3 | zclient->redist_default = redist_default; |
734 | 3 | zclient->instance = instance; |
735 | | /* Pending: make afi(s) an arg. */ |
736 | 12 | for (afi = AFI_IP; afi < AFI_MAX; afi++) { |
737 | 9 | redist_add_instance(&zclient->mi_redist[afi][redist_default], |
738 | 9 | instance); |
739 | | |
740 | | /* Set default-information redistribute to zero. */ |
741 | 9 | zclient->default_information[afi] = vrf_bitmap_init(); |
742 | 9 | } |
743 | | |
744 | 3 | if (zclient_debug) |
745 | 0 | zlog_debug("scheduling zclient connection"); |
746 | | |
747 | 3 | zclient_event(ZCLIENT_SCHEDULE, zclient); |
748 | 3 | } |
749 | | |
750 | | /* This function is a wrapper function for calling zclient_start from |
751 | | timer or event thread. */ |
752 | | static void zclient_connect(struct event *t) |
753 | 0 | { |
754 | 0 | struct zclient *zclient; |
755 | 0 |
|
756 | 0 | zclient = EVENT_ARG(t); |
757 | 0 | zclient->t_connect = NULL; |
758 | 0 |
|
759 | 0 | if (zclient_debug) |
760 | 0 | zlog_debug("zclient_connect is called"); |
761 | 0 |
|
762 | 0 | zclient_start(zclient); |
763 | 0 | } |
764 | | |
765 | | enum zclient_send_status zclient_send_rnh(struct zclient *zclient, int command, |
766 | | const struct prefix *p, safi_t safi, |
767 | | bool connected, bool resolve_via_def, |
768 | | vrf_id_t vrf_id) |
769 | 47.1k | { |
770 | 47.1k | struct stream *s; |
771 | | |
772 | 47.1k | s = zclient->obuf; |
773 | 47.1k | stream_reset(s); |
774 | 47.1k | zclient_create_header(s, command, vrf_id); |
775 | 47.1k | stream_putc(s, (connected) ? 1 : 0); |
776 | 47.1k | stream_putc(s, (resolve_via_def) ? 1 : 0); |
777 | 47.1k | stream_putw(s, safi); |
778 | 47.1k | stream_putw(s, PREFIX_FAMILY(p)); |
779 | 47.1k | stream_putc(s, p->prefixlen); |
780 | 47.1k | switch (PREFIX_FAMILY(p)) { |
781 | 47.1k | case AF_INET: |
782 | 47.1k | stream_put_in_addr(s, &p->u.prefix4); |
783 | 47.1k | break; |
784 | 0 | case AF_INET6: |
785 | 0 | stream_put(s, &(p->u.prefix6), 16); |
786 | 0 | break; |
787 | 0 | default: |
788 | 0 | break; |
789 | 47.1k | } |
790 | 47.1k | stream_putw_at(s, 0, stream_get_endp(s)); |
791 | | |
792 | 47.1k | return zclient_send_message(zclient); |
793 | 47.1k | } |
794 | | |
795 | | /* |
796 | | * "xdr_encode"-like interface that allows daemon (client) to send |
797 | | * a message to zebra server for a route that needs to be |
798 | | * added/deleted to the kernel. Info about the route is specified |
799 | | * by the caller in a struct zapi_route. zapi_route_encode() then writes |
800 | | * the info down the zclient socket using the stream_* functions. |
801 | | * |
802 | | * The corresponding read ("xdr_decode") function on the server |
803 | | * side is zapi_route_decode(). |
804 | | * |
805 | | * If ZAPI_MESSAGE_DISTANCE is set, the distance value is written as a 1 |
806 | | * byte value. |
807 | | * |
808 | | * If ZAPI_MESSAGE_METRIC is set, the metric value is written as a 4 |
809 | | * byte value. |
810 | | * |
811 | | * If ZAPI_MESSAGE_TAG is set, the tag value is written as a 4 byte value |
812 | | * |
813 | | * If ZAPI_MESSAGE_MTU is set, the mtu value is written as a 4 byte value |
814 | | * |
815 | | * XXX: No attention paid to alignment. |
816 | | */ |
817 | | enum zclient_send_status |
818 | | zclient_route_send(uint8_t cmd, struct zclient *zclient, struct zapi_route *api) |
819 | 0 | { |
820 | 0 | if (zapi_route_encode(cmd, zclient->obuf, api) < 0) |
821 | 0 | return ZCLIENT_SEND_FAILURE; |
822 | 0 | return zclient_send_message(zclient); |
823 | 0 | } |
824 | | |
825 | | static int zapi_nexthop_labels_cmp(const struct zapi_nexthop *next1, |
826 | | const struct zapi_nexthop *next2) |
827 | 0 | { |
828 | 0 | if (next1->label_num > next2->label_num) |
829 | 0 | return 1; |
830 | | |
831 | 0 | if (next1->label_num < next2->label_num) |
832 | 0 | return -1; |
833 | | |
834 | 0 | return memcmp(next1->labels, next2->labels, next1->label_num); |
835 | 0 | } |
836 | | |
837 | | static int zapi_nexthop_srv6_cmp(const struct zapi_nexthop *next1, |
838 | | const struct zapi_nexthop *next2) |
839 | 0 | { |
840 | 0 | int ret = 0; |
841 | |
|
842 | 0 | ret = memcmp(&next1->seg6_segs, &next2->seg6_segs, |
843 | 0 | sizeof(struct in6_addr)); |
844 | 0 | if (ret != 0) |
845 | 0 | return ret; |
846 | | |
847 | 0 | if (next1->seg6local_action > next2->seg6local_action) |
848 | 0 | return 1; |
849 | | |
850 | 0 | if (next1->seg6local_action < next2->seg6local_action) |
851 | 0 | return -1; |
852 | | |
853 | 0 | return memcmp(&next1->seg6local_ctx, &next2->seg6local_ctx, |
854 | 0 | sizeof(struct seg6local_context)); |
855 | 0 | } |
856 | | |
857 | | static int zapi_nexthop_cmp_no_labels(const struct zapi_nexthop *next1, |
858 | | const struct zapi_nexthop *next2) |
859 | 0 | { |
860 | 0 | int ret = 0; |
861 | |
|
862 | 0 | if (next1->vrf_id < next2->vrf_id) |
863 | 0 | return -1; |
864 | | |
865 | 0 | if (next1->vrf_id > next2->vrf_id) |
866 | 0 | return 1; |
867 | | |
868 | 0 | if (next1->type < next2->type) |
869 | 0 | return -1; |
870 | | |
871 | 0 | if (next1->type > next2->type) |
872 | 0 | return 1; |
873 | | |
874 | 0 | if (next1->weight < next2->weight) |
875 | 0 | return -1; |
876 | | |
877 | 0 | if (next1->weight > next2->weight) |
878 | 0 | return 1; |
879 | | |
880 | 0 | switch (next1->type) { |
881 | 0 | case NEXTHOP_TYPE_IPV4: |
882 | 0 | case NEXTHOP_TYPE_IPV6: |
883 | 0 | ret = nexthop_g_addr_cmp(next1->type, &next1->gate, |
884 | 0 | &next2->gate); |
885 | 0 | if (ret != 0) |
886 | 0 | return ret; |
887 | 0 | break; |
888 | 0 | case NEXTHOP_TYPE_IPV4_IFINDEX: |
889 | 0 | case NEXTHOP_TYPE_IPV6_IFINDEX: |
890 | 0 | ret = nexthop_g_addr_cmp(next1->type, &next1->gate, |
891 | 0 | &next2->gate); |
892 | 0 | if (ret != 0) |
893 | 0 | return ret; |
894 | | /* Intentional Fall-Through */ |
895 | 0 | case NEXTHOP_TYPE_IFINDEX: |
896 | 0 | if (next1->ifindex < next2->ifindex) |
897 | 0 | return -1; |
898 | | |
899 | 0 | if (next1->ifindex > next2->ifindex) |
900 | 0 | return 1; |
901 | 0 | break; |
902 | 0 | case NEXTHOP_TYPE_BLACKHOLE: |
903 | 0 | if (next1->bh_type < next2->bh_type) |
904 | 0 | return -1; |
905 | | |
906 | 0 | if (next1->bh_type > next2->bh_type) |
907 | 0 | return 1; |
908 | 0 | break; |
909 | 0 | } |
910 | | |
911 | 0 | if (next1->srte_color < next2->srte_color) |
912 | 0 | return -1; |
913 | 0 | if (next1->srte_color > next2->srte_color) |
914 | 0 | return 1; |
915 | | |
916 | 0 | if (CHECK_FLAG(next1->flags, NEXTHOP_FLAG_HAS_BACKUP) || |
917 | 0 | CHECK_FLAG(next2->flags, NEXTHOP_FLAG_HAS_BACKUP)) { |
918 | |
|
919 | 0 | if (!CHECK_FLAG(next1->flags, NEXTHOP_FLAG_HAS_BACKUP) && |
920 | 0 | CHECK_FLAG(next2->flags, NEXTHOP_FLAG_HAS_BACKUP)) |
921 | 0 | return -1; |
922 | | |
923 | 0 | if (CHECK_FLAG(next1->flags, NEXTHOP_FLAG_HAS_BACKUP) && |
924 | 0 | !CHECK_FLAG(next2->flags, NEXTHOP_FLAG_HAS_BACKUP)) |
925 | 0 | return 1; |
926 | | |
927 | 0 | if (next1->backup_num > 0 || next2->backup_num > 0) { |
928 | |
|
929 | 0 | if (next1->backup_num < next2->backup_num) |
930 | 0 | return -1; |
931 | | |
932 | 0 | if (next1->backup_num > next2->backup_num) |
933 | 0 | return 1; |
934 | | |
935 | 0 | ret = memcmp(next1->backup_idx, |
936 | 0 | next2->backup_idx, next1->backup_num); |
937 | 0 | if (ret != 0) |
938 | 0 | return ret; |
939 | 0 | } |
940 | 0 | } |
941 | | |
942 | 0 | return 0; |
943 | 0 | } |
944 | | |
945 | | static int zapi_nexthop_cmp(const void *item1, const void *item2) |
946 | 0 | { |
947 | 0 | int ret = 0; |
948 | |
|
949 | 0 | const struct zapi_nexthop *next1 = item1; |
950 | 0 | const struct zapi_nexthop *next2 = item2; |
951 | |
|
952 | 0 | ret = zapi_nexthop_cmp_no_labels(next1, next2); |
953 | 0 | if (ret != 0) |
954 | 0 | return ret; |
955 | | |
956 | 0 | ret = zapi_nexthop_labels_cmp(next1, next2); |
957 | 0 | if (ret != 0) |
958 | 0 | return ret; |
959 | | |
960 | 0 | ret = zapi_nexthop_srv6_cmp(next1, next2); |
961 | |
|
962 | 0 | return ret; |
963 | 0 | } |
964 | | |
965 | | static void zapi_nexthop_group_sort(struct zapi_nexthop *nh_grp, |
966 | | uint16_t nexthop_num) |
967 | 0 | { |
968 | 0 | qsort(nh_grp, nexthop_num, sizeof(struct zapi_nexthop), |
969 | 0 | &zapi_nexthop_cmp); |
970 | 0 | } |
971 | | |
972 | | /* |
973 | | * Encode a single zapi nexthop |
974 | | */ |
975 | | int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh, |
976 | | uint32_t api_flags, uint32_t api_message) |
977 | 0 | { |
978 | 0 | int i, ret = 0; |
979 | 0 | int nh_flags = api_nh->flags; |
980 | |
|
981 | 0 | stream_putl(s, api_nh->vrf_id); |
982 | 0 | stream_putc(s, api_nh->type); |
983 | | |
984 | | /* If needed, set 'labelled nexthop' flag */ |
985 | 0 | if (api_nh->label_num > 0) { |
986 | 0 | SET_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_LABEL); |
987 | | |
988 | | /* Validate label count */ |
989 | 0 | if (api_nh->label_num > MPLS_MAX_LABELS) { |
990 | 0 | ret = -1; |
991 | 0 | goto done; |
992 | 0 | } |
993 | 0 | } |
994 | | |
995 | | /* If present, set 'weight' flag before encoding flags */ |
996 | 0 | if (api_nh->weight) |
997 | 0 | SET_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_WEIGHT); |
998 | | |
999 | | /* Note that we're only encoding a single octet */ |
1000 | 0 | stream_putc(s, nh_flags); |
1001 | |
|
1002 | 0 | switch (api_nh->type) { |
1003 | 0 | case NEXTHOP_TYPE_BLACKHOLE: |
1004 | 0 | stream_putc(s, api_nh->bh_type); |
1005 | 0 | break; |
1006 | 0 | case NEXTHOP_TYPE_IPV4: |
1007 | 0 | case NEXTHOP_TYPE_IPV4_IFINDEX: |
1008 | 0 | stream_put_in_addr(s, &api_nh->gate.ipv4); |
1009 | 0 | stream_putl(s, api_nh->ifindex); |
1010 | 0 | break; |
1011 | 0 | case NEXTHOP_TYPE_IFINDEX: |
1012 | 0 | stream_putl(s, api_nh->ifindex); |
1013 | 0 | break; |
1014 | 0 | case NEXTHOP_TYPE_IPV6: |
1015 | 0 | case NEXTHOP_TYPE_IPV6_IFINDEX: |
1016 | 0 | stream_write(s, (uint8_t *)&api_nh->gate.ipv6, |
1017 | 0 | 16); |
1018 | 0 | stream_putl(s, api_nh->ifindex); |
1019 | 0 | break; |
1020 | 0 | } |
1021 | | |
1022 | | /* We only encode labels if we have >0 - we use |
1023 | | * the per-nexthop flag above to signal that the count |
1024 | | * is present in the payload. |
1025 | | */ |
1026 | 0 | if (api_nh->label_num > 0) { |
1027 | 0 | stream_putc(s, api_nh->label_num); |
1028 | 0 | stream_putc(s, api_nh->label_type); |
1029 | 0 | stream_put(s, &api_nh->labels[0], |
1030 | 0 | api_nh->label_num * sizeof(mpls_label_t)); |
1031 | 0 | } |
1032 | |
|
1033 | 0 | if (api_nh->weight) |
1034 | 0 | stream_putl(s, api_nh->weight); |
1035 | | |
1036 | | /* Router MAC for EVPN routes. */ |
1037 | 0 | if (CHECK_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_EVPN)) |
1038 | 0 | stream_put(s, &(api_nh->rmac), |
1039 | 0 | sizeof(struct ethaddr)); |
1040 | | |
1041 | | /* Color for Segment Routing TE. */ |
1042 | 0 | if (CHECK_FLAG(api_message, ZAPI_MESSAGE_SRTE)) |
1043 | 0 | stream_putl(s, api_nh->srte_color); |
1044 | | |
1045 | | /* Index of backup nexthop */ |
1046 | 0 | if (CHECK_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) { |
1047 | | /* Validate backup count */ |
1048 | 0 | if (api_nh->backup_num > NEXTHOP_MAX_BACKUPS) { |
1049 | 0 | ret = -1; |
1050 | 0 | goto done; |
1051 | 0 | } |
1052 | | |
1053 | 0 | stream_putc(s, api_nh->backup_num); |
1054 | 0 | for (i = 0; i < api_nh->backup_num; i++) |
1055 | 0 | stream_putc(s, api_nh->backup_idx[i]); |
1056 | 0 | } |
1057 | | |
1058 | 0 | if (CHECK_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_SEG6LOCAL)) { |
1059 | 0 | stream_putl(s, api_nh->seg6local_action); |
1060 | 0 | stream_write(s, &api_nh->seg6local_ctx, |
1061 | 0 | sizeof(struct seg6local_context)); |
1062 | 0 | } |
1063 | |
|
1064 | 0 | if (CHECK_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_SEG6)) |
1065 | 0 | stream_write(s, &api_nh->seg6_segs, |
1066 | 0 | sizeof(struct in6_addr)); |
1067 | |
|
1068 | 0 | done: |
1069 | 0 | return ret; |
1070 | 0 | } |
1071 | | |
1072 | | int zapi_srv6_locator_chunk_encode(struct stream *s, |
1073 | | const struct srv6_locator_chunk *c) |
1074 | 0 | { |
1075 | 0 | stream_putw(s, strlen(c->locator_name)); |
1076 | 0 | stream_put(s, c->locator_name, strlen(c->locator_name)); |
1077 | 0 | stream_putw(s, c->prefix.prefixlen); |
1078 | 0 | stream_put(s, &c->prefix.prefix, sizeof(c->prefix.prefix)); |
1079 | 0 | stream_putc(s, c->block_bits_length); |
1080 | 0 | stream_putc(s, c->node_bits_length); |
1081 | 0 | stream_putc(s, c->function_bits_length); |
1082 | 0 | stream_putc(s, c->argument_bits_length); |
1083 | 0 | stream_putc(s, c->flags); |
1084 | 0 | return 0; |
1085 | 0 | } |
1086 | | |
1087 | | int zapi_srv6_locator_chunk_decode(struct stream *s, |
1088 | | struct srv6_locator_chunk *c) |
1089 | 0 | { |
1090 | 0 | uint16_t len = 0; |
1091 | |
|
1092 | 0 | c->prefix.family = AF_INET6; |
1093 | |
|
1094 | 0 | STREAM_GETW(s, len); |
1095 | 0 | if (len > SRV6_LOCNAME_SIZE) |
1096 | 0 | goto stream_failure; |
1097 | | |
1098 | 0 | STREAM_GET(c->locator_name, s, len); |
1099 | 0 | STREAM_GETW(s, c->prefix.prefixlen); |
1100 | 0 | STREAM_GET(&c->prefix.prefix, s, sizeof(c->prefix.prefix)); |
1101 | 0 | STREAM_GETC(s, c->block_bits_length); |
1102 | 0 | STREAM_GETC(s, c->node_bits_length); |
1103 | 0 | STREAM_GETC(s, c->function_bits_length); |
1104 | 0 | STREAM_GETC(s, c->argument_bits_length); |
1105 | 0 | STREAM_GETC(s, c->flags); |
1106 | 0 | return 0; |
1107 | | |
1108 | 0 | stream_failure: |
1109 | 0 | return -1; |
1110 | 0 | } |
1111 | | |
1112 | | int zapi_srv6_locator_encode(struct stream *s, const struct srv6_locator *l) |
1113 | 0 | { |
1114 | 0 | stream_putw(s, strlen(l->name)); |
1115 | 0 | stream_put(s, l->name, strlen(l->name)); |
1116 | 0 | stream_putw(s, l->prefix.prefixlen); |
1117 | 0 | stream_put(s, &l->prefix.prefix, sizeof(l->prefix.prefix)); |
1118 | 0 | return 0; |
1119 | 0 | } |
1120 | | |
1121 | | int zapi_srv6_locator_decode(struct stream *s, struct srv6_locator *l) |
1122 | 0 | { |
1123 | 0 | uint16_t len = 0; |
1124 | |
|
1125 | 0 | STREAM_GETW(s, len); |
1126 | 0 | if (len > SRV6_LOCNAME_SIZE) |
1127 | 0 | goto stream_failure; |
1128 | | |
1129 | 0 | STREAM_GET(l->name, s, len); |
1130 | 0 | STREAM_GETW(s, l->prefix.prefixlen); |
1131 | 0 | STREAM_GET(&l->prefix.prefix, s, sizeof(l->prefix.prefix)); |
1132 | 0 | l->prefix.family = AF_INET6; |
1133 | 0 | return 0; |
1134 | | |
1135 | 0 | stream_failure: |
1136 | 0 | return -1; |
1137 | 0 | } |
1138 | | |
1139 | | static int zapi_nhg_encode(struct stream *s, int cmd, struct zapi_nhg *api_nhg) |
1140 | 0 | { |
1141 | 0 | int i; |
1142 | |
|
1143 | 0 | if (cmd != ZEBRA_NHG_DEL && cmd != ZEBRA_NHG_ADD) { |
1144 | 0 | flog_err(EC_LIB_ZAPI_ENCODE, |
1145 | 0 | "%s: Specified zapi NHG command (%d) doesn't exist", |
1146 | 0 | __func__, cmd); |
1147 | 0 | return -1; |
1148 | 0 | } |
1149 | | |
1150 | 0 | if (api_nhg->nexthop_num >= MULTIPATH_NUM || |
1151 | 0 | api_nhg->backup_nexthop_num >= MULTIPATH_NUM) { |
1152 | 0 | flog_err(EC_LIB_ZAPI_ENCODE, |
1153 | 0 | "%s: zapi NHG encode with invalid input", __func__); |
1154 | 0 | return -1; |
1155 | 0 | } |
1156 | | |
1157 | 0 | stream_reset(s); |
1158 | 0 | zclient_create_header(s, cmd, VRF_DEFAULT); |
1159 | |
|
1160 | 0 | stream_putw(s, api_nhg->proto); |
1161 | 0 | stream_putl(s, api_nhg->id); |
1162 | |
|
1163 | 0 | stream_putw(s, api_nhg->resilience.buckets); |
1164 | 0 | stream_putl(s, api_nhg->resilience.idle_timer); |
1165 | 0 | stream_putl(s, api_nhg->resilience.unbalanced_timer); |
1166 | |
|
1167 | 0 | if (cmd == ZEBRA_NHG_ADD) { |
1168 | | /* Nexthops */ |
1169 | 0 | zapi_nexthop_group_sort(api_nhg->nexthops, |
1170 | 0 | api_nhg->nexthop_num); |
1171 | |
|
1172 | 0 | stream_putw(s, api_nhg->nexthop_num); |
1173 | |
|
1174 | 0 | for (i = 0; i < api_nhg->nexthop_num; i++) |
1175 | 0 | zapi_nexthop_encode(s, &api_nhg->nexthops[i], 0, 0); |
1176 | | |
1177 | | /* Backup nexthops */ |
1178 | 0 | stream_putw(s, api_nhg->backup_nexthop_num); |
1179 | |
|
1180 | 0 | for (i = 0; i < api_nhg->backup_nexthop_num; i++) |
1181 | 0 | zapi_nexthop_encode(s, &api_nhg->backup_nexthops[i], 0, |
1182 | 0 | 0); |
1183 | 0 | } |
1184 | |
|
1185 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
1186 | |
|
1187 | 0 | return 0; |
1188 | 0 | } |
1189 | | |
1190 | | enum zclient_send_status zclient_nhg_send(struct zclient *zclient, int cmd, |
1191 | | struct zapi_nhg *api_nhg) |
1192 | 0 | { |
1193 | 0 | api_nhg->proto = zclient->redist_default; |
1194 | |
|
1195 | 0 | if (zapi_nhg_encode(zclient->obuf, cmd, api_nhg)) |
1196 | 0 | return -1; |
1197 | | |
1198 | 0 | return zclient_send_message(zclient); |
1199 | 0 | } |
1200 | | |
1201 | | int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api) |
1202 | 0 | { |
1203 | 0 | struct zapi_nexthop *api_nh; |
1204 | 0 | int i; |
1205 | 0 | int psize; |
1206 | |
|
1207 | 0 | stream_reset(s); |
1208 | 0 | zclient_create_header(s, cmd, api->vrf_id); |
1209 | |
|
1210 | 0 | if (api->type >= ZEBRA_ROUTE_MAX) { |
1211 | 0 | flog_err(EC_LIB_ZAPI_ENCODE, |
1212 | 0 | "%s: Specified route type (%u) is not a legal value", |
1213 | 0 | __func__, api->type); |
1214 | 0 | return -1; |
1215 | 0 | } |
1216 | 0 | stream_putc(s, api->type); |
1217 | |
|
1218 | 0 | stream_putw(s, api->instance); |
1219 | 0 | stream_putl(s, api->flags); |
1220 | 0 | stream_putl(s, api->message); |
1221 | |
|
1222 | 0 | if (api->safi < SAFI_UNICAST || api->safi >= SAFI_MAX) { |
1223 | 0 | flog_err(EC_LIB_ZAPI_ENCODE, |
1224 | 0 | "%s: Specified route SAFI (%u) is not a legal value", |
1225 | 0 | __func__, api->safi); |
1226 | 0 | return -1; |
1227 | 0 | } |
1228 | 0 | stream_putc(s, api->safi); |
1229 | | |
1230 | | /* Put prefix information. */ |
1231 | 0 | stream_putc(s, api->prefix.family); |
1232 | 0 | psize = PSIZE(api->prefix.prefixlen); |
1233 | 0 | stream_putc(s, api->prefix.prefixlen); |
1234 | 0 | stream_write(s, &api->prefix.u.prefix, psize); |
1235 | |
|
1236 | 0 | if (CHECK_FLAG(api->message, ZAPI_MESSAGE_SRCPFX)) { |
1237 | 0 | psize = PSIZE(api->src_prefix.prefixlen); |
1238 | 0 | stream_putc(s, api->src_prefix.prefixlen); |
1239 | 0 | stream_write(s, (uint8_t *)&api->src_prefix.prefix, psize); |
1240 | 0 | } |
1241 | |
|
1242 | 0 | if (CHECK_FLAG(api->message, ZAPI_MESSAGE_NHG)) |
1243 | 0 | stream_putl(s, api->nhgid); |
1244 | | |
1245 | | /* Nexthops. */ |
1246 | 0 | if (CHECK_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP)) { |
1247 | | /* limit the number of nexthops if necessary */ |
1248 | 0 | if (api->nexthop_num > MULTIPATH_NUM) { |
1249 | 0 | flog_err( |
1250 | 0 | EC_LIB_ZAPI_ENCODE, |
1251 | 0 | "%s: prefix %pFX: can't encode %u nexthops (maximum is %u)", |
1252 | 0 | __func__, &api->prefix, api->nexthop_num, |
1253 | 0 | MULTIPATH_NUM); |
1254 | 0 | return -1; |
1255 | 0 | } |
1256 | | |
1257 | | /* We canonicalize the nexthops by sorting them; this allows |
1258 | | * zebra to resolve the list of nexthops to a nexthop-group |
1259 | | * more efficiently. |
1260 | | */ |
1261 | 0 | zapi_nexthop_group_sort(api->nexthops, api->nexthop_num); |
1262 | |
|
1263 | 0 | stream_putw(s, api->nexthop_num); |
1264 | |
|
1265 | 0 | for (i = 0; i < api->nexthop_num; i++) { |
1266 | 0 | api_nh = &api->nexthops[i]; |
1267 | | |
1268 | | /* MPLS labels for BGP-LU or Segment Routing */ |
1269 | 0 | if (api_nh->label_num > MPLS_MAX_LABELS) { |
1270 | 0 | flog_err( |
1271 | 0 | EC_LIB_ZAPI_ENCODE, |
1272 | 0 | "%s: prefix %pFX: can't encode %u labels (maximum is %u)", |
1273 | 0 | __func__, &api->prefix, |
1274 | 0 | api_nh->label_num, MPLS_MAX_LABELS); |
1275 | 0 | return -1; |
1276 | 0 | } |
1277 | | |
1278 | 0 | if (zapi_nexthop_encode(s, api_nh, api->flags, |
1279 | 0 | api->message) |
1280 | 0 | != 0) |
1281 | 0 | return -1; |
1282 | 0 | } |
1283 | 0 | } |
1284 | | |
1285 | | /* Backup nexthops */ |
1286 | 0 | if (CHECK_FLAG(api->message, ZAPI_MESSAGE_BACKUP_NEXTHOPS)) { |
1287 | | /* limit the number of nexthops if necessary */ |
1288 | 0 | if (api->backup_nexthop_num > MULTIPATH_NUM) { |
1289 | 0 | flog_err( |
1290 | 0 | EC_LIB_ZAPI_ENCODE, |
1291 | 0 | "%s: prefix %pFX: can't encode %u backup nexthops (maximum is %u)", |
1292 | 0 | __func__, &api->prefix, api->backup_nexthop_num, |
1293 | 0 | MULTIPATH_NUM); |
1294 | 0 | return -1; |
1295 | 0 | } |
1296 | | |
1297 | | /* Note that we do not sort the list of backup nexthops - |
1298 | | * this list is treated as an array and indexed by each |
1299 | | * primary nexthop that is associated with a backup. |
1300 | | */ |
1301 | | |
1302 | 0 | stream_putw(s, api->backup_nexthop_num); |
1303 | |
|
1304 | 0 | for (i = 0; i < api->backup_nexthop_num; i++) { |
1305 | 0 | api_nh = &api->backup_nexthops[i]; |
1306 | | |
1307 | | /* MPLS labels for BGP-LU or Segment Routing */ |
1308 | 0 | if (api_nh->label_num > MPLS_MAX_LABELS) { |
1309 | 0 | flog_err( |
1310 | 0 | EC_LIB_ZAPI_ENCODE, |
1311 | 0 | "%s: prefix %pFX: backup: can't encode %u labels (maximum is %u)", |
1312 | 0 | __func__, &api->prefix, |
1313 | 0 | api_nh->label_num, MPLS_MAX_LABELS); |
1314 | 0 | return -1; |
1315 | 0 | } |
1316 | | |
1317 | 0 | if (zapi_nexthop_encode(s, api_nh, api->flags, |
1318 | 0 | api->message) |
1319 | 0 | != 0) |
1320 | 0 | return -1; |
1321 | 0 | } |
1322 | 0 | } |
1323 | | |
1324 | | /* Attributes. */ |
1325 | 0 | if (CHECK_FLAG(api->message, ZAPI_MESSAGE_DISTANCE)) |
1326 | 0 | stream_putc(s, api->distance); |
1327 | 0 | if (CHECK_FLAG(api->message, ZAPI_MESSAGE_METRIC)) |
1328 | 0 | stream_putl(s, api->metric); |
1329 | 0 | if (CHECK_FLAG(api->message, ZAPI_MESSAGE_TAG)) |
1330 | 0 | stream_putl(s, api->tag); |
1331 | 0 | if (CHECK_FLAG(api->message, ZAPI_MESSAGE_MTU)) |
1332 | 0 | stream_putl(s, api->mtu); |
1333 | 0 | if (CHECK_FLAG(api->message, ZAPI_MESSAGE_TABLEID)) |
1334 | 0 | stream_putl(s, api->tableid); |
1335 | |
|
1336 | 0 | if (CHECK_FLAG(api->message, ZAPI_MESSAGE_OPAQUE)) { |
1337 | 0 | if (api->opaque.length > ZAPI_MESSAGE_OPAQUE_LENGTH) { |
1338 | 0 | flog_err( |
1339 | 0 | EC_LIB_ZAPI_ENCODE, |
1340 | 0 | "%s: opaque length %u is greater than allowed value", |
1341 | 0 | __func__, api->opaque.length); |
1342 | 0 | return -1; |
1343 | 0 | } |
1344 | | |
1345 | 0 | stream_putw(s, api->opaque.length); |
1346 | 0 | stream_write(s, api->opaque.data, api->opaque.length); |
1347 | 0 | } |
1348 | | /* Put length at the first point of the stream. */ |
1349 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
1350 | |
|
1351 | 0 | return 0; |
1352 | 0 | } |
1353 | | |
1354 | | /* |
1355 | | * Decode a single zapi nexthop object |
1356 | | */ |
1357 | | int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh, |
1358 | | uint32_t api_flags, uint32_t api_message) |
1359 | 0 | { |
1360 | 0 | int i, ret = -1; |
1361 | |
|
1362 | 0 | STREAM_GETL(s, api_nh->vrf_id); |
1363 | 0 | STREAM_GETC(s, api_nh->type); |
1364 | | |
1365 | | /* Note that we're only using a single octet of flags */ |
1366 | 0 | STREAM_GETC(s, api_nh->flags); |
1367 | | |
1368 | 0 | switch (api_nh->type) { |
1369 | 0 | case NEXTHOP_TYPE_BLACKHOLE: |
1370 | 0 | STREAM_GETC(s, api_nh->bh_type); |
1371 | 0 | break; |
1372 | 0 | case NEXTHOP_TYPE_IPV4: |
1373 | 0 | case NEXTHOP_TYPE_IPV4_IFINDEX: |
1374 | 0 | STREAM_GET(&api_nh->gate.ipv4.s_addr, s, |
1375 | 0 | IPV4_MAX_BYTELEN); |
1376 | 0 | STREAM_GETL(s, api_nh->ifindex); |
1377 | 0 | break; |
1378 | 0 | case NEXTHOP_TYPE_IFINDEX: |
1379 | 0 | STREAM_GETL(s, api_nh->ifindex); |
1380 | 0 | break; |
1381 | 0 | case NEXTHOP_TYPE_IPV6: |
1382 | 0 | case NEXTHOP_TYPE_IPV6_IFINDEX: |
1383 | 0 | STREAM_GET(&api_nh->gate.ipv6, s, 16); |
1384 | 0 | STREAM_GETL(s, api_nh->ifindex); |
1385 | 0 | break; |
1386 | 0 | } |
1387 | | |
1388 | | /* MPLS labels for BGP-LU or Segment Routing */ |
1389 | 0 | if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL)) { |
1390 | 0 | STREAM_GETC(s, api_nh->label_num); |
1391 | 0 | STREAM_GETC(s, api_nh->label_type); |
1392 | 0 | if (api_nh->label_num > MPLS_MAX_LABELS) { |
1393 | 0 | flog_err( |
1394 | 0 | EC_LIB_ZAPI_ENCODE, |
1395 | 0 | "%s: invalid number of MPLS labels (%u)", |
1396 | 0 | __func__, api_nh->label_num); |
1397 | 0 | return -1; |
1398 | 0 | } |
1399 | | |
1400 | 0 | STREAM_GET(&api_nh->labels[0], s, |
1401 | 0 | api_nh->label_num * sizeof(mpls_label_t)); |
1402 | 0 | } |
1403 | | |
1404 | 0 | if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_WEIGHT)) |
1405 | 0 | STREAM_GETL(s, api_nh->weight); |
1406 | | |
1407 | | /* Router MAC for EVPN routes. */ |
1408 | 0 | if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN)) |
1409 | 0 | STREAM_GET(&(api_nh->rmac), s, |
1410 | 0 | sizeof(struct ethaddr)); |
1411 | | |
1412 | | /* Color for Segment Routing TE. */ |
1413 | 0 | if (CHECK_FLAG(api_message, ZAPI_MESSAGE_SRTE)) |
1414 | 0 | STREAM_GETL(s, api_nh->srte_color); |
1415 | | |
1416 | | /* Backup nexthop index */ |
1417 | 0 | if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) { |
1418 | 0 | STREAM_GETC(s, api_nh->backup_num); |
1419 | | |
1420 | 0 | if (api_nh->backup_num > NEXTHOP_MAX_BACKUPS) |
1421 | 0 | return -1; |
1422 | | |
1423 | 0 | for (i = 0; i < api_nh->backup_num; i++) |
1424 | 0 | STREAM_GETC(s, api_nh->backup_idx[i]); |
1425 | 0 | } |
1426 | | |
1427 | 0 | if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6LOCAL)) { |
1428 | 0 | STREAM_GETL(s, api_nh->seg6local_action); |
1429 | 0 | STREAM_GET(&api_nh->seg6local_ctx, s, |
1430 | 0 | sizeof(struct seg6local_context)); |
1431 | 0 | } |
1432 | | |
1433 | 0 | if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6)) |
1434 | 0 | STREAM_GET(&api_nh->seg6_segs, s, |
1435 | 0 | sizeof(struct in6_addr)); |
1436 | | |
1437 | | /* Success */ |
1438 | 0 | ret = 0; |
1439 | |
|
1440 | 0 | stream_failure: |
1441 | |
|
1442 | 0 | return ret; |
1443 | 0 | } |
1444 | | |
1445 | | int zapi_route_decode(struct stream *s, struct zapi_route *api) |
1446 | 0 | { |
1447 | 0 | struct zapi_nexthop *api_nh; |
1448 | 0 | int i; |
1449 | |
|
1450 | 0 | memset(api, 0, sizeof(*api)); |
1451 | | |
1452 | | /* Type, flags, message. */ |
1453 | 0 | STREAM_GETC(s, api->type); |
1454 | 0 | if (api->type >= ZEBRA_ROUTE_MAX) { |
1455 | 0 | flog_err(EC_LIB_ZAPI_ENCODE, |
1456 | 0 | "%s: Specified route type: %d is not a legal value", |
1457 | 0 | __func__, api->type); |
1458 | 0 | return -1; |
1459 | 0 | } |
1460 | | |
1461 | 0 | STREAM_GETW(s, api->instance); |
1462 | 0 | STREAM_GETL(s, api->flags); |
1463 | 0 | STREAM_GETL(s, api->message); |
1464 | 0 | STREAM_GETC(s, api->safi); |
1465 | 0 | if (api->safi < SAFI_UNICAST || api->safi >= SAFI_MAX) { |
1466 | 0 | flog_err(EC_LIB_ZAPI_ENCODE, |
1467 | 0 | "%s: Specified route SAFI (%u) is not a legal value", |
1468 | 0 | __func__, api->safi); |
1469 | 0 | return -1; |
1470 | 0 | } |
1471 | | |
1472 | | /* Prefix. */ |
1473 | 0 | STREAM_GETC(s, api->prefix.family); |
1474 | 0 | STREAM_GETC(s, api->prefix.prefixlen); |
1475 | 0 | switch (api->prefix.family) { |
1476 | 0 | case AF_INET: |
1477 | 0 | if (api->prefix.prefixlen > IPV4_MAX_BITLEN) { |
1478 | 0 | flog_err( |
1479 | 0 | EC_LIB_ZAPI_ENCODE, |
1480 | 0 | "%s: V4 prefixlen is %d which should not be more than 32", |
1481 | 0 | __func__, api->prefix.prefixlen); |
1482 | 0 | return -1; |
1483 | 0 | } |
1484 | 0 | break; |
1485 | 0 | case AF_INET6: |
1486 | 0 | if (api->prefix.prefixlen > IPV6_MAX_BITLEN) { |
1487 | 0 | flog_err( |
1488 | 0 | EC_LIB_ZAPI_ENCODE, |
1489 | 0 | "%s: v6 prefixlen is %d which should not be more than 128", |
1490 | 0 | __func__, api->prefix.prefixlen); |
1491 | 0 | return -1; |
1492 | 0 | } |
1493 | 0 | break; |
1494 | 0 | default: |
1495 | 0 | flog_err(EC_LIB_ZAPI_ENCODE, |
1496 | 0 | "%s: Specified family %d is not v4 or v6", __func__, |
1497 | 0 | api->prefix.family); |
1498 | 0 | return -1; |
1499 | 0 | } |
1500 | 0 | STREAM_GET(&api->prefix.u.prefix, s, PSIZE(api->prefix.prefixlen)); |
1501 | | |
1502 | 0 | if (CHECK_FLAG(api->message, ZAPI_MESSAGE_SRCPFX)) { |
1503 | 0 | api->src_prefix.family = AF_INET6; |
1504 | 0 | STREAM_GETC(s, api->src_prefix.prefixlen); |
1505 | 0 | if (api->src_prefix.prefixlen > IPV6_MAX_BITLEN) { |
1506 | 0 | flog_err( |
1507 | 0 | EC_LIB_ZAPI_ENCODE, |
1508 | 0 | "%s: SRC Prefix prefixlen received: %d is too large", |
1509 | 0 | __func__, api->src_prefix.prefixlen); |
1510 | 0 | return -1; |
1511 | 0 | } |
1512 | 0 | STREAM_GET(&api->src_prefix.prefix, s, |
1513 | 0 | PSIZE(api->src_prefix.prefixlen)); |
1514 | | |
1515 | 0 | if (api->prefix.family != AF_INET6 |
1516 | 0 | || api->src_prefix.prefixlen == 0) { |
1517 | 0 | flog_err( |
1518 | 0 | EC_LIB_ZAPI_ENCODE, |
1519 | 0 | "%s: SRC prefix specified in some manner that makes no sense", |
1520 | 0 | __func__); |
1521 | 0 | return -1; |
1522 | 0 | } |
1523 | 0 | } |
1524 | | |
1525 | 0 | if (CHECK_FLAG(api->message, ZAPI_MESSAGE_NHG)) |
1526 | 0 | STREAM_GETL(s, api->nhgid); |
1527 | | |
1528 | | /* Nexthops. */ |
1529 | 0 | if (CHECK_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP)) { |
1530 | 0 | STREAM_GETW(s, api->nexthop_num); |
1531 | 0 | if (api->nexthop_num > MULTIPATH_NUM) { |
1532 | 0 | flog_err(EC_LIB_ZAPI_ENCODE, |
1533 | 0 | "%s: invalid number of nexthops (%u)", |
1534 | 0 | __func__, api->nexthop_num); |
1535 | 0 | return -1; |
1536 | 0 | } |
1537 | | |
1538 | 0 | for (i = 0; i < api->nexthop_num; i++) { |
1539 | 0 | api_nh = &api->nexthops[i]; |
1540 | |
|
1541 | 0 | if (zapi_nexthop_decode(s, api_nh, api->flags, |
1542 | 0 | api->message) |
1543 | 0 | != 0) |
1544 | 0 | return -1; |
1545 | 0 | } |
1546 | 0 | } |
1547 | | |
1548 | | /* Backup nexthops. */ |
1549 | 0 | if (CHECK_FLAG(api->message, ZAPI_MESSAGE_BACKUP_NEXTHOPS)) { |
1550 | 0 | STREAM_GETW(s, api->backup_nexthop_num); |
1551 | 0 | if (api->backup_nexthop_num > MULTIPATH_NUM) { |
1552 | 0 | flog_err(EC_LIB_ZAPI_ENCODE, |
1553 | 0 | "%s: invalid number of backup nexthops (%u)", |
1554 | 0 | __func__, api->backup_nexthop_num); |
1555 | 0 | return -1; |
1556 | 0 | } |
1557 | | |
1558 | 0 | for (i = 0; i < api->backup_nexthop_num; i++) { |
1559 | 0 | api_nh = &api->backup_nexthops[i]; |
1560 | |
|
1561 | 0 | if (zapi_nexthop_decode(s, api_nh, api->flags, |
1562 | 0 | api->message) |
1563 | 0 | != 0) |
1564 | 0 | return -1; |
1565 | 0 | } |
1566 | 0 | } |
1567 | | |
1568 | | /* Attributes. */ |
1569 | 0 | if (CHECK_FLAG(api->message, ZAPI_MESSAGE_DISTANCE)) |
1570 | 0 | STREAM_GETC(s, api->distance); |
1571 | 0 | if (CHECK_FLAG(api->message, ZAPI_MESSAGE_METRIC)) |
1572 | 0 | STREAM_GETL(s, api->metric); |
1573 | 0 | if (CHECK_FLAG(api->message, ZAPI_MESSAGE_TAG)) |
1574 | 0 | STREAM_GETL(s, api->tag); |
1575 | 0 | if (CHECK_FLAG(api->message, ZAPI_MESSAGE_MTU)) |
1576 | 0 | STREAM_GETL(s, api->mtu); |
1577 | 0 | if (CHECK_FLAG(api->message, ZAPI_MESSAGE_TABLEID)) |
1578 | 0 | STREAM_GETL(s, api->tableid); |
1579 | | |
1580 | 0 | if (CHECK_FLAG(api->message, ZAPI_MESSAGE_OPAQUE)) { |
1581 | 0 | STREAM_GETW(s, api->opaque.length); |
1582 | 0 | if (api->opaque.length > ZAPI_MESSAGE_OPAQUE_LENGTH) { |
1583 | 0 | flog_err( |
1584 | 0 | EC_LIB_ZAPI_ENCODE, |
1585 | 0 | "%s: opaque length %u is greater than allowed value", |
1586 | 0 | __func__, api->opaque.length); |
1587 | 0 | return -1; |
1588 | 0 | } |
1589 | | |
1590 | 0 | STREAM_GET(api->opaque.data, s, api->opaque.length); |
1591 | 0 | } |
1592 | | |
1593 | 0 | return 0; |
1594 | 0 | stream_failure: |
1595 | 0 | return -1; |
1596 | 0 | } |
1597 | | |
1598 | | static void zapi_encode_prefix(struct stream *s, struct prefix *p, |
1599 | | uint8_t family) |
1600 | 0 | { |
1601 | 0 | struct prefix any; |
1602 | |
|
1603 | 0 | if (!p) { |
1604 | 0 | memset(&any, 0, sizeof(any)); |
1605 | 0 | any.family = family; |
1606 | 0 | p = &any; |
1607 | 0 | } |
1608 | |
|
1609 | 0 | stream_putc(s, p->family); |
1610 | 0 | stream_putc(s, p->prefixlen); |
1611 | 0 | stream_put(s, &p->u.prefix, prefix_blen(p)); |
1612 | 0 | } |
1613 | | |
1614 | | int zapi_pbr_rule_encode(uint8_t cmd, struct stream *s, struct pbr_rule *zrule) |
1615 | 0 | { |
1616 | 0 | stream_reset(s); |
1617 | 0 | zclient_create_header(s, cmd, zrule->vrf_id); |
1618 | | |
1619 | | /* |
1620 | | * We are sending one item at a time at the moment |
1621 | | */ |
1622 | 0 | stream_putl(s, 1); |
1623 | |
|
1624 | 0 | stream_putl(s, zrule->seq); |
1625 | 0 | stream_putl(s, zrule->priority); |
1626 | 0 | stream_putl(s, zrule->unique); |
1627 | |
|
1628 | 0 | zapi_encode_prefix(s, &(zrule->filter.src_ip), |
1629 | 0 | zrule->filter.src_ip.family); |
1630 | 0 | stream_putw(s, zrule->filter.src_port); /* src port */ |
1631 | 0 | zapi_encode_prefix(s, &(zrule->filter.dst_ip), |
1632 | 0 | zrule->filter.src_ip.family); |
1633 | 0 | stream_putw(s, zrule->filter.dst_port); /* dst port */ |
1634 | 0 | stream_putw(s, zrule->filter.fwmark); /* fwmark */ |
1635 | |
|
1636 | 0 | stream_putl(s, zrule->action.table); |
1637 | 0 | stream_put(s, zrule->ifname, INTERFACE_NAMSIZ); |
1638 | | |
1639 | | /* Put length at the first point of the stream. */ |
1640 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
1641 | |
|
1642 | 0 | return 0; |
1643 | 0 | } |
1644 | | |
1645 | | int zapi_tc_qdisc_encode(uint8_t cmd, struct stream *s, struct tc_qdisc *qdisc) |
1646 | 0 | { |
1647 | 0 | stream_reset(s); |
1648 | 0 | zclient_create_header(s, cmd, VRF_DEFAULT); |
1649 | | |
1650 | |
|
1651 | 0 | stream_putl(s, 1); |
1652 | |
|
1653 | 0 | stream_putl(s, qdisc->ifindex); |
1654 | 0 | stream_putl(s, qdisc->kind); |
1655 | |
|
1656 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
1657 | |
|
1658 | 0 | return 0; |
1659 | 0 | } |
1660 | | |
1661 | | int zapi_tc_class_encode(uint8_t cmd, struct stream *s, struct tc_class *class) |
1662 | 0 | { |
1663 | 0 | stream_reset(s); |
1664 | 0 | zclient_create_header(s, cmd, VRF_DEFAULT); |
1665 | |
|
1666 | 0 | stream_putl(s, 1); |
1667 | |
|
1668 | 0 | stream_putl(s, class->ifindex); |
1669 | 0 | stream_putl(s, class->handle); |
1670 | 0 | stream_putl(s, class->kind); |
1671 | |
|
1672 | 0 | switch (class->kind) { |
1673 | 0 | case TC_QDISC_HTB: |
1674 | 0 | stream_putq(s, class->u.htb.rate); |
1675 | 0 | stream_putq(s, class->u.htb.ceil); |
1676 | 0 | break; |
1677 | 0 | case TC_QDISC_UNSPEC: |
1678 | 0 | case TC_QDISC_NOQUEUE: |
1679 | | /* not implemented */ |
1680 | 0 | break; |
1681 | 0 | } |
1682 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
1683 | |
|
1684 | 0 | return 0; |
1685 | 0 | } |
1686 | | |
1687 | | int zapi_tc_filter_encode(uint8_t cmd, struct stream *s, |
1688 | | struct tc_filter *filter) |
1689 | 0 | { |
1690 | 0 | stream_reset(s); |
1691 | 0 | zclient_create_header(s, cmd, VRF_DEFAULT); |
1692 | |
|
1693 | 0 | stream_putl(s, 1); |
1694 | |
|
1695 | 0 | stream_putl(s, filter->ifindex); |
1696 | 0 | stream_putl(s, filter->handle); |
1697 | 0 | stream_putl(s, filter->priority); |
1698 | 0 | stream_putl(s, filter->protocol); |
1699 | 0 | stream_putl(s, filter->kind); |
1700 | |
|
1701 | 0 | switch (filter->kind) { |
1702 | 0 | case TC_FILTER_FLOWER: |
1703 | 0 | stream_putl(s, filter->u.flower.filter_bm); |
1704 | 0 | if (filter->u.flower.filter_bm & TC_FLOWER_IP_PROTOCOL) |
1705 | 0 | stream_putc(s, filter->u.flower.ip_proto); |
1706 | 0 | if (filter->u.flower.filter_bm & TC_FLOWER_SRC_IP) |
1707 | 0 | zapi_encode_prefix(s, &filter->u.flower.src_ip, |
1708 | 0 | filter->u.flower.src_ip.family); |
1709 | 0 | if (filter->u.flower.filter_bm & TC_FLOWER_SRC_PORT) { |
1710 | 0 | stream_putw(s, filter->u.flower.src_port_min); |
1711 | 0 | stream_putw(s, filter->u.flower.src_port_max); |
1712 | 0 | } |
1713 | 0 | if (filter->u.flower.filter_bm & TC_FLOWER_DST_IP) |
1714 | 0 | zapi_encode_prefix(s, &filter->u.flower.dst_ip, |
1715 | 0 | filter->u.flower.dst_ip.family); |
1716 | 0 | if (filter->u.flower.filter_bm & TC_FLOWER_DST_PORT) { |
1717 | 0 | stream_putw(s, filter->u.flower.dst_port_min); |
1718 | 0 | stream_putw(s, filter->u.flower.dst_port_max); |
1719 | 0 | } |
1720 | 0 | if (filter->u.flower.filter_bm & TC_FLOWER_DSFIELD) { |
1721 | 0 | stream_putc(s, filter->u.flower.dsfield); |
1722 | 0 | stream_putc(s, filter->u.flower.dsfield_mask); |
1723 | 0 | } |
1724 | 0 | stream_putl(s, filter->u.flower.classid); |
1725 | 0 | break; |
1726 | 0 | case TC_FILTER_UNSPEC: |
1727 | 0 | case TC_FILTER_BPF: |
1728 | 0 | case TC_FILTER_FLOW: |
1729 | 0 | case TC_FILTER_U32: |
1730 | | /* not implemented */ |
1731 | 0 | break; |
1732 | 0 | } |
1733 | | |
1734 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
1735 | |
|
1736 | 0 | return 0; |
1737 | 0 | } |
1738 | | |
1739 | | bool zapi_nhg_notify_decode(struct stream *s, uint32_t *id, |
1740 | | enum zapi_nhg_notify_owner *note) |
1741 | 0 | { |
1742 | 0 | uint32_t read_id; |
1743 | |
|
1744 | 0 | STREAM_GET(note, s, sizeof(*note)); |
1745 | 0 | STREAM_GETL(s, read_id); |
1746 | | |
1747 | 0 | *id = read_id; |
1748 | |
|
1749 | 0 | return true; |
1750 | | |
1751 | 0 | stream_failure: |
1752 | 0 | return false; |
1753 | 0 | } |
1754 | | |
1755 | | bool zapi_route_notify_decode(struct stream *s, struct prefix *p, |
1756 | | uint32_t *tableid, |
1757 | | enum zapi_route_notify_owner *note, |
1758 | | afi_t *afi, safi_t *safi) |
1759 | 0 | { |
1760 | 0 | uint32_t t; |
1761 | 0 | afi_t afi_val; |
1762 | 0 | safi_t safi_val; |
1763 | |
|
1764 | 0 | STREAM_GET(note, s, sizeof(*note)); |
1765 | | |
1766 | 0 | STREAM_GETC(s, p->family); |
1767 | 0 | STREAM_GETC(s, p->prefixlen); |
1768 | 0 | STREAM_GET(&p->u.prefix, s, prefix_blen(p)); |
1769 | 0 | STREAM_GETL(s, t); |
1770 | 0 | STREAM_GETC(s, afi_val); |
1771 | 0 | STREAM_GETC(s, safi_val); |
1772 | | |
1773 | 0 | *tableid = t; |
1774 | |
|
1775 | 0 | if (afi) |
1776 | 0 | *afi = afi_val; |
1777 | 0 | if (safi) |
1778 | 0 | *safi = safi_val; |
1779 | |
|
1780 | 0 | return true; |
1781 | | |
1782 | 0 | stream_failure: |
1783 | 0 | return false; |
1784 | 0 | } |
1785 | | |
1786 | | bool zapi_rule_notify_decode(struct stream *s, uint32_t *seqno, |
1787 | | uint32_t *priority, uint32_t *unique, char *ifname, |
1788 | | enum zapi_rule_notify_owner *note) |
1789 | 0 | { |
1790 | 0 | uint32_t prio, seq, uni; |
1791 | |
|
1792 | 0 | STREAM_GET(note, s, sizeof(*note)); |
1793 | | |
1794 | 0 | STREAM_GETL(s, seq); |
1795 | 0 | STREAM_GETL(s, prio); |
1796 | 0 | STREAM_GETL(s, uni); |
1797 | 0 | STREAM_GET(ifname, s, INTERFACE_NAMSIZ); |
1798 | | |
1799 | 0 | if (zclient_debug) |
1800 | 0 | zlog_debug("%s: %u %u %u %s", __func__, seq, prio, uni, ifname); |
1801 | 0 | *seqno = seq; |
1802 | 0 | *priority = prio; |
1803 | 0 | *unique = uni; |
1804 | |
|
1805 | 0 | return true; |
1806 | | |
1807 | 0 | stream_failure: |
1808 | 0 | return false; |
1809 | 0 | } |
1810 | | |
1811 | | bool zapi_ipset_notify_decode(struct stream *s, uint32_t *unique, |
1812 | | enum zapi_ipset_notify_owner *note) |
1813 | 0 | { |
1814 | 0 | uint32_t uni; |
1815 | 0 | uint16_t notew; |
1816 | |
|
1817 | 0 | STREAM_GETW(s, notew); |
1818 | | |
1819 | 0 | STREAM_GETL(s, uni); |
1820 | | |
1821 | 0 | if (zclient_debug) |
1822 | 0 | zlog_debug("%s: %u", __func__, uni); |
1823 | 0 | *unique = uni; |
1824 | 0 | *note = (enum zapi_ipset_notify_owner)notew; |
1825 | 0 | return true; |
1826 | | |
1827 | 0 | stream_failure: |
1828 | 0 | return false; |
1829 | 0 | } |
1830 | | |
1831 | | bool zapi_ipset_entry_notify_decode(struct stream *s, uint32_t *unique, |
1832 | | char *ipset_name, |
1833 | | enum zapi_ipset_entry_notify_owner *note) |
1834 | 0 | { |
1835 | 0 | uint32_t uni; |
1836 | 0 | uint16_t notew; |
1837 | |
|
1838 | 0 | STREAM_GETW(s, notew); |
1839 | | |
1840 | 0 | STREAM_GETL(s, uni); |
1841 | | |
1842 | 0 | STREAM_GET(ipset_name, s, ZEBRA_IPSET_NAME_SIZE); |
1843 | | |
1844 | 0 | if (zclient_debug) |
1845 | 0 | zlog_debug("%s: %u", __func__, uni); |
1846 | 0 | *unique = uni; |
1847 | 0 | *note = (enum zapi_ipset_entry_notify_owner)notew; |
1848 | |
|
1849 | 0 | return true; |
1850 | | |
1851 | 0 | stream_failure: |
1852 | 0 | return false; |
1853 | 0 | } |
1854 | | |
1855 | | bool zapi_iptable_notify_decode(struct stream *s, |
1856 | | uint32_t *unique, |
1857 | | enum zapi_iptable_notify_owner *note) |
1858 | 0 | { |
1859 | 0 | uint32_t uni; |
1860 | 0 | uint16_t notew; |
1861 | |
|
1862 | 0 | STREAM_GETW(s, notew); |
1863 | | |
1864 | 0 | STREAM_GETL(s, uni); |
1865 | | |
1866 | 0 | if (zclient_debug) |
1867 | 0 | zlog_debug("%s: %u", __func__, uni); |
1868 | 0 | *unique = uni; |
1869 | 0 | *note = (enum zapi_iptable_notify_owner)notew; |
1870 | |
|
1871 | 0 | return true; |
1872 | | |
1873 | 0 | stream_failure: |
1874 | 0 | return false; |
1875 | 0 | } |
1876 | | |
1877 | | struct nexthop *nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh) |
1878 | 0 | { |
1879 | 0 | struct nexthop *n = nexthop_new(); |
1880 | |
|
1881 | 0 | n->type = znh->type; |
1882 | 0 | n->vrf_id = znh->vrf_id; |
1883 | 0 | n->ifindex = znh->ifindex; |
1884 | 0 | n->gate = znh->gate; |
1885 | 0 | n->srte_color = znh->srte_color; |
1886 | | |
1887 | | /* |
1888 | | * This function currently handles labels |
1889 | | */ |
1890 | 0 | if (znh->label_num) { |
1891 | 0 | nexthop_add_labels(n, ZEBRA_LSP_NONE, znh->label_num, |
1892 | 0 | znh->labels); |
1893 | 0 | } |
1894 | |
|
1895 | 0 | if (CHECK_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) { |
1896 | 0 | SET_FLAG(n->flags, NEXTHOP_FLAG_HAS_BACKUP); |
1897 | 0 | n->backup_num = znh->backup_num; |
1898 | 0 | memcpy(n->backup_idx, znh->backup_idx, n->backup_num); |
1899 | 0 | } |
1900 | |
|
1901 | 0 | if (znh->seg6local_action != ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) |
1902 | 0 | nexthop_add_srv6_seg6local(n, znh->seg6local_action, |
1903 | 0 | &znh->seg6local_ctx); |
1904 | |
|
1905 | 0 | if (!sid_zero(&znh->seg6_segs)) |
1906 | 0 | nexthop_add_srv6_seg6(n, &znh->seg6_segs); |
1907 | |
|
1908 | 0 | return n; |
1909 | 0 | } |
1910 | | |
1911 | | /* |
1912 | | * Convert nexthop to zapi nexthop |
1913 | | */ |
1914 | | int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh, |
1915 | | const struct nexthop *nh) |
1916 | 0 | { |
1917 | 0 | int i; |
1918 | |
|
1919 | 0 | memset(znh, 0, sizeof(*znh)); |
1920 | |
|
1921 | 0 | znh->type = nh->type; |
1922 | 0 | znh->vrf_id = nh->vrf_id; |
1923 | 0 | znh->weight = nh->weight; |
1924 | 0 | znh->ifindex = nh->ifindex; |
1925 | 0 | znh->gate = nh->gate; |
1926 | |
|
1927 | 0 | if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ONLINK)) |
1928 | 0 | SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_ONLINK); |
1929 | |
|
1930 | 0 | if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_EVPN)) |
1931 | 0 | SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_EVPN); |
1932 | |
|
1933 | 0 | if (nh->nh_label && (nh->nh_label->num_labels > 0)) { |
1934 | | |
1935 | | /* Validate */ |
1936 | 0 | if (nh->nh_label->num_labels > MPLS_MAX_LABELS) |
1937 | 0 | return -1; |
1938 | | |
1939 | 0 | for (i = 0; i < nh->nh_label->num_labels; i++) |
1940 | 0 | znh->labels[i] = nh->nh_label->label[i]; |
1941 | |
|
1942 | 0 | znh->label_num = i; |
1943 | 0 | znh->label_type = nh->nh_label_type; |
1944 | 0 | SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_LABEL); |
1945 | 0 | } |
1946 | | |
1947 | 0 | if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_HAS_BACKUP)) { |
1948 | 0 | if (nh->backup_num > NEXTHOP_MAX_BACKUPS) |
1949 | 0 | return -1; |
1950 | | |
1951 | 0 | SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP); |
1952 | 0 | znh->backup_num = nh->backup_num; |
1953 | 0 | memcpy(znh->backup_idx, nh->backup_idx, znh->backup_num); |
1954 | 0 | } |
1955 | | |
1956 | 0 | if (nh->nh_srv6) { |
1957 | 0 | if (nh->nh_srv6->seg6local_action != |
1958 | 0 | ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) { |
1959 | 0 | SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_SEG6LOCAL); |
1960 | 0 | znh->seg6local_action = nh->nh_srv6->seg6local_action; |
1961 | 0 | memcpy(&znh->seg6local_ctx, |
1962 | 0 | &nh->nh_srv6->seg6local_ctx, |
1963 | 0 | sizeof(struct seg6local_context)); |
1964 | 0 | } |
1965 | |
|
1966 | 0 | if (!sid_zero(&nh->nh_srv6->seg6_segs)) { |
1967 | 0 | SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_SEG6); |
1968 | 0 | memcpy(&znh->seg6_segs, &nh->nh_srv6->seg6_segs, |
1969 | 0 | sizeof(struct in6_addr)); |
1970 | 0 | } |
1971 | 0 | } |
1972 | |
|
1973 | 0 | return 0; |
1974 | 0 | } |
1975 | | |
1976 | | /* |
1977 | | * Wrapper that converts backup nexthop |
1978 | | */ |
1979 | | int zapi_backup_nexthop_from_nexthop(struct zapi_nexthop *znh, |
1980 | | const struct nexthop *nh) |
1981 | 0 | { |
1982 | 0 | int ret; |
1983 | | |
1984 | | /* Ensure that zapi flags are correct: backups don't have backups */ |
1985 | 0 | ret = zapi_nexthop_from_nexthop(znh, nh); |
1986 | 0 | if (ret == 0) |
1987 | 0 | UNSET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP); |
1988 | |
|
1989 | 0 | return ret; |
1990 | 0 | } |
1991 | | |
1992 | | /* |
1993 | | * Format some info about a zapi nexthop, for debug or logging. |
1994 | | */ |
1995 | | const char *zapi_nexthop2str(const struct zapi_nexthop *znh, char *buf, |
1996 | | int bufsize) |
1997 | 0 | { |
1998 | 0 | char tmp[INET6_ADDRSTRLEN]; |
1999 | |
|
2000 | 0 | switch (znh->type) { |
2001 | 0 | case NEXTHOP_TYPE_IFINDEX: |
2002 | 0 | snprintf(buf, bufsize, "if %u", znh->ifindex); |
2003 | 0 | break; |
2004 | 0 | case NEXTHOP_TYPE_IPV4: |
2005 | 0 | case NEXTHOP_TYPE_IPV4_IFINDEX: |
2006 | 0 | inet_ntop(AF_INET, &znh->gate.ipv4, tmp, sizeof(tmp)); |
2007 | 0 | snprintf(buf, bufsize, "%s if %u", tmp, znh->ifindex); |
2008 | 0 | break; |
2009 | 0 | case NEXTHOP_TYPE_IPV6: |
2010 | 0 | case NEXTHOP_TYPE_IPV6_IFINDEX: |
2011 | 0 | inet_ntop(AF_INET6, &znh->gate.ipv6, tmp, sizeof(tmp)); |
2012 | 0 | snprintf(buf, bufsize, "%s if %u", tmp, znh->ifindex); |
2013 | 0 | break; |
2014 | 0 | case NEXTHOP_TYPE_BLACKHOLE: |
2015 | 0 | snprintf(buf, bufsize, "blackhole"); |
2016 | 0 | break; |
2017 | 0 | default: |
2018 | 0 | snprintf(buf, bufsize, "unknown"); |
2019 | 0 | break; |
2020 | 0 | } |
2021 | | |
2022 | 0 | return buf; |
2023 | 0 | } |
2024 | | |
2025 | | /* |
2026 | | * Decode the nexthop-tracking update message |
2027 | | */ |
2028 | | bool zapi_nexthop_update_decode(struct stream *s, struct prefix *match, |
2029 | | struct zapi_route *nhr) |
2030 | 0 | { |
2031 | 0 | uint32_t i; |
2032 | |
|
2033 | 0 | memset(nhr, 0, sizeof(*nhr)); |
2034 | |
|
2035 | 0 | STREAM_GETL(s, nhr->message); |
2036 | 0 | STREAM_GETW(s, nhr->safi); |
2037 | 0 | STREAM_GETW(s, match->family); |
2038 | 0 | STREAM_GETC(s, match->prefixlen); |
2039 | | /* |
2040 | | * What we got told to match against |
2041 | | */ |
2042 | 0 | switch (match->family) { |
2043 | 0 | case AF_INET: |
2044 | 0 | STREAM_GET(&match->u.prefix4.s_addr, s, IPV4_MAX_BYTELEN); |
2045 | 0 | break; |
2046 | 0 | case AF_INET6: |
2047 | 0 | STREAM_GET(&match->u.prefix6, s, IPV6_MAX_BYTELEN); |
2048 | 0 | break; |
2049 | 0 | } |
2050 | | /* |
2051 | | * What we matched against |
2052 | | */ |
2053 | 0 | STREAM_GETW(s, nhr->prefix.family); |
2054 | 0 | STREAM_GETC(s, nhr->prefix.prefixlen); |
2055 | 0 | switch (nhr->prefix.family) { |
2056 | 0 | case AF_INET: |
2057 | 0 | STREAM_GET(&nhr->prefix.u.prefix4.s_addr, s, IPV4_MAX_BYTELEN); |
2058 | 0 | break; |
2059 | 0 | case AF_INET6: |
2060 | 0 | STREAM_GET(&nhr->prefix.u.prefix6, s, IPV6_MAX_BYTELEN); |
2061 | 0 | break; |
2062 | 0 | default: |
2063 | 0 | break; |
2064 | 0 | } |
2065 | 0 | if (CHECK_FLAG(nhr->message, ZAPI_MESSAGE_SRTE)) |
2066 | 0 | STREAM_GETL(s, nhr->srte_color); |
2067 | | |
2068 | 0 | STREAM_GETC(s, nhr->type); |
2069 | 0 | STREAM_GETW(s, nhr->instance); |
2070 | 0 | STREAM_GETC(s, nhr->distance); |
2071 | 0 | STREAM_GETL(s, nhr->metric); |
2072 | 0 | STREAM_GETC(s, nhr->nexthop_num); |
2073 | | |
2074 | 0 | for (i = 0; i < nhr->nexthop_num; i++) { |
2075 | 0 | if (zapi_nexthop_decode(s, &(nhr->nexthops[i]), 0, 0) != 0) |
2076 | 0 | return false; |
2077 | 0 | } |
2078 | | |
2079 | 0 | return true; |
2080 | 0 | stream_failure: |
2081 | 0 | return false; |
2082 | 0 | } |
2083 | | |
2084 | | bool zapi_error_decode(struct stream *s, enum zebra_error_types *error) |
2085 | 0 | { |
2086 | 0 | memset(error, 0, sizeof(*error)); |
2087 | |
|
2088 | 0 | STREAM_GET(error, s, sizeof(*error)); |
2089 | | |
2090 | 0 | if (zclient_debug) |
2091 | 0 | zlog_debug("%s: type: %s", __func__, |
2092 | 0 | zebra_error_type2str(*error)); |
2093 | |
|
2094 | 0 | return true; |
2095 | 0 | stream_failure: |
2096 | 0 | return false; |
2097 | 0 | } |
2098 | | |
2099 | | /* |
2100 | | * send a ZEBRA_REDISTRIBUTE_ADD or ZEBRA_REDISTRIBUTE_DELETE |
2101 | | * for the route type (ZEBRA_ROUTE_KERNEL etc.). The zebra server will |
2102 | | * then set/unset redist[type] in the client handle (a struct zserv) for the |
2103 | | * sending client |
2104 | | */ |
2105 | | enum zclient_send_status |
2106 | | zebra_redistribute_send(int command, struct zclient *zclient, afi_t afi, |
2107 | | int type, unsigned short instance, vrf_id_t vrf_id) |
2108 | 0 | { |
2109 | 0 | struct stream *s; |
2110 | |
|
2111 | 0 | s = zclient->obuf; |
2112 | 0 | stream_reset(s); |
2113 | |
|
2114 | 0 | zclient_create_header(s, command, vrf_id); |
2115 | 0 | stream_putc(s, afi); |
2116 | 0 | stream_putc(s, type); |
2117 | 0 | stream_putw(s, instance); |
2118 | |
|
2119 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
2120 | |
|
2121 | 0 | return zclient_send_message(zclient); |
2122 | 0 | } |
2123 | | |
2124 | | enum zclient_send_status |
2125 | | zebra_redistribute_default_send(int command, struct zclient *zclient, afi_t afi, |
2126 | | vrf_id_t vrf_id) |
2127 | 0 | { |
2128 | 0 | struct stream *s; |
2129 | |
|
2130 | 0 | s = zclient->obuf; |
2131 | 0 | stream_reset(s); |
2132 | |
|
2133 | 0 | zclient_create_header(s, command, vrf_id); |
2134 | 0 | stream_putc(s, afi); |
2135 | |
|
2136 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
2137 | |
|
2138 | 0 | return zclient_send_message(zclient); |
2139 | 0 | } |
2140 | | |
2141 | | /* Send route notify request to zebra */ |
2142 | | int zebra_route_notify_send(int command, struct zclient *zclient, bool set) |
2143 | 0 | { |
2144 | 0 | struct stream *s; |
2145 | |
|
2146 | 0 | s = zclient->obuf; |
2147 | 0 | stream_reset(s); |
2148 | |
|
2149 | 0 | zclient_create_header(s, command, 0); |
2150 | 0 | stream_putc(s, !!set); |
2151 | |
|
2152 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
2153 | |
|
2154 | 0 | return zclient_send_message(zclient); |
2155 | 0 | } |
2156 | | |
2157 | | /* Get prefix in ZServ format; family should be filled in on prefix */ |
2158 | | static int zclient_stream_get_prefix(struct stream *s, struct prefix *p) |
2159 | 0 | { |
2160 | 0 | size_t plen = prefix_blen(p); |
2161 | 0 | uint8_t c; |
2162 | 0 | p->prefixlen = 0; |
2163 | |
|
2164 | 0 | if (plen == 0) |
2165 | 0 | return -1; |
2166 | | |
2167 | 0 | STREAM_GET(&p->u.prefix, s, plen); |
2168 | 0 | STREAM_GETC(s, c); |
2169 | 0 | p->prefixlen = MIN(plen * 8, c); |
2170 | |
|
2171 | 0 | return 0; |
2172 | 0 | stream_failure: |
2173 | 0 | return -1; |
2174 | 0 | } |
2175 | | |
2176 | | /* Router-id update from zebra daemon. */ |
2177 | | int zebra_router_id_update_read(struct stream *s, struct prefix *rid) |
2178 | 0 | { |
2179 | | /* Fetch interface address. */ |
2180 | 0 | STREAM_GETC(s, rid->family); |
2181 | | |
2182 | 0 | return zclient_stream_get_prefix(s, rid); |
2183 | | |
2184 | 0 | stream_failure: |
2185 | 0 | return -1; |
2186 | 0 | } |
2187 | | |
2188 | | /* Interface addition from zebra daemon. */ |
2189 | | /* |
2190 | | * The format of the message sent with type ZEBRA_INTERFACE_ADD or |
2191 | | * ZEBRA_INTERFACE_DELETE from zebra to the client is: |
2192 | | * 0 1 2 3 |
2193 | | * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 |
2194 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
2195 | | * | ifname | |
2196 | | * | | |
2197 | | * | | |
2198 | | * | | |
2199 | | * | | |
2200 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
2201 | | * | ifindex | |
2202 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
2203 | | * | status | |
2204 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
2205 | | * | if_flags | |
2206 | | * | | |
2207 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
2208 | | * | metric | |
2209 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
2210 | | * | speed | |
2211 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
2212 | | * | ifmtu | |
2213 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
2214 | | * | ifmtu6 | |
2215 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
2216 | | * | bandwidth | |
2217 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
2218 | | * | parent ifindex | |
2219 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
2220 | | * | Link Layer Type | |
2221 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
2222 | | * | Harware Address Length | |
2223 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
2224 | | * | Hardware Address if HW length different from 0 | |
2225 | | * | ... max INTERFACE_HWADDR_MAX | |
2226 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
2227 | | * | Link_params? | Whether a link-params follows: 1 or 0. |
2228 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
2229 | | * | Link_params 0 or 1 INTERFACE_LINK_PARAMS_SIZE sized | |
2230 | | * | .... (struct if_link_params). | |
2231 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
2232 | | */ |
2233 | | |
2234 | | static int zclient_vrf_add(ZAPI_CALLBACK_ARGS) |
2235 | 0 | { |
2236 | 0 | struct vrf *vrf; |
2237 | 0 | char vrfname_tmp[VRF_NAMSIZ + 1] = {}; |
2238 | 0 | struct vrf_data data; |
2239 | |
|
2240 | 0 | STREAM_GET(&data, zclient->ibuf, sizeof(struct vrf_data)); |
2241 | | /* Read interface name. */ |
2242 | 0 | STREAM_GET(vrfname_tmp, zclient->ibuf, VRF_NAMSIZ); |
2243 | | |
2244 | 0 | if (strlen(vrfname_tmp) == 0) |
2245 | 0 | goto stream_failure; |
2246 | | |
2247 | | /* Lookup/create vrf by name, then vrf_id. */ |
2248 | 0 | vrf = vrf_get(vrf_id, vrfname_tmp); |
2249 | | |
2250 | | /* If there's already a VRF with this name, don't create vrf */ |
2251 | 0 | if (!vrf) |
2252 | 0 | return 0; |
2253 | | |
2254 | 0 | vrf->data.l.table_id = data.l.table_id; |
2255 | 0 | memcpy(vrf->data.l.netns_name, data.l.netns_name, NS_NAMSIZ); |
2256 | 0 | vrf_enable(vrf); |
2257 | |
|
2258 | 0 | return 0; |
2259 | 0 | stream_failure: |
2260 | 0 | return -1; |
2261 | 0 | } |
2262 | | |
2263 | | static int zclient_vrf_delete(ZAPI_CALLBACK_ARGS) |
2264 | 0 | { |
2265 | 0 | struct vrf *vrf; |
2266 | | |
2267 | | /* Lookup vrf by vrf_id. */ |
2268 | 0 | vrf = vrf_lookup_by_id(vrf_id); |
2269 | | |
2270 | | /* |
2271 | | * If a routing protocol doesn't know about a |
2272 | | * vrf that is about to be deleted. There is |
2273 | | * no point in attempting to delete it. |
2274 | | */ |
2275 | 0 | if (!vrf) |
2276 | 0 | return 0; |
2277 | | |
2278 | 0 | vrf_delete(vrf); |
2279 | 0 | return 0; |
2280 | 0 | } |
2281 | | |
2282 | | static int zclient_interface_add(ZAPI_CALLBACK_ARGS) |
2283 | 0 | { |
2284 | 0 | struct interface *ifp; |
2285 | 0 | char ifname_tmp[INTERFACE_NAMSIZ + 1] = {}; |
2286 | 0 | struct stream *s = zclient->ibuf; |
2287 | 0 | struct vrf *vrf; |
2288 | | |
2289 | | /* Read interface name. */ |
2290 | 0 | STREAM_GET(ifname_tmp, s, INTERFACE_NAMSIZ); |
2291 | | |
2292 | | /* Lookup/create interface by name. */ |
2293 | 0 | vrf = vrf_lookup_by_id(vrf_id); |
2294 | 0 | if (!vrf) { |
2295 | 0 | zlog_debug( |
2296 | 0 | "Rx'd interface add from Zebra, but VRF %u does not exist", |
2297 | 0 | vrf_id); |
2298 | 0 | return -1; |
2299 | 0 | } |
2300 | | |
2301 | 0 | ifp = if_get_by_name(ifname_tmp, vrf_id, vrf->name); |
2302 | |
|
2303 | 0 | zebra_interface_if_set_value(s, ifp); |
2304 | |
|
2305 | 0 | if_new_via_zapi(ifp); |
2306 | |
|
2307 | 0 | return 0; |
2308 | 0 | stream_failure: |
2309 | 0 | return -1; |
2310 | 0 | } |
2311 | | |
2312 | | /* |
2313 | | * Read interface up/down msg (ZEBRA_INTERFACE_UP/ZEBRA_INTERFACE_DOWN) |
2314 | | * from zebra server. The format of this message is the same as |
2315 | | * that sent for ZEBRA_INTERFACE_ADD/ZEBRA_INTERFACE_DELETE, |
2316 | | * except that no sockaddr_dl is sent at the tail of the message. |
2317 | | */ |
2318 | | struct interface *zebra_interface_state_read(struct stream *s, vrf_id_t vrf_id) |
2319 | 0 | { |
2320 | 0 | struct interface *ifp; |
2321 | 0 | char ifname_tmp[INTERFACE_NAMSIZ + 1] = {}; |
2322 | | |
2323 | | /* Read interface name. */ |
2324 | 0 | STREAM_GET(ifname_tmp, s, INTERFACE_NAMSIZ); |
2325 | | |
2326 | | /* Lookup this by interface index. */ |
2327 | 0 | ifp = if_lookup_by_name(ifname_tmp, vrf_id); |
2328 | 0 | if (ifp == NULL) { |
2329 | 0 | flog_err(EC_LIB_ZAPI_ENCODE, |
2330 | 0 | "INTERFACE_STATE: Cannot find IF %s in VRF %d", |
2331 | 0 | ifname_tmp, vrf_id); |
2332 | 0 | return NULL; |
2333 | 0 | } |
2334 | | |
2335 | 0 | zebra_interface_if_set_value(s, ifp); |
2336 | |
|
2337 | 0 | return ifp; |
2338 | 0 | stream_failure: |
2339 | 0 | return NULL; |
2340 | 0 | } |
2341 | | |
2342 | | static int zclient_interface_delete(ZAPI_CALLBACK_ARGS) |
2343 | 0 | { |
2344 | 0 | struct interface *ifp; |
2345 | 0 | struct stream *s = zclient->ibuf; |
2346 | |
|
2347 | 0 | ifp = zebra_interface_state_read(s, vrf_id); |
2348 | |
|
2349 | 0 | if (ifp == NULL) |
2350 | 0 | return 0; |
2351 | | |
2352 | 0 | if_destroy_via_zapi(ifp); |
2353 | 0 | return 0; |
2354 | 0 | } |
2355 | | |
2356 | | static int zclient_interface_up(ZAPI_CALLBACK_ARGS) |
2357 | 0 | { |
2358 | 0 | struct interface *ifp; |
2359 | 0 | struct stream *s = zclient->ibuf; |
2360 | |
|
2361 | 0 | ifp = zebra_interface_state_read(s, vrf_id); |
2362 | |
|
2363 | 0 | if (!ifp) |
2364 | 0 | return 0; |
2365 | | |
2366 | 0 | if_up_via_zapi(ifp); |
2367 | 0 | return 0; |
2368 | 0 | } |
2369 | | |
2370 | | static int zclient_interface_down(ZAPI_CALLBACK_ARGS) |
2371 | 0 | { |
2372 | 0 | struct interface *ifp; |
2373 | 0 | struct stream *s = zclient->ibuf; |
2374 | |
|
2375 | 0 | ifp = zebra_interface_state_read(s, vrf_id); |
2376 | |
|
2377 | 0 | if (!ifp) |
2378 | 0 | return 0; |
2379 | | |
2380 | 0 | if_down_via_zapi(ifp); |
2381 | 0 | return 0; |
2382 | 0 | } |
2383 | | |
2384 | | static int zclient_handle_error(ZAPI_CALLBACK_ARGS) |
2385 | 0 | { |
2386 | 0 | enum zebra_error_types error; |
2387 | 0 | struct stream *s = zclient->ibuf; |
2388 | |
|
2389 | 0 | zapi_error_decode(s, &error); |
2390 | |
|
2391 | 0 | if (zclient->handle_error) |
2392 | 0 | (*zclient->handle_error)(error); |
2393 | 0 | return 0; |
2394 | 0 | } |
2395 | | |
2396 | | static int link_params_set_value(struct stream *s, struct interface *ifp) |
2397 | 0 | { |
2398 | 0 | uint8_t link_params_enabled, nb_ext_adm_grp; |
2399 | 0 | struct if_link_params *iflp; |
2400 | 0 | uint32_t bwclassnum, bitmap_data; |
2401 | |
|
2402 | 0 | iflp = if_link_params_get(ifp); |
2403 | |
|
2404 | 0 | if (iflp == NULL) |
2405 | 0 | iflp = if_link_params_init(ifp); |
2406 | |
|
2407 | 0 | STREAM_GETC(s, link_params_enabled); |
2408 | 0 | if (!link_params_enabled) { |
2409 | 0 | if_link_params_free(ifp); |
2410 | 0 | return 0; |
2411 | 0 | } |
2412 | | |
2413 | 0 | STREAM_GETL(s, iflp->lp_status); |
2414 | 0 | STREAM_GETL(s, iflp->te_metric); |
2415 | 0 | STREAM_GETF(s, iflp->max_bw); |
2416 | 0 | STREAM_GETF(s, iflp->max_rsv_bw); |
2417 | 0 | STREAM_GETL(s, bwclassnum); |
2418 | 0 | { |
2419 | 0 | unsigned int i; |
2420 | 0 | for (i = 0; i < bwclassnum && i < MAX_CLASS_TYPE; i++) |
2421 | 0 | STREAM_GETF(s, iflp->unrsv_bw[i]); |
2422 | 0 | if (i < bwclassnum) |
2423 | 0 | flog_err( |
2424 | 0 | EC_LIB_ZAPI_MISSMATCH, |
2425 | 0 | "%s: received %d > %d (MAX_CLASS_TYPE) bw entries - outdated library?", |
2426 | 0 | __func__, bwclassnum, MAX_CLASS_TYPE); |
2427 | 0 | } |
2428 | 0 | STREAM_GETL(s, iflp->admin_grp); |
2429 | | |
2430 | | /* Extended Administrative Group */ |
2431 | 0 | admin_group_clear(&iflp->ext_admin_grp); |
2432 | 0 | STREAM_GETC(s, nb_ext_adm_grp); |
2433 | 0 | for (size_t i = 0; i < nb_ext_adm_grp; i++) { |
2434 | 0 | STREAM_GETL(s, bitmap_data); |
2435 | 0 | admin_group_bulk_set(&iflp->ext_admin_grp, bitmap_data, i); |
2436 | 0 | } |
2437 | | |
2438 | 0 | STREAM_GETL(s, iflp->rmt_as); |
2439 | 0 | iflp->rmt_ip.s_addr = stream_get_ipv4(s); |
2440 | |
|
2441 | 0 | STREAM_GETL(s, iflp->av_delay); |
2442 | 0 | STREAM_GETL(s, iflp->min_delay); |
2443 | 0 | STREAM_GETL(s, iflp->max_delay); |
2444 | 0 | STREAM_GETL(s, iflp->delay_var); |
2445 | | |
2446 | 0 | STREAM_GETF(s, iflp->pkt_loss); |
2447 | 0 | STREAM_GETF(s, iflp->res_bw); |
2448 | 0 | STREAM_GETF(s, iflp->ava_bw); |
2449 | 0 | STREAM_GETF(s, iflp->use_bw); |
2450 | | |
2451 | 0 | return 0; |
2452 | 0 | stream_failure: |
2453 | 0 | return -1; |
2454 | 0 | } |
2455 | | |
2456 | | struct interface *zebra_interface_link_params_read(struct stream *s, |
2457 | | vrf_id_t vrf_id, |
2458 | | bool *changed) |
2459 | 0 | { |
2460 | 0 | struct if_link_params *iflp; |
2461 | 0 | struct if_link_params iflp_prev = {0}; |
2462 | 0 | ifindex_t ifindex; |
2463 | 0 | bool iflp_prev_set = false; |
2464 | |
|
2465 | 0 | STREAM_GETL(s, ifindex); |
2466 | | |
2467 | 0 | struct interface *ifp = if_lookup_by_index(ifindex, vrf_id); |
2468 | |
|
2469 | 0 | if (ifp == NULL) { |
2470 | 0 | flog_err(EC_LIB_ZAPI_ENCODE, |
2471 | 0 | "%s: unknown ifindex %u, shouldn't happen", __func__, |
2472 | 0 | ifindex); |
2473 | 0 | return NULL; |
2474 | 0 | } |
2475 | | |
2476 | 0 | iflp = if_link_params_get(ifp); |
2477 | |
|
2478 | 0 | if (iflp) { |
2479 | 0 | iflp_prev_set = true; |
2480 | 0 | admin_group_init(&iflp_prev.ext_admin_grp); |
2481 | 0 | if_link_params_copy(&iflp_prev, iflp); |
2482 | 0 | } |
2483 | | |
2484 | | /* read the link_params from stream |
2485 | | * Free ifp->link_params if the stream has no params |
2486 | | * to means that link-params are not enabled on links. |
2487 | | */ |
2488 | 0 | if (link_params_set_value(s, ifp) != 0) |
2489 | 0 | goto stream_failure; |
2490 | | |
2491 | 0 | if (changed != NULL) { |
2492 | 0 | iflp = if_link_params_get(ifp); |
2493 | |
|
2494 | 0 | if (iflp_prev_set && iflp) { |
2495 | 0 | if (if_link_params_cmp(&iflp_prev, iflp)) |
2496 | 0 | *changed = false; |
2497 | 0 | else |
2498 | 0 | *changed = true; |
2499 | 0 | } else if (!iflp_prev_set && !iflp) |
2500 | 0 | *changed = false; |
2501 | 0 | else |
2502 | 0 | *changed = true; |
2503 | 0 | } |
2504 | |
|
2505 | 0 | if (iflp_prev_set) |
2506 | 0 | admin_group_term(&iflp_prev.ext_admin_grp); |
2507 | |
|
2508 | 0 | return ifp; |
2509 | | |
2510 | 0 | stream_failure: |
2511 | 0 | if (iflp_prev_set) |
2512 | 0 | admin_group_term(&iflp_prev.ext_admin_grp); |
2513 | 0 | return NULL; |
2514 | 0 | } |
2515 | | |
2516 | | static void zebra_interface_if_set_value(struct stream *s, |
2517 | | struct interface *ifp) |
2518 | 0 | { |
2519 | 0 | uint8_t link_params_status = 0; |
2520 | 0 | ifindex_t old_ifindex, new_ifindex; |
2521 | |
|
2522 | 0 | old_ifindex = ifp->oldifindex; |
2523 | | /* Read interface's index. */ |
2524 | 0 | STREAM_GETL(s, new_ifindex); |
2525 | 0 | if_set_index(ifp, new_ifindex); |
2526 | 0 | STREAM_GETC(s, ifp->status); |
2527 | | |
2528 | | /* Read interface's value. */ |
2529 | 0 | STREAM_GETQ(s, ifp->flags); |
2530 | 0 | STREAM_GETC(s, ifp->ptm_enable); |
2531 | 0 | STREAM_GETC(s, ifp->ptm_status); |
2532 | 0 | STREAM_GETL(s, ifp->metric); |
2533 | 0 | STREAM_GETL(s, ifp->speed); |
2534 | 0 | STREAM_GETL(s, ifp->mtu); |
2535 | 0 | STREAM_GETL(s, ifp->mtu6); |
2536 | 0 | STREAM_GETL(s, ifp->bandwidth); |
2537 | 0 | STREAM_GETL(s, ifp->link_ifindex); |
2538 | 0 | STREAM_GETL(s, ifp->ll_type); |
2539 | 0 | STREAM_GETL(s, ifp->hw_addr_len); |
2540 | 0 | if (ifp->hw_addr_len) |
2541 | 0 | STREAM_GET(ifp->hw_addr, s, |
2542 | 0 | MIN(ifp->hw_addr_len, INTERFACE_HWADDR_MAX)); |
2543 | | |
2544 | | /* Read Traffic Engineering status */ |
2545 | 0 | link_params_status = stream_getc(s); |
2546 | | /* Then, Traffic Engineering parameters if any */ |
2547 | 0 | if (link_params_status) |
2548 | 0 | link_params_set_value(s, ifp); |
2549 | |
|
2550 | 0 | nexthop_group_interface_state_change(ifp, old_ifindex); |
2551 | |
|
2552 | 0 | return; |
2553 | 0 | stream_failure: |
2554 | 0 | zlog_err("Could not parse interface values; aborting"); |
2555 | 0 | assert(!"Failed to parse interface values"); |
2556 | 0 | } |
2557 | | |
2558 | | size_t zebra_interface_link_params_write(struct stream *s, |
2559 | | struct interface *ifp) |
2560 | 0 | { |
2561 | 0 | size_t w, nb_ext_adm_grp; |
2562 | 0 | struct if_link_params *iflp; |
2563 | 0 | int i; |
2564 | | |
2565 | |
|
2566 | 0 | if (s == NULL || ifp == NULL) |
2567 | 0 | return 0; |
2568 | | |
2569 | 0 | iflp = ifp->link_params; |
2570 | 0 | w = 0; |
2571 | | |
2572 | | /* encode if link_params is enabled */ |
2573 | 0 | if (iflp) { |
2574 | 0 | w += stream_putc(s, true); |
2575 | 0 | } else { |
2576 | 0 | w += stream_putc(s, false); |
2577 | 0 | return w; |
2578 | 0 | } |
2579 | | |
2580 | 0 | w += stream_putl(s, iflp->lp_status); |
2581 | |
|
2582 | 0 | w += stream_putl(s, iflp->te_metric); |
2583 | 0 | w += stream_putf(s, iflp->max_bw); |
2584 | 0 | w += stream_putf(s, iflp->max_rsv_bw); |
2585 | |
|
2586 | 0 | w += stream_putl(s, MAX_CLASS_TYPE); |
2587 | 0 | for (i = 0; i < MAX_CLASS_TYPE; i++) |
2588 | 0 | w += stream_putf(s, iflp->unrsv_bw[i]); |
2589 | |
|
2590 | 0 | w += stream_putl(s, iflp->admin_grp); |
2591 | | |
2592 | | /* Extended Administrative Group */ |
2593 | 0 | nb_ext_adm_grp = admin_group_nb_words(&iflp->ext_admin_grp); |
2594 | 0 | w += stream_putc(s, nb_ext_adm_grp); |
2595 | 0 | for (size_t i = 0; i < nb_ext_adm_grp; i++) |
2596 | 0 | stream_putl(s, admin_group_get_offset(&iflp->ext_admin_grp, i)); |
2597 | |
|
2598 | 0 | w += stream_putl(s, iflp->rmt_as); |
2599 | 0 | w += stream_put_in_addr(s, &iflp->rmt_ip); |
2600 | |
|
2601 | 0 | w += stream_putl(s, iflp->av_delay); |
2602 | 0 | w += stream_putl(s, iflp->min_delay); |
2603 | 0 | w += stream_putl(s, iflp->max_delay); |
2604 | 0 | w += stream_putl(s, iflp->delay_var); |
2605 | |
|
2606 | 0 | w += stream_putf(s, iflp->pkt_loss); |
2607 | 0 | w += stream_putf(s, iflp->res_bw); |
2608 | 0 | w += stream_putf(s, iflp->ava_bw); |
2609 | 0 | w += stream_putf(s, iflp->use_bw); |
2610 | |
|
2611 | 0 | return w; |
2612 | 0 | } |
2613 | | |
2614 | | /* |
2615 | | * format of message for address addition is: |
2616 | | * 0 |
2617 | | * 0 1 2 3 4 5 6 7 |
2618 | | * +-+-+-+-+-+-+-+-+ |
2619 | | * | type | ZEBRA_INTERFACE_ADDRESS_ADD or |
2620 | | * +-+-+-+-+-+-+-+-+ ZEBRA_INTERFACE_ADDRES_DELETE |
2621 | | * | | |
2622 | | * + + |
2623 | | * | ifindex | |
2624 | | * + + |
2625 | | * | | |
2626 | | * + + |
2627 | | * | | |
2628 | | * +-+-+-+-+-+-+-+-+ |
2629 | | * | ifc_flags | flags for connected address |
2630 | | * +-+-+-+-+-+-+-+-+ |
2631 | | * | addr_family | |
2632 | | * +-+-+-+-+-+-+-+-+ |
2633 | | * | addr... | |
2634 | | * : : |
2635 | | * | | |
2636 | | * +-+-+-+-+-+-+-+-+ |
2637 | | * | addr_len | len of addr. E.g., addr_len = 4 for ipv4 addrs. |
2638 | | * +-+-+-+-+-+-+-+-+ |
2639 | | * | daddr.. | |
2640 | | * : : |
2641 | | * | | |
2642 | | * +-+-+-+-+-+-+-+-+ |
2643 | | */ |
2644 | | |
2645 | | static int memconstant(const void *s, int c, size_t n) |
2646 | 0 | { |
2647 | 0 | const uint8_t *p = s; |
2648 | |
|
2649 | 0 | while (n-- > 0) |
2650 | 0 | if (*p++ != c) |
2651 | 0 | return 0; |
2652 | 0 | return 1; |
2653 | 0 | } |
2654 | | |
2655 | | |
2656 | | struct connected *zebra_interface_address_read(int type, struct stream *s, |
2657 | | vrf_id_t vrf_id) |
2658 | 0 | { |
2659 | 0 | ifindex_t ifindex; |
2660 | 0 | struct interface *ifp; |
2661 | 0 | struct connected *ifc; |
2662 | 0 | struct prefix p, d, *dp; |
2663 | 0 | int plen; |
2664 | 0 | uint8_t ifc_flags; |
2665 | |
|
2666 | 0 | memset(&p, 0, sizeof(p)); |
2667 | 0 | memset(&d, 0, sizeof(d)); |
2668 | | |
2669 | | /* Get interface index. */ |
2670 | 0 | STREAM_GETL(s, ifindex); |
2671 | | |
2672 | | /* Lookup index. */ |
2673 | 0 | ifp = if_lookup_by_index(ifindex, vrf_id); |
2674 | 0 | if (ifp == NULL) { |
2675 | 0 | flog_err(EC_LIB_ZAPI_ENCODE, |
2676 | 0 | "INTERFACE_ADDRESS_%s: Cannot find IF %u in VRF %d", |
2677 | 0 | (type == ZEBRA_INTERFACE_ADDRESS_ADD) ? "ADD" : "DEL", |
2678 | 0 | ifindex, vrf_id); |
2679 | 0 | return NULL; |
2680 | 0 | } |
2681 | | |
2682 | | /* Fetch flag. */ |
2683 | 0 | STREAM_GETC(s, ifc_flags); |
2684 | | |
2685 | | /* Fetch interface address. */ |
2686 | 0 | STREAM_GETC(s, d.family); |
2687 | 0 | p.family = d.family; |
2688 | 0 | plen = prefix_blen(&d); |
2689 | |
|
2690 | 0 | if (zclient_stream_get_prefix(s, &p) != 0) |
2691 | 0 | goto stream_failure; |
2692 | | |
2693 | | /* Fetch destination address. */ |
2694 | 0 | STREAM_GET(&d.u.prefix, s, plen); |
2695 | | |
2696 | | /* N.B. NULL destination pointers are encoded as all zeroes */ |
2697 | 0 | dp = memconstant(&d.u.prefix, 0, plen) ? NULL : &d; |
2698 | |
|
2699 | 0 | if (type == ZEBRA_INTERFACE_ADDRESS_ADD) { |
2700 | 0 | ifc = connected_lookup_prefix_exact(ifp, &p); |
2701 | 0 | if (!ifc) { |
2702 | | /* N.B. NULL destination pointers are encoded as all |
2703 | | * zeroes */ |
2704 | 0 | ifc = connected_add_by_prefix(ifp, &p, dp); |
2705 | 0 | } |
2706 | 0 | if (ifc) { |
2707 | 0 | ifc->flags = ifc_flags; |
2708 | 0 | if (ifc->destination) |
2709 | 0 | ifc->destination->prefixlen = |
2710 | 0 | ifc->address->prefixlen; |
2711 | 0 | else if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER)) { |
2712 | | /* carp interfaces on OpenBSD with 0.0.0.0/0 as |
2713 | | * "peer" */ |
2714 | 0 | flog_err( |
2715 | 0 | EC_LIB_ZAPI_ENCODE, |
2716 | 0 | "interface %s address %pFX with peer flag set, but no peer address!", |
2717 | 0 | ifp->name, ifc->address); |
2718 | 0 | UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER); |
2719 | 0 | } |
2720 | 0 | } |
2721 | 0 | } else { |
2722 | 0 | assert(type == ZEBRA_INTERFACE_ADDRESS_DELETE); |
2723 | 0 | ifc = connected_delete_by_prefix(ifp, &p); |
2724 | 0 | } |
2725 | |
|
2726 | 0 | return ifc; |
2727 | | |
2728 | 0 | stream_failure: |
2729 | 0 | return NULL; |
2730 | 0 | } |
2731 | | |
2732 | | /* |
2733 | | * format of message for neighbor connected address is: |
2734 | | * 0 |
2735 | | * 0 1 2 3 4 5 6 7 |
2736 | | * +-+-+-+-+-+-+-+-+ |
2737 | | * | type | ZEBRA_INTERFACE_NBR_ADDRESS_ADD or |
2738 | | * +-+-+-+-+-+-+-+-+ ZEBRA_INTERFACE_NBR_ADDRES_DELETE |
2739 | | * | | |
2740 | | * + + |
2741 | | * | ifindex | |
2742 | | * + + |
2743 | | * | | |
2744 | | * + + |
2745 | | * | | |
2746 | | * +-+-+-+-+-+-+-+-+ |
2747 | | * | addr_family | |
2748 | | * +-+-+-+-+-+-+-+-+ |
2749 | | * | addr... | |
2750 | | * : : |
2751 | | * | | |
2752 | | * +-+-+-+-+-+-+-+-+ |
2753 | | * | addr_len | len of addr. |
2754 | | * +-+-+-+-+-+-+-+-+ |
2755 | | */ |
2756 | | struct nbr_connected * |
2757 | | zebra_interface_nbr_address_read(int type, struct stream *s, vrf_id_t vrf_id) |
2758 | 0 | { |
2759 | 0 | unsigned int ifindex; |
2760 | 0 | struct interface *ifp; |
2761 | 0 | struct prefix p; |
2762 | 0 | struct nbr_connected *ifc; |
2763 | | |
2764 | | /* Get interface index. */ |
2765 | 0 | STREAM_GETL(s, ifindex); |
2766 | | |
2767 | | /* Lookup index. */ |
2768 | 0 | ifp = if_lookup_by_index(ifindex, vrf_id); |
2769 | 0 | if (ifp == NULL) { |
2770 | 0 | flog_err(EC_LIB_ZAPI_ENCODE, |
2771 | 0 | "INTERFACE_NBR_%s: Cannot find IF %u in VRF %d", |
2772 | 0 | (type == ZEBRA_INTERFACE_NBR_ADDRESS_ADD) ? "ADD" |
2773 | 0 | : "DELETE", |
2774 | 0 | ifindex, vrf_id); |
2775 | 0 | return NULL; |
2776 | 0 | } |
2777 | | |
2778 | 0 | STREAM_GETC(s, p.family); |
2779 | 0 | STREAM_GET(&p.u.prefix, s, prefix_blen(&p)); |
2780 | 0 | STREAM_GETC(s, p.prefixlen); |
2781 | | |
2782 | 0 | if (type == ZEBRA_INTERFACE_NBR_ADDRESS_ADD) { |
2783 | | /* Currently only supporting P2P links, so any new RA source |
2784 | | address is |
2785 | | considered as the replacement of the previously learnt |
2786 | | Link-Local address. */ |
2787 | 0 | if (!(ifc = listnode_head(ifp->nbr_connected))) { |
2788 | 0 | ifc = nbr_connected_new(); |
2789 | 0 | ifc->address = prefix_new(); |
2790 | 0 | ifc->ifp = ifp; |
2791 | 0 | listnode_add(ifp->nbr_connected, ifc); |
2792 | 0 | } |
2793 | |
|
2794 | 0 | prefix_copy(ifc->address, &p); |
2795 | 0 | } else { |
2796 | 0 | assert(type == ZEBRA_INTERFACE_NBR_ADDRESS_DELETE); |
2797 | |
|
2798 | 0 | ifc = nbr_connected_check(ifp, &p); |
2799 | 0 | if (ifc) |
2800 | 0 | listnode_delete(ifp->nbr_connected, ifc); |
2801 | 0 | } |
2802 | |
|
2803 | 0 | return ifc; |
2804 | | |
2805 | 0 | stream_failure: |
2806 | 0 | return NULL; |
2807 | 0 | } |
2808 | | |
2809 | | struct interface *zebra_interface_vrf_update_read(struct stream *s, |
2810 | | vrf_id_t vrf_id, |
2811 | | vrf_id_t *new_vrf_id) |
2812 | 0 | { |
2813 | 0 | char ifname[INTERFACE_NAMSIZ + 1] = {}; |
2814 | 0 | struct interface *ifp; |
2815 | 0 | vrf_id_t new_id; |
2816 | | |
2817 | | /* Read interface name. */ |
2818 | 0 | STREAM_GET(ifname, s, INTERFACE_NAMSIZ); |
2819 | | |
2820 | | /* Lookup interface. */ |
2821 | 0 | ifp = if_lookup_by_name(ifname, vrf_id); |
2822 | 0 | if (ifp == NULL) { |
2823 | 0 | flog_err(EC_LIB_ZAPI_ENCODE, |
2824 | 0 | "INTERFACE_VRF_UPDATE: Cannot find IF %s in VRF %d", |
2825 | 0 | ifname, vrf_id); |
2826 | 0 | return NULL; |
2827 | 0 | } |
2828 | | |
2829 | | /* Fetch new VRF Id. */ |
2830 | 0 | STREAM_GETL(s, new_id); |
2831 | | |
2832 | 0 | *new_vrf_id = new_id; |
2833 | 0 | return ifp; |
2834 | | |
2835 | 0 | stream_failure: |
2836 | 0 | return NULL; |
2837 | 0 | } |
2838 | | |
2839 | | /* filter unwanted messages until the expected one arrives */ |
2840 | | static int zclient_read_sync_response(struct zclient *zclient, |
2841 | | uint16_t expected_cmd) |
2842 | 0 | { |
2843 | 0 | struct stream *s; |
2844 | 0 | uint16_t size = -1; |
2845 | 0 | uint8_t marker; |
2846 | 0 | uint8_t version; |
2847 | 0 | vrf_id_t vrf_id; |
2848 | 0 | uint16_t cmd; |
2849 | 0 | fd_set readfds; |
2850 | 0 | int ret; |
2851 | |
|
2852 | 0 | ret = 0; |
2853 | 0 | cmd = expected_cmd + 1; |
2854 | 0 | while (ret == 0 && cmd != expected_cmd) { |
2855 | 0 | s = zclient->ibuf; |
2856 | 0 | stream_reset(s); |
2857 | | |
2858 | | /* wait until response arrives */ |
2859 | 0 | FD_ZERO(&readfds); |
2860 | 0 | FD_SET(zclient->sock, &readfds); |
2861 | 0 | select(zclient->sock + 1, &readfds, NULL, NULL, NULL); |
2862 | 0 | if (!FD_ISSET(zclient->sock, &readfds)) |
2863 | 0 | continue; |
2864 | | /* read response */ |
2865 | 0 | ret = zclient_read_header(s, zclient->sock, &size, &marker, |
2866 | 0 | &version, &vrf_id, &cmd); |
2867 | 0 | if (zclient_debug) |
2868 | 0 | zlog_debug("%s: Response (%d bytes) received", __func__, |
2869 | 0 | size); |
2870 | 0 | } |
2871 | 0 | if (ret != 0) { |
2872 | 0 | flog_err(EC_LIB_ZAPI_ENCODE, "%s: Invalid Sync Message Reply", |
2873 | 0 | __func__); |
2874 | 0 | return -1; |
2875 | 0 | } |
2876 | | |
2877 | 0 | return 0; |
2878 | 0 | } |
2879 | | /** |
2880 | | * Connect to label manager in a synchronous way |
2881 | | * |
2882 | | * It first writes the request to zclient output buffer and then |
2883 | | * immediately reads the answer from the input buffer. |
2884 | | * |
2885 | | * @param zclient Zclient used to connect to label manager (zebra) |
2886 | | * @param async Synchronous (0) or asynchronous (1) operation |
2887 | | * @result Result of response |
2888 | | */ |
2889 | | int lm_label_manager_connect(struct zclient *zclient, int async) |
2890 | 0 | { |
2891 | 0 | int ret; |
2892 | 0 | struct stream *s; |
2893 | 0 | uint8_t result; |
2894 | 0 | uint16_t cmd = async ? ZEBRA_LABEL_MANAGER_CONNECT_ASYNC : |
2895 | 0 | ZEBRA_LABEL_MANAGER_CONNECT; |
2896 | |
|
2897 | 0 | if (zclient_debug) |
2898 | 0 | zlog_debug("Connecting to Label Manager (LM)"); |
2899 | |
|
2900 | 0 | if (zclient->sock < 0) { |
2901 | 0 | zlog_debug("%s: invalid zclient socket", __func__); |
2902 | 0 | return -1; |
2903 | 0 | } |
2904 | | |
2905 | | /* send request */ |
2906 | 0 | s = zclient->obuf; |
2907 | 0 | stream_reset(s); |
2908 | 0 | zclient_create_header(s, cmd, VRF_DEFAULT); |
2909 | | |
2910 | | /* proto */ |
2911 | 0 | stream_putc(s, zclient->redist_default); |
2912 | | /* instance */ |
2913 | 0 | stream_putw(s, zclient->instance); |
2914 | | |
2915 | | /* Put length at the first point of the stream. */ |
2916 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
2917 | |
|
2918 | 0 | ret = writen(zclient->sock, s->data, stream_get_endp(s)); |
2919 | 0 | if (ret < 0) { |
2920 | 0 | flog_err(EC_LIB_ZAPI_SOCKET, "Can't write to zclient sock"); |
2921 | 0 | close(zclient->sock); |
2922 | 0 | zclient->sock = -1; |
2923 | 0 | return -1; |
2924 | 0 | } |
2925 | 0 | if (ret == 0) { |
2926 | 0 | flog_err(EC_LIB_ZAPI_SOCKET, "Zclient sock closed"); |
2927 | 0 | close(zclient->sock); |
2928 | 0 | zclient->sock = -1; |
2929 | 0 | return -1; |
2930 | 0 | } |
2931 | 0 | if (zclient_debug) |
2932 | 0 | zlog_debug("LM connect request sent (%d bytes)", ret); |
2933 | |
|
2934 | 0 | if (async) |
2935 | 0 | return 0; |
2936 | | |
2937 | | /* read response */ |
2938 | 0 | if (zclient_read_sync_response(zclient, cmd) |
2939 | 0 | != 0) |
2940 | 0 | return -1; |
2941 | | |
2942 | 0 | s = zclient->ibuf; |
2943 | | |
2944 | | /* read instance and proto */ |
2945 | 0 | uint8_t proto; |
2946 | 0 | uint16_t instance; |
2947 | |
|
2948 | 0 | STREAM_GETC(s, proto); |
2949 | 0 | STREAM_GETW(s, instance); |
2950 | | |
2951 | | /* sanity */ |
2952 | 0 | if (proto != zclient->redist_default) |
2953 | 0 | flog_err( |
2954 | 0 | EC_LIB_ZAPI_ENCODE, |
2955 | 0 | "Wrong proto (%u) in LM connect response. Should be %u", |
2956 | 0 | proto, zclient->redist_default); |
2957 | 0 | if (instance != zclient->instance) |
2958 | 0 | flog_err( |
2959 | 0 | EC_LIB_ZAPI_ENCODE, |
2960 | 0 | "Wrong instId (%u) in LM connect response. Should be %u", |
2961 | 0 | instance, zclient->instance); |
2962 | | |
2963 | | /* result code */ |
2964 | 0 | STREAM_GETC(s, result); |
2965 | 0 | if (zclient_debug) |
2966 | 0 | zlog_debug("LM connect-response received, result %u", result); |
2967 | |
|
2968 | 0 | return (int)result; |
2969 | | |
2970 | 0 | stream_failure: |
2971 | 0 | return -1; |
2972 | 0 | } |
2973 | | |
2974 | | /** |
2975 | | * Function to request a srv6-locator chunk in an asynchronous way |
2976 | | * |
2977 | | * @param zclient Zclient used to connect to table manager (zebra) |
2978 | | * @param locator_name Name of SRv6-locator |
2979 | | * @result 0 on success, -1 otherwise |
2980 | | */ |
2981 | | int srv6_manager_get_locator_chunk(struct zclient *zclient, |
2982 | | const char *locator_name) |
2983 | 0 | { |
2984 | 0 | struct stream *s; |
2985 | 0 | const size_t len = strlen(locator_name); |
2986 | |
|
2987 | 0 | if (zclient_debug) |
2988 | 0 | zlog_debug("Getting SRv6-Locator Chunk %s", locator_name); |
2989 | |
|
2990 | 0 | if (zclient->sock < 0) |
2991 | 0 | return -1; |
2992 | | |
2993 | | /* send request */ |
2994 | 0 | s = zclient->obuf; |
2995 | 0 | stream_reset(s); |
2996 | 0 | zclient_create_header(s, ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK, |
2997 | 0 | VRF_DEFAULT); |
2998 | | |
2999 | | /* locator_name */ |
3000 | 0 | stream_putw(s, len); |
3001 | 0 | stream_put(s, locator_name, len); |
3002 | | |
3003 | | /* Put length at the first point of the stream. */ |
3004 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
3005 | |
|
3006 | 0 | return zclient_send_message(zclient); |
3007 | 0 | } |
3008 | | |
3009 | | /** |
3010 | | * Function to release a srv6-locator chunk |
3011 | | * |
3012 | | * @param zclient Zclient used to connect to table manager (zebra) |
3013 | | * @param locator_name Name of SRv6-locator |
3014 | | * @result 0 on success, -1 otherwise |
3015 | | */ |
3016 | | int srv6_manager_release_locator_chunk(struct zclient *zclient, |
3017 | | const char *locator_name) |
3018 | 0 | { |
3019 | 0 | struct stream *s; |
3020 | 0 | const size_t len = strlen(locator_name); |
3021 | |
|
3022 | 0 | if (zclient_debug) |
3023 | 0 | zlog_debug("Releasing SRv6-Locator Chunk %s", locator_name); |
3024 | |
|
3025 | 0 | if (zclient->sock < 0) |
3026 | 0 | return -1; |
3027 | | |
3028 | | /* send request */ |
3029 | 0 | s = zclient->obuf; |
3030 | 0 | stream_reset(s); |
3031 | 0 | zclient_create_header(s, ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK, |
3032 | 0 | VRF_DEFAULT); |
3033 | | |
3034 | | /* locator_name */ |
3035 | 0 | stream_putw(s, len); |
3036 | 0 | stream_put(s, locator_name, len); |
3037 | | |
3038 | | /* Put length at the first point of the stream. */ |
3039 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
3040 | |
|
3041 | 0 | return zclient_send_message(zclient); |
3042 | 0 | } |
3043 | | |
3044 | | /* |
3045 | | * Asynchronous label chunk request |
3046 | | * |
3047 | | * @param zclient Zclient used to connect to label manager (zebra) |
3048 | | * @param keep Avoid garbage collection |
3049 | | * @param chunk_size Amount of labels requested |
3050 | | * @param base Base for the label chunk. if MPLS_LABEL_BASE_ANY we do not care |
3051 | | * @result 0 on success, -1 otherwise |
3052 | | */ |
3053 | | enum zclient_send_status zclient_send_get_label_chunk(struct zclient *zclient, |
3054 | | uint8_t keep, |
3055 | | uint32_t chunk_size, |
3056 | | uint32_t base) |
3057 | 0 | { |
3058 | 0 | struct stream *s; |
3059 | |
|
3060 | 0 | if (zclient_debug) |
3061 | 0 | zlog_debug("Getting Label Chunk"); |
3062 | |
|
3063 | 0 | if (zclient->sock < 0) |
3064 | 0 | return ZCLIENT_SEND_FAILURE; |
3065 | | |
3066 | 0 | s = zclient->obuf; |
3067 | 0 | stream_reset(s); |
3068 | |
|
3069 | 0 | zclient_create_header(s, ZEBRA_GET_LABEL_CHUNK, VRF_DEFAULT); |
3070 | | /* proto */ |
3071 | 0 | stream_putc(s, zclient->redist_default); |
3072 | | /* instance */ |
3073 | 0 | stream_putw(s, zclient->instance); |
3074 | 0 | stream_putc(s, keep); |
3075 | 0 | stream_putl(s, chunk_size); |
3076 | 0 | stream_putl(s, base); |
3077 | | |
3078 | | /* Put length at the first point of the stream. */ |
3079 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
3080 | |
|
3081 | 0 | return zclient_send_message(zclient); |
3082 | 0 | } |
3083 | | |
3084 | | /** |
3085 | | * Function to request a label chunk in a synchronous way |
3086 | | * |
3087 | | * It first writes the request to zclient output buffer and then |
3088 | | * immediately reads the answer from the input buffer. |
3089 | | * |
3090 | | * @param zclient Zclient used to connect to label manager (zebra) |
3091 | | * @param keep Avoid garbage collection |
3092 | | * @param chunk_size Amount of labels requested |
3093 | | * @param start To write first assigned chunk label to |
3094 | | * @param end To write last assigned chunk label to |
3095 | | * @result 0 on success, -1 otherwise |
3096 | | */ |
3097 | | int lm_get_label_chunk(struct zclient *zclient, uint8_t keep, uint32_t base, |
3098 | | uint32_t chunk_size, uint32_t *start, uint32_t *end) |
3099 | 0 | { |
3100 | 0 | int ret; |
3101 | 0 | struct stream *s; |
3102 | 0 | uint8_t response_keep; |
3103 | |
|
3104 | 0 | if (zclient_debug) |
3105 | 0 | zlog_debug("Getting Label Chunk"); |
3106 | |
|
3107 | 0 | if (zclient->sock < 0) |
3108 | 0 | return -1; |
3109 | | |
3110 | | /* send request */ |
3111 | 0 | s = zclient->obuf; |
3112 | 0 | stream_reset(s); |
3113 | 0 | zclient_create_header(s, ZEBRA_GET_LABEL_CHUNK, VRF_DEFAULT); |
3114 | | /* proto */ |
3115 | 0 | stream_putc(s, zclient->redist_default); |
3116 | | /* instance */ |
3117 | 0 | stream_putw(s, zclient->instance); |
3118 | | /* keep */ |
3119 | 0 | stream_putc(s, keep); |
3120 | | /* chunk size */ |
3121 | 0 | stream_putl(s, chunk_size); |
3122 | | /* requested chunk base */ |
3123 | 0 | stream_putl(s, base); |
3124 | | /* Put length at the first point of the stream. */ |
3125 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
3126 | |
|
3127 | 0 | ret = writen(zclient->sock, s->data, stream_get_endp(s)); |
3128 | 0 | if (ret < 0) { |
3129 | 0 | flog_err(EC_LIB_ZAPI_SOCKET, "Can't write to zclient sock"); |
3130 | 0 | close(zclient->sock); |
3131 | 0 | zclient->sock = -1; |
3132 | 0 | return -1; |
3133 | 0 | } |
3134 | 0 | if (ret == 0) { |
3135 | 0 | flog_err(EC_LIB_ZAPI_SOCKET, "Zclient sock closed"); |
3136 | 0 | close(zclient->sock); |
3137 | 0 | zclient->sock = -1; |
3138 | 0 | return -1; |
3139 | 0 | } |
3140 | 0 | if (zclient_debug) |
3141 | 0 | zlog_debug("Label chunk request (%d bytes) sent", ret); |
3142 | | |
3143 | | /* read response */ |
3144 | 0 | if (zclient_read_sync_response(zclient, ZEBRA_GET_LABEL_CHUNK) != 0) |
3145 | 0 | return -1; |
3146 | | |
3147 | | /* parse response */ |
3148 | 0 | s = zclient->ibuf; |
3149 | | |
3150 | | /* read proto and instance */ |
3151 | 0 | uint8_t proto; |
3152 | 0 | uint8_t instance; |
3153 | |
|
3154 | 0 | STREAM_GETC(s, proto); |
3155 | 0 | STREAM_GETW(s, instance); |
3156 | | |
3157 | | /* sanities */ |
3158 | 0 | if (proto != zclient->redist_default) |
3159 | 0 | flog_err(EC_LIB_ZAPI_ENCODE, |
3160 | 0 | "Wrong proto (%u) in get chunk response. Should be %u", |
3161 | 0 | proto, zclient->redist_default); |
3162 | 0 | if (instance != zclient->instance) |
3163 | 0 | flog_err(EC_LIB_ZAPI_ENCODE, |
3164 | 0 | "Wrong instId (%u) in get chunk response Should be %u", |
3165 | 0 | instance, zclient->instance); |
3166 | | |
3167 | | /* if we requested a specific chunk and it could not be allocated, the |
3168 | | * response message will end here |
3169 | | */ |
3170 | 0 | if (!STREAM_READABLE(s)) { |
3171 | 0 | zlog_info("Unable to assign Label Chunk to %s instance %u", |
3172 | 0 | zebra_route_string(proto), instance); |
3173 | 0 | return -1; |
3174 | 0 | } |
3175 | | |
3176 | | /* keep */ |
3177 | 0 | STREAM_GETC(s, response_keep); |
3178 | | /* start and end labels */ |
3179 | 0 | STREAM_GETL(s, *start); |
3180 | 0 | STREAM_GETL(s, *end); |
3181 | | |
3182 | | /* not owning this response */ |
3183 | 0 | if (keep != response_keep) { |
3184 | 0 | flog_err( |
3185 | 0 | EC_LIB_ZAPI_ENCODE, |
3186 | 0 | "Invalid Label chunk: %u - %u, keeps mismatch %u != %u", |
3187 | 0 | *start, *end, keep, response_keep); |
3188 | 0 | } |
3189 | | /* sanity */ |
3190 | 0 | if (*start > *end || *start < MPLS_LABEL_UNRESERVED_MIN |
3191 | 0 | || *end > MPLS_LABEL_UNRESERVED_MAX) { |
3192 | 0 | flog_err(EC_LIB_ZAPI_ENCODE, "Invalid Label chunk: %u - %u", |
3193 | 0 | *start, *end); |
3194 | 0 | return -1; |
3195 | 0 | } |
3196 | | |
3197 | 0 | if (zclient_debug) |
3198 | 0 | zlog_debug("Label Chunk assign: %u - %u (%u)", *start, *end, |
3199 | 0 | response_keep); |
3200 | |
|
3201 | 0 | return 0; |
3202 | | |
3203 | 0 | stream_failure: |
3204 | 0 | return -1; |
3205 | 0 | } |
3206 | | |
3207 | | /** |
3208 | | * Function to release a label chunk |
3209 | | * |
3210 | | * @param zclient Zclient used to connect to label manager (zebra) |
3211 | | * @param start First label of chunk |
3212 | | * @param end Last label of chunk |
3213 | | * @result 0 on success, -1 otherwise |
3214 | | */ |
3215 | | int lm_release_label_chunk(struct zclient *zclient, uint32_t start, |
3216 | | uint32_t end) |
3217 | 0 | { |
3218 | 0 | int ret; |
3219 | 0 | struct stream *s; |
3220 | |
|
3221 | 0 | if (zclient_debug) |
3222 | 0 | zlog_debug("Releasing Label Chunk %u - %u", start, end); |
3223 | |
|
3224 | 0 | if (zclient->sock < 0) |
3225 | 0 | return -1; |
3226 | | |
3227 | | /* send request */ |
3228 | 0 | s = zclient->obuf; |
3229 | 0 | stream_reset(s); |
3230 | 0 | zclient_create_header(s, ZEBRA_RELEASE_LABEL_CHUNK, VRF_DEFAULT); |
3231 | | |
3232 | | /* proto */ |
3233 | 0 | stream_putc(s, zclient->redist_default); |
3234 | | /* instance */ |
3235 | 0 | stream_putw(s, zclient->instance); |
3236 | | /* start */ |
3237 | 0 | stream_putl(s, start); |
3238 | | /* end */ |
3239 | 0 | stream_putl(s, end); |
3240 | | |
3241 | | /* Put length at the first point of the stream. */ |
3242 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
3243 | |
|
3244 | 0 | ret = writen(zclient->sock, s->data, stream_get_endp(s)); |
3245 | 0 | if (ret < 0) { |
3246 | 0 | flog_err(EC_LIB_ZAPI_SOCKET, "Can't write to zclient sock"); |
3247 | 0 | close(zclient->sock); |
3248 | 0 | zclient->sock = -1; |
3249 | 0 | return -1; |
3250 | 0 | } |
3251 | 0 | if (ret == 0) { |
3252 | 0 | flog_err(EC_LIB_ZAPI_SOCKET, "Zclient sock connection closed"); |
3253 | 0 | close(zclient->sock); |
3254 | 0 | zclient->sock = -1; |
3255 | 0 | return -1; |
3256 | 0 | } |
3257 | | |
3258 | 0 | return 0; |
3259 | 0 | } |
3260 | | |
3261 | | /** |
3262 | | * Connect to table manager in a synchronous way |
3263 | | * |
3264 | | * It first writes the request to zclient output buffer and then |
3265 | | * immediately reads the answer from the input buffer. |
3266 | | * |
3267 | | * @param zclient Zclient used to connect to table manager (zebra) |
3268 | | * @result Result of response |
3269 | | */ |
3270 | | int tm_table_manager_connect(struct zclient *zclient) |
3271 | 0 | { |
3272 | 0 | int ret; |
3273 | 0 | struct stream *s; |
3274 | 0 | uint8_t result; |
3275 | |
|
3276 | 0 | if (zclient_debug) |
3277 | 0 | zlog_debug("Connecting to Table Manager"); |
3278 | |
|
3279 | 0 | if (zclient->sock < 0) |
3280 | 0 | return ZCLIENT_SEND_FAILURE; |
3281 | | |
3282 | | /* send request */ |
3283 | 0 | s = zclient->obuf; |
3284 | 0 | stream_reset(s); |
3285 | 0 | zclient_create_header(s, ZEBRA_TABLE_MANAGER_CONNECT, VRF_DEFAULT); |
3286 | | |
3287 | | /* proto */ |
3288 | 0 | stream_putc(s, zclient->redist_default); |
3289 | | /* instance */ |
3290 | 0 | stream_putw(s, zclient->instance); |
3291 | | |
3292 | | /* Put length at the first point of the stream. */ |
3293 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
3294 | |
|
3295 | 0 | ret = zclient_send_message(zclient); |
3296 | 0 | if (ret == ZCLIENT_SEND_FAILURE) |
3297 | 0 | return -1; |
3298 | | |
3299 | 0 | if (zclient_debug) |
3300 | 0 | zlog_debug("%s: Table manager connect request sent", __func__); |
3301 | | |
3302 | | /* read response */ |
3303 | 0 | if (zclient_read_sync_response(zclient, ZEBRA_TABLE_MANAGER_CONNECT) |
3304 | 0 | != 0) |
3305 | 0 | return -1; |
3306 | | |
3307 | | /* result */ |
3308 | 0 | s = zclient->ibuf; |
3309 | 0 | STREAM_GETC(s, result); |
3310 | 0 | if (zclient_debug) |
3311 | 0 | zlog_debug( |
3312 | 0 | "%s: Table Manager connect response received, result %u", |
3313 | 0 | __func__, result); |
3314 | |
|
3315 | 0 | return (int)result; |
3316 | 0 | stream_failure: |
3317 | 0 | return -1; |
3318 | 0 | } |
3319 | | |
3320 | | /** |
3321 | | * Function to request a table chunk in a synchronous way |
3322 | | * |
3323 | | * It first writes the request to zclient output buffer and then |
3324 | | * immediately reads the answer from the input buffer. |
3325 | | * |
3326 | | * @param zclient Zclient used to connect to table manager (zebra) |
3327 | | * @param chunk_size Amount of table requested |
3328 | | * @param start to write first assigned chunk table RT ID to |
3329 | | * @param end To write last assigned chunk table RT ID to |
3330 | | * @result 0 on success, -1 otherwise |
3331 | | */ |
3332 | | int tm_get_table_chunk(struct zclient *zclient, uint32_t chunk_size, |
3333 | | uint32_t *start, uint32_t *end) |
3334 | 0 | { |
3335 | 0 | int ret; |
3336 | 0 | struct stream *s; |
3337 | |
|
3338 | 0 | if (zclient_debug) |
3339 | 0 | zlog_debug("Getting Table Chunk"); |
3340 | |
|
3341 | 0 | if (zclient->sock < 0) |
3342 | 0 | return -1; |
3343 | | |
3344 | | /* send request */ |
3345 | 0 | s = zclient->obuf; |
3346 | 0 | stream_reset(s); |
3347 | 0 | zclient_create_header(s, ZEBRA_GET_TABLE_CHUNK, VRF_DEFAULT); |
3348 | | /* chunk size */ |
3349 | 0 | stream_putl(s, chunk_size); |
3350 | | /* Put length at the first point of the stream. */ |
3351 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
3352 | |
|
3353 | 0 | ret = writen(zclient->sock, s->data, stream_get_endp(s)); |
3354 | 0 | if (ret < 0) { |
3355 | 0 | flog_err(EC_LIB_ZAPI_SOCKET, "%s: can't write to zclient->sock", |
3356 | 0 | __func__); |
3357 | 0 | close(zclient->sock); |
3358 | 0 | zclient->sock = -1; |
3359 | 0 | return -1; |
3360 | 0 | } |
3361 | 0 | if (ret == 0) { |
3362 | 0 | flog_err(EC_LIB_ZAPI_SOCKET, |
3363 | 0 | "%s: zclient->sock connection closed", __func__); |
3364 | 0 | close(zclient->sock); |
3365 | 0 | zclient->sock = -1; |
3366 | 0 | return -1; |
3367 | 0 | } |
3368 | 0 | if (zclient_debug) |
3369 | 0 | zlog_debug("%s: Table chunk request (%d bytes) sent", __func__, |
3370 | 0 | ret); |
3371 | | |
3372 | | /* read response */ |
3373 | 0 | if (zclient_read_sync_response(zclient, ZEBRA_GET_TABLE_CHUNK) != 0) |
3374 | 0 | return -1; |
3375 | | |
3376 | 0 | s = zclient->ibuf; |
3377 | | /* start and end table IDs */ |
3378 | 0 | STREAM_GETL(s, *start); |
3379 | 0 | STREAM_GETL(s, *end); |
3380 | | |
3381 | 0 | if (zclient_debug) |
3382 | 0 | zlog_debug("Table Chunk assign: %u - %u ", *start, *end); |
3383 | |
|
3384 | 0 | return 0; |
3385 | 0 | stream_failure: |
3386 | 0 | return -1; |
3387 | 0 | } |
3388 | | |
3389 | | /** |
3390 | | * Function to release a table chunk |
3391 | | * |
3392 | | * @param zclient Zclient used to connect to table manager (zebra) |
3393 | | * @param start First label of table |
3394 | | * @param end Last label of chunk |
3395 | | * @result 0 on success, -1 otherwise |
3396 | | */ |
3397 | | int tm_release_table_chunk(struct zclient *zclient, uint32_t start, |
3398 | | uint32_t end) |
3399 | 0 | { |
3400 | 0 | struct stream *s; |
3401 | |
|
3402 | 0 | if (zclient_debug) |
3403 | 0 | zlog_debug("Releasing Table Chunk"); |
3404 | |
|
3405 | 0 | if (zclient->sock < 0) |
3406 | 0 | return -1; |
3407 | | |
3408 | | /* send request */ |
3409 | 0 | s = zclient->obuf; |
3410 | 0 | stream_reset(s); |
3411 | 0 | zclient_create_header(s, ZEBRA_RELEASE_TABLE_CHUNK, VRF_DEFAULT); |
3412 | | |
3413 | | /* start */ |
3414 | 0 | stream_putl(s, start); |
3415 | | /* end */ |
3416 | 0 | stream_putl(s, end); |
3417 | | |
3418 | | /* Put length at the first point of the stream. */ |
3419 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
3420 | |
|
3421 | 0 | if (zclient_send_message(zclient) == ZCLIENT_SEND_FAILURE) |
3422 | 0 | return -1; |
3423 | | |
3424 | 0 | return 0; |
3425 | 0 | } |
3426 | | |
3427 | | enum zclient_send_status zebra_send_sr_policy(struct zclient *zclient, int cmd, |
3428 | | struct zapi_sr_policy *zp) |
3429 | 0 | { |
3430 | 0 | if (zapi_sr_policy_encode(zclient->obuf, cmd, zp) < 0) |
3431 | 0 | return ZCLIENT_SEND_FAILURE; |
3432 | 0 | return zclient_send_message(zclient); |
3433 | 0 | } |
3434 | | |
3435 | | int zapi_sr_policy_encode(struct stream *s, int cmd, struct zapi_sr_policy *zp) |
3436 | 0 | { |
3437 | 0 | struct zapi_srte_tunnel *zt = &zp->segment_list; |
3438 | |
|
3439 | 0 | stream_reset(s); |
3440 | |
|
3441 | 0 | zclient_create_header(s, cmd, VRF_DEFAULT); |
3442 | 0 | stream_putl(s, zp->color); |
3443 | 0 | stream_put_ipaddr(s, &zp->endpoint); |
3444 | 0 | stream_write(s, &zp->name, SRTE_POLICY_NAME_MAX_LENGTH); |
3445 | |
|
3446 | 0 | stream_putc(s, zt->type); |
3447 | 0 | stream_putl(s, zt->local_label); |
3448 | |
|
3449 | 0 | if (zt->label_num > MPLS_MAX_LABELS) { |
3450 | 0 | flog_err(EC_LIB_ZAPI_ENCODE, |
3451 | 0 | "%s: label %u: can't encode %u labels (maximum is %u)", |
3452 | 0 | __func__, zt->local_label, zt->label_num, |
3453 | 0 | MPLS_MAX_LABELS); |
3454 | 0 | return -1; |
3455 | 0 | } |
3456 | 0 | stream_putw(s, zt->label_num); |
3457 | |
|
3458 | 0 | for (int i = 0; i < zt->label_num; i++) |
3459 | 0 | stream_putl(s, zt->labels[i]); |
3460 | | |
3461 | | /* Put length at the first point of the stream. */ |
3462 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
3463 | |
|
3464 | 0 | return 0; |
3465 | 0 | } |
3466 | | |
3467 | | int zapi_sr_policy_decode(struct stream *s, struct zapi_sr_policy *zp) |
3468 | 6 | { |
3469 | 6 | memset(zp, 0, sizeof(*zp)); |
3470 | | |
3471 | 6 | struct zapi_srte_tunnel *zt = &zp->segment_list; |
3472 | | |
3473 | 6 | STREAM_GETL(s, zp->color); |
3474 | 6 | STREAM_GET_IPADDR(s, &zp->endpoint); |
3475 | 6 | STREAM_GET(&zp->name, s, SRTE_POLICY_NAME_MAX_LENGTH); |
3476 | | |
3477 | | /* segment list of active candidate path */ |
3478 | 6 | STREAM_GETC(s, zt->type); |
3479 | 6 | STREAM_GETL(s, zt->local_label); |
3480 | 6 | STREAM_GETW(s, zt->label_num); |
3481 | 6 | if (zt->label_num > MPLS_MAX_LABELS) { |
3482 | 2 | flog_err(EC_LIB_ZAPI_ENCODE, |
3483 | 2 | "%s: label %u: can't decode %u labels (maximum is %u)", |
3484 | 2 | __func__, zt->local_label, zt->label_num, |
3485 | 2 | MPLS_MAX_LABELS); |
3486 | 2 | return -1; |
3487 | 2 | } |
3488 | 10 | for (int i = 0; i < zt->label_num; i++) |
3489 | 6 | STREAM_GETL(s, zt->labels[i]); |
3490 | | |
3491 | 4 | return 0; |
3492 | | |
3493 | 0 | stream_failure: |
3494 | 0 | return -1; |
3495 | 4 | } |
3496 | | |
3497 | | int zapi_sr_policy_notify_status_decode(struct stream *s, |
3498 | | struct zapi_sr_policy *zp) |
3499 | 0 | { |
3500 | 0 | memset(zp, 0, sizeof(*zp)); |
3501 | |
|
3502 | 0 | STREAM_GETL(s, zp->color); |
3503 | 0 | STREAM_GET_IPADDR(s, &zp->endpoint); |
3504 | 0 | STREAM_GET(&zp->name, s, SRTE_POLICY_NAME_MAX_LENGTH); |
3505 | 0 | STREAM_GETL(s, zp->status); |
3506 | | |
3507 | 0 | return 0; |
3508 | | |
3509 | 0 | stream_failure: |
3510 | 0 | return -1; |
3511 | 0 | } |
3512 | | |
3513 | | enum zclient_send_status zebra_send_mpls_labels(struct zclient *zclient, |
3514 | | int cmd, struct zapi_labels *zl) |
3515 | 0 | { |
3516 | 0 | if (zapi_labels_encode(zclient->obuf, cmd, zl) < 0) |
3517 | 0 | return ZCLIENT_SEND_FAILURE; |
3518 | 0 | return zclient_send_message(zclient); |
3519 | 0 | } |
3520 | | |
3521 | | int zapi_labels_encode(struct stream *s, int cmd, struct zapi_labels *zl) |
3522 | 0 | { |
3523 | 0 | struct zapi_nexthop *znh; |
3524 | |
|
3525 | 0 | stream_reset(s); |
3526 | |
|
3527 | 0 | zclient_create_header(s, cmd, VRF_DEFAULT); |
3528 | 0 | stream_putc(s, zl->message); |
3529 | 0 | stream_putc(s, zl->type); |
3530 | 0 | stream_putl(s, zl->local_label); |
3531 | |
|
3532 | 0 | if (CHECK_FLAG(zl->message, ZAPI_LABELS_FTN)) { |
3533 | 0 | stream_putw(s, zl->route.prefix.family); |
3534 | 0 | stream_put_prefix(s, &zl->route.prefix); |
3535 | 0 | stream_putc(s, zl->route.type); |
3536 | 0 | stream_putw(s, zl->route.instance); |
3537 | 0 | } |
3538 | |
|
3539 | 0 | if (zl->nexthop_num > MULTIPATH_NUM) { |
3540 | 0 | flog_err( |
3541 | 0 | EC_LIB_ZAPI_ENCODE, |
3542 | 0 | "%s: label %u: can't encode %u nexthops (maximum is %u)", |
3543 | 0 | __func__, zl->local_label, zl->nexthop_num, |
3544 | 0 | MULTIPATH_NUM); |
3545 | 0 | return -1; |
3546 | 0 | } |
3547 | 0 | stream_putw(s, zl->nexthop_num); |
3548 | |
|
3549 | 0 | for (int i = 0; i < zl->nexthop_num; i++) { |
3550 | 0 | znh = &zl->nexthops[i]; |
3551 | |
|
3552 | 0 | if (zapi_nexthop_encode(s, znh, 0, 0) < 0) |
3553 | 0 | return -1; |
3554 | 0 | } |
3555 | | |
3556 | 0 | if (CHECK_FLAG(zl->message, ZAPI_LABELS_HAS_BACKUPS)) { |
3557 | |
|
3558 | 0 | if (zl->backup_nexthop_num > MULTIPATH_NUM) { |
3559 | 0 | flog_err( |
3560 | 0 | EC_LIB_ZAPI_ENCODE, |
3561 | 0 | "%s: label %u: can't encode %u nexthops (maximum is %u)", |
3562 | 0 | __func__, zl->local_label, zl->nexthop_num, |
3563 | 0 | MULTIPATH_NUM); |
3564 | 0 | return -1; |
3565 | 0 | } |
3566 | 0 | stream_putw(s, zl->backup_nexthop_num); |
3567 | |
|
3568 | 0 | for (int i = 0; i < zl->backup_nexthop_num; i++) { |
3569 | 0 | znh = &zl->backup_nexthops[i]; |
3570 | |
|
3571 | 0 | if (zapi_nexthop_encode(s, znh, 0, 0) < 0) |
3572 | 0 | return -1; |
3573 | 0 | } |
3574 | |
|
3575 | 0 | } |
3576 | | |
3577 | | /* Put length at the first point of the stream. */ |
3578 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
3579 | |
|
3580 | 0 | return 0; |
3581 | 0 | } |
3582 | | |
3583 | | int zapi_labels_decode(struct stream *s, struct zapi_labels *zl) |
3584 | 0 | { |
3585 | 0 | struct zapi_nexthop *znh; |
3586 | |
|
3587 | 0 | memset(zl, 0, sizeof(*zl)); |
3588 | | |
3589 | | /* Get data. */ |
3590 | 0 | STREAM_GETC(s, zl->message); |
3591 | 0 | STREAM_GETC(s, zl->type); |
3592 | 0 | STREAM_GETL(s, zl->local_label); |
3593 | | |
3594 | 0 | if (CHECK_FLAG(zl->message, ZAPI_LABELS_FTN)) { |
3595 | 0 | size_t psize; |
3596 | |
|
3597 | 0 | STREAM_GETW(s, zl->route.prefix.family); |
3598 | 0 | STREAM_GETC(s, zl->route.prefix.prefixlen); |
3599 | | |
3600 | 0 | psize = PSIZE(zl->route.prefix.prefixlen); |
3601 | 0 | switch (zl->route.prefix.family) { |
3602 | 0 | case AF_INET: |
3603 | 0 | if (zl->route.prefix.prefixlen > IPV4_MAX_BITLEN) { |
3604 | 0 | zlog_debug( |
3605 | 0 | "%s: Specified prefix length %d is greater than a v4 address can support", |
3606 | 0 | __func__, zl->route.prefix.prefixlen); |
3607 | 0 | return -1; |
3608 | 0 | } |
3609 | 0 | STREAM_GET(&zl->route.prefix.u.prefix4.s_addr, s, |
3610 | 0 | psize); |
3611 | 0 | break; |
3612 | 0 | case AF_INET6: |
3613 | 0 | if (zl->route.prefix.prefixlen > IPV6_MAX_BITLEN) { |
3614 | 0 | zlog_debug( |
3615 | 0 | "%s: Specified prefix length %d is greater than a v6 address can support", |
3616 | 0 | __func__, zl->route.prefix.prefixlen); |
3617 | 0 | return -1; |
3618 | 0 | } |
3619 | 0 | STREAM_GET(&zl->route.prefix.u.prefix6, s, psize); |
3620 | 0 | break; |
3621 | 0 | default: |
3622 | 0 | flog_err(EC_LIB_ZAPI_ENCODE, |
3623 | 0 | "%s: Specified family %u is not v4 or v6", |
3624 | 0 | __func__, zl->route.prefix.family); |
3625 | 0 | return -1; |
3626 | 0 | } |
3627 | | |
3628 | 0 | STREAM_GETC(s, zl->route.type); |
3629 | 0 | STREAM_GETW(s, zl->route.instance); |
3630 | 0 | } |
3631 | | |
3632 | 0 | STREAM_GETW(s, zl->nexthop_num); |
3633 | | |
3634 | 0 | if (zl->nexthop_num > MULTIPATH_NUM) { |
3635 | 0 | flog_warn( |
3636 | 0 | EC_LIB_ZAPI_ENCODE, |
3637 | 0 | "%s: Prefix %pFX has %d nexthops, but we can only use the first %d", |
3638 | 0 | __func__, &zl->route.prefix, zl->nexthop_num, |
3639 | 0 | MULTIPATH_NUM); |
3640 | 0 | } |
3641 | |
|
3642 | 0 | zl->nexthop_num = MIN(MULTIPATH_NUM, zl->nexthop_num); |
3643 | |
|
3644 | 0 | for (int i = 0; i < zl->nexthop_num; i++) { |
3645 | 0 | znh = &zl->nexthops[i]; |
3646 | |
|
3647 | 0 | if (zapi_nexthop_decode(s, znh, 0, 0) < 0) |
3648 | 0 | return -1; |
3649 | | |
3650 | 0 | if (znh->type == NEXTHOP_TYPE_BLACKHOLE) { |
3651 | 0 | flog_warn( |
3652 | 0 | EC_LIB_ZAPI_ENCODE, |
3653 | 0 | "%s: Prefix %pFX has a blackhole nexthop which we cannot use for a label", |
3654 | 0 | __func__, &zl->route.prefix); |
3655 | 0 | return -1; |
3656 | 0 | } |
3657 | 0 | } |
3658 | | |
3659 | 0 | if (CHECK_FLAG(zl->message, ZAPI_LABELS_HAS_BACKUPS)) { |
3660 | 0 | STREAM_GETW(s, zl->backup_nexthop_num); |
3661 | | |
3662 | 0 | if (zl->backup_nexthop_num > MULTIPATH_NUM) { |
3663 | 0 | flog_warn( |
3664 | 0 | EC_LIB_ZAPI_ENCODE, |
3665 | 0 | "%s: Prefix %pFX has %d backup nexthops, but we can only use the first %d", |
3666 | 0 | __func__, &zl->route.prefix, |
3667 | 0 | zl->backup_nexthop_num, MULTIPATH_NUM); |
3668 | 0 | } |
3669 | |
|
3670 | 0 | zl->backup_nexthop_num = MIN(MULTIPATH_NUM, |
3671 | 0 | zl->backup_nexthop_num); |
3672 | |
|
3673 | 0 | for (int i = 0; i < zl->backup_nexthop_num; i++) { |
3674 | 0 | znh = &zl->backup_nexthops[i]; |
3675 | |
|
3676 | 0 | if (zapi_nexthop_decode(s, znh, 0, 0) < 0) |
3677 | 0 | return -1; |
3678 | | |
3679 | 0 | if (znh->type == NEXTHOP_TYPE_BLACKHOLE) { |
3680 | 0 | flog_warn( |
3681 | 0 | EC_LIB_ZAPI_ENCODE, |
3682 | 0 | "%s: Prefix %pFX has a backup blackhole nexthop which we cannot use for a label", |
3683 | 0 | __func__, &zl->route.prefix); |
3684 | 0 | return -1; |
3685 | 0 | } |
3686 | 0 | } |
3687 | 0 | } |
3688 | | |
3689 | 0 | return 0; |
3690 | 0 | stream_failure: |
3691 | 0 | return -1; |
3692 | 0 | } |
3693 | | |
3694 | | enum zclient_send_status zebra_send_pw(struct zclient *zclient, int command, |
3695 | | struct zapi_pw *pw) |
3696 | 0 | { |
3697 | 0 | struct stream *s; |
3698 | | |
3699 | | /* Reset stream. */ |
3700 | 0 | s = zclient->obuf; |
3701 | 0 | stream_reset(s); |
3702 | |
|
3703 | 0 | zclient_create_header(s, command, VRF_DEFAULT); |
3704 | 0 | stream_write(s, pw->ifname, INTERFACE_NAMSIZ); |
3705 | 0 | stream_putl(s, pw->ifindex); |
3706 | | |
3707 | | /* Put type */ |
3708 | 0 | stream_putl(s, pw->type); |
3709 | | |
3710 | | /* Put nexthop */ |
3711 | 0 | stream_putl(s, pw->af); |
3712 | 0 | switch (pw->af) { |
3713 | 0 | case AF_INET: |
3714 | 0 | stream_put_in_addr(s, &pw->nexthop.ipv4); |
3715 | 0 | break; |
3716 | 0 | case AF_INET6: |
3717 | 0 | stream_write(s, (uint8_t *)&pw->nexthop.ipv6, 16); |
3718 | 0 | break; |
3719 | 0 | default: |
3720 | 0 | flog_err(EC_LIB_ZAPI_ENCODE, "%s: unknown af", __func__); |
3721 | 0 | return ZCLIENT_SEND_FAILURE; |
3722 | 0 | } |
3723 | | |
3724 | | /* Put labels */ |
3725 | 0 | stream_putl(s, pw->local_label); |
3726 | 0 | stream_putl(s, pw->remote_label); |
3727 | | |
3728 | | /* Put flags */ |
3729 | 0 | stream_putc(s, pw->flags); |
3730 | | |
3731 | | /* Protocol specific fields */ |
3732 | 0 | stream_write(s, &pw->data, sizeof(union pw_protocol_fields)); |
3733 | | |
3734 | | /* Put length at the first point of the stream. */ |
3735 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
3736 | |
|
3737 | 0 | return zclient_send_message(zclient); |
3738 | 0 | } |
3739 | | |
3740 | | /* |
3741 | | * Receive PW status update from Zebra and send it to LDE process. |
3742 | | */ |
3743 | | int zebra_read_pw_status_update(ZAPI_CALLBACK_ARGS, struct zapi_pw_status *pw) |
3744 | 0 | { |
3745 | 0 | struct stream *s; |
3746 | |
|
3747 | 0 | memset(pw, 0, sizeof(struct zapi_pw_status)); |
3748 | 0 | s = zclient->ibuf; |
3749 | | |
3750 | | /* Get data. */ |
3751 | 0 | stream_get(pw->ifname, s, INTERFACE_NAMSIZ); |
3752 | 0 | STREAM_GETL(s, pw->ifindex); |
3753 | 0 | STREAM_GETL(s, pw->status); |
3754 | | |
3755 | 0 | return 0; |
3756 | 0 | stream_failure: |
3757 | 0 | return -1; |
3758 | 0 | } |
3759 | | |
3760 | | static int zclient_capability_decode(ZAPI_CALLBACK_ARGS) |
3761 | 0 | { |
3762 | 0 | struct zclient_capabilities cap; |
3763 | 0 | struct stream *s = zclient->ibuf; |
3764 | 0 | int vrf_backend; |
3765 | 0 | uint8_t mpls_enabled; |
3766 | |
|
3767 | 0 | STREAM_GETL(s, vrf_backend); |
3768 | | |
3769 | 0 | if (vrf_backend < 0 || vrf_configure_backend(vrf_backend)) { |
3770 | 0 | flog_err(EC_LIB_ZAPI_ENCODE, |
3771 | 0 | "%s: Garbage VRF backend type: %d", __func__, |
3772 | 0 | vrf_backend); |
3773 | 0 | goto stream_failure; |
3774 | 0 | } |
3775 | | |
3776 | | |
3777 | 0 | memset(&cap, 0, sizeof(cap)); |
3778 | 0 | STREAM_GETC(s, mpls_enabled); |
3779 | 0 | cap.mpls_enabled = !!mpls_enabled; |
3780 | 0 | STREAM_GETL(s, cap.ecmp); |
3781 | 0 | STREAM_GETC(s, cap.role); |
3782 | | |
3783 | 0 | if (zclient->zebra_capabilities) |
3784 | 0 | (*zclient->zebra_capabilities)(&cap); |
3785 | |
|
3786 | 0 | stream_failure: |
3787 | 0 | return 0; |
3788 | 0 | } |
3789 | | |
3790 | | enum zclient_send_status zclient_send_mlag_register(struct zclient *client, |
3791 | | uint32_t bit_map) |
3792 | 0 | { |
3793 | 0 | struct stream *s; |
3794 | |
|
3795 | 0 | s = client->obuf; |
3796 | 0 | stream_reset(s); |
3797 | |
|
3798 | 0 | zclient_create_header(s, ZEBRA_MLAG_CLIENT_REGISTER, VRF_DEFAULT); |
3799 | 0 | stream_putl(s, bit_map); |
3800 | |
|
3801 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
3802 | 0 | return zclient_send_message(client); |
3803 | 0 | } |
3804 | | |
3805 | | enum zclient_send_status zclient_send_mlag_deregister(struct zclient *client) |
3806 | 0 | { |
3807 | 0 | return zebra_message_send(client, ZEBRA_MLAG_CLIENT_UNREGISTER, |
3808 | 0 | VRF_DEFAULT); |
3809 | 0 | } |
3810 | | |
3811 | | enum zclient_send_status zclient_send_mlag_data(struct zclient *client, |
3812 | | struct stream *client_s) |
3813 | 0 | { |
3814 | 0 | struct stream *s; |
3815 | |
|
3816 | 0 | s = client->obuf; |
3817 | 0 | stream_reset(s); |
3818 | |
|
3819 | 0 | zclient_create_header(s, ZEBRA_MLAG_FORWARD_MSG, VRF_DEFAULT); |
3820 | 0 | stream_put(s, client_s->data, client_s->endp); |
3821 | |
|
3822 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
3823 | 0 | return zclient_send_message(client); |
3824 | 0 | } |
3825 | | |
3826 | | /* |
3827 | | * Send an OPAQUE message, contents opaque to zebra. The message header |
3828 | | * is a message subtype. |
3829 | | */ |
3830 | | enum zclient_send_status zclient_send_opaque(struct zclient *zclient, |
3831 | | uint32_t type, const uint8_t *data, |
3832 | | size_t datasize) |
3833 | 0 | { |
3834 | 0 | struct stream *s; |
3835 | 0 | uint16_t flags = 0; |
3836 | | |
3837 | | /* Check buffer size */ |
3838 | 0 | if (STREAM_SIZE(zclient->obuf) < |
3839 | 0 | (ZEBRA_HEADER_SIZE + sizeof(type) + datasize)) |
3840 | 0 | return ZCLIENT_SEND_FAILURE; |
3841 | | |
3842 | 0 | s = zclient->obuf; |
3843 | 0 | stream_reset(s); |
3844 | |
|
3845 | 0 | zclient_create_header(s, ZEBRA_OPAQUE_MESSAGE, VRF_DEFAULT); |
3846 | | |
3847 | | /* Send sub-type and flags */ |
3848 | 0 | stream_putl(s, type); |
3849 | 0 | stream_putw(s, flags); |
3850 | | |
3851 | | /* Send opaque data */ |
3852 | 0 | stream_write(s, data, datasize); |
3853 | | |
3854 | | /* Put length into the header at the start of the stream. */ |
3855 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
3856 | |
|
3857 | 0 | return zclient_send_message(zclient); |
3858 | 0 | } |
3859 | | |
3860 | | /* |
3861 | | * Send an OPAQUE message to a specific zclient. The contents are opaque |
3862 | | * to zebra. |
3863 | | */ |
3864 | | enum zclient_send_status |
3865 | | zclient_send_opaque_unicast(struct zclient *zclient, uint32_t type, |
3866 | | uint8_t proto, uint16_t instance, |
3867 | | uint32_t session_id, const uint8_t *data, |
3868 | | size_t datasize) |
3869 | 0 | { |
3870 | 0 | struct stream *s; |
3871 | 0 | uint16_t flags = 0; |
3872 | | |
3873 | | /* Check buffer size */ |
3874 | 0 | if (STREAM_SIZE(zclient->obuf) < |
3875 | 0 | (ZEBRA_HEADER_SIZE + sizeof(struct zapi_opaque_msg) + datasize)) |
3876 | 0 | return ZCLIENT_SEND_FAILURE; |
3877 | | |
3878 | 0 | s = zclient->obuf; |
3879 | 0 | stream_reset(s); |
3880 | |
|
3881 | 0 | zclient_create_header(s, ZEBRA_OPAQUE_MESSAGE, VRF_DEFAULT); |
3882 | | |
3883 | | /* Send sub-type and flags */ |
3884 | 0 | SET_FLAG(flags, ZAPI_OPAQUE_FLAG_UNICAST); |
3885 | 0 | stream_putl(s, type); |
3886 | 0 | stream_putw(s, flags); |
3887 | | |
3888 | | /* Send destination client info */ |
3889 | 0 | stream_putc(s, proto); |
3890 | 0 | stream_putw(s, instance); |
3891 | 0 | stream_putl(s, session_id); |
3892 | | |
3893 | | /* Send opaque data */ |
3894 | 0 | stream_write(s, data, datasize); |
3895 | | |
3896 | | /* Put length into the header at the start of the stream. */ |
3897 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
3898 | |
|
3899 | 0 | return zclient_send_message(zclient); |
3900 | 0 | } |
3901 | | |
3902 | | /* |
3903 | | * Decode incoming opaque message into info struct |
3904 | | */ |
3905 | | int zclient_opaque_decode(struct stream *s, struct zapi_opaque_msg *info) |
3906 | 0 | { |
3907 | 0 | memset(info, 0, sizeof(*info)); |
3908 | | |
3909 | | /* Decode subtype and flags */ |
3910 | 0 | STREAM_GETL(s, info->type); |
3911 | 0 | STREAM_GETW(s, info->flags); |
3912 | | |
3913 | | /* Decode unicast client info if present */ |
3914 | 0 | if (CHECK_FLAG(info->flags, ZAPI_OPAQUE_FLAG_UNICAST)) { |
3915 | 0 | STREAM_GETC(s, info->proto); |
3916 | 0 | STREAM_GETW(s, info->instance); |
3917 | 0 | STREAM_GETL(s, info->session_id); |
3918 | 0 | } |
3919 | | |
3920 | 0 | info->len = STREAM_READABLE(s); |
3921 | |
|
3922 | 0 | return 0; |
3923 | | |
3924 | 0 | stream_failure: |
3925 | |
|
3926 | 0 | return -1; |
3927 | 0 | } |
3928 | | |
3929 | | /* |
3930 | | * Send a registration request for opaque messages with a specified subtype. |
3931 | | */ |
3932 | | enum zclient_send_status zclient_register_opaque(struct zclient *zclient, |
3933 | | uint32_t type) |
3934 | 0 | { |
3935 | 0 | struct stream *s; |
3936 | |
|
3937 | 0 | s = zclient->obuf; |
3938 | 0 | stream_reset(s); |
3939 | |
|
3940 | 0 | zclient_create_header(s, ZEBRA_OPAQUE_REGISTER, VRF_DEFAULT); |
3941 | | |
3942 | | /* Send sub-type */ |
3943 | 0 | stream_putl(s, type); |
3944 | | |
3945 | | /* Add zclient info */ |
3946 | 0 | stream_putc(s, zclient->redist_default); |
3947 | 0 | stream_putw(s, zclient->instance); |
3948 | 0 | stream_putl(s, zclient->session_id); |
3949 | | |
3950 | | /* Put length at the first point of the stream. */ |
3951 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
3952 | |
|
3953 | 0 | return zclient_send_message(zclient); |
3954 | 0 | } |
3955 | | |
3956 | | /* |
3957 | | * Send an un-registration request for a specified opaque subtype. |
3958 | | */ |
3959 | | enum zclient_send_status zclient_unregister_opaque(struct zclient *zclient, |
3960 | | uint32_t type) |
3961 | 0 | { |
3962 | 0 | struct stream *s; |
3963 | |
|
3964 | 0 | s = zclient->obuf; |
3965 | 0 | stream_reset(s); |
3966 | |
|
3967 | 0 | zclient_create_header(s, ZEBRA_OPAQUE_UNREGISTER, VRF_DEFAULT); |
3968 | | |
3969 | | /* Send sub-type */ |
3970 | 0 | stream_putl(s, type); |
3971 | | |
3972 | | /* Add zclient info */ |
3973 | 0 | stream_putc(s, zclient->redist_default); |
3974 | 0 | stream_putw(s, zclient->instance); |
3975 | 0 | stream_putl(s, zclient->session_id); |
3976 | | |
3977 | | /* Put length at the first point of the stream. */ |
3978 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
3979 | |
|
3980 | 0 | return zclient_send_message(zclient); |
3981 | 0 | } |
3982 | | |
3983 | | /* Utility to decode opaque registration info */ |
3984 | | int zapi_opaque_reg_decode(struct stream *s, struct zapi_opaque_reg_info *info) |
3985 | 0 | { |
3986 | 0 | STREAM_GETL(s, info->type); |
3987 | 0 | STREAM_GETC(s, info->proto); |
3988 | 0 | STREAM_GETW(s, info->instance); |
3989 | 0 | STREAM_GETL(s, info->session_id); |
3990 | | |
3991 | 0 | return 0; |
3992 | | |
3993 | 0 | stream_failure: |
3994 | |
|
3995 | 0 | return -1; |
3996 | 0 | } |
3997 | | |
3998 | | /* Utility to decode client close notify info */ |
3999 | | int zapi_client_close_notify_decode(struct stream *s, |
4000 | | struct zapi_client_close_info *info) |
4001 | 0 | { |
4002 | 0 | memset(info, 0, sizeof(*info)); |
4003 | |
|
4004 | 0 | STREAM_GETC(s, info->proto); |
4005 | 0 | STREAM_GETW(s, info->instance); |
4006 | 0 | STREAM_GETL(s, info->session_id); |
4007 | | |
4008 | 0 | return 0; |
4009 | | |
4010 | 0 | stream_failure: |
4011 | |
|
4012 | 0 | return -1; |
4013 | 0 | } |
4014 | | |
4015 | | static zclient_handler *const lib_handlers[] = { |
4016 | | /* fundamentals */ |
4017 | | [ZEBRA_CAPABILITIES] = zclient_capability_decode, |
4018 | | [ZEBRA_ERROR] = zclient_handle_error, |
4019 | | |
4020 | | /* VRF & interface code is shared in lib */ |
4021 | | [ZEBRA_VRF_ADD] = zclient_vrf_add, |
4022 | | [ZEBRA_VRF_DELETE] = zclient_vrf_delete, |
4023 | | [ZEBRA_INTERFACE_ADD] = zclient_interface_add, |
4024 | | [ZEBRA_INTERFACE_DELETE] = zclient_interface_delete, |
4025 | | [ZEBRA_INTERFACE_UP] = zclient_interface_up, |
4026 | | [ZEBRA_INTERFACE_DOWN] = zclient_interface_down, |
4027 | | |
4028 | | /* BFD */ |
4029 | | [ZEBRA_BFD_DEST_REPLAY] = zclient_bfd_session_replay, |
4030 | | [ZEBRA_INTERFACE_BFD_DEST_UPDATE] = zclient_bfd_session_update, |
4031 | | }; |
4032 | | |
4033 | | #ifdef FUZZING |
4034 | | int zclient_read_fuzz(struct zclient *zclient, const uint8_t *data, size_t len) |
4035 | 0 | { |
4036 | 0 | uint16_t length, command; |
4037 | 0 | uint8_t marker, version; |
4038 | 0 | vrf_id_t vrf_id; |
4039 | | |
4040 | | /* Length check. */ |
4041 | 0 | if (len > STREAM_SIZE(zclient->ibuf)) { |
4042 | 0 | struct stream *ns; |
4043 | 0 | flog_err( |
4044 | 0 | EC_LIB_ZAPI_ENCODE, |
4045 | 0 | "%s: message size %zu exceeds buffer size %lu, expanding...", |
4046 | 0 | __func__, len, |
4047 | 0 | (unsigned long)STREAM_SIZE(zclient->ibuf)); |
4048 | 0 | ns = stream_new(len); |
4049 | 0 | stream_free(zclient->ibuf); |
4050 | 0 | zclient->ibuf = ns; |
4051 | 0 | } |
4052 | |
|
4053 | 0 | if (len < ZEBRA_HEADER_SIZE) { |
4054 | 0 | flog_err(EC_LIB_ZAPI_MISSMATCH, |
4055 | 0 | "%s: socket %d message length %zu is less than %d ", |
4056 | 0 | __func__, zclient->sock, len, ZEBRA_HEADER_SIZE); |
4057 | 0 | return -1; |
4058 | 0 | } |
4059 | | |
4060 | 0 | stream_reset(zclient->ibuf); |
4061 | 0 | stream_put(zclient->ibuf, data, len); |
4062 | |
|
4063 | 0 | length = stream_getw(zclient->ibuf); |
4064 | 0 | marker = stream_getc(zclient->ibuf); |
4065 | 0 | version = stream_getc(zclient->ibuf); |
4066 | 0 | vrf_id = stream_getl(zclient->ibuf); |
4067 | 0 | command = stream_getw(zclient->ibuf); |
4068 | |
|
4069 | 0 | if (marker != ZEBRA_HEADER_MARKER || version != ZSERV_VERSION) { |
4070 | 0 | flog_err( |
4071 | 0 | EC_LIB_ZAPI_MISSMATCH, |
4072 | 0 | "%s: socket %d version mismatch, marker %d, version %d", |
4073 | 0 | __func__, zclient->sock, marker, version); |
4074 | 0 | return -1; |
4075 | 0 | } |
4076 | | |
4077 | 0 | length -= ZEBRA_HEADER_SIZE; |
4078 | |
|
4079 | 0 | if (zclient_debug) |
4080 | 0 | zlog_debug("zclient %p command %s VRF %u", zclient, |
4081 | 0 | zserv_command_string(command), vrf_id); |
4082 | |
|
4083 | 0 | if (command < array_size(lib_handlers) && lib_handlers[command]) |
4084 | 0 | lib_handlers[command](command, zclient, length, vrf_id); |
4085 | 0 | if (command < zclient->n_handlers && zclient->handlers[command]) |
4086 | 0 | zclient->handlers[command](command, zclient, length, vrf_id); |
4087 | |
|
4088 | 0 | if (zclient->sock < 0) |
4089 | | /* Connection was closed during packet processing. */ |
4090 | 0 | return -1; |
4091 | | |
4092 | | /* Register read thread. */ |
4093 | 0 | stream_reset(zclient->ibuf); |
4094 | 0 | zclient_event(ZCLIENT_READ, zclient); |
4095 | |
|
4096 | 0 | return 0; |
4097 | 0 | } |
4098 | | #endif |
4099 | | |
4100 | | /* Zebra client message read function. */ |
4101 | | static void zclient_read(struct event *thread) |
4102 | 0 | { |
4103 | 0 | size_t already; |
4104 | 0 | uint16_t length, command; |
4105 | 0 | uint8_t marker, version; |
4106 | 0 | vrf_id_t vrf_id; |
4107 | 0 | struct zclient *zclient; |
4108 | 0 |
|
4109 | 0 | /* Get socket to zebra. */ |
4110 | 0 | zclient = EVENT_ARG(thread); |
4111 | 0 | zclient->t_read = NULL; |
4112 | 0 |
|
4113 | 0 | /* Read zebra header (if we don't have it already). */ |
4114 | 0 | already = stream_get_endp(zclient->ibuf); |
4115 | 0 | if (already < ZEBRA_HEADER_SIZE) { |
4116 | 0 | ssize_t nbyte; |
4117 | 0 | if (((nbyte = stream_read_try(zclient->ibuf, zclient->sock, |
4118 | 0 | ZEBRA_HEADER_SIZE - already)) |
4119 | 0 | == 0) |
4120 | 0 | || (nbyte == -1)) { |
4121 | 0 | if (zclient_debug) |
4122 | 0 | zlog_debug( |
4123 | 0 | "zclient connection closed socket [%d].", |
4124 | 0 | zclient->sock); |
4125 | 0 | zclient_failed(zclient); |
4126 | 0 | return; |
4127 | 0 | } |
4128 | 0 | if (nbyte != (ssize_t)(ZEBRA_HEADER_SIZE - already)) { |
4129 | 0 | zclient_event(ZCLIENT_READ, zclient); |
4130 | 0 | return; |
4131 | 0 | } |
4132 | 0 | already = ZEBRA_HEADER_SIZE; |
4133 | 0 | } |
4134 | 0 |
|
4135 | 0 | /* Reset to read from the beginning of the incoming packet. */ |
4136 | 0 | stream_set_getp(zclient->ibuf, 0); |
4137 | 0 |
|
4138 | 0 | /* Fetch header values. */ |
4139 | 0 | length = stream_getw(zclient->ibuf); |
4140 | 0 | marker = stream_getc(zclient->ibuf); |
4141 | 0 | version = stream_getc(zclient->ibuf); |
4142 | 0 | vrf_id = stream_getl(zclient->ibuf); |
4143 | 0 | command = stream_getw(zclient->ibuf); |
4144 | 0 |
|
4145 | 0 | if (marker != ZEBRA_HEADER_MARKER || version != ZSERV_VERSION) { |
4146 | 0 | flog_err( |
4147 | 0 | EC_LIB_ZAPI_MISSMATCH, |
4148 | 0 | "%s: socket %d version mismatch, marker %d, version %d", |
4149 | 0 | __func__, zclient->sock, marker, version); |
4150 | 0 | zclient_failed(zclient); |
4151 | 0 | return; |
4152 | 0 | } |
4153 | 0 |
|
4154 | 0 | if (length < ZEBRA_HEADER_SIZE) { |
4155 | 0 | flog_err(EC_LIB_ZAPI_MISSMATCH, |
4156 | 0 | "%s: socket %d message length %u is less than %d ", |
4157 | 0 | __func__, zclient->sock, length, ZEBRA_HEADER_SIZE); |
4158 | 0 | zclient_failed(zclient); |
4159 | 0 | return; |
4160 | 0 | } |
4161 | 0 |
|
4162 | 0 | /* Length check. */ |
4163 | 0 | if (length > STREAM_SIZE(zclient->ibuf)) { |
4164 | 0 | struct stream *ns; |
4165 | 0 | flog_err( |
4166 | 0 | EC_LIB_ZAPI_ENCODE, |
4167 | 0 | "%s: message size %u exceeds buffer size %lu, expanding...", |
4168 | 0 | __func__, length, |
4169 | 0 | (unsigned long)STREAM_SIZE(zclient->ibuf)); |
4170 | 0 | ns = stream_new(length); |
4171 | 0 | stream_copy(ns, zclient->ibuf); |
4172 | 0 | stream_free(zclient->ibuf); |
4173 | 0 | zclient->ibuf = ns; |
4174 | 0 | } |
4175 | 0 |
|
4176 | 0 | /* Read rest of zebra packet. */ |
4177 | 0 | if (already < length) { |
4178 | 0 | ssize_t nbyte; |
4179 | 0 | if (((nbyte = stream_read_try(zclient->ibuf, zclient->sock, |
4180 | 0 | length - already)) |
4181 | 0 | == 0) |
4182 | 0 | || (nbyte == -1)) { |
4183 | 0 | if (zclient_debug) |
4184 | 0 | zlog_debug( |
4185 | 0 | "zclient connection closed socket [%d].", |
4186 | 0 | zclient->sock); |
4187 | 0 | zclient_failed(zclient); |
4188 | 0 | return; |
4189 | 0 | } |
4190 | 0 | if (nbyte != (ssize_t)(length - already)) { |
4191 | 0 | /* Try again later. */ |
4192 | 0 | zclient_event(ZCLIENT_READ, zclient); |
4193 | 0 | return; |
4194 | 0 | } |
4195 | 0 | } |
4196 | 0 |
|
4197 | 0 | length -= ZEBRA_HEADER_SIZE; |
4198 | 0 |
|
4199 | 0 | if (zclient_debug) |
4200 | 0 | zlog_debug("zclient %p command %s VRF %u", zclient, |
4201 | 0 | zserv_command_string(command), vrf_id); |
4202 | 0 |
|
4203 | 0 | if (command < array_size(lib_handlers) && lib_handlers[command]) |
4204 | 0 | lib_handlers[command](command, zclient, length, vrf_id); |
4205 | 0 | if (command < zclient->n_handlers && zclient->handlers[command]) |
4206 | 0 | zclient->handlers[command](command, zclient, length, vrf_id); |
4207 | 0 |
|
4208 | 0 | if (zclient->sock < 0) |
4209 | 0 | /* Connection was closed during packet processing. */ |
4210 | 0 | return; |
4211 | 0 |
|
4212 | 0 | /* Register read thread. */ |
4213 | 0 | stream_reset(zclient->ibuf); |
4214 | 0 | zclient_event(ZCLIENT_READ, zclient); |
4215 | 0 | } |
4216 | | |
4217 | | void zclient_redistribute(int command, struct zclient *zclient, afi_t afi, |
4218 | | int type, unsigned short instance, vrf_id_t vrf_id) |
4219 | 0 | { |
4220 | |
|
4221 | 0 | if (instance) { |
4222 | 0 | if (command == ZEBRA_REDISTRIBUTE_ADD) { |
4223 | 0 | if (redist_check_instance( |
4224 | 0 | &zclient->mi_redist[afi][type], instance)) |
4225 | 0 | return; |
4226 | 0 | redist_add_instance(&zclient->mi_redist[afi][type], |
4227 | 0 | instance); |
4228 | 0 | } else { |
4229 | 0 | if (!redist_check_instance( |
4230 | 0 | &zclient->mi_redist[afi][type], instance)) |
4231 | 0 | return; |
4232 | 0 | redist_del_instance(&zclient->mi_redist[afi][type], |
4233 | 0 | instance); |
4234 | 0 | } |
4235 | |
|
4236 | 0 | } else { |
4237 | 0 | if (command == ZEBRA_REDISTRIBUTE_ADD) { |
4238 | 0 | if (vrf_bitmap_check(zclient->redist[afi][type], |
4239 | 0 | vrf_id)) |
4240 | 0 | return; |
4241 | 0 | vrf_bitmap_set(zclient->redist[afi][type], vrf_id); |
4242 | 0 | } else { |
4243 | 0 | if (!vrf_bitmap_check(zclient->redist[afi][type], |
4244 | 0 | vrf_id)) |
4245 | 0 | return; |
4246 | 0 | vrf_bitmap_unset(zclient->redist[afi][type], vrf_id); |
4247 | 0 | } |
4248 | 0 | } |
4249 | | |
4250 | 0 | if (zclient->sock > 0) |
4251 | 0 | zebra_redistribute_send(command, zclient, afi, type, instance, |
4252 | 0 | vrf_id); |
4253 | 0 | } |
4254 | | |
4255 | | |
4256 | | void zclient_redistribute_default(int command, struct zclient *zclient, |
4257 | | afi_t afi, vrf_id_t vrf_id) |
4258 | 0 | { |
4259 | |
|
4260 | 0 | if (command == ZEBRA_REDISTRIBUTE_DEFAULT_ADD) { |
4261 | 0 | if (vrf_bitmap_check(zclient->default_information[afi], vrf_id)) |
4262 | 0 | return; |
4263 | 0 | vrf_bitmap_set(zclient->default_information[afi], vrf_id); |
4264 | 0 | } else { |
4265 | 0 | if (!vrf_bitmap_check(zclient->default_information[afi], |
4266 | 0 | vrf_id)) |
4267 | 0 | return; |
4268 | 0 | vrf_bitmap_unset(zclient->default_information[afi], vrf_id); |
4269 | 0 | } |
4270 | | |
4271 | 0 | if (zclient->sock > 0) |
4272 | 0 | zebra_redistribute_default_send(command, zclient, afi, vrf_id); |
4273 | 0 | } |
4274 | | |
4275 | | static void zclient_event(enum zclient_event event, struct zclient *zclient) |
4276 | 3 | { |
4277 | 3 | switch (event) { |
4278 | 3 | case ZCLIENT_SCHEDULE: |
4279 | 3 | event_add_event(zclient->master, zclient_connect, zclient, 0, |
4280 | 3 | &zclient->t_connect); |
4281 | 3 | break; |
4282 | 0 | case ZCLIENT_CONNECT: |
4283 | 0 | if (zclient_debug) |
4284 | 0 | zlog_debug( |
4285 | 0 | "zclient connect failures: %d schedule interval is now %d", |
4286 | 0 | zclient->fail, zclient->fail < 3 ? 10 : 60); |
4287 | 0 | event_add_timer(zclient->master, zclient_connect, zclient, |
4288 | 0 | zclient->fail < 3 ? 10 : 60, |
4289 | 0 | &zclient->t_connect); |
4290 | 0 | break; |
4291 | 0 | case ZCLIENT_READ: |
4292 | 0 | zclient->t_read = NULL; |
4293 | 0 | event_add_read(zclient->master, zclient_read, zclient, |
4294 | 0 | zclient->sock, &zclient->t_read); |
4295 | 0 | break; |
4296 | 3 | } |
4297 | 3 | } |
4298 | | |
4299 | | enum zclient_send_status zclient_interface_set_master(struct zclient *client, |
4300 | | struct interface *master, |
4301 | | struct interface *slave) |
4302 | 0 | { |
4303 | 0 | struct stream *s; |
4304 | |
|
4305 | 0 | s = client->obuf; |
4306 | 0 | stream_reset(s); |
4307 | |
|
4308 | 0 | zclient_create_header(s, ZEBRA_INTERFACE_SET_MASTER, |
4309 | 0 | master->vrf->vrf_id); |
4310 | |
|
4311 | 0 | stream_putl(s, master->vrf->vrf_id); |
4312 | 0 | stream_putl(s, master->ifindex); |
4313 | 0 | stream_putl(s, slave->vrf->vrf_id); |
4314 | 0 | stream_putl(s, slave->ifindex); |
4315 | |
|
4316 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
4317 | 0 | return zclient_send_message(client); |
4318 | 0 | } |
4319 | | |
4320 | | /* |
4321 | | * Send capabilities message to zebra |
4322 | | */ |
4323 | | enum zclient_send_status zclient_capabilities_send(uint32_t cmd, |
4324 | | struct zclient *zclient, |
4325 | | struct zapi_cap *api) |
4326 | 0 | { |
4327 | |
|
4328 | 0 | struct stream *s; |
4329 | |
|
4330 | 0 | if (zclient == NULL) |
4331 | 0 | return ZCLIENT_SEND_FAILURE; |
4332 | | |
4333 | 0 | s = zclient->obuf; |
4334 | 0 | stream_reset(s); |
4335 | 0 | zclient_create_header(s, cmd, 0); |
4336 | 0 | stream_putl(s, api->cap); |
4337 | |
|
4338 | 0 | switch (api->cap) { |
4339 | 0 | case ZEBRA_CLIENT_GR_CAPABILITIES: |
4340 | 0 | case ZEBRA_CLIENT_RIB_STALE_TIME: |
4341 | 0 | stream_putl(s, api->stale_removal_time); |
4342 | 0 | stream_putl(s, api->vrf_id); |
4343 | 0 | break; |
4344 | 0 | case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE: |
4345 | 0 | case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING: |
4346 | 0 | stream_putl(s, api->afi); |
4347 | 0 | stream_putl(s, api->safi); |
4348 | 0 | stream_putl(s, api->vrf_id); |
4349 | 0 | break; |
4350 | 0 | case ZEBRA_CLIENT_GR_DISABLE: |
4351 | 0 | stream_putl(s, api->vrf_id); |
4352 | 0 | break; |
4353 | 0 | } |
4354 | | |
4355 | | /* Put length at the first point of the stream */ |
4356 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
4357 | |
|
4358 | 0 | return zclient_send_message(zclient); |
4359 | 0 | } |
4360 | | |
4361 | | /* |
4362 | | * Process capabilities message from zebra |
4363 | | */ |
4364 | | int32_t zapi_capabilities_decode(struct stream *s, struct zapi_cap *api) |
4365 | 0 | { |
4366 | |
|
4367 | 0 | memset(api, 0, sizeof(*api)); |
4368 | |
|
4369 | 0 | api->safi = SAFI_UNICAST; |
4370 | |
|
4371 | 0 | STREAM_GETL(s, api->cap); |
4372 | 0 | switch (api->cap) { |
4373 | 0 | case ZEBRA_CLIENT_GR_CAPABILITIES: |
4374 | 0 | case ZEBRA_CLIENT_RIB_STALE_TIME: |
4375 | 0 | STREAM_GETL(s, api->stale_removal_time); |
4376 | 0 | STREAM_GETL(s, api->vrf_id); |
4377 | 0 | break; |
4378 | 0 | case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE: |
4379 | 0 | case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING: |
4380 | 0 | STREAM_GETL(s, api->afi); |
4381 | 0 | STREAM_GETL(s, api->safi); |
4382 | 0 | STREAM_GETL(s, api->vrf_id); |
4383 | 0 | break; |
4384 | 0 | case ZEBRA_CLIENT_GR_DISABLE: |
4385 | 0 | STREAM_GETL(s, api->vrf_id); |
4386 | 0 | break; |
4387 | 0 | } |
4388 | 0 | stream_failure: |
4389 | 0 | return 0; |
4390 | 0 | } |
4391 | | |
4392 | | enum zclient_send_status |
4393 | | zclient_send_neigh_discovery_req(struct zclient *zclient, |
4394 | | const struct interface *ifp, |
4395 | | const struct prefix *p) |
4396 | 0 | { |
4397 | 0 | struct stream *s; |
4398 | |
|
4399 | 0 | s = zclient->obuf; |
4400 | 0 | stream_reset(s); |
4401 | |
|
4402 | 0 | zclient_create_header(s, ZEBRA_NEIGH_DISCOVER, ifp->vrf->vrf_id); |
4403 | 0 | stream_putl(s, ifp->ifindex); |
4404 | |
|
4405 | 0 | stream_putc(s, p->family); |
4406 | 0 | stream_putc(s, p->prefixlen); |
4407 | 0 | stream_put(s, &p->u.prefix, prefix_blen(p)); |
4408 | |
|
4409 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
4410 | 0 | return zclient_send_message(zclient); |
4411 | 0 | } |
4412 | | |
4413 | | /* |
4414 | | * Get a starting nhg point for a routing protocol |
4415 | | */ |
4416 | | uint32_t zclient_get_nhg_start(uint32_t proto) |
4417 | 0 | { |
4418 | 0 | assert(proto < ZEBRA_ROUTE_MAX); |
4419 | |
|
4420 | 0 | return ZEBRA_NHG_PROTO_SPACING * proto; |
4421 | 0 | } |
4422 | | |
4423 | | char *zclient_dump_route_flags(uint32_t flags, char *buf, size_t len) |
4424 | 0 | { |
4425 | 0 | if (flags == 0) { |
4426 | 0 | snprintfrr(buf, len, "None "); |
4427 | 0 | return buf; |
4428 | 0 | } |
4429 | | |
4430 | 0 | snprintfrr( |
4431 | 0 | buf, len, "%s%s%s%s%s%s%s%s%s%s", |
4432 | 0 | CHECK_FLAG(flags, ZEBRA_FLAG_ALLOW_RECURSION) ? "Recursion " |
4433 | 0 | : "", |
4434 | 0 | CHECK_FLAG(flags, ZEBRA_FLAG_SELFROUTE) ? "Self " : "", |
4435 | 0 | CHECK_FLAG(flags, ZEBRA_FLAG_IBGP) ? "iBGP " : "", |
4436 | 0 | CHECK_FLAG(flags, ZEBRA_FLAG_SELECTED) ? "Selected " : "", |
4437 | 0 | CHECK_FLAG(flags, ZEBRA_FLAG_FIB_OVERRIDE) ? "Override " : "", |
4438 | 0 | CHECK_FLAG(flags, ZEBRA_FLAG_EVPN_ROUTE) ? "Evpn " : "", |
4439 | 0 | CHECK_FLAG(flags, ZEBRA_FLAG_RR_USE_DISTANCE) ? "RR Distance " |
4440 | 0 | : "", |
4441 | 0 | CHECK_FLAG(flags, ZEBRA_FLAG_TRAPPED) ? "Trapped " : "", |
4442 | 0 | CHECK_FLAG(flags, ZEBRA_FLAG_OFFLOADED) ? "Offloaded " : "", |
4443 | 0 | CHECK_FLAG(flags, ZEBRA_FLAG_OFFLOAD_FAILED) ? "Offload Failed " |
4444 | 0 | : ""); |
4445 | 0 | return buf; |
4446 | 0 | } |
4447 | | |
4448 | | char *zclient_evpn_dump_macip_flags(uint8_t flags, char *buf, size_t len) |
4449 | 0 | { |
4450 | 0 | if (flags == 0) { |
4451 | 0 | snprintfrr(buf, len, "None "); |
4452 | 0 | return buf; |
4453 | 0 | } |
4454 | | |
4455 | 0 | snprintfrr( |
4456 | 0 | buf, len, "%s%s%s%s%s%s%s", |
4457 | 0 | CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY) ? "Sticky MAC " : "", |
4458 | 0 | CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW) ? "Gateway MAC " : "", |
4459 | 0 | CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG) ? "Router " |
4460 | 0 | : "", |
4461 | 0 | CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_OVERRIDE_FLAG) ? "Override " |
4462 | 0 | : "", |
4463 | 0 | CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_SVI_IP) ? "SVI MAC " : "", |
4464 | 0 | CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT) ? "Proxy " |
4465 | 0 | : "", |
4466 | 0 | CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_SYNC_PATH) ? "Sync " : ""); |
4467 | |
|
4468 | 0 | return buf; |
4469 | 0 | } |
4470 | | |
4471 | | static int zclient_neigh_ip_read_entry(struct stream *s, struct ipaddr *add) |
4472 | 0 | { |
4473 | 0 | uint8_t family; |
4474 | |
|
4475 | 0 | STREAM_GETC(s, family); |
4476 | 0 | if (family != AF_INET && family != AF_INET6) |
4477 | 0 | return -1; |
4478 | | |
4479 | 0 | STREAM_GET(&add->ip.addr, s, family2addrsize(family)); |
4480 | 0 | add->ipa_type = family; |
4481 | 0 | return 0; |
4482 | 0 | stream_failure: |
4483 | 0 | return -1; |
4484 | 0 | } |
4485 | | |
4486 | | int zclient_neigh_ip_encode(struct stream *s, uint16_t cmd, union sockunion *in, |
4487 | | union sockunion *out, struct interface *ifp, |
4488 | | int ndm_state) |
4489 | 0 | { |
4490 | 0 | int ret = 0; |
4491 | |
|
4492 | 0 | zclient_create_header(s, cmd, ifp->vrf->vrf_id); |
4493 | 0 | stream_putc(s, sockunion_family(in)); |
4494 | 0 | stream_write(s, sockunion_get_addr(in), sockunion_get_addrlen(in)); |
4495 | 0 | if (out && sockunion_family(out) != AF_UNSPEC) { |
4496 | 0 | stream_putc(s, sockunion_family(out)); |
4497 | 0 | stream_write(s, sockunion_get_addr(out), |
4498 | 0 | sockunion_get_addrlen(out)); |
4499 | 0 | } else |
4500 | 0 | stream_putc(s, AF_UNSPEC); |
4501 | 0 | stream_putl(s, ifp->ifindex); |
4502 | 0 | if (out) |
4503 | 0 | stream_putl(s, ndm_state); |
4504 | 0 | else |
4505 | 0 | stream_putl(s, ZEBRA_NEIGH_STATE_FAILED); |
4506 | 0 | return ret; |
4507 | 0 | } |
4508 | | |
4509 | | int zclient_neigh_ip_decode(struct stream *s, struct zapi_neigh_ip *api) |
4510 | 0 | { |
4511 | 0 | int ret; |
4512 | |
|
4513 | 0 | ret = zclient_neigh_ip_read_entry(s, &api->ip_in); |
4514 | 0 | if (ret < 0) |
4515 | 0 | return -1; |
4516 | 0 | zclient_neigh_ip_read_entry(s, &api->ip_out); |
4517 | |
|
4518 | 0 | STREAM_GETL(s, api->index); |
4519 | 0 | STREAM_GETL(s, api->ndm_state); |
4520 | 0 | return 0; |
4521 | 0 | stream_failure: |
4522 | 0 | return -1; |
4523 | 0 | } |
4524 | | |
4525 | | int zclient_send_zebra_gre_request(struct zclient *client, |
4526 | | struct interface *ifp) |
4527 | 0 | { |
4528 | 0 | struct stream *s; |
4529 | |
|
4530 | 0 | if (!client || client->sock < 0) { |
4531 | 0 | zlog_err("%s : zclient not ready", __func__); |
4532 | 0 | return -1; |
4533 | 0 | } |
4534 | 0 | s = client->obuf; |
4535 | 0 | stream_reset(s); |
4536 | 0 | zclient_create_header(s, ZEBRA_GRE_GET, ifp->vrf->vrf_id); |
4537 | 0 | stream_putl(s, ifp->ifindex); |
4538 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
4539 | 0 | zclient_send_message(client); |
4540 | 0 | return 0; |
4541 | 0 | } |