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