]> git.proxmox.com Git - mirror_frr.git/blame - pbrd/pbr_zebra.c
doc: Add documentation for PBRD
[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. */
46struct zclient *zclient = NULL;
47
48/* For registering threads. */
49extern struct thread_master *master;
50
51static struct interface *zebra_interface_if_lookup(struct stream *s)
52{
53 char ifname_tmp[INTERFACE_NAMSIZ];
54
55 /* Read interface name. */
56 stream_get(ifname_tmp, s, INTERFACE_NAMSIZ);
57
58 /* And look it up. */
59 return if_lookup_by_name(ifname_tmp, VRF_DEFAULT);
60}
61
62static struct pbr_interface *pbr_if_new(struct interface *ifp)
63{
64 struct pbr_interface *pbr_ifp;
65
66 zassert(ifp);
67 zassert(!ifp->info);
68
69 pbr_ifp = XCALLOC(MTYPE_PBR_INTERFACE, sizeof(*pbr_ifp));
70
71 if (!pbr_ifp) {
72 zlog_err("%s: PBR XCALLOC(%zu) failure", __PRETTY_FUNCTION__,
73 sizeof(*pbr_ifp));
74 return 0;
75 }
76
77 return (pbr_ifp);
78}
79
80/* Inteface addition message from zebra. */
81static int interface_add(int command, struct zclient *zclient,
82 zebra_size_t length, vrf_id_t vrf_id)
83{
84 struct interface *ifp;
85
86 ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
87
88 if (!ifp)
89 return 0;
90
91 if (!ifp->info) {
92 struct pbr_interface *pbr_ifp;
93
94 pbr_ifp = pbr_if_new(ifp);
95 ifp->info = pbr_ifp;
96 }
97
98 return 0;
99}
100
101static int interface_delete(int command, struct zclient *zclient,
102 zebra_size_t length, vrf_id_t vrf_id)
103{
104 struct interface *ifp;
105 struct stream *s;
106
107 s = zclient->ibuf;
108 /* zebra_interface_state_read () updates interface structure in iflist
109 */
110 ifp = zebra_interface_state_read(s, vrf_id);
111
112 if (ifp == NULL)
113 return 0;
114
115 if_set_index(ifp, IFINDEX_INTERNAL);
116
117 return 0;
118}
119
120static int interface_address_add(int command, struct zclient *zclient,
121 zebra_size_t length, vrf_id_t vrf_id)
122{
123 zebra_interface_address_read(command, zclient->ibuf, vrf_id);
124
125 return 0;
126}
127
128static int interface_address_delete(int command, struct zclient *zclient,
129 zebra_size_t length, vrf_id_t vrf_id)
130{
131 struct connected *c;
132
133 c = zebra_interface_address_read(command, zclient->ibuf, vrf_id);
134
135 if (!c)
136 return 0;
137
138 connected_free(c);
139 return 0;
140}
141
142static int interface_state_up(int command, struct zclient *zclient,
143 zebra_size_t length, vrf_id_t vrf_id)
144{
145
146 zebra_interface_if_lookup(zclient->ibuf);
147
148 return 0;
149}
150
151static int interface_state_down(int command, struct zclient *zclient,
152 zebra_size_t length, vrf_id_t vrf_id)
153{
154
155 zebra_interface_state_read(zclient->ibuf, vrf_id);
156
157 return 0;
158}
159
160static int route_notify_owner(int command, struct zclient *zclient,
161 zebra_size_t length, vrf_id_t vrf_id)
162{
163 struct prefix p;
164 enum zapi_route_notify_owner note;
165 uint32_t table_id;
166 char buf[PREFIX_STRLEN];
167
168 prefix2str(&p, buf, sizeof(buf));
169
170 if (!zapi_route_notify_decode(zclient->ibuf, &p, &table_id, &note))
171 return -1;
172
173 switch (note) {
174 case ZAPI_ROUTE_FAIL_INSTALL:
175 DEBUGD(&pbr_dbg_zebra,
176 "%s: [%s] Route install failure for table: %u",
177 __PRETTY_FUNCTION__, buf, table_id);
178 break;
179 case ZAPI_ROUTE_BETTER_ADMIN_WON:
180 DEBUGD(&pbr_dbg_zebra,
181 "%s: [%s] Route better admin distance won for table: %u",
182 __PRETTY_FUNCTION__, buf, table_id);
183 break;
184 case ZAPI_ROUTE_INSTALLED:
185 DEBUGD(&pbr_dbg_zebra,
186 "%s: [%s] Route installed succeeded for table: %u",
187 __PRETTY_FUNCTION__, buf, table_id);
188 pbr_nht_route_installed_for_table(table_id);
189 break;
190 case ZAPI_ROUTE_REMOVED:
191 DEBUGD(&pbr_dbg_zebra,
192 "%s: [%s] Route Removed succeeded for table: %u",
193 __PRETTY_FUNCTION__, buf, table_id);
194 pbr_nht_route_removed_for_table(table_id);
195 break;
196 case ZAPI_ROUTE_REMOVE_FAIL:
197 DEBUGD(&pbr_dbg_zebra,
198 "%s: [%s] Route remove fail for table: %u",
199 __PRETTY_FUNCTION__, buf, table_id);
200 break;
201 }
202
203 return 0;
204}
205
206static int rule_notify_owner(int command, struct zclient *zclient,
207 zebra_size_t length, vrf_id_t vrf_id)
208{
209 uint32_t seqno, priority, unique;
210 enum zapi_rule_notify_owner note;
211 struct pbr_map_sequence *pbrms;
212 ifindex_t ifi;
213
214 if (!zapi_rule_notify_decode(zclient->ibuf, &seqno, &priority, &unique,
215 &ifi, &note))
216 return -1;
217
218 pbrms = pbrms_lookup_unique(unique, ifi);
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
226 switch (note) {
227 case ZAPI_RULE_FAIL_INSTALL:
228 DEBUGD(&pbr_dbg_zebra, "%s: Recieved RULE_FAIL_INSTALL",
229 __PRETTY_FUNCTION__);
230 pbrms->installed = false;
231 break;
232 case ZAPI_RULE_INSTALLED:
233 pbrms->installed = true;
234 DEBUGD(&pbr_dbg_zebra, "%s: Recived RULE_INSTALLED",
235 __PRETTY_FUNCTION__);
236 break;
237 case ZAPI_RULE_REMOVED:
238 DEBUGD(&pbr_dbg_zebra, "%s: Received RULE REMOVED",
239 __PRETTY_FUNCTION__);
240 break;
241 }
242
243 return 0;
244}
245
246static void zebra_connected(struct zclient *zclient)
247{
248 zclient_send_reg_requests(zclient, VRF_DEFAULT);
249}
250
251static void route_add_helper(struct zapi_route *api, struct nexthop_group nhg,
252 uint8_t install_afi)
253{
254 struct zapi_nexthop *api_nh;
255 struct nexthop *nhop;
256 int i;
257
258 api->prefix.family = install_afi;
259
260 i = 0;
261 for (ALL_NEXTHOPS(nhg, nhop)) {
262 api_nh = &api->nexthops[i];
263 api_nh->vrf_id = nhop->vrf_id;
264 api_nh->type = nhop->type;
265 switch (nhop->type) {
266 case NEXTHOP_TYPE_IPV4:
267 api_nh->gate.ipv4 = nhop->gate.ipv4;
268 break;
269 case NEXTHOP_TYPE_IPV4_IFINDEX:
270 api_nh->gate.ipv4 = nhop->gate.ipv4;
271 api_nh->ifindex = nhop->ifindex;
272 break;
273 case NEXTHOP_TYPE_IFINDEX:
274 api_nh->ifindex = nhop->ifindex;
275 break;
276 case NEXTHOP_TYPE_IPV6:
277 memcpy(&api_nh->gate.ipv6, &nhop->gate.ipv6, 16);
278 break;
279 case NEXTHOP_TYPE_IPV6_IFINDEX:
280 api_nh->ifindex = nhop->ifindex;
281 memcpy(&api_nh->gate.ipv6, &nhop->gate.ipv6, 16);
282 break;
283 case NEXTHOP_TYPE_BLACKHOLE:
284 api_nh->bh_type = nhop->bh_type;
285 break;
286 }
287 i++;
288 }
289 api->nexthop_num = i;
290
291 zclient_route_send(ZEBRA_ROUTE_ADD, zclient, api);
292}
293
294/*
295 * This function assumes a default route is being
296 * installed into the appropriate tableid
297 */
298void route_add(struct pbr_nexthop_group_cache *pnhgc, struct nexthop_group nhg,
299 afi_t install_afi)
300{
301 struct zapi_route api;
302
303 memset(&api, 0, sizeof(api));
304
305 api.vrf_id = VRF_DEFAULT;
306 api.type = ZEBRA_ROUTE_PBR;
307 api.safi = SAFI_UNICAST;
308 /*
309 * Sending a default route
310 */
311 api.tableid = pnhgc->table_id;
312 SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
313 SET_FLAG(api.message, ZAPI_MESSAGE_TABLEID);
314 SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
315 switch (install_afi) {
316 case AFI_MAX:
317 route_add_helper(&api, nhg, AF_INET);
318 route_add_helper(&api, nhg, AF_INET6);
319 break;
320 case AFI_IP:
321 route_add_helper(&api, nhg, AF_INET);
322 break;
323 case AFI_IP6:
324 route_add_helper(&api, nhg, AF_INET6);
325 break;
326 case AFI_L2VPN:
327 DEBUGD(&pbr_dbg_zebra,
328 "%s: Asked to install unsupported route type: L2VPN",
329 __PRETTY_FUNCTION__);
330 break;
331 }
332}
333
334/*
335 * This function assumes a default route is being
336 * removed from the appropriate tableid
337 */
338void route_delete(struct pbr_nexthop_group_cache *pnhgc, afi_t afi)
339{
340 struct zapi_route api;
341
342 memset(&api, 0, sizeof(api));
343 api.vrf_id = VRF_DEFAULT;
344 api.type = ZEBRA_ROUTE_PBR;
345 api.safi = SAFI_UNICAST;
346
347 api.tableid = pnhgc->table_id;
348 SET_FLAG(api.message, ZAPI_MESSAGE_TABLEID);
349
350 switch (afi) {
351 case AFI_IP:
352 api.prefix.family = AF_INET;
353 zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
354 break;
355 case AFI_IP6:
356 api.prefix.family = AF_INET6;
357 zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
358 break;
359 case AFI_MAX:
360 api.prefix.family = AF_INET;
361 zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
362 api.prefix.family = AF_INET6;
363 zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
364 break;
365 case AFI_L2VPN:
366 DEBUGD(&pbr_dbg_zebra,
367 "%s: Asked to delete unsupported route type: L2VPN",
368 __PRETTY_FUNCTION__);
369 break;
370 }
371
372 return;
373}
374
375static int pbr_zebra_nexthop_update(int command, struct zclient *zclient,
376 zebra_size_t length, vrf_id_t vrf_id)
377{
378 struct zapi_route nhr;
379 char buf[PREFIX2STR_BUFFER];
380 uint32_t i;
381
382 zapi_nexthop_update_decode(zclient->ibuf, &nhr);
383
384 if (DEBUG_MODE_CHECK(&pbr_dbg_zebra, DEBUG_MODE_ALL)) {
385
386 DEBUGD(&pbr_dbg_zebra, "%s: Received Nexthop update: %s",
387 __PRETTY_FUNCTION__,
388 prefix2str(&nhr.prefix, buf, sizeof(buf)));
389
390 DEBUGD(&pbr_dbg_zebra, "%s: (\tNexthops(%u)",
391 __PRETTY_FUNCTION__, nhr.nexthop_num);
392
393 for (i = 0; i < nhr.nexthop_num; i++) {
394 DEBUGD(&pbr_dbg_zebra,
395 "%s: \tType: %d: vrf: %d, ifindex: %d gate: %s",
396 __PRETTY_FUNCTION__, nhr.nexthops[i].type,
397 nhr.nexthops[i].vrf_id, nhr.nexthops[i].ifindex,
398 inet_ntoa(nhr.nexthops[i].gate.ipv4));
399 }
400 }
401
402 pbr_nht_nexthop_update(&nhr);
403 return 1;
404}
405
406extern struct zebra_privs_t pbr_privs;
407
408void pbr_zebra_init(void)
409{
410 struct zclient_options opt = { .receive_notify = true };
411
412 zclient = zclient_new_notify(master, &opt);
413
414 zclient_init(zclient, ZEBRA_ROUTE_PBR, 0, &pbr_privs);
415 zclient->zebra_connected = zebra_connected;
416 zclient->interface_add = interface_add;
417 zclient->interface_delete = interface_delete;
418 zclient->interface_up = interface_state_up;
419 zclient->interface_down = interface_state_down;
420 zclient->interface_address_add = interface_address_add;
421 zclient->interface_address_delete = interface_address_delete;
422 zclient->route_notify_owner = route_notify_owner;
423 zclient->rule_notify_owner = rule_notify_owner;
424 zclient->nexthop_update = pbr_zebra_nexthop_update;
425}
426
427void pbr_send_rnh(struct nexthop *nhop, bool reg)
428{
429 uint32_t command;
430 struct prefix p;
431
432 command = (reg) ?
433 ZEBRA_NEXTHOP_REGISTER : ZEBRA_NEXTHOP_UNREGISTER;
434
435 memset(&p, 0, sizeof(p));
436 switch(nhop->type) {
437 case NEXTHOP_TYPE_IFINDEX:
438 case NEXTHOP_TYPE_BLACKHOLE:
439 return;
440 case NEXTHOP_TYPE_IPV4:
441 case NEXTHOP_TYPE_IPV4_IFINDEX:
442 p.family = AF_INET;
443 p.u.prefix4.s_addr = nhop->gate.ipv4.s_addr;
444 p.prefixlen = 32;
445 break;
446 case NEXTHOP_TYPE_IPV6:
447 case NEXTHOP_TYPE_IPV6_IFINDEX:
448 p.family = AF_INET6;
449 memcpy(&p.u.prefix6, &nhop->gate.ipv6, 16);
450 p.prefixlen = 128;
451 break;
452 }
453
454 if (zclient_send_rnh(zclient, command, &p,
455 false, nhop->vrf_id) < 0) {
456 zlog_warn("%s: Failure to send nexthop to zebra",
457 __PRETTY_FUNCTION__);
458 }
459}
460
461static void pbr_encode_pbr_map_sequence_prefix(struct stream *s,
462 struct prefix *p,
463 u_char family)
464{
465 struct prefix any;
466
467 if (!p) {
468 memset(&any, 0, sizeof(any));
469 any.family = family;
470 p = &any;
471 }
472
473 stream_putc(s, p->family);
474 stream_putc(s, p->prefixlen);
475 stream_put(s, &p->u.prefix, prefix_blen(p));
476}
477
478static void pbr_encode_pbr_map_sequence(struct stream *s,
479 struct pbr_map_sequence *pbrms,
480 struct interface *ifp)
481{
482 u_char family;
483
484 family = AF_INET;
485 if (pbrms->src)
486 family = pbrms->src->family;
487
488 if (pbrms->dst)
489 family = pbrms->dst->family;
490
491 stream_putl(s, pbrms->seqno);
492 stream_putl(s, pbrms->ruleno);
493 stream_putl(s, pbrms->unique);
494 pbr_encode_pbr_map_sequence_prefix(s, pbrms->src, family);
495 stream_putw(s, 0); /* src port */
496 pbr_encode_pbr_map_sequence_prefix(s, pbrms->dst, family);
497 stream_putw(s, 0); /* dst port */
498 if (pbrms->nhgrp_name)
499 stream_putl(s, pbr_nht_get_table(pbrms->nhgrp_name));
500 else if (pbrms->nhg)
501 stream_putl(s, pbr_nht_get_table(pbrms->internal_nhg_name));
502 stream_putl(s, ifp->ifindex);
503}
504
505void pbr_send_pbr_map(struct pbr_map *pbrm, bool install)
506{
507 struct listnode *inode, *snode;
508 struct pbr_map_sequence *pbrms;
509 struct pbr_map_interface *pmi;
510 struct stream *s;
511 uint32_t total;
512 ssize_t tspot;
513
514 DEBUGD(&pbr_dbg_zebra, "%s: for %s %d", __PRETTY_FUNCTION__, pbrm->name,
515 install);
516
517 s = zclient->obuf;
518 stream_reset(s);
519
520 zclient_create_header(s,
521 install ? ZEBRA_RULE_ADD : ZEBRA_RULE_DELETE,
522 VRF_DEFAULT);
523
524 total = 0;
525 tspot = stream_get_endp(s);
526 stream_putl(s, 0);
527 for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi)) {
528
529 DEBUGD(&pbr_dbg_zebra, "%s: \t%s %s %d %s %u",
530 __PRETTY_FUNCTION__, install ? "Installing" : "Deleting",
531 pbrm->name, install, pmi->ifp->name, pmi->delete);
532
533 if (!install && pmi->delete) {
534 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, snode,
535 pbrms)) {
536 pbr_encode_pbr_map_sequence(s,
537 pbrms, pmi->ifp);
538 total++;
539 }
540 continue;
541 }
542
543 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, snode, pbrms)) {
544
545 DEBUGD(&pbr_dbg_zebra, "%s: \tSeqno: %u %ld valid %u",
546 __PRETTY_FUNCTION__, pbrms->seqno, pbrms->reason,
547 pbrm->valid);
548
549 if (!install &&
550 !(pbrms->reason & PBR_MAP_DEL_SEQUENCE_NUMBER))
551 continue;
552
553 if (!install && !pbrms->installed)
554 continue;
555
556 if (install && pbrms->installed)
557 continue;
558
559 DEBUGD(&pbr_dbg_zebra, "%s: \t Seq: %u ifp %s",
560 __PRETTY_FUNCTION__, pbrms->seqno,
561 pmi->ifp->name);
562
563 pbr_encode_pbr_map_sequence(s, pbrms, pmi->ifp);
564 total++;
565 }
566 }
567
568 DEBUGD(&pbr_dbg_zebra, "%s: Putting %u at %zu ", __PRETTY_FUNCTION__,
569 total, tspot);
570
571 stream_putl_at(s, tspot, total);
572 stream_putw_at(s, 0, stream_get_endp(s));
573
574 if (!total) {
575 stream_reset(s);
576 return;
577 }
578 zclient_send_message(zclient);
579}