1 // SPDX-License-Identifier: GPL-2.0-or-later
5 * @copyright Copyright (C) 2016 Sproute Networks, Inc.
7 * @author Avneesh Sachdev <avneesh@sproute.com>
14 #include "zebra_vrf.h"
16 #include "qpb/qpb.pb-c.h"
18 #include "qpb/qpb_allocator.h"
19 #include "qpb/linear_allocator.h"
20 #include "fpm/fpm_pb.h"
22 #include "zebra_router.h"
23 #include "zebra_fpm_private.h"
26 * create_delete_route_message
28 static Fpm__DeleteRoute
*create_delete_route_message(qpb_allocator_t
*allocator
,
30 struct route_entry
*re
)
32 Fpm__DeleteRoute
*msg
;
34 msg
= QPB_ALLOC(allocator
, typeof(*msg
));
40 fpm__delete_route__init(msg
);
41 msg
->vrf_id
= zvrf_id(rib_dest_vrf(dest
));
43 qpb_address_family_set(&msg
->address_family
, rib_dest_af(dest
));
46 * XXX Hardcode subaddress family for now.
48 msg
->sub_address_family
= QPB__SUB_ADDRESS_FAMILY__UNICAST
;
49 msg
->key
= fpm_route_key_create(allocator
, rib_dest_prefix(dest
));
61 static inline int add_nexthop(qpb_allocator_t
*allocator
, Fpm__AddRoute
*msg
,
62 rib_dest_t
*dest
, struct nexthop
*nexthop
)
65 union g_addr
*gateway
, *src
;
69 if_index
= nexthop
->ifindex
;
71 if (nexthop
->type
== NEXTHOP_TYPE_IPV4
72 || nexthop
->type
== NEXTHOP_TYPE_IPV4_IFINDEX
) {
73 gateway
= &nexthop
->gate
;
74 if (nexthop
->src
.ipv4
.s_addr
!= INADDR_ANY
)
78 if (nexthop
->type
== NEXTHOP_TYPE_IPV6
79 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFINDEX
) {
80 gateway
= &nexthop
->gate
;
83 if (nexthop
->type
== NEXTHOP_TYPE_IFINDEX
) {
84 if (nexthop
->src
.ipv4
.s_addr
!= INADDR_ANY
)
88 if (!gateway
&& if_index
== 0)
92 * We have a valid nexthop.
96 pb_nh
= QPB_ALLOC(allocator
, typeof(*pb_nh
));
102 fpm__nexthop__init(pb_nh
);
106 qpb_if_identifier_create(allocator
, if_index
);
110 pb_nh
->address
= qpb_l3_address_create(
111 allocator
, gateway
, rib_dest_af(dest
));
114 msg
->nexthops
[msg
->n_nexthops
++] = pb_nh
;
124 * create_add_route_message
126 static Fpm__AddRoute
*create_add_route_message(qpb_allocator_t
*allocator
,
128 struct route_entry
*re
)
131 struct nexthop
*nexthop
;
133 struct nexthop
*nexthops
[MULTIPATH_NUM
];
135 msg
= QPB_ALLOC(allocator
, typeof(*msg
));
141 fpm__add_route__init(msg
);
143 msg
->vrf_id
= zvrf_id(rib_dest_vrf(dest
));
145 qpb_address_family_set(&msg
->address_family
, rib_dest_af(dest
));
148 * XXX Hardcode subaddress family for now.
150 msg
->sub_address_family
= QPB__SUB_ADDRESS_FAMILY__UNICAST
;
151 msg
->key
= fpm_route_key_create(allocator
, rib_dest_prefix(dest
));
152 qpb_protocol_set(&msg
->protocol
, re
->type
);
153 msg
->has_route_type
= 1;
154 msg
->route_type
= FPM__ROUTE_TYPE__NORMAL
;
155 msg
->metric
= re
->metric
;
158 * Figure out the set of nexthops to be added to the message.
161 for (ALL_NEXTHOPS(re
->nhe
->nhg
, nexthop
)) {
162 if (num_nhs
>= zrouter
.multipath_num
)
165 if (num_nhs
>= array_size(nexthops
))
168 if (nexthop
->type
== NEXTHOP_TYPE_BLACKHOLE
) {
169 switch (nexthop
->bh_type
) {
170 case BLACKHOLE_REJECT
:
171 msg
->route_type
= FPM__ROUTE_TYPE__UNREACHABLE
;
174 case BLACKHOLE_UNSPEC
:
175 case BLACKHOLE_ADMINPROHIB
:
176 msg
->route_type
= FPM__ROUTE_TYPE__BLACKHOLE
;
182 if (CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
))
185 if (!CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
))
188 nexthops
[num_nhs
] = nexthop
;
193 zfpm_debug("netlink_encode_route(): No useful nexthop.");
199 * And add them to the message.
201 if (!(msg
->nexthops
= qpb_alloc_ptr_array(allocator
, num_nhs
))) {
207 for (u
= 0; u
< num_nhs
; u
++) {
208 if (!add_nexthop(allocator
, msg
, dest
, nexthops
[u
])) {
214 assert(msg
->n_nexthops
== num_nhs
);
220 * create_route_message
222 static Fpm__Message
*create_route_message(qpb_allocator_t
*allocator
,
224 struct route_entry
*re
)
228 msg
= QPB_ALLOC(allocator
, typeof(*msg
));
234 fpm__message__init(msg
);
238 msg
->type
= FPM__MESSAGE__TYPE__DELETE_ROUTE
;
240 create_delete_route_message(allocator
, dest
, re
);
241 if (!msg
->delete_route
) {
249 msg
->type
= FPM__MESSAGE__TYPE__ADD_ROUTE
;
250 msg
->add_route
= create_add_route_message(allocator
, dest
, re
);
251 if (!msg
->add_route
) {
260 * zfpm_protobuf_encode_route
262 * Create a protobuf message corresponding to the given route in the
263 * given buffer space.
265 * Returns the number of bytes written to the buffer. 0 or a negative
266 * value indicates an error.
268 int zfpm_protobuf_encode_route(rib_dest_t
*dest
, struct route_entry
*re
,
269 uint8_t *in_buf
, size_t in_buf_len
)
272 QPB_DECLARE_STACK_ALLOCATOR(allocator
, 4096);
275 QPB_INIT_STACK_ALLOCATOR(allocator
);
277 msg
= create_route_message(&allocator
, dest
, re
);
283 len
= fpm__message__pack(msg
, in_buf
);
284 assert(len
<= in_buf_len
);
286 QPB_RESET_STACK_ALLOCATOR(allocator
);