]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_fpm_protobuf.c
Merge pull request #531 from qlyoung/fix-stack-ref
[mirror_frr.git] / zebra / zebra_fpm_protobuf.c
CommitLineData
fb0aa886
AS
1/*
2 * zebra_fpm_protobuf.c
3 *
4 * @copyright Copyright (C) 2016 Sproute Networks, Inc.
5 *
6 * @author Avneesh Sachdev <avneesh@sproute.com>
7 *
8 * This file is part of Quagga.
9 *
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
13 * later version.
14 *
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.
19 *
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
23 * 02111-1307, USA.
24 */
25#include <zebra.h>
26
27#include "log.h"
28#include "rib.h"
518acd6f
DL
29#include "zserv.h"
30#include "zebra_vrf.h"
fb0aa886
AS
31
32#include "qpb/qpb.pb-c.h"
33#include "qpb/qpb.h"
34#include "qpb/qpb_allocator.h"
35#include "qpb/linear_allocator.h"
36#include "fpm/fpm_pb.h"
37
38#include "zebra_fpm_private.h"
39
40/*
41 * create_delete_route_message
42 */
43static Fpm__DeleteRoute *
44create_delete_route_message (qpb_allocator_t *allocator, rib_dest_t *dest,
45 struct rib *rib)
46{
47 Fpm__DeleteRoute *msg;
48
49 msg = QPB_ALLOC(allocator, typeof(*msg));
50 if (!msg) {
51 assert(0);
52 return NULL;
53 }
54
55 fpm__delete_route__init(msg);
b74f1be8 56 msg->vrf_id = zvrf_id(rib_dest_vrf(dest));
fb0aa886
AS
57
58 qpb_address_family_set(&msg->address_family, rib_dest_af(dest));
59
60 /*
61 * XXX Hardcode subaddress family for now.
62 */
63 msg->sub_address_family = QPB__SUB_ADDRESS_FAMILY__UNICAST;
64 msg->key = fpm_route_key_create (allocator, rib_dest_prefix(dest));
65 if (!msg->key) {
66 assert(0);
67 return NULL;
68 }
69
70 return msg;
71}
72
73/*
74 * add_nexthop
75 */
76static inline int
77add_nexthop (qpb_allocator_t *allocator, Fpm__AddRoute *msg, rib_dest_t *dest,
78 struct nexthop *nexthop)
79{
80 uint32_t if_index;
81 union g_addr *gateway, *src;
82
83 gateway = src = NULL;
84
85 if_index = nexthop->ifindex;
86
87 if (nexthop->type == NEXTHOP_TYPE_IPV4
88 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
89 {
90 gateway = &nexthop->gate;
91 if (nexthop->src.ipv4.s_addr)
92 src = &nexthop->src;
93 }
94
95 if (nexthop->type == NEXTHOP_TYPE_IPV6
fb0aa886
AS
96 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
97 {
98 gateway = &nexthop->gate;
99 }
100
518acd6f 101 if (nexthop->type == NEXTHOP_TYPE_IFINDEX)
fb0aa886
AS
102 {
103 if (nexthop->src.ipv4.s_addr)
104 src = &nexthop->src;
105 }
106
107 if (!gateway && if_index == 0)
108 return 0;
109
110 /*
111 * We have a valid nexthop.
112 */
113 {
114 Fpm__Nexthop *pb_nh;
115 pb_nh = QPB_ALLOC(allocator, typeof(*pb_nh));
116 if (!pb_nh) {
117 assert(0);
118 return 0;
119 }
120
121 fpm__nexthop__init(pb_nh);
122
123 if (if_index != 0) {
124 pb_nh->if_id = qpb_if_identifier_create (allocator, if_index);
125 }
126
127 if (gateway) {
128 pb_nh->address = qpb_l3_address_create (allocator, gateway,
129 rib_dest_af(dest));
130 }
131
132 msg->nexthops[msg->n_nexthops++] = pb_nh;
133 }
134
135 // TODO: Use src.
136
137 return 1;
138}
139
140/*
141 * create_add_route_message
142 */
143static Fpm__AddRoute *
144create_add_route_message (qpb_allocator_t *allocator, rib_dest_t *dest,
145 struct rib *rib)
146{
147 Fpm__AddRoute *msg;
148 int discard;
149 struct nexthop *nexthop, *tnexthop;
150 int recursing;
151 uint num_nhs, u;
37fe7731 152 struct nexthop *nexthops[MULTIPATH_NUM];
fb0aa886
AS
153
154 msg = QPB_ALLOC(allocator, typeof(*msg));
155 if (!msg) {
156 assert(0);
157 return NULL;
158 }
159
160 fpm__add_route__init(msg);
161
b74f1be8 162 msg->vrf_id = zvrf_id(rib_dest_vrf(dest));
fb0aa886
AS
163
164 qpb_address_family_set (&msg->address_family, rib_dest_af(dest));
165
166 /*
167 * XXX Hardcode subaddress family for now.
168 */
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);
172
173 if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
174 discard = 1;
175 else
176 discard = 0;
177
178 if (discard)
179 {
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;
184 } else {
185 assert (0);
186 }
187 return msg;
188 }
189 else {
190 msg->route_type = FPM__ROUTE_TYPE__NORMAL;
191 }
192
193 msg->metric = rib->metric;
194
195 /*
196 * Figure out the set of nexthops to be added to the message.
197 */
198 num_nhs = 0;
199 for (ALL_NEXTHOPS_RO (rib->nexthop, nexthop, tnexthop, recursing))
200 {
37fe7731 201 if (num_nhs >= multipath_num)
fb0aa886
AS
202 break;
203
204 if (num_nhs >= ZEBRA_NUM_OF(nexthops))
205 break;
206
207 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
208 continue;
209
210 if (!CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
211 continue;
212
213 nexthops[num_nhs] = nexthop;
214 num_nhs++;
215 }
216
217 if (!num_nhs) {
218 zfpm_debug ("netlink_encode_route(): No useful nexthop.");
219 assert(0);
220 return NULL;
221 }
222
223 /*
224 * And add them to the message.
225 */
226 if (!(msg->nexthops = qpb_alloc_ptr_array(allocator, num_nhs))) {
227 assert(0);
228 return NULL;
229 }
230
231 msg->n_nexthops = 0;
232 for (u = 0; u < num_nhs; u++) {
233 if (!add_nexthop(allocator, msg, dest, nexthops[u])) {
234 assert(0);
235 return NULL;
236 }
237 }
238
239 assert(msg->n_nexthops == num_nhs);
240
241 return msg;
242}
243
244/*
245 * create_route_message
246 */
247static Fpm__Message *
248create_route_message (qpb_allocator_t *allocator, rib_dest_t *dest,
249 struct rib *rib)
250{
251 Fpm__Message *msg;
252
253 msg = QPB_ALLOC(allocator, typeof(*msg));
254 if (!msg) {
255 assert(0);
256 return NULL;
257 }
258
259 fpm__message__init(msg);
260
261 if (!rib) {
262 msg->type = FPM__MESSAGE__TYPE__DELETE_ROUTE;
263 msg->delete_route = create_delete_route_message(allocator, dest, rib);
264 if (!msg->delete_route) {
265 assert(0);
266 return NULL;
267 }
268 return msg;
269 }
270
271 msg->type = FPM__MESSAGE__TYPE__ADD_ROUTE;
272 msg->add_route = create_add_route_message(allocator, dest, rib);
273 if (!msg->add_route) {
274 assert(0);
275 return NULL;
276 }
277
278 return msg;
279}
280
281/*
282 * zfpm_protobuf_encode_route
283 *
284 * Create a protobuf message corresponding to the given route in the
285 * given buffer space.
286 *
287 * Returns the number of bytes written to the buffer. 0 or a negative
288 * value indicates an error.
289 */
290int
291zfpm_protobuf_encode_route (rib_dest_t *dest, struct rib *rib,
292 uint8_t *in_buf, size_t in_buf_len)
293{
294 Fpm__Message *msg;
295 QPB_DECLARE_STACK_ALLOCATOR (allocator, 4096);
296 size_t len;
297
298 QPB_INIT_STACK_ALLOCATOR (allocator);
299
300 msg = create_route_message(&allocator, dest, rib);
301 if (!msg) {
302 assert(0);
303 return 0;
304 }
305
306 len = fpm__message__pack(msg, (uint8_t *) in_buf);
307 assert(len <= in_buf_len);
308
309 QPB_RESET_STACK_ALLOCATOR (allocator);
310 return len;
311}