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_router.h"
36 #include "zebra/zebra_dplane.h"
37 #include "zebra/zebra_ns.h"
38 #include "zebra/zebra_vrf.h"
39 #include "zebra/kernel_netlink.h"
40 #include "zebra/rt_netlink.h"
43 #include "zebra/zebra_fpm_private.h"
44 #include "zebra/zebra_vxlan_private.h"
49 * Returns string representation of an address of the given AF.
51 static inline const char *addr_to_a(uint8_t af
, void *addr
)
54 return "<No address>";
59 return inet_ntoa(*((struct in_addr
*)addr
));
61 return inet6_ntoa(*((struct in6_addr
*)addr
));
63 return "<Addr in unknown AF>";
70 * Convience wrapper that returns a human-readable string for the
71 * address in a prefix.
73 static const char *prefix_addr_to_a(struct prefix
*prefix
)
76 return "<No address>";
78 return addr_to_a(prefix
->family
, &prefix
->u
.prefix
);
84 * The size of an address in a given address family.
86 static size_t af_addr_size(uint8_t af
)
101 * We plan to use RTA_ENCAP_TYPE attribute for VxLAN encap as well.
102 * Currently, values 0 to 8 for this attribute are used by lwtunnel_encap_types
103 * So, we cannot use these values for VxLAN encap.
105 enum fpm_nh_encap_type_t
{
106 FPM_NH_ENCAP_NONE
= 0,
107 FPM_NH_ENCAP_VXLAN
= 100,
112 * fpm_nh_encap_type_to_str
114 static const char *fpm_nh_encap_type_to_str(enum fpm_nh_encap_type_t encap_type
)
116 switch (encap_type
) {
117 case FPM_NH_ENCAP_NONE
:
120 case FPM_NH_ENCAP_VXLAN
:
123 case FPM_NH_ENCAP_MAX
:
130 struct vxlan_encap_info_t
{
134 enum vxlan_encap_info_type_t
{
138 struct fpm_nh_encap_info_t
{
139 enum fpm_nh_encap_type_t encap_type
;
141 struct vxlan_encap_info_t vxlan_encap
;
148 * Holds information about a single nexthop for netlink. These info
149 * structures are transient and may contain pointers into rib
150 * data structures for convenience.
152 typedef struct netlink_nh_info_t_
{
154 union g_addr
*gateway
;
157 * Information from the struct nexthop from which this nh was
158 * derived. For debug purposes only.
161 enum nexthop_types_t type
;
162 struct fpm_nh_encap_info_t encap_info
;
166 * netlink_route_info_t
168 * A structure for holding information for a netlink route message.
170 typedef struct netlink_route_info_t_
{
174 uint8_t rtm_protocol
;
176 struct prefix
*prefix
;
178 unsigned int num_nhs
;
183 netlink_nh_info_t nhs
[MULTIPATH_NUM
];
184 union g_addr
*pref_src
;
185 } netlink_route_info_t
;
188 * netlink_route_info_add_nh
190 * Add information about the given nexthop to the given route info
193 * Returns true if a nexthop was added, false otherwise.
195 static int netlink_route_info_add_nh(netlink_route_info_t
*ri
,
196 struct nexthop
*nexthop
,
197 struct route_entry
*re
)
199 netlink_nh_info_t nhi
;
201 zebra_l3vni_t
*zl3vni
= NULL
;
203 memset(&nhi
, 0, sizeof(nhi
));
206 if (ri
->num_nhs
>= (int)array_size(ri
->nhs
))
209 nhi
.recursive
= nexthop
->rparent
? 1 : 0;
210 nhi
.type
= nexthop
->type
;
211 nhi
.if_index
= nexthop
->ifindex
;
213 if (nexthop
->type
== NEXTHOP_TYPE_IPV4
214 || nexthop
->type
== NEXTHOP_TYPE_IPV4_IFINDEX
) {
215 nhi
.gateway
= &nexthop
->gate
;
216 if (nexthop
->src
.ipv4
.s_addr
!= INADDR_ANY
)
220 if (nexthop
->type
== NEXTHOP_TYPE_IPV6
221 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFINDEX
) {
222 nhi
.gateway
= &nexthop
->gate
;
225 if (nexthop
->type
== NEXTHOP_TYPE_IFINDEX
) {
226 if (nexthop
->src
.ipv4
.s_addr
!= INADDR_ANY
)
230 if (!nhi
.gateway
&& nhi
.if_index
== 0)
233 if (re
&& CHECK_FLAG(re
->flags
, ZEBRA_FLAG_EVPN_ROUTE
)) {
234 nhi
.encap_info
.encap_type
= FPM_NH_ENCAP_VXLAN
;
236 zl3vni
= zl3vni_from_vrf(nexthop
->vrf_id
);
237 if (zl3vni
&& is_l3vni_oper_up(zl3vni
)) {
239 /* Add VNI to VxLAN encap info */
240 nhi
.encap_info
.vxlan_encap
.vni
= zl3vni
->vni
;
245 * We have a valid nhi. Copy the structure over to the route_info.
247 ri
->nhs
[ri
->num_nhs
] = nhi
;
250 if (src
&& !ri
->pref_src
)
257 * netlink_proto_from_route_type
259 static uint8_t netlink_proto_from_route_type(int type
)
262 case ZEBRA_ROUTE_KERNEL
:
263 case ZEBRA_ROUTE_CONNECT
:
264 return RTPROT_KERNEL
;
272 * netlink_route_info_fill
274 * Fill out the route information object from the given route.
276 * Returns true on success and false on failure.
278 static int netlink_route_info_fill(netlink_route_info_t
*ri
, int cmd
,
279 rib_dest_t
*dest
, struct route_entry
*re
)
281 struct nexthop
*nexthop
;
282 struct zebra_vrf
*zvrf
;
284 memset(ri
, 0, sizeof(*ri
));
286 ri
->prefix
= rib_dest_prefix(dest
);
287 ri
->af
= rib_dest_af(dest
);
289 ri
->nlmsg_type
= cmd
;
290 zvrf
= rib_dest_vrf(dest
);
292 ri
->rtm_table
= zvrf
->table_id
;
293 ri
->rtm_protocol
= RTPROT_UNSPEC
;
296 * An RTM_DELROUTE need not be accompanied by any nexthops,
297 * particularly in our communication with the FPM.
299 if (cmd
== RTM_DELROUTE
&& !re
)
303 zfpm_debug("%s: Expected non-NULL re pointer",
304 __PRETTY_FUNCTION__
);
308 ri
->rtm_protocol
= netlink_proto_from_route_type(re
->type
);
309 ri
->rtm_type
= RTN_UNICAST
;
310 ri
->metric
= &re
->metric
;
312 for (ALL_NEXTHOPS(re
->nhe
->nhg
, nexthop
)) {
313 if (ri
->num_nhs
>= zrouter
.multipath_num
)
316 if (CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
))
319 if (nexthop
->type
== NEXTHOP_TYPE_BLACKHOLE
) {
320 switch (nexthop
->bh_type
) {
321 case BLACKHOLE_ADMINPROHIB
:
322 ri
->rtm_type
= RTN_PROHIBIT
;
324 case BLACKHOLE_REJECT
:
325 ri
->rtm_type
= RTN_UNREACHABLE
;
329 ri
->rtm_type
= RTN_BLACKHOLE
;
334 if ((cmd
== RTM_NEWROUTE
335 && CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
))
336 || (cmd
== RTM_DELROUTE
337 && CHECK_FLAG(re
->status
, ROUTE_ENTRY_INSTALLED
))) {
338 netlink_route_info_add_nh(ri
, nexthop
, re
);
342 /* If there is no useful nexthop then return. */
343 if (ri
->num_nhs
== 0) {
344 zfpm_debug("netlink_encode_route(): No useful nexthop.");
352 * netlink_route_info_encode
354 * Returns the number of bytes written to the buffer. 0 or a negative
355 * value indicates an error.
357 static int netlink_route_info_encode(netlink_route_info_t
*ri
, char *in_buf
,
361 unsigned int nexthop_num
= 0;
363 netlink_nh_info_t
*nhi
;
364 enum fpm_nh_encap_type_t encap
;
366 struct vxlan_encap_info_t
*vxlan
;
375 req
= (void *)in_buf
;
377 buf_offset
= ((char *)req
->buf
) - ((char *)req
);
379 if (in_buf_len
< buf_offset
) {
384 memset(req
, 0, buf_offset
);
386 bytelen
= af_addr_size(ri
->af
);
388 req
->n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct rtmsg
));
389 req
->n
.nlmsg_flags
= NLM_F_CREATE
| NLM_F_REQUEST
;
390 req
->n
.nlmsg_type
= ri
->nlmsg_type
;
391 req
->r
.rtm_family
= ri
->af
;
394 * rtm_table field is a uchar field which can accomodate table_id less
396 * To support table id greater than 255, if the table_id is greater than
397 * 255, set rtm_table to RT_TABLE_UNSPEC and add RTA_TABLE attribute
398 * with 32 bit value as the table_id.
400 if (ri
->rtm_table
< 256)
401 req
->r
.rtm_table
= ri
->rtm_table
;
403 req
->r
.rtm_table
= RT_TABLE_UNSPEC
;
404 addattr32(&req
->n
, in_buf_len
, RTA_TABLE
, ri
->rtm_table
);
407 req
->r
.rtm_dst_len
= ri
->prefix
->prefixlen
;
408 req
->r
.rtm_protocol
= ri
->rtm_protocol
;
409 req
->r
.rtm_scope
= RT_SCOPE_UNIVERSE
;
411 addattr_l(&req
->n
, in_buf_len
, RTA_DST
, &ri
->prefix
->u
.prefix
, bytelen
);
413 req
->r
.rtm_type
= ri
->rtm_type
;
417 addattr32(&req
->n
, in_buf_len
, RTA_PRIORITY
, *ri
->metric
);
419 if (ri
->num_nhs
== 0)
422 if (ri
->num_nhs
== 1) {
426 addattr_l(&req
->n
, in_buf_len
, RTA_GATEWAY
,
427 nhi
->gateway
, bytelen
);
431 addattr32(&req
->n
, in_buf_len
, RTA_OIF
, nhi
->if_index
);
434 encap
= nhi
->encap_info
.encap_type
;
435 if (encap
> FPM_NH_ENCAP_NONE
) {
436 addattr_l(&req
->n
, in_buf_len
, RTA_ENCAP_TYPE
, &encap
,
439 case FPM_NH_ENCAP_NONE
:
441 case FPM_NH_ENCAP_VXLAN
:
442 vxlan
= &nhi
->encap_info
.vxlan_encap
;
443 nest
= addattr_nest(&req
->n
, in_buf_len
,
445 addattr32(&req
->n
, in_buf_len
, VXLAN_VNI
,
447 addattr_nest_end(&req
->n
, nest
);
449 case FPM_NH_ENCAP_MAX
:
460 char buf
[NL_PKT_BUF_SIZE
];
461 struct rtattr
*rta
= (void *)buf
;
462 struct rtnexthop
*rtnh
;
464 rta
->rta_type
= RTA_MULTIPATH
;
465 rta
->rta_len
= RTA_LENGTH(0);
466 rtnh
= RTA_DATA(rta
);
468 for (nexthop_num
= 0; nexthop_num
< ri
->num_nhs
; nexthop_num
++) {
469 nhi
= &ri
->nhs
[nexthop_num
];
471 rtnh
->rtnh_len
= sizeof(*rtnh
);
472 rtnh
->rtnh_flags
= 0;
474 rtnh
->rtnh_ifindex
= 0;
475 rta
->rta_len
+= rtnh
->rtnh_len
;
478 rta_addattr_l(rta
, sizeof(buf
), RTA_GATEWAY
,
479 nhi
->gateway
, bytelen
);
480 rtnh
->rtnh_len
+= sizeof(struct rtattr
) + bytelen
;
484 rtnh
->rtnh_ifindex
= nhi
->if_index
;
487 encap
= nhi
->encap_info
.encap_type
;
488 if (encap
> FPM_NH_ENCAP_NONE
) {
489 rta_addattr_l(rta
, sizeof(buf
), RTA_ENCAP_TYPE
,
490 &encap
, sizeof(uint16_t));
491 rtnh
->rtnh_len
+= sizeof(struct rtattr
) +
494 case FPM_NH_ENCAP_NONE
:
496 case FPM_NH_ENCAP_VXLAN
:
497 vxlan
= &nhi
->encap_info
.vxlan_encap
;
498 nest
= rta_nest(rta
, sizeof(buf
), RTA_ENCAP
);
499 rta_addattr_l(rta
, sizeof(buf
), VXLAN_VNI
,
500 &vxlan
->vni
, sizeof(uint32_t));
501 nest_len
= rta_nest_end(rta
, nest
);
502 rtnh
->rtnh_len
+= nest_len
;
504 case FPM_NH_ENCAP_MAX
:
509 rtnh
= RTNH_NEXT(rtnh
);
512 assert(rta
->rta_len
> RTA_LENGTH(0));
513 addattr_l(&req
->n
, in_buf_len
, RTA_MULTIPATH
, RTA_DATA(rta
),
519 addattr_l(&req
->n
, in_buf_len
, RTA_PREFSRC
, &ri
->pref_src
,
523 assert(req
->n
.nlmsg_len
< in_buf_len
);
524 return req
->n
.nlmsg_len
;
528 * zfpm_log_route_info
530 * Helper function to log the information in a route_info structure.
532 static void zfpm_log_route_info(netlink_route_info_t
*ri
, const char *label
)
534 netlink_nh_info_t
*nhi
;
537 zfpm_debug("%s : %s %s/%d, Proto: %s, Metric: %u", label
,
538 nl_msg_type_to_str(ri
->nlmsg_type
),
539 prefix_addr_to_a(ri
->prefix
), ri
->prefix
->prefixlen
,
540 nl_rtproto_to_str(ri
->rtm_protocol
),
541 ri
->metric
? *ri
->metric
: 0);
543 for (i
= 0; i
< ri
->num_nhs
; i
++) {
545 zfpm_debug(" Intf: %u, Gateway: %s, Recursive: %s, Type: %s, Encap type: %s",
546 nhi
->if_index
, addr_to_a(ri
->af
, nhi
->gateway
),
547 nhi
->recursive
? "yes" : "no",
548 nexthop_type_to_str(nhi
->type
),
549 fpm_nh_encap_type_to_str(nhi
->encap_info
.encap_type
)
555 * zfpm_netlink_encode_route
557 * Create a netlink message corresponding to the given route in the
558 * given buffer space.
560 * Returns the number of bytes written to the buffer. 0 or a negative
561 * value indicates an error.
563 int zfpm_netlink_encode_route(int cmd
, rib_dest_t
*dest
, struct route_entry
*re
,
564 char *in_buf
, size_t in_buf_len
)
566 netlink_route_info_t ri_space
, *ri
;
570 if (!netlink_route_info_fill(ri
, cmd
, dest
, re
))
573 zfpm_log_route_info(ri
, __FUNCTION__
);
575 return netlink_route_info_encode(ri
, in_buf
, in_buf_len
);
579 * zfpm_netlink_encode_mac
581 * Create a netlink message corresponding to the given MAC.
583 * Returns the number of bytes written to the buffer. 0 or a negative
584 * value indicates an error.
586 int zfpm_netlink_encode_mac(struct fpm_mac_info_t
*mac
, char *in_buf
,
589 char buf1
[ETHER_ADDR_STRLEN
];
597 req
= (void *)in_buf
;
599 buf_offset
= offsetof(struct macmsg
, buf
);
600 if (in_buf_len
< buf_offset
)
602 memset(req
, 0, buf_offset
);
604 /* Construct nlmsg header */
605 req
->hdr
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ndmsg
));
606 req
->hdr
.nlmsg_type
= CHECK_FLAG(mac
->fpm_flags
, ZEBRA_MAC_DELETE_FPM
) ?
607 RTM_DELNEIGH
: RTM_NEWNEIGH
;
608 req
->hdr
.nlmsg_flags
= NLM_F_REQUEST
;
609 if (req
->hdr
.nlmsg_type
== RTM_NEWNEIGH
)
610 req
->hdr
.nlmsg_flags
|= (NLM_F_CREATE
| NLM_F_REPLACE
);
612 /* Construct ndmsg */
613 req
->ndm
.ndm_family
= AF_BRIDGE
;
614 req
->ndm
.ndm_ifindex
= mac
->vxlan_if
;
616 req
->ndm
.ndm_state
= NUD_REACHABLE
;
617 req
->ndm
.ndm_flags
|= NTF_SELF
| NTF_MASTER
;
618 if (CHECK_FLAG(mac
->zebra_flags
,
619 (ZEBRA_MAC_STICKY
| ZEBRA_MAC_REMOTE_DEF_GW
)))
620 req
->ndm
.ndm_state
|= NUD_NOARP
;
622 req
->ndm
.ndm_flags
|= NTF_EXT_LEARNED
;
625 addattr_l(&req
->hdr
, in_buf_len
, NDA_LLADDR
, &mac
->macaddr
, 6);
626 addattr_l(&req
->hdr
, in_buf_len
, NDA_DST
, &mac
->r_vtep_ip
, 4);
627 addattr32(&req
->hdr
, in_buf_len
, NDA_MASTER
, mac
->svi_if
);
628 addattr32(&req
->hdr
, in_buf_len
, NDA_VNI
, mac
->vni
);
630 assert(req
->hdr
.nlmsg_len
< in_buf_len
);
632 zfpm_debug("Tx %s family %s ifindex %u MAC %s DEST %s",
633 nl_msg_type_to_str(req
->hdr
.nlmsg_type
),
634 nl_family_to_str(req
->ndm
.ndm_family
), req
->ndm
.ndm_ifindex
,
635 prefix_mac2str(&mac
->macaddr
, buf1
, sizeof(buf1
)),
636 inet_ntoa(mac
->r_vtep_ip
));
638 return req
->hdr
.nlmsg_len
;
641 #endif /* HAVE_NETLINK */