/src/frr/pimd/pim_zlookup.c
Line | Count | Source |
1 | | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | | /* |
3 | | * PIM for Quagga |
4 | | * Copyright (C) 2008 Everton da Silva Marques |
5 | | */ |
6 | | |
7 | | #include <zebra.h> |
8 | | |
9 | | #include "log.h" |
10 | | #include "prefix.h" |
11 | | #include "zclient.h" |
12 | | #include "stream.h" |
13 | | #include "network.h" |
14 | | #include "frrevent.h" |
15 | | #include "prefix.h" |
16 | | #include "vty.h" |
17 | | #include "lib_errors.h" |
18 | | |
19 | | #include "pimd.h" |
20 | | #include "pim_instance.h" |
21 | | #include "pim_iface.h" |
22 | | #include "pim_neighbor.h" |
23 | | #include "pim_pim.h" |
24 | | #include "pim_str.h" |
25 | | #include "pim_oil.h" |
26 | | #include "pim_zlookup.h" |
27 | | #include "pim_addr.h" |
28 | | |
29 | | static struct zclient *zlookup = NULL; |
30 | | struct event *zlookup_read; |
31 | | |
32 | | static void zclient_lookup_sched(struct zclient *zlookup, int delay); |
33 | | static void zclient_lookup_read_pipe(struct event *thread); |
34 | | |
35 | | /* Connect to zebra for nexthop lookup. */ |
36 | | static void zclient_lookup_connect(struct event *t) |
37 | 0 | { |
38 | 0 | struct zclient *zlookup; |
39 | 0 |
|
40 | 0 | zlookup = EVENT_ARG(t); |
41 | 0 |
|
42 | 0 | if (zlookup->sock >= 0) { |
43 | 0 | return; |
44 | 0 | } |
45 | 0 |
|
46 | 0 | if (zclient_socket_connect(zlookup) < 0) { |
47 | 0 | ++zlookup->fail; |
48 | 0 | zlog_warn("%s: failure connecting zclient socket: failures=%d", |
49 | 0 | __func__, zlookup->fail); |
50 | 0 | } else { |
51 | 0 | zlookup->fail = 0; /* reset counter on connection */ |
52 | 0 | } |
53 | 0 |
|
54 | 0 | if (zclient_send_hello(zlookup) == ZCLIENT_SEND_FAILURE) { |
55 | 0 | if (close(zlookup->sock)) { |
56 | 0 | zlog_warn("%s: closing fd=%d: errno=%d %s", __func__, |
57 | 0 | zlookup->sock, errno, safe_strerror(errno)); |
58 | 0 | } |
59 | 0 | zlookup->sock = -1; |
60 | 0 | } |
61 | 0 |
|
62 | 0 | if (zlookup->sock < 0) { |
63 | 0 | /* Since last connect failed, retry within 10 secs */ |
64 | 0 | zclient_lookup_sched(zlookup, 10); |
65 | 0 | return; |
66 | 0 | } |
67 | 0 |
|
68 | 0 | event_add_timer(router->master, zclient_lookup_read_pipe, zlookup, 60, |
69 | 0 | &zlookup_read); |
70 | 0 | } |
71 | | |
72 | | /* Schedule connection with delay. */ |
73 | | static void zclient_lookup_sched(struct zclient *zlookup, int delay) |
74 | 0 | { |
75 | 0 | event_add_timer(router->master, zclient_lookup_connect, zlookup, delay, |
76 | 0 | &zlookup->t_connect); |
77 | 0 |
|
78 | 0 | zlog_notice("%s: zclient lookup connection scheduled for %d seconds", |
79 | 0 | __func__, delay); |
80 | 0 | } |
81 | | |
82 | | /* Schedule connection for now. */ |
83 | | static void zclient_lookup_sched_now(struct zclient *zlookup) |
84 | 83.3k | { |
85 | 83.3k | event_add_event(router->master, zclient_lookup_connect, zlookup, 0, |
86 | 83.3k | &zlookup->t_connect); |
87 | | |
88 | 83.3k | zlog_notice("%s: zclient lookup immediate connection scheduled", |
89 | 83.3k | __func__); |
90 | 83.3k | } |
91 | | |
92 | | /* Schedule reconnection, if needed. */ |
93 | | static void zclient_lookup_reconnect(struct zclient *zlookup) |
94 | 83.3k | { |
95 | 83.3k | if (zlookup->t_connect) { |
96 | 0 | return; |
97 | 0 | } |
98 | | |
99 | 83.3k | zclient_lookup_sched_now(zlookup); |
100 | 83.3k | } |
101 | | |
102 | | static void zclient_lookup_failed(struct zclient *zlookup) |
103 | 83.3k | { |
104 | 83.3k | if (zlookup->sock >= 0) { |
105 | 0 | if (close(zlookup->sock)) { |
106 | 0 | zlog_warn("%s: closing fd=%d: errno=%d %s", __func__, |
107 | 0 | zlookup->sock, errno, safe_strerror(errno)); |
108 | 0 | } |
109 | 0 | zlookup->sock = -1; |
110 | 0 | } |
111 | | |
112 | 83.3k | zclient_lookup_reconnect(zlookup); |
113 | 83.3k | } |
114 | | |
115 | | void zclient_lookup_free(void) |
116 | 0 | { |
117 | 0 | EVENT_OFF(zlookup_read); |
118 | 0 | zclient_stop(zlookup); |
119 | 0 | zclient_free(zlookup); |
120 | 0 | zlookup = NULL; |
121 | 0 | } |
122 | | |
123 | | void zclient_lookup_new(void) |
124 | 1 | { |
125 | 1 | struct zclient_options options = zclient_options_default; |
126 | 1 | options.synchronous = true; |
127 | | |
128 | 1 | zlookup = zclient_new(router->master, &options, NULL, 0); |
129 | 1 | if (!zlookup) { |
130 | 0 | flog_err(EC_LIB_ZAPI_SOCKET, "%s: zclient_new() failure", |
131 | 0 | __func__); |
132 | 0 | return; |
133 | 0 | } |
134 | | |
135 | 1 | zlookup->sock = -1; |
136 | 1 | zlookup->t_connect = NULL; |
137 | 1 | zlookup->privs = &pimd_privs; |
138 | | |
139 | 1 | zclient_lookup_sched_now(zlookup); |
140 | | |
141 | 1 | zlog_notice("%s: zclient lookup socket initialized", __func__); |
142 | 1 | } |
143 | | |
144 | | static int zclient_read_nexthop(struct pim_instance *pim, |
145 | | struct zclient *zlookup, |
146 | | struct pim_zlookup_nexthop nexthop_tab[], |
147 | | const int tab_size, pim_addr addr) |
148 | 0 | { |
149 | 0 | int num_ifindex = 0; |
150 | 0 | struct stream *s; |
151 | 0 | uint16_t length; |
152 | 0 | uint8_t marker; |
153 | 0 | uint8_t version; |
154 | 0 | vrf_id_t vrf_id; |
155 | 0 | uint16_t command = 0; |
156 | 0 | struct ipaddr raddr; |
157 | 0 | uint8_t distance; |
158 | 0 | uint32_t metric; |
159 | 0 | int nexthop_num; |
160 | 0 | int i, err; |
161 | |
|
162 | 0 | if (PIM_DEBUG_PIM_NHT_DETAIL) |
163 | 0 | zlog_debug("%s: addr=%pPAs(%s)", __func__, &addr, |
164 | 0 | pim->vrf->name); |
165 | |
|
166 | 0 | s = zlookup->ibuf; |
167 | |
|
168 | 0 | while (command != ZEBRA_NEXTHOP_LOOKUP_MRIB) { |
169 | 0 | stream_reset(s); |
170 | 0 | err = zclient_read_header(s, zlookup->sock, &length, &marker, |
171 | 0 | &version, &vrf_id, &command); |
172 | 0 | if (err < 0) { |
173 | 0 | flog_err(EC_LIB_ZAPI_MISSMATCH, |
174 | 0 | "%s: zclient_read_header() failed", __func__); |
175 | 0 | zclient_lookup_failed(zlookup); |
176 | 0 | return -1; |
177 | 0 | } |
178 | | |
179 | 0 | if (command == ZEBRA_ERROR) { |
180 | 0 | enum zebra_error_types error; |
181 | |
|
182 | 0 | zapi_error_decode(s, &error); |
183 | | /* Do nothing with it for now */ |
184 | 0 | return -1; |
185 | 0 | } |
186 | 0 | } |
187 | | |
188 | 0 | stream_get_ipaddr(s, &raddr); |
189 | |
|
190 | 0 | if (raddr.ipa_type != PIM_IPADDR || |
191 | 0 | pim_addr_cmp(raddr.ipaddr_pim, addr)) { |
192 | 0 | zlog_warn("%s: address mismatch: addr=%pPA(%s) raddr=%pIA", |
193 | 0 | __func__, &addr, pim->vrf->name, &raddr); |
194 | | /* warning only */ |
195 | 0 | } |
196 | |
|
197 | 0 | distance = stream_getc(s); |
198 | 0 | metric = stream_getl(s); |
199 | 0 | nexthop_num = stream_getc(s); |
200 | |
|
201 | 0 | if (nexthop_num < 1 || nexthop_num > router->multipath) { |
202 | 0 | if (PIM_DEBUG_PIM_NHT_DETAIL) |
203 | 0 | zlog_debug("%s: socket %d bad nexthop_num=%d", __func__, |
204 | 0 | zlookup->sock, nexthop_num); |
205 | 0 | return -6; |
206 | 0 | } |
207 | | |
208 | 0 | for (i = 0; i < nexthop_num; ++i) { |
209 | 0 | vrf_id_t nexthop_vrf_id; |
210 | 0 | enum nexthop_types_t nexthop_type; |
211 | 0 | struct in_addr nh_ip4; |
212 | 0 | struct in6_addr nh_ip6; |
213 | 0 | ifindex_t nh_ifi; |
214 | |
|
215 | 0 | nexthop_vrf_id = stream_getl(s); |
216 | 0 | nexthop_type = stream_getc(s); |
217 | 0 | if (num_ifindex >= tab_size) { |
218 | 0 | zlog_warn( |
219 | 0 | "%s: found too many nexthop ifindexes (%d > %d) for address %pPAs(%s)", |
220 | 0 | __func__, (num_ifindex + 1), tab_size, &addr, |
221 | 0 | pim->vrf->name); |
222 | 0 | return num_ifindex; |
223 | 0 | } |
224 | 0 | nexthop_tab[num_ifindex].protocol_distance = distance; |
225 | 0 | nexthop_tab[num_ifindex].route_metric = metric; |
226 | 0 | nexthop_tab[num_ifindex].vrf_id = nexthop_vrf_id; |
227 | 0 | switch (nexthop_type) { |
228 | 0 | case NEXTHOP_TYPE_IFINDEX: |
229 | 0 | nexthop_tab[num_ifindex].ifindex = stream_getl(s); |
230 | | /* |
231 | | * Connected route (i.e. no nexthop), use |
232 | | * address passed in as PIM nexthop. This will |
233 | | * allow us to work in cases where we are |
234 | | * trying to find a route for this box. |
235 | | */ |
236 | 0 | nexthop_tab[num_ifindex].nexthop_addr = addr; |
237 | 0 | ++num_ifindex; |
238 | 0 | break; |
239 | 0 | case NEXTHOP_TYPE_IPV4_IFINDEX: |
240 | 0 | case NEXTHOP_TYPE_IPV4: |
241 | 0 | nh_ip4.s_addr = stream_get_ipv4(s); |
242 | 0 | nh_ifi = stream_getl(s); |
243 | 0 | #if PIM_IPV == 4 |
244 | 0 | nexthop_tab[num_ifindex].nexthop_addr = nh_ip4; |
245 | 0 | nexthop_tab[num_ifindex].ifindex = nh_ifi; |
246 | 0 | ++num_ifindex; |
247 | | #else |
248 | | zlog_warn( |
249 | | "cannot use IPv4 nexthop %pI4(%d) for IPv6 %pPA", |
250 | | &nh_ip4, nh_ifi, &addr); |
251 | | #endif |
252 | 0 | break; |
253 | 0 | case NEXTHOP_TYPE_IPV6: |
254 | 0 | case NEXTHOP_TYPE_IPV6_IFINDEX: |
255 | 0 | stream_get(&nh_ip6, s, sizeof(nh_ip6)); |
256 | 0 | nh_ifi = stream_getl(s); |
257 | |
|
258 | | #if PIM_IPV == 6 |
259 | | nexthop_tab[num_ifindex].nexthop_addr = nh_ip6; |
260 | | nexthop_tab[num_ifindex].ifindex = nh_ifi; |
261 | | ++num_ifindex; |
262 | | #else |
263 | | /* RFC 5549 v4-over-v6 nexthop handling */ |
264 | | |
265 | | /* |
266 | | * If we are sending v6 secondary assume we receive v6 |
267 | | * secondary |
268 | | */ |
269 | 0 | struct interface *ifp = if_lookup_by_index( |
270 | 0 | nh_ifi, |
271 | 0 | nexthop_vrf_id); |
272 | |
|
273 | 0 | if (!ifp) |
274 | 0 | break; |
275 | | |
276 | 0 | struct pim_neighbor *nbr; |
277 | |
|
278 | 0 | if (pim->send_v6_secondary) { |
279 | 0 | struct prefix p; |
280 | |
|
281 | 0 | p.family = AF_INET6; |
282 | 0 | p.prefixlen = IPV6_MAX_BITLEN; |
283 | 0 | p.u.prefix6 = nh_ip6; |
284 | |
|
285 | 0 | nbr = pim_neighbor_find_by_secondary(ifp, &p); |
286 | 0 | } else |
287 | 0 | nbr = pim_neighbor_find_if(ifp); |
288 | |
|
289 | 0 | if (!nbr) |
290 | 0 | break; |
291 | | |
292 | 0 | nexthop_tab[num_ifindex].nexthop_addr = |
293 | 0 | nbr->source_addr; |
294 | 0 | nexthop_tab[num_ifindex].ifindex = nh_ifi; |
295 | 0 | ++num_ifindex; |
296 | 0 | #endif |
297 | 0 | break; |
298 | 0 | case NEXTHOP_TYPE_BLACKHOLE: |
299 | | /* do nothing */ |
300 | 0 | zlog_warn( |
301 | 0 | "%s: found non-ifindex nexthop type=%d for address %pPAs(%s)", |
302 | 0 | __func__, nexthop_type, &addr, pim->vrf->name); |
303 | 0 | break; |
304 | 0 | } |
305 | 0 | } |
306 | | |
307 | 0 | return num_ifindex; |
308 | 0 | } |
309 | | |
310 | | static int zclient_lookup_nexthop_once(struct pim_instance *pim, |
311 | | struct pim_zlookup_nexthop nexthop_tab[], |
312 | | const int tab_size, pim_addr addr) |
313 | 83.3k | { |
314 | 83.3k | struct stream *s; |
315 | 83.3k | int ret; |
316 | 83.3k | struct ipaddr ipaddr; |
317 | | |
318 | 83.3k | if (PIM_DEBUG_PIM_NHT_DETAIL) |
319 | 0 | zlog_debug("%s: addr=%pPAs(%s)", __func__, &addr, |
320 | 83.3k | pim->vrf->name); |
321 | | |
322 | | /* Check socket. */ |
323 | 83.3k | if (zlookup->sock < 0) { |
324 | 83.3k | flog_err(EC_LIB_ZAPI_SOCKET, |
325 | 83.3k | "%s: zclient lookup socket is not connected", |
326 | 83.3k | __func__); |
327 | 83.3k | zclient_lookup_failed(zlookup); |
328 | 83.3k | return -1; |
329 | 83.3k | } |
330 | | |
331 | 0 | if (pim->vrf->vrf_id == VRF_UNKNOWN) { |
332 | 0 | zlog_notice( |
333 | 0 | "%s: VRF: %s does not fully exist yet, delaying lookup", |
334 | 0 | __func__, pim->vrf->name); |
335 | 0 | return -1; |
336 | 0 | } |
337 | | |
338 | 0 | ipaddr.ipa_type = PIM_IPADDR; |
339 | 0 | ipaddr.ipaddr_pim = addr; |
340 | |
|
341 | 0 | s = zlookup->obuf; |
342 | 0 | stream_reset(s); |
343 | 0 | zclient_create_header(s, ZEBRA_NEXTHOP_LOOKUP_MRIB, pim->vrf->vrf_id); |
344 | 0 | stream_put_ipaddr(s, &ipaddr); |
345 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
346 | |
|
347 | 0 | ret = writen(zlookup->sock, s->data, stream_get_endp(s)); |
348 | 0 | if (ret < 0) { |
349 | 0 | flog_err( |
350 | 0 | EC_LIB_SOCKET, |
351 | 0 | "%s: writen() failure: %d writing to zclient lookup socket", |
352 | 0 | __func__, errno); |
353 | 0 | zclient_lookup_failed(zlookup); |
354 | 0 | return -2; |
355 | 0 | } |
356 | 0 | if (ret == 0) { |
357 | 0 | flog_err_sys(EC_LIB_SOCKET, |
358 | 0 | "%s: connection closed on zclient lookup socket", |
359 | 0 | __func__); |
360 | 0 | zclient_lookup_failed(zlookup); |
361 | 0 | return -3; |
362 | 0 | } |
363 | | |
364 | 0 | return zclient_read_nexthop(pim, zlookup, nexthop_tab, tab_size, addr); |
365 | 0 | } |
366 | | |
367 | | void zclient_lookup_read_pipe(struct event *thread) |
368 | 0 | { |
369 | 0 | struct zclient *zlookup = EVENT_ARG(thread); |
370 | 0 | struct pim_instance *pim = pim_get_pim_instance(VRF_DEFAULT); |
371 | 0 | struct pim_zlookup_nexthop nexthop_tab[10]; |
372 | 0 | pim_addr l = PIMADDR_ANY; |
373 | 0 |
|
374 | 0 | if (!pim) { |
375 | 0 | if (PIM_DEBUG_PIM_NHT_DETAIL) |
376 | 0 | zlog_debug("%s: Unable to find pim instance", __func__); |
377 | 0 | return; |
378 | 0 | } |
379 | 0 |
|
380 | 0 | zclient_lookup_nexthop_once(pim, nexthop_tab, 10, l); |
381 | 0 | event_add_timer(router->master, zclient_lookup_read_pipe, zlookup, 60, |
382 | 0 | &zlookup_read); |
383 | 0 | } |
384 | | |
385 | | int zclient_lookup_nexthop(struct pim_instance *pim, |
386 | | struct pim_zlookup_nexthop nexthop_tab[], |
387 | | const int tab_size, pim_addr addr, |
388 | | int max_lookup) |
389 | 83.3k | { |
390 | 83.3k | int lookup; |
391 | 83.3k | uint32_t route_metric = 0xFFFFFFFF; |
392 | 83.3k | uint8_t protocol_distance = 0xFF; |
393 | | |
394 | 83.3k | pim->nexthop_lookups++; |
395 | | |
396 | 83.3k | for (lookup = 0; lookup < max_lookup; ++lookup) { |
397 | 83.3k | int num_ifindex; |
398 | 83.3k | int first_ifindex; |
399 | 83.3k | pim_addr nexthop_addr; |
400 | | |
401 | 83.3k | num_ifindex = zclient_lookup_nexthop_once(pim, nexthop_tab, |
402 | 83.3k | tab_size, addr); |
403 | 83.3k | if (num_ifindex < 1) { |
404 | 83.3k | if (PIM_DEBUG_PIM_NHT_DETAIL) |
405 | 0 | zlog_debug( |
406 | 83.3k | "%s: lookup=%d/%d: could not find nexthop ifindex for address %pPA(%s)", |
407 | 83.3k | __func__, lookup, max_lookup, &addr, |
408 | 83.3k | pim->vrf->name); |
409 | 83.3k | return -1; |
410 | 83.3k | } |
411 | | |
412 | 0 | if (lookup < 1) { |
413 | | /* this is the non-recursive lookup - save original |
414 | | * metric/distance */ |
415 | 0 | route_metric = nexthop_tab[0].route_metric; |
416 | 0 | protocol_distance = nexthop_tab[0].protocol_distance; |
417 | 0 | } |
418 | | |
419 | | /* |
420 | | * FIXME: Non-recursive nexthop ensured only for first ifindex. |
421 | | * However, recursive route lookup should really be fixed in |
422 | | * zebra daemon. |
423 | | * See also TODO T24. |
424 | | * |
425 | | * So Zebra for NEXTHOP_TYPE_IPV4 returns the ifindex now since |
426 | | * it was being stored. This Doesn't solve all cases of |
427 | | * recursive lookup but for the most common types it does. |
428 | | */ |
429 | 0 | first_ifindex = nexthop_tab[0].ifindex; |
430 | 0 | nexthop_addr = nexthop_tab[0].nexthop_addr; |
431 | 0 | if (first_ifindex > 0) { |
432 | | /* found: first ifindex is non-recursive nexthop */ |
433 | |
|
434 | 0 | if (lookup > 0) { |
435 | | /* Report non-recursive success after first |
436 | | * lookup */ |
437 | 0 | if (PIM_DEBUG_PIM_NHT) |
438 | 0 | zlog_debug( |
439 | 0 | "%s: lookup=%d/%d: found non-recursive ifindex=%d for address %pPA(%s) dist=%d met=%d", |
440 | 0 | __func__, lookup, max_lookup, |
441 | 0 | first_ifindex, &addr, |
442 | 0 | pim->vrf->name, |
443 | 0 | nexthop_tab[0] |
444 | 0 | .protocol_distance, |
445 | 0 | nexthop_tab[0].route_metric); |
446 | | |
447 | | /* use last address as nexthop address */ |
448 | 0 | nexthop_tab[0].nexthop_addr = addr; |
449 | | |
450 | | /* report original route metric/distance */ |
451 | 0 | nexthop_tab[0].route_metric = route_metric; |
452 | 0 | nexthop_tab[0].protocol_distance = |
453 | 0 | protocol_distance; |
454 | 0 | } |
455 | |
|
456 | 0 | return num_ifindex; |
457 | 0 | } |
458 | | |
459 | 0 | if (PIM_DEBUG_PIM_NHT) |
460 | 0 | zlog_debug( |
461 | 0 | "%s: lookup=%d/%d: zebra returned recursive nexthop %pPAs for address %pPA(%s) dist=%d met=%d", |
462 | 0 | __func__, lookup, max_lookup, &nexthop_addr, |
463 | 0 | &addr, pim->vrf->name, |
464 | 0 | nexthop_tab[0].protocol_distance, |
465 | 0 | nexthop_tab[0].route_metric); |
466 | |
|
467 | 0 | addr = nexthop_addr; /* use nexthop |
468 | | addr for recursive lookup */ |
469 | |
|
470 | 0 | } /* for (max_lookup) */ |
471 | | |
472 | 0 | if (PIM_DEBUG_PIM_NHT) |
473 | 0 | zlog_warn( |
474 | 0 | "%s: lookup=%d/%d: failure searching recursive nexthop ifindex for address %pPA(%s)", |
475 | 0 | __func__, lookup, max_lookup, &addr, pim->vrf->name); |
476 | |
|
477 | 0 | return -2; |
478 | 83.3k | } |
479 | | |
480 | | void pim_zlookup_show_ip_multicast(struct vty *vty) |
481 | 0 | { |
482 | 0 | vty_out(vty, "Zclient lookup socket: "); |
483 | 0 | if (zlookup) { |
484 | 0 | vty_out(vty, "%d failures=%d\n", zlookup->sock, zlookup->fail); |
485 | 0 | } else { |
486 | 0 | vty_out(vty, "<null zclient>\n"); |
487 | 0 | } |
488 | 0 | } |
489 | | |
490 | | int pim_zlookup_sg_statistics(struct channel_oil *c_oil) |
491 | 0 | { |
492 | 0 | struct stream *s = zlookup->obuf; |
493 | 0 | uint16_t command = 0; |
494 | 0 | unsigned long long lastused; |
495 | 0 | pim_sgaddr sg; |
496 | 0 | int count = 0; |
497 | 0 | int ret; |
498 | 0 | pim_sgaddr more = {}; |
499 | 0 | struct interface *ifp = |
500 | 0 | pim_if_find_by_vif_index(c_oil->pim, *oil_parent(c_oil)); |
501 | |
|
502 | 0 | if (PIM_DEBUG_ZEBRA) { |
503 | 0 | more.src = *oil_origin(c_oil); |
504 | 0 | more.grp = *oil_mcastgrp(c_oil); |
505 | 0 | zlog_debug( |
506 | 0 | "Sending Request for New Channel Oil Information%pSG VIIF %d(%s)", |
507 | 0 | &more, *oil_parent(c_oil), c_oil->pim->vrf->name); |
508 | 0 | } |
509 | |
|
510 | 0 | if (!ifp) |
511 | 0 | return -1; |
512 | | |
513 | 0 | stream_reset(s); |
514 | 0 | zclient_create_header(s, ZEBRA_IPMR_ROUTE_STATS, |
515 | 0 | c_oil->pim->vrf->vrf_id); |
516 | 0 | stream_putl(s, PIM_AF); |
517 | 0 | stream_write(s, oil_origin(c_oil), sizeof(pim_addr)); |
518 | 0 | stream_write(s, oil_mcastgrp(c_oil), sizeof(pim_addr)); |
519 | 0 | stream_putl(s, ifp->ifindex); |
520 | 0 | stream_putw_at(s, 0, stream_get_endp(s)); |
521 | |
|
522 | 0 | count = stream_get_endp(s); |
523 | 0 | ret = writen(zlookup->sock, s->data, count); |
524 | 0 | if (ret <= 0) { |
525 | 0 | flog_err( |
526 | 0 | EC_LIB_SOCKET, |
527 | 0 | "%s: writen() failure: %d writing to zclient lookup socket", |
528 | 0 | __func__, errno); |
529 | 0 | return -1; |
530 | 0 | } |
531 | | |
532 | 0 | s = zlookup->ibuf; |
533 | |
|
534 | 0 | while (command != ZEBRA_IPMR_ROUTE_STATS) { |
535 | 0 | int err; |
536 | 0 | uint16_t length = 0; |
537 | 0 | vrf_id_t vrf_id; |
538 | 0 | uint8_t marker; |
539 | 0 | uint8_t version; |
540 | |
|
541 | 0 | stream_reset(s); |
542 | 0 | err = zclient_read_header(s, zlookup->sock, &length, &marker, |
543 | 0 | &version, &vrf_id, &command); |
544 | 0 | if (err < 0) { |
545 | 0 | flog_err(EC_LIB_ZAPI_MISSMATCH, |
546 | 0 | "%s: zclient_read_header() failed", __func__); |
547 | 0 | zclient_lookup_failed(zlookup); |
548 | 0 | return -1; |
549 | 0 | } |
550 | 0 | } |
551 | | |
552 | 0 | stream_get(&sg.src, s, sizeof(pim_addr)); |
553 | 0 | stream_get(&sg.grp, s, sizeof(pim_addr)); |
554 | |
|
555 | 0 | more.src = *oil_origin(c_oil); |
556 | 0 | more.grp = *oil_mcastgrp(c_oil); |
557 | 0 | if (pim_sgaddr_cmp(sg, more)) { |
558 | 0 | if (PIM_DEBUG_ZEBRA) |
559 | 0 | flog_err( |
560 | 0 | EC_LIB_ZAPI_MISSMATCH, |
561 | 0 | "%s: Received wrong %pSG(%s) information requested", |
562 | 0 | __func__, &more, c_oil->pim->vrf->name); |
563 | 0 | zclient_lookup_failed(zlookup); |
564 | 0 | return -3; |
565 | 0 | } |
566 | | |
567 | 0 | stream_get(&lastused, s, sizeof(lastused)); |
568 | | /* signed success value from netlink_talk; currently unused */ |
569 | 0 | (void)stream_getl(s); |
570 | |
|
571 | 0 | c_oil->cc.lastused = lastused; |
572 | |
|
573 | 0 | return 0; |
574 | 0 | } |