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 along
21 * with this program; see the file COPYING; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
34 #include "zebra/zserv.h"
35 #include "zebra/zebra_dplane.h"
36 #include "zebra/zebra_ns.h"
37 #include "zebra/zebra_vrf.h"
38 #include "zebra/kernel_netlink.h"
39 #include "zebra/rt_netlink.h"
42 #include "zebra/zebra_fpm_private.h"
47 * Returns string representation of an address of the given AF.
49 static inline const char *addr_to_a(uint8_t af
, void *addr
)
52 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.
74 static const char *prefix_addr_to_a(struct prefix
*prefix
)
77 return "<No address>";
79 return addr_to_a(prefix
->family
, &prefix
->u
.prefix
);
85 * The size of an address in a given address family.
87 static size_t af_addr_size(uint8_t af
)
106 * Holds information about a single nexthop for netlink. These info
107 * structures are transient and may contain pointers into rib
108 * data structures for convenience.
110 typedef struct netlink_nh_info_t_
{
112 union g_addr
*gateway
;
115 * Information from the struct nexthop from which this nh was
116 * derived. For debug purposes only.
119 enum nexthop_types_t type
;
123 * netlink_route_info_t
125 * A structure for holding information for a netlink route message.
127 typedef struct netlink_route_info_t_
{
131 uint8_t rtm_protocol
;
133 struct prefix
*prefix
;
135 unsigned int num_nhs
;
140 netlink_nh_info_t nhs
[MULTIPATH_NUM
];
141 union g_addr
*pref_src
;
142 } netlink_route_info_t
;
145 * netlink_route_info_add_nh
147 * Add information about the given nexthop to the given route info
150 * Returns TRUE if a nexthop was added, FALSE otherwise.
152 static int netlink_route_info_add_nh(netlink_route_info_t
*ri
,
153 struct nexthop
*nexthop
)
155 netlink_nh_info_t nhi
;
158 memset(&nhi
, 0, sizeof(nhi
));
161 if (ri
->num_nhs
>= (int)ZEBRA_NUM_OF(ri
->nhs
))
164 nhi
.recursive
= nexthop
->rparent
? 1 : 0;
165 nhi
.type
= nexthop
->type
;
166 nhi
.if_index
= nexthop
->ifindex
;
168 if (nexthop
->type
== NEXTHOP_TYPE_IPV4
169 || nexthop
->type
== NEXTHOP_TYPE_IPV4_IFINDEX
) {
170 nhi
.gateway
= &nexthop
->gate
;
171 if (nexthop
->src
.ipv4
.s_addr
)
175 if (nexthop
->type
== NEXTHOP_TYPE_IPV6
176 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFINDEX
) {
177 nhi
.gateway
= &nexthop
->gate
;
180 if (nexthop
->type
== NEXTHOP_TYPE_IFINDEX
) {
181 if (nexthop
->src
.ipv4
.s_addr
)
185 if (!nhi
.gateway
&& nhi
.if_index
== 0)
189 * We have a valid nhi. Copy the structure over to the route_info.
191 ri
->nhs
[ri
->num_nhs
] = nhi
;
194 if (src
&& !ri
->pref_src
)
201 * netlink_proto_from_route_type
203 static uint8_t netlink_proto_from_route_type(int type
)
206 case ZEBRA_ROUTE_KERNEL
:
207 case ZEBRA_ROUTE_CONNECT
:
208 return RTPROT_KERNEL
;
216 * netlink_route_info_fill
218 * Fill out the route information object from the given route.
220 * Returns TRUE on success and FALSE on failure.
222 static int netlink_route_info_fill(netlink_route_info_t
*ri
, int cmd
,
223 rib_dest_t
*dest
, struct route_entry
*re
)
225 struct nexthop
*nexthop
;
227 memset(ri
, 0, sizeof(*ri
));
229 ri
->prefix
= rib_dest_prefix(dest
);
230 ri
->af
= rib_dest_af(dest
);
232 ri
->nlmsg_type
= cmd
;
233 ri
->rtm_table
= zvrf_id(rib_dest_vrf(dest
));
234 ri
->rtm_protocol
= RTPROT_UNSPEC
;
237 * An RTM_DELROUTE need not be accompanied by any nexthops,
238 * particularly in our communication with the FPM.
240 if (cmd
== RTM_DELROUTE
&& !re
)
244 zfpm_debug("%s: Expected non-NULL re pointer",
245 __PRETTY_FUNCTION__
);
249 ri
->rtm_protocol
= netlink_proto_from_route_type(re
->type
);
250 ri
->rtm_type
= RTN_UNICAST
;
251 ri
->metric
= &re
->metric
;
253 for (ALL_NEXTHOPS(re
->ng
, nexthop
)) {
254 if (ri
->num_nhs
>= multipath_num
)
257 if (CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
))
260 if (nexthop
->type
== NEXTHOP_TYPE_BLACKHOLE
) {
261 switch (nexthop
->bh_type
) {
262 case BLACKHOLE_ADMINPROHIB
:
263 ri
->rtm_type
= RTN_PROHIBIT
;
265 case BLACKHOLE_REJECT
:
266 ri
->rtm_type
= RTN_UNREACHABLE
;
270 ri
->rtm_type
= RTN_BLACKHOLE
;
276 if ((cmd
== RTM_NEWROUTE
277 && CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
))
278 || (cmd
== RTM_DELROUTE
279 && CHECK_FLAG(re
->status
, ROUTE_ENTRY_INSTALLED
))) {
280 netlink_route_info_add_nh(ri
, nexthop
);
284 /* If there is no useful nexthop then return. */
285 if (ri
->num_nhs
== 0) {
286 zfpm_debug("netlink_encode_route(): No useful nexthop.");
294 * netlink_route_info_encode
296 * Returns the number of bytes written to the buffer. 0 or a negative
297 * value indicates an error.
299 static int netlink_route_info_encode(netlink_route_info_t
*ri
, char *in_buf
,
303 unsigned int nexthop_num
= 0;
305 netlink_nh_info_t
*nhi
;
313 req
= (void *)in_buf
;
315 buf_offset
= ((char *)req
->buf
) - ((char *)req
);
317 if (in_buf_len
< buf_offset
) {
322 memset(req
, 0, buf_offset
);
324 bytelen
= af_addr_size(ri
->af
);
326 req
->n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct rtmsg
));
327 req
->n
.nlmsg_flags
= NLM_F_CREATE
| NLM_F_REQUEST
;
328 req
->n
.nlmsg_type
= ri
->nlmsg_type
;
329 req
->r
.rtm_family
= ri
->af
;
330 req
->r
.rtm_table
= ri
->rtm_table
;
331 req
->r
.rtm_dst_len
= ri
->prefix
->prefixlen
;
332 req
->r
.rtm_protocol
= ri
->rtm_protocol
;
333 req
->r
.rtm_scope
= RT_SCOPE_UNIVERSE
;
335 addattr_l(&req
->n
, in_buf_len
, RTA_DST
, &ri
->prefix
->u
.prefix
, bytelen
);
337 req
->r
.rtm_type
= ri
->rtm_type
;
341 addattr32(&req
->n
, in_buf_len
, RTA_PRIORITY
, *ri
->metric
);
343 if (ri
->num_nhs
== 0)
346 if (ri
->num_nhs
== 1) {
350 addattr_l(&req
->n
, in_buf_len
, RTA_GATEWAY
,
351 nhi
->gateway
, bytelen
);
355 addattr32(&req
->n
, in_buf_len
, RTA_OIF
, nhi
->if_index
);
364 char buf
[NL_PKT_BUF_SIZE
];
365 struct rtattr
*rta
= (void *)buf
;
366 struct rtnexthop
*rtnh
;
368 rta
->rta_type
= RTA_MULTIPATH
;
369 rta
->rta_len
= RTA_LENGTH(0);
370 rtnh
= RTA_DATA(rta
);
372 for (nexthop_num
= 0; nexthop_num
< ri
->num_nhs
; nexthop_num
++) {
373 nhi
= &ri
->nhs
[nexthop_num
];
375 rtnh
->rtnh_len
= sizeof(*rtnh
);
376 rtnh
->rtnh_flags
= 0;
378 rtnh
->rtnh_ifindex
= 0;
379 rta
->rta_len
+= rtnh
->rtnh_len
;
382 rta_addattr_l(rta
, sizeof(buf
), RTA_GATEWAY
,
383 nhi
->gateway
, bytelen
);
384 rtnh
->rtnh_len
+= sizeof(struct rtattr
) + bytelen
;
388 rtnh
->rtnh_ifindex
= nhi
->if_index
;
391 rtnh
= RTNH_NEXT(rtnh
);
394 assert(rta
->rta_len
> RTA_LENGTH(0));
395 addattr_l(&req
->n
, in_buf_len
, RTA_MULTIPATH
, RTA_DATA(rta
),
401 addattr_l(&req
->n
, in_buf_len
, RTA_PREFSRC
, &ri
->pref_src
,
405 assert(req
->n
.nlmsg_len
< in_buf_len
);
406 return req
->n
.nlmsg_len
;
410 * zfpm_log_route_info
412 * Helper function to log the information in a route_info structure.
414 static void zfpm_log_route_info(netlink_route_info_t
*ri
, const char *label
)
416 netlink_nh_info_t
*nhi
;
419 zfpm_debug("%s : %s %s/%d, Proto: %s, Metric: %u", label
,
420 nl_msg_type_to_str(ri
->nlmsg_type
),
421 prefix_addr_to_a(ri
->prefix
), ri
->prefix
->prefixlen
,
422 nl_rtproto_to_str(ri
->rtm_protocol
),
423 ri
->metric
? *ri
->metric
: 0);
425 for (i
= 0; i
< ri
->num_nhs
; i
++) {
427 zfpm_debug(" Intf: %u, Gateway: %s, Recursive: %s, Type: %s",
428 nhi
->if_index
, addr_to_a(ri
->af
, nhi
->gateway
),
429 nhi
->recursive
? "yes" : "no",
430 nexthop_type_to_str(nhi
->type
));
435 * zfpm_netlink_encode_route
437 * Create a netlink message corresponding to the given route in the
438 * given buffer space.
440 * Returns the number of bytes written to the buffer. 0 or a negative
441 * value indicates an error.
443 int zfpm_netlink_encode_route(int cmd
, rib_dest_t
*dest
, struct route_entry
*re
,
444 char *in_buf
, size_t in_buf_len
)
446 netlink_route_info_t ri_space
, *ri
;
450 if (!netlink_route_info_fill(ri
, cmd
, dest
, re
))
453 zfpm_log_route_info(ri
, __FUNCTION__
);
455 return netlink_route_info_encode(ri
, in_buf
, in_buf_len
);
458 #endif /* HAVE_NETLINK */