]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_fpm_protobuf.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / zebra / zebra_fpm_protobuf.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * zebra_fpm_protobuf.c
4 *
5 * @copyright Copyright (C) 2016 Sproute Networks, Inc.
6 *
7 * @author Avneesh Sachdev <avneesh@sproute.com>
8 */
9 #include <zebra.h>
10
11 #include "log.h"
12 #include "rib.h"
13 #include "zserv.h"
14 #include "zebra_vrf.h"
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
22 #include "zebra_router.h"
23 #include "zebra_fpm_private.h"
24
25 /*
26 * create_delete_route_message
27 */
28 static Fpm__DeleteRoute *create_delete_route_message(qpb_allocator_t *allocator,
29 rib_dest_t *dest,
30 struct route_entry *re)
31 {
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;
56 }
57
58 /*
59 * add_nexthop
60 */
61 static inline int add_nexthop(qpb_allocator_t *allocator, Fpm__AddRoute *msg,
62 rib_dest_t *dest, struct nexthop *nexthop)
63 {
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;
74 if (nexthop->src.ipv4.s_addr != INADDR_ANY)
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) {
84 if (nexthop->src.ipv4.s_addr != INADDR_ANY)
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.
118 (void)src;
119
120 return 1;
121 }
122
123 /*
124 * create_add_route_message
125 */
126 static Fpm__AddRoute *create_add_route_message(qpb_allocator_t *allocator,
127 rib_dest_t *dest,
128 struct route_entry *re)
129 {
130 Fpm__AddRoute *msg;
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);
153 msg->has_route_type = 1;
154 msg->route_type = FPM__ROUTE_TYPE__NORMAL;
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;
161 for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) {
162 if (num_nhs >= zrouter.multipath_num)
163 break;
164
165 if (num_nhs >= array_size(nexthops))
166 break;
167
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:
174 case BLACKHOLE_UNSPEC:
175 case BLACKHOLE_ADMINPROHIB:
176 msg->route_type = FPM__ROUTE_TYPE__BLACKHOLE;
177 break;
178 }
179 return msg;
180 }
181
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;
217 }
218
219 /*
220 * create_route_message
221 */
222 static Fpm__Message *create_route_message(qpb_allocator_t *allocator,
223 rib_dest_t *dest,
224 struct route_entry *re)
225 {
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) {
237 msg->has_type = 1;
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
248 msg->has_type = 1;
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;
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 */
268 int zfpm_protobuf_encode_route(rib_dest_t *dest, struct route_entry *re,
269 uint8_t *in_buf, size_t in_buf_len)
270 {
271 Fpm__Message *msg;
272 QPB_DECLARE_STACK_ALLOCATOR(allocator, 4096);
273 size_t len;
274
275 QPB_INIT_STACK_ALLOCATOR(allocator);
276
277 msg = create_route_message(&allocator, dest, re);
278 if (!msg) {
279 assert(0);
280 return 0;
281 }
282
283 len = fpm__message__pack(msg, in_buf);
284 assert(len <= in_buf_len);
285
286 QPB_RESET_STACK_ALLOCATOR(allocator);
287 return len;
288 }