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
*
43 create_delete_route_message (qpb_allocator_t
*allocator
, rib_dest_t
*dest
,
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
));
76 add_nexthop (qpb_allocator_t
*allocator
, Fpm__AddRoute
*msg
, rib_dest_t
*dest
,
77 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
)
89 gateway
= &nexthop
->gate
;
90 if (nexthop
->src
.ipv4
.s_addr
)
94 if (nexthop
->type
== NEXTHOP_TYPE_IPV6
95 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFINDEX
)
97 gateway
= &nexthop
->gate
;
100 if (nexthop
->type
== NEXTHOP_TYPE_IFINDEX
)
102 if (nexthop
->src
.ipv4
.s_addr
)
106 if (!gateway
&& if_index
== 0)
110 * We have a valid nexthop.
114 pb_nh
= QPB_ALLOC(allocator
, typeof(*pb_nh
));
120 fpm__nexthop__init(pb_nh
);
123 pb_nh
->if_id
= qpb_if_identifier_create (allocator
, if_index
);
127 pb_nh
->address
= qpb_l3_address_create (allocator
, gateway
,
131 msg
->nexthops
[msg
->n_nexthops
++] = pb_nh
;
140 * create_add_route_message
142 static Fpm__AddRoute
*
143 create_add_route_message (qpb_allocator_t
*allocator
, rib_dest_t
*dest
,
148 struct nexthop
*nexthop
, *tnexthop
;
151 struct nexthop
*nexthops
[MULTIPATH_NUM
];
153 msg
= QPB_ALLOC(allocator
, typeof(*msg
));
159 fpm__add_route__init(msg
);
161 msg
->vrf_id
= zvrf_id(rib_dest_vrf(dest
));
163 qpb_address_family_set (&msg
->address_family
, rib_dest_af(dest
));
166 * XXX Hardcode subaddress family for now.
168 msg
->sub_address_family
= QPB__SUB_ADDRESS_FAMILY__UNICAST
;
169 msg
->key
= fpm_route_key_create (allocator
, rib_dest_prefix(dest
));
170 qpb_protocol_set (&msg
->protocol
, rib
->type
);
172 if ((rib
->flags
& ZEBRA_FLAG_BLACKHOLE
) || (rib
->flags
& ZEBRA_FLAG_REJECT
))
179 if (rib
->flags
& ZEBRA_FLAG_BLACKHOLE
) {
180 msg
->route_type
= FPM__ROUTE_TYPE__BLACKHOLE
;
181 } else if (rib
->flags
& ZEBRA_FLAG_REJECT
) {
182 msg
->route_type
= FPM__ROUTE_TYPE__UNREACHABLE
;
189 msg
->route_type
= FPM__ROUTE_TYPE__NORMAL
;
192 msg
->metric
= rib
->metric
;
195 * Figure out the set of nexthops to be added to the message.
198 for (ALL_NEXTHOPS_RO (rib
->nexthop
, nexthop
, tnexthop
, recursing
))
200 if (num_nhs
>= multipath_num
)
203 if (num_nhs
>= ZEBRA_NUM_OF(nexthops
))
206 if (CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
))
209 if (!CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
))
212 nexthops
[num_nhs
] = nexthop
;
217 zfpm_debug ("netlink_encode_route(): No useful nexthop.");
223 * And add them to the message.
225 if (!(msg
->nexthops
= qpb_alloc_ptr_array(allocator
, num_nhs
))) {
231 for (u
= 0; u
< num_nhs
; u
++) {
232 if (!add_nexthop(allocator
, msg
, dest
, nexthops
[u
])) {
238 assert(msg
->n_nexthops
== num_nhs
);
244 * create_route_message
246 static Fpm__Message
*
247 create_route_message (qpb_allocator_t
*allocator
, rib_dest_t
*dest
,
252 msg
= QPB_ALLOC(allocator
, typeof(*msg
));
258 fpm__message__init(msg
);
261 msg
->type
= FPM__MESSAGE__TYPE__DELETE_ROUTE
;
262 msg
->delete_route
= create_delete_route_message(allocator
, dest
, rib
);
263 if (!msg
->delete_route
) {
270 msg
->type
= FPM__MESSAGE__TYPE__ADD_ROUTE
;
271 msg
->add_route
= create_add_route_message(allocator
, dest
, rib
);
272 if (!msg
->add_route
) {
281 * zfpm_protobuf_encode_route
283 * Create a protobuf message corresponding to the given route in the
284 * given buffer space.
286 * Returns the number of bytes written to the buffer. 0 or a negative
287 * value indicates an error.
290 zfpm_protobuf_encode_route (rib_dest_t
*dest
, struct rib
*rib
,
291 uint8_t *in_buf
, size_t in_buf_len
)
294 QPB_DECLARE_STACK_ALLOCATOR (allocator
, 4096);
297 QPB_INIT_STACK_ALLOCATOR (allocator
);
299 msg
= create_route_message(&allocator
, dest
, rib
);
305 len
= fpm__message__pack(msg
, (uint8_t *) in_buf
);
306 assert(len
<= in_buf_len
);
308 QPB_RESET_STACK_ALLOCATOR (allocator
);