2 * Code for encoding/decoding FPM messages that are in netlink format.
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")
8 * This file is part of GNU Zebra.
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
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.
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
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"
40 #include "zebra/zebra_fpm_private.h"
45 * Returns string representation of an address of the given AF.
47 static inline const char *
48 addr_to_a (u_char af
, void *addr
)
51 return "<No address>";
57 return inet_ntoa (*((struct in_addr
*) addr
));
60 return inet6_ntoa (*((struct in6_addr
*) addr
));
63 return "<Addr in unknown AF>";
71 * Convience wrapper that returns a human-readable string for the
72 * address in a prefix.
75 prefix_addr_to_a (struct prefix
*prefix
)
78 return "<No address>";
80 return addr_to_a (prefix
->family
, &prefix
->u
.prefix
);
86 * The size of an address in a given address family.
89 af_addr_size (u_char af
)
109 * Holds information about a single nexthop for netlink. These info
110 * structures are transient and may contain pointers into rib
111 * data structures for convenience.
113 typedef struct netlink_nh_info_t_
116 union g_addr
*gateway
;
119 * Information from the struct nexthop from which this nh was
120 * derived. For debug purposes only.
123 enum nexthop_types_t type
;
127 * netlink_route_info_t
129 * A structure for holding information for a netlink route message.
131 typedef struct netlink_route_info_t_
138 struct prefix
*prefix
;
140 unsigned int num_nhs
;
145 netlink_nh_info_t nhs
[MULTIPATH_NUM
];
146 union g_addr
*pref_src
;
147 } netlink_route_info_t
;
150 * netlink_route_info_add_nh
152 * Add information about the given nexthop to the given route info
155 * Returns TRUE if a nexthop was added, FALSE otherwise.
158 netlink_route_info_add_nh (netlink_route_info_t
*ri
, struct nexthop
*nexthop
,
161 netlink_nh_info_t nhi
;
164 memset (&nhi
, 0, sizeof (nhi
));
167 if (ri
->num_nhs
>= (int) ZEBRA_NUM_OF (ri
->nhs
))
170 nhi
.recursive
= recursive
;
171 nhi
.type
= nexthop
->type
;
172 nhi
.if_index
= nexthop
->ifindex
;
174 if (nexthop
->type
== NEXTHOP_TYPE_IPV4
175 || nexthop
->type
== NEXTHOP_TYPE_IPV4_IFINDEX
)
177 nhi
.gateway
= &nexthop
->gate
;
178 if (nexthop
->src
.ipv4
.s_addr
)
182 if (nexthop
->type
== NEXTHOP_TYPE_IPV6
183 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFINDEX
)
185 nhi
.gateway
= &nexthop
->gate
;
188 if (nexthop
->type
== NEXTHOP_TYPE_IFINDEX
)
190 if (nexthop
->src
.ipv4
.s_addr
)
194 if (!nhi
.gateway
&& nhi
.if_index
== 0)
198 * We have a valid nhi. Copy the structure over to the route_info.
200 ri
->nhs
[ri
->num_nhs
] = nhi
;
203 if (src
&& !ri
->pref_src
)
210 * netlink_proto_from_route_type
213 netlink_proto_from_route_type (int type
)
217 case ZEBRA_ROUTE_KERNEL
:
218 case ZEBRA_ROUTE_CONNECT
:
219 return RTPROT_KERNEL
;
227 * netlink_route_info_fill
229 * Fill out the route information object from the given route.
231 * Returns TRUE on success and FALSE on failure.
234 netlink_route_info_fill (netlink_route_info_t
*ri
, int cmd
,
235 rib_dest_t
*dest
, struct rib
*rib
)
237 struct nexthop
*nexthop
, *tnexthop
;
241 memset (ri
, 0, sizeof (*ri
));
243 ri
->prefix
= rib_dest_prefix (dest
);
244 ri
->af
= rib_dest_af (dest
);
246 ri
->nlmsg_type
= cmd
;
247 ri
->rtm_table
= zvrf_id (rib_dest_vrf (dest
));
248 ri
->rtm_protocol
= RTPROT_UNSPEC
;
251 * An RTM_DELROUTE need not be accompanied by any nexthops,
252 * particularly in our communication with the FPM.
254 if (cmd
== RTM_DELROUTE
&& !rib
)
259 zfpm_debug ("%s: Expected non-NULL rib pointer", __PRETTY_FUNCTION__
);
263 ri
->rtm_protocol
= netlink_proto_from_route_type (rib
->type
);
265 if ((rib
->flags
& ZEBRA_FLAG_BLACKHOLE
) || (rib
->flags
& ZEBRA_FLAG_REJECT
))
270 if (cmd
== RTM_NEWROUTE
)
274 if (rib
->flags
& ZEBRA_FLAG_BLACKHOLE
)
275 ri
->rtm_type
= RTN_BLACKHOLE
;
276 else if (rib
->flags
& ZEBRA_FLAG_REJECT
)
277 ri
->rtm_type
= RTN_UNREACHABLE
;
282 ri
->rtm_type
= RTN_UNICAST
;
285 ri
->metric
= &rib
->metric
;
290 for (ALL_NEXTHOPS_RO(rib
->nexthop
, nexthop
, tnexthop
, recursing
))
292 if (ri
->num_nhs
>= multipath_num
)
295 if (CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
))
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
)))
303 netlink_route_info_add_nh (ri
, nexthop
, recursing
);
307 /* If there is no useful nexthop then return. */
308 if (ri
->num_nhs
== 0)
310 zfpm_debug ("netlink_encode_route(): No useful nexthop.");
318 * netlink_route_info_encode
320 * Returns the number of bytes written to the buffer. 0 or a negative
321 * value indicates an error.
324 netlink_route_info_encode (netlink_route_info_t
*ri
, char *in_buf
,
328 unsigned int nexthop_num
= 0;
330 netlink_nh_info_t
*nhi
;
339 req
= (void *) in_buf
;
341 buf_offset
= ((char *) req
->buf
) - ((char *) req
);
343 if (in_buf_len
< buf_offset
) {
348 memset (req
, 0, buf_offset
);
350 bytelen
= af_addr_size (ri
->af
);
352 req
->n
.nlmsg_len
= NLMSG_LENGTH (sizeof (struct rtmsg
));
353 req
->n
.nlmsg_flags
= NLM_F_CREATE
| NLM_F_REQUEST
;
354 req
->n
.nlmsg_type
= ri
->nlmsg_type
;
355 req
->r
.rtm_family
= ri
->af
;
356 req
->r
.rtm_table
= ri
->rtm_table
;
357 req
->r
.rtm_dst_len
= ri
->prefix
->prefixlen
;
358 req
->r
.rtm_protocol
= ri
->rtm_protocol
;
359 req
->r
.rtm_scope
= RT_SCOPE_UNIVERSE
;
361 addattr_l (&req
->n
, in_buf_len
, RTA_DST
, &ri
->prefix
->u
.prefix
, bytelen
);
363 req
->r
.rtm_type
= ri
->rtm_type
;
367 addattr32 (&req
->n
, in_buf_len
, RTA_PRIORITY
, *ri
->metric
);
369 if (ri
->num_nhs
== 0)
372 if (ri
->num_nhs
== 1)
378 addattr_l (&req
->n
, in_buf_len
, RTA_GATEWAY
, nhi
->gateway
,
384 addattr32 (&req
->n
, in_buf_len
, RTA_OIF
, nhi
->if_index
);
394 char buf
[NL_PKT_BUF_SIZE
];
395 struct rtattr
*rta
= (void *) buf
;
396 struct rtnexthop
*rtnh
;
398 rta
->rta_type
= RTA_MULTIPATH
;
399 rta
->rta_len
= RTA_LENGTH (0);
400 rtnh
= RTA_DATA (rta
);
402 for (nexthop_num
= 0; nexthop_num
< ri
->num_nhs
; nexthop_num
++)
404 nhi
= &ri
->nhs
[nexthop_num
];
406 rtnh
->rtnh_len
= sizeof (*rtnh
);
407 rtnh
->rtnh_flags
= 0;
409 rtnh
->rtnh_ifindex
= 0;
410 rta
->rta_len
+= rtnh
->rtnh_len
;
414 rta_addattr_l (rta
, sizeof (buf
), RTA_GATEWAY
, nhi
->gateway
, bytelen
);
415 rtnh
->rtnh_len
+= sizeof (struct rtattr
) + bytelen
;
420 rtnh
->rtnh_ifindex
= nhi
->if_index
;
423 rtnh
= RTNH_NEXT (rtnh
);
426 assert (rta
->rta_len
> RTA_LENGTH (0));
427 addattr_l (&req
->n
, in_buf_len
, RTA_MULTIPATH
, RTA_DATA (rta
),
434 addattr_l (&req
->n
, in_buf_len
, RTA_PREFSRC
, &ri
->pref_src
, bytelen
);
437 assert (req
->n
.nlmsg_len
< in_buf_len
);
438 return req
->n
.nlmsg_len
;
442 * zfpm_log_route_info
444 * Helper function to log the information in a route_info structure.
447 zfpm_log_route_info (netlink_route_info_t
*ri
, const char *label
)
449 netlink_nh_info_t
*nhi
;
452 zfpm_debug ("%s : %s %s/%d, Proto: %s, Metric: %u", label
,
453 nl_msg_type_to_str (ri
->nlmsg_type
),
454 prefix_addr_to_a (ri
->prefix
), ri
->prefix
->prefixlen
,
455 nl_rtproto_to_str (ri
->rtm_protocol
),
456 ri
->metric
? *ri
->metric
: 0);
458 for (i
= 0; i
< ri
->num_nhs
; i
++)
461 zfpm_debug(" Intf: %u, Gateway: %s, Recursive: %s, Type: %s",
462 nhi
->if_index
, addr_to_a (ri
->af
, nhi
->gateway
),
463 nhi
->recursive
? "yes" : "no",
464 nexthop_type_to_str (nhi
->type
));
469 * zfpm_netlink_encode_route
471 * Create a netlink message corresponding to the given route in the
472 * given buffer space.
474 * Returns the number of bytes written to the buffer. 0 or a negative
475 * value indicates an error.
478 zfpm_netlink_encode_route (int cmd
, rib_dest_t
*dest
, struct rib
*rib
,
479 char *in_buf
, size_t in_buf_len
)
481 netlink_route_info_t ri_space
, *ri
;
485 if (!netlink_route_info_fill (ri
, cmd
, dest
, rib
))
488 zfpm_log_route_info (ri
, __FUNCTION__
);
490 return netlink_route_info_encode (ri
, in_buf
, in_buf_len
);