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
)
145 struct nexthop
*nexthop
;
147 struct nexthop
*nexthops
[MULTIPATH_NUM
];
149 msg
= QPB_ALLOC(allocator
, typeof(*msg
));
155 fpm__add_route__init(msg
);
157 msg
->vrf_id
= zvrf_id(rib_dest_vrf(dest
));
159 qpb_address_family_set(&msg
->address_family
, rib_dest_af(dest
));
162 * XXX Hardcode subaddress family for now.
164 msg
->sub_address_family
= QPB__SUB_ADDRESS_FAMILY__UNICAST
;
165 msg
->key
= fpm_route_key_create(allocator
, rib_dest_prefix(dest
));
166 qpb_protocol_set(&msg
->protocol
, re
->type
);
168 if ((re
->flags
& ZEBRA_FLAG_BLACKHOLE
)
169 || (re
->flags
& ZEBRA_FLAG_REJECT
))
175 if (re
->flags
& ZEBRA_FLAG_BLACKHOLE
) {
176 msg
->route_type
= FPM__ROUTE_TYPE__BLACKHOLE
;
177 } else if (re
->flags
& ZEBRA_FLAG_REJECT
) {
178 msg
->route_type
= FPM__ROUTE_TYPE__UNREACHABLE
;
184 msg
->route_type
= FPM__ROUTE_TYPE__NORMAL
;
187 msg
->metric
= re
->metric
;
190 * Figure out the set of nexthops to be added to the message.
193 for (ALL_NEXTHOPS(re
->nexthop
, nexthop
)) {
194 if (num_nhs
>= multipath_num
)
197 if (num_nhs
>= ZEBRA_NUM_OF(nexthops
))
200 if (CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
))
203 if (!CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
))
206 nexthops
[num_nhs
] = nexthop
;
211 zfpm_debug("netlink_encode_route(): No useful nexthop.");
217 * And add them to the message.
219 if (!(msg
->nexthops
= qpb_alloc_ptr_array(allocator
, num_nhs
))) {
225 for (u
= 0; u
< num_nhs
; u
++) {
226 if (!add_nexthop(allocator
, msg
, dest
, nexthops
[u
])) {
232 assert(msg
->n_nexthops
== num_nhs
);
238 * create_route_message
240 static Fpm__Message
*create_route_message(qpb_allocator_t
*allocator
,
242 struct route_entry
*re
)
246 msg
= QPB_ALLOC(allocator
, typeof(*msg
));
252 fpm__message__init(msg
);
255 msg
->type
= FPM__MESSAGE__TYPE__DELETE_ROUTE
;
257 create_delete_route_message(allocator
, dest
, re
);
258 if (!msg
->delete_route
) {
265 msg
->type
= FPM__MESSAGE__TYPE__ADD_ROUTE
;
266 msg
->add_route
= create_add_route_message(allocator
, dest
, re
);
267 if (!msg
->add_route
) {
276 * zfpm_protobuf_encode_route
278 * Create a protobuf message corresponding to the given route in the
279 * given buffer space.
281 * Returns the number of bytes written to the buffer. 0 or a negative
282 * value indicates an error.
284 int zfpm_protobuf_encode_route(rib_dest_t
*dest
, struct route_entry
*re
,
285 uint8_t *in_buf
, size_t in_buf_len
)
288 QPB_DECLARE_STACK_ALLOCATOR(allocator
, 4096);
291 QPB_INIT_STACK_ALLOCATOR(allocator
);
293 msg
= create_route_message(&allocator
, dest
, re
);
299 len
= fpm__message__pack(msg
, (uint8_t *)in_buf
);
300 assert(len
<= in_buf_len
);
302 QPB_RESET_STACK_ALLOCATOR(allocator
);