4 * @copyright Copyright (C) 2016 Sproute Networks, Inc.
6 * @author Avneesh Sachdev <avneesh@sproute.com>
8 * This file is part of Quagga.
10 * Quagga 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 * Quagga 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
29 #include "zebra_vrf.h"
31 #include "qpb/qpb.pb-c.h"
33 #include "qpb/qpb_allocator.h"
34 #include "qpb/linear_allocator.h"
35 #include "fpm/fpm_pb.h"
37 #include "zebra_router.h"
38 #include "zebra_fpm_private.h"
41 * create_delete_route_message
43 static Fpm__DeleteRoute
*create_delete_route_message(qpb_allocator_t
*allocator
,
45 struct route_entry
*re
)
47 Fpm__DeleteRoute
*msg
;
49 msg
= QPB_ALLOC(allocator
, typeof(*msg
));
55 fpm__delete_route__init(msg
);
56 msg
->vrf_id
= zvrf_id(rib_dest_vrf(dest
));
58 qpb_address_family_set(&msg
->address_family
, rib_dest_af(dest
));
61 * XXX Hardcode subaddress family for now.
63 msg
->sub_address_family
= QPB__SUB_ADDRESS_FAMILY__UNICAST
;
64 msg
->key
= fpm_route_key_create(allocator
, rib_dest_prefix(dest
));
76 static inline int add_nexthop(qpb_allocator_t
*allocator
, Fpm__AddRoute
*msg
,
77 rib_dest_t
*dest
, struct nexthop
*nexthop
)
80 union g_addr
*gateway
, *src
;
84 if_index
= nexthop
->ifindex
;
86 if (nexthop
->type
== NEXTHOP_TYPE_IPV4
87 || nexthop
->type
== NEXTHOP_TYPE_IPV4_IFINDEX
) {
88 gateway
= &nexthop
->gate
;
89 if (nexthop
->src
.ipv4
.s_addr
)
93 if (nexthop
->type
== NEXTHOP_TYPE_IPV6
94 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFINDEX
) {
95 gateway
= &nexthop
->gate
;
98 if (nexthop
->type
== NEXTHOP_TYPE_IFINDEX
) {
99 if (nexthop
->src
.ipv4
.s_addr
)
103 if (!gateway
&& if_index
== 0)
107 * We have a valid nexthop.
111 pb_nh
= QPB_ALLOC(allocator
, typeof(*pb_nh
));
117 fpm__nexthop__init(pb_nh
);
121 qpb_if_identifier_create(allocator
, if_index
);
125 pb_nh
->address
= qpb_l3_address_create(
126 allocator
, gateway
, rib_dest_af(dest
));
129 msg
->nexthops
[msg
->n_nexthops
++] = pb_nh
;
139 * create_add_route_message
141 static Fpm__AddRoute
*create_add_route_message(qpb_allocator_t
*allocator
,
143 struct route_entry
*re
)
146 struct nexthop
*nexthop
;
148 struct nexthop
*nexthops
[MULTIPATH_NUM
];
150 msg
= QPB_ALLOC(allocator
, typeof(*msg
));
156 fpm__add_route__init(msg
);
158 msg
->vrf_id
= zvrf_id(rib_dest_vrf(dest
));
160 qpb_address_family_set(&msg
->address_family
, rib_dest_af(dest
));
163 * XXX Hardcode subaddress family for now.
165 msg
->sub_address_family
= QPB__SUB_ADDRESS_FAMILY__UNICAST
;
166 msg
->key
= fpm_route_key_create(allocator
, rib_dest_prefix(dest
));
167 qpb_protocol_set(&msg
->protocol
, re
->type
);
168 msg
->has_route_type
= 1;
169 msg
->route_type
= FPM__ROUTE_TYPE__NORMAL
;
170 msg
->metric
= re
->metric
;
173 * Figure out the set of nexthops to be added to the message.
176 for (ALL_NEXTHOPS(re
->ng
, nexthop
)) {
177 if (num_nhs
>= zrouter
.multipath_num
)
180 if (num_nhs
>= array_size(nexthops
))
183 if (nexthop
->type
== NEXTHOP_TYPE_BLACKHOLE
) {
184 switch (nexthop
->bh_type
) {
185 case BLACKHOLE_REJECT
:
186 msg
->route_type
= FPM__ROUTE_TYPE__UNREACHABLE
;
190 msg
->route_type
= FPM__ROUTE_TYPE__BLACKHOLE
;
196 if (CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
))
199 if (!CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
))
202 nexthops
[num_nhs
] = nexthop
;
207 zfpm_debug("netlink_encode_route(): No useful nexthop.");
213 * And add them to the message.
215 if (!(msg
->nexthops
= qpb_alloc_ptr_array(allocator
, num_nhs
))) {
221 for (u
= 0; u
< num_nhs
; u
++) {
222 if (!add_nexthop(allocator
, msg
, dest
, nexthops
[u
])) {
228 assert(msg
->n_nexthops
== num_nhs
);
234 * create_route_message
236 static Fpm__Message
*create_route_message(qpb_allocator_t
*allocator
,
238 struct route_entry
*re
)
242 msg
= QPB_ALLOC(allocator
, typeof(*msg
));
248 fpm__message__init(msg
);
252 msg
->type
= FPM__MESSAGE__TYPE__DELETE_ROUTE
;
254 create_delete_route_message(allocator
, dest
, re
);
255 if (!msg
->delete_route
) {
263 msg
->type
= FPM__MESSAGE__TYPE__ADD_ROUTE
;
264 msg
->add_route
= create_add_route_message(allocator
, dest
, re
);
265 if (!msg
->add_route
) {
274 * zfpm_protobuf_encode_route
276 * Create a protobuf message corresponding to the given route in the
277 * given buffer space.
279 * Returns the number of bytes written to the buffer. 0 or a negative
280 * value indicates an error.
282 int zfpm_protobuf_encode_route(rib_dest_t
*dest
, struct route_entry
*re
,
283 uint8_t *in_buf
, size_t in_buf_len
)
286 QPB_DECLARE_STACK_ALLOCATOR(allocator
, 4096);
289 QPB_INIT_STACK_ALLOCATOR(allocator
);
291 msg
= create_route_message(&allocator
, dest
, re
);
297 len
= fpm__message__pack(msg
, (uint8_t *)in_buf
);
298 assert(len
<= in_buf_len
);
300 QPB_RESET_STACK_ALLOCATOR(allocator
);