]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_fpm_protobuf.c
Merge pull request #13649 from donaldsharp/unlock_the_node_or_else
[mirror_frr.git] / zebra / zebra_fpm_protobuf.c
CommitLineData
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 28static 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 61static 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 126static 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 222static 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 268int 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}