]> git.proxmox.com Git - mirror_frr.git/blame - pbrd/pbr_zebra.c
lib: Store nexthop information independently
[mirror_frr.git] / pbrd / pbr_zebra.c
CommitLineData
e5c83d9b
DS
1/*
2 * Zebra connect code.
3 * Copyright (C) 2018 Cumulus Networks, Inc.
4 * Donald Sharp
5 *
6 * FRR is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * FRR is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20#include <zebra.h>
21
22#include "thread.h"
23#include "command.h"
24#include "network.h"
25#include "prefix.h"
26#include "routemap.h"
27#include "table.h"
28#include "stream.h"
29#include "memory.h"
30#include "zclient.h"
31#include "filter.h"
32#include "plist.h"
33#include "log.h"
34#include "nexthop.h"
35#include "nexthop_group.h"
36
37#include "pbr_nht.h"
38#include "pbr_map.h"
39#include "pbr_memory.h"
40#include "pbr_zebra.h"
41#include "pbr_debug.h"
42
43DEFINE_MTYPE_STATIC(PBRD, PBR_INTERFACE, "PBR Interface")
44
45/* Zebra structure to hold current status. */
d3765386 46struct zclient *zclient;
e5c83d9b
DS
47
48static struct interface *zebra_interface_if_lookup(struct stream *s)
49{
50 char ifname_tmp[INTERFACE_NAMSIZ];
51
52 /* Read interface name. */
53 stream_get(ifname_tmp, s, INTERFACE_NAMSIZ);
54
55 /* And look it up. */
56 return if_lookup_by_name(ifname_tmp, VRF_DEFAULT);
57}
58
b13e5ad6 59struct pbr_interface *pbr_if_new(struct interface *ifp)
e5c83d9b
DS
60{
61 struct pbr_interface *pbr_ifp;
62
63 zassert(ifp);
64 zassert(!ifp->info);
65
66 pbr_ifp = XCALLOC(MTYPE_PBR_INTERFACE, sizeof(*pbr_ifp));
67
68 if (!pbr_ifp) {
69 zlog_err("%s: PBR XCALLOC(%zu) failure", __PRETTY_FUNCTION__,
70 sizeof(*pbr_ifp));
71 return 0;
72 }
73
74 return (pbr_ifp);
75}
76
77/* Inteface addition message from zebra. */
78static int interface_add(int command, struct zclient *zclient,
79 zebra_size_t length, vrf_id_t vrf_id)
80{
81 struct interface *ifp;
82
83 ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
84
85 if (!ifp)
86 return 0;
87
88 if (!ifp->info) {
89 struct pbr_interface *pbr_ifp;
90
91 pbr_ifp = pbr_if_new(ifp);
92 ifp->info = pbr_ifp;
93 }
94
95 return 0;
96}
97
98static int interface_delete(int command, struct zclient *zclient,
99 zebra_size_t length, vrf_id_t vrf_id)
100{
101 struct interface *ifp;
102 struct stream *s;
103
104 s = zclient->ibuf;
105 /* zebra_interface_state_read () updates interface structure in iflist
106 */
107 ifp = zebra_interface_state_read(s, vrf_id);
108
109 if (ifp == NULL)
110 return 0;
111
112 if_set_index(ifp, IFINDEX_INTERNAL);
113
114 return 0;
115}
116
117static int interface_address_add(int command, struct zclient *zclient,
118 zebra_size_t length, vrf_id_t vrf_id)
119{
120 zebra_interface_address_read(command, zclient->ibuf, vrf_id);
121
122 return 0;
123}
124
125static int interface_address_delete(int command, struct zclient *zclient,
126 zebra_size_t length, vrf_id_t vrf_id)
127{
128 struct connected *c;
129
130 c = zebra_interface_address_read(command, zclient->ibuf, vrf_id);
131
132 if (!c)
133 return 0;
134
135 connected_free(c);
136 return 0;
137}
138
139static int interface_state_up(int command, struct zclient *zclient,
140 zebra_size_t length, vrf_id_t vrf_id)
141{
142
143 zebra_interface_if_lookup(zclient->ibuf);
144
145 return 0;
146}
147
148static int interface_state_down(int command, struct zclient *zclient,
149 zebra_size_t length, vrf_id_t vrf_id)
150{
151
152 zebra_interface_state_read(zclient->ibuf, vrf_id);
153
154 return 0;
155}
156
157static int route_notify_owner(int command, struct zclient *zclient,
158 zebra_size_t length, vrf_id_t vrf_id)
159{
160 struct prefix p;
161 enum zapi_route_notify_owner note;
162 uint32_t table_id;
163 char buf[PREFIX_STRLEN];
164
165 prefix2str(&p, buf, sizeof(buf));
166
167 if (!zapi_route_notify_decode(zclient->ibuf, &p, &table_id, &note))
168 return -1;
169
170 switch (note) {
171 case ZAPI_ROUTE_FAIL_INSTALL:
172 DEBUGD(&pbr_dbg_zebra,
173 "%s: [%s] Route install failure for table: %u",
174 __PRETTY_FUNCTION__, buf, table_id);
175 break;
176 case ZAPI_ROUTE_BETTER_ADMIN_WON:
177 DEBUGD(&pbr_dbg_zebra,
178 "%s: [%s] Route better admin distance won for table: %u",
179 __PRETTY_FUNCTION__, buf, table_id);
180 break;
181 case ZAPI_ROUTE_INSTALLED:
182 DEBUGD(&pbr_dbg_zebra,
183 "%s: [%s] Route installed succeeded for table: %u",
184 __PRETTY_FUNCTION__, buf, table_id);
185 pbr_nht_route_installed_for_table(table_id);
186 break;
187 case ZAPI_ROUTE_REMOVED:
188 DEBUGD(&pbr_dbg_zebra,
189 "%s: [%s] Route Removed succeeded for table: %u",
190 __PRETTY_FUNCTION__, buf, table_id);
191 pbr_nht_route_removed_for_table(table_id);
192 break;
193 case ZAPI_ROUTE_REMOVE_FAIL:
194 DEBUGD(&pbr_dbg_zebra,
195 "%s: [%s] Route remove fail for table: %u",
196 __PRETTY_FUNCTION__, buf, table_id);
197 break;
198 }
199
200 return 0;
201}
202
203static int rule_notify_owner(int command, struct zclient *zclient,
204 zebra_size_t length, vrf_id_t vrf_id)
205{
206 uint32_t seqno, priority, unique;
207 enum zapi_rule_notify_owner note;
208 struct pbr_map_sequence *pbrms;
37c606ff 209 struct pbr_map_interface *pmi;
e5c83d9b 210 ifindex_t ifi;
37c606ff 211 uint64_t installed;
e5c83d9b
DS
212
213 if (!zapi_rule_notify_decode(zclient->ibuf, &seqno, &priority, &unique,
214 &ifi, &note))
215 return -1;
216
37c606ff
DS
217 pmi = NULL;
218 pbrms = pbrms_lookup_unique(unique, ifi, &pmi);
e5c83d9b
DS
219 if (!pbrms) {
220 DEBUGD(&pbr_dbg_zebra,
221 "%s: Failure to lookup pbrms based upon %u",
222 __PRETTY_FUNCTION__, unique);
223 return 0;
224 }
225
37c606ff
DS
226 installed = 1 << pmi->install_bit;
227
e5c83d9b
DS
228 switch (note) {
229 case ZAPI_RULE_FAIL_INSTALL:
230 DEBUGD(&pbr_dbg_zebra, "%s: Recieved RULE_FAIL_INSTALL",
231 __PRETTY_FUNCTION__);
37c606ff 232 pbrms->installed &= ~installed;
e5c83d9b
DS
233 break;
234 case ZAPI_RULE_INSTALLED:
37c606ff 235 pbrms->installed |= installed;
e5c83d9b
DS
236 DEBUGD(&pbr_dbg_zebra, "%s: Recived RULE_INSTALLED",
237 __PRETTY_FUNCTION__);
238 break;
239 case ZAPI_RULE_REMOVED:
0f03639d 240 pbrms->installed &= ~installed;
e5c83d9b
DS
241 DEBUGD(&pbr_dbg_zebra, "%s: Received RULE REMOVED",
242 __PRETTY_FUNCTION__);
243 break;
244 }
245
246 return 0;
247}
248
249static void zebra_connected(struct zclient *zclient)
250{
251 zclient_send_reg_requests(zclient, VRF_DEFAULT);
252}
253
254static void route_add_helper(struct zapi_route *api, struct nexthop_group nhg,
255 uint8_t install_afi)
256{
257 struct zapi_nexthop *api_nh;
258 struct nexthop *nhop;
259 int i;
260
261 api->prefix.family = install_afi;
262
263 i = 0;
264 for (ALL_NEXTHOPS(nhg, nhop)) {
265 api_nh = &api->nexthops[i];
266 api_nh->vrf_id = nhop->vrf_id;
267 api_nh->type = nhop->type;
268 switch (nhop->type) {
269 case NEXTHOP_TYPE_IPV4:
270 api_nh->gate.ipv4 = nhop->gate.ipv4;
271 break;
272 case NEXTHOP_TYPE_IPV4_IFINDEX:
273 api_nh->gate.ipv4 = nhop->gate.ipv4;
274 api_nh->ifindex = nhop->ifindex;
275 break;
276 case NEXTHOP_TYPE_IFINDEX:
277 api_nh->ifindex = nhop->ifindex;
278 break;
279 case NEXTHOP_TYPE_IPV6:
280 memcpy(&api_nh->gate.ipv6, &nhop->gate.ipv6, 16);
281 break;
282 case NEXTHOP_TYPE_IPV6_IFINDEX:
283 api_nh->ifindex = nhop->ifindex;
284 memcpy(&api_nh->gate.ipv6, &nhop->gate.ipv6, 16);
285 break;
286 case NEXTHOP_TYPE_BLACKHOLE:
287 api_nh->bh_type = nhop->bh_type;
288 break;
289 }
290 i++;
291 }
292 api->nexthop_num = i;
293
294 zclient_route_send(ZEBRA_ROUTE_ADD, zclient, api);
295}
296
297/*
298 * This function assumes a default route is being
299 * installed into the appropriate tableid
300 */
301void route_add(struct pbr_nexthop_group_cache *pnhgc, struct nexthop_group nhg,
302 afi_t install_afi)
303{
304 struct zapi_route api;
305
306 memset(&api, 0, sizeof(api));
307
308 api.vrf_id = VRF_DEFAULT;
309 api.type = ZEBRA_ROUTE_PBR;
310 api.safi = SAFI_UNICAST;
311 /*
312 * Sending a default route
313 */
314 api.tableid = pnhgc->table_id;
315 SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
316 SET_FLAG(api.message, ZAPI_MESSAGE_TABLEID);
317 SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
318 switch (install_afi) {
319 case AFI_MAX:
320 route_add_helper(&api, nhg, AF_INET);
321 route_add_helper(&api, nhg, AF_INET6);
322 break;
323 case AFI_IP:
324 route_add_helper(&api, nhg, AF_INET);
325 break;
326 case AFI_IP6:
327 route_add_helper(&api, nhg, AF_INET6);
328 break;
329 case AFI_L2VPN:
330 DEBUGD(&pbr_dbg_zebra,
331 "%s: Asked to install unsupported route type: L2VPN",
332 __PRETTY_FUNCTION__);
333 break;
334 }
335}
336
337/*
338 * This function assumes a default route is being
339 * removed from the appropriate tableid
340 */
341void route_delete(struct pbr_nexthop_group_cache *pnhgc, afi_t afi)
342{
343 struct zapi_route api;
344
345 memset(&api, 0, sizeof(api));
346 api.vrf_id = VRF_DEFAULT;
347 api.type = ZEBRA_ROUTE_PBR;
348 api.safi = SAFI_UNICAST;
349
350 api.tableid = pnhgc->table_id;
351 SET_FLAG(api.message, ZAPI_MESSAGE_TABLEID);
352
353 switch (afi) {
354 case AFI_IP:
355 api.prefix.family = AF_INET;
356 zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
357 break;
358 case AFI_IP6:
359 api.prefix.family = AF_INET6;
360 zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
361 break;
362 case AFI_MAX:
363 api.prefix.family = AF_INET;
364 zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
365 api.prefix.family = AF_INET6;
366 zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
367 break;
368 case AFI_L2VPN:
369 DEBUGD(&pbr_dbg_zebra,
370 "%s: Asked to delete unsupported route type: L2VPN",
371 __PRETTY_FUNCTION__);
372 break;
373 }
e5c83d9b
DS
374}
375
376static int pbr_zebra_nexthop_update(int command, struct zclient *zclient,
377 zebra_size_t length, vrf_id_t vrf_id)
378{
379 struct zapi_route nhr;
380 char buf[PREFIX2STR_BUFFER];
381 uint32_t i;
382
383 zapi_nexthop_update_decode(zclient->ibuf, &nhr);
384
385 if (DEBUG_MODE_CHECK(&pbr_dbg_zebra, DEBUG_MODE_ALL)) {
386
387 DEBUGD(&pbr_dbg_zebra, "%s: Received Nexthop update: %s",
388 __PRETTY_FUNCTION__,
389 prefix2str(&nhr.prefix, buf, sizeof(buf)));
390
391 DEBUGD(&pbr_dbg_zebra, "%s: (\tNexthops(%u)",
392 __PRETTY_FUNCTION__, nhr.nexthop_num);
393
394 for (i = 0; i < nhr.nexthop_num; i++) {
395 DEBUGD(&pbr_dbg_zebra,
396 "%s: \tType: %d: vrf: %d, ifindex: %d gate: %s",
397 __PRETTY_FUNCTION__, nhr.nexthops[i].type,
398 nhr.nexthops[i].vrf_id, nhr.nexthops[i].ifindex,
399 inet_ntoa(nhr.nexthops[i].gate.ipv4));
400 }
401 }
402
403 pbr_nht_nexthop_update(&nhr);
404 return 1;
405}
406
407extern struct zebra_privs_t pbr_privs;
408
409void pbr_zebra_init(void)
410{
411 struct zclient_options opt = { .receive_notify = true };
412
413 zclient = zclient_new_notify(master, &opt);
414
415 zclient_init(zclient, ZEBRA_ROUTE_PBR, 0, &pbr_privs);
416 zclient->zebra_connected = zebra_connected;
417 zclient->interface_add = interface_add;
418 zclient->interface_delete = interface_delete;
419 zclient->interface_up = interface_state_up;
420 zclient->interface_down = interface_state_down;
421 zclient->interface_address_add = interface_address_add;
422 zclient->interface_address_delete = interface_address_delete;
423 zclient->route_notify_owner = route_notify_owner;
424 zclient->rule_notify_owner = rule_notify_owner;
425 zclient->nexthop_update = pbr_zebra_nexthop_update;
426}
427
428void pbr_send_rnh(struct nexthop *nhop, bool reg)
429{
430 uint32_t command;
431 struct prefix p;
432
433 command = (reg) ?
434 ZEBRA_NEXTHOP_REGISTER : ZEBRA_NEXTHOP_UNREGISTER;
435
436 memset(&p, 0, sizeof(p));
d3765386 437 switch (nhop->type) {
e5c83d9b
DS
438 case NEXTHOP_TYPE_IFINDEX:
439 case NEXTHOP_TYPE_BLACKHOLE:
440 return;
441 case NEXTHOP_TYPE_IPV4:
442 case NEXTHOP_TYPE_IPV4_IFINDEX:
443 p.family = AF_INET;
444 p.u.prefix4.s_addr = nhop->gate.ipv4.s_addr;
445 p.prefixlen = 32;
446 break;
447 case NEXTHOP_TYPE_IPV6:
448 case NEXTHOP_TYPE_IPV6_IFINDEX:
449 p.family = AF_INET6;
450 memcpy(&p.u.prefix6, &nhop->gate.ipv6, 16);
451 p.prefixlen = 128;
452 break;
453 }
454
455 if (zclient_send_rnh(zclient, command, &p,
456 false, nhop->vrf_id) < 0) {
457 zlog_warn("%s: Failure to send nexthop to zebra",
458 __PRETTY_FUNCTION__);
459 }
460}
461
462static void pbr_encode_pbr_map_sequence_prefix(struct stream *s,
463 struct prefix *p,
49027ce8 464 unsigned char family)
e5c83d9b
DS
465{
466 struct prefix any;
467
468 if (!p) {
469 memset(&any, 0, sizeof(any));
470 any.family = family;
471 p = &any;
472 }
473
474 stream_putc(s, p->family);
475 stream_putc(s, p->prefixlen);
476 stream_put(s, &p->u.prefix, prefix_blen(p));
477}
478
479static void pbr_encode_pbr_map_sequence(struct stream *s,
480 struct pbr_map_sequence *pbrms,
481 struct interface *ifp)
482{
49027ce8 483 unsigned char family;
e5c83d9b
DS
484
485 family = AF_INET;
49027ce8
DS
486 if (pbrms->family)
487 family = pbrms->family;
e5c83d9b
DS
488
489 stream_putl(s, pbrms->seqno);
490 stream_putl(s, pbrms->ruleno);
491 stream_putl(s, pbrms->unique);
492 pbr_encode_pbr_map_sequence_prefix(s, pbrms->src, family);
493 stream_putw(s, 0); /* src port */
494 pbr_encode_pbr_map_sequence_prefix(s, pbrms->dst, family);
495 stream_putw(s, 0); /* dst port */
496 if (pbrms->nhgrp_name)
497 stream_putl(s, pbr_nht_get_table(pbrms->nhgrp_name));
498 else if (pbrms->nhg)
499 stream_putl(s, pbr_nht_get_table(pbrms->internal_nhg_name));
500 stream_putl(s, ifp->ifindex);
501}
502
b13e5ad6
DS
503void pbr_send_pbr_map(struct pbr_map_sequence *pbrms,
504 struct pbr_map_interface *pmi, bool install)
e5c83d9b 505{
b13e5ad6 506 struct pbr_map *pbrm = pbrms->parent;
e5c83d9b 507 struct stream *s;
37c606ff
DS
508 uint64_t is_installed = 1 << pmi->install_bit;
509
510 is_installed &= pbrms->installed;
e5c83d9b 511
37c606ff
DS
512 DEBUGD(&pbr_dbg_zebra, "%s: for %s %d(%" PRIu64 ")",
513 __PRETTY_FUNCTION__, pbrm->name, install, is_installed);
9b71ea4b
DS
514
515 /*
516 * If we are installed and asked to do so again
517 * just return. If we are not installed and asked
518 * and asked to delete just return;
519 */
37c606ff 520 if (install && is_installed)
9b71ea4b
DS
521 return;
522
37c606ff 523 if (!install && !is_installed)
9b71ea4b 524 return;
e5c83d9b
DS
525
526 s = zclient->obuf;
527 stream_reset(s);
528
529 zclient_create_header(s,
530 install ? ZEBRA_RULE_ADD : ZEBRA_RULE_DELETE,
531 VRF_DEFAULT);
532
b13e5ad6
DS
533 /*
534 * We are sending one item at a time at the moment
535 */
536 stream_putl(s, 1);
e5c83d9b 537
b13e5ad6
DS
538 DEBUGD(&pbr_dbg_zebra, "%s: \t%s %s %d %s %u",
539 __PRETTY_FUNCTION__, install ? "Installing" : "Deleting",
540 pbrm->name, install, pmi->ifp->name, pmi->delete);
e5c83d9b 541
b13e5ad6 542 pbr_encode_pbr_map_sequence(s, pbrms, pmi->ifp);
e5c83d9b 543
e5c83d9b
DS
544 stream_putw_at(s, 0, stream_get_endp(s));
545
e5c83d9b
DS
546 zclient_send_message(zclient);
547}