]>
Commit | Line | Data |
---|---|---|
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 | * | |
896014f4 DL |
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 | |
fb0aa886 AS |
23 | */ |
24 | #include <zebra.h> | |
25 | ||
26 | #include "log.h" | |
27 | #include "rib.h" | |
518acd6f DL |
28 | #include "zserv.h" |
29 | #include "zebra_vrf.h" | |
fb0aa886 AS |
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 | ||
b03e089d | 37 | #include "zebra_router.h" |
fb0aa886 AS |
38 | #include "zebra_fpm_private.h" |
39 | ||
40 | /* | |
41 | * create_delete_route_message | |
42 | */ | |
d62a17ae | 43 | static Fpm__DeleteRoute *create_delete_route_message(qpb_allocator_t *allocator, |
44 | rib_dest_t *dest, | |
45 | struct route_entry *re) | |
fb0aa886 | 46 | { |
d62a17ae | 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; | |
fb0aa886 AS |
71 | } |
72 | ||
73 | /* | |
74 | * add_nexthop | |
75 | */ | |
d62a17ae | 76 | static inline int add_nexthop(qpb_allocator_t *allocator, Fpm__AddRoute *msg, |
77 | rib_dest_t *dest, struct nexthop *nexthop) | |
fb0aa886 | 78 | { |
d62a17ae | 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; | |
975a328e | 89 | if (nexthop->src.ipv4.s_addr != INADDR_ANY) |
d62a17ae | 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) { | |
975a328e | 99 | if (nexthop->src.ipv4.s_addr != INADDR_ANY) |
d62a17ae | 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. | |
4f4060f6 | 133 | (void)src; |
d62a17ae | 134 | |
135 | return 1; | |
fb0aa886 AS |
136 | } |
137 | ||
138 | /* | |
139 | * create_add_route_message | |
140 | */ | |
d62a17ae | 141 | static Fpm__AddRoute *create_add_route_message(qpb_allocator_t *allocator, |
142 | rib_dest_t *dest, | |
143 | struct route_entry *re) | |
fb0aa886 | 144 | { |
d62a17ae | 145 | Fpm__AddRoute *msg; |
d62a17ae | 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); | |
1a6a5e69 | 168 | msg->has_route_type = 1; |
a8309422 | 169 | msg->route_type = FPM__ROUTE_TYPE__NORMAL; |
d62a17ae | 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; | |
97cd9bfc | 176 | for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) { |
b03e089d | 177 | if (num_nhs >= zrouter.multipath_num) |
d62a17ae | 178 | break; |
179 | ||
7e3a1ec7 | 180 | if (num_nhs >= array_size(nexthops)) |
d62a17ae | 181 | break; |
182 | ||
a8309422 DL |
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: | |
a98701f0 DS |
189 | case BLACKHOLE_UNSPEC: |
190 | case BLACKHOLE_ADMINPROHIB: | |
a8309422 DL |
191 | msg->route_type = FPM__ROUTE_TYPE__BLACKHOLE; |
192 | break; | |
193 | } | |
194 | return msg; | |
195 | } | |
196 | ||
d62a17ae | 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; | |
fb0aa886 AS |
232 | } |
233 | ||
234 | /* | |
235 | * create_route_message | |
236 | */ | |
d62a17ae | 237 | static Fpm__Message *create_route_message(qpb_allocator_t *allocator, |
238 | rib_dest_t *dest, | |
239 | struct route_entry *re) | |
fb0aa886 | 240 | { |
d62a17ae | 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) { | |
1a6a5e69 | 252 | msg->has_type = 1; |
d62a17ae | 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 | ||
1a6a5e69 | 263 | msg->has_type = 1; |
d62a17ae | 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; | |
fb0aa886 AS |
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 | */ | |
d62a17ae | 283 | int zfpm_protobuf_encode_route(rib_dest_t *dest, struct route_entry *re, |
284 | uint8_t *in_buf, size_t in_buf_len) | |
fb0aa886 | 285 | { |
d62a17ae | 286 | Fpm__Message *msg; |
287 | QPB_DECLARE_STACK_ALLOCATOR(allocator, 4096); | |
288 | size_t len; | |
fb0aa886 | 289 | |
d62a17ae | 290 | QPB_INIT_STACK_ALLOCATOR(allocator); |
fb0aa886 | 291 | |
d62a17ae | 292 | msg = create_route_message(&allocator, dest, re); |
293 | if (!msg) { | |
294 | assert(0); | |
295 | return 0; | |
296 | } | |
fb0aa886 | 297 | |
c4efd0f4 | 298 | len = fpm__message__pack(msg, in_buf); |
d62a17ae | 299 | assert(len <= in_buf_len); |
fb0aa886 | 300 | |
d62a17ae | 301 | QPB_RESET_STACK_ALLOCATOR(allocator); |
302 | return len; | |
fb0aa886 | 303 | } |