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
21 * along with Quagga; see the file COPYING. If not, write to the Free
22 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
30 #include "qpb/qpb.pb-c.h"
32 #include "qpb/qpb_allocator.h"
33 #include "qpb/linear_allocator.h"
34 #include "fpm/fpm_pb.h"
36 #include "zebra_fpm_private.h"
39 * create_delete_route_message
41 static Fpm__DeleteRoute *
42 create_delete_route_message (qpb_allocator_t *allocator, rib_dest_t *dest,
45 Fpm__DeleteRoute *msg;
47 msg = QPB_ALLOC(allocator, typeof(*msg));
53 fpm__delete_route__init(msg);
54 msg->vrf_id = rib_dest_vrf(dest)->vrf_id;
56 qpb_address_family_set(&msg->address_family, rib_dest_af(dest));
59 * XXX Hardcode subaddress family for now.
61 msg->sub_address_family = QPB__SUB_ADDRESS_FAMILY__UNICAST;
62 msg->key = fpm_route_key_create (allocator, rib_dest_prefix(dest));
75 add_nexthop (qpb_allocator_t *allocator, Fpm__AddRoute *msg, rib_dest_t *dest,
76 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)
88 gateway = &nexthop->gate;
89 if (nexthop->src.ipv4.s_addr)
93 if (nexthop->type == NEXTHOP_TYPE_IPV6
94 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
95 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
97 gateway = &nexthop->gate;
100 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
101 || nexthop->type == NEXTHOP_TYPE_IFNAME)
103 if (nexthop->src.ipv4.s_addr)
107 if (!gateway && if_index == 0)
111 * We have a valid nexthop.
115 pb_nh = QPB_ALLOC(allocator, typeof(*pb_nh));
121 fpm__nexthop__init(pb_nh);
124 pb_nh->if_id = qpb_if_identifier_create (allocator, if_index);
128 pb_nh->address = qpb_l3_address_create (allocator, gateway,
132 msg->nexthops[msg->n_nexthops++] = pb_nh;
141 * create_add_route_message
143 static Fpm__AddRoute *
144 create_add_route_message (qpb_allocator_t *allocator, rib_dest_t *dest,
149 struct nexthop *nexthop, *tnexthop;
152 struct nexthop *nexthops[MAX (MULTIPATH_NUM, 64)];
154 msg = QPB_ALLOC(allocator, typeof(*msg));
160 fpm__add_route__init(msg);
162 msg->vrf_id = rib_dest_vrf(dest)->vrf_id;
164 qpb_address_family_set (&msg->address_family, rib_dest_af(dest));
167 * XXX Hardcode subaddress family for now.
169 msg->sub_address_family = QPB__SUB_ADDRESS_FAMILY__UNICAST;
170 msg->key = fpm_route_key_create (allocator, rib_dest_prefix(dest));
171 qpb_protocol_set (&msg->protocol, rib->type);
173 if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
180 if (rib->flags & ZEBRA_FLAG_BLACKHOLE) {
181 msg->route_type = FPM__ROUTE_TYPE__BLACKHOLE;
182 } else if (rib->flags & ZEBRA_FLAG_REJECT) {
183 msg->route_type = FPM__ROUTE_TYPE__UNREACHABLE;
190 msg->route_type = FPM__ROUTE_TYPE__NORMAL;
193 msg->metric = rib->metric;
196 * Figure out the set of nexthops to be added to the message.
199 for (ALL_NEXTHOPS_RO (rib->nexthop, nexthop, tnexthop, recursing))
201 if (MULTIPATH_NUM != 0 && num_nhs >= MULTIPATH_NUM)
204 if (num_nhs >= ZEBRA_NUM_OF(nexthops))
207 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
210 if (!CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
213 nexthops[num_nhs] = nexthop;
218 zfpm_debug ("netlink_encode_route(): No useful nexthop.");
224 * And add them to the message.
226 if (!(msg->nexthops = qpb_alloc_ptr_array(allocator, num_nhs))) {
232 for (u = 0; u < num_nhs; u++) {
233 if (!add_nexthop(allocator, msg, dest, nexthops[u])) {
239 assert(msg->n_nexthops == num_nhs);
245 * create_route_message
247 static Fpm__Message *
248 create_route_message (qpb_allocator_t *allocator, rib_dest_t *dest,
253 msg = QPB_ALLOC(allocator, typeof(*msg));
259 fpm__message__init(msg);
262 msg->type = FPM__MESSAGE__TYPE__DELETE_ROUTE;
263 msg->delete_route = create_delete_route_message(allocator, dest, rib);
264 if (!msg->delete_route) {
271 msg->type = FPM__MESSAGE__TYPE__ADD_ROUTE;
272 msg->add_route = create_add_route_message(allocator, dest, rib);
273 if (!msg->add_route) {
282 * zfpm_protobuf_encode_route
284 * Create a protobuf message corresponding to the given route in the
285 * given buffer space.
287 * Returns the number of bytes written to the buffer. 0 or a negative
288 * value indicates an error.
291 zfpm_protobuf_encode_route (rib_dest_t *dest, struct rib *rib,
292 uint8_t *in_buf, size_t in_buf_len)
295 QPB_DECLARE_STACK_ALLOCATOR (allocator, 4096);
298 QPB_INIT_STACK_ALLOCATOR (allocator);
300 msg = create_route_message(&allocator, dest, rib);
306 len = fpm__message__pack(msg, (uint8_t *) in_buf);
307 assert(len <= in_buf_len);
309 QPB_RESET_STACK_ALLOCATOR (allocator);