]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_fpm_protobuf.c
zebra, lib: fix the ZEBRA_INTERFACE_VRF_UPDATE zapi message
[mirror_frr.git] / zebra / zebra_fpm_protobuf.c
CommitLineData
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
37#include "zebra_fpm_private.h"
38
39/*
40 * create_delete_route_message
41 */
d62a17ae 42static Fpm__DeleteRoute *create_delete_route_message(qpb_allocator_t *allocator,
43 rib_dest_t *dest,
44 struct route_entry *re)
fb0aa886 45{
d62a17ae 46 Fpm__DeleteRoute *msg;
47
48 msg = QPB_ALLOC(allocator, typeof(*msg));
49 if (!msg) {
50 assert(0);
51 return NULL;
52 }
53
54 fpm__delete_route__init(msg);
55 msg->vrf_id = zvrf_id(rib_dest_vrf(dest));
56
57 qpb_address_family_set(&msg->address_family, rib_dest_af(dest));
58
59 /*
60 * XXX Hardcode subaddress family for now.
61 */
62 msg->sub_address_family = QPB__SUB_ADDRESS_FAMILY__UNICAST;
63 msg->key = fpm_route_key_create(allocator, rib_dest_prefix(dest));
64 if (!msg->key) {
65 assert(0);
66 return NULL;
67 }
68
69 return msg;
fb0aa886
AS
70}
71
72/*
73 * add_nexthop
74 */
d62a17ae 75static inline int add_nexthop(qpb_allocator_t *allocator, Fpm__AddRoute *msg,
76 rib_dest_t *dest, struct nexthop *nexthop)
fb0aa886 77{
d62a17ae 78 uint32_t if_index;
79 union g_addr *gateway, *src;
80
81 gateway = src = NULL;
82
83 if_index = nexthop->ifindex;
84
85 if (nexthop->type == NEXTHOP_TYPE_IPV4
86 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) {
87 gateway = &nexthop->gate;
88 if (nexthop->src.ipv4.s_addr)
89 src = &nexthop->src;
90 }
91
92 if (nexthop->type == NEXTHOP_TYPE_IPV6
93 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) {
94 gateway = &nexthop->gate;
95 }
96
97 if (nexthop->type == NEXTHOP_TYPE_IFINDEX) {
98 if (nexthop->src.ipv4.s_addr)
99 src = &nexthop->src;
100 }
101
102 if (!gateway && if_index == 0)
103 return 0;
104
105 /*
106 * We have a valid nexthop.
107 */
108 {
109 Fpm__Nexthop *pb_nh;
110 pb_nh = QPB_ALLOC(allocator, typeof(*pb_nh));
111 if (!pb_nh) {
112 assert(0);
113 return 0;
114 }
115
116 fpm__nexthop__init(pb_nh);
117
118 if (if_index != 0) {
119 pb_nh->if_id =
120 qpb_if_identifier_create(allocator, if_index);
121 }
122
123 if (gateway) {
124 pb_nh->address = qpb_l3_address_create(
125 allocator, gateway, rib_dest_af(dest));
126 }
127
128 msg->nexthops[msg->n_nexthops++] = pb_nh;
129 }
130
131 // TODO: Use src.
4f4060f6 132 (void)src;
d62a17ae 133
134 return 1;
fb0aa886
AS
135}
136
137/*
138 * create_add_route_message
139 */
d62a17ae 140static Fpm__AddRoute *create_add_route_message(qpb_allocator_t *allocator,
141 rib_dest_t *dest,
142 struct route_entry *re)
fb0aa886 143{
d62a17ae 144 Fpm__AddRoute *msg;
d62a17ae 145 struct nexthop *nexthop;
146 uint num_nhs, u;
147 struct nexthop *nexthops[MULTIPATH_NUM];
148
149 msg = QPB_ALLOC(allocator, typeof(*msg));
150 if (!msg) {
151 assert(0);
152 return NULL;
153 }
154
155 fpm__add_route__init(msg);
156
157 msg->vrf_id = zvrf_id(rib_dest_vrf(dest));
158
159 qpb_address_family_set(&msg->address_family, rib_dest_af(dest));
160
161 /*
162 * XXX Hardcode subaddress family for now.
163 */
164 msg->sub_address_family = QPB__SUB_ADDRESS_FAMILY__UNICAST;
165 msg->key = fpm_route_key_create(allocator, rib_dest_prefix(dest));
166 qpb_protocol_set(&msg->protocol, re->type);
1a6a5e69 167 msg->has_route_type = 1;
a8309422 168 msg->route_type = FPM__ROUTE_TYPE__NORMAL;
d62a17ae 169 msg->metric = re->metric;
170
171 /*
172 * Figure out the set of nexthops to be added to the message.
173 */
174 num_nhs = 0;
7ee30f28 175 for (ALL_NEXTHOPS(re->ng, nexthop)) {
d62a17ae 176 if (num_nhs >= multipath_num)
177 break;
178
179 if (num_nhs >= ZEBRA_NUM_OF(nexthops))
180 break;
181
a8309422
DL
182 if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) {
183 switch (nexthop->bh_type) {
184 case BLACKHOLE_REJECT:
185 msg->route_type = FPM__ROUTE_TYPE__UNREACHABLE;
186 break;
187 case BLACKHOLE_NULL:
188 default:
189 msg->route_type = FPM__ROUTE_TYPE__BLACKHOLE;
190 break;
191 }
192 return msg;
193 }
194
d62a17ae 195 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
196 continue;
197
198 if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
199 continue;
200
201 nexthops[num_nhs] = nexthop;
202 num_nhs++;
203 }
204
205 if (!num_nhs) {
206 zfpm_debug("netlink_encode_route(): No useful nexthop.");
207 assert(0);
208 return NULL;
209 }
210
211 /*
212 * And add them to the message.
213 */
214 if (!(msg->nexthops = qpb_alloc_ptr_array(allocator, num_nhs))) {
215 assert(0);
216 return NULL;
217 }
218
219 msg->n_nexthops = 0;
220 for (u = 0; u < num_nhs; u++) {
221 if (!add_nexthop(allocator, msg, dest, nexthops[u])) {
222 assert(0);
223 return NULL;
224 }
225 }
226
227 assert(msg->n_nexthops == num_nhs);
228
229 return msg;
fb0aa886
AS
230}
231
232/*
233 * create_route_message
234 */
d62a17ae 235static Fpm__Message *create_route_message(qpb_allocator_t *allocator,
236 rib_dest_t *dest,
237 struct route_entry *re)
fb0aa886 238{
d62a17ae 239 Fpm__Message *msg;
240
241 msg = QPB_ALLOC(allocator, typeof(*msg));
242 if (!msg) {
243 assert(0);
244 return NULL;
245 }
246
247 fpm__message__init(msg);
248
249 if (!re) {
1a6a5e69 250 msg->has_type = 1;
d62a17ae 251 msg->type = FPM__MESSAGE__TYPE__DELETE_ROUTE;
252 msg->delete_route =
253 create_delete_route_message(allocator, dest, re);
254 if (!msg->delete_route) {
255 assert(0);
256 return NULL;
257 }
258 return msg;
259 }
260
1a6a5e69 261 msg->has_type = 1;
d62a17ae 262 msg->type = FPM__MESSAGE__TYPE__ADD_ROUTE;
263 msg->add_route = create_add_route_message(allocator, dest, re);
264 if (!msg->add_route) {
265 assert(0);
266 return NULL;
267 }
268
269 return msg;
fb0aa886
AS
270}
271
272/*
273 * zfpm_protobuf_encode_route
274 *
275 * Create a protobuf message corresponding to the given route in the
276 * given buffer space.
277 *
278 * Returns the number of bytes written to the buffer. 0 or a negative
279 * value indicates an error.
280 */
d62a17ae 281int zfpm_protobuf_encode_route(rib_dest_t *dest, struct route_entry *re,
282 uint8_t *in_buf, size_t in_buf_len)
fb0aa886 283{
d62a17ae 284 Fpm__Message *msg;
285 QPB_DECLARE_STACK_ALLOCATOR(allocator, 4096);
286 size_t len;
fb0aa886 287
d62a17ae 288 QPB_INIT_STACK_ALLOCATOR(allocator);
fb0aa886 289
d62a17ae 290 msg = create_route_message(&allocator, dest, re);
291 if (!msg) {
292 assert(0);
293 return 0;
294 }
fb0aa886 295
d62a17ae 296 len = fpm__message__pack(msg, (uint8_t *)in_buf);
297 assert(len <= in_buf_len);
fb0aa886 298
d62a17ae 299 QPB_RESET_STACK_ALLOCATOR(allocator);
300 return len;
fb0aa886 301}