]>
Commit | Line | Data |
---|---|---|
acddc0ed | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
fb0aa886 AS |
2 | /* |
3 | * zebra_fpm_protobuf.c | |
4 | * | |
5 | * @copyright Copyright (C) 2016 Sproute Networks, Inc. | |
6 | * | |
7 | * @author Avneesh Sachdev <avneesh@sproute.com> | |
fb0aa886 AS |
8 | */ |
9 | #include <zebra.h> | |
10 | ||
11 | #include "log.h" | |
12 | #include "rib.h" | |
518acd6f DL |
13 | #include "zserv.h" |
14 | #include "zebra_vrf.h" | |
fb0aa886 AS |
15 | |
16 | #include "qpb/qpb.pb-c.h" | |
17 | #include "qpb/qpb.h" | |
18 | #include "qpb/qpb_allocator.h" | |
19 | #include "qpb/linear_allocator.h" | |
20 | #include "fpm/fpm_pb.h" | |
21 | ||
b03e089d | 22 | #include "zebra_router.h" |
fb0aa886 AS |
23 | #include "zebra_fpm_private.h" |
24 | ||
25 | /* | |
26 | * create_delete_route_message | |
27 | */ | |
d62a17ae | 28 | static Fpm__DeleteRoute *create_delete_route_message(qpb_allocator_t *allocator, |
29 | rib_dest_t *dest, | |
30 | struct route_entry *re) | |
fb0aa886 | 31 | { |
d62a17ae | 32 | Fpm__DeleteRoute *msg; |
33 | ||
34 | msg = QPB_ALLOC(allocator, typeof(*msg)); | |
35 | if (!msg) { | |
36 | assert(0); | |
37 | return NULL; | |
38 | } | |
39 | ||
40 | fpm__delete_route__init(msg); | |
41 | msg->vrf_id = zvrf_id(rib_dest_vrf(dest)); | |
42 | ||
43 | qpb_address_family_set(&msg->address_family, rib_dest_af(dest)); | |
44 | ||
45 | /* | |
46 | * XXX Hardcode subaddress family for now. | |
47 | */ | |
48 | msg->sub_address_family = QPB__SUB_ADDRESS_FAMILY__UNICAST; | |
49 | msg->key = fpm_route_key_create(allocator, rib_dest_prefix(dest)); | |
50 | if (!msg->key) { | |
51 | assert(0); | |
52 | return NULL; | |
53 | } | |
54 | ||
55 | return msg; | |
fb0aa886 AS |
56 | } |
57 | ||
58 | /* | |
59 | * add_nexthop | |
60 | */ | |
d62a17ae | 61 | static inline int add_nexthop(qpb_allocator_t *allocator, Fpm__AddRoute *msg, |
62 | rib_dest_t *dest, struct nexthop *nexthop) | |
fb0aa886 | 63 | { |
d62a17ae | 64 | uint32_t if_index; |
65 | union g_addr *gateway, *src; | |
66 | ||
67 | gateway = src = NULL; | |
68 | ||
69 | if_index = nexthop->ifindex; | |
70 | ||
71 | if (nexthop->type == NEXTHOP_TYPE_IPV4 | |
72 | || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) { | |
73 | gateway = &nexthop->gate; | |
975a328e | 74 | if (nexthop->src.ipv4.s_addr != INADDR_ANY) |
d62a17ae | 75 | src = &nexthop->src; |
76 | } | |
77 | ||
78 | if (nexthop->type == NEXTHOP_TYPE_IPV6 | |
79 | || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) { | |
80 | gateway = &nexthop->gate; | |
81 | } | |
82 | ||
83 | if (nexthop->type == NEXTHOP_TYPE_IFINDEX) { | |
975a328e | 84 | if (nexthop->src.ipv4.s_addr != INADDR_ANY) |
d62a17ae | 85 | src = &nexthop->src; |
86 | } | |
87 | ||
88 | if (!gateway && if_index == 0) | |
89 | return 0; | |
90 | ||
91 | /* | |
92 | * We have a valid nexthop. | |
93 | */ | |
94 | { | |
95 | Fpm__Nexthop *pb_nh; | |
96 | pb_nh = QPB_ALLOC(allocator, typeof(*pb_nh)); | |
97 | if (!pb_nh) { | |
98 | assert(0); | |
99 | return 0; | |
100 | } | |
101 | ||
102 | fpm__nexthop__init(pb_nh); | |
103 | ||
104 | if (if_index != 0) { | |
105 | pb_nh->if_id = | |
106 | qpb_if_identifier_create(allocator, if_index); | |
107 | } | |
108 | ||
109 | if (gateway) { | |
110 | pb_nh->address = qpb_l3_address_create( | |
111 | allocator, gateway, rib_dest_af(dest)); | |
112 | } | |
113 | ||
114 | msg->nexthops[msg->n_nexthops++] = pb_nh; | |
115 | } | |
116 | ||
117 | // TODO: Use src. | |
4f4060f6 | 118 | (void)src; |
d62a17ae | 119 | |
120 | return 1; | |
fb0aa886 AS |
121 | } |
122 | ||
123 | /* | |
124 | * create_add_route_message | |
125 | */ | |
d62a17ae | 126 | static Fpm__AddRoute *create_add_route_message(qpb_allocator_t *allocator, |
127 | rib_dest_t *dest, | |
128 | struct route_entry *re) | |
fb0aa886 | 129 | { |
d62a17ae | 130 | Fpm__AddRoute *msg; |
d62a17ae | 131 | struct nexthop *nexthop; |
132 | uint num_nhs, u; | |
133 | struct nexthop *nexthops[MULTIPATH_NUM]; | |
134 | ||
135 | msg = QPB_ALLOC(allocator, typeof(*msg)); | |
136 | if (!msg) { | |
137 | assert(0); | |
138 | return NULL; | |
139 | } | |
140 | ||
141 | fpm__add_route__init(msg); | |
142 | ||
143 | msg->vrf_id = zvrf_id(rib_dest_vrf(dest)); | |
144 | ||
145 | qpb_address_family_set(&msg->address_family, rib_dest_af(dest)); | |
146 | ||
147 | /* | |
148 | * XXX Hardcode subaddress family for now. | |
149 | */ | |
150 | msg->sub_address_family = QPB__SUB_ADDRESS_FAMILY__UNICAST; | |
151 | msg->key = fpm_route_key_create(allocator, rib_dest_prefix(dest)); | |
152 | qpb_protocol_set(&msg->protocol, re->type); | |
1a6a5e69 | 153 | msg->has_route_type = 1; |
a8309422 | 154 | msg->route_type = FPM__ROUTE_TYPE__NORMAL; |
d62a17ae | 155 | msg->metric = re->metric; |
156 | ||
157 | /* | |
158 | * Figure out the set of nexthops to be added to the message. | |
159 | */ | |
160 | num_nhs = 0; | |
97cd9bfc | 161 | for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) { |
b03e089d | 162 | if (num_nhs >= zrouter.multipath_num) |
d62a17ae | 163 | break; |
164 | ||
7e3a1ec7 | 165 | if (num_nhs >= array_size(nexthops)) |
d62a17ae | 166 | break; |
167 | ||
a8309422 DL |
168 | if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) { |
169 | switch (nexthop->bh_type) { | |
170 | case BLACKHOLE_REJECT: | |
171 | msg->route_type = FPM__ROUTE_TYPE__UNREACHABLE; | |
172 | break; | |
173 | case BLACKHOLE_NULL: | |
a98701f0 DS |
174 | case BLACKHOLE_UNSPEC: |
175 | case BLACKHOLE_ADMINPROHIB: | |
a8309422 DL |
176 | msg->route_type = FPM__ROUTE_TYPE__BLACKHOLE; |
177 | break; | |
178 | } | |
179 | return msg; | |
180 | } | |
181 | ||
d62a17ae | 182 | if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) |
183 | continue; | |
184 | ||
185 | if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) | |
186 | continue; | |
187 | ||
188 | nexthops[num_nhs] = nexthop; | |
189 | num_nhs++; | |
190 | } | |
191 | ||
192 | if (!num_nhs) { | |
193 | zfpm_debug("netlink_encode_route(): No useful nexthop."); | |
194 | assert(0); | |
195 | return NULL; | |
196 | } | |
197 | ||
198 | /* | |
199 | * And add them to the message. | |
200 | */ | |
201 | if (!(msg->nexthops = qpb_alloc_ptr_array(allocator, num_nhs))) { | |
202 | assert(0); | |
203 | return NULL; | |
204 | } | |
205 | ||
206 | msg->n_nexthops = 0; | |
207 | for (u = 0; u < num_nhs; u++) { | |
208 | if (!add_nexthop(allocator, msg, dest, nexthops[u])) { | |
209 | assert(0); | |
210 | return NULL; | |
211 | } | |
212 | } | |
213 | ||
214 | assert(msg->n_nexthops == num_nhs); | |
215 | ||
216 | return msg; | |
fb0aa886 AS |
217 | } |
218 | ||
219 | /* | |
220 | * create_route_message | |
221 | */ | |
d62a17ae | 222 | static Fpm__Message *create_route_message(qpb_allocator_t *allocator, |
223 | rib_dest_t *dest, | |
224 | struct route_entry *re) | |
fb0aa886 | 225 | { |
d62a17ae | 226 | Fpm__Message *msg; |
227 | ||
228 | msg = QPB_ALLOC(allocator, typeof(*msg)); | |
229 | if (!msg) { | |
230 | assert(0); | |
231 | return NULL; | |
232 | } | |
233 | ||
234 | fpm__message__init(msg); | |
235 | ||
236 | if (!re) { | |
1a6a5e69 | 237 | msg->has_type = 1; |
d62a17ae | 238 | msg->type = FPM__MESSAGE__TYPE__DELETE_ROUTE; |
239 | msg->delete_route = | |
240 | create_delete_route_message(allocator, dest, re); | |
241 | if (!msg->delete_route) { | |
242 | assert(0); | |
243 | return NULL; | |
244 | } | |
245 | return msg; | |
246 | } | |
247 | ||
1a6a5e69 | 248 | msg->has_type = 1; |
d62a17ae | 249 | msg->type = FPM__MESSAGE__TYPE__ADD_ROUTE; |
250 | msg->add_route = create_add_route_message(allocator, dest, re); | |
251 | if (!msg->add_route) { | |
252 | assert(0); | |
253 | return NULL; | |
254 | } | |
255 | ||
256 | return msg; | |
fb0aa886 AS |
257 | } |
258 | ||
259 | /* | |
260 | * zfpm_protobuf_encode_route | |
261 | * | |
262 | * Create a protobuf message corresponding to the given route in the | |
263 | * given buffer space. | |
264 | * | |
265 | * Returns the number of bytes written to the buffer. 0 or a negative | |
266 | * value indicates an error. | |
267 | */ | |
d62a17ae | 268 | int zfpm_protobuf_encode_route(rib_dest_t *dest, struct route_entry *re, |
269 | uint8_t *in_buf, size_t in_buf_len) | |
fb0aa886 | 270 | { |
d62a17ae | 271 | Fpm__Message *msg; |
272 | QPB_DECLARE_STACK_ALLOCATOR(allocator, 4096); | |
273 | size_t len; | |
fb0aa886 | 274 | |
d62a17ae | 275 | QPB_INIT_STACK_ALLOCATOR(allocator); |
fb0aa886 | 276 | |
d62a17ae | 277 | msg = create_route_message(&allocator, dest, re); |
278 | if (!msg) { | |
279 | assert(0); | |
280 | return 0; | |
281 | } | |
fb0aa886 | 282 | |
c4efd0f4 | 283 | len = fpm__message__pack(msg, in_buf); |
d62a17ae | 284 | assert(len <= in_buf_len); |
fb0aa886 | 285 | |
d62a17ae | 286 | QPB_RESET_STACK_ALLOCATOR(allocator); |
287 | return len; | |
fb0aa886 | 288 | } |