Merge pull request #1813 from donaldsharp/pbr_setup

Pbr setup
This commit is contained in:
Philippe Guibert 2018-03-09 18:05:03 +01:00 committed by GitHub
commit 58e7db106d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 1247 additions and 183 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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
View 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

View File

@ -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

View File

@ -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:

View File

@ -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. */

View File

@ -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

View File

@ -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)
{

View File

@ -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
View 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
View 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

View File

@ -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 \

View File

@ -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);

View File

@ -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 *);

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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:

View File

@ -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);

View File

@ -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();

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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 */

View File

@ -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 */

View File

@ -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
View 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
View 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
View 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

View File

@ -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 \

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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
View 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
View 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 */

View File

@ -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",

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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]++;

View File

@ -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, &note, 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;

View File

@ -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);