]> git.proxmox.com Git - mirror_frr.git/blame - pbrd/pbr_zebra.c
pbrd, zebra: Fix multiple pbr-policy install
[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:
240 DEBUGD(&pbr_dbg_zebra, "%s: Received RULE REMOVED",
241 __PRETTY_FUNCTION__);
242 break;
243 }
244
245 return 0;
246}
247
248static void zebra_connected(struct zclient *zclient)
249{
250 zclient_send_reg_requests(zclient, VRF_DEFAULT);
251}
252
253static void route_add_helper(struct zapi_route *api, struct nexthop_group nhg,
254 uint8_t install_afi)
255{
256 struct zapi_nexthop *api_nh;
257 struct nexthop *nhop;
258 int i;
259
260 api->prefix.family = install_afi;
261
262 i = 0;
263 for (ALL_NEXTHOPS(nhg, nhop)) {
264 api_nh = &api->nexthops[i];
265 api_nh->vrf_id = nhop->vrf_id;
266 api_nh->type = nhop->type;
267 switch (nhop->type) {
268 case NEXTHOP_TYPE_IPV4:
269 api_nh->gate.ipv4 = nhop->gate.ipv4;
270 break;
271 case NEXTHOP_TYPE_IPV4_IFINDEX:
272 api_nh->gate.ipv4 = nhop->gate.ipv4;
273 api_nh->ifindex = nhop->ifindex;
274 break;
275 case NEXTHOP_TYPE_IFINDEX:
276 api_nh->ifindex = nhop->ifindex;
277 break;
278 case NEXTHOP_TYPE_IPV6:
279 memcpy(&api_nh->gate.ipv6, &nhop->gate.ipv6, 16);
280 break;
281 case NEXTHOP_TYPE_IPV6_IFINDEX:
282 api_nh->ifindex = nhop->ifindex;
283 memcpy(&api_nh->gate.ipv6, &nhop->gate.ipv6, 16);
284 break;
285 case NEXTHOP_TYPE_BLACKHOLE:
286 api_nh->bh_type = nhop->bh_type;
287 break;
288 }
289 i++;
290 }
291 api->nexthop_num = i;
292
293 zclient_route_send(ZEBRA_ROUTE_ADD, zclient, api);
294}
295
296/*
297 * This function assumes a default route is being
298 * installed into the appropriate tableid
299 */
300void route_add(struct pbr_nexthop_group_cache *pnhgc, struct nexthop_group nhg,
301 afi_t install_afi)
302{
303 struct zapi_route api;
304
305 memset(&api, 0, sizeof(api));
306
307 api.vrf_id = VRF_DEFAULT;
308 api.type = ZEBRA_ROUTE_PBR;
309 api.safi = SAFI_UNICAST;
310 /*
311 * Sending a default route
312 */
313 api.tableid = pnhgc->table_id;
314 SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
315 SET_FLAG(api.message, ZAPI_MESSAGE_TABLEID);
316 SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
317 switch (install_afi) {
318 case AFI_MAX:
319 route_add_helper(&api, nhg, AF_INET);
320 route_add_helper(&api, nhg, AF_INET6);
321 break;
322 case AFI_IP:
323 route_add_helper(&api, nhg, AF_INET);
324 break;
325 case AFI_IP6:
326 route_add_helper(&api, nhg, AF_INET6);
327 break;
328 case AFI_L2VPN:
329 DEBUGD(&pbr_dbg_zebra,
330 "%s: Asked to install unsupported route type: L2VPN",
331 __PRETTY_FUNCTION__);
332 break;
333 }
334}
335
336/*
337 * This function assumes a default route is being
338 * removed from the appropriate tableid
339 */
340void route_delete(struct pbr_nexthop_group_cache *pnhgc, afi_t afi)
341{
342 struct zapi_route api;
343
344 memset(&api, 0, sizeof(api));
345 api.vrf_id = VRF_DEFAULT;
346 api.type = ZEBRA_ROUTE_PBR;
347 api.safi = SAFI_UNICAST;
348
349 api.tableid = pnhgc->table_id;
350 SET_FLAG(api.message, ZAPI_MESSAGE_TABLEID);
351
352 switch (afi) {
353 case AFI_IP:
354 api.prefix.family = AF_INET;
355 zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
356 break;
357 case AFI_IP6:
358 api.prefix.family = AF_INET6;
359 zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
360 break;
361 case AFI_MAX:
362 api.prefix.family = AF_INET;
363 zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
364 api.prefix.family = AF_INET6;
365 zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
366 break;
367 case AFI_L2VPN:
368 DEBUGD(&pbr_dbg_zebra,
369 "%s: Asked to delete unsupported route type: L2VPN",
370 __PRETTY_FUNCTION__);
371 break;
372 }
e5c83d9b
DS
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));
d3765386 436 switch (nhop->type) {
e5c83d9b
DS
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,
49027ce8 463 unsigned char family)
e5c83d9b
DS
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{
49027ce8 482 unsigned char family;
e5c83d9b
DS
483
484 family = AF_INET;
49027ce8
DS
485 if (pbrms->family)
486 family = pbrms->family;
e5c83d9b
DS
487
488 stream_putl(s, pbrms->seqno);
489 stream_putl(s, pbrms->ruleno);
490 stream_putl(s, pbrms->unique);
491 pbr_encode_pbr_map_sequence_prefix(s, pbrms->src, family);
492 stream_putw(s, 0); /* src port */
493 pbr_encode_pbr_map_sequence_prefix(s, pbrms->dst, family);
494 stream_putw(s, 0); /* dst port */
495 if (pbrms->nhgrp_name)
496 stream_putl(s, pbr_nht_get_table(pbrms->nhgrp_name));
497 else if (pbrms->nhg)
498 stream_putl(s, pbr_nht_get_table(pbrms->internal_nhg_name));
499 stream_putl(s, ifp->ifindex);
500}
501
b13e5ad6
DS
502void pbr_send_pbr_map(struct pbr_map_sequence *pbrms,
503 struct pbr_map_interface *pmi, bool install)
e5c83d9b 504{
b13e5ad6 505 struct pbr_map *pbrm = pbrms->parent;
e5c83d9b 506 struct stream *s;
37c606ff
DS
507 uint64_t is_installed = 1 << pmi->install_bit;
508
509 is_installed &= pbrms->installed;
e5c83d9b 510
37c606ff
DS
511 DEBUGD(&pbr_dbg_zebra, "%s: for %s %d(%" PRIu64 ")",
512 __PRETTY_FUNCTION__, pbrm->name, install, is_installed);
9b71ea4b
DS
513
514 /*
515 * If we are installed and asked to do so again
516 * just return. If we are not installed and asked
517 * and asked to delete just return;
518 */
37c606ff 519 if (install && is_installed)
9b71ea4b
DS
520 return;
521
37c606ff 522 if (!install && !is_installed)
9b71ea4b 523 return;
e5c83d9b
DS
524
525 s = zclient->obuf;
526 stream_reset(s);
527
528 zclient_create_header(s,
529 install ? ZEBRA_RULE_ADD : ZEBRA_RULE_DELETE,
530 VRF_DEFAULT);
531
b13e5ad6
DS
532 /*
533 * We are sending one item at a time at the moment
534 */
535 stream_putl(s, 1);
e5c83d9b 536
b13e5ad6
DS
537 DEBUGD(&pbr_dbg_zebra, "%s: \t%s %s %d %s %u",
538 __PRETTY_FUNCTION__, install ? "Installing" : "Deleting",
539 pbrm->name, install, pmi->ifp->name, pmi->delete);
e5c83d9b 540
b13e5ad6 541 pbr_encode_pbr_map_sequence(s, pbrms, pmi->ifp);
e5c83d9b 542
e5c83d9b
DS
543 stream_putw_at(s, 0, stream_get_endp(s));
544
e5c83d9b
DS
545 zclient_send_message(zclient);
546}