]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_fpm_netlink.c
pimd: Removing impossible code
[mirror_frr.git] / zebra / zebra_fpm_netlink.c
CommitLineData
5adc2528
AS
1/*
2 * Code for encoding/decoding FPM messages that are in netlink format.
3 *
4 * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
5 * Copyright (C) 2012 by Open Source Routing.
6 * Copyright (C) 2012 by Internet Systems Consortium, Inc. ("ISC")
7 *
8 * This file is part of GNU Zebra.
9 *
10 * GNU Zebra is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2, or (at your option) any
13 * later version.
14 *
15 * GNU Zebra is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with GNU Zebra; see the file COPYING. If not, write to the Free
22 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
23 * 02111-1307, USA.
24 */
25
26#include <zebra.h>
27
28#include "log.h"
29#include "rib.h"
82f97584 30#include "vty.h"
e3be0432 31#include "prefix.h"
5adc2528 32
1fdc9eae 33#include "zebra/zserv.h"
34#include "zebra/zebra_ns.h"
35#include "zebra/zebra_vrf.h"
36#include "zebra/kernel_netlink.h"
37#include "zebra/rt_netlink.h"
fb018d25 38#include "nexthop.h"
5adc2528 39
1fdc9eae 40#include "zebra/zebra_fpm_private.h"
5adc2528
AS
41
42/*
43 * addr_to_a
44 *
45 * Returns string representation of an address of the given AF.
46 */
47static inline const char *
48addr_to_a (u_char af, void *addr)
49{
50 if (!addr)
51 return "<No address>";
52
53 switch (af)
54 {
55
56 case AF_INET:
57 return inet_ntoa (*((struct in_addr *) addr));
58
59#ifdef HAVE_IPV6
60 case AF_INET6:
61 return inet6_ntoa (*((struct in6_addr *) addr));
62#endif
63
64 default:
65 return "<Addr in unknown AF>";
66 }
67}
68
69/*
70 * prefix_addr_to_a
71 *
72 * Convience wrapper that returns a human-readable string for the
73 * address in a prefix.
74 */
75static const char *
76prefix_addr_to_a (struct prefix *prefix)
77{
78 if (!prefix)
79 return "<No address>";
80
81 return addr_to_a (prefix->family, &prefix->u.prefix);
82}
83
84/*
85 * af_addr_size
86 *
87 * The size of an address in a given address family.
88 */
89static size_t
90af_addr_size (u_char af)
91{
92 switch (af)
93 {
94
95 case AF_INET:
96 return 4;
97
98#ifdef HAVE_IPV6
99 case AF_INET6:
100 return 16;
101#endif
102
103 default:
104 assert(0);
105 return 16;
106 }
107}
108
109/*
110 * netlink_nh_info_t
111 *
112 * Holds information about a single nexthop for netlink. These info
113 * structures are transient and may contain pointers into rib
114 * data structures for convenience.
115 */
116typedef struct netlink_nh_info_t_
117{
118 uint32_t if_index;
119 union g_addr *gateway;
120
121 /*
122 * Information from the struct nexthop from which this nh was
123 * derived. For debug purposes only.
124 */
125 int recursive;
126 enum nexthop_types_t type;
127} netlink_nh_info_t;
128
129/*
130 * netlink_route_info_t
131 *
132 * A structure for holding information for a netlink route message.
133 */
134typedef struct netlink_route_info_t_
135{
136 uint16_t nlmsg_type;
137 u_char rtm_type;
138 uint32_t rtm_table;
139 u_char rtm_protocol;
140 u_char af;
141 struct prefix *prefix;
142 uint32_t *metric;
143 int num_nhs;
144
145 /*
7c5d2b76 146 * Nexthop structures
5adc2528 147 */
7c5d2b76 148 netlink_nh_info_t nhs[MULTIPATH_NUM];
5adc2528
AS
149 union g_addr *pref_src;
150} netlink_route_info_t;
151
152/*
153 * netlink_route_info_add_nh
154 *
155 * Add information about the given nexthop to the given route info
156 * structure.
157 *
158 * Returns TRUE if a nexthop was added, FALSE otherwise.
159 */
160static int
fa713d9e
CF
161netlink_route_info_add_nh (netlink_route_info_t *ri, struct nexthop *nexthop,
162 int recursive)
5adc2528
AS
163{
164 netlink_nh_info_t nhi;
165 union g_addr *src;
166
167 memset (&nhi, 0, sizeof (nhi));
168 src = NULL;
169
170 if (ri->num_nhs >= (int) ZEBRA_NUM_OF (ri->nhs))
171 return 0;
172
fa713d9e 173 nhi.recursive = recursive;
5adc2528 174 nhi.type = nexthop->type;
324ed1f8 175 nhi.if_index = nexthop->ifindex;
5adc2528
AS
176
177 if (nexthop->type == NEXTHOP_TYPE_IPV4
178 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
179 {
180 nhi.gateway = &nexthop->gate;
181 if (nexthop->src.ipv4.s_addr)
182 src = &nexthop->src;
183 }
184
5adc2528 185 if (nexthop->type == NEXTHOP_TYPE_IPV6
5adc2528
AS
186 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
187 {
188 nhi.gateway = &nexthop->gate;
189 }
324ed1f8 190
3ee39b5b 191 if (nexthop->type == NEXTHOP_TYPE_IFINDEX)
5adc2528 192 {
5adc2528
AS
193 if (nexthop->src.ipv4.s_addr)
194 src = &nexthop->src;
195 }
5adc2528 196
5adc2528
AS
197 if (!nhi.gateway && nhi.if_index == 0)
198 return 0;
199
200 /*
201 * We have a valid nhi. Copy the structure over to the route_info.
202 */
203 ri->nhs[ri->num_nhs] = nhi;
204 ri->num_nhs++;
205
206 if (src && !ri->pref_src)
207 ri->pref_src = src;
208
209 return 1;
210}
211
212/*
213 * netlink_proto_from_route_type
214 */
215static u_char
216netlink_proto_from_route_type (int type)
217{
218 switch (type)
219 {
220 case ZEBRA_ROUTE_KERNEL:
221 case ZEBRA_ROUTE_CONNECT:
222 return RTPROT_KERNEL;
223
224 default:
225 return RTPROT_ZEBRA;
226 }
227}
228
229/*
230 * netlink_route_info_fill
231 *
232 * Fill out the route information object from the given route.
233 *
234 * Returns TRUE on success and FALSE on failure.
235 */
236static int
237netlink_route_info_fill (netlink_route_info_t *ri, int cmd,
238 rib_dest_t *dest, struct rib *rib)
239{
fa713d9e
CF
240 struct nexthop *nexthop, *tnexthop;
241 int recursing;
5adc2528
AS
242 int discard;
243
244 memset (ri, 0, sizeof (*ri));
245
246 ri->prefix = rib_dest_prefix (dest);
247 ri->af = rib_dest_af (dest);
248
249 ri->nlmsg_type = cmd;
661512bf 250 ri->rtm_table = zvrf_id (rib_dest_vrf (dest));
5adc2528
AS
251 ri->rtm_protocol = RTPROT_UNSPEC;
252
253 /*
254 * An RTM_DELROUTE need not be accompanied by any nexthops,
255 * particularly in our communication with the FPM.
256 */
257 if (cmd == RTM_DELROUTE && !rib)
258 goto skip;
259
260 if (rib)
261 ri->rtm_protocol = netlink_proto_from_route_type (rib->type);
262
263 if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
264 discard = 1;
265 else
266 discard = 0;
267
268 if (cmd == RTM_NEWROUTE)
269 {
270 if (discard)
271 {
272 if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
273 ri->rtm_type = RTN_BLACKHOLE;
274 else if (rib->flags & ZEBRA_FLAG_REJECT)
275 ri->rtm_type = RTN_UNREACHABLE;
276 else
277 assert (0);
278 }
279 else
280 ri->rtm_type = RTN_UNICAST;
281 }
282
283 ri->metric = &rib->metric;
284
285 if (discard)
286 {
287 goto skip;
288 }
289
fa713d9e 290 for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
5adc2528 291 {
7c5d2b76 292 if (ri->num_nhs >= MULTIPATH_NUM)
fa713d9e 293 break;
5adc2528 294
fa713d9e
CF
295 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
296 continue;
297
298 if ((cmd == RTM_NEWROUTE
299 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
300 || (cmd == RTM_DELROUTE
301 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
5adc2528 302 {
fa713d9e 303 netlink_route_info_add_nh (ri, nexthop, recursing);
5adc2528
AS
304 }
305 }
306
307 /* If there is no useful nexthop then return. */
308 if (ri->num_nhs == 0)
309 {
310 zfpm_debug ("netlink_encode_route(): No useful nexthop.");
311 return 0;
312 }
313
314 skip:
315 return 1;
316}
317
318/*
319 * netlink_route_info_encode
320 *
321 * Returns the number of bytes written to the buffer. 0 or a negative
322 * value indicates an error.
323 */
324static int
325netlink_route_info_encode (netlink_route_info_t *ri, char *in_buf,
326 size_t in_buf_len)
327{
c7450f9a 328 size_t bytelen;
5adc2528
AS
329 int nexthop_num = 0;
330 size_t buf_offset;
331 netlink_nh_info_t *nhi;
332
333 struct
334 {
335 struct nlmsghdr n;
336 struct rtmsg r;
337 char buf[1];
338 } *req;
339
340 req = (void *) in_buf;
341
342 buf_offset = ((char *) req->buf) - ((char *) req);
343
344 if (in_buf_len < buf_offset) {
345 assert(0);
346 return 0;
347 }
348
349 memset (req, 0, buf_offset);
350
351 bytelen = af_addr_size (ri->af);
352
353 req->n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
354 req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
355 req->n.nlmsg_type = ri->nlmsg_type;
356 req->r.rtm_family = ri->af;
357 req->r.rtm_table = ri->rtm_table;
358 req->r.rtm_dst_len = ri->prefix->prefixlen;
359 req->r.rtm_protocol = ri->rtm_protocol;
360 req->r.rtm_scope = RT_SCOPE_UNIVERSE;
361
362 addattr_l (&req->n, in_buf_len, RTA_DST, &ri->prefix->u.prefix, bytelen);
363
364 req->r.rtm_type = ri->rtm_type;
365
366 /* Metric. */
367 if (ri->metric)
368 addattr32 (&req->n, in_buf_len, RTA_PRIORITY, *ri->metric);
369
370 if (ri->num_nhs == 0)
371 goto done;
372
373 if (ri->num_nhs == 1)
374 {
375 nhi = &ri->nhs[0];
376
377 if (nhi->gateway)
378 {
379 addattr_l (&req->n, in_buf_len, RTA_GATEWAY, nhi->gateway,
380 bytelen);
381 }
382
383 if (nhi->if_index)
384 {
385 addattr32 (&req->n, in_buf_len, RTA_OIF, nhi->if_index);
386 }
387
388 goto done;
389
390 }
391
392 /*
393 * Multipath case.
394 */
395 char buf[NL_PKT_BUF_SIZE];
396 struct rtattr *rta = (void *) buf;
397 struct rtnexthop *rtnh;
398
399 rta->rta_type = RTA_MULTIPATH;
400 rta->rta_len = RTA_LENGTH (0);
401 rtnh = RTA_DATA (rta);
402
403 for (nexthop_num = 0; nexthop_num < ri->num_nhs; nexthop_num++)
404 {
405 nhi = &ri->nhs[nexthop_num];
406
407 rtnh->rtnh_len = sizeof (*rtnh);
408 rtnh->rtnh_flags = 0;
409 rtnh->rtnh_hops = 0;
410 rtnh->rtnh_ifindex = 0;
411 rta->rta_len += rtnh->rtnh_len;
412
413 if (nhi->gateway)
414 {
415 rta_addattr_l (rta, sizeof (buf), RTA_GATEWAY, nhi->gateway, bytelen);
416 rtnh->rtnh_len += sizeof (struct rtattr) + bytelen;
417 }
418
419 if (nhi->if_index)
420 {
421 rtnh->rtnh_ifindex = nhi->if_index;
422 }
423
424 rtnh = RTNH_NEXT (rtnh);
425 }
426
427 assert (rta->rta_len > RTA_LENGTH (0));
428 addattr_l (&req->n, in_buf_len, RTA_MULTIPATH, RTA_DATA (rta),
429 RTA_PAYLOAD (rta));
430
431done:
432
433 if (ri->pref_src)
434 {
435 addattr_l (&req->n, in_buf_len, RTA_PREFSRC, &ri->pref_src, bytelen);
436 }
437
438 assert (req->n.nlmsg_len < in_buf_len);
439 return req->n.nlmsg_len;
440}
441
442/*
443 * zfpm_log_route_info
444 *
445 * Helper function to log the information in a route_info structure.
446 */
447static void
448zfpm_log_route_info (netlink_route_info_t *ri, const char *label)
449{
450 netlink_nh_info_t *nhi;
451 int i;
452
453 zfpm_debug ("%s : %s %s/%d, Proto: %s, Metric: %u", label,
454 nl_msg_type_to_str (ri->nlmsg_type),
455 prefix_addr_to_a (ri->prefix), ri->prefix->prefixlen,
456 nl_rtproto_to_str (ri->rtm_protocol),
457 ri->metric ? *ri->metric : 0);
458
459 for (i = 0; i < ri->num_nhs; i++)
460 {
461 nhi = &ri->nhs[i];
462 zfpm_debug(" Intf: %u, Gateway: %s, Recursive: %s, Type: %s",
463 nhi->if_index, addr_to_a (ri->af, nhi->gateway),
464 nhi->recursive ? "yes" : "no",
465 nexthop_type_to_str (nhi->type));
466 }
467}
468
469/*
470 * zfpm_netlink_encode_route
471 *
472 * Create a netlink message corresponding to the given route in the
473 * given buffer space.
474 *
475 * Returns the number of bytes written to the buffer. 0 or a negative
476 * value indicates an error.
477 */
478int
479zfpm_netlink_encode_route (int cmd, rib_dest_t *dest, struct rib *rib,
480 char *in_buf, size_t in_buf_len)
481{
482 netlink_route_info_t ri_space, *ri;
483
484 ri = &ri_space;
485
486 if (!netlink_route_info_fill (ri, cmd, dest, rib))
487 return 0;
488
489 zfpm_log_route_info (ri, __FUNCTION__);
490
491 return netlink_route_info_encode (ri, in_buf, in_buf_len);
492}