]>
Commit | Line | Data |
---|---|---|
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" | |
29 | #include "zserv.h" | |
30 | #include "zebra_vrf.h" | |
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 | */ | |
43 | static Fpm__DeleteRoute * | |
44 | create_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); | |
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 | |
77 | add_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 | |
96 | || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) | |
97 | { | |
98 | gateway = &nexthop->gate; | |
99 | } | |
100 | ||
101 | if (nexthop->type == NEXTHOP_TYPE_IFINDEX) | |
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 | */ | |
143 | static Fpm__AddRoute * | |
144 | create_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; | |
152 | struct nexthop *nexthops[MULTIPATH_NUM]; | |
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 | ||
162 | msg->vrf_id = zvrf_id(rib_dest_vrf(dest)); | |
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 | { | |
201 | if (num_nhs >= multipath_num) | |
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 | */ | |
247 | static Fpm__Message * | |
248 | create_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 | */ | |
290 | int | |
291 | zfpm_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 | } |