mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-13 22:26:14 +00:00
commit
5295200043
14
configure.ac
14
configure.ac
@ -1793,7 +1793,6 @@ AS_IF([test "$enable_pathd" != "no"], [
|
||||
AC_DEFINE([HAVE_PATHD], [1], [pathd])
|
||||
])
|
||||
|
||||
|
||||
if test "$ac_cv_lib_json_c_json_object_get" = "no" -a "$BFDD" = "bfdd"; then
|
||||
AC_MSG_ERROR(["you must use json-c library to use bfdd"])
|
||||
fi
|
||||
@ -1999,6 +1998,18 @@ if test "$enable_grpc" = "yes"; then
|
||||
AC_LANG_POP([C++])
|
||||
fi
|
||||
|
||||
dnl ---------
|
||||
dnl DPDK
|
||||
dnl ---------
|
||||
if test "$enable_dp_dpdk" = "yes"; then
|
||||
PKG_CHECK_MODULES([DPDK], [libdpdk], [
|
||||
AC_DEFINE([HAVE_DPDK], [1], [Enable DPDK backend])
|
||||
DPDK=true
|
||||
], [
|
||||
AC_MSG_ERROR([configuration specifies --enable-dp-dpdk but DPDK libs were not found])
|
||||
])
|
||||
fi
|
||||
|
||||
dnl -----
|
||||
dnl LTTng
|
||||
dnl -----
|
||||
@ -2707,6 +2718,7 @@ AM_CONDITIONAL([FABRICD], [test "$enable_fabricd" != "no"])
|
||||
AM_CONDITIONAL([VRRPD], [test "$enable_vrrpd" != "no"])
|
||||
AM_CONDITIONAL([PATHD], [test "$enable_pathd" != "no"])
|
||||
AM_CONDITIONAL([PATHD_PCEP], [test "$enable_pathd" != "no"])
|
||||
AM_CONDITIONAL([DP_DPDK], [test "$enable_dp_dpdk" = "yes"])
|
||||
|
||||
AC_CONFIG_FILES([Makefile],[
|
||||
test "$enable_dev_build" = "yes" && makefile_devbuild="--dev-build"
|
||||
|
@ -299,6 +299,15 @@ the default route.
|
||||
table. An alternative form of the command is ``show ip import-check`` and this
|
||||
form of the command is deprecated at this point in time.
|
||||
|
||||
PBR dataplane programming
|
||||
=========================
|
||||
|
||||
Some dataplanes require the PBR nexthop to be resolved into a SMAC, DMAC and
|
||||
outgoing interface
|
||||
|
||||
.. clicmd:: pbr nexthop-resolve
|
||||
|
||||
Resolve PBR nexthop via ip neigh tracking
|
||||
|
||||
Administrative Distance
|
||||
=======================
|
||||
@ -1131,6 +1140,59 @@ order to off-load work from the main zebra pthread.
|
||||
waiting to be processed by the dataplane pthread.
|
||||
|
||||
|
||||
DPDK dataplane
|
||||
==============
|
||||
|
||||
The zebra DPDK subsystem programs the dataplane via rte_XXX APIs.
|
||||
This module needs be compiled in via "--enable-dp-dpdk=yes"
|
||||
and enabled at start up time via the zebra daemon option "-M dplane_dpdk".
|
||||
|
||||
To program the PBR rules as rte_flows you additionally need to configure
|
||||
"pbr nexthop-resolve". This is used to expland the PBR actions into the
|
||||
{SMAC, DMAC, outgoing port} needed by rte_flow.
|
||||
|
||||
|
||||
.. clicmd:: show dplane dpdk port [detail]
|
||||
|
||||
Displays the mapping table between zebra interfaces and DPDK port-ids.
|
||||
Sample output:
|
||||
|
||||
::
|
||||
Port Device IfName IfIndex sw,domain,port
|
||||
|
||||
0 0000:03:00.0 p0 4 0000:03:00.0,0,65535
|
||||
1 0000:03:00.0 pf0hpf 6 0000:03:00.0,0,4095
|
||||
2 0000:03:00.0 pf0vf0 15 0000:03:00.0,0,4096
|
||||
3 0000:03:00.0 pf0vf1 16 0000:03:00.0,0,4097
|
||||
4 0000:03:00.1 p1 5 0000:03:00.1,1,65535
|
||||
5 0000:03:00.1 pf1hpf 7 0000:03:00.1,1,20479
|
||||
|
||||
.. clicmd:: show dplane dpdk pbr flows
|
||||
Displays the DPDK stats per-PBR entry.
|
||||
Sample output:
|
||||
|
||||
::
|
||||
Rules if pf0vf0
|
||||
Seq 1 pri 300
|
||||
SRC Match 77.0.0.8/32
|
||||
DST Match 88.0.0.8/32
|
||||
Tableid: 10000
|
||||
Action: nh: 45.0.0.250 intf: p0
|
||||
Action: mac: 00:00:5e:00:01:fa
|
||||
DPDK flow: installed 0x40
|
||||
DPDK flow stats: packets 13 bytes 1586
|
||||
|
||||
.. clicmd:: show dplane dpdk counters
|
||||
Displays the ZAPI message handler counters
|
||||
|
||||
Sample output:
|
||||
|
||||
::
|
||||
Ignored updates: 0
|
||||
PBR rule adds: 1
|
||||
PBR rule dels: 0
|
||||
|
||||
|
||||
zebra Terminal Mode Commands
|
||||
============================
|
||||
|
||||
@ -1188,6 +1250,14 @@ zebra Terminal Mode Commands
|
||||
|
||||
Display whether the host's IP v6 forwarding is enabled or not.
|
||||
|
||||
.. clicmd:: show ip neigh
|
||||
|
||||
Display the ip neighbor table
|
||||
|
||||
.. clicmd:: show pbr rule
|
||||
|
||||
Display the pbr rule table with resolved nexthops
|
||||
|
||||
.. clicmd:: show zebra
|
||||
|
||||
Display various statistics related to the installation and deletion
|
||||
|
@ -163,6 +163,10 @@ static struct {
|
||||
{
|
||||
1, (pvalue_t[]){CAP_IPC_LOCK},
|
||||
},
|
||||
[ZCAP_SYS_RAWIO] =
|
||||
{
|
||||
1, (pvalue_t[]){CAP_SYS_RAWIO},
|
||||
},
|
||||
#endif /* HAVE_LCAPS */
|
||||
};
|
||||
|
||||
|
@ -45,6 +45,7 @@ typedef enum {
|
||||
ZCAP_READ_SEARCH,
|
||||
ZCAP_FOWNER,
|
||||
ZCAP_IPC_LOCK,
|
||||
ZCAP_SYS_RAWIO,
|
||||
ZCAP_MAX
|
||||
} zebra_capabilities_t;
|
||||
|
||||
|
@ -848,9 +848,13 @@ static void vty_show_pbrms(struct vty *vty,
|
||||
}
|
||||
|
||||
if (pbrms->src)
|
||||
vty_out(vty, " SRC Match: %pFX\n", pbrms->src);
|
||||
vty_out(vty, " SRC IP Match: %pFX\n", pbrms->src);
|
||||
if (pbrms->dst)
|
||||
vty_out(vty, " DST Match: %pFX\n", pbrms->dst);
|
||||
vty_out(vty, " DST IP Match: %pFX\n", pbrms->dst);
|
||||
if (pbrms->src_prt)
|
||||
vty_out(vty, " SRC Port Match: %u\n", pbrms->src_prt);
|
||||
if (pbrms->dst_prt)
|
||||
vty_out(vty, " DST Port Match: %u\n", pbrms->dst_prt);
|
||||
if (pbrms->dsfield & PBR_DSFIELD_DSCP)
|
||||
vty_out(vty, " DSCP Match: %u\n",
|
||||
(pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2);
|
||||
|
@ -66,6 +66,7 @@ extern struct thread_master *master;
|
||||
/* Daemons who can process nexthop-group configs */
|
||||
#define VTYSH_NH_GROUP VTYSH_PBRD|VTYSH_SHARPD
|
||||
#define VTYSH_SR VTYSH_ZEBRA|VTYSH_PATHD
|
||||
#define VTYSH_DPDK VTYSH_ZEBRA
|
||||
|
||||
enum vtysh_write_integrated {
|
||||
WRITE_INTEGRATED_UNSPECIFIED,
|
||||
|
@ -38,10 +38,12 @@ unsigned long zebra_debug_mpls;
|
||||
unsigned long zebra_debug_vxlan;
|
||||
unsigned long zebra_debug_pw;
|
||||
unsigned long zebra_debug_dplane;
|
||||
unsigned long zebra_debug_dplane_dpdk;
|
||||
unsigned long zebra_debug_mlag;
|
||||
unsigned long zebra_debug_nexthop;
|
||||
unsigned long zebra_debug_evpn_mh;
|
||||
unsigned long zebra_debug_pbr;
|
||||
unsigned long zebra_debug_neigh;
|
||||
|
||||
DEFINE_HOOK(zebra_debug_show_debugging, (struct vty *vty), (vty));
|
||||
|
||||
@ -107,6 +109,11 @@ DEFUN_NOSH (show_debugging_zebra,
|
||||
vty_out(vty, " Zebra detailed dataplane debugging is on\n");
|
||||
else if (IS_ZEBRA_DEBUG_DPLANE)
|
||||
vty_out(vty, " Zebra dataplane debugging is on\n");
|
||||
if (IS_ZEBRA_DEBUG_DPLANE_DPDK_DETAIL)
|
||||
vty_out(vty,
|
||||
" Zebra detailed dpdk dataplane debugging is on\n");
|
||||
else if (IS_ZEBRA_DEBUG_DPLANE_DPDK)
|
||||
vty_out(vty, " Zebra dataplane dpdk debugging is on\n");
|
||||
if (IS_ZEBRA_DEBUG_MLAG)
|
||||
vty_out(vty, " Zebra mlag debugging is on\n");
|
||||
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
|
||||
@ -316,6 +323,29 @@ DEFUN (debug_zebra_dplane,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY(debug_zebra_dplane_dpdk, debug_zebra_dplane_dpdk_cmd,
|
||||
"[no$no] debug zebra dplane dpdk [detailed$detail]",
|
||||
NO_STR DEBUG_STR
|
||||
"Zebra configuration\n"
|
||||
"Debug zebra dataplane events\n"
|
||||
"Debug zebra DPDK offload events\n"
|
||||
"Detailed debug information\n")
|
||||
{
|
||||
if (no) {
|
||||
UNSET_FLAG(zebra_debug_dplane_dpdk, ZEBRA_DEBUG_DPLANE_DPDK);
|
||||
UNSET_FLAG(zebra_debug_dplane_dpdk,
|
||||
ZEBRA_DEBUG_DPLANE_DPDK_DETAIL);
|
||||
} else {
|
||||
SET_FLAG(zebra_debug_dplane_dpdk, ZEBRA_DEBUG_DPLANE_DPDK);
|
||||
|
||||
if (detail)
|
||||
SET_FLAG(zebra_debug_dplane,
|
||||
ZEBRA_DEBUG_DPLANE_DPDK_DETAIL);
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (debug_zebra_pbr,
|
||||
debug_zebra_pbr_cmd,
|
||||
"debug zebra pbr",
|
||||
@ -327,6 +357,22 @@ DEFUN (debug_zebra_pbr,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY (debug_zebra_neigh,
|
||||
debug_zebra_neigh_cmd,
|
||||
"[no$no] debug zebra neigh",
|
||||
NO_STR
|
||||
DEBUG_STR
|
||||
"Zebra configuration\n"
|
||||
"Debug zebra neigh events\n")
|
||||
{
|
||||
if (no)
|
||||
UNSET_FLAG(zebra_debug_neigh, ZEBRA_DEBUG_NEIGH);
|
||||
else
|
||||
SET_FLAG(zebra_debug_neigh, ZEBRA_DEBUG_NEIGH);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY (debug_zebra_mlag,
|
||||
debug_zebra_mlag_cmd,
|
||||
"[no$no] debug zebra mlag",
|
||||
@ -681,6 +727,14 @@ static int config_write_debug(struct vty *vty)
|
||||
write++;
|
||||
}
|
||||
|
||||
if (CHECK_FLAG(zebra_debug_dplane, ZEBRA_DEBUG_DPLANE_DPDK_DETAIL)) {
|
||||
vty_out(vty, "debug zebra dplane dpdk detailed\n");
|
||||
write++;
|
||||
} else if (CHECK_FLAG(zebra_debug_dplane, ZEBRA_DEBUG_DPLANE_DPDK)) {
|
||||
vty_out(vty, "debug zebra dplane dpdk\n");
|
||||
write++;
|
||||
}
|
||||
|
||||
if (CHECK_FLAG(zebra_debug_nexthop, ZEBRA_DEBUG_NHG_DETAILED)) {
|
||||
vty_out(vty, "debug zebra nexthop detail\n");
|
||||
write++;
|
||||
@ -694,6 +748,11 @@ static int config_write_debug(struct vty *vty)
|
||||
write++;
|
||||
}
|
||||
|
||||
if (IS_ZEBRA_DEBUG_NEIGH) {
|
||||
vty_out(vty, "debug zebra neigh\n");
|
||||
write++;
|
||||
}
|
||||
|
||||
return write;
|
||||
}
|
||||
|
||||
@ -708,11 +767,13 @@ void zebra_debug_init(void)
|
||||
zebra_debug_vxlan = 0;
|
||||
zebra_debug_pw = 0;
|
||||
zebra_debug_dplane = 0;
|
||||
zebra_debug_dplane_dpdk = 0;
|
||||
zebra_debug_mlag = 0;
|
||||
zebra_debug_evpn_mh = 0;
|
||||
zebra_debug_nht = 0;
|
||||
zebra_debug_nexthop = 0;
|
||||
zebra_debug_pbr = 0;
|
||||
zebra_debug_neigh = 0;
|
||||
|
||||
install_node(&debug_node);
|
||||
|
||||
@ -734,6 +795,8 @@ void zebra_debug_init(void)
|
||||
install_element(ENABLE_NODE, &debug_zebra_mlag_cmd);
|
||||
install_element(ENABLE_NODE, &debug_zebra_nexthop_cmd);
|
||||
install_element(ENABLE_NODE, &debug_zebra_pbr_cmd);
|
||||
install_element(ENABLE_NODE, &debug_zebra_neigh_cmd);
|
||||
install_element(ENABLE_NODE, &debug_zebra_dplane_dpdk_cmd);
|
||||
install_element(ENABLE_NODE, &no_debug_zebra_events_cmd);
|
||||
install_element(ENABLE_NODE, &no_debug_zebra_nht_cmd);
|
||||
install_element(ENABLE_NODE, &no_debug_zebra_mpls_cmd);
|
||||
@ -762,8 +825,10 @@ void zebra_debug_init(void)
|
||||
install_element(CONFIG_NODE, &debug_zebra_rib_cmd);
|
||||
install_element(CONFIG_NODE, &debug_zebra_fpm_cmd);
|
||||
install_element(CONFIG_NODE, &debug_zebra_dplane_cmd);
|
||||
install_element(CONFIG_NODE, &debug_zebra_dplane_dpdk_cmd);
|
||||
install_element(CONFIG_NODE, &debug_zebra_nexthop_cmd);
|
||||
install_element(CONFIG_NODE, &debug_zebra_pbr_cmd);
|
||||
install_element(CONFIG_NODE, &debug_zebra_neigh_cmd);
|
||||
|
||||
install_element(CONFIG_NODE, &no_debug_zebra_events_cmd);
|
||||
install_element(CONFIG_NODE, &no_debug_zebra_nht_cmd);
|
||||
|
@ -58,6 +58,9 @@ extern "C" {
|
||||
#define ZEBRA_DEBUG_DPLANE 0x01
|
||||
#define ZEBRA_DEBUG_DPLANE_DETAILED 0x02
|
||||
|
||||
#define ZEBRA_DEBUG_DPLANE_DPDK 0x01
|
||||
#define ZEBRA_DEBUG_DPLANE_DPDK_DETAIL 0x02
|
||||
|
||||
#define ZEBRA_DEBUG_MLAG 0x01
|
||||
|
||||
#define ZEBRA_DEBUG_NHG 0x01
|
||||
@ -70,6 +73,8 @@ extern "C" {
|
||||
|
||||
#define ZEBRA_DEBUG_PBR 0x01
|
||||
|
||||
#define ZEBRA_DEBUG_NEIGH 0x01
|
||||
|
||||
/* Debug related macro. */
|
||||
#define IS_ZEBRA_DEBUG_EVENT (zebra_debug_event & ZEBRA_DEBUG_EVENT)
|
||||
|
||||
@ -103,6 +108,11 @@ extern "C" {
|
||||
#define IS_ZEBRA_DEBUG_DPLANE_DETAIL \
|
||||
(zebra_debug_dplane & ZEBRA_DEBUG_DPLANE_DETAILED)
|
||||
|
||||
#define IS_ZEBRA_DEBUG_DPLANE_DPDK \
|
||||
(zebra_debug_dplane & ZEBRA_DEBUG_DPLANE_DPDK)
|
||||
#define IS_ZEBRA_DEBUG_DPLANE_DPDK_DETAIL \
|
||||
(zebra_debug_dplane & ZEBRA_DEBUG_DPLANE_DPDK_DETAIL)
|
||||
|
||||
#define IS_ZEBRA_DEBUG_MLAG (zebra_debug_mlag & ZEBRA_DEBUG_MLAG)
|
||||
|
||||
#define IS_ZEBRA_DEBUG_NHG (zebra_debug_nexthop & ZEBRA_DEBUG_NHG)
|
||||
@ -121,6 +131,8 @@ extern "C" {
|
||||
|
||||
#define IS_ZEBRA_DEBUG_PBR (zebra_debug_pbr & ZEBRA_DEBUG_PBR)
|
||||
|
||||
#define IS_ZEBRA_DEBUG_NEIGH (zebra_debug_neigh & ZEBRA_DEBUG_NEIGH)
|
||||
|
||||
extern unsigned long zebra_debug_event;
|
||||
extern unsigned long zebra_debug_packet;
|
||||
extern unsigned long zebra_debug_kernel;
|
||||
@ -131,10 +143,12 @@ extern unsigned long zebra_debug_mpls;
|
||||
extern unsigned long zebra_debug_vxlan;
|
||||
extern unsigned long zebra_debug_pw;
|
||||
extern unsigned long zebra_debug_dplane;
|
||||
extern unsigned long zebra_debug_dplane_dpdk;
|
||||
extern unsigned long zebra_debug_mlag;
|
||||
extern unsigned long zebra_debug_nexthop;
|
||||
extern unsigned long zebra_debug_evpn_mh;
|
||||
extern unsigned long zebra_debug_pbr;
|
||||
extern unsigned long zebra_debug_neigh;
|
||||
|
||||
extern void zebra_debug_init(void);
|
||||
|
||||
|
733
zebra/dpdk/zebra_dplane_dpdk.c
Normal file
733
zebra/dpdk/zebra_dplane_dpdk.c
Normal file
@ -0,0 +1,733 @@
|
||||
/*
|
||||
* Zebra dataplane plugin for DPDK based hw offload
|
||||
*
|
||||
* Copyright (C) 2021 Nvidia
|
||||
* Anuradha Karuppiah
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h" /* Include this explicitly */
|
||||
#endif
|
||||
|
||||
#include "lib/libfrr.h"
|
||||
|
||||
#include "zebra/debug.h"
|
||||
#include "zebra/interface.h"
|
||||
#include "zebra/zebra_dplane.h"
|
||||
#include "zebra/debug.h"
|
||||
#include "zebra/zebra_pbr.h"
|
||||
|
||||
#include "zebra/dpdk/zebra_dplane_dpdk_private.h"
|
||||
|
||||
static const char *plugin_name = "zebra_dplane_dpdk";
|
||||
|
||||
static struct zd_dpdk_ctx dpdk_ctx_buf, *dpdk_ctx = &dpdk_ctx_buf;
|
||||
#define dpdk_stat (&dpdk_ctx->stats)
|
||||
|
||||
static struct zd_dpdk_port *zd_dpdk_port_find_by_index(int ifindex);
|
||||
|
||||
DEFINE_MTYPE_STATIC(ZEBRA, DPDK_PORTS, "ZD DPDK port database");
|
||||
|
||||
void zd_dpdk_stat_show(struct vty *vty)
|
||||
{
|
||||
uint32_t tmp_cnt;
|
||||
|
||||
vty_out(vty, "%30s\n%30s\n", "Dataplane DPDK counters",
|
||||
"=======================");
|
||||
|
||||
#define ZD_DPDK_SHOW_COUNTER(label, counter) \
|
||||
do { \
|
||||
tmp_cnt = \
|
||||
atomic_load_explicit(&counter, memory_order_relaxed); \
|
||||
vty_out(vty, "%28s: %u\n", (label), (tmp_cnt)); \
|
||||
} while (0)
|
||||
|
||||
ZD_DPDK_SHOW_COUNTER("PBR rule adds", dpdk_stat->rule_adds);
|
||||
ZD_DPDK_SHOW_COUNTER("PBR rule dels", dpdk_stat->rule_dels);
|
||||
ZD_DPDK_SHOW_COUNTER("Ignored updates", dpdk_stat->ignored_updates);
|
||||
}
|
||||
|
||||
|
||||
static void zd_dpdk_flow_stat_show(struct vty *vty, int in_ifindex,
|
||||
intptr_t dp_flow_ptr)
|
||||
{
|
||||
struct rte_flow_action_count count = {.shared = 0, .id = 0};
|
||||
const struct rte_flow_action actions[] = {
|
||||
{
|
||||
.type = RTE_FLOW_ACTION_TYPE_COUNT,
|
||||
.conf = &count,
|
||||
},
|
||||
{
|
||||
.type = RTE_FLOW_ACTION_TYPE_END,
|
||||
},
|
||||
};
|
||||
int rc;
|
||||
struct zd_dpdk_port *in_dport;
|
||||
struct rte_flow_query_count query;
|
||||
struct rte_flow_error error;
|
||||
uint64_t hits, bytes;
|
||||
|
||||
in_dport = zd_dpdk_port_find_by_index(in_ifindex);
|
||||
if (!in_dport) {
|
||||
vty_out(vty, "PBR dpdk flow query failed; in_port %d missing\n",
|
||||
in_ifindex);
|
||||
return;
|
||||
}
|
||||
memset(&query, 0, sizeof(query));
|
||||
rc = rte_flow_query(in_dport->port_id, (struct rte_flow *)dp_flow_ptr,
|
||||
actions, &query, &error);
|
||||
if (rc) {
|
||||
vty_out(vty,
|
||||
"PBR dpdk flow query failed; in_ifindex %d rc %d\n",
|
||||
in_ifindex, error.type);
|
||||
return;
|
||||
}
|
||||
hits = (query.hits_set) ? query.hits : 0;
|
||||
bytes = (query.bytes_set) ? query.bytes : 0;
|
||||
vty_out(vty, " DPDK stats: packets %" PRIu64 " bytes %" PRIu64 "\n",
|
||||
hits, bytes);
|
||||
}
|
||||
|
||||
|
||||
static int zd_dpdk_pbr_show_rules_walkcb(struct hash_bucket *bucket, void *arg)
|
||||
{
|
||||
struct zebra_pbr_rule *rule = (struct zebra_pbr_rule *)bucket->data;
|
||||
struct vty *vty = (struct vty *)arg;
|
||||
struct vrf *vrf;
|
||||
struct interface *ifp = NULL;
|
||||
struct zebra_pbr_action *zaction = &rule->action;
|
||||
|
||||
zebra_pbr_show_rule_unit(rule, vty);
|
||||
if (zaction->dp_flow_ptr) {
|
||||
vrf = vrf_lookup_by_id(rule->vrf_id);
|
||||
if (vrf)
|
||||
ifp = if_lookup_by_name_vrf(rule->ifname, vrf);
|
||||
|
||||
if (ifp)
|
||||
zd_dpdk_flow_stat_show(vty, ifp->ifindex,
|
||||
zaction->dp_flow_ptr);
|
||||
}
|
||||
return HASHWALK_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
void zd_dpdk_pbr_flows_show(struct vty *vty)
|
||||
{
|
||||
hash_walk(zrouter.rules_hash, zd_dpdk_pbr_show_rules_walkcb, vty);
|
||||
}
|
||||
|
||||
|
||||
static void zd_dpdk_rule_add(struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
static struct rte_flow_attr attrs = {.ingress = 1, .transfer = 1};
|
||||
uint32_t filter_bm = dplane_ctx_rule_get_filter_bm(ctx);
|
||||
int in_ifindex = dplane_ctx_get_ifindex(ctx);
|
||||
int out_ifindex = dplane_ctx_rule_get_out_ifindex(ctx);
|
||||
struct rte_flow_item_eth eth, eth_mask;
|
||||
struct rte_flow_item_ipv4 ip, ip_mask;
|
||||
struct rte_flow_item_udp udp, udp_mask;
|
||||
struct rte_flow_action_count conf_count;
|
||||
struct rte_flow_action_set_mac conf_smac, conf_dmac;
|
||||
struct rte_flow_action_port_id conf_port;
|
||||
struct rte_flow_item items[ZD_PBR_PATTERN_MAX];
|
||||
struct rte_flow_action actions[ZD_PBR_ACTION_MAX];
|
||||
int item_cnt = 0;
|
||||
int act_cnt = 0;
|
||||
struct in_addr tmp_mask;
|
||||
const struct ethaddr *mac;
|
||||
struct rte_flow *flow;
|
||||
struct rte_flow_error error;
|
||||
struct zd_dpdk_port *in_dport;
|
||||
struct zd_dpdk_port *out_dport;
|
||||
uint32_t pri = dplane_ctx_rule_get_priority(ctx);
|
||||
int seq = dplane_ctx_rule_get_seq(ctx);
|
||||
int unique = dplane_ctx_rule_get_unique(ctx);
|
||||
|
||||
if (IS_ZEBRA_DEBUG_DPLANE_DPDK_DETAIL)
|
||||
zlog_debug(
|
||||
"PBR dpdk flow create ifname %s seq %d pri %u unique %d\n",
|
||||
dplane_ctx_rule_get_ifname(ctx), seq, pri, unique);
|
||||
in_dport = zd_dpdk_port_find_by_index(in_ifindex);
|
||||
if (!in_dport) {
|
||||
if (IS_ZEBRA_DEBUG_DPLANE_DPDK_DETAIL)
|
||||
zlog_debug(
|
||||
"PBR dpdk flow create ifname %s seq %d pri %u unique %d failed; in_port %d missing\n",
|
||||
dplane_ctx_rule_get_ifname(ctx), seq, pri,
|
||||
unique, in_ifindex);
|
||||
return;
|
||||
}
|
||||
|
||||
out_dport = zd_dpdk_port_find_by_index(out_ifindex);
|
||||
if (!out_dport) {
|
||||
if (IS_ZEBRA_DEBUG_DPLANE_DPDK_DETAIL)
|
||||
zlog_debug(
|
||||
"PBR dpdk flow create ifname %s seq %d pri %u unique %d failed; out_port %d missing\n",
|
||||
dplane_ctx_rule_get_ifname(ctx), seq, pri,
|
||||
unique, out_ifindex);
|
||||
return;
|
||||
}
|
||||
|
||||
/*********************** match items **************************/
|
||||
memset(ð, 0, sizeof(eth));
|
||||
memset(ð_mask, 0, sizeof(eth_mask));
|
||||
eth.type = eth_mask.type = htons(RTE_ETHER_TYPE_IPV4);
|
||||
items[item_cnt].type = RTE_FLOW_ITEM_TYPE_ETH;
|
||||
items[item_cnt].spec = ð
|
||||
items[item_cnt].mask = ð_mask;
|
||||
items[item_cnt].last = NULL;
|
||||
++item_cnt;
|
||||
|
||||
memset(&ip, 0, sizeof(ip));
|
||||
memset(&ip_mask, 0, sizeof(ip_mask));
|
||||
if (filter_bm & PBR_FILTER_SRC_IP) {
|
||||
const struct prefix *src_ip;
|
||||
|
||||
src_ip = dplane_ctx_rule_get_src_ip(ctx);
|
||||
ip.hdr.src_addr = src_ip->u.prefix4.s_addr;
|
||||
masklen2ip(src_ip->prefixlen, &tmp_mask);
|
||||
ip_mask.hdr.src_addr = tmp_mask.s_addr;
|
||||
}
|
||||
if (filter_bm & PBR_FILTER_DST_IP) {
|
||||
const struct prefix *dst_ip;
|
||||
|
||||
dst_ip = dplane_ctx_rule_get_dst_ip(ctx);
|
||||
ip.hdr.dst_addr = dst_ip->u.prefix4.s_addr;
|
||||
masklen2ip(dst_ip->prefixlen, &tmp_mask);
|
||||
ip_mask.hdr.dst_addr = tmp_mask.s_addr;
|
||||
}
|
||||
if (filter_bm & PBR_FILTER_IP_PROTOCOL) {
|
||||
ip.hdr.next_proto_id = dplane_ctx_rule_get_ipproto(ctx);
|
||||
ip_mask.hdr.next_proto_id = UINT8_MAX;
|
||||
}
|
||||
items[item_cnt].type = RTE_FLOW_ITEM_TYPE_IPV4;
|
||||
items[item_cnt].spec = &ip;
|
||||
items[item_cnt].mask = &ip_mask;
|
||||
items[item_cnt].last = NULL;
|
||||
++item_cnt;
|
||||
|
||||
if ((filter_bm & (PBR_FILTER_SRC_PORT | PBR_FILTER_DST_PORT))) {
|
||||
memset(&udp, 0, sizeof(udp));
|
||||
memset(&udp_mask, 0, sizeof(udp_mask));
|
||||
if (filter_bm & PBR_FILTER_SRC_PORT) {
|
||||
udp.hdr.src_port =
|
||||
RTE_BE16(dplane_ctx_rule_get_src_port(ctx));
|
||||
udp_mask.hdr.src_port = UINT16_MAX;
|
||||
}
|
||||
if (filter_bm & PBR_FILTER_DST_PORT) {
|
||||
udp.hdr.dst_port =
|
||||
RTE_BE16(dplane_ctx_rule_get_dst_port(ctx));
|
||||
udp_mask.hdr.dst_port = UINT16_MAX;
|
||||
}
|
||||
items[item_cnt].type = RTE_FLOW_ITEM_TYPE_UDP;
|
||||
items[item_cnt].spec = &udp;
|
||||
items[item_cnt].mask = &udp_mask;
|
||||
items[item_cnt].last = NULL;
|
||||
++item_cnt;
|
||||
}
|
||||
|
||||
items[item_cnt].type = RTE_FLOW_ITEM_TYPE_END;
|
||||
|
||||
/*************************** actions *****************************/
|
||||
actions[act_cnt].type = RTE_FLOW_ACTION_TYPE_COUNT;
|
||||
memset(&conf_count, 0, sizeof(conf_count));
|
||||
actions[act_cnt].conf = &conf_count;
|
||||
++act_cnt;
|
||||
|
||||
actions[act_cnt].type = RTE_FLOW_ACTION_TYPE_DEC_TTL;
|
||||
++act_cnt;
|
||||
|
||||
mac = dplane_ctx_rule_get_smac(ctx);
|
||||
memcpy(conf_smac.mac_addr, mac, RTE_ETHER_ADDR_LEN);
|
||||
actions[act_cnt].type = RTE_FLOW_ACTION_TYPE_SET_MAC_SRC;
|
||||
actions[act_cnt].conf = &conf_smac;
|
||||
++act_cnt;
|
||||
|
||||
mac = dplane_ctx_rule_get_dmac(ctx);
|
||||
memcpy(conf_dmac.mac_addr, mac, RTE_ETHER_ADDR_LEN);
|
||||
actions[act_cnt].type = RTE_FLOW_ACTION_TYPE_SET_MAC_DST;
|
||||
actions[act_cnt].conf = &conf_dmac;
|
||||
++act_cnt;
|
||||
|
||||
memset(&conf_port, 0, sizeof(conf_port));
|
||||
conf_port.id = out_dport->port_id;
|
||||
actions[act_cnt].type = RTE_FLOW_ACTION_TYPE_PORT_ID;
|
||||
actions[act_cnt].conf = &conf_port;
|
||||
++act_cnt;
|
||||
|
||||
actions[act_cnt].type = RTE_FLOW_ACTION_TYPE_END;
|
||||
|
||||
frr_with_privs (&zserv_privs) {
|
||||
flow = rte_flow_create(in_dport->port_id, &attrs, items,
|
||||
actions, &error);
|
||||
}
|
||||
|
||||
if (flow) {
|
||||
dplane_ctx_rule_set_dp_flow_ptr(ctx, (intptr_t)flow);
|
||||
if (IS_ZEBRA_DEBUG_DPLANE_DPDK_DETAIL)
|
||||
zlog_debug(
|
||||
"PBR dpdk flow 0x%" PRIxPTR
|
||||
" created ifname %s seq %d pri %u unique %d\n",
|
||||
(intptr_t)flow, dplane_ctx_rule_get_ifname(ctx),
|
||||
seq, pri, unique);
|
||||
} else {
|
||||
zlog_warn(
|
||||
"PBR dpdk flow create failed ifname %s seq %d pri %u unique %d; rc %d\n",
|
||||
dplane_ctx_rule_get_ifname(ctx), seq, pri, unique,
|
||||
error.type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void zd_dpdk_rule_del(struct zebra_dplane_ctx *ctx, const char *ifname,
|
||||
int in_ifindex, intptr_t dp_flow_ptr)
|
||||
{
|
||||
struct zd_dpdk_port *in_dport;
|
||||
struct rte_flow_error error;
|
||||
int rc;
|
||||
|
||||
if (IS_ZEBRA_DEBUG_DPLANE_DPDK_DETAIL)
|
||||
zlog_debug(
|
||||
"PBR dpdk flow delete ifname %s ifindex %d dp_flow 0x%" PRIxPTR
|
||||
"\n",
|
||||
ifname, in_ifindex, dp_flow_ptr);
|
||||
|
||||
if (!dp_flow_ptr) {
|
||||
if (IS_ZEBRA_DEBUG_DPLANE_DPDK_DETAIL)
|
||||
zlog_debug(
|
||||
"PBR dpdk flow delete failed; ifname %s ifindex %d dp_flow 0x%" PRIxPTR
|
||||
"; empty dp\n",
|
||||
ifname, in_ifindex, dp_flow_ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
dplane_ctx_rule_set_dp_flow_ptr(ctx, (intptr_t)NULL);
|
||||
in_dport = zd_dpdk_port_find_by_index(in_ifindex);
|
||||
if (!in_dport) {
|
||||
if (IS_ZEBRA_DEBUG_DPLANE_DPDK_DETAIL)
|
||||
zlog_debug(
|
||||
"PBR dpdk flow delete failed; ifname %s ifindex %d dp_flow 0x%" PRIxPTR
|
||||
" in port missing\n",
|
||||
ifname, in_ifindex, dp_flow_ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
frr_with_privs (&zserv_privs) {
|
||||
rc = rte_flow_destroy(in_dport->port_id,
|
||||
(struct rte_flow *)dp_flow_ptr, &error);
|
||||
}
|
||||
|
||||
if (rc)
|
||||
zlog_warn(
|
||||
"PBR dpdk flow delete failed; ifname %s ifindex %d dp_flow 0x%" PRIxPTR
|
||||
"\n",
|
||||
ifname, in_ifindex, dp_flow_ptr);
|
||||
}
|
||||
|
||||
|
||||
static void zd_dpdk_rule_update(struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
enum dplane_op_e op;
|
||||
int in_ifindex;
|
||||
intptr_t dp_flow_ptr;
|
||||
|
||||
if (IS_ZEBRA_DEBUG_DPLANE_DPDK_DETAIL)
|
||||
zlog_debug("Dplane %s", dplane_op2str(dplane_ctx_get_op(ctx)));
|
||||
|
||||
|
||||
op = dplane_ctx_get_op(ctx);
|
||||
switch (op) {
|
||||
case DPLANE_OP_RULE_ADD:
|
||||
atomic_fetch_add_explicit(&dpdk_stat->rule_adds, 1,
|
||||
memory_order_relaxed);
|
||||
zd_dpdk_rule_add(ctx);
|
||||
break;
|
||||
|
||||
case DPLANE_OP_RULE_UPDATE:
|
||||
/* delete old rule and install new one */
|
||||
atomic_fetch_add_explicit(&dpdk_stat->rule_adds, 1,
|
||||
memory_order_relaxed);
|
||||
in_ifindex = dplane_ctx_get_ifindex(ctx);
|
||||
dp_flow_ptr = dplane_ctx_rule_get_old_dp_flow_ptr(ctx);
|
||||
zd_dpdk_rule_del(ctx, dplane_ctx_rule_get_ifname(ctx),
|
||||
in_ifindex, dp_flow_ptr);
|
||||
zd_dpdk_rule_add(ctx);
|
||||
break;
|
||||
|
||||
case DPLANE_OP_RULE_DELETE:
|
||||
atomic_fetch_add_explicit(&dpdk_stat->rule_dels, 1,
|
||||
memory_order_relaxed);
|
||||
in_ifindex = dplane_ctx_get_ifindex(ctx);
|
||||
dp_flow_ptr = dplane_ctx_rule_get_dp_flow_ptr(ctx);
|
||||
zd_dpdk_rule_del(ctx, dplane_ctx_rule_get_ifname(ctx),
|
||||
in_ifindex, dp_flow_ptr);
|
||||
break;
|
||||
|
||||
case DPLANE_OP_NONE:
|
||||
case DPLANE_OP_ROUTE_INSTALL:
|
||||
case DPLANE_OP_ROUTE_UPDATE:
|
||||
case DPLANE_OP_ROUTE_DELETE:
|
||||
case DPLANE_OP_ROUTE_NOTIFY:
|
||||
case DPLANE_OP_NH_INSTALL:
|
||||
case DPLANE_OP_NH_UPDATE:
|
||||
case DPLANE_OP_NH_DELETE:
|
||||
case DPLANE_OP_LSP_INSTALL:
|
||||
case DPLANE_OP_LSP_UPDATE:
|
||||
case DPLANE_OP_LSP_DELETE:
|
||||
case DPLANE_OP_LSP_NOTIFY:
|
||||
case DPLANE_OP_PW_INSTALL:
|
||||
case DPLANE_OP_PW_UNINSTALL:
|
||||
case DPLANE_OP_SYS_ROUTE_ADD:
|
||||
case DPLANE_OP_SYS_ROUTE_DELETE:
|
||||
case DPLANE_OP_ADDR_INSTALL:
|
||||
case DPLANE_OP_ADDR_UNINSTALL:
|
||||
case DPLANE_OP_MAC_INSTALL:
|
||||
case DPLANE_OP_MAC_DELETE:
|
||||
case DPLANE_OP_NEIGH_INSTALL:
|
||||
case DPLANE_OP_NEIGH_UPDATE:
|
||||
case DPLANE_OP_NEIGH_DELETE:
|
||||
case DPLANE_OP_VTEP_ADD:
|
||||
case DPLANE_OP_VTEP_DELETE:
|
||||
case DPLANE_OP_NEIGH_DISCOVER:
|
||||
case DPLANE_OP_BR_PORT_UPDATE:
|
||||
case DPLANE_OP_IPTABLE_ADD:
|
||||
case DPLANE_OP_IPTABLE_DELETE:
|
||||
case DPLANE_OP_IPSET_ADD:
|
||||
case DPLANE_OP_IPSET_DELETE:
|
||||
case DPLANE_OP_IPSET_ENTRY_ADD:
|
||||
case DPLANE_OP_IPSET_ENTRY_DELETE:
|
||||
case DPLANE_OP_NEIGH_IP_INSTALL:
|
||||
case DPLANE_OP_NEIGH_IP_DELETE:
|
||||
case DPLANE_OP_NEIGH_TABLE_UPDATE:
|
||||
case DPLANE_OP_GRE_SET:
|
||||
case DPLANE_OP_INTF_ADDR_ADD:
|
||||
case DPLANE_OP_INTF_ADDR_DEL:
|
||||
case DPLANE_OP_INTF_NETCONFIG:
|
||||
case DPLANE_OP_INTF_INSTALL:
|
||||
case DPLANE_OP_INTF_UPDATE:
|
||||
case DPLANE_OP_INTF_DELETE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* DPDK provider callback.
|
||||
*/
|
||||
static void zd_dpdk_process_update(struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
switch (dplane_ctx_get_op(ctx)) {
|
||||
|
||||
case DPLANE_OP_RULE_ADD:
|
||||
case DPLANE_OP_RULE_UPDATE:
|
||||
case DPLANE_OP_RULE_DELETE:
|
||||
zd_dpdk_rule_update(ctx);
|
||||
break;
|
||||
case DPLANE_OP_NONE:
|
||||
case DPLANE_OP_ROUTE_INSTALL:
|
||||
case DPLANE_OP_ROUTE_UPDATE:
|
||||
case DPLANE_OP_ROUTE_DELETE:
|
||||
case DPLANE_OP_ROUTE_NOTIFY:
|
||||
case DPLANE_OP_NH_INSTALL:
|
||||
case DPLANE_OP_NH_UPDATE:
|
||||
case DPLANE_OP_NH_DELETE:
|
||||
case DPLANE_OP_LSP_INSTALL:
|
||||
case DPLANE_OP_LSP_UPDATE:
|
||||
case DPLANE_OP_LSP_DELETE:
|
||||
case DPLANE_OP_LSP_NOTIFY:
|
||||
case DPLANE_OP_PW_INSTALL:
|
||||
case DPLANE_OP_PW_UNINSTALL:
|
||||
case DPLANE_OP_SYS_ROUTE_ADD:
|
||||
case DPLANE_OP_SYS_ROUTE_DELETE:
|
||||
case DPLANE_OP_ADDR_INSTALL:
|
||||
case DPLANE_OP_ADDR_UNINSTALL:
|
||||
case DPLANE_OP_MAC_INSTALL:
|
||||
case DPLANE_OP_MAC_DELETE:
|
||||
case DPLANE_OP_NEIGH_INSTALL:
|
||||
case DPLANE_OP_NEIGH_UPDATE:
|
||||
case DPLANE_OP_NEIGH_DELETE:
|
||||
case DPLANE_OP_VTEP_ADD:
|
||||
case DPLANE_OP_VTEP_DELETE:
|
||||
case DPLANE_OP_NEIGH_DISCOVER:
|
||||
case DPLANE_OP_BR_PORT_UPDATE:
|
||||
case DPLANE_OP_IPTABLE_ADD:
|
||||
case DPLANE_OP_IPTABLE_DELETE:
|
||||
case DPLANE_OP_IPSET_ADD:
|
||||
case DPLANE_OP_IPSET_DELETE:
|
||||
case DPLANE_OP_IPSET_ENTRY_ADD:
|
||||
case DPLANE_OP_IPSET_ENTRY_DELETE:
|
||||
case DPLANE_OP_NEIGH_IP_INSTALL:
|
||||
case DPLANE_OP_NEIGH_IP_DELETE:
|
||||
case DPLANE_OP_NEIGH_TABLE_UPDATE:
|
||||
case DPLANE_OP_GRE_SET:
|
||||
case DPLANE_OP_INTF_ADDR_ADD:
|
||||
case DPLANE_OP_INTF_ADDR_DEL:
|
||||
case DPLANE_OP_INTF_NETCONFIG:
|
||||
case DPLANE_OP_INTF_INSTALL:
|
||||
case DPLANE_OP_INTF_UPDATE:
|
||||
case DPLANE_OP_INTF_DELETE:
|
||||
atomic_fetch_add_explicit(&dpdk_stat->ignored_updates, 1,
|
||||
memory_order_relaxed);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int zd_dpdk_process(struct zebra_dplane_provider *prov)
|
||||
{
|
||||
struct zebra_dplane_ctx *ctx;
|
||||
int counter, limit;
|
||||
|
||||
if (IS_ZEBRA_DEBUG_DPLANE_DPDK_DETAIL)
|
||||
zlog_debug("processing %s", dplane_provider_get_name(prov));
|
||||
|
||||
limit = dplane_provider_get_work_limit(prov);
|
||||
for (counter = 0; counter < limit; counter++) {
|
||||
ctx = dplane_provider_dequeue_in_ctx(prov);
|
||||
if (!ctx)
|
||||
break;
|
||||
|
||||
zd_dpdk_process_update(ctx);
|
||||
dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS);
|
||||
dplane_provider_enqueue_out_ctx(prov, ctx);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void zd_dpdk_port_show_entry(struct zd_dpdk_port *dport, struct vty *vty,
|
||||
int detail)
|
||||
{
|
||||
struct rte_eth_dev_info *dev_info;
|
||||
|
||||
dev_info = &dport->dev_info;
|
||||
if (detail) {
|
||||
vty_out(vty, "DPDK port: %u\n", dport->port_id);
|
||||
vty_out(vty, " Device: %s\n",
|
||||
dev_info->device ? dev_info->device->name : "-");
|
||||
vty_out(vty, " Driver: %s\n",
|
||||
dev_info->driver_name ? dev_info->driver_name : "-");
|
||||
vty_out(vty, " Interface: %s (%d)\n",
|
||||
ifindex2ifname(dev_info->if_index, VRF_DEFAULT),
|
||||
dev_info->if_index);
|
||||
vty_out(vty, " Switch: %s Domain: %u Port: %u\n",
|
||||
dev_info->switch_info.name,
|
||||
dev_info->switch_info.domain_id,
|
||||
dev_info->switch_info.port_id);
|
||||
vty_out(vty, "\n");
|
||||
} else {
|
||||
vty_out(vty, "%-4u %-16s %-16s %-16d %s,%u,%u\n",
|
||||
dport->port_id,
|
||||
dev_info->device ? dev_info->device->name : "-",
|
||||
ifindex2ifname(dev_info->if_index, VRF_DEFAULT),
|
||||
dev_info->if_index, dev_info->switch_info.name,
|
||||
dev_info->switch_info.domain_id,
|
||||
dev_info->switch_info.port_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static struct zd_dpdk_port *zd_dpdk_port_find_by_index(int ifindex)
|
||||
{
|
||||
int count;
|
||||
struct zd_dpdk_port *dport;
|
||||
struct rte_eth_dev_info *dev_info;
|
||||
|
||||
for (count = 0; count < RTE_MAX_ETHPORTS; ++count) {
|
||||
dport = &dpdk_ctx->dpdk_ports[count];
|
||||
if (!(dport->flags & ZD_DPDK_PORT_FLAG_INITED))
|
||||
continue;
|
||||
dev_info = &dport->dev_info;
|
||||
if (dev_info->if_index == (uint32_t)ifindex)
|
||||
return dport;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void zd_dpdk_port_show(struct vty *vty, uint16_t port_id, bool uj, int detail)
|
||||
{
|
||||
int count;
|
||||
struct zd_dpdk_port *dport;
|
||||
|
||||
/* XXX - support for json is yet to be added */
|
||||
if (uj)
|
||||
return;
|
||||
|
||||
if (!detail) {
|
||||
vty_out(vty, "%-4s %-16s %-16s %-16s %s\n", "Port", "Device",
|
||||
"IfName", "IfIndex", "sw,domain,port");
|
||||
}
|
||||
|
||||
for (count = 0; count < RTE_MAX_ETHPORTS; ++count) {
|
||||
dport = &dpdk_ctx->dpdk_ports[count];
|
||||
if (dport->flags & ZD_DPDK_PORT_FLAG_INITED)
|
||||
zd_dpdk_port_show_entry(dport, vty, detail);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void zd_dpdk_port_init(void)
|
||||
{
|
||||
struct zd_dpdk_port *dport;
|
||||
uint16_t port_id;
|
||||
struct rte_eth_dev_info *dev_info;
|
||||
int count;
|
||||
int rc;
|
||||
struct rte_flow_error error;
|
||||
|
||||
/* allocate a list of ports */
|
||||
dpdk_ctx->dpdk_ports =
|
||||
XCALLOC(MTYPE_DPDK_PORTS,
|
||||
sizeof(struct zd_dpdk_port) * RTE_MAX_ETHPORTS);
|
||||
|
||||
if (IS_ZEBRA_DEBUG_DPLANE_DPDK)
|
||||
zlog_debug("dpdk port init");
|
||||
count = 0;
|
||||
RTE_ETH_FOREACH_DEV(port_id)
|
||||
{
|
||||
if (IS_ZEBRA_DEBUG_DPLANE_DPDK)
|
||||
zlog_debug("dpdk port init %d", port_id);
|
||||
dport = &dpdk_ctx->dpdk_ports[count];
|
||||
count++;
|
||||
dport->port_id = port_id;
|
||||
dport->flags |= ZD_DPDK_PORT_FLAG_PROBED;
|
||||
dev_info = &dport->dev_info;
|
||||
if (rte_eth_dev_info_get(port_id, dev_info) < 0) {
|
||||
zlog_warn("failed to get dev info for %u, %s", port_id,
|
||||
rte_strerror(rte_errno));
|
||||
continue;
|
||||
}
|
||||
dport->flags |= ZD_DPDK_PORT_FLAG_INITED;
|
||||
if (IS_ZEBRA_DEBUG_DPLANE_DPDK)
|
||||
zlog_debug(
|
||||
"port %u, dev %s, ifI %d, sw_name %s, sw_domain %u, sw_port %u",
|
||||
port_id,
|
||||
dev_info->device ? dev_info->device->name : "-",
|
||||
dev_info->if_index, dev_info->switch_info.name,
|
||||
dev_info->switch_info.domain_id,
|
||||
dev_info->switch_info.port_id);
|
||||
if (rte_flow_isolate(port_id, 1, &error)) {
|
||||
if (IS_ZEBRA_DEBUG_DPLANE_DPDK)
|
||||
zlog_debug(
|
||||
"Flow isolate on port %u failed %d\n",
|
||||
port_id, error.type);
|
||||
} else {
|
||||
if (IS_ZEBRA_DEBUG_DPLANE_DPDK)
|
||||
zlog_debug("Flow isolate on port %u\n",
|
||||
port_id);
|
||||
}
|
||||
rc = rte_eth_dev_start(port_id);
|
||||
if (rc) {
|
||||
zlog_warn("DPDK port %d start error: %s", port_id,
|
||||
rte_strerror(-rc));
|
||||
continue;
|
||||
}
|
||||
if (IS_ZEBRA_DEBUG_DPLANE_DPDK)
|
||||
zlog_debug("DPDK port %d started in promiscuous mode ",
|
||||
port_id);
|
||||
}
|
||||
|
||||
if (!count) {
|
||||
if (IS_ZEBRA_DEBUG_DPLANE_DPDK)
|
||||
zlog_debug("no probed ethernet devices");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int zd_dpdk_init(void)
|
||||
{
|
||||
int rc;
|
||||
static const char *argv[] = {(char *)"/usr/lib/frr/zebra",
|
||||
(char *)"--"};
|
||||
|
||||
zd_dpdk_vty_init();
|
||||
|
||||
frr_with_privs (&zserv_privs) {
|
||||
rc = rte_eal_init(ARRAY_SIZE(argv), argv);
|
||||
}
|
||||
if (rc < 0) {
|
||||
zlog_warn("EAL init failed %s", rte_strerror(rte_errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
frr_with_privs (&zserv_privs) {
|
||||
zd_dpdk_port_init();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int zd_dpdk_start(struct zebra_dplane_provider *prov)
|
||||
{
|
||||
if (IS_ZEBRA_DEBUG_DPLANE_DPDK)
|
||||
zlog_debug("%s start", dplane_provider_get_name(prov));
|
||||
|
||||
return zd_dpdk_init();
|
||||
}
|
||||
|
||||
|
||||
static int zd_dpdk_finish(struct zebra_dplane_provider *prov, bool early)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (early) {
|
||||
if (IS_ZEBRA_DEBUG_DPLANE_DPDK)
|
||||
zlog_debug("%s early finish",
|
||||
dplane_provider_get_name(prov));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (IS_ZEBRA_DEBUG_DPLANE_DPDK)
|
||||
zlog_debug("%s finish", dplane_provider_get_name(prov));
|
||||
|
||||
|
||||
frr_with_privs (&zserv_privs) {
|
||||
rc = rte_eal_cleanup();
|
||||
}
|
||||
if (rc < 0)
|
||||
zlog_warn("EAL cleanup failed %s", rte_strerror(rte_errno));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int zd_dpdk_plugin_init(struct thread_master *tm)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = dplane_provider_register(
|
||||
plugin_name, DPLANE_PRIO_KERNEL, DPLANE_PROV_FLAGS_DEFAULT,
|
||||
zd_dpdk_start, zd_dpdk_process, zd_dpdk_finish, dpdk_ctx, NULL);
|
||||
|
||||
if (IS_ZEBRA_DEBUG_DPLANE_DPDK)
|
||||
zlog_debug("%s register status %d", plugin_name, ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int zd_dpdk_module_init(void)
|
||||
{
|
||||
hook_register(frr_late_init, zd_dpdk_plugin_init);
|
||||
return 0;
|
||||
}
|
||||
|
||||
FRR_MODULE_SETUP(.name = "dplane_dpdk", .version = "0.0.1",
|
||||
.description = "Data plane plugin using dpdk for hw offload",
|
||||
.init = zd_dpdk_module_init);
|
36
zebra/dpdk/zebra_dplane_dpdk.h
Normal file
36
zebra/dpdk/zebra_dplane_dpdk.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Zebra dataplane plugin for DPDK based hw offload
|
||||
*
|
||||
* Copyright (C) 2021 Nvidia
|
||||
* Anuradha Karuppiah
|
||||
*
|
||||
* 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 _ZEBRA_DPLANE_DPDK_H
|
||||
#define _ZEBRA_DPLANE_DPDK_H
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
|
||||
#define ZD_DPDK_INVALID_PORT 0xffff
|
||||
|
||||
extern void zd_dpdk_pbr_flows_show(struct vty *vty);
|
||||
extern void zd_dpdk_port_show(struct vty *vty, uint16_t port_id, bool uj,
|
||||
int detail);
|
||||
extern void zd_dpdk_stat_show(struct vty *vty);
|
||||
extern void zd_dpdk_vty_init(void);
|
||||
|
||||
#endif
|
61
zebra/dpdk/zebra_dplane_dpdk_private.h
Normal file
61
zebra/dpdk/zebra_dplane_dpdk_private.h
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Zebra dataplane plugin for DPDK based hw offload
|
||||
*
|
||||
* Copyright (C) 2021 Nvidia
|
||||
* Anuradha Karuppiah
|
||||
*
|
||||
* 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 _ZEBRA_DPLANE_DPDK_PRIVATE_H
|
||||
#define _ZEBRA_DPLANE_DPDK_PRIVATE_H
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
#include <rte_ethdev.h>
|
||||
|
||||
#include "zebra_dplane_dpdk.h"
|
||||
|
||||
/* match on eth, sip, dip, udp */
|
||||
#define ZD_PBR_PATTERN_MAX 6
|
||||
/* dec_ttl, set_smac, set_dmac, * phy_port, count
|
||||
*/
|
||||
#define ZD_PBR_ACTION_MAX 6
|
||||
|
||||
#define ZD_ETH_TYPE_IP 0x800
|
||||
|
||||
struct zd_dpdk_port {
|
||||
uint16_t port_id; /* dpdk port_id */
|
||||
struct rte_eth_dev_info dev_info; /* PCI info + driver name */
|
||||
uint32_t flags;
|
||||
#define ZD_DPDK_PORT_FLAG_PROBED (1 << 0)
|
||||
#define ZD_DPDK_PORT_FLAG_INITED (1 << 1)
|
||||
};
|
||||
|
||||
struct zd_dpdk_stat {
|
||||
_Atomic uint32_t ignored_updates;
|
||||
|
||||
_Atomic uint32_t rule_adds;
|
||||
_Atomic uint32_t rule_dels;
|
||||
};
|
||||
|
||||
struct zd_dpdk_ctx {
|
||||
/* Stats */
|
||||
struct zd_dpdk_stat stats;
|
||||
struct zd_dpdk_port *dpdk_ports;
|
||||
int dpdk_logtype;
|
||||
};
|
||||
|
||||
#endif
|
85
zebra/dpdk/zebra_dplane_dpdk_vty.c
Normal file
85
zebra/dpdk/zebra_dplane_dpdk_vty.c
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Zebra dataplane plugin for DPDK based hw offload
|
||||
*
|
||||
* Copyright (C) 2021 Nvidia
|
||||
* 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 "lib/json.h"
|
||||
#include "zebra/dpdk/zebra_dplane_dpdk.h"
|
||||
|
||||
#ifndef VTYSH_EXTRACT_PL
|
||||
#include "zebra/dpdk/zebra_dplane_dpdk_vty_clippy.c"
|
||||
#endif
|
||||
|
||||
#define ZD_STR "Zebra dataplane information\n"
|
||||
#define ZD_DPDK_STR "DPDK offload information\n"
|
||||
|
||||
DEFPY(zd_dpdk_show_counters, zd_dpdk_show_counters_cmd,
|
||||
"show dplane dpdk counters",
|
||||
SHOW_STR ZD_STR ZD_DPDK_STR "show counters\n")
|
||||
{
|
||||
zd_dpdk_stat_show(vty);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
DEFPY (zd_dpdk_show_ports,
|
||||
zd_dpdk_show_ports_cmd,
|
||||
"show dplane dpdk port [(1-32)$port_id] [detail$detail] [json$json]",
|
||||
SHOW_STR
|
||||
ZD_STR
|
||||
ZD_DPDK_STR
|
||||
"show port info\n"
|
||||
"DPDK port identifier\n"
|
||||
"Detailed information\n"
|
||||
JSON_STR)
|
||||
{
|
||||
bool uj = !!json;
|
||||
bool ud = !!detail;
|
||||
|
||||
if (!port_id)
|
||||
port_id = ZD_DPDK_INVALID_PORT;
|
||||
zd_dpdk_port_show(vty, port_id, uj, ud);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
DEFPY (zd_dpdk_show_pbr_flows,
|
||||
zd_dpdk_show_pbr_flows_cmd,
|
||||
"show dplane dpdk pbr flows",
|
||||
SHOW_STR
|
||||
ZD_STR
|
||||
ZD_DPDK_STR
|
||||
"show pbr info\n"
|
||||
"DPDK flows\n")
|
||||
{
|
||||
zd_dpdk_pbr_flows_show(vty);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void zd_dpdk_vty_init(void)
|
||||
{
|
||||
install_element(VIEW_NODE, &zd_dpdk_show_counters_cmd);
|
||||
install_element(VIEW_NODE, &zd_dpdk_show_ports_cmd);
|
||||
install_element(VIEW_NODE, &zd_dpdk_show_pbr_flows_cmd);
|
||||
}
|
@ -105,8 +105,12 @@ const struct option longopts[] = {
|
||||
#endif /* HAVE_NETLINK */
|
||||
{0}};
|
||||
|
||||
zebra_capabilities_t _caps_p[] = {
|
||||
ZCAP_NET_ADMIN, ZCAP_SYS_ADMIN, ZCAP_NET_RAW,
|
||||
zebra_capabilities_t _caps_p[] = {ZCAP_NET_ADMIN, ZCAP_SYS_ADMIN,
|
||||
ZCAP_NET_RAW,
|
||||
#ifdef HAVE_DPDK
|
||||
ZCAP_IPC_LOCK, ZCAP_READ_SEARCH,
|
||||
ZCAP_SYS_RAWIO
|
||||
#endif
|
||||
};
|
||||
|
||||
/* zebra privileges to run with */
|
||||
|
@ -80,6 +80,7 @@
|
||||
#include "zebra/zebra_errors.h"
|
||||
#include "zebra/zebra_evpn_mh.h"
|
||||
#include "zebra/zebra_trace.h"
|
||||
#include "zebra/zebra_neigh.h"
|
||||
|
||||
#ifndef AF_MPLS
|
||||
#define AF_MPLS 28
|
||||
@ -3882,10 +3883,10 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
|
||||
} else if (IS_ZEBRA_IF_BRIDGE(ifp))
|
||||
link_if = ifp;
|
||||
else {
|
||||
link_if = NULL;
|
||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||
zlog_debug(
|
||||
" Neighbor Entry received is not on a VLAN or a BRIDGE, ignoring");
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(&mac, 0, sizeof(mac));
|
||||
@ -3949,12 +3950,25 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
|
||||
*/
|
||||
local_inactive = false;
|
||||
|
||||
return zebra_vxlan_handle_kernel_neigh_update(
|
||||
ifp, link_if, &ip, &mac, ndm->ndm_state, is_ext,
|
||||
is_router, local_inactive, dp_static);
|
||||
/* Add local neighbors to the l3 interface database */
|
||||
if (is_ext)
|
||||
zebra_neigh_del(ifp, &ip);
|
||||
else
|
||||
zebra_neigh_add(ifp, &ip, &mac);
|
||||
|
||||
if (link_if)
|
||||
zebra_vxlan_handle_kernel_neigh_update(
|
||||
ifp, link_if, &ip, &mac, ndm->ndm_state,
|
||||
is_ext, is_router, local_inactive,
|
||||
dp_static);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return zebra_vxlan_handle_kernel_neigh_del(ifp, link_if, &ip);
|
||||
|
||||
zebra_neigh_del(ifp, &ip);
|
||||
if (link_if)
|
||||
zebra_vxlan_handle_kernel_neigh_del(ifp, link_if, &ip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||
@ -3967,7 +3981,11 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
|
||||
/* Process the delete - it may result in re-adding the neighbor if it is
|
||||
* a valid "remote" neighbor.
|
||||
*/
|
||||
return zebra_vxlan_handle_kernel_neigh_del(ifp, link_if, &ip);
|
||||
zebra_neigh_del(ifp, &ip);
|
||||
if (link_if)
|
||||
zebra_vxlan_handle_kernel_neigh_del(ifp, link_if, &ip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int netlink_neigh_table(struct nlmsghdr *h, ns_id_t ns_id, int startup)
|
||||
|
@ -20,6 +20,7 @@ vtysh_scan += \
|
||||
zebra/zebra_vty.c \
|
||||
zebra/zserv.c \
|
||||
zebra/zebra_vrf.c \
|
||||
zebra/dpdk/zebra_dplane_dpdk_vty.c \
|
||||
# end
|
||||
|
||||
# can be loaded as DSO - always include for vtysh
|
||||
@ -125,6 +126,7 @@ zebra_zebra_SOURCES = \
|
||||
zebra/zebra_vty.c \
|
||||
zebra/zebra_vxlan.c \
|
||||
zebra/zebra_evpn_mh.c \
|
||||
zebra/zebra_neigh.c \
|
||||
zebra/zserv.c \
|
||||
# end
|
||||
|
||||
@ -138,6 +140,7 @@ clippy_scan += \
|
||||
zebra/zebra_vty.c \
|
||||
zebra/zebra_srv6_vty.c \
|
||||
zebra/zebra_vrf.c \
|
||||
zebra/dpdk/zebra_dplane_dpdk_vty.c \
|
||||
# end
|
||||
|
||||
noinst_HEADERS += \
|
||||
@ -197,7 +200,10 @@ noinst_HEADERS += \
|
||||
zebra/zebra_vxlan.h \
|
||||
zebra/zebra_vxlan_private.h \
|
||||
zebra/zebra_evpn_mh.h \
|
||||
zebra/zebra_neigh.h \
|
||||
zebra/zserv.h \
|
||||
zebra/dpdk/zebra_dplane_dpdk.h \
|
||||
zebra/dpdk/zebra_dplane_dpdk_private.h \
|
||||
# end
|
||||
|
||||
zebra_zebra_irdp_la_SOURCES = \
|
||||
@ -255,3 +261,12 @@ zebra_zebra_SOURCES += \
|
||||
zebra/debug_nl.c \
|
||||
# end
|
||||
endif
|
||||
|
||||
if DP_DPDK
|
||||
module_LTLIBRARIES += zebra/zebra_dplane_dpdk.la
|
||||
endif
|
||||
|
||||
zebra_zebra_dplane_dpdk_la_SOURCES = zebra/dpdk/zebra_dplane_dpdk.c zebra/dpdk/zebra_dplane_dpdk_vty.c
|
||||
zebra_zebra_dplane_dpdk_la_LDFLAGS = -avoid-version -module -shared -export-dynamic -L/usr/local/lib -v
|
||||
zebra_zebra_dplane_dpdk_la_CFLAGS = $(DPDK_CFLAGS)
|
||||
zebra_zebra_dplane_dpdk_la_LIBADD = $(DPDK_LIBS)
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "zebra/rt.h"
|
||||
#include "zebra/debug.h"
|
||||
#include "zebra/zebra_pbr.h"
|
||||
#include "zebra/zebra_neigh.h"
|
||||
#include "printfrr.h"
|
||||
|
||||
/* Memory types */
|
||||
@ -265,6 +266,8 @@ struct dplane_ctx_rule {
|
||||
struct prefix src_ip;
|
||||
struct prefix dst_ip;
|
||||
uint8_t ip_proto;
|
||||
uint16_t src_port;
|
||||
uint16_t dst_port;
|
||||
|
||||
uint8_t action_pcp;
|
||||
uint16_t action_vlan_id;
|
||||
@ -273,6 +276,10 @@ struct dplane_ctx_rule {
|
||||
uint32_t action_queue_id;
|
||||
|
||||
char ifname[INTERFACE_NAMSIZ + 1];
|
||||
struct ethaddr smac;
|
||||
struct ethaddr dmac;
|
||||
int out_ifindex;
|
||||
intptr_t dp_flow_ptr;
|
||||
};
|
||||
|
||||
struct dplane_rule_info {
|
||||
@ -2144,6 +2151,34 @@ uint8_t dplane_ctx_rule_get_old_ipproto(const struct zebra_dplane_ctx *ctx)
|
||||
return ctx->u.rule.old.ip_proto;
|
||||
}
|
||||
|
||||
uint16_t dplane_ctx_rule_get_src_port(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return ctx->u.rule.new.src_port;
|
||||
}
|
||||
|
||||
uint16_t dplane_ctx_rule_get_old_src_port(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return ctx->u.rule.old.src_port;
|
||||
}
|
||||
|
||||
uint16_t dplane_ctx_rule_get_dst_port(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return ctx->u.rule.new.dst_port;
|
||||
}
|
||||
|
||||
uint16_t dplane_ctx_rule_get_old_dst_port(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return ctx->u.rule.old.dst_port;
|
||||
}
|
||||
|
||||
uint8_t dplane_ctx_rule_get_dsfield(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
@ -2258,6 +2293,51 @@ void dplane_ctx_get_pbr_ipset_entry(const struct zebra_dplane_ctx *ctx,
|
||||
memcpy(entry, &ctx->u.ipset_entry.entry, sizeof(struct zebra_pbr_ipset_entry));
|
||||
}
|
||||
|
||||
const struct ethaddr *
|
||||
dplane_ctx_rule_get_smac(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return &(ctx->u.rule.new.smac);
|
||||
}
|
||||
|
||||
const struct ethaddr *
|
||||
dplane_ctx_rule_get_dmac(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return &(ctx->u.rule.new.dmac);
|
||||
}
|
||||
|
||||
int dplane_ctx_rule_get_out_ifindex(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return ctx->u.rule.new.out_ifindex;
|
||||
}
|
||||
|
||||
intptr_t dplane_ctx_rule_get_old_dp_flow_ptr(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return ctx->u.rule.old.dp_flow_ptr;
|
||||
}
|
||||
|
||||
intptr_t dplane_ctx_rule_get_dp_flow_ptr(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return ctx->u.rule.new.dp_flow_ptr;
|
||||
}
|
||||
|
||||
void dplane_ctx_rule_set_dp_flow_ptr(struct zebra_dplane_ctx *ctx,
|
||||
intptr_t dp_flow_ptr)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
ctx->u.rule.new.dp_flow_ptr = dp_flow_ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* End of dplane context accessors
|
||||
*/
|
||||
@ -2976,6 +3056,8 @@ done:
|
||||
static void dplane_ctx_rule_init_single(struct dplane_ctx_rule *dplane_rule,
|
||||
struct zebra_pbr_rule *rule)
|
||||
{
|
||||
struct zebra_neigh_ent *n;
|
||||
|
||||
dplane_rule->priority = rule->rule.priority;
|
||||
dplane_rule->table = rule->rule.action.table;
|
||||
|
||||
@ -2983,6 +3065,8 @@ static void dplane_ctx_rule_init_single(struct dplane_ctx_rule *dplane_rule,
|
||||
dplane_rule->fwmark = rule->rule.filter.fwmark;
|
||||
dplane_rule->dsfield = rule->rule.filter.dsfield;
|
||||
dplane_rule->ip_proto = rule->rule.filter.ip_proto;
|
||||
dplane_rule->src_port = rule->rule.filter.src_port;
|
||||
dplane_rule->dst_port = rule->rule.filter.dst_port;
|
||||
prefix_copy(&(dplane_rule->dst_ip), &rule->rule.filter.dst_ip);
|
||||
prefix_copy(&(dplane_rule->src_ip), &rule->rule.filter.src_ip);
|
||||
|
||||
@ -2992,6 +3076,19 @@ static void dplane_ctx_rule_init_single(struct dplane_ctx_rule *dplane_rule,
|
||||
dplane_rule->action_queue_id = rule->rule.action.queue_id;
|
||||
|
||||
strlcpy(dplane_rule->ifname, rule->ifname, INTERFACE_NAMSIZ);
|
||||
dplane_rule->dp_flow_ptr = rule->action.dp_flow_ptr;
|
||||
n = rule->action.neigh;
|
||||
if (n && (n->flags & ZEBRA_NEIGH_ENT_ACTIVE)) {
|
||||
struct interface *ifp = if_lookup_by_index_per_ns(
|
||||
zebra_ns_lookup(NS_DEFAULT), n->ifindex);
|
||||
if (ifp) {
|
||||
dplane_rule->out_ifindex = n->ifindex;
|
||||
memcpy(&dplane_rule->dmac, &n->mac, ETH_ALEN);
|
||||
memcpy(&dplane_rule->smac, ifp->hw_addr, ETH_ALEN);
|
||||
} else {
|
||||
dplane_rule->out_ifindex = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3031,8 +3128,13 @@ static int dplane_ctx_rule_init(struct zebra_dplane_ctx *ctx,
|
||||
ctx->u.rule.seq = new_rule->rule.seq;
|
||||
|
||||
dplane_ctx_rule_init_single(&ctx->u.rule.new, new_rule);
|
||||
if (op == DPLANE_OP_RULE_UPDATE)
|
||||
if (op == DPLANE_OP_RULE_UPDATE) {
|
||||
dplane_ctx_rule_init_single(&ctx->u.rule.old, old_rule);
|
||||
/* clear the dp_flow_ptr in the old_rule - it is about to be
|
||||
* deleted
|
||||
*/
|
||||
old_rule->action.dp_flow_ptr = (intptr_t)NULL;
|
||||
}
|
||||
|
||||
return AOK;
|
||||
}
|
||||
|
@ -547,6 +547,10 @@ uint8_t dplane_ctx_rule_get_dsfield(const struct zebra_dplane_ctx *ctx);
|
||||
uint8_t dplane_ctx_rule_get_old_dsfield(const struct zebra_dplane_ctx *ctx);
|
||||
uint8_t dplane_ctx_rule_get_ipproto(const struct zebra_dplane_ctx *ctx);
|
||||
uint8_t dplane_ctx_rule_get_old_ipproto(const struct zebra_dplane_ctx *ctx);
|
||||
uint16_t dplane_ctx_rule_get_src_port(const struct zebra_dplane_ctx *ctx);
|
||||
uint16_t dplane_ctx_rule_get_old_src_port(const struct zebra_dplane_ctx *ctx);
|
||||
uint16_t dplane_ctx_rule_get_dst_port(const struct zebra_dplane_ctx *ctx);
|
||||
uint16_t dplane_ctx_rule_get_old_dst_port(const struct zebra_dplane_ctx *ctx);
|
||||
const struct prefix *
|
||||
dplane_ctx_rule_get_src_ip(const struct zebra_dplane_ctx *ctx);
|
||||
const struct prefix *
|
||||
@ -555,6 +559,16 @@ const struct prefix *
|
||||
dplane_ctx_rule_get_dst_ip(const struct zebra_dplane_ctx *ctx);
|
||||
const struct prefix *
|
||||
dplane_ctx_rule_get_old_dst_ip(const struct zebra_dplane_ctx *ctx);
|
||||
const struct ethaddr *
|
||||
dplane_ctx_rule_get_smac(const struct zebra_dplane_ctx *ctx);
|
||||
const struct ethaddr *
|
||||
dplane_ctx_rule_get_dmac(const struct zebra_dplane_ctx *ctx);
|
||||
int dplane_ctx_rule_get_out_ifindex(const struct zebra_dplane_ctx *ctx);
|
||||
intptr_t dplane_ctx_rule_get_dp_flow_ptr(const struct zebra_dplane_ctx *ctx);
|
||||
intptr_t
|
||||
dplane_ctx_rule_get_old_dp_flow_ptr(const struct zebra_dplane_ctx *ctx);
|
||||
void dplane_ctx_rule_set_dp_flow_ptr(struct zebra_dplane_ctx *ctx,
|
||||
intptr_t dp_flow_ptr);
|
||||
/* Accessors for policy based routing iptable information */
|
||||
struct zebra_pbr_iptable;
|
||||
void dplane_ctx_get_pbr_iptable(const struct zebra_dplane_ctx *ctx,
|
||||
|
279
zebra/zebra_neigh.c
Normal file
279
zebra/zebra_neigh.c
Normal file
@ -0,0 +1,279 @@
|
||||
/*
|
||||
* Zebra neighbor table management
|
||||
*
|
||||
* Copyright (C) 2021 Nvidia
|
||||
* Anuradha Karuppiah
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
#include "command.h"
|
||||
#include "hash.h"
|
||||
#include "if.h"
|
||||
#include "jhash.h"
|
||||
#include "linklist.h"
|
||||
#include "log.h"
|
||||
#include "memory.h"
|
||||
#include "prefix.h"
|
||||
#include "stream.h"
|
||||
#include "table.h"
|
||||
|
||||
#include "zebra/zebra_router.h"
|
||||
#include "zebra/debug.h"
|
||||
#include "zebra/interface.h"
|
||||
#include "zebra/rib.h"
|
||||
#include "zebra/rt.h"
|
||||
#include "zebra/rt_netlink.h"
|
||||
#include "zebra/zebra_errors.h"
|
||||
#include "zebra/interface.h"
|
||||
#include "zebra/zebra_neigh.h"
|
||||
#include "zebra/zebra_pbr.h"
|
||||
|
||||
DEFINE_MTYPE_STATIC(ZEBRA, ZNEIGH_INFO, "Zebra neigh table");
|
||||
DEFINE_MTYPE_STATIC(ZEBRA, ZNEIGH_ENT, "Zebra neigh entry");
|
||||
|
||||
static int zebra_neigh_rb_cmp(const struct zebra_neigh_ent *n1,
|
||||
const struct zebra_neigh_ent *n2)
|
||||
{
|
||||
if (n1->ifindex < n2->ifindex)
|
||||
return -1;
|
||||
|
||||
if (n1->ifindex > n2->ifindex)
|
||||
return 1;
|
||||
|
||||
if (n1->ip.ipa_type < n2->ip.ipa_type)
|
||||
return -1;
|
||||
|
||||
if (n1->ip.ipa_type > n2->ip.ipa_type)
|
||||
return 1;
|
||||
|
||||
if (n1->ip.ipa_type == AF_INET) {
|
||||
if (n1->ip.ipaddr_v4.s_addr < n2->ip.ipaddr_v4.s_addr)
|
||||
return -1;
|
||||
|
||||
if (n1->ip.ipaddr_v4.s_addr > n2->ip.ipaddr_v4.s_addr)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return memcmp(&n1->ip.ipaddr_v6, &n2->ip.ipaddr_v6, IPV6_MAX_BYTELEN);
|
||||
}
|
||||
RB_GENERATE(zebra_neigh_rb_head, zebra_neigh_ent, rb_node, zebra_neigh_rb_cmp);
|
||||
|
||||
static struct zebra_neigh_ent *zebra_neigh_find(ifindex_t ifindex,
|
||||
struct ipaddr *ip)
|
||||
{
|
||||
struct zebra_neigh_ent tmp;
|
||||
|
||||
tmp.ifindex = ifindex;
|
||||
memcpy(&tmp.ip, ip, sizeof(*ip));
|
||||
return RB_FIND(zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree, &tmp);
|
||||
}
|
||||
|
||||
static struct zebra_neigh_ent *
|
||||
zebra_neigh_new(ifindex_t ifindex, struct ipaddr *ip, struct ethaddr *mac)
|
||||
{
|
||||
struct zebra_neigh_ent *n;
|
||||
|
||||
n = XCALLOC(MTYPE_ZNEIGH_ENT, sizeof(struct zebra_neigh_ent));
|
||||
|
||||
memcpy(&n->ip, ip, sizeof(*ip));
|
||||
n->ifindex = ifindex;
|
||||
if (mac) {
|
||||
memcpy(&n->mac, mac, sizeof(*mac));
|
||||
n->flags |= ZEBRA_NEIGH_ENT_ACTIVE;
|
||||
}
|
||||
|
||||
/* Add to rb_tree */
|
||||
if (RB_INSERT(zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree, n)) {
|
||||
XFREE(MTYPE_ZNEIGH_ENT, n);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Initialise the pbr rule list */
|
||||
n->pbr_rule_list = list_new();
|
||||
listset_app_node_mem(n->pbr_rule_list);
|
||||
|
||||
if (IS_ZEBRA_DEBUG_NEIGH)
|
||||
zlog_debug("zebra neigh new if %d %pIA %pEA", n->ifindex,
|
||||
&n->ip, &n->mac);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static void zebra_neigh_pbr_rules_update(struct zebra_neigh_ent *n)
|
||||
{
|
||||
struct zebra_pbr_rule *rule;
|
||||
struct listnode *node;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(n->pbr_rule_list, node, rule))
|
||||
dplane_pbr_rule_update(rule, rule);
|
||||
}
|
||||
|
||||
static void zebra_neigh_free(struct zebra_neigh_ent *n)
|
||||
{
|
||||
if (listcount(n->pbr_rule_list)) {
|
||||
/* if rules are still using the neigh mark it as inactive and
|
||||
* update the dataplane
|
||||
*/
|
||||
if (n->flags & ZEBRA_NEIGH_ENT_ACTIVE) {
|
||||
n->flags &= ~ZEBRA_NEIGH_ENT_ACTIVE;
|
||||
memset(&n->mac, 0, sizeof(n->mac));
|
||||
}
|
||||
zebra_neigh_pbr_rules_update(n);
|
||||
return;
|
||||
}
|
||||
if (IS_ZEBRA_DEBUG_NEIGH)
|
||||
zlog_debug("zebra neigh free if %d %pIA %pEA", n->ifindex,
|
||||
&n->ip, &n->mac);
|
||||
|
||||
/* cleanup resources maintained against the neigh */
|
||||
list_delete(&n->pbr_rule_list);
|
||||
|
||||
RB_REMOVE(zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree, n);
|
||||
|
||||
XFREE(MTYPE_ZNEIGH_ENT, n);
|
||||
}
|
||||
|
||||
/* kernel neigh del */
|
||||
void zebra_neigh_del(struct interface *ifp, struct ipaddr *ip)
|
||||
{
|
||||
struct zebra_neigh_ent *n;
|
||||
|
||||
if (IS_ZEBRA_DEBUG_NEIGH)
|
||||
zlog_debug("zebra neigh del if %s/%d %pIA", ifp->name,
|
||||
ifp->ifindex, ip);
|
||||
|
||||
n = zebra_neigh_find(ifp->ifindex, ip);
|
||||
if (!n)
|
||||
return;
|
||||
zebra_neigh_free(n);
|
||||
}
|
||||
|
||||
/* kernel neigh add */
|
||||
void zebra_neigh_add(struct interface *ifp, struct ipaddr *ip,
|
||||
struct ethaddr *mac)
|
||||
{
|
||||
struct zebra_neigh_ent *n;
|
||||
|
||||
if (IS_ZEBRA_DEBUG_NEIGH)
|
||||
zlog_debug("zebra neigh add if %s/%d %pIA %pEA", ifp->name,
|
||||
ifp->ifindex, ip, mac);
|
||||
|
||||
n = zebra_neigh_find(ifp->ifindex, ip);
|
||||
if (n) {
|
||||
if (!memcmp(&n->mac, mac, sizeof(*mac)))
|
||||
return;
|
||||
|
||||
memcpy(&n->mac, mac, sizeof(*mac));
|
||||
n->flags |= ZEBRA_NEIGH_ENT_ACTIVE;
|
||||
|
||||
/* update rules linked to the neigh */
|
||||
zebra_neigh_pbr_rules_update(n);
|
||||
} else {
|
||||
zebra_neigh_new(ifp->ifindex, ip, mac);
|
||||
}
|
||||
}
|
||||
|
||||
void zebra_neigh_deref(struct zebra_pbr_rule *rule)
|
||||
{
|
||||
struct zebra_neigh_ent *n = rule->action.neigh;
|
||||
|
||||
if (IS_ZEBRA_DEBUG_NEIGH)
|
||||
zlog_debug("zebra neigh deref if %d %pIA by pbr rule %u",
|
||||
n->ifindex, &n->ip, rule->rule.seq);
|
||||
|
||||
rule->action.neigh = NULL;
|
||||
/* remove rule from the list and free if it is inactive */
|
||||
list_delete_node(n->pbr_rule_list, &rule->action.neigh_listnode);
|
||||
if (!(n->flags & ZEBRA_NEIGH_ENT_ACTIVE))
|
||||
zebra_neigh_free(n);
|
||||
}
|
||||
|
||||
/* XXX - this needs to work with evpn's neigh read */
|
||||
static void zebra_neigh_read_on_first_ref(void)
|
||||
{
|
||||
static bool neigh_read_done;
|
||||
|
||||
if (!neigh_read_done) {
|
||||
neigh_read(zebra_ns_lookup(NS_DEFAULT));
|
||||
neigh_read_done = true;
|
||||
}
|
||||
}
|
||||
|
||||
void zebra_neigh_ref(int ifindex, struct ipaddr *ip,
|
||||
struct zebra_pbr_rule *rule)
|
||||
{
|
||||
struct zebra_neigh_ent *n;
|
||||
|
||||
if (IS_ZEBRA_DEBUG_NEIGH)
|
||||
zlog_debug("zebra neigh ref if %d %pIA by pbr rule %u", ifindex,
|
||||
ip, rule->rule.seq);
|
||||
|
||||
zebra_neigh_read_on_first_ref();
|
||||
n = zebra_neigh_find(ifindex, ip);
|
||||
if (!n)
|
||||
n = zebra_neigh_new(ifindex, ip, NULL);
|
||||
|
||||
/* link the pbr entry to the neigh */
|
||||
if (rule->action.neigh == n)
|
||||
return;
|
||||
|
||||
if (rule->action.neigh)
|
||||
zebra_neigh_deref(rule);
|
||||
|
||||
rule->action.neigh = n;
|
||||
listnode_init(&rule->action.neigh_listnode, rule);
|
||||
listnode_add(n->pbr_rule_list, &rule->action.neigh_listnode);
|
||||
}
|
||||
|
||||
static void zebra_neigh_show_one(struct vty *vty, struct zebra_neigh_ent *n)
|
||||
{
|
||||
char mac_buf[ETHER_ADDR_STRLEN];
|
||||
char ip_buf[INET6_ADDRSTRLEN];
|
||||
struct interface *ifp;
|
||||
|
||||
ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT),
|
||||
n->ifindex);
|
||||
ipaddr2str(&n->ip, ip_buf, sizeof(ip_buf));
|
||||
prefix_mac2str(&n->mac, mac_buf, sizeof(mac_buf));
|
||||
vty_out(vty, "%-20s %-30s %-18s %u\n", ifp ? ifp->name : "-", ip_buf,
|
||||
mac_buf, listcount(n->pbr_rule_list));
|
||||
}
|
||||
|
||||
void zebra_neigh_show(struct vty *vty)
|
||||
{
|
||||
struct zebra_neigh_ent *n;
|
||||
|
||||
vty_out(vty, "%-20s %-30s %-18s %s\n", "Interface", "Neighbor", "MAC",
|
||||
"#Rules");
|
||||
RB_FOREACH (n, zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree)
|
||||
zebra_neigh_show_one(vty, n);
|
||||
}
|
||||
|
||||
void zebra_neigh_init(void)
|
||||
{
|
||||
zneigh_info = XCALLOC(MTYPE_ZNEIGH_INFO, sizeof(*zrouter.neigh_info));
|
||||
RB_INIT(zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree);
|
||||
}
|
||||
|
||||
void zebra_neigh_terminate(void)
|
||||
{
|
||||
if (!zrouter.neigh_info)
|
||||
return;
|
||||
|
||||
XFREE(MTYPE_ZNEIGH_INFO, zneigh_info);
|
||||
}
|
64
zebra/zebra_neigh.h
Normal file
64
zebra/zebra_neigh.h
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Zebra neighbor table management
|
||||
*
|
||||
* Copyright (C) 2021 Nvidia
|
||||
* Anuradha Karuppiah
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _ZEBRA_NEIGH_H
|
||||
#define _ZEBRA_NEIGH_H
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
#include "if.h"
|
||||
|
||||
#define zneigh_info zrouter.neigh_info
|
||||
|
||||
struct zebra_neigh_ent {
|
||||
ifindex_t ifindex;
|
||||
struct ipaddr ip;
|
||||
|
||||
struct ethaddr mac;
|
||||
|
||||
uint32_t flags;
|
||||
#define ZEBRA_NEIGH_ENT_ACTIVE (1 << 0) /* can be used for traffic */
|
||||
|
||||
/* memory used for adding the neigt entry to zneigh_info->es_rb_tree */
|
||||
RB_ENTRY(zebra_neigh_ent) rb_node;
|
||||
|
||||
/* list of pbr rules associated with this neigh */
|
||||
struct list *pbr_rule_list;
|
||||
};
|
||||
RB_HEAD(zebra_neigh_rb_head, zebra_neigh_ent);
|
||||
RB_PROTOTYPE(zebra_neigh_rb_head, zebra_neigh_ent, rb_node, zebra_es_rb_cmp);
|
||||
|
||||
struct zebra_neigh_info {
|
||||
/* RB tree of neighbor entries */
|
||||
struct zebra_neigh_rb_head neigh_rb_tree;
|
||||
};
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
extern void zebra_neigh_add(struct interface *ifp, struct ipaddr *ip,
|
||||
struct ethaddr *mac);
|
||||
extern void zebra_neigh_del(struct interface *ifp, struct ipaddr *ip);
|
||||
extern void zebra_neigh_show(struct vty *vty);
|
||||
extern void zebra_neigh_init(void);
|
||||
extern void zebra_neigh_terminate(void);
|
||||
extern void zebra_neigh_deref(struct zebra_pbr_rule *rule);
|
||||
extern void zebra_neigh_ref(int ifindex, struct ipaddr *ip,
|
||||
struct zebra_pbr_rule *rule);
|
||||
|
||||
#endif /* _ZEBRA_NEIGH_H */
|
@ -32,6 +32,7 @@
|
||||
#include "zebra/zapi_msg.h"
|
||||
#include "zebra/zserv.h"
|
||||
#include "zebra/debug.h"
|
||||
#include "zebra/zebra_neigh.h"
|
||||
|
||||
/* definitions */
|
||||
DEFINE_MTYPE_STATIC(ZEBRA, PBR_IPTABLE_IFNAME, "PBR interface list");
|
||||
@ -123,6 +124,12 @@ static const struct message fragment_value_str[] = {
|
||||
{0}
|
||||
};
|
||||
|
||||
struct zebra_pbr_env_display {
|
||||
struct zebra_ns *zns;
|
||||
struct vty *vty;
|
||||
char *name;
|
||||
};
|
||||
|
||||
/* static function declarations */
|
||||
DEFINE_HOOK(zebra_pbr_ipset_entry_get_stat,
|
||||
(struct zebra_pbr_ipset_entry *ipset, uint64_t *pkts,
|
||||
@ -143,6 +150,9 @@ DEFINE_HOOK(zebra_pbr_ipset_entry_update,
|
||||
DEFINE_HOOK(zebra_pbr_ipset_update,
|
||||
(int cmd, struct zebra_pbr_ipset *ipset), (cmd, ipset));
|
||||
|
||||
/* resolve nexthop for dataplane (dpdk) programming */
|
||||
static bool zebra_pbr_expand_action;
|
||||
|
||||
/* Private functions */
|
||||
|
||||
/* Public functions */
|
||||
@ -475,24 +485,181 @@ static void *pbr_rule_alloc_intern(void *arg)
|
||||
return new;
|
||||
}
|
||||
|
||||
static int pbr_rule_release(struct zebra_pbr_rule *rule)
|
||||
static struct zebra_pbr_rule *pbr_rule_free(struct zebra_pbr_rule *hash_data,
|
||||
bool free_data)
|
||||
{
|
||||
if (hash_data->action.neigh)
|
||||
zebra_neigh_deref(hash_data);
|
||||
hash_release(zrouter.rules_hash, hash_data);
|
||||
if (free_data) {
|
||||
XFREE(MTYPE_TMP, hash_data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return hash_data;
|
||||
}
|
||||
|
||||
static struct zebra_pbr_rule *pbr_rule_release(struct zebra_pbr_rule *rule,
|
||||
bool free_data)
|
||||
{
|
||||
struct zebra_pbr_rule *lookup;
|
||||
|
||||
lookup = hash_lookup(zrouter.rules_hash, rule);
|
||||
|
||||
if (!lookup)
|
||||
return -ENOENT;
|
||||
return NULL;
|
||||
|
||||
hash_release(zrouter.rules_hash, lookup);
|
||||
XFREE(MTYPE_TMP, lookup);
|
||||
return pbr_rule_free(lookup, free_data);
|
||||
}
|
||||
|
||||
return 0;
|
||||
void zebra_pbr_show_rule_unit(struct zebra_pbr_rule *rule, struct vty *vty)
|
||||
{
|
||||
struct pbr_rule *prule = &rule->rule;
|
||||
struct zebra_pbr_action *zaction = &rule->action;
|
||||
|
||||
vty_out(vty, "Rules if %s\n", rule->ifname);
|
||||
vty_out(vty, " Seq %u pri %u\n", prule->seq, prule->priority);
|
||||
if (prule->filter.filter_bm & PBR_FILTER_SRC_IP)
|
||||
vty_out(vty, " SRC IP Match: %pFX\n", &prule->filter.src_ip);
|
||||
if (prule->filter.filter_bm & PBR_FILTER_DST_IP)
|
||||
vty_out(vty, " DST IP Match: %pFX\n", &prule->filter.dst_ip);
|
||||
if (prule->filter.filter_bm & PBR_FILTER_IP_PROTOCOL)
|
||||
vty_out(vty, " IP protocol Match: %u\n",
|
||||
prule->filter.ip_proto);
|
||||
if (prule->filter.filter_bm & PBR_FILTER_SRC_PORT)
|
||||
vty_out(vty, " SRC Port Match: %u\n", prule->filter.src_port);
|
||||
if (prule->filter.filter_bm & PBR_FILTER_DST_PORT)
|
||||
vty_out(vty, " DST Port Match: %u\n", prule->filter.dst_port);
|
||||
|
||||
if (prule->filter.filter_bm & PBR_FILTER_DSFIELD) {
|
||||
vty_out(vty, " DSCP Match: %u\n",
|
||||
(prule->filter.dsfield & PBR_DSFIELD_DSCP) >> 2);
|
||||
vty_out(vty, " ECN Match: %u\n",
|
||||
prule->filter.dsfield & PBR_DSFIELD_ECN);
|
||||
}
|
||||
|
||||
if (prule->filter.filter_bm & PBR_FILTER_FWMARK)
|
||||
vty_out(vty, " MARK Match: %u\n", prule->filter.fwmark);
|
||||
|
||||
vty_out(vty, " Tableid: %u\n", prule->action.table);
|
||||
if (zaction->afi == AFI_IP)
|
||||
vty_out(vty, " Action: nh: %pI4 intf: %s\n",
|
||||
&zaction->gate.ipv4,
|
||||
ifindex2ifname(zaction->ifindex, rule->vrf_id));
|
||||
if (zaction->afi == AFI_IP6)
|
||||
vty_out(vty, " Action: nh: %pI6 intf: %s\n",
|
||||
&zaction->gate.ipv6,
|
||||
ifindex2ifname(zaction->ifindex, rule->vrf_id));
|
||||
if (zaction->neigh && (zaction->neigh->flags & ZEBRA_NEIGH_ENT_ACTIVE))
|
||||
vty_out(vty, " Action: mac: %pEA\n", &zaction->neigh->mac);
|
||||
}
|
||||
|
||||
static int zebra_pbr_show_rules_walkcb(struct hash_bucket *bucket, void *arg)
|
||||
{
|
||||
struct zebra_pbr_rule *rule = (struct zebra_pbr_rule *)bucket->data;
|
||||
struct zebra_pbr_env_display *env = (struct zebra_pbr_env_display *)arg;
|
||||
struct vty *vty = env->vty;
|
||||
|
||||
zebra_pbr_show_rule_unit(rule, vty);
|
||||
|
||||
return HASHWALK_CONTINUE;
|
||||
}
|
||||
|
||||
void zebra_pbr_show_rule(struct vty *vty)
|
||||
{
|
||||
struct zebra_pbr_env_display env;
|
||||
|
||||
env.vty = vty;
|
||||
hash_walk(zrouter.rules_hash, zebra_pbr_show_rules_walkcb, &env);
|
||||
}
|
||||
|
||||
void zebra_pbr_config_write(struct vty *vty)
|
||||
{
|
||||
if (zebra_pbr_expand_action)
|
||||
vty_out(vty, "pbr nexthop-resolve\n");
|
||||
}
|
||||
|
||||
void zebra_pbr_expand_action_update(bool enable)
|
||||
{
|
||||
zebra_pbr_expand_action = enable;
|
||||
}
|
||||
|
||||
static void zebra_pbr_expand_rule(struct zebra_pbr_rule *rule)
|
||||
{
|
||||
struct prefix p;
|
||||
struct route_table *table;
|
||||
struct route_node *rn;
|
||||
rib_dest_t *dest;
|
||||
struct route_entry *re;
|
||||
const struct nexthop_group *nhg;
|
||||
const struct nexthop *nexthop;
|
||||
struct zebra_pbr_action *action = &rule->action;
|
||||
struct ipaddr ip;
|
||||
|
||||
if (!zebra_pbr_expand_action)
|
||||
return;
|
||||
|
||||
table = zebra_vrf_get_table_with_table_id(
|
||||
AFI_IP, SAFI_UNICAST, VRF_DEFAULT, rule->rule.action.table);
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
memset(&p, 0, sizeof(p));
|
||||
p.family = AF_INET;
|
||||
|
||||
rn = route_node_lookup(table, &p);
|
||||
if (!rn)
|
||||
return;
|
||||
|
||||
dest = rib_dest_from_rnode(rn);
|
||||
re = dest->selected_fib;
|
||||
if (!re) {
|
||||
route_unlock_node(rn);
|
||||
return;
|
||||
}
|
||||
|
||||
nhg = rib_get_fib_nhg(re);
|
||||
if (!nhg) {
|
||||
route_unlock_node(rn);
|
||||
return;
|
||||
}
|
||||
|
||||
nexthop = nhg->nexthop;
|
||||
if (nexthop) {
|
||||
switch (nexthop->type) {
|
||||
case NEXTHOP_TYPE_IPV4:
|
||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||
action->afi = AFI_IP;
|
||||
action->gate.ipv4 = nexthop->gate.ipv4;
|
||||
action->ifindex = nexthop->ifindex;
|
||||
ip.ipa_type = AF_INET;
|
||||
ip.ipaddr_v4 = action->gate.ipv4;
|
||||
zebra_neigh_ref(action->ifindex, &ip, rule);
|
||||
break;
|
||||
|
||||
case NEXTHOP_TYPE_IPV6:
|
||||
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||
action->afi = AFI_IP6;
|
||||
action->gate.ipv6 = nexthop->gate.ipv6;
|
||||
action->ifindex = nexthop->ifindex;
|
||||
ip.ipa_type = AF_INET6;
|
||||
ip.ipaddr_v6 = action->gate.ipv6;
|
||||
zebra_neigh_ref(action->ifindex, &ip, rule);
|
||||
break;
|
||||
|
||||
default:
|
||||
action->afi = AFI_UNSPEC;
|
||||
}
|
||||
}
|
||||
|
||||
route_unlock_node(rn);
|
||||
}
|
||||
|
||||
void zebra_pbr_add_rule(struct zebra_pbr_rule *rule)
|
||||
{
|
||||
struct zebra_pbr_rule *found;
|
||||
struct zebra_pbr_rule *old;
|
||||
struct zebra_pbr_rule *new;
|
||||
|
||||
/**
|
||||
* Check if we already have it (this checks via a unique ID, walking
|
||||
@ -508,13 +675,20 @@ void zebra_pbr_add_rule(struct zebra_pbr_rule *rule)
|
||||
__func__, rule->rule.seq, rule->rule.priority,
|
||||
rule->rule.unique, rule->rule.ifname);
|
||||
|
||||
(void)dplane_pbr_rule_update(found, rule);
|
||||
|
||||
if (pbr_rule_release(found))
|
||||
zlog_debug(
|
||||
"%s: Rule being updated we know nothing about",
|
||||
__func__);
|
||||
/* remove the old entry from the hash but don't free the hash
|
||||
* data yet as we need it for the dplane update
|
||||
*/
|
||||
old = pbr_rule_release(found, false);
|
||||
|
||||
/* insert new entry into hash */
|
||||
new = hash_get(zrouter.rules_hash, rule, pbr_rule_alloc_intern);
|
||||
/* expand the action if needed */
|
||||
zebra_pbr_expand_rule(new);
|
||||
/* update dataplane */
|
||||
(void)dplane_pbr_rule_update(found, new);
|
||||
/* release the old hash data */
|
||||
if (old)
|
||||
XFREE(MTYPE_TMP, old);
|
||||
} else {
|
||||
if (IS_ZEBRA_DEBUG_PBR)
|
||||
zlog_debug(
|
||||
@ -522,10 +696,13 @@ void zebra_pbr_add_rule(struct zebra_pbr_rule *rule)
|
||||
__func__, rule->rule.seq, rule->rule.priority,
|
||||
rule->rule.unique, rule->rule.ifname);
|
||||
|
||||
(void)dplane_pbr_rule_add(rule);
|
||||
/* insert new entry into hash */
|
||||
new = hash_get(zrouter.rules_hash, rule, pbr_rule_alloc_intern);
|
||||
/* expand the action if needed */
|
||||
zebra_pbr_expand_rule(new);
|
||||
(void)dplane_pbr_rule_add(new);
|
||||
}
|
||||
|
||||
(void)hash_get(zrouter.rules_hash, rule, pbr_rule_alloc_intern);
|
||||
}
|
||||
|
||||
void zebra_pbr_del_rule(struct zebra_pbr_rule *rule)
|
||||
@ -537,7 +714,7 @@ void zebra_pbr_del_rule(struct zebra_pbr_rule *rule)
|
||||
|
||||
(void)dplane_pbr_rule_delete(rule);
|
||||
|
||||
if (pbr_rule_release(rule))
|
||||
if (pbr_rule_release(rule, true))
|
||||
zlog_debug("%s: Rule being deleted we know nothing about",
|
||||
__func__);
|
||||
}
|
||||
@ -610,12 +787,7 @@ static void zebra_pbr_cleanup_rules(struct hash_bucket *b, void *data)
|
||||
|
||||
if (rule->sock == *sock) {
|
||||
(void)dplane_pbr_rule_delete(rule);
|
||||
if (hash_release(zrouter.rules_hash, rule))
|
||||
XFREE(MTYPE_TMP, rule);
|
||||
else
|
||||
zlog_debug(
|
||||
"%s: Rule seq: %u is being cleaned but we can't find it in our tables",
|
||||
__func__, rule->rule.seq);
|
||||
pbr_rule_free(rule, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -915,11 +1087,6 @@ struct zebra_pbr_ipset_entry_unique_display {
|
||||
struct zebra_ns *zns;
|
||||
};
|
||||
|
||||
struct zebra_pbr_env_display {
|
||||
struct zebra_ns *zns;
|
||||
struct vty *vty;
|
||||
char *name;
|
||||
};
|
||||
|
||||
static const char *zebra_pbr_prefix2str(union prefixconstptr pu,
|
||||
char *str, int size)
|
||||
|
@ -36,6 +36,24 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct zebra_pbr_action {
|
||||
afi_t afi;
|
||||
|
||||
/* currently only one nexthop is supported */
|
||||
union g_addr gate;
|
||||
|
||||
/* dest-interface */
|
||||
ifindex_t ifindex;
|
||||
|
||||
/* dataplane info */
|
||||
intptr_t dp_flow_ptr;
|
||||
|
||||
/* neigh */
|
||||
struct zebra_neigh_ent *neigh;
|
||||
/* zebra_pbr_rule is linked to neigh via neigh_listnode */
|
||||
struct listnode neigh_listnode;
|
||||
};
|
||||
|
||||
struct zebra_pbr_rule {
|
||||
int sock;
|
||||
|
||||
@ -43,6 +61,8 @@ struct zebra_pbr_rule {
|
||||
|
||||
char ifname[INTERFACE_NAMSIZ];
|
||||
|
||||
struct zebra_pbr_action action;
|
||||
|
||||
vrf_id_t vrf_id;
|
||||
};
|
||||
|
||||
@ -243,6 +263,8 @@ extern void zebra_pbr_iptable_free(void *arg);
|
||||
extern uint32_t zebra_pbr_iptable_hash_key(const void *arg);
|
||||
extern bool zebra_pbr_iptable_hash_equal(const void *arg1, const void *arg2);
|
||||
|
||||
extern void zebra_pbr_config_write(struct vty *vty);
|
||||
extern void zebra_pbr_expand_action_update(bool enable);
|
||||
extern void zebra_pbr_init(void);
|
||||
extern void zebra_pbr_show_ipset_list(struct vty *vty, char *ipsetname);
|
||||
extern void zebra_pbr_show_iptable(struct vty *vty, char *iptable);
|
||||
@ -250,6 +272,9 @@ extern void zebra_pbr_iptable_update_interfacelist(struct stream *s,
|
||||
struct zebra_pbr_iptable *zpi);
|
||||
size_t zebra_pbr_tcpflags_snprintf(char *buffer, size_t len,
|
||||
uint16_t tcp_val);
|
||||
extern void zebra_pbr_show_rule(struct vty *vty);
|
||||
extern void zebra_pbr_show_rule_unit(struct zebra_pbr_rule *rule,
|
||||
struct vty *vty);
|
||||
|
||||
DECLARE_HOOK(zebra_pbr_ipset_entry_get_stat,
|
||||
(struct zebra_pbr_ipset_entry *ipset, uint64_t *pkts,
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "zebra_vxlan.h"
|
||||
#include "zebra_mlag.h"
|
||||
#include "zebra_nhg.h"
|
||||
#include "zebra_neigh.h"
|
||||
#include "debug.h"
|
||||
#include "zebra_script.h"
|
||||
|
||||
@ -242,6 +243,7 @@ void zebra_router_terminate(void)
|
||||
|
||||
zebra_vxlan_disable();
|
||||
zebra_mlag_terminate();
|
||||
zebra_neigh_terminate();
|
||||
|
||||
/* Free NHE in ID table only since it has unhashable entries as well */
|
||||
hash_clean(zrouter.nhgs_id, zebra_nhg_hash_free);
|
||||
@ -282,6 +284,7 @@ void zebra_router_init(bool asic_offload, bool notify_on_ack)
|
||||
|
||||
zebra_vxlan_init();
|
||||
zebra_mlag_init();
|
||||
zebra_neigh_init();
|
||||
|
||||
zrouter.rules_hash = hash_create_size(8, zebra_pbr_rules_hash_key,
|
||||
zebra_pbr_rules_hash_equal,
|
||||
|
@ -159,6 +159,8 @@ struct zebra_router {
|
||||
/* Tables and other global info maintained for EVPN multihoming */
|
||||
struct zebra_evpn_mh_info *mh_info;
|
||||
|
||||
struct zebra_neigh_info *neigh_info;
|
||||
|
||||
/* EVPN MH broadcast domains indexed by the VID */
|
||||
struct hash *evpn_vlan_table;
|
||||
|
||||
|
@ -64,6 +64,7 @@
|
||||
#include "zebra/table_manager.h"
|
||||
#include "zebra/zebra_script.h"
|
||||
#include "zebra/rtadv.h"
|
||||
#include "zebra/zebra_neigh.h"
|
||||
|
||||
extern int allow_delete;
|
||||
|
||||
@ -3005,6 +3006,15 @@ DEFUN (show_evpn_global,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY(show_evpn_neigh, show_neigh_cmd, "show ip neigh",
|
||||
SHOW_STR IP_STR "neighbors\n")
|
||||
|
||||
{
|
||||
zebra_neigh_show(vty);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY(show_evpn_l2_nh,
|
||||
show_evpn_l2_nh_cmd,
|
||||
"show evpn l2-nh [json$json]",
|
||||
@ -3642,6 +3652,29 @@ DEFUN (show_pbr_iptable,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* policy routing contexts */
|
||||
DEFPY (show_pbr_rule,
|
||||
show_pbr_rule_cmd,
|
||||
"show pbr rule",
|
||||
SHOW_STR
|
||||
"Policy-Based Routing\n"
|
||||
"Rule\n")
|
||||
{
|
||||
zebra_pbr_show_rule(vty);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY (pbr_nexthop_resolve,
|
||||
pbr_nexthop_resolve_cmd,
|
||||
"[no$no] pbr nexthop-resolve",
|
||||
NO_STR
|
||||
"Policy Based Routing\n"
|
||||
"Resolve nexthop for dataplane programming\n")
|
||||
{
|
||||
zebra_pbr_expand_action_update(!no);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY (clear_evpn_dup_addr,
|
||||
clear_evpn_dup_addr_cmd,
|
||||
"clear evpn dup-addr vni <all$vni_all |" CMD_VNI_RANGE"$vni [mac X:X:X:X:X:X | ip <A.B.C.D|X:X::X:X>]>",
|
||||
@ -3912,6 +3945,8 @@ static int config_write_protocol(struct vty *vty)
|
||||
|
||||
zebra_evpn_mh_config_write(vty);
|
||||
|
||||
zebra_pbr_config_write(vty);
|
||||
|
||||
/* Include nexthop-group config */
|
||||
if (!zebra_nhg_kernel_nexthops_enabled())
|
||||
vty_out(vty, "no zebra nexthop kernel enable\n");
|
||||
@ -4547,8 +4582,12 @@ void zebra_vty_init(void)
|
||||
install_element(VIEW_NODE, &show_evpn_neigh_vni_all_dad_cmd);
|
||||
install_element(ENABLE_NODE, &clear_evpn_dup_addr_cmd);
|
||||
|
||||
install_element(VIEW_NODE, &show_neigh_cmd);
|
||||
|
||||
install_element(VIEW_NODE, &show_pbr_ipset_cmd);
|
||||
install_element(VIEW_NODE, &show_pbr_iptable_cmd);
|
||||
install_element(VIEW_NODE, &show_pbr_rule_cmd);
|
||||
install_element(CONFIG_NODE, &pbr_nexthop_resolve_cmd);
|
||||
install_element(VIEW_NODE, &show_route_zebra_dump_cmd);
|
||||
|
||||
install_element(CONFIG_NODE, &evpn_mh_mac_holdtime_cmd);
|
||||
|
Loading…
Reference in New Issue
Block a user