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