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_fpm_private.h"
40 * create_delete_route_message
42 static Fpm__DeleteRoute
*create_delete_route_message(qpb_allocator_t
*allocator
,
44 struct route_entry
*re
)
46 Fpm__DeleteRoute
*msg
;
48 msg
= QPB_ALLOC(allocator
, typeof(*msg
));
54 fpm__delete_route__init(msg
);
55 msg
->vrf_id
= zvrf_id(rib_dest_vrf(dest
));
57 qpb_address_family_set(&msg
->address_family
, rib_dest_af(dest
));
60 * XXX Hardcode subaddress family for now.
62 msg
->sub_address_family
= QPB__SUB_ADDRESS_FAMILY__UNICAST
;
63 msg
->key
= fpm_route_key_create(allocator
, rib_dest_prefix(dest
));
75 static inline int add_nexthop(qpb_allocator_t
*allocator
, Fpm__AddRoute
*msg
,
76 rib_dest_t
*dest
, struct nexthop
*nexthop
)
79 union g_addr
*gateway
, *src
;
83 if_index
= nexthop
->ifindex
;
85 if (nexthop
->type
== NEXTHOP_TYPE_IPV4
86 || nexthop
->type
== NEXTHOP_TYPE_IPV4_IFINDEX
) {
87 gateway
= &nexthop
->gate
;
88 if (nexthop
->src
.ipv4
.s_addr
)
92 if (nexthop
->type
== NEXTHOP_TYPE_IPV6
93 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFINDEX
) {
94 gateway
= &nexthop
->gate
;
97 if (nexthop
->type
== NEXTHOP_TYPE_IFINDEX
) {
98 if (nexthop
->src
.ipv4
.s_addr
)
102 if (!gateway
&& if_index
== 0)
106 * We have a valid nexthop.
110 pb_nh
= QPB_ALLOC(allocator
, typeof(*pb_nh
));
116 fpm__nexthop__init(pb_nh
);
120 qpb_if_identifier_create(allocator
, if_index
);
124 pb_nh
->address
= qpb_l3_address_create(
125 allocator
, gateway
, rib_dest_af(dest
));
128 msg
->nexthops
[msg
->n_nexthops
++] = pb_nh
;
137 * create_add_route_message
139 static Fpm__AddRoute
*create_add_route_message(qpb_allocator_t
*allocator
,
141 struct route_entry
*re
)
144 struct nexthop
*nexthop
;
146 struct nexthop
*nexthops
[MULTIPATH_NUM
];
148 msg
= QPB_ALLOC(allocator
, typeof(*msg
));
154 fpm__add_route__init(msg
);
156 msg
->vrf_id
= zvrf_id(rib_dest_vrf(dest
));
158 qpb_address_family_set(&msg
->address_family
, rib_dest_af(dest
));
161 * XXX Hardcode subaddress family for now.
163 msg
->sub_address_family
= QPB__SUB_ADDRESS_FAMILY__UNICAST
;
164 msg
->key
= fpm_route_key_create(allocator
, rib_dest_prefix(dest
));
165 qpb_protocol_set(&msg
->protocol
, re
->type
);
166 msg
->route_type
= FPM__ROUTE_TYPE__NORMAL
;
167 msg
->metric
= re
->metric
;
170 * Figure out the set of nexthops to be added to the message.
173 for (ALL_NEXTHOPS(re
->nexthop
, nexthop
)) {
174 if (num_nhs
>= multipath_num
)
177 if (num_nhs
>= ZEBRA_NUM_OF(nexthops
))
180 if (nexthop
->type
== NEXTHOP_TYPE_BLACKHOLE
) {
181 switch (nexthop
->bh_type
) {
182 case BLACKHOLE_REJECT
:
183 msg
->route_type
= FPM__ROUTE_TYPE__UNREACHABLE
;
187 msg
->route_type
= FPM__ROUTE_TYPE__BLACKHOLE
;
193 if (CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
))
196 if (!CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
))
199 nexthops
[num_nhs
] = nexthop
;
204 zfpm_debug("netlink_encode_route(): No useful nexthop.");
210 * And add them to the message.
212 if (!(msg
->nexthops
= qpb_alloc_ptr_array(allocator
, num_nhs
))) {
218 for (u
= 0; u
< num_nhs
; u
++) {
219 if (!add_nexthop(allocator
, msg
, dest
, nexthops
[u
])) {
225 assert(msg
->n_nexthops
== num_nhs
);
231 * create_route_message
233 static Fpm__Message
*create_route_message(qpb_allocator_t
*allocator
,
235 struct route_entry
*re
)
239 msg
= QPB_ALLOC(allocator
, typeof(*msg
));
245 fpm__message__init(msg
);
248 msg
->type
= FPM__MESSAGE__TYPE__DELETE_ROUTE
;
250 create_delete_route_message(allocator
, dest
, re
);
251 if (!msg
->delete_route
) {
258 msg
->type
= FPM__MESSAGE__TYPE__ADD_ROUTE
;
259 msg
->add_route
= create_add_route_message(allocator
, dest
, re
);
260 if (!msg
->add_route
) {
269 * zfpm_protobuf_encode_route
271 * Create a protobuf message corresponding to the given route in the
272 * given buffer space.
274 * Returns the number of bytes written to the buffer. 0 or a negative
275 * value indicates an error.
277 int zfpm_protobuf_encode_route(rib_dest_t
*dest
, struct route_entry
*re
,
278 uint8_t *in_buf
, size_t in_buf_len
)
281 QPB_DECLARE_STACK_ALLOCATOR(allocator
, 4096);
284 QPB_INIT_STACK_ALLOCATOR(allocator
);
286 msg
= create_route_message(&allocator
, dest
, re
);
292 len
= fpm__message__pack(msg
, (uint8_t *)in_buf
);
293 assert(len
<= in_buf_len
);
295 QPB_RESET_STACK_ALLOCATOR(allocator
);