mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-06 10:54:47 +00:00
commit
58e7db106d
12
bgpd/bgpd.c
12
bgpd/bgpd.c
@ -1079,10 +1079,8 @@ static void peer_free(struct peer *peer)
|
||||
XFREE(MTYPE_TMP, peer->notify.data);
|
||||
memset(&peer->notify, 0, sizeof(struct bgp_notify));
|
||||
|
||||
if (peer->clear_node_queue) {
|
||||
work_queue_free(peer->clear_node_queue);
|
||||
peer->clear_node_queue = NULL;
|
||||
}
|
||||
if (peer->clear_node_queue)
|
||||
work_queue_free_and_null(&peer->clear_node_queue);
|
||||
|
||||
bgp_sync_delete(peer);
|
||||
|
||||
@ -7639,10 +7637,8 @@ void bgp_terminate(void)
|
||||
bgp_notify_send(peer, BGP_NOTIFY_CEASE,
|
||||
BGP_NOTIFY_CEASE_PEER_UNCONFIG);
|
||||
|
||||
if (bm->process_main_queue) {
|
||||
work_queue_free(bm->process_main_queue);
|
||||
bm->process_main_queue = NULL;
|
||||
}
|
||||
if (bm->process_main_queue)
|
||||
work_queue_free_and_null(&bm->process_main_queue);
|
||||
|
||||
if (bm->t_rmap_update)
|
||||
BGP_TIMER_OFF(bm->t_rmap_update);
|
||||
|
@ -4336,7 +4336,7 @@ void bgp_rfapi_destroy(struct bgp *bgp, struct rfapi *h)
|
||||
h->import_mac = NULL;
|
||||
}
|
||||
|
||||
work_queue_free(h->deferred_close_q);
|
||||
work_queue_free_and_null(&h->deferred_close_q);
|
||||
|
||||
if (h->rfp != NULL)
|
||||
rfp_stop(h->rfp);
|
||||
|
@ -571,10 +571,8 @@ void rfapiRibClear(struct rfapi_descriptor *rfd)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rfd->updated_responses_queue) {
|
||||
work_queue_free(rfd->updated_responses_queue);
|
||||
rfd->updated_responses_queue = NULL;
|
||||
}
|
||||
if (rfd->updated_responses_queue)
|
||||
work_queue_free_and_null(&rfd->updated_responses_queue);
|
||||
}
|
||||
|
||||
/*
|
||||
|
74
include/linux/fib_rules.h
Normal file
74
include/linux/fib_rules.h
Normal file
@ -0,0 +1,74 @@
|
||||
#ifndef __LINUX_FIB_RULES_H
|
||||
#define __LINUX_FIB_RULES_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
/* rule is permanent, and cannot be deleted */
|
||||
#define FIB_RULE_PERMANENT 0x00000001
|
||||
#define FIB_RULE_INVERT 0x00000002
|
||||
#define FIB_RULE_UNRESOLVED 0x00000004
|
||||
#define FIB_RULE_IIF_DETACHED 0x00000008
|
||||
#define FIB_RULE_DEV_DETACHED FIB_RULE_IIF_DETACHED
|
||||
#define FIB_RULE_OIF_DETACHED 0x00000010
|
||||
|
||||
/* try to find source address in routing lookups */
|
||||
#define FIB_RULE_FIND_SADDR 0x00010000
|
||||
|
||||
struct fib_rule_hdr {
|
||||
__u8 family;
|
||||
__u8 dst_len;
|
||||
__u8 src_len;
|
||||
__u8 tos;
|
||||
|
||||
__u8 table;
|
||||
__u8 res1; /* reserved */
|
||||
__u8 res2; /* reserved */
|
||||
__u8 action;
|
||||
|
||||
__u32 flags;
|
||||
};
|
||||
|
||||
enum {
|
||||
FRA_UNSPEC,
|
||||
FRA_DST, /* destination address */
|
||||
FRA_SRC, /* source address */
|
||||
FRA_IIFNAME, /* interface name */
|
||||
#define FRA_IFNAME FRA_IIFNAME
|
||||
FRA_GOTO, /* target to jump to (FR_ACT_GOTO) */
|
||||
FRA_UNUSED2,
|
||||
FRA_PRIORITY, /* priority/preference */
|
||||
FRA_UNUSED3,
|
||||
FRA_UNUSED4,
|
||||
FRA_UNUSED5,
|
||||
FRA_FWMARK, /* mark */
|
||||
FRA_FLOW, /* flow/class id */
|
||||
FRA_UNUSED6,
|
||||
FRA_SUPPRESS_IFGROUP,
|
||||
FRA_SUPPRESS_PREFIXLEN,
|
||||
FRA_TABLE, /* Extended table id */
|
||||
FRA_FWMASK, /* mask for netfilter mark */
|
||||
FRA_OIFNAME,
|
||||
FRA_PAD,
|
||||
FRA_L3MDEV, /* iif or oif is l3mdev goto its table */
|
||||
__FRA_MAX
|
||||
};
|
||||
|
||||
#define FRA_MAX (__FRA_MAX - 1)
|
||||
|
||||
enum {
|
||||
FR_ACT_UNSPEC,
|
||||
FR_ACT_TO_TBL, /* Pass to fixed table */
|
||||
FR_ACT_GOTO, /* Jump to another rule */
|
||||
FR_ACT_NOP, /* No operation */
|
||||
FR_ACT_RES3,
|
||||
FR_ACT_RES4,
|
||||
FR_ACT_BLACKHOLE, /* Drop without notification */
|
||||
FR_ACT_UNREACHABLE, /* Drop with ENETUNREACH */
|
||||
FR_ACT_PROHIBIT, /* Drop with EACCES */
|
||||
__FR_ACT_MAX,
|
||||
};
|
||||
|
||||
#define FR_ACT_MAX (__FR_ACT_MAX - 1)
|
||||
|
||||
#endif
|
@ -7,4 +7,5 @@ noinst_HEADERS += \
|
||||
include/linux/rtnetlink.h \
|
||||
include/linux/socket.h \
|
||||
include/linux/net_namespace.h \
|
||||
include/linux/fib_rules.h \
|
||||
# end
|
||||
|
@ -65,6 +65,7 @@ const char *node_names[] = {
|
||||
"logical-router", // LOGICALROUTER_NODE,
|
||||
"vrf", // VRF_NODE,
|
||||
"interface", // INTERFACE_NODE,
|
||||
"nexthop-group", // NH_GROUP_NODE,
|
||||
"zebra", // ZEBRA_NODE,
|
||||
"table", // TABLE_NODE,
|
||||
"rip", // RIP_NODE,
|
||||
@ -1294,6 +1295,7 @@ void cmd_exit(struct vty *vty)
|
||||
case PW_NODE:
|
||||
case LOGICALROUTER_NODE:
|
||||
case VRF_NODE:
|
||||
case NH_GROUP_NODE:
|
||||
case ZEBRA_NODE:
|
||||
case BGP_NODE:
|
||||
case RIP_NODE:
|
||||
@ -1379,6 +1381,7 @@ DEFUN (config_end,
|
||||
case PW_NODE:
|
||||
case LOGICALROUTER_NODE:
|
||||
case VRF_NODE:
|
||||
case NH_GROUP_NODE:
|
||||
case ZEBRA_NODE:
|
||||
case RIP_NODE:
|
||||
case RIPNG_NODE:
|
||||
|
@ -88,6 +88,7 @@ enum node_type {
|
||||
LOGICALROUTER_NODE, /* Logical-Router node. */
|
||||
VRF_NODE, /* VRF mode node. */
|
||||
INTERFACE_NODE, /* Interface mode node. */
|
||||
NH_GROUP_NODE, /* Nexthop-Group mode node. */
|
||||
ZEBRA_NODE, /* zebra connection node. */
|
||||
TABLE_NODE, /* rtm_table selection node. */
|
||||
RIP_NODE, /* RIP protocol mode node. */
|
||||
|
@ -961,6 +961,9 @@ static const struct zebra_desc_table command_types[] = {
|
||||
DESC_ENTRY(ZEBRA_PW_SET),
|
||||
DESC_ENTRY(ZEBRA_PW_UNSET),
|
||||
DESC_ENTRY(ZEBRA_PW_STATUS_UPDATE),
|
||||
DESC_ENTRY(ZEBRA_RULE_ADD),
|
||||
DESC_ENTRY(ZEBRA_RULE_DELETE),
|
||||
DESC_ENTRY(ZEBRA_RULE_NOTIFY_OWNER),
|
||||
};
|
||||
#undef DESC_ENTRY
|
||||
|
||||
|
@ -143,49 +143,6 @@ struct nexthop *nexthop_new(void)
|
||||
return XCALLOC(MTYPE_NEXTHOP, sizeof(struct nexthop));
|
||||
}
|
||||
|
||||
/* Add nexthop to the end of a nexthop list. */
|
||||
void nexthop_add(struct nexthop **target, struct nexthop *nexthop)
|
||||
{
|
||||
struct nexthop *last;
|
||||
|
||||
for (last = *target; last && last->next; last = last->next)
|
||||
;
|
||||
if (last)
|
||||
last->next = nexthop;
|
||||
else
|
||||
*target = nexthop;
|
||||
nexthop->prev = last;
|
||||
}
|
||||
|
||||
void copy_nexthops(struct nexthop **tnh, struct nexthop *nh,
|
||||
struct nexthop *rparent)
|
||||
{
|
||||
struct nexthop *nexthop;
|
||||
struct nexthop *nh1;
|
||||
|
||||
for (nh1 = nh; nh1; nh1 = nh1->next) {
|
||||
nexthop = nexthop_new();
|
||||
nexthop->vrf_id = nh1->vrf_id;
|
||||
nexthop->ifindex = nh1->ifindex;
|
||||
nexthop->type = nh1->type;
|
||||
nexthop->flags = nh1->flags;
|
||||
memcpy(&nexthop->gate, &nh1->gate, sizeof(nh1->gate));
|
||||
memcpy(&nexthop->src, &nh1->src, sizeof(nh1->src));
|
||||
memcpy(&nexthop->rmap_src, &nh1->rmap_src,
|
||||
sizeof(nh1->rmap_src));
|
||||
nexthop->rparent = rparent;
|
||||
if (nh1->nh_label)
|
||||
nexthop_add_labels(nexthop, nh1->nh_label_type,
|
||||
nh1->nh_label->num_labels,
|
||||
&nh1->nh_label->label[0]);
|
||||
nexthop_add(tnh, nexthop);
|
||||
|
||||
if (CHECK_FLAG(nh1->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||
copy_nexthops(&nexthop->resolved, nh1->resolved,
|
||||
nexthop);
|
||||
}
|
||||
}
|
||||
|
||||
/* Free nexthop. */
|
||||
void nexthop_free(struct nexthop *nexthop)
|
||||
{
|
||||
|
@ -109,24 +109,8 @@ struct nexthop {
|
||||
struct mpls_label_stack *nh_label;
|
||||
};
|
||||
|
||||
/* The following for loop allows to iterate over the nexthop
|
||||
* structure of routes.
|
||||
*
|
||||
* head: The pointer to the first nexthop in the chain.
|
||||
*
|
||||
* nexthop: The pointer to the current nexthop, either in the
|
||||
* top-level chain or in a resolved chain.
|
||||
*/
|
||||
#define ALL_NEXTHOPS(head, nexthop) \
|
||||
(nexthop) = (head); \
|
||||
(nexthop); \
|
||||
(nexthop) = nexthop_next(nexthop)
|
||||
|
||||
struct nexthop *nexthop_new(void);
|
||||
void nexthop_add(struct nexthop **target, struct nexthop *nexthop);
|
||||
|
||||
void copy_nexthops(struct nexthop **tnh, struct nexthop *nh,
|
||||
struct nexthop *rparent);
|
||||
void nexthop_free(struct nexthop *nexthop);
|
||||
void nexthops_free(struct nexthop *nexthop);
|
||||
|
||||
|
100
lib/nexthop_group.c
Normal file
100
lib/nexthop_group.c
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Nexthop Group structure definition.
|
||||
* Copyright (C) 2018 Cumulus Networks, Inc.
|
||||
* Donald Sharp
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <zebra.h>
|
||||
|
||||
#include <nexthop.h>
|
||||
#include <nexthop_group.h>
|
||||
#include <vty.h>
|
||||
#include <command.h>
|
||||
|
||||
#ifndef VTYSH_EXTRACT_PL
|
||||
#include "lib/nexthop_group_clippy.c"
|
||||
#endif
|
||||
|
||||
/* Add nexthop to the end of a nexthop list. */
|
||||
void nexthop_add(struct nexthop **target, struct nexthop *nexthop)
|
||||
{
|
||||
struct nexthop *last;
|
||||
|
||||
for (last = *target; last && last->next; last = last->next)
|
||||
;
|
||||
if (last)
|
||||
last->next = nexthop;
|
||||
else
|
||||
*target = nexthop;
|
||||
nexthop->prev = last;
|
||||
}
|
||||
|
||||
void copy_nexthops(struct nexthop **tnh, struct nexthop *nh,
|
||||
struct nexthop *rparent)
|
||||
{
|
||||
struct nexthop *nexthop;
|
||||
struct nexthop *nh1;
|
||||
|
||||
for (nh1 = nh; nh1; nh1 = nh1->next) {
|
||||
nexthop = nexthop_new();
|
||||
nexthop->vrf_id = nh1->vrf_id;
|
||||
nexthop->ifindex = nh1->ifindex;
|
||||
nexthop->type = nh1->type;
|
||||
nexthop->flags = nh1->flags;
|
||||
memcpy(&nexthop->gate, &nh1->gate, sizeof(nh1->gate));
|
||||
memcpy(&nexthop->src, &nh1->src, sizeof(nh1->src));
|
||||
memcpy(&nexthop->rmap_src, &nh1->rmap_src,
|
||||
sizeof(nh1->rmap_src));
|
||||
nexthop->rparent = rparent;
|
||||
if (nh1->nh_label)
|
||||
nexthop_add_labels(nexthop, nh1->nh_label_type,
|
||||
nh1->nh_label->num_labels,
|
||||
&nh1->nh_label->label[0]);
|
||||
nexthop_add(tnh, nexthop);
|
||||
|
||||
if (CHECK_FLAG(nh1->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||
copy_nexthops(&nexthop->resolved, nh1->resolved,
|
||||
nexthop);
|
||||
}
|
||||
}
|
||||
|
||||
DEFPY (nexthop_group,
|
||||
nexthop_group_cmd,
|
||||
"nexthop-group NAME",
|
||||
"Enter into the nexthop-group submode\n"
|
||||
"Specify the NAME of the nexthop-group\n")
|
||||
{
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
struct cmd_node nexthop_group_node = {
|
||||
NH_GROUP_NODE,
|
||||
"%s(config-nh-group)# ",
|
||||
1
|
||||
};
|
||||
|
||||
static int nexthop_group_write(struct vty *vty)
|
||||
{
|
||||
vty_out(vty, "!\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void nexthop_group_init(void)
|
||||
{
|
||||
install_node(&nexthop_group_node, nexthop_group_write);
|
||||
install_element(CONFIG_NODE, &nexthop_group_cmd);
|
||||
}
|
54
lib/nexthop_group.h
Normal file
54
lib/nexthop_group.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Nexthop Group structure definition.
|
||||
* Copyright (C) 2018 Cumulus Networks, Inc.
|
||||
* Donald Sharp
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __NEXTHOP_GROUP__
|
||||
#define __NEXTHOP_GROUP__
|
||||
|
||||
/*
|
||||
* What is a nexthop group?
|
||||
*
|
||||
* A nexthop group is a collection of nexthops that make up
|
||||
* the ECMP path for the route.
|
||||
*
|
||||
* This module provides a proper abstraction to this idea.
|
||||
*/
|
||||
struct nexthop_group {
|
||||
struct nexthop *nexthop;
|
||||
};
|
||||
|
||||
void nexthop_group_init(void);
|
||||
|
||||
void nexthop_add(struct nexthop **target, struct nexthop *nexthop);
|
||||
void copy_nexthops(struct nexthop **tnh, struct nexthop *nh,
|
||||
struct nexthop *rparent);
|
||||
|
||||
/* The following for loop allows to iterate over the nexthop
|
||||
* structure of routes.
|
||||
*
|
||||
* head: The pointer to the first nexthop in the chain.
|
||||
*
|
||||
* nexthop: The pointer to the current nexthop, either in the
|
||||
* top-level chain or in a resolved chain.
|
||||
*/
|
||||
#define ALL_NEXTHOPS(head, nhop) \
|
||||
(nhop) = (head.nexthop); \
|
||||
(nhop); \
|
||||
(nhop) = nexthop_next(nhop)
|
||||
#endif
|
@ -45,6 +45,7 @@ lib_libfrr_la_SOURCES = \
|
||||
lib/nexthop.c \
|
||||
lib/netns_linux.c \
|
||||
lib/netns_other.c \
|
||||
lib/nexthop_group.c \
|
||||
lib/openbsd-tree.c \
|
||||
lib/pid_output.c \
|
||||
lib/plist.c \
|
||||
@ -81,6 +82,8 @@ lib_libfrr_la_SOURCES = \
|
||||
|
||||
lib/plist_clippy.c: $(CLIPPY_DEPS)
|
||||
lib/plist.lo: lib/plist_clippy.c
|
||||
lib/nexthop_group_clippy.c: $(CLIPPY_DEPS)
|
||||
lib/nexthop_group.lo: lib/nexthop_group_clippy.c
|
||||
|
||||
pkginclude_HEADERS += \
|
||||
lib/bfd.h \
|
||||
@ -124,6 +127,7 @@ pkginclude_HEADERS += \
|
||||
lib/mpls.h \
|
||||
lib/network.h \
|
||||
lib/nexthop.h \
|
||||
lib/nexthop_group.h \
|
||||
lib/ns.h \
|
||||
lib/openbsd-queue.h \
|
||||
lib/openbsd-tree.h \
|
||||
|
@ -101,7 +101,7 @@ struct work_queue *work_queue_new(struct thread_master *m,
|
||||
return new;
|
||||
}
|
||||
|
||||
void work_queue_free(struct work_queue *wq)
|
||||
void work_queue_free_original(struct work_queue *wq)
|
||||
{
|
||||
if (wq->thread != NULL)
|
||||
thread_cancel(wq->thread);
|
||||
@ -119,6 +119,12 @@ void work_queue_free(struct work_queue *wq)
|
||||
return;
|
||||
}
|
||||
|
||||
void work_queue_free_and_null(struct work_queue **wq)
|
||||
{
|
||||
work_queue_free_original(*wq);
|
||||
*wq = NULL;
|
||||
}
|
||||
|
||||
bool work_queue_is_scheduled(struct work_queue *wq)
|
||||
{
|
||||
return (wq->thread != NULL);
|
||||
|
@ -28,7 +28,7 @@
|
||||
DECLARE_MTYPE(WORK_QUEUE)
|
||||
|
||||
/* Hold time for the initial schedule of a queue run, in millisec */
|
||||
#define WORK_QUEUE_DEFAULT_HOLD 50
|
||||
#define WORK_QUEUE_DEFAULT_HOLD 50
|
||||
|
||||
/* action value, for use by item processor and item error handlers */
|
||||
typedef enum {
|
||||
@ -148,8 +148,22 @@ static inline void work_queue_item_dequeue(struct work_queue *wq,
|
||||
* anything to it
|
||||
*/
|
||||
extern struct work_queue *work_queue_new(struct thread_master *, const char *);
|
||||
|
||||
/* destroy work queue */
|
||||
extern void work_queue_free(struct work_queue *);
|
||||
/*
|
||||
* The usage of work_queue_free is being transitioned to pass
|
||||
* in the double pointer to remove use after free's.
|
||||
*/
|
||||
#if CONFDATE > 20190205
|
||||
CPP_NOTICE("work_queue_free without double pointer is deprecated, please fixup")
|
||||
#endif
|
||||
extern void work_queue_free_and_null(struct work_queue **);
|
||||
extern void work_queue_free_original(struct work_queue *);
|
||||
#define work_queue_free(X) \
|
||||
do { \
|
||||
work_queue_free_original((X)); \
|
||||
CPP_WARN("Please use work_queue_free_and_null"); \
|
||||
} while (0)
|
||||
|
||||
/* Add the supplied data as an item onto the workqueue */
|
||||
extern void work_queue_add(struct work_queue *, void *);
|
||||
|
@ -1058,6 +1058,8 @@ int zapi_route_encode(u_char cmd, struct stream *s, struct zapi_route *api)
|
||||
stream_putl(s, api->tag);
|
||||
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_MTU))
|
||||
stream_putl(s, api->mtu);
|
||||
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_TABLEID))
|
||||
stream_putl(s, api->tableid);
|
||||
|
||||
/* Put length at the first point of the stream. */
|
||||
stream_putw_at(s, 0, stream_get_endp(s));
|
||||
@ -1207,6 +1209,8 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api)
|
||||
STREAM_GETL(s, api->tag);
|
||||
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_MTU))
|
||||
STREAM_GETL(s, api->mtu);
|
||||
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_TABLEID))
|
||||
STREAM_GETL(s, api->tableid);
|
||||
|
||||
stream_failure:
|
||||
return 0;
|
||||
@ -1233,6 +1237,35 @@ stream_failure:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool zapi_rule_notify_decode(struct stream *s, uint32_t *seqno,
|
||||
uint32_t *priority, uint32_t *unique,
|
||||
ifindex_t *ifindex,
|
||||
enum zapi_rule_notify_owner *note)
|
||||
{
|
||||
uint32_t prio, seq, uni;
|
||||
ifindex_t ifi;
|
||||
|
||||
STREAM_GET(note, s, sizeof(*note));
|
||||
|
||||
STREAM_GETL(s, seq);
|
||||
STREAM_GETL(s, prio);
|
||||
STREAM_GETL(s, uni);
|
||||
STREAM_GETL(s, ifi);
|
||||
|
||||
if (zclient_debug)
|
||||
zlog_debug("%s: %u %u %u %u", __PRETTY_FUNCTION__,
|
||||
seq, prio, uni, ifi);
|
||||
*seqno = seq;
|
||||
*priority = prio;
|
||||
*unique = uni;
|
||||
*ifindex = ifi;
|
||||
|
||||
return true;
|
||||
|
||||
stream_failure:
|
||||
return false;
|
||||
}
|
||||
|
||||
struct nexthop *nexthop_from_zapi_nexthop(struct zapi_nexthop *znh)
|
||||
{
|
||||
struct nexthop *n = nexthop_new();
|
||||
@ -2377,6 +2410,10 @@ static int zclient_read(struct thread *thread)
|
||||
(*zclient->route_notify_owner)(command, zclient, length,
|
||||
vrf_id);
|
||||
break;
|
||||
case ZEBRA_RULE_NOTIFY_OWNER:
|
||||
if (zclient->rule_notify_owner)
|
||||
(*zclient->rule_notify_owner)(command, zclient, length,
|
||||
vrf_id);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -129,6 +129,9 @@ typedef enum {
|
||||
ZEBRA_PW_SET,
|
||||
ZEBRA_PW_UNSET,
|
||||
ZEBRA_PW_STATUS_UPDATE,
|
||||
ZEBRA_RULE_ADD,
|
||||
ZEBRA_RULE_DELETE,
|
||||
ZEBRA_RULE_NOTIFY_OWNER,
|
||||
} zebra_message_types_t;
|
||||
|
||||
struct redist_proto {
|
||||
@ -215,6 +218,8 @@ struct zclient {
|
||||
int (*pw_status_update)(int, struct zclient *, uint16_t, vrf_id_t);
|
||||
int (*route_notify_owner)(int command, struct zclient *zclient,
|
||||
uint16_t length, vrf_id_t vrf_id);
|
||||
int (*rule_notify_owner)(int command, struct zclient *zclient,
|
||||
uint16_t length, vrf_id_t vrf_id);
|
||||
};
|
||||
|
||||
/* Zebra API message flag. */
|
||||
@ -225,6 +230,12 @@ struct zclient {
|
||||
#define ZAPI_MESSAGE_MTU 0x10
|
||||
#define ZAPI_MESSAGE_SRCPFX 0x20
|
||||
#define ZAPI_MESSAGE_LABEL 0x40
|
||||
/*
|
||||
* This should only be used by a DAEMON that needs to communicate
|
||||
* the table being used is not in the VRF. You must pass the
|
||||
* default vrf, else this will be ignored.
|
||||
*/
|
||||
#define ZAPI_MESSAGE_TABLEID 0x80
|
||||
|
||||
/* Zserv protocol message header */
|
||||
struct zserv_header {
|
||||
@ -289,6 +300,8 @@ struct zapi_route {
|
||||
|
||||
vrf_id_t vrf_id;
|
||||
|
||||
uint32_t tableid;
|
||||
|
||||
struct ethaddr rmac;
|
||||
};
|
||||
|
||||
@ -350,6 +363,12 @@ enum zapi_route_notify_owner {
|
||||
ZAPI_ROUTE_REMOVE_FAIL,
|
||||
};
|
||||
|
||||
enum zapi_rule_notify_owner {
|
||||
ZAPI_RULE_FAIL_INSTALL,
|
||||
ZAPI_RULE_INSTALLED,
|
||||
ZAPI_RULE_REMOVED,
|
||||
};
|
||||
|
||||
/* Zebra MAC types */
|
||||
#define ZEBRA_MACIP_TYPE_STICKY 0x01 /* Sticky MAC*/
|
||||
#define ZEBRA_MACIP_TYPE_GW 0x02 /* gateway (SVI) mac*/
|
||||
@ -520,6 +539,10 @@ extern int zapi_route_decode(struct stream *, struct zapi_route *);
|
||||
bool zapi_route_notify_decode(struct stream *s, struct prefix *p,
|
||||
uint32_t *tableid,
|
||||
enum zapi_route_notify_owner *note);
|
||||
bool zapi_rule_notify_decode(struct stream *s, uint32_t *seqno,
|
||||
uint32_t *priority, uint32_t *unique,
|
||||
ifindex_t *ifindex,
|
||||
enum zapi_rule_notify_owner *note);
|
||||
extern struct nexthop *nexthop_from_zapi_nexthop(struct zapi_nexthop *znh);
|
||||
extern bool zapi_nexthop_update_decode(struct stream *s,
|
||||
struct zapi_route *nhr);
|
||||
|
@ -60,7 +60,7 @@ static void str_appendf(char **buf, const char *format, ...)
|
||||
* and its expected representation */
|
||||
struct nexthop_chain {
|
||||
/* Head of the chain */
|
||||
struct nexthop *head;
|
||||
struct nexthop_group head;
|
||||
/* Last nexthop in top chain */
|
||||
struct nexthop *current_top;
|
||||
/* Last nexthop in current recursive chain */
|
||||
@ -85,12 +85,12 @@ static void nexthop_chain_add_top(struct nexthop_chain *nc)
|
||||
nh = calloc(sizeof(*nh), 1);
|
||||
assert(nh);
|
||||
|
||||
if (nc->head) {
|
||||
if (nc->head.nexthop) {
|
||||
nc->current_top->next = nh;
|
||||
nh->prev = nc->current_top;
|
||||
nc->current_top = nh;
|
||||
} else {
|
||||
nc->head = nc->current_top = nh;
|
||||
nc->head.nexthop = nc->current_top = nh;
|
||||
}
|
||||
nc->current_recursive = NULL;
|
||||
str_appendf(&nc->repr, "%p\n", nh);
|
||||
@ -166,8 +166,8 @@ static void nexthop_clear_recursive(struct nexthop *tcur)
|
||||
}
|
||||
static void nexthop_chain_clear(struct nexthop_chain *nc)
|
||||
{
|
||||
nexthop_clear_recursive(nc->head);
|
||||
nc->head = nc->current_top = nc->current_recursive = NULL;
|
||||
nexthop_clear_recursive(nc->head.nexthop);
|
||||
nc->head.nexthop = nc->current_top = nc->current_recursive = NULL;
|
||||
free(nc->repr);
|
||||
nc->repr = NULL;
|
||||
}
|
||||
|
@ -1499,6 +1499,7 @@ static int vtysh_exit(struct vty *vty)
|
||||
case PW_NODE:
|
||||
case LOGICALROUTER_NODE:
|
||||
case VRF_NODE:
|
||||
case NH_GROUP_NODE:
|
||||
case ZEBRA_NODE:
|
||||
case BGP_NODE:
|
||||
case RIP_NODE:
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "zebra/kernel_netlink.h"
|
||||
#include "zebra/rt_netlink.h"
|
||||
#include "zebra/if_netlink.h"
|
||||
#include "zebra/rule_netlink.h"
|
||||
|
||||
#ifndef SO_RCVBUFFORCE
|
||||
#define SO_RCVBUFFORCE (33)
|
||||
@ -85,6 +86,9 @@ static const struct message nlmsg_str[] = {{RTM_NEWROUTE, "RTM_NEWROUTE"},
|
||||
{RTM_NEWNEIGH, "RTM_NEWNEIGH"},
|
||||
{RTM_DELNEIGH, "RTM_DELNEIGH"},
|
||||
{RTM_GETNEIGH, "RTM_GETNEIGH"},
|
||||
{RTM_NEWRULE, "RTM_NEWRULE"},
|
||||
{RTM_DELRULE, "RTM_DELRULE"},
|
||||
{RTM_GETRULE, "RTM_GETRULE"},
|
||||
{0}};
|
||||
|
||||
static const struct message rtproto_str[] = {
|
||||
@ -240,28 +244,24 @@ static int netlink_information_fetch(struct sockaddr_nl *snl,
|
||||
switch (h->nlmsg_type) {
|
||||
case RTM_NEWROUTE:
|
||||
return netlink_route_change(snl, h, ns_id, startup);
|
||||
break;
|
||||
case RTM_DELROUTE:
|
||||
return netlink_route_change(snl, h, ns_id, startup);
|
||||
break;
|
||||
case RTM_NEWLINK:
|
||||
return netlink_link_change(snl, h, ns_id, startup);
|
||||
break;
|
||||
case RTM_DELLINK:
|
||||
return netlink_link_change(snl, h, ns_id, startup);
|
||||
break;
|
||||
case RTM_NEWADDR:
|
||||
return netlink_interface_addr(snl, h, ns_id, startup);
|
||||
break;
|
||||
case RTM_DELADDR:
|
||||
return netlink_interface_addr(snl, h, ns_id, startup);
|
||||
break;
|
||||
case RTM_NEWNEIGH:
|
||||
return netlink_neigh_change(snl, h, ns_id);
|
||||
break;
|
||||
case RTM_DELNEIGH:
|
||||
return netlink_neigh_change(snl, h, ns_id);
|
||||
break;
|
||||
case RTM_NEWRULE:
|
||||
return netlink_rule_change(snl, h, ns_id, startup);
|
||||
case RTM_DELRULE:
|
||||
return netlink_rule_change(snl, h, ns_id, startup);
|
||||
default:
|
||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||
zlog_debug("Unknown netlink nlmsg_type %d vrf %u\n",
|
||||
@ -788,7 +788,8 @@ void kernel_init(struct zebra_ns *zns)
|
||||
/* Initialize netlink sockets */
|
||||
groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR
|
||||
| RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR | RTMGRP_IPV4_MROUTE
|
||||
| RTMGRP_NEIGH;
|
||||
| RTMGRP_NEIGH
|
||||
| RTNLGRP_IPV4_RULE | RTNLGRP_IPV6_RULE;
|
||||
|
||||
snprintf(zns->netlink.name, sizeof(zns->netlink.name),
|
||||
"netlink-listen (NS %u)", zns->ns_id);
|
||||
|
@ -140,7 +140,7 @@ static void sigint(void)
|
||||
SET_FLAG(zvrf->flags, ZEBRA_VRF_RETAIN);
|
||||
}
|
||||
if (zebrad.lsp_process_q)
|
||||
work_queue_free(zebrad.lsp_process_q);
|
||||
work_queue_free_and_null(&zebrad.lsp_process_q);
|
||||
vrf_terminate();
|
||||
|
||||
ns_walk_func(zebra_ns_disabled);
|
||||
@ -151,7 +151,7 @@ static void sigint(void)
|
||||
route_map_finish();
|
||||
|
||||
list_delete_and_null(&zebrad.client_list);
|
||||
work_queue_free(zebrad.ribq);
|
||||
work_queue_free_and_null(&zebrad.ribq);
|
||||
meta_queue_free(zebrad.mq);
|
||||
|
||||
frr_fini();
|
||||
|
@ -519,8 +519,8 @@ int zebra_add_import_table_entry(struct route_node *rn, struct route_entry *re,
|
||||
afi = family2afi(rn->p.family);
|
||||
if (rmap_name)
|
||||
ret = zebra_import_table_route_map_check(
|
||||
afi, re->type, &rn->p, re->nexthop, re->vrf_id, re->tag,
|
||||
rmap_name);
|
||||
afi, re->type, &rn->p, re->ng.nexthop, re->vrf_id,
|
||||
re->tag, rmap_name);
|
||||
|
||||
if (ret != RMAP_MATCH) {
|
||||
zebra_del_import_table_entry(rn, re);
|
||||
@ -552,7 +552,7 @@ int zebra_add_import_table_entry(struct route_node *rn, struct route_entry *re,
|
||||
newre->nexthop_num = 0;
|
||||
newre->uptime = time(NULL);
|
||||
newre->instance = re->table;
|
||||
route_entry_copy_nexthops(newre, re->nexthop);
|
||||
route_entry_copy_nexthops(newre, re->ng.nexthop);
|
||||
|
||||
rib_add_multipath(afi, SAFI_UNICAST, &p, NULL, newre);
|
||||
|
||||
@ -568,8 +568,8 @@ int zebra_del_import_table_entry(struct route_node *rn, struct route_entry *re)
|
||||
prefix_copy(&p, &rn->p);
|
||||
|
||||
rib_delete(afi, SAFI_UNICAST, re->vrf_id, ZEBRA_ROUTE_TABLE, re->table,
|
||||
re->flags, &p, NULL, re->nexthop, zebrad.rtm_table_default,
|
||||
re->metric, false, NULL);
|
||||
re->flags, &p, NULL, re->ng.nexthop,
|
||||
zebrad.rtm_table_default, re->metric, false, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "table.h"
|
||||
#include "queue.h"
|
||||
#include "nexthop.h"
|
||||
#include "nexthop_group.h"
|
||||
#include "vrf.h"
|
||||
#include "if.h"
|
||||
#include "mpls.h"
|
||||
@ -43,7 +44,7 @@ struct route_entry {
|
||||
struct route_entry *prev;
|
||||
|
||||
/* Nexthop structure */
|
||||
struct nexthop *nexthop;
|
||||
struct nexthop_group ng;
|
||||
|
||||
/* Tag */
|
||||
route_tag_t tag;
|
||||
|
@ -1398,7 +1398,7 @@ static int netlink_route_multipath(int cmd, struct prefix *p,
|
||||
/* Count overall nexthops so we can decide whether to use singlepath
|
||||
* or multipath case. */
|
||||
nexthop_num = 0;
|
||||
for (ALL_NEXTHOPS(re->nexthop, nexthop)) {
|
||||
for (ALL_NEXTHOPS(re->ng, nexthop)) {
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||
continue;
|
||||
if (cmd == RTM_NEWROUTE && !NEXTHOP_IS_ACTIVE(nexthop->flags))
|
||||
@ -1413,7 +1413,7 @@ static int netlink_route_multipath(int cmd, struct prefix *p,
|
||||
/* Singlepath case. */
|
||||
if (nexthop_num == 1 || multipath_num == 1) {
|
||||
nexthop_num = 0;
|
||||
for (ALL_NEXTHOPS(re->nexthop, nexthop)) {
|
||||
for (ALL_NEXTHOPS(re->ng, nexthop)) {
|
||||
/*
|
||||
* So we want to cover 2 types of blackhole
|
||||
* routes here:
|
||||
@ -1513,7 +1513,7 @@ static int netlink_route_multipath(int cmd, struct prefix *p,
|
||||
rtnh = RTA_DATA(rta);
|
||||
|
||||
nexthop_num = 0;
|
||||
for (ALL_NEXTHOPS(re->nexthop, nexthop)) {
|
||||
for (ALL_NEXTHOPS(re->ng, nexthop)) {
|
||||
if (nexthop_num >= multipath_num)
|
||||
break;
|
||||
|
||||
|
@ -123,7 +123,7 @@ static int kernel_rtm_ipv4(int cmd, struct prefix *p, struct route_entry *re)
|
||||
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
|
||||
|
||||
/* Make gateway. */
|
||||
for (ALL_NEXTHOPS(re->nexthop, nexthop)) {
|
||||
for (ALL_NEXTHOPS(re->ng, nexthop)) {
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||
continue;
|
||||
|
||||
@ -303,7 +303,7 @@ static int kernel_rtm_ipv6(int cmd, struct prefix *p, struct route_entry *re)
|
||||
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
|
||||
|
||||
/* Make gateway. */
|
||||
for (ALL_NEXTHOPS(re->nexthop, nexthop)) {
|
||||
for (ALL_NEXTHOPS(re->ng, nexthop)) {
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||
continue;
|
||||
|
||||
|
@ -263,4 +263,8 @@ void neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if)
|
||||
{
|
||||
}
|
||||
|
||||
void kernel_read_pbr_rules(struct zebra_ns *zns)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* SUNOS_5 */
|
||||
|
@ -25,7 +25,9 @@
|
||||
|
||||
#include "vty.h"
|
||||
#include "zebra/rt.h"
|
||||
#include "zebra/zebra_pbr.h"
|
||||
#include "zebra/rt_netlink.h"
|
||||
#include "zebra/rule_netlink.h"
|
||||
|
||||
void route_read(struct zebra_ns *zns)
|
||||
{
|
||||
@ -53,4 +55,9 @@ void neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if)
|
||||
netlink_neigh_read_for_vlan(zns, vlan_if);
|
||||
}
|
||||
|
||||
void kernel_read_pbr_rules(struct zebra_ns *zns)
|
||||
{
|
||||
netlink_rules_read(zns);
|
||||
}
|
||||
|
||||
#endif /* GNU_LINUX */
|
||||
|
@ -30,6 +30,7 @@
|
||||
|
||||
#include "zebra/rt.h"
|
||||
#include "zebra/kernel_socket.h"
|
||||
#include "zebra/zebra_pbr.h"
|
||||
|
||||
/* Kernel routing table read up by sysctl function. */
|
||||
void route_read(struct zebra_ns *zns)
|
||||
@ -92,4 +93,8 @@ void neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if)
|
||||
{
|
||||
}
|
||||
|
||||
void kernel_read_pbr_rules(struct zebra_ns *zns)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* !defined(GNU_LINUX) && !defined(SUNOS_5) */
|
||||
|
267
zebra/rule_netlink.c
Normal file
267
zebra/rule_netlink.c
Normal file
@ -0,0 +1,267 @@
|
||||
/*
|
||||
* Zebra Policy Based Routing (PBR) interaction with the kernel using
|
||||
* netlink.
|
||||
* Copyright (C) 2018 Cumulus Networks, Inc.
|
||||
*
|
||||
* This file is part of FRR.
|
||||
*
|
||||
* FRR is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* FRR is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with FRR; see the file COPYING. If not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
#ifdef HAVE_NETLINK
|
||||
|
||||
#include "if.h"
|
||||
#include "prefix.h"
|
||||
#include "vrf.h"
|
||||
|
||||
#include <linux/fib_rules.h>
|
||||
#include "zebra/zserv.h"
|
||||
#include "zebra/zebra_ns.h"
|
||||
#include "zebra/zebra_vrf.h"
|
||||
#include "zebra/rt.h"
|
||||
#include "zebra/interface.h"
|
||||
#include "zebra/debug.h"
|
||||
#include "zebra/rtadv.h"
|
||||
#include "zebra/kernel_netlink.h"
|
||||
#include "zebra/rule_netlink.h"
|
||||
#include "zebra/zebra_pbr.h"
|
||||
|
||||
/* definitions */
|
||||
|
||||
/* static function declarations */
|
||||
|
||||
/* Private functions */
|
||||
|
||||
/* Install or uninstall specified rule for a specific interface.
|
||||
* Form netlink message and ship it. Currently, notify status after
|
||||
* waiting for netlink status.
|
||||
*/
|
||||
static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule)
|
||||
{
|
||||
int family;
|
||||
int bytelen;
|
||||
struct {
|
||||
struct nlmsghdr n;
|
||||
struct fib_rule_hdr frh;
|
||||
char buf[NL_PKT_BUF_SIZE];
|
||||
} req;
|
||||
struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
|
||||
struct sockaddr_nl snl;
|
||||
char buf1[PREFIX_STRLEN];
|
||||
char buf2[PREFIX_STRLEN];
|
||||
|
||||
memset(&req, 0, sizeof(req) - NL_PKT_BUF_SIZE);
|
||||
family = PREFIX_FAMILY(&rule->filter.src_ip);
|
||||
bytelen = (family == AF_INET ? 4 : 16);
|
||||
|
||||
req.n.nlmsg_type = cmd;
|
||||
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
||||
req.n.nlmsg_flags = NLM_F_REQUEST;
|
||||
req.n.nlmsg_pid = zns->netlink_cmd.snl.nl_pid;
|
||||
|
||||
req.frh.family = family;
|
||||
req.frh.action = FR_ACT_TO_TBL;
|
||||
|
||||
if (cmd == RTM_NEWRULE)
|
||||
req.n.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
|
||||
|
||||
/* rule's pref # */
|
||||
addattr32(&req.n, sizeof(req), FRA_PRIORITY, rule->priority);
|
||||
|
||||
/* interface on which applied */
|
||||
if (rule->ifp)
|
||||
addattr_l(&req.n, sizeof(req), FRA_IFNAME, rule->ifp->name,
|
||||
strlen(rule->ifp->name) + 1);
|
||||
|
||||
/* source IP, if specified */
|
||||
if (IS_RULE_FILTERING_ON_SRC_IP(rule)) {
|
||||
req.frh.src_len = rule->filter.src_ip.prefixlen;
|
||||
addattr_l(&req.n, sizeof(req), FRA_SRC,
|
||||
&rule->filter.src_ip.u.prefix, bytelen);
|
||||
}
|
||||
/* destination IP, if specified */
|
||||
if (IS_RULE_FILTERING_ON_DST_IP(rule)) {
|
||||
req.frh.dst_len = rule->filter.dst_ip.prefixlen;
|
||||
addattr_l(&req.n, sizeof(req), FRA_DST,
|
||||
&rule->filter.dst_ip.u.prefix, bytelen);
|
||||
}
|
||||
|
||||
/* Route table to use to forward, if filter criteria matches. */
|
||||
if (rule->action.table < 256)
|
||||
req.frh.table = rule->action.table;
|
||||
else {
|
||||
req.frh.table = RT_TABLE_UNSPEC;
|
||||
addattr32(&req.n, sizeof(req), FRA_TABLE,
|
||||
rule->action.table);
|
||||
}
|
||||
|
||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||
zlog_debug(
|
||||
"Tx %s family %s IF %s(%u) Pref %u Src %s Dst %s Table %u",
|
||||
nl_msg_type_to_str(cmd), nl_family_to_str(family),
|
||||
rule->ifp ? rule->ifp->name : "Unknown",
|
||||
rule->ifp ? rule->ifp->ifindex : 0, rule->priority,
|
||||
prefix2str(&rule->filter.src_ip, buf1, sizeof(buf1)),
|
||||
prefix2str(&rule->filter.dst_ip, buf2, sizeof(buf2)),
|
||||
rule->action.table);
|
||||
|
||||
/* Ship off the message.
|
||||
* Note: Currently, netlink_talk() is a blocking call which returns
|
||||
* back the status.
|
||||
*/
|
||||
memset(&snl, 0, sizeof(snl));
|
||||
snl.nl_family = AF_NETLINK;
|
||||
return netlink_talk(netlink_talk_filter, &req.n,
|
||||
&zns->netlink_cmd, zns, 0);
|
||||
}
|
||||
|
||||
|
||||
/* Public functions */
|
||||
/*
|
||||
* Install specified rule for a specific interface. The preference is what
|
||||
* goes in the rule to denote relative ordering; it may or may not be the
|
||||
* same as the rule's user-defined sequence number.
|
||||
*/
|
||||
void kernel_add_pbr_rule(struct zebra_pbr_rule *rule)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = netlink_rule_update(RTM_NEWRULE, rule);
|
||||
kernel_pbr_rule_add_del_status(rule,
|
||||
(!ret) ? SOUTHBOUND_INSTALL_SUCCESS
|
||||
: SOUTHBOUND_INSTALL_FAILURE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Uninstall specified rule for a specific interface.
|
||||
*/
|
||||
void kernel_del_pbr_rule(struct zebra_pbr_rule *rule)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = netlink_rule_update(RTM_DELRULE, rule);
|
||||
kernel_pbr_rule_add_del_status(rule,
|
||||
(!ret) ? SOUTHBOUND_DELETE_SUCCESS
|
||||
: SOUTHBOUND_DELETE_FAILURE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle netlink notification informing a rule add or delete.
|
||||
* Handling of an ADD is TBD.
|
||||
* DELs are notified up, if other attributes indicate it may be a
|
||||
* notification of interest. The expectation is that if this corresponds
|
||||
* to a PBR rule added by FRR, it will be readded.
|
||||
*/
|
||||
int netlink_rule_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
|
||||
ns_id_t ns_id, int startup)
|
||||
{
|
||||
struct zebra_ns *zns;
|
||||
struct fib_rule_hdr *frh;
|
||||
struct rtattr *tb[FRA_MAX + 1];
|
||||
int len;
|
||||
char *ifname;
|
||||
struct zebra_pbr_rule rule;
|
||||
char buf1[PREFIX_STRLEN];
|
||||
char buf2[PREFIX_STRLEN];
|
||||
|
||||
/* Basic validation followed by extracting attributes. */
|
||||
if (h->nlmsg_type != RTM_NEWRULE && h->nlmsg_type != RTM_DELRULE)
|
||||
return 0;
|
||||
|
||||
/* TBD */
|
||||
if (h->nlmsg_type == RTM_NEWRULE)
|
||||
return 0;
|
||||
|
||||
len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct fib_rule_hdr));
|
||||
if (len < 0)
|
||||
return -1;
|
||||
|
||||
frh = NLMSG_DATA(h);
|
||||
if (frh->family != AF_INET && frh->family != AF_INET6)
|
||||
return 0;
|
||||
if (frh->action != FR_ACT_TO_TBL)
|
||||
return 0;
|
||||
|
||||
memset(tb, 0, sizeof(tb));
|
||||
netlink_parse_rtattr(tb, FRA_MAX, RTM_RTA(frh), len);
|
||||
|
||||
/* TBD: We don't care about rules not specifying an IIF. */
|
||||
if (tb[FRA_IFNAME] == NULL)
|
||||
return 0;
|
||||
|
||||
/* If we don't know the interface, we don't care. */
|
||||
ifname = (char *)RTA_DATA(tb[FRA_IFNAME]);
|
||||
zns = zebra_ns_lookup(ns_id);
|
||||
rule.ifp = if_lookup_by_name_per_ns(zns, ifname);
|
||||
if (!rule.ifp)
|
||||
return 0;
|
||||
|
||||
memset(&rule, 0, sizeof(rule));
|
||||
if (tb[FRA_PRIORITY])
|
||||
rule.priority = *(uint32_t *)RTA_DATA(tb[FRA_PRIORITY]);
|
||||
|
||||
if (tb[FRA_SRC]) {
|
||||
if (frh->family == AF_INET)
|
||||
memcpy(&rule.filter.src_ip.u.prefix4,
|
||||
RTA_DATA(tb[FRA_SRC]), 4);
|
||||
else
|
||||
memcpy(&rule.filter.src_ip.u.prefix6,
|
||||
RTA_DATA(tb[FRA_SRC]), 16);
|
||||
rule.filter.src_ip.prefixlen = frh->src_len;
|
||||
rule.filter.filter_bm |= PBR_FILTER_SRC_IP;
|
||||
}
|
||||
|
||||
if (tb[FRA_DST]) {
|
||||
if (frh->family == AF_INET)
|
||||
memcpy(&rule.filter.dst_ip.u.prefix4,
|
||||
RTA_DATA(tb[FRA_DST]), 4);
|
||||
else
|
||||
memcpy(&rule.filter.dst_ip.u.prefix6,
|
||||
RTA_DATA(tb[FRA_DST]), 16);
|
||||
rule.filter.dst_ip.prefixlen = frh->dst_len;
|
||||
rule.filter.filter_bm |= PBR_FILTER_DST_IP;
|
||||
}
|
||||
|
||||
if (tb[FRA_TABLE])
|
||||
rule.action.table = *(uint32_t *)RTA_DATA(tb[FRA_TABLE]);
|
||||
else
|
||||
rule.action.table = frh->table;
|
||||
|
||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||
zlog_debug(
|
||||
"Rx %s family %s IF %s(%u) Pref %u Src %s Dst %s Table %u",
|
||||
nl_msg_type_to_str(h->nlmsg_type),
|
||||
nl_family_to_str(frh->family), rule.ifp->name,
|
||||
rule.ifp->ifindex, rule.priority,
|
||||
prefix2str(&rule.filter.src_ip, buf1, sizeof(buf1)),
|
||||
prefix2str(&rule.filter.dst_ip, buf2, sizeof(buf2)),
|
||||
rule.action.table);
|
||||
|
||||
return kernel_pbr_rule_del(&rule);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get to know existing PBR rules in the kernel - typically called at startup.
|
||||
* TBD.
|
||||
*/
|
||||
int netlink_rules_read(struct zebra_ns *zns)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* HAVE_NETLINK */
|
42
zebra/rule_netlink.h
Normal file
42
zebra/rule_netlink.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Zebra Policy Based Routing (PBR) interaction with the kernel using
|
||||
* netlink - public definitions and function declarations.
|
||||
* Copyright (C) 2018 Cumulus Networks, Inc.
|
||||
*
|
||||
* This file is part of FRR.
|
||||
*
|
||||
* FRR is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* FRR is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with FRR; see the file COPYING. If not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _ZEBRA_RULE_NETLINK_H
|
||||
#define _ZEBRA_RULE_NETLINK_H
|
||||
|
||||
#ifdef HAVE_NETLINK
|
||||
|
||||
/*
|
||||
* Handle netlink notification informing a rule add or delete.
|
||||
*/
|
||||
extern int netlink_rule_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
|
||||
ns_id_t ns_id, int startup);
|
||||
|
||||
/*
|
||||
* Get to know existing PBR rules in the kernel - typically called at startup.
|
||||
*/
|
||||
extern int netlink_rules_read(struct zebra_ns *zns);
|
||||
|
||||
#endif /* HAVE_NETLINK */
|
||||
|
||||
#endif /* _ZEBRA_RULE_NETLINK_H */
|
51
zebra/rule_socket.c
Normal file
51
zebra/rule_socket.c
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Zebra Policy Based Routing (PBR) interaction with the kernel using
|
||||
* netlink.
|
||||
* Copyright (C) 2018 Cumulus Networks, Inc.
|
||||
* Donald Sharp
|
||||
*
|
||||
* This file is part of FRR.
|
||||
*
|
||||
* FRR is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* FRR is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with FRR; see the file COPYING. If not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
#ifndef HAVE_NETLINK
|
||||
|
||||
#include "if.h"
|
||||
#include "prefix.h"
|
||||
#include "vrf.h"
|
||||
|
||||
#include "zebra/zserv.h"
|
||||
#include "zebra/zebra_ns.h"
|
||||
#include "zebra/zebra_vrf.h"
|
||||
#include "zebra/rt.h"
|
||||
#include "zebra/interface.h"
|
||||
#include "zebra/debug.h"
|
||||
#include "zebra/rtadv.h"
|
||||
#include "zebra/kernel_netlink.h"
|
||||
#include "zebra/rule_netlink.h"
|
||||
#include "zebra/zebra_pbr.h"
|
||||
|
||||
void kernel_add_pbr_rule(struct zebra_pbr_rule *rule)
|
||||
{
|
||||
}
|
||||
void kernel_del_pbr_rule(struct zebra_pbr_rule *rule)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
@ -45,6 +45,8 @@ zebra_zebra_SOURCES = \
|
||||
zebra/rtread_getmsg.c \
|
||||
zebra/rtread_netlink.c \
|
||||
zebra/rtread_sysctl.c \
|
||||
zebra/rule_netlink.c \
|
||||
zebra/rule_socket.c \
|
||||
zebra/zebra_l2.c \
|
||||
zebra/zebra_memory.c \
|
||||
zebra/zebra_mpls.c \
|
||||
@ -54,6 +56,7 @@ zebra_zebra_SOURCES = \
|
||||
zebra/zebra_mpls_vty.c \
|
||||
zebra/zebra_mroute.c \
|
||||
zebra/zebra_ns.c \
|
||||
zebra/zebra_pbr.c \
|
||||
zebra/zebra_ptm.c \
|
||||
zebra/zebra_ptm_redistribute.c \
|
||||
zebra/zebra_pw.c \
|
||||
@ -90,12 +93,14 @@ noinst_HEADERS += \
|
||||
zebra/rt.h \
|
||||
zebra/rt_netlink.h \
|
||||
zebra/rtadv.h \
|
||||
zebra/rule_netlink.h \
|
||||
zebra/zebra_fpm_private.h \
|
||||
zebra/zebra_l2.h \
|
||||
zebra/zebra_memory.h \
|
||||
zebra/zebra_mpls.h \
|
||||
zebra/zebra_mroute.h \
|
||||
zebra/zebra_ns.h \
|
||||
zebra/zebra_pbr.h \
|
||||
zebra/zebra_ptm.h \
|
||||
zebra/zebra_ptm_redistribute.h \
|
||||
zebra/zebra_pw.h \
|
||||
|
@ -249,7 +249,7 @@ static int netlink_route_info_fill(netlink_route_info_t *ri, int cmd,
|
||||
ri->rtm_type = RTN_UNICAST;
|
||||
ri->metric = &re->metric;
|
||||
|
||||
for (ALL_NEXTHOPS(re->nexthop, nexthop)) {
|
||||
for (ALL_NEXTHOPS(re->ng, nexthop)) {
|
||||
if (ri->num_nhs >= multipath_num)
|
||||
break;
|
||||
|
||||
|
@ -170,7 +170,7 @@ static Fpm__AddRoute *create_add_route_message(qpb_allocator_t *allocator,
|
||||
* Figure out the set of nexthops to be added to the message.
|
||||
*/
|
||||
num_nhs = 0;
|
||||
for (ALL_NEXTHOPS(re->nexthop, nexthop)) {
|
||||
for (ALL_NEXTHOPS(re->ng, nexthop)) {
|
||||
if (num_nhs >= multipath_num)
|
||||
break;
|
||||
|
||||
|
@ -182,7 +182,7 @@ static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label,
|
||||
* the label advertised by the recursive nexthop (plus we don't have the
|
||||
* logic yet to push multiple labels).
|
||||
*/
|
||||
for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next) {
|
||||
for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) {
|
||||
/* Skip inactive and recursive entries. */
|
||||
if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
|
||||
continue;
|
||||
@ -637,7 +637,7 @@ static int nhlfe_nexthop_active_ipv4(zebra_nhlfe_t *nhlfe,
|
||||
|| !CHECK_FLAG(match->flags, ZEBRA_FLAG_SELECTED))
|
||||
continue;
|
||||
|
||||
for (match_nh = match->nexthop; match_nh;
|
||||
for (match_nh = match->ng.nexthop; match_nh;
|
||||
match_nh = match_nh->next) {
|
||||
if (match->type == ZEBRA_ROUTE_CONNECT
|
||||
|| nexthop->ifindex == match_nh->ifindex) {
|
||||
@ -688,10 +688,10 @@ static int nhlfe_nexthop_active_ipv6(zebra_nhlfe_t *nhlfe,
|
||||
break;
|
||||
}
|
||||
|
||||
if (!match || !match->nexthop)
|
||||
if (!match || !match->ng.nexthop)
|
||||
return 0;
|
||||
|
||||
nexthop->ifindex = match->nexthop->ifindex;
|
||||
nexthop->ifindex = match->ng.nexthop->ifindex;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -2286,7 +2286,7 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type,
|
||||
if (re == NULL)
|
||||
return -1;
|
||||
|
||||
for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next) {
|
||||
for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) {
|
||||
switch (nexthop->type) {
|
||||
case NEXTHOP_TYPE_IPV4:
|
||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||
@ -2504,7 +2504,7 @@ void mpls_ldp_ftn_uninstall_all(struct zebra_vrf *zvrf, int afi)
|
||||
for (rn = route_top(table); rn; rn = route_next(rn)) {
|
||||
update = 0;
|
||||
RNODE_FOREACH_RE (rn, re) {
|
||||
for (nexthop = re->nexthop; nexthop;
|
||||
for (nexthop = re->ng.nexthop; nexthop;
|
||||
nexthop = nexthop->next) {
|
||||
if (nexthop->nh_label_type != ZEBRA_LSP_LDP)
|
||||
continue;
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "debug.h"
|
||||
#include "zebra_netns_notify.h"
|
||||
#include "zebra_netns_id.h"
|
||||
#include "zebra_pbr.h"
|
||||
|
||||
extern struct zebra_privs_t zserv_privs;
|
||||
|
||||
@ -211,12 +212,15 @@ int zebra_ns_disable(ns_id_t ns_id, void **info)
|
||||
struct zebra_ns_table *znst;
|
||||
struct zebra_ns *zns = (struct zebra_ns *)(*info);
|
||||
|
||||
hash_clean(zns->rules_hash, zebra_pbr_rules_free);
|
||||
hash_free(zns->rules_hash);
|
||||
while (!RB_EMPTY(zebra_ns_table_head, &zns->ns_tables)) {
|
||||
znst = RB_ROOT(zebra_ns_table_head, &zns->ns_tables);
|
||||
|
||||
RB_REMOVE(zebra_ns_table_head, &zns->ns_tables, znst);
|
||||
zebra_ns_free_table(znst);
|
||||
}
|
||||
|
||||
route_table_finish(zns->if_table);
|
||||
zebra_vxlan_ns_disable(zns);
|
||||
#if defined(HAVE_RTADV)
|
||||
@ -257,6 +261,9 @@ int zebra_ns_init(void)
|
||||
/* Default NS is activated */
|
||||
zebra_ns_enable(ns_id, (void **)&dzns);
|
||||
|
||||
dzns->rules_hash =
|
||||
hash_create_size(8, zebra_pbr_rules_hash_key,
|
||||
zebra_pbr_rules_hash_equal, "Rules Hash");
|
||||
if (vrf_is_backend_netns()) {
|
||||
ns_add_hook(NS_NEW_HOOK, zebra_ns_new);
|
||||
ns_add_hook(NS_ENABLE_HOOK, zebra_ns_enabled);
|
||||
|
@ -23,6 +23,7 @@
|
||||
#define __ZEBRA_NS_H__
|
||||
|
||||
#include <lib/ns.h>
|
||||
#include <lib/vrf.h>
|
||||
|
||||
#ifdef HAVE_NETLINK
|
||||
/* Socket interface to kernel */
|
||||
@ -70,6 +71,8 @@ struct zebra_ns {
|
||||
|
||||
struct zebra_ns_table_head ns_tables;
|
||||
|
||||
struct hash *rules_hash;
|
||||
|
||||
/* Back pointer */
|
||||
struct ns *ns;
|
||||
};
|
||||
|
162
zebra/zebra_pbr.c
Normal file
162
zebra/zebra_pbr.c
Normal file
@ -0,0 +1,162 @@
|
||||
/* Zebra Policy Based Routing (PBR) main handling.
|
||||
* Copyright (C) 2018 Cumulus Networks, Inc.
|
||||
*
|
||||
* This file is part of FRR.
|
||||
*
|
||||
* FRR is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* FRR is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with FRR; see the file COPYING. If not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
#include <jhash.h>
|
||||
#include <hash.h>
|
||||
|
||||
#include "zebra/zebra_pbr.h"
|
||||
#include "zebra/rt.h"
|
||||
|
||||
/* definitions */
|
||||
|
||||
/* static function declarations */
|
||||
|
||||
/* Private functions */
|
||||
|
||||
/* Public functions */
|
||||
void zebra_pbr_rules_free(void *arg)
|
||||
{
|
||||
struct zebra_pbr_rule *rule;
|
||||
|
||||
rule = (struct zebra_pbr_rule *)arg;
|
||||
|
||||
kernel_del_pbr_rule(rule);
|
||||
XFREE(MTYPE_TMP, rule);
|
||||
}
|
||||
|
||||
uint32_t zebra_pbr_rules_hash_key(void *arg)
|
||||
{
|
||||
struct zebra_pbr_rule *rule;
|
||||
uint32_t key;
|
||||
|
||||
rule = (struct zebra_pbr_rule *)arg;
|
||||
key = jhash_3words(rule->seq, rule->priority, rule->action.table,
|
||||
prefix_hash_key(&rule->filter.src_ip));
|
||||
if (rule->ifp)
|
||||
key = jhash_1word(rule->ifp->ifindex, key);
|
||||
else
|
||||
key = jhash_1word(0, key);
|
||||
|
||||
return jhash_3words(rule->filter.src_port, rule->filter.dst_port,
|
||||
prefix_hash_key(&rule->filter.dst_ip),
|
||||
jhash_1word(rule->unique, key));
|
||||
}
|
||||
|
||||
int zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2)
|
||||
{
|
||||
const struct zebra_pbr_rule *r1, *r2;
|
||||
|
||||
r1 = (const struct zebra_pbr_rule *)arg1;
|
||||
r2 = (const struct zebra_pbr_rule *)arg2;
|
||||
|
||||
if (r1->seq != r2->seq)
|
||||
return 0;
|
||||
|
||||
if (r1->priority != r2->priority)
|
||||
return 0;
|
||||
|
||||
if (r1->unique != r2->unique)
|
||||
return 0;
|
||||
|
||||
if (r1->action.table != r2->action.table)
|
||||
return 0;
|
||||
|
||||
if (r1->filter.src_port != r2->filter.src_port)
|
||||
return 0;
|
||||
|
||||
if (r1->filter.dst_port != r2->filter.dst_port)
|
||||
return 0;
|
||||
|
||||
if (!prefix_same(&r1->filter.src_ip, &r2->filter.src_ip))
|
||||
return 0;
|
||||
|
||||
if (!prefix_same(&r1->filter.dst_ip, &r2->filter.dst_ip))
|
||||
return 0;
|
||||
|
||||
if (r1->ifp != r2->ifp)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void *pbr_rule_alloc_intern(void *arg)
|
||||
{
|
||||
struct zebra_pbr_rule *zpr;
|
||||
struct zebra_pbr_rule *new;
|
||||
|
||||
zpr = (struct zebra_pbr_rule *)arg;
|
||||
|
||||
new = XCALLOC(MTYPE_TMP, sizeof(*new));
|
||||
|
||||
memcpy(new, zpr, sizeof(*zpr));
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
void zebra_pbr_add_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule)
|
||||
{
|
||||
(void)hash_get(zns->rules_hash, rule, pbr_rule_alloc_intern);
|
||||
kernel_add_pbr_rule(rule);
|
||||
}
|
||||
|
||||
void zebra_pbr_del_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule)
|
||||
{
|
||||
struct zebra_pbr_rule *lookup;
|
||||
|
||||
lookup = hash_lookup(zns->rules_hash, rule);
|
||||
kernel_del_pbr_rule(rule);
|
||||
|
||||
if (lookup)
|
||||
XFREE(MTYPE_TMP, lookup);
|
||||
else
|
||||
zlog_warn("%s: Rule being deleted we know nothing about",
|
||||
__PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle success or failure of rule (un)install in the kernel.
|
||||
*/
|
||||
void kernel_pbr_rule_add_del_status(struct zebra_pbr_rule *rule,
|
||||
enum southbound_results res)
|
||||
{
|
||||
switch (res) {
|
||||
case SOUTHBOUND_INSTALL_SUCCESS:
|
||||
zsend_rule_notify_owner(rule, ZAPI_RULE_INSTALLED);
|
||||
break;
|
||||
case SOUTHBOUND_INSTALL_FAILURE:
|
||||
zsend_rule_notify_owner(rule, ZAPI_RULE_FAIL_INSTALL);
|
||||
break;
|
||||
case SOUTHBOUND_DELETE_SUCCESS:
|
||||
break;
|
||||
case SOUTHBOUND_DELETE_FAILURE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle rule delete notification from kernel.
|
||||
*/
|
||||
int kernel_pbr_rule_del(struct zebra_pbr_rule *rule)
|
||||
{
|
||||
return 0;
|
||||
}
|
138
zebra/zebra_pbr.h
Normal file
138
zebra/zebra_pbr.h
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Zebra Policy Based Routing (PBR) Data structures and definitions
|
||||
* These are public definitions referenced by multiple files.
|
||||
* Copyright (C) 2018 Cumulus Networks, Inc.
|
||||
*
|
||||
* This file is part of FRR.
|
||||
*
|
||||
* FRR is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* FRR is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with FRR; see the file COPYING. If not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _ZEBRA_PBR_H
|
||||
#define _ZEBRA_PBR_H
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
#include "prefix.h"
|
||||
#include "if.h"
|
||||
|
||||
#include "rt.h"
|
||||
|
||||
/*
|
||||
* A PBR filter
|
||||
*
|
||||
* The filter or match criteria in a PBR rule.
|
||||
* For simplicity, all supported filters are grouped into a structure rather
|
||||
* than delineating further. A bitmask denotes which filters are actually
|
||||
* specified.
|
||||
*/
|
||||
struct zebra_pbr_filter {
|
||||
uint32_t filter_bm;
|
||||
#define PBR_FILTER_SRC_IP (1 << 0)
|
||||
#define PBR_FILTER_DST_IP (1 << 1)
|
||||
#define PBR_FILTER_SRC_PORT (1 << 2)
|
||||
#define PBR_FILTER_DST_PORT (1 << 3)
|
||||
|
||||
/* Source and Destination IP address with masks. */
|
||||
struct prefix src_ip;
|
||||
struct prefix dst_ip;
|
||||
|
||||
/* Source and Destination higher-layer (TCP/UDP) port numbers. */
|
||||
uint16_t src_port;
|
||||
uint16_t dst_port;
|
||||
};
|
||||
|
||||
#define IS_RULE_FILTERING_ON_SRC_IP(r) \
|
||||
(r->filter.filter_bm & PBR_FILTER_SRC_IP)
|
||||
#define IS_RULE_FILTERING_ON_DST_IP(r) \
|
||||
(r->filter.filter_bm & PBR_FILTER_DST_IP)
|
||||
#define IS_RULE_FILTERING_ON_SRC_PORT(r) \
|
||||
(r->filter.filter_bm & PBR_FILTER_SRC_PORT)
|
||||
#define IS_RULE_FILTERING_ON_DST_PORT(r) \
|
||||
(r->filter.filter_bm & PBR_FILTER_DST_PORT)
|
||||
|
||||
/*
|
||||
* A PBR action
|
||||
*
|
||||
* The action corresponding to a PBR rule.
|
||||
* While the user specifies the action in a particular way, the forwarding
|
||||
* plane implementation (Linux only) requires that to be encoded into a
|
||||
* route table and the rule then point to that route table; in some cases,
|
||||
* the user criteria may directly point to a table too.
|
||||
*/
|
||||
struct zebra_pbr_action {
|
||||
uint32_t table;
|
||||
};
|
||||
|
||||
/*
|
||||
* A PBR rule
|
||||
*
|
||||
* This is a combination of the filter criteria and corresponding action.
|
||||
* Rules also have a user-defined sequence number which defines the relative
|
||||
* order amongst rules.
|
||||
*/
|
||||
struct zebra_pbr_rule {
|
||||
/*
|
||||
* Originating zclient sock fd, so we can know who to send
|
||||
* back to.
|
||||
*/
|
||||
int sock;
|
||||
|
||||
uint32_t seq;
|
||||
uint32_t priority;
|
||||
struct interface *ifp;
|
||||
uint32_t unique;
|
||||
struct zebra_pbr_filter filter;
|
||||
struct zebra_pbr_action action;
|
||||
};
|
||||
|
||||
void zebra_pbr_add_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule);
|
||||
void zebra_pbr_del_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule);
|
||||
|
||||
/*
|
||||
* Install specified rule for a specific interface.
|
||||
* It is possible that the user-defined sequence number and the one in the
|
||||
* forwarding plane may not coincide, hence the API requires a separate
|
||||
* rule priority - maps to preference/FRA_PRIORITY on Linux.
|
||||
*/
|
||||
extern void kernel_add_pbr_rule(struct zebra_pbr_rule *rule);
|
||||
|
||||
/*
|
||||
* Uninstall specified rule for a specific interface.
|
||||
*/
|
||||
extern void kernel_del_pbr_rule(struct zebra_pbr_rule *rule);
|
||||
|
||||
/*
|
||||
* Get to know existing PBR rules in the kernel - typically called at startup.
|
||||
*/
|
||||
extern void kernel_read_pbr_rules(struct zebra_ns *zns);
|
||||
|
||||
enum southbound_results;
|
||||
/*
|
||||
* Handle success or failure of rule (un)install in the kernel.
|
||||
*/
|
||||
extern void kernel_pbr_rule_add_del_status(struct zebra_pbr_rule *rule,
|
||||
enum southbound_results res);
|
||||
|
||||
/*
|
||||
* Handle rule delete notification from kernel.
|
||||
*/
|
||||
extern int kernel_pbr_rule_del(struct zebra_pbr_rule *rule);
|
||||
|
||||
extern void zebra_pbr_rules_free(void *arg);
|
||||
extern uint32_t zebra_pbr_rules_hash_key(void *arg);
|
||||
extern int zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2);
|
||||
#endif /* _ZEBRA_PBR_H */
|
@ -256,7 +256,7 @@ static int zebra_pw_check_reachability(struct zebra_pw *pw)
|
||||
* Need to ensure that there's a label binding for all nexthops.
|
||||
* Otherwise, ECMP for this route could render the pseudowire unusable.
|
||||
*/
|
||||
for (ALL_NEXTHOPS(re->nexthop, nexthop)) {
|
||||
for (ALL_NEXTHOPS(re->ng, nexthop)) {
|
||||
if (!nexthop->nh_label) {
|
||||
if (IS_ZEBRA_DEBUG_PW)
|
||||
zlog_warn("%s: unlabeled route for %s",
|
||||
|
@ -183,7 +183,7 @@ int zebra_check_addr(struct prefix *p)
|
||||
/* Add nexthop to the end of a rib node's nexthop list */
|
||||
void route_entry_nexthop_add(struct route_entry *re, struct nexthop *nexthop)
|
||||
{
|
||||
nexthop_add(&re->nexthop, nexthop);
|
||||
nexthop_add(&re->ng.nexthop, nexthop);
|
||||
re->nexthop_num++;
|
||||
}
|
||||
|
||||
@ -193,8 +193,8 @@ void route_entry_nexthop_add(struct route_entry *re, struct nexthop *nexthop)
|
||||
*/
|
||||
void route_entry_copy_nexthops(struct route_entry *re, struct nexthop *nh)
|
||||
{
|
||||
assert(!re->nexthop);
|
||||
copy_nexthops(&re->nexthop, nh, NULL);
|
||||
assert(!re->ng.nexthop);
|
||||
copy_nexthops(&re->ng.nexthop, nh, NULL);
|
||||
for (struct nexthop *nexthop = nh; nexthop; nexthop = nexthop->next)
|
||||
re->nexthop_num++;
|
||||
}
|
||||
@ -207,7 +207,7 @@ void route_entry_nexthop_delete(struct route_entry *re, struct nexthop *nexthop)
|
||||
if (nexthop->prev)
|
||||
nexthop->prev->next = nexthop->next;
|
||||
else
|
||||
re->nexthop = nexthop->next;
|
||||
re->ng.nexthop = nexthop->next;
|
||||
re->nexthop_num--;
|
||||
}
|
||||
|
||||
@ -507,7 +507,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
|
||||
|
||||
if (match->type == ZEBRA_ROUTE_CONNECT) {
|
||||
/* Directly point connected route. */
|
||||
newhop = match->nexthop;
|
||||
newhop = match->ng.nexthop;
|
||||
if (newhop) {
|
||||
if (nexthop->type == NEXTHOP_TYPE_IPV4
|
||||
|| nexthop->type == NEXTHOP_TYPE_IPV6)
|
||||
@ -516,7 +516,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
|
||||
return 1;
|
||||
} else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
|
||||
resolved = 0;
|
||||
for (ALL_NEXTHOPS(match->nexthop, newhop)) {
|
||||
for (ALL_NEXTHOPS(match->ng, newhop)) {
|
||||
if (!CHECK_FLAG(newhop->flags,
|
||||
NEXTHOP_FLAG_FIB))
|
||||
continue;
|
||||
@ -539,7 +539,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
|
||||
return resolved;
|
||||
} else if (re->type == ZEBRA_ROUTE_STATIC) {
|
||||
resolved = 0;
|
||||
for (ALL_NEXTHOPS(match->nexthop, newhop)) {
|
||||
for (ALL_NEXTHOPS(match->ng, newhop)) {
|
||||
if (!CHECK_FLAG(newhop->flags,
|
||||
NEXTHOP_FLAG_FIB))
|
||||
continue;
|
||||
@ -610,7 +610,7 @@ struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id,
|
||||
} else {
|
||||
if (match->type != ZEBRA_ROUTE_CONNECT) {
|
||||
int found = 0;
|
||||
for (ALL_NEXTHOPS(match->nexthop, newhop))
|
||||
for (ALL_NEXTHOPS(match->ng, newhop))
|
||||
if (CHECK_FLAG(newhop->flags,
|
||||
NEXTHOP_FLAG_FIB)) {
|
||||
found = 1;
|
||||
@ -733,7 +733,7 @@ struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, vrf_id_t vrf_id)
|
||||
if (match->type == ZEBRA_ROUTE_CONNECT)
|
||||
return match;
|
||||
|
||||
for (ALL_NEXTHOPS(match->nexthop, nexthop))
|
||||
for (ALL_NEXTHOPS(match->ng, nexthop))
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
|
||||
return match;
|
||||
|
||||
@ -793,7 +793,7 @@ int rib_lookup_ipv4_route(struct prefix_ipv4 *p, union sockunion *qgate,
|
||||
|
||||
/* Ok, we have a cood candidate, let's check it's nexthop list... */
|
||||
nexthops_active = 0;
|
||||
for (ALL_NEXTHOPS(match->nexthop, nexthop))
|
||||
for (ALL_NEXTHOPS(match->ng, nexthop))
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) {
|
||||
nexthops_active = 1;
|
||||
if (nexthop->gate.ipv4.s_addr == sockunion2ip(qgate))
|
||||
@ -959,7 +959,7 @@ static int nexthop_active_update(struct route_node *rn, struct route_entry *re,
|
||||
re->nexthop_active_num = 0;
|
||||
UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
|
||||
|
||||
for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next) {
|
||||
for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) {
|
||||
/* No protocol daemon provides src and so we're skipping
|
||||
* tracking it */
|
||||
prev_src = nexthop->rmap_src;
|
||||
@ -1003,7 +1003,7 @@ int zebra_rib_labeled_unicast(struct route_entry *re)
|
||||
if (re->type != ZEBRA_ROUTE_BGP)
|
||||
return 0;
|
||||
|
||||
for (ALL_NEXTHOPS(re->nexthop, nexthop))
|
||||
for (ALL_NEXTHOPS(re->ng, nexthop))
|
||||
if (!nexthop->nh_label || !nexthop->nh_label->num_labels)
|
||||
return 0;
|
||||
|
||||
@ -1023,7 +1023,7 @@ void kernel_route_rib_pass_fail(struct route_node *rn, struct prefix *p,
|
||||
switch (res) {
|
||||
case SOUTHBOUND_INSTALL_SUCCESS:
|
||||
dest->selected_fib = re;
|
||||
for (ALL_NEXTHOPS(re->nexthop, nexthop)) {
|
||||
for (ALL_NEXTHOPS(re->ng, nexthop)) {
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||
continue;
|
||||
|
||||
@ -1056,7 +1056,7 @@ void kernel_route_rib_pass_fail(struct route_node *rn, struct prefix *p,
|
||||
*/
|
||||
if (dest->selected_fib == re)
|
||||
dest->selected_fib = NULL;
|
||||
for (ALL_NEXTHOPS(re->nexthop, nexthop))
|
||||
for (ALL_NEXTHOPS(re->ng, nexthop))
|
||||
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
|
||||
|
||||
zsend_route_notify_owner(re, p, ZAPI_ROUTE_REMOVED);
|
||||
@ -1089,15 +1089,15 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re,
|
||||
srcdest_rnode_prefixes(rn, &p, &src_p);
|
||||
|
||||
if (info->safi != SAFI_UNICAST) {
|
||||
for (ALL_NEXTHOPS(re->nexthop, nexthop))
|
||||
for (ALL_NEXTHOPS(re->ng, nexthop))
|
||||
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
|
||||
return;
|
||||
} else {
|
||||
struct nexthop *prev;
|
||||
|
||||
for (ALL_NEXTHOPS(re->nexthop, nexthop)) {
|
||||
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE);
|
||||
for (ALL_NEXTHOPS(re->nexthop, prev)) {
|
||||
for (ALL_NEXTHOPS(re->ng, nexthop)) {
|
||||
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_DUPLICATE);
|
||||
for (ALL_NEXTHOPS(re->ng, prev)) {
|
||||
if (prev == nexthop)
|
||||
break;
|
||||
if (nexthop_same_firsthop(nexthop, prev)) {
|
||||
@ -1138,7 +1138,7 @@ void rib_uninstall_kernel(struct route_node *rn, struct route_entry *re)
|
||||
srcdest_rnode_prefixes(rn, &p, &src_p);
|
||||
|
||||
if (info->safi != SAFI_UNICAST) {
|
||||
for (ALL_NEXTHOPS(re->nexthop, nexthop))
|
||||
for (ALL_NEXTHOPS(re->ng, nexthop))
|
||||
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
|
||||
return;
|
||||
}
|
||||
@ -1388,7 +1388,7 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf,
|
||||
if (!RIB_SYSTEM_ROUTE(old))
|
||||
rib_uninstall_kernel(rn, old);
|
||||
} else {
|
||||
for (nexthop = old->nexthop; nexthop;
|
||||
for (nexthop = old->ng.nexthop; nexthop;
|
||||
nexthop = nexthop->next)
|
||||
UNSET_FLAG(nexthop->flags,
|
||||
NEXTHOP_FLAG_FIB);
|
||||
@ -1444,7 +1444,7 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf,
|
||||
if (!RIB_SYSTEM_ROUTE(new)) {
|
||||
bool in_fib = false;
|
||||
|
||||
for (ALL_NEXTHOPS(new->nexthop, nexthop))
|
||||
for (ALL_NEXTHOPS(new->ng, nexthop))
|
||||
if (CHECK_FLAG(nexthop->flags,
|
||||
NEXTHOP_FLAG_FIB)) {
|
||||
in_fib = true;
|
||||
@ -1676,13 +1676,16 @@ static void rib_process(struct route_node *rn)
|
||||
|
||||
/* Redistribute SELECTED entry */
|
||||
if (old_selected != new_selected || selected_changed) {
|
||||
struct nexthop *nexthop;
|
||||
struct nexthop *nexthop = NULL;
|
||||
|
||||
/* Check if we have a FIB route for the destination, otherwise,
|
||||
* don't redistribute it */
|
||||
for (ALL_NEXTHOPS(new_fib ? new_fib->nexthop : NULL, nexthop)) {
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) {
|
||||
break;
|
||||
if (new_fib) {
|
||||
for (ALL_NEXTHOPS(new_fib->ng, nexthop)) {
|
||||
if (CHECK_FLAG(nexthop->flags,
|
||||
NEXTHOP_FLAG_FIB)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!nexthop)
|
||||
@ -2116,9 +2119,9 @@ void rib_unlink(struct route_node *rn, struct route_entry *re)
|
||||
|
||||
/* free RE and nexthops */
|
||||
if (re->type == ZEBRA_ROUTE_STATIC)
|
||||
zebra_deregister_rnh_static_nexthops(re->vrf_id, re->nexthop,
|
||||
zebra_deregister_rnh_static_nexthops(re->vrf_id, re->ng.nexthop,
|
||||
rn);
|
||||
nexthops_free(re->nexthop);
|
||||
nexthops_free(re->ng.nexthop);
|
||||
XFREE(MTYPE_RE, re);
|
||||
}
|
||||
|
||||
@ -2182,7 +2185,7 @@ void _route_entry_dump(const char *func, union prefixconstptr pp,
|
||||
zlog_debug("%s: nexthop_num == %u, nexthop_active_num == %u", func,
|
||||
re->nexthop_num, re->nexthop_active_num);
|
||||
|
||||
for (ALL_NEXTHOPS(re->nexthop, nexthop)) {
|
||||
for (ALL_NEXTHOPS(re->ng, nexthop)) {
|
||||
inet_ntop(p->family, &nexthop->gate, straddr, INET6_ADDRSTRLEN);
|
||||
zlog_debug("%s: %s %s[%u] with flags %s%s%s", func,
|
||||
(nexthop->rparent ? " NH" : "NH"), straddr,
|
||||
@ -2357,7 +2360,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
|
||||
|
||||
/* If this route is kernel route, set FIB flag to the route. */
|
||||
if (RIB_SYSTEM_ROUTE(re))
|
||||
for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next)
|
||||
for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next)
|
||||
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
|
||||
|
||||
/* Link new re to node.*/
|
||||
@ -2443,7 +2446,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
|
||||
continue;
|
||||
if (re->type == ZEBRA_ROUTE_KERNEL && re->metric != metric)
|
||||
continue;
|
||||
if (re->type == ZEBRA_ROUTE_CONNECT && (rtnh = re->nexthop)
|
||||
if (re->type == ZEBRA_ROUTE_CONNECT && (rtnh = re->ng.nexthop)
|
||||
&& rtnh->type == NEXTHOP_TYPE_IFINDEX && nh) {
|
||||
if (rtnh->ifindex != nh->ifindex)
|
||||
continue;
|
||||
@ -2456,7 +2459,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
|
||||
same = re;
|
||||
break;
|
||||
}
|
||||
for (ALL_NEXTHOPS(re->nexthop, rtnh))
|
||||
for (ALL_NEXTHOPS(re->ng, rtnh))
|
||||
if (nexthop_same_no_recurse(rtnh, nh)) {
|
||||
same = re;
|
||||
break;
|
||||
@ -2493,7 +2496,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
|
||||
}
|
||||
if (allow_delete) {
|
||||
/* Unset flags. */
|
||||
for (rtnh = fib->nexthop; rtnh;
|
||||
for (rtnh = fib->ng.nexthop; rtnh;
|
||||
rtnh = rtnh->next)
|
||||
UNSET_FLAG(rtnh->flags,
|
||||
NEXTHOP_FLAG_FIB);
|
||||
@ -2547,7 +2550,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
|
||||
if (CHECK_FLAG(flags, ZEBRA_FLAG_EVPN_ROUTE)) {
|
||||
struct nexthop *tmp_nh;
|
||||
|
||||
for (ALL_NEXTHOPS(re->nexthop, tmp_nh)) {
|
||||
for (ALL_NEXTHOPS(re->ng, tmp_nh)) {
|
||||
struct ipaddr vtep_ip;
|
||||
|
||||
memset(&vtep_ip, 0, sizeof(struct ipaddr));
|
||||
@ -2642,7 +2645,7 @@ static void rib_update_table(struct route_table *table,
|
||||
continue;
|
||||
}
|
||||
|
||||
for (nh = re->nexthop; nh; nh = nh->next)
|
||||
for (nh = re->ng.nexthop; nh; nh = nh->next)
|
||||
if (!(nh->type == NEXTHOP_TYPE_IPV4
|
||||
|| nh->type == NEXTHOP_TYPE_IPV6))
|
||||
break;
|
||||
@ -2759,7 +2762,7 @@ static void rib_sweep_table(struct route_table *table)
|
||||
* to a different spot (ie startup )
|
||||
* this decision needs to be revisited
|
||||
*/
|
||||
for (ALL_NEXTHOPS(re->nexthop, nexthop))
|
||||
for (ALL_NEXTHOPS(re->ng, nexthop))
|
||||
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
|
||||
|
||||
rib_uninstall_kernel(rn, re);
|
||||
|
@ -355,7 +355,8 @@ static int zebra_rnh_apply_nht_rmap(int family, struct route_node *prn,
|
||||
rmap_family = (family == AF_INET) ? AFI_IP : AFI_IP6;
|
||||
|
||||
if (prn && re) {
|
||||
for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next) {
|
||||
for (nexthop = re->ng.nexthop; nexthop;
|
||||
nexthop = nexthop->next) {
|
||||
ret = zebra_nht_route_map_check(rmap_family, proto,
|
||||
&prn->p, re, nexthop);
|
||||
if (ret != RMAP_DENYMATCH) {
|
||||
@ -428,7 +429,7 @@ static void zebra_rnh_eval_import_check_entry(vrf_id_t vrfid, int family,
|
||||
struct nexthop *nexthop;
|
||||
|
||||
if (re && (rnh->state == NULL)) {
|
||||
for (ALL_NEXTHOPS(re->nexthop, nexthop))
|
||||
for (ALL_NEXTHOPS(re->ng, nexthop))
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) {
|
||||
state_changed = 1;
|
||||
break;
|
||||
@ -559,7 +560,7 @@ static void zebra_rnh_process_static_routes(vrf_id_t vrfid, int family,
|
||||
* be having multiple. We care here only about
|
||||
* registered nexthops.
|
||||
*/
|
||||
for (nexthop = sre->nexthop; nexthop;
|
||||
for (nexthop = sre->ng.nexthop; nexthop;
|
||||
nexthop = nexthop->next) {
|
||||
switch (nexthop->type) {
|
||||
case NEXTHOP_TYPE_IPV4:
|
||||
@ -673,7 +674,7 @@ zebra_rnh_resolve_nexthop_entry(vrf_id_t vrfid, int family,
|
||||
if (re->type == ZEBRA_ROUTE_NHRP) {
|
||||
struct nexthop *nexthop;
|
||||
|
||||
for (nexthop = re->nexthop; nexthop;
|
||||
for (nexthop = re->ng.nexthop; nexthop;
|
||||
nexthop = nexthop->next)
|
||||
if (nexthop->type
|
||||
== NEXTHOP_TYPE_IFINDEX)
|
||||
@ -925,8 +926,8 @@ static void free_state(vrf_id_t vrf_id, struct route_entry *re,
|
||||
return;
|
||||
|
||||
/* free RE and nexthops */
|
||||
zebra_deregister_rnh_static_nexthops(vrf_id, re->nexthop, rn);
|
||||
nexthops_free(re->nexthop);
|
||||
zebra_deregister_rnh_static_nexthops(vrf_id, re->ng.nexthop, rn);
|
||||
nexthops_free(re->ng.nexthop);
|
||||
XFREE(MTYPE_RE, re);
|
||||
}
|
||||
|
||||
@ -949,7 +950,7 @@ static void copy_state(struct rnh *rnh, struct route_entry *re,
|
||||
state->metric = re->metric;
|
||||
state->vrf_id = re->vrf_id;
|
||||
|
||||
route_entry_copy_nexthops(state, re->nexthop);
|
||||
route_entry_copy_nexthops(state, re->ng.nexthop);
|
||||
rnh->state = state;
|
||||
}
|
||||
|
||||
@ -1022,7 +1023,7 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type,
|
||||
num = 0;
|
||||
nump = stream_get_endp(s);
|
||||
stream_putc(s, 0);
|
||||
for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next)
|
||||
for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next)
|
||||
if ((CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)
|
||||
|| CHECK_FLAG(nexthop->flags,
|
||||
NEXTHOP_FLAG_RECURSIVE))
|
||||
@ -1115,7 +1116,7 @@ static void print_rnh(struct route_node *rn, struct vty *vty)
|
||||
if (rnh->state) {
|
||||
vty_out(vty, " resolved via %s\n",
|
||||
zebra_route_string(rnh->state->type));
|
||||
for (nexthop = rnh->state->nexthop; nexthop;
|
||||
for (nexthop = rnh->state->ng.nexthop; nexthop;
|
||||
nexthop = nexthop->next)
|
||||
print_nh(nexthop, vty);
|
||||
} else
|
||||
|
@ -285,8 +285,8 @@ static void check_replace(struct route_node *np2, struct route_entry *re2,
|
||||
return;
|
||||
}
|
||||
|
||||
if (in_addr_cmp((u_char *)&(*re)->nexthop->gate.ipv4,
|
||||
(u_char *)&re2->nexthop->gate.ipv4)
|
||||
if (in_addr_cmp((u_char *)&(*re)->ng.nexthop->gate.ipv4,
|
||||
(u_char *)&re2->ng.nexthop->gate.ipv4)
|
||||
<= 0)
|
||||
return;
|
||||
|
||||
@ -370,9 +370,9 @@ static void get_fwtable_route_node(struct variable *v, oid objid[],
|
||||
for (*np = route_top(table); *np; *np = route_next(*np)) {
|
||||
if (!in_addr_cmp(&(*np)->p.u.prefix, (u_char *)&dest)) {
|
||||
RNODE_FOREACH_RE (*np, *re) {
|
||||
if (!in_addr_cmp((u_char *)&(*re)
|
||||
->nexthop->gate
|
||||
.ipv4,
|
||||
if (!in_addr_cmp(
|
||||
(u_char *)&(*re)
|
||||
->ng.nexthop->gate.ipv4,
|
||||
(u_char *)&nexthop))
|
||||
if (proto
|
||||
== proto_trans((*re)->type))
|
||||
@ -404,9 +404,10 @@ static void get_fwtable_route_node(struct variable *v, oid objid[],
|
||||
if ((policy < policy2)
|
||||
|| ((policy == policy2) && (proto < proto2))
|
||||
|| ((policy == policy2) && (proto == proto2)
|
||||
&& (in_addr_cmp((u_char *)&re2->nexthop
|
||||
->gate.ipv4,
|
||||
(u_char *)&nexthop)
|
||||
&& (in_addr_cmp(
|
||||
(u_char *)&re2->ng.nexthop
|
||||
->gate.ipv4,
|
||||
(u_char *)&nexthop)
|
||||
>= 0)))
|
||||
check_replace(np2, re2, np, re);
|
||||
}
|
||||
@ -430,7 +431,7 @@ static void get_fwtable_route_node(struct variable *v, oid objid[],
|
||||
{
|
||||
struct nexthop *nexthop;
|
||||
|
||||
nexthop = (*re)->nexthop;
|
||||
nexthop = (*re)->ng.nexthop;
|
||||
if (nexthop) {
|
||||
pnt = (u_char *)&nexthop->gate.ipv4;
|
||||
for (i = 0; i < 4; i++)
|
||||
@ -459,7 +460,7 @@ static u_char *ipFwTable(struct variable *v, oid objid[], size_t *objid_len,
|
||||
if (!np)
|
||||
return NULL;
|
||||
|
||||
nexthop = re->nexthop;
|
||||
nexthop = re->ng.nexthop;
|
||||
if (!nexthop)
|
||||
return NULL;
|
||||
|
||||
|
@ -300,7 +300,7 @@ void static_uninstall_route(afi_t afi, safi_t safi, struct prefix *p,
|
||||
}
|
||||
|
||||
/* Lookup nexthop. */
|
||||
for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next)
|
||||
for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next)
|
||||
if (static_nexthop_same(nexthop, si))
|
||||
break;
|
||||
|
||||
|
@ -743,7 +743,7 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
|
||||
tm->tm_hour);
|
||||
vty_out(vty, " ago\n");
|
||||
|
||||
for (ALL_NEXTHOPS(re->nexthop, nexthop)) {
|
||||
for (ALL_NEXTHOPS(re->ng, nexthop)) {
|
||||
char addrstr[32];
|
||||
|
||||
vty_out(vty, " %c%s",
|
||||
@ -922,7 +922,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
|
||||
|
||||
json_object_string_add(json_route, "uptime", buf);
|
||||
|
||||
for (ALL_NEXTHOPS(re->nexthop, nexthop)) {
|
||||
for (ALL_NEXTHOPS(re->ng, nexthop)) {
|
||||
json_nexthop = json_object_new_object();
|
||||
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE))
|
||||
@ -1088,8 +1088,8 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
|
||||
}
|
||||
|
||||
/* Nexthop information. */
|
||||
for (ALL_NEXTHOPS(re->nexthop, nexthop)) {
|
||||
if (nexthop == re->nexthop) {
|
||||
for (ALL_NEXTHOPS(re->ng, nexthop)) {
|
||||
if (nexthop == re->ng.nexthop) {
|
||||
/* Prefix information. */
|
||||
len = vty_out(vty, "%c", zebra_route_char(re->type));
|
||||
if (re->instance)
|
||||
@ -1842,7 +1842,7 @@ static void vty_show_ip_route_summary_prefix(struct vty *vty,
|
||||
* In case of ECMP, count only once.
|
||||
*/
|
||||
cnt = 0;
|
||||
for (nexthop = re->nexthop; (!cnt && nexthop);
|
||||
for (nexthop = re->ng.nexthop; (!cnt && nexthop);
|
||||
nexthop = nexthop->next) {
|
||||
cnt++;
|
||||
rib_cnt[ZEBRA_ROUTE_TOTAL]++;
|
||||
|
129
zebra/zserv.c
129
zebra/zserv.c
@ -60,6 +60,7 @@
|
||||
#include "zebra/label_manager.h"
|
||||
#include "zebra/zebra_vxlan.h"
|
||||
#include "zebra/rt.h"
|
||||
#include "zebra/zebra_pbr.h"
|
||||
|
||||
/* Event list of zebra. */
|
||||
enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE };
|
||||
@ -616,7 +617,7 @@ int zsend_redistribute_route(int cmd, struct zserv *client, struct prefix *p,
|
||||
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
|
||||
api.nexthop_num = re->nexthop_active_num;
|
||||
}
|
||||
for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next) {
|
||||
for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) {
|
||||
if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
|
||||
continue;
|
||||
|
||||
@ -978,7 +979,7 @@ static int zsend_ipv4_nexthop_lookup_mrib(struct zserv *client,
|
||||
* we
|
||||
* are looking up. Therefore, we will just iterate over the top
|
||||
* chain of nexthops. */
|
||||
for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next)
|
||||
for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next)
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
|
||||
num += zsend_write_nexthop(s, nexthop);
|
||||
|
||||
@ -1042,6 +1043,44 @@ int zsend_route_notify_owner(struct route_entry *re, struct prefix *p,
|
||||
return zebra_server_send_message(client);
|
||||
}
|
||||
|
||||
void zsend_rule_notify_owner(struct zebra_pbr_rule *rule,
|
||||
enum zapi_rule_notify_owner note)
|
||||
{
|
||||
struct listnode *node;
|
||||
struct zserv *client;
|
||||
struct stream *s;
|
||||
|
||||
if (IS_ZEBRA_DEBUG_PACKET) {
|
||||
zlog_debug("%s: Notifying %u",
|
||||
__PRETTY_FUNCTION__, rule->unique);
|
||||
}
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) {
|
||||
if (rule->sock == client->sock)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!client)
|
||||
return;
|
||||
|
||||
s = client->obuf;
|
||||
stream_reset(s);
|
||||
|
||||
zclient_create_header(s, ZEBRA_RULE_NOTIFY_OWNER, VRF_DEFAULT);
|
||||
stream_put(s, ¬e, sizeof(note));
|
||||
stream_putl(s, rule->seq);
|
||||
stream_putl(s, rule->priority);
|
||||
stream_putl(s, rule->unique);
|
||||
if (rule->ifp)
|
||||
stream_putl(s, rule->ifp->ifindex);
|
||||
else
|
||||
stream_putl(s, 0);
|
||||
|
||||
stream_putw_at(s, 0, stream_get_endp(s));
|
||||
|
||||
zebra_server_send_message(client);
|
||||
}
|
||||
|
||||
/* Router-id is updated. Send ZEBRA_ROUTER_ID_ADD to client. */
|
||||
int zsend_router_id_update(struct zserv *client, struct prefix *p,
|
||||
vrf_id_t vrf_id)
|
||||
@ -1164,7 +1203,10 @@ static int zread_route_add(struct zserv *client, u_short length,
|
||||
re->flags = api.flags;
|
||||
re->uptime = time(NULL);
|
||||
re->vrf_id = vrf_id;
|
||||
re->table = zvrf->table_id;
|
||||
if (api.tableid && vrf_id == VRF_DEFAULT)
|
||||
re->table = api.tableid;
|
||||
else
|
||||
re->table = zvrf->table_id;
|
||||
|
||||
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
|
||||
for (i = 0; i < api.nexthop_num; i++) {
|
||||
@ -1233,7 +1275,7 @@ static int zread_route_add(struct zserv *client, u_short length,
|
||||
zlog_warn(
|
||||
"%s: Nexthops Specified: %d but we failed to properly create one",
|
||||
__PRETTY_FUNCTION__, api.nexthop_num);
|
||||
nexthops_free(re->nexthop);
|
||||
nexthops_free(re->ng.nexthop);
|
||||
XFREE(MTYPE_RE, re);
|
||||
return -1;
|
||||
}
|
||||
@ -1265,7 +1307,7 @@ static int zread_route_add(struct zserv *client, u_short length,
|
||||
if (afi != AFI_IP6 && CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) {
|
||||
zlog_warn("%s: Received SRC Prefix but afi is not v6",
|
||||
__PRETTY_FUNCTION__);
|
||||
nexthops_free(re->nexthop);
|
||||
nexthops_free(re->ng.nexthop);
|
||||
XFREE(MTYPE_RE, re);
|
||||
return -1;
|
||||
}
|
||||
@ -1434,7 +1476,7 @@ static int zread_ipv4_add(struct zserv *client, u_short length,
|
||||
zlog_warn(
|
||||
"%s: Please use ZEBRA_ROUTE_ADD if you want to pass v6 nexthops",
|
||||
__PRETTY_FUNCTION__);
|
||||
nexthops_free(re->nexthop);
|
||||
nexthops_free(re->ng.nexthop);
|
||||
XFREE(MTYPE_RE, re);
|
||||
return -1;
|
||||
break;
|
||||
@ -1445,7 +1487,7 @@ static int zread_ipv4_add(struct zserv *client, u_short length,
|
||||
zlog_warn(
|
||||
"%s: Specified nexthop type: %d does not exist",
|
||||
__PRETTY_FUNCTION__, nexthop_type);
|
||||
nexthops_free(re->nexthop);
|
||||
nexthops_free(re->ng.nexthop);
|
||||
XFREE(MTYPE_RE, re);
|
||||
return -1;
|
||||
}
|
||||
@ -1485,7 +1527,7 @@ static int zread_ipv4_add(struct zserv *client, u_short length,
|
||||
return 0;
|
||||
|
||||
stream_failure:
|
||||
nexthops_free(re->nexthop);
|
||||
nexthops_free(re->ng.nexthop);
|
||||
XFREE(MTYPE_RE, re);
|
||||
return -1;
|
||||
}
|
||||
@ -1651,7 +1693,7 @@ static int zread_ipv4_route_ipv6_nexthop_add(struct zserv *client,
|
||||
zlog_warn(
|
||||
"%s: Please use ZEBRA_ROUTE_ADD if you want to pass non v6 nexthops",
|
||||
__PRETTY_FUNCTION__);
|
||||
nexthops_free(re->nexthop);
|
||||
nexthops_free(re->ng.nexthop);
|
||||
XFREE(MTYPE_RE, re);
|
||||
return -1;
|
||||
}
|
||||
@ -1714,7 +1756,7 @@ static int zread_ipv4_route_ipv6_nexthop_add(struct zserv *client,
|
||||
return 0;
|
||||
|
||||
stream_failure:
|
||||
nexthops_free(re->nexthop);
|
||||
nexthops_free(re->ng.nexthop);
|
||||
XFREE(MTYPE_RE, re);
|
||||
return -1;
|
||||
}
|
||||
@ -1847,7 +1889,7 @@ static int zread_ipv6_add(struct zserv *client, u_short length,
|
||||
zlog_warn(
|
||||
"%s: Please use ZEBRA_ROUTE_ADD if you want to pass non v6 nexthops",
|
||||
__PRETTY_FUNCTION__);
|
||||
nexthops_free(re->nexthop);
|
||||
nexthops_free(re->ng.nexthop);
|
||||
XFREE(MTYPE_RE, re);
|
||||
return -1;
|
||||
}
|
||||
@ -1908,7 +1950,7 @@ static int zread_ipv6_add(struct zserv *client, u_short length,
|
||||
return 0;
|
||||
|
||||
stream_failure:
|
||||
nexthops_free(re->nexthop);
|
||||
nexthops_free(re->ng.nexthop);
|
||||
XFREE(MTYPE_RE, re);
|
||||
|
||||
return -1;
|
||||
@ -2584,6 +2626,65 @@ stream_failure:
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void zread_rule(uint16_t command, struct zserv *client,
|
||||
uint16_t length, struct zebra_vrf *zvrf)
|
||||
{
|
||||
struct zebra_pbr_rule zpr;
|
||||
struct stream *s;
|
||||
uint32_t total, i;
|
||||
ifindex_t ifindex;
|
||||
|
||||
s = client->ibuf;
|
||||
STREAM_GETL(s, total);
|
||||
|
||||
for (i = 0; i < total; i++) {
|
||||
memset(&zpr, 0, sizeof(zpr));
|
||||
|
||||
zpr.sock = client->sock;
|
||||
STREAM_GETL(s, zpr.seq);
|
||||
STREAM_GETL(s, zpr.priority);
|
||||
STREAM_GETL(s, zpr.unique);
|
||||
STREAM_GETC(s, zpr.filter.src_ip.family);
|
||||
STREAM_GETC(s, zpr.filter.src_ip.prefixlen);
|
||||
STREAM_GET(&zpr.filter.src_ip.u.prefix, s,
|
||||
prefix_blen(&zpr.filter.src_ip));
|
||||
STREAM_GETW(s, zpr.filter.src_port);
|
||||
STREAM_GETC(s, zpr.filter.dst_ip.family);
|
||||
STREAM_GETC(s, zpr.filter.dst_ip.prefixlen);
|
||||
STREAM_GET(&zpr.filter.dst_ip.u.prefix, s,
|
||||
prefix_blen(&zpr.filter.dst_ip));
|
||||
STREAM_GETW(s, zpr.filter.dst_port);
|
||||
STREAM_GETL(s, zpr.action.table);
|
||||
STREAM_GETL(s, ifindex);
|
||||
|
||||
zpr.ifp = if_lookup_by_index(ifindex, VRF_UNKNOWN);
|
||||
if (!zpr.ifp) {
|
||||
zlog_debug("FAiled to lookup ifindex: %u", ifindex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_default_prefix(&zpr.filter.src_ip))
|
||||
zpr.filter.filter_bm |= PBR_FILTER_SRC_IP;
|
||||
|
||||
if (!is_default_prefix(&zpr.filter.dst_ip))
|
||||
zpr.filter.filter_bm |= PBR_FILTER_DST_IP;
|
||||
|
||||
if (zpr.filter.src_port)
|
||||
zpr.filter.filter_bm |= PBR_FILTER_SRC_PORT;
|
||||
|
||||
if (zpr.filter.dst_port)
|
||||
zpr.filter.filter_bm |= PBR_FILTER_DST_PORT;
|
||||
|
||||
if (command == ZEBRA_RULE_ADD)
|
||||
zebra_pbr_add_rule(zvrf->zns, &zpr);
|
||||
else
|
||||
zebra_pbr_del_rule(zvrf->zns, &zpr);
|
||||
}
|
||||
|
||||
stream_failure:
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void zserv_handle_commands(struct zserv *client, uint16_t command,
|
||||
uint16_t length,
|
||||
struct zebra_vrf *zvrf)
|
||||
@ -2728,6 +2829,10 @@ static inline void zserv_handle_commands(struct zserv *client, uint16_t command,
|
||||
case ZEBRA_PW_UNSET:
|
||||
zread_pseudowire(command, client, length, zvrf);
|
||||
break;
|
||||
case ZEBRA_RULE_ADD:
|
||||
case ZEBRA_RULE_DELETE:
|
||||
zread_rule(command, client, length, zvrf);
|
||||
break;
|
||||
default:
|
||||
zlog_info("Zebra received unknown command %d", command);
|
||||
break;
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
#include "zebra/zebra_ns.h"
|
||||
#include "zebra/zebra_pw.h"
|
||||
//#include "zebra/zebra_pbr.h"
|
||||
|
||||
/* Default port information. */
|
||||
#define ZEBRA_VTY_PORT 2601
|
||||
@ -178,6 +179,10 @@ extern int zsend_pw_update(struct zserv *, struct zebra_pw *);
|
||||
extern int zsend_route_notify_owner(struct route_entry *re, struct prefix *p,
|
||||
enum zapi_route_notify_owner note);
|
||||
|
||||
struct zebra_pbr_rule;
|
||||
extern void zsend_rule_notify_owner(struct zebra_pbr_rule *rule,
|
||||
enum zapi_rule_notify_owner note);
|
||||
|
||||
extern void zserv_nexthop_num_warn(const char *, const struct prefix *,
|
||||
const unsigned int);
|
||||
extern int zebra_server_send_message(struct zserv *client);
|
||||
|
Loading…
Reference in New Issue
Block a user