]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_zlookup.c
pimd: Fix various sizeof and buffer length issues
[mirror_frr.git] / pimd / pim_zlookup.c
CommitLineData
12e41d03
DL
1/*
2 PIM for Quagga
3 Copyright (C) 2008 Everton da Silva Marques
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; see the file COPYING; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
18 MA 02110-1301 USA
12e41d03
DL
19*/
20
21#include <zebra.h>
22#include "zebra/rib.h"
23
24#include "log.h"
25#include "prefix.h"
26#include "zclient.h"
27#include "stream.h"
28#include "network.h"
29#include "thread.h"
e3be0432 30#include "prefix.h"
05b0d0d0 31#include "vty.h"
12e41d03
DL
32
33#include "pimd.h"
e3be0432 34#include "pim_iface.h"
12e41d03
DL
35#include "pim_pim.h"
36#include "pim_str.h"
e3be0432 37#include "pim_oil.h"
12e41d03
DL
38#include "pim_zlookup.h"
39
05b0d0d0
DS
40static struct zclient *zlookup = NULL;
41
12e41d03
DL
42static void zclient_lookup_sched(struct zclient *zlookup, int delay);
43
44/* Connect to zebra for nexthop lookup. */
45static int zclient_lookup_connect(struct thread *t)
46{
47 struct zclient *zlookup;
48
49 zlookup = THREAD_ARG(t);
50 zlookup->t_connect = NULL;
51
52 if (zlookup->sock >= 0) {
53 return 0;
54 }
55
56 if (zclient_socket_connect(zlookup) < 0) {
57 ++zlookup->fail;
58 zlog_warn("%s: failure connecting zclient socket: failures=%d",
59 __PRETTY_FUNCTION__, zlookup->fail);
60 }
61 else {
62 zlookup->fail = 0; /* reset counter on connection */
63 }
64
65 zassert(!zlookup->t_connect);
66 if (zlookup->sock < 0) {
67 /* Since last connect failed, retry within 10 secs */
68 zclient_lookup_sched(zlookup, 10);
69 return -1;
70 }
71
72 return 0;
73}
74
75/* Schedule connection with delay. */
76static void zclient_lookup_sched(struct zclient *zlookup, int delay)
77{
78 zassert(!zlookup->t_connect);
79
80 THREAD_TIMER_ON(master, zlookup->t_connect,
81 zclient_lookup_connect,
82 zlookup, delay);
83
84 zlog_notice("%s: zclient lookup connection scheduled for %d seconds",
85 __PRETTY_FUNCTION__, delay);
86}
87
88/* Schedule connection for now. */
89static void zclient_lookup_sched_now(struct zclient *zlookup)
90{
91 zassert(!zlookup->t_connect);
92
93 zlookup->t_connect = thread_add_event(master, zclient_lookup_connect,
94 zlookup, 0);
95
96 zlog_notice("%s: zclient lookup immediate connection scheduled",
97 __PRETTY_FUNCTION__);
98}
99
100/* Schedule reconnection, if needed. */
101static void zclient_lookup_reconnect(struct zclient *zlookup)
102{
103 if (zlookup->t_connect) {
104 return;
105 }
106
107 zclient_lookup_sched_now(zlookup);
108}
109
110static void zclient_lookup_failed(struct zclient *zlookup)
111{
112 if (zlookup->sock >= 0) {
113 if (close(zlookup->sock)) {
114 zlog_warn("%s: closing fd=%d: errno=%d %s", __func__, zlookup->sock,
115 errno, safe_strerror(errno));
116 }
117 zlookup->sock = -1;
118 }
119
120 zclient_lookup_reconnect(zlookup);
121}
122
0b6817c5
DS
123void
124zclient_lookup_free (void)
125{
126 zclient_free (zlookup);
127 zlookup = NULL;
128}
129
05b0d0d0
DS
130void
131zclient_lookup_new (void)
12e41d03 132{
469351b3 133 zlookup = zclient_new (master);
12e41d03
DL
134 if (!zlookup) {
135 zlog_err("%s: zclient_new() failure",
136 __PRETTY_FUNCTION__);
05b0d0d0 137 return;
12e41d03
DL
138 }
139
140 zlookup->sock = -1;
0b6817c5 141 zlookup->t_connect = NULL;
12e41d03
DL
142
143 zclient_lookup_sched_now(zlookup);
144
145 zlog_notice("%s: zclient lookup socket initialized",
146 __PRETTY_FUNCTION__);
147
12e41d03
DL
148}
149
150static int zclient_read_nexthop(struct zclient *zlookup,
151 struct pim_zlookup_nexthop nexthop_tab[],
152 const int tab_size,
153 struct in_addr addr)
154{
155 int num_ifindex = 0;
156 struct stream *s;
55119089
ND
157 const uint16_t MIN_LEN = 10; /* getipv4=4 getc=1 getl=4 getc=1 */
158 uint16_t length;
12e41d03
DL
159 u_char marker;
160 u_char version;
e7a2870b 161 vrf_id_t vrf_id;
78d3e257 162 uint16_t command = 0;
12e41d03
DL
163 struct in_addr raddr;
164 uint8_t distance;
165 uint32_t metric;
166 int nexthop_num;
55119089 167 int i, err;
12e41d03 168
802b226c 169 if (PIM_DEBUG_PIM_TRACE_DETAIL) {
eaa54bdb 170 char addr_str[INET_ADDRSTRLEN];
12e41d03
DL
171 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
172 zlog_debug("%s: addr=%s",
173 __PRETTY_FUNCTION__,
174 addr_str);
175 }
176
177 s = zlookup->ibuf;
12e41d03 178
78d3e257
DS
179 while (command != ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB)
180 {
181 stream_reset(s);
182 err = zclient_read_header (s, zlookup->sock, &length, &marker, &version,
183 &vrf_id, &command);
184 if (err < 0) {
185 zlog_err("%s %s: zclient_read_header() failed",
186 __FILE__, __PRETTY_FUNCTION__);
187 zclient_lookup_failed(zlookup);
188 return -1;
189 }
190
191 if (length < MIN_LEN) {
192 zlog_err("%s %s: failure reading zclient lookup socket: len=%d < MIN_LEN=%d",
193 __FILE__, __PRETTY_FUNCTION__, length, MIN_LEN);
194 zclient_lookup_failed(zlookup);
195 return -2;
196 }
78d3e257 197 }
12e41d03
DL
198
199 raddr.s_addr = stream_get_ipv4(s);
200
201 if (raddr.s_addr != addr.s_addr) {
eaa54bdb
DW
202 char addr_str[INET_ADDRSTRLEN];
203 char raddr_str[INET_ADDRSTRLEN];
12e41d03
DL
204 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
205 pim_inet4_dump("<raddr?>", raddr, raddr_str, sizeof(raddr_str));
206 zlog_warn("%s: address mismatch: addr=%s raddr=%s",
207 __PRETTY_FUNCTION__,
208 addr_str, raddr_str);
209 /* warning only */
210 }
211
212 distance = stream_getc(s);
213 metric = stream_getl(s);
214 nexthop_num = stream_getc(s);
215
216 if (nexthop_num < 1) {
217 zlog_err("%s: socket %d bad nexthop_num=%d",
218 __func__, zlookup->sock, nexthop_num);
219 return -6;
220 }
221
12e41d03
DL
222 for (i = 0; i < nexthop_num; ++i) {
223 enum nexthop_types_t nexthop_type;
12c7b75b 224 struct pim_neighbor *nbr;
eeff6d3f 225 struct prefix p;
12e41d03 226
12e41d03 227 nexthop_type = stream_getc(s);
84a35fdf 228 if (num_ifindex >= tab_size) {
eaa54bdb 229 char addr_str[INET_ADDRSTRLEN];
84a35fdf
DS
230 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
231 zlog_warn("%s %s: found too many nexthop ifindexes (%d > %d) for address %s",
232 __FILE__, __PRETTY_FUNCTION__,
233 (num_ifindex + 1), tab_size, addr_str);
234 return num_ifindex;
235 }
12e41d03 236 switch (nexthop_type) {
5b30316e
DS
237 case NEXTHOP_TYPE_IFINDEX:
238 case NEXTHOP_TYPE_IPV4_IFINDEX:
d4a2bc11 239 case NEXTHOP_TYPE_IPV4:
ba634917 240 nexthop_tab[num_ifindex].nexthop_addr.family = AF_INET;
d4a2bc11
DS
241 if (nexthop_type == NEXTHOP_TYPE_IPV4_IFINDEX ||
242 nexthop_type == NEXTHOP_TYPE_IPV4) {
ba634917 243 nexthop_tab[num_ifindex].nexthop_addr.u.prefix4.s_addr = stream_get_ipv4(s);
12e41d03
DL
244 }
245 else {
ba634917 246 nexthop_tab[num_ifindex].nexthop_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
12e41d03
DL
247 }
248 nexthop_tab[num_ifindex].ifindex = stream_getl(s);
249 nexthop_tab[num_ifindex].protocol_distance = distance;
250 nexthop_tab[num_ifindex].route_metric = metric;
251 ++num_ifindex;
252 break;
12c7b75b
DS
253 case NEXTHOP_TYPE_IPV6_IFINDEX:
254 nexthop_tab[num_ifindex].nexthop_addr.family = AF_INET6;
4390fb99
DS
255 stream_get (&nexthop_tab[num_ifindex].nexthop_addr.u.prefix6,
256 s,
257 sizeof(struct in6_addr));
12c7b75b 258 nexthop_tab[num_ifindex].ifindex = stream_getl (s);
eeff6d3f
DS
259
260 p.family = AF_INET6;
261 p.prefixlen = IPV6_MAX_PREFIXLEN;
4390fb99
DS
262 memcpy (&p.u.prefix6,
263 &nexthop_tab[num_ifindex].nexthop_addr.u.prefix6,
264 sizeof(struct in6_addr));
eeff6d3f
DS
265
266 /*
267 * If we are sending v6 secondary assume we receive v6 secondary
268 */
269 if (pimg->send_v6_secondary)
270 nbr = pim_neighbor_find_by_secondary(if_lookup_by_index (nexthop_tab[num_ifindex].ifindex, VRF_DEFAULT), &p);
271 else
272 nbr = pim_neighbor_find_if (if_lookup_by_index (nexthop_tab[num_ifindex].ifindex, VRF_DEFAULT));
12c7b75b
DS
273 if (nbr)
274 {
275 nexthop_tab[num_ifindex].nexthop_addr.family = AF_INET;
276 nexthop_tab[num_ifindex].nexthop_addr.u.prefix4 = nbr->source_addr;
277 }
278 ++num_ifindex;
279 break;
12e41d03
DL
280 default:
281 /* do nothing */
282 {
eaa54bdb 283 char addr_str[INET_ADDRSTRLEN];
12e41d03
DL
284 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
285 zlog_warn("%s %s: found non-ifindex nexthop type=%d for address %s",
286 __FILE__, __PRETTY_FUNCTION__,
287 nexthop_type, addr_str);
288 }
289 break;
290 }
291 }
292
293 return num_ifindex;
294}
295
05b0d0d0
DS
296static int
297zclient_lookup_nexthop_once (struct pim_zlookup_nexthop nexthop_tab[],
298 const int tab_size,
299 struct in_addr addr)
12e41d03
DL
300{
301 struct stream *s;
302 int ret;
303
802b226c 304 if (PIM_DEBUG_PIM_TRACE_DETAIL) {
eaa54bdb 305 char addr_str[INET_ADDRSTRLEN];
12e41d03
DL
306 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
307 zlog_debug("%s: addr=%s",
308 __PRETTY_FUNCTION__,
309 addr_str);
310 }
311
312 /* Check socket. */
313 if (zlookup->sock < 0) {
314 zlog_err("%s %s: zclient lookup socket is not connected",
315 __FILE__, __PRETTY_FUNCTION__);
316 zclient_lookup_failed(zlookup);
317 return -1;
318 }
319
320 s = zlookup->obuf;
321 stream_reset(s);
469351b3 322 zclient_create_header(s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB, VRF_DEFAULT);
12e41d03
DL
323 stream_put_in_addr(s, &addr);
324 stream_putw_at(s, 0, stream_get_endp(s));
325
326 ret = writen(zlookup->sock, s->data, stream_get_endp(s));
327 if (ret < 0) {
5f8fec87
DS
328 zlog_err("%s %s: writen() failure: %d writing to zclient lookup socket",
329 __FILE__, __PRETTY_FUNCTION__, errno);
12e41d03
DL
330 zclient_lookup_failed(zlookup);
331 return -2;
332 }
333 if (ret == 0) {
334 zlog_err("%s %s: connection closed on zclient lookup socket",
335 __FILE__, __PRETTY_FUNCTION__);
336 zclient_lookup_failed(zlookup);
337 return -3;
338 }
339
340 return zclient_read_nexthop(zlookup, nexthop_tab,
341 tab_size, addr);
342}
343
05b0d0d0
DS
344int
345zclient_lookup_nexthop (struct pim_zlookup_nexthop nexthop_tab[],
346 const int tab_size,
347 struct in_addr addr,
348 int max_lookup)
12e41d03
DL
349{
350 int lookup;
351 uint32_t route_metric = 0xFFFFFFFF;
352 uint8_t protocol_distance = 0xFF;
353
284b4301
DS
354 qpim_nexthop_lookups++;
355
12e41d03
DL
356 for (lookup = 0; lookup < max_lookup; ++lookup) {
357 int num_ifindex;
358 int first_ifindex;
ba634917 359 struct prefix nexthop_addr;
12e41d03 360
05b0d0d0 361 num_ifindex = zclient_lookup_nexthop_once(nexthop_tab,
7b2c4d16 362 tab_size, addr);
d5a0a629
DS
363 if (num_ifindex < 1) {
364 if (PIM_DEBUG_ZEBRA) {
eaa54bdb 365 char addr_str[INET_ADDRSTRLEN];
d5a0a629
DS
366 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
367 zlog_debug("%s %s: lookup=%d/%d: could not find nexthop ifindex for address %s",
368 __FILE__, __PRETTY_FUNCTION__,
369 lookup, max_lookup, addr_str);
370 }
12e41d03
DL
371 return -1;
372 }
373
374 if (lookup < 1) {
375 /* this is the non-recursive lookup - save original metric/distance */
376 route_metric = nexthop_tab[0].route_metric;
377 protocol_distance = nexthop_tab[0].protocol_distance;
378 }
379
380 /*
d8ba2f4a
DS
381 * FIXME: Non-recursive nexthop ensured only for first ifindex.
382 * However, recursive route lookup should really be fixed in zebra daemon.
383 * See also TODO T24.
384 *
385 * So Zebra for NEXTHOP_TYPE_IPV4 returns the ifindex now since
386 * it was being stored. This Doesn't solve all cases of
387 * recursive lookup but for the most common types it does.
12e41d03
DL
388 */
389 first_ifindex = nexthop_tab[0].ifindex;
390 nexthop_addr = nexthop_tab[0].nexthop_addr;
391 if (first_ifindex > 0) {
392 /* found: first ifindex is non-recursive nexthop */
393
d5a0a629 394 if (lookup > 0) {
12e41d03 395 /* Report non-recursive success after first lookup */
d5a0a629 396 if (PIM_DEBUG_ZEBRA) {
eaa54bdb 397 char addr_str[INET_ADDRSTRLEN];
d5a0a629
DS
398 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
399 zlog_debug("%s %s: lookup=%d/%d: found non-recursive ifindex=%d for address %s dist=%d met=%d",
400 __FILE__, __PRETTY_FUNCTION__,
401 lookup, max_lookup, first_ifindex, addr_str,
402 nexthop_tab[0].protocol_distance,
403 nexthop_tab[0].route_metric);
404 }
12e41d03
DL
405
406 /* use last address as nexthop address */
ba634917 407 nexthop_tab[0].nexthop_addr.u.prefix4 = addr;
12e41d03
DL
408
409 /* report original route metric/distance */
410 nexthop_tab[0].route_metric = route_metric;
411 nexthop_tab[0].protocol_distance = protocol_distance;
412 }
413
414 return num_ifindex;
415 }
416
7adf0260 417 if (PIM_DEBUG_ZEBRA) {
eaa54bdb
DW
418 char addr_str[INET_ADDRSTRLEN];
419 char nexthop_str[PREFIX_STRLEN];
12e41d03 420 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
ba634917 421 pim_addr_dump("<nexthop?>", &nexthop_addr, nexthop_str, sizeof(nexthop_str));
7adf0260 422 zlog_debug("%s %s: lookup=%d/%d: zebra returned recursive nexthop %s for address %s dist=%d met=%d",
12e41d03
DL
423 __FILE__, __PRETTY_FUNCTION__,
424 lookup, max_lookup, nexthop_str, addr_str,
425 nexthop_tab[0].protocol_distance,
426 nexthop_tab[0].route_metric);
427 }
428
ba634917 429 addr = nexthop_addr.u.prefix4; /* use nexthop addr for recursive lookup */
12e41d03
DL
430
431 } /* for (max_lookup) */
432
7adf0260 433 if (PIM_DEBUG_ZEBRA) {
eaa54bdb 434 char addr_str[INET_ADDRSTRLEN];
7adf0260
DS
435 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
436 zlog_warn("%s %s: lookup=%d/%d: failure searching recursive nexthop ifindex for address %s",
437 __FILE__, __PRETTY_FUNCTION__,
438 lookup, max_lookup, addr_str);
439 }
12e41d03
DL
440
441 return -2;
442}
05b0d0d0
DS
443
444void
445pim_zlookup_show_ip_multicast (struct vty *vty)
446{
447 vty_out(vty, "Zclient lookup socket: ");
448 if (zlookup) {
449 vty_out(vty, "%d failures=%d%s", zlookup->sock,
450 zlookup->fail, VTY_NEWLINE);
451 }
452 else {
453 vty_out(vty, "<null zclient>%s", VTY_NEWLINE);
454 }
455}
e3be0432
DS
456
457int
458pim_zlookup_sg_statistics (struct channel_oil *c_oil)
459{
460 struct stream *s = zlookup->obuf;
461 uint16_t command = 0;
462 unsigned long long lastused;
463 struct prefix_sg sg;
464 int count = 0;
465 int ret;
466 struct interface *ifp = pim_if_find_by_vif_index (c_oil->oil.mfcc_parent);
467
468 if (PIM_DEBUG_ZEBRA)
c7b1183f
DS
469 {
470 struct prefix_sg more;
471
472 more.src = c_oil->oil.mfcc_origin;
473 more.grp = c_oil->oil.mfcc_mcastgrp;
429a291b
CS
474 zlog_debug ("Sending Request for New Channel Oil Information(%s) VIIF %d",
475 pim_str_sg_dump (&more), c_oil->oil.mfcc_parent);
c7b1183f 476 }
e3be0432 477
d1b64e31
DS
478 if (!ifp)
479 return -1;
480
e3be0432
DS
481 stream_reset (s);
482 zclient_create_header (s, ZEBRA_IPMR_ROUTE_STATS, VRF_DEFAULT);
483 stream_put_in_addr (s, &c_oil->oil.mfcc_origin);
484 stream_put_in_addr (s, &c_oil->oil.mfcc_mcastgrp);
485 stream_putl (s, ifp->ifindex);
486 stream_putw_at(s, 0, stream_get_endp(s));
487
488 count = stream_get_endp (s);
489 ret = writen (zlookup->sock, s->data, count);
490 if (ret <= 0)
491 {
5f8fec87
DS
492 zlog_err("%s %s: writen() failure: %d writing to zclient lookup socket",
493 __FILE__, __PRETTY_FUNCTION__, errno);
e3be0432
DS
494 return -1;
495 }
496
497 s = zlookup->ibuf;
498
499 while (command != ZEBRA_IPMR_ROUTE_STATS)
500 {
501 int err;
502 uint16_t length = 0;
503 vrf_id_t vrf_id;
504 u_char marker;
505 u_char version;
506
507 stream_reset (s);
508 err = zclient_read_header (s, zlookup->sock, &length, &marker, &version,
509 &vrf_id, &command);
510 if (err < 0)
511 {
512 zlog_err ("%s %s: zclient_read_header() failed",
513 __FILE__, __PRETTY_FUNCTION__);
514 zclient_lookup_failed(zlookup);
515 return -1;
516 }
517 }
518
519 sg.src.s_addr = stream_get_ipv4 (s);
520 sg.grp.s_addr = stream_get_ipv4 (s);
521 if (sg.src.s_addr != c_oil->oil.mfcc_origin.s_addr ||
522 sg.grp.s_addr != c_oil->oil.mfcc_mcastgrp.s_addr)
523 {
524 zlog_err ("%s: Received wrong %s information",
525 __PRETTY_FUNCTION__, pim_str_sg_dump (&sg));
526 zclient_lookup_failed (zlookup);
527 return -3;
528 }
529
530 stream_get (&lastused, s, sizeof (lastused));
9a5aa742 531 ret = stream_getl (s);
e3be0432 532
8d63c2d9 533 if (PIM_DEBUG_ZEBRA)
9a5aa742 534 zlog_debug ("Received %lld for %s success: %d", lastused, pim_str_sg_dump (&sg), ret);
e3be0432
DS
535
536 c_oil->cc.lastused = lastused;
537
538 return 0;
539
540}