]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_fpm_protobuf.c
d18a62e6f805d5c4d8805399bef66e940b7276a1
[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_router.h"
38 #include "zebra_fpm_private.h"
39
40 /*
41 * create_delete_route_message
42 */
43 static Fpm__DeleteRoute *create_delete_route_message(qpb_allocator_t *allocator,
44 rib_dest_t *dest,
45 struct route_entry *re)
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);
56 msg->vrf_id = zvrf_id(rib_dest_vrf(dest));
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 */
76 static inline int add_nexthop(qpb_allocator_t *allocator, Fpm__AddRoute *msg,
77 rib_dest_t *dest, 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 gateway = &nexthop->gate;
89 if (nexthop->src.ipv4.s_addr != INADDR_ANY)
90 src = &nexthop->src;
91 }
92
93 if (nexthop->type == NEXTHOP_TYPE_IPV6
94 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) {
95 gateway = &nexthop->gate;
96 }
97
98 if (nexthop->type == NEXTHOP_TYPE_IFINDEX) {
99 if (nexthop->src.ipv4.s_addr != INADDR_ANY)
100 src = &nexthop->src;
101 }
102
103 if (!gateway && if_index == 0)
104 return 0;
105
106 /*
107 * We have a valid nexthop.
108 */
109 {
110 Fpm__Nexthop *pb_nh;
111 pb_nh = QPB_ALLOC(allocator, typeof(*pb_nh));
112 if (!pb_nh) {
113 assert(0);
114 return 0;
115 }
116
117 fpm__nexthop__init(pb_nh);
118
119 if (if_index != 0) {
120 pb_nh->if_id =
121 qpb_if_identifier_create(allocator, if_index);
122 }
123
124 if (gateway) {
125 pb_nh->address = qpb_l3_address_create(
126 allocator, gateway, rib_dest_af(dest));
127 }
128
129 msg->nexthops[msg->n_nexthops++] = pb_nh;
130 }
131
132 // TODO: Use src.
133 (void)src;
134
135 return 1;
136 }
137
138 /*
139 * create_add_route_message
140 */
141 static Fpm__AddRoute *create_add_route_message(qpb_allocator_t *allocator,
142 rib_dest_t *dest,
143 struct route_entry *re)
144 {
145 Fpm__AddRoute *msg;
146 struct nexthop *nexthop;
147 uint num_nhs, u;
148 struct nexthop *nexthops[MULTIPATH_NUM];
149
150 msg = QPB_ALLOC(allocator, typeof(*msg));
151 if (!msg) {
152 assert(0);
153 return NULL;
154 }
155
156 fpm__add_route__init(msg);
157
158 msg->vrf_id = zvrf_id(rib_dest_vrf(dest));
159
160 qpb_address_family_set(&msg->address_family, rib_dest_af(dest));
161
162 /*
163 * XXX Hardcode subaddress family for now.
164 */
165 msg->sub_address_family = QPB__SUB_ADDRESS_FAMILY__UNICAST;
166 msg->key = fpm_route_key_create(allocator, rib_dest_prefix(dest));
167 qpb_protocol_set(&msg->protocol, re->type);
168 msg->has_route_type = 1;
169 msg->route_type = FPM__ROUTE_TYPE__NORMAL;
170 msg->metric = re->metric;
171
172 /*
173 * Figure out the set of nexthops to be added to the message.
174 */
175 num_nhs = 0;
176 for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) {
177 if (num_nhs >= zrouter.multipath_num)
178 break;
179
180 if (num_nhs >= array_size(nexthops))
181 break;
182
183 if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) {
184 switch (nexthop->bh_type) {
185 case BLACKHOLE_REJECT:
186 msg->route_type = FPM__ROUTE_TYPE__UNREACHABLE;
187 break;
188 case BLACKHOLE_NULL:
189 case BLACKHOLE_UNSPEC:
190 case BLACKHOLE_ADMINPROHIB:
191 msg->route_type = FPM__ROUTE_TYPE__BLACKHOLE;
192 break;
193 }
194 return msg;
195 }
196
197 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
198 continue;
199
200 if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
201 continue;
202
203 nexthops[num_nhs] = nexthop;
204 num_nhs++;
205 }
206
207 if (!num_nhs) {
208 zfpm_debug("netlink_encode_route(): No useful nexthop.");
209 assert(0);
210 return NULL;
211 }
212
213 /*
214 * And add them to the message.
215 */
216 if (!(msg->nexthops = qpb_alloc_ptr_array(allocator, num_nhs))) {
217 assert(0);
218 return NULL;
219 }
220
221 msg->n_nexthops = 0;
222 for (u = 0; u < num_nhs; u++) {
223 if (!add_nexthop(allocator, msg, dest, nexthops[u])) {
224 assert(0);
225 return NULL;
226 }
227 }
228
229 assert(msg->n_nexthops == num_nhs);
230
231 return msg;
232 }
233
234 /*
235 * create_route_message
236 */
237 static Fpm__Message *create_route_message(qpb_allocator_t *allocator,
238 rib_dest_t *dest,
239 struct route_entry *re)
240 {
241 Fpm__Message *msg;
242
243 msg = QPB_ALLOC(allocator, typeof(*msg));
244 if (!msg) {
245 assert(0);
246 return NULL;
247 }
248
249 fpm__message__init(msg);
250
251 if (!re) {
252 msg->has_type = 1;
253 msg->type = FPM__MESSAGE__TYPE__DELETE_ROUTE;
254 msg->delete_route =
255 create_delete_route_message(allocator, dest, re);
256 if (!msg->delete_route) {
257 assert(0);
258 return NULL;
259 }
260 return msg;
261 }
262
263 msg->has_type = 1;
264 msg->type = FPM__MESSAGE__TYPE__ADD_ROUTE;
265 msg->add_route = create_add_route_message(allocator, dest, re);
266 if (!msg->add_route) {
267 assert(0);
268 return NULL;
269 }
270
271 return msg;
272 }
273
274 /*
275 * zfpm_protobuf_encode_route
276 *
277 * Create a protobuf message corresponding to the given route in the
278 * given buffer space.
279 *
280 * Returns the number of bytes written to the buffer. 0 or a negative
281 * value indicates an error.
282 */
283 int zfpm_protobuf_encode_route(rib_dest_t *dest, struct route_entry *re,
284 uint8_t *in_buf, size_t in_buf_len)
285 {
286 Fpm__Message *msg;
287 QPB_DECLARE_STACK_ALLOCATOR(allocator, 4096);
288 size_t len;
289
290 QPB_INIT_STACK_ALLOCATOR(allocator);
291
292 msg = create_route_message(&allocator, dest, re);
293 if (!msg) {
294 assert(0);
295 return 0;
296 }
297
298 len = fpm__message__pack(msg, in_buf);
299 assert(len <= in_buf_len);
300
301 QPB_RESET_STACK_ALLOCATOR(allocator);
302 return len;
303 }