mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-14 13:57:40 +00:00
zebra: traffic control state management
This allows Zebra to manage QDISC, TCLASS, TFILTER in kernel and do cleaning jobs when it starts up. Signed-off-by: Siger Yang <siger.yang@outlook.com>
This commit is contained in:
parent
daa602b593
commit
c317d3f246
@ -123,6 +123,7 @@ lib_libfrr_la_SOURCES = \
|
||||
lib/printf/glue.c \
|
||||
lib/routing_nb.c \
|
||||
lib/routing_nb_config.c \
|
||||
lib/tc.c \
|
||||
# end
|
||||
|
||||
nodist_lib_libfrr_la_SOURCES = \
|
||||
@ -275,6 +276,7 @@ pkginclude_HEADERS += \
|
||||
lib/zlog_live.h \
|
||||
lib/zlog_targets.h \
|
||||
lib/pbr.h \
|
||||
lib/tc.h \
|
||||
lib/routing_nb.h \
|
||||
\
|
||||
lib/assert/assert.h \
|
||||
|
88
lib/tc.c
Normal file
88
lib/tc.c
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Traffic Control (TC) main library
|
||||
* Copyright (C) 2022 Shichu Yang
|
||||
*
|
||||
* 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 "tc.h"
|
||||
|
||||
int tc_getrate(const char *str, uint64_t *rate)
|
||||
{
|
||||
char *endp;
|
||||
uint64_t raw = strtoull(str, &endp, 10);
|
||||
|
||||
if (endp == str)
|
||||
return -1;
|
||||
|
||||
/* if the string only contains a number, it must be valid rate (bps) */
|
||||
bool valid = (*endp == '\0');
|
||||
|
||||
const char *p = endp;
|
||||
bool bytes = false, binary_base = false;
|
||||
int power = 0;
|
||||
|
||||
while (*p) {
|
||||
if (strcmp(p, "Bps") == 0) {
|
||||
bytes = true;
|
||||
valid = true;
|
||||
break;
|
||||
} else if (strcmp(p, "bit") == 0) {
|
||||
valid = true;
|
||||
break;
|
||||
}
|
||||
switch (*p) {
|
||||
case 'k':
|
||||
case 'K':
|
||||
power = 1;
|
||||
break;
|
||||
case 'm':
|
||||
case 'M':
|
||||
power = 2;
|
||||
break;
|
||||
case 'g':
|
||||
case 'G':
|
||||
power = 3;
|
||||
break;
|
||||
case 't':
|
||||
case 'T':
|
||||
power = 4;
|
||||
break;
|
||||
case 'i':
|
||||
case 'I':
|
||||
if (power != 0)
|
||||
binary_base = true;
|
||||
else
|
||||
return -1;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
if (!valid)
|
||||
return -1;
|
||||
|
||||
for (int i = 0; i < power; i++)
|
||||
raw *= binary_base ? 1024ULL : 1000ULL;
|
||||
|
||||
if (bytes)
|
||||
*rate = raw;
|
||||
else
|
||||
*rate = raw / 8ULL;
|
||||
|
||||
return 0;
|
||||
}
|
151
lib/tc.h
Normal file
151
lib/tc.h
Normal file
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Traffic Control (TC) main header
|
||||
* Copyright (C) 2022 Shichu Yang
|
||||
*
|
||||
* 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 _TC_H
|
||||
#define _TC_H
|
||||
|
||||
#include <zebra.h>
|
||||
#include "stream.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define TC_STR "Traffic Control\n"
|
||||
|
||||
/* qdisc definitions */
|
||||
|
||||
/* qdisc kind (same as class kinds) */
|
||||
enum tc_qdisc_kind {
|
||||
TC_QDISC_UNSPEC,
|
||||
TC_QDISC_HTB,
|
||||
TC_QDISC_NOQUEUE,
|
||||
};
|
||||
|
||||
struct tc_qdisc_htb {
|
||||
/* currently no members */
|
||||
};
|
||||
|
||||
struct tc_qdisc {
|
||||
ifindex_t ifindex;
|
||||
|
||||
enum tc_qdisc_kind kind;
|
||||
union {
|
||||
struct tc_qdisc_htb htb;
|
||||
} u;
|
||||
};
|
||||
|
||||
/* class definitions */
|
||||
|
||||
/* since classes share the same kinds of qdisc, duplicates omitted */
|
||||
struct tc_class_htb {
|
||||
uint64_t rate;
|
||||
uint64_t ceil;
|
||||
};
|
||||
|
||||
struct tc_class {
|
||||
ifindex_t ifindex;
|
||||
uint32_t handle;
|
||||
|
||||
enum tc_qdisc_kind kind;
|
||||
union {
|
||||
struct tc_class_htb htb;
|
||||
} u;
|
||||
};
|
||||
|
||||
/* filter definitions */
|
||||
|
||||
/* filter kinds */
|
||||
enum tc_filter_kind {
|
||||
TC_FILTER_UNSPEC,
|
||||
TC_FILTER_BPF,
|
||||
TC_FILTER_FLOW,
|
||||
TC_FILTER_FLOWER,
|
||||
TC_FILTER_U32,
|
||||
};
|
||||
|
||||
struct tc_bpf {
|
||||
/* TODO: fill in */
|
||||
};
|
||||
|
||||
struct tc_flow {
|
||||
/* TODO: fill in */
|
||||
};
|
||||
|
||||
struct tc_flower {
|
||||
uint32_t classid;
|
||||
|
||||
#define TC_FLOWER_IP_PROTOCOL (1 << 0)
|
||||
#define TC_FLOWER_SRC_IP (1 << 1)
|
||||
#define TC_FLOWER_DST_IP (1 << 2)
|
||||
#define TC_FLOWER_SRC_PORT (1 << 3)
|
||||
#define TC_FLOWER_DST_PORT (1 << 4)
|
||||
#define TC_FLOWER_DSFIELD (1 << 5)
|
||||
|
||||
uint32_t filter_bm;
|
||||
|
||||
uint8_t ip_proto;
|
||||
|
||||
struct prefix src_ip;
|
||||
struct prefix dst_ip;
|
||||
|
||||
uint16_t src_port_min;
|
||||
uint16_t src_port_max;
|
||||
uint16_t dst_port_min;
|
||||
uint16_t dst_port_max;
|
||||
|
||||
uint8_t dsfield;
|
||||
uint8_t dsfield_mask;
|
||||
};
|
||||
|
||||
struct tc_u32 {
|
||||
/* TODO: fill in */
|
||||
};
|
||||
|
||||
struct tc_filter {
|
||||
ifindex_t ifindex;
|
||||
uint32_t handle;
|
||||
|
||||
uint32_t priority;
|
||||
uint16_t protocol;
|
||||
|
||||
enum tc_filter_kind kind;
|
||||
|
||||
union {
|
||||
struct tc_bpf bpf;
|
||||
struct tc_flow flow;
|
||||
struct tc_flower flower;
|
||||
struct tc_u32 u32;
|
||||
} u;
|
||||
};
|
||||
|
||||
extern int tc_getrate(const char *str, uint64_t *rate);
|
||||
|
||||
extern int zapi_tc_qdisc_encode(uint8_t cmd, struct stream *s,
|
||||
struct tc_qdisc *qdisc);
|
||||
extern int zapi_tc_class_encode(uint8_t cmd, struct stream *s,
|
||||
struct tc_class *class);
|
||||
extern int zapi_tc_filter_encode(uint8_t cmd, struct stream *s,
|
||||
struct tc_filter *filter);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TC_H */
|
@ -42,6 +42,7 @@ unsigned long zebra_debug_nexthop;
|
||||
unsigned long zebra_debug_evpn_mh;
|
||||
unsigned long zebra_debug_pbr;
|
||||
unsigned long zebra_debug_neigh;
|
||||
unsigned long zebra_debug_tc;
|
||||
|
||||
DEFINE_HOOK(zebra_debug_show_debugging, (struct vty *vty), (vty));
|
||||
|
||||
@ -374,6 +375,17 @@ DEFPY (debug_zebra_neigh,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (debug_zebra_tc,
|
||||
debug_zebra_tc_cmd,
|
||||
"debug zebra tc",
|
||||
DEBUG_STR
|
||||
"Zebra configuration\n"
|
||||
"Debug zebra tc events\n")
|
||||
{
|
||||
SET_FLAG(zebra_debug_tc, ZEBRA_DEBUG_TC);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY (debug_zebra_mlag,
|
||||
debug_zebra_mlag_cmd,
|
||||
"[no$no] debug zebra mlag",
|
||||
@ -797,6 +809,7 @@ void zebra_debug_init(void)
|
||||
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_tc_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);
|
||||
|
@ -75,6 +75,8 @@ extern "C" {
|
||||
|
||||
#define ZEBRA_DEBUG_NEIGH 0x01
|
||||
|
||||
#define ZEBRA_DEBUG_TC 0x01
|
||||
|
||||
/* Debug related macro. */
|
||||
#define IS_ZEBRA_DEBUG_EVENT (zebra_debug_event & ZEBRA_DEBUG_EVENT)
|
||||
|
||||
@ -133,6 +135,8 @@ extern "C" {
|
||||
|
||||
#define IS_ZEBRA_DEBUG_NEIGH (zebra_debug_neigh & ZEBRA_DEBUG_NEIGH)
|
||||
|
||||
#define IS_ZEBRA_DEBUG_TC (zebra_debug_tc & ZEBRA_DEBUG_TC)
|
||||
|
||||
extern unsigned long zebra_debug_event;
|
||||
extern unsigned long zebra_debug_packet;
|
||||
extern unsigned long zebra_debug_kernel;
|
||||
@ -149,6 +153,7 @@ 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 unsigned long zebra_debug_tc;
|
||||
|
||||
extern void zebra_debug_init(void);
|
||||
|
||||
|
@ -816,9 +816,14 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx)
|
||||
case DPLANE_OP_INTF_INSTALL:
|
||||
case DPLANE_OP_INTF_UPDATE:
|
||||
case DPLANE_OP_INTF_DELETE:
|
||||
case DPLANE_OP_TC_INSTALL:
|
||||
case DPLANE_OP_TC_UPDATE:
|
||||
case DPLANE_OP_TC_DELETE:
|
||||
case DPLANE_OP_TC_QDISC_INSTALL:
|
||||
case DPLANE_OP_TC_QDISC_UNINSTALL:
|
||||
case DPLANE_OP_TC_CLASS_ADD:
|
||||
case DPLANE_OP_TC_CLASS_DELETE:
|
||||
case DPLANE_OP_TC_CLASS_UPDATE:
|
||||
case DPLANE_OP_TC_FILTER_ADD:
|
||||
case DPLANE_OP_TC_FILTER_DELETE:
|
||||
case DPLANE_OP_TC_FILTER_UPDATE:
|
||||
case DPLANE_OP_NONE:
|
||||
break;
|
||||
|
||||
|
@ -1573,9 +1573,14 @@ void zebra_if_dplane_result(struct zebra_dplane_ctx *ctx)
|
||||
case DPLANE_OP_IPSET_ENTRY_DELETE:
|
||||
case DPLANE_OP_NEIGH_TABLE_UPDATE:
|
||||
case DPLANE_OP_GRE_SET:
|
||||
case DPLANE_OP_TC_INSTALL:
|
||||
case DPLANE_OP_TC_UPDATE:
|
||||
case DPLANE_OP_TC_DELETE:
|
||||
case DPLANE_OP_TC_QDISC_INSTALL:
|
||||
case DPLANE_OP_TC_QDISC_UNINSTALL:
|
||||
case DPLANE_OP_TC_CLASS_ADD:
|
||||
case DPLANE_OP_TC_CLASS_DELETE:
|
||||
case DPLANE_OP_TC_CLASS_UPDATE:
|
||||
case DPLANE_OP_TC_FILTER_ADD:
|
||||
case DPLANE_OP_TC_FILTER_DELETE:
|
||||
case DPLANE_OP_TC_FILTER_UPDATE:
|
||||
break; /* should never hit here */
|
||||
}
|
||||
}
|
||||
|
@ -423,6 +423,15 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id,
|
||||
return netlink_nexthop_change(h, ns_id, startup);
|
||||
case RTM_DELNEXTHOP:
|
||||
return netlink_nexthop_change(h, ns_id, startup);
|
||||
case RTM_NEWQDISC:
|
||||
case RTM_DELQDISC:
|
||||
return netlink_qdisc_change(h, ns_id, startup);
|
||||
case RTM_NEWTCLASS:
|
||||
case RTM_DELTCLASS:
|
||||
return netlink_tclass_change(h, ns_id, startup);
|
||||
case RTM_NEWTFILTER:
|
||||
case RTM_DELTFILTER:
|
||||
return netlink_tfilter_change(h, ns_id, startup);
|
||||
|
||||
/* Messages handled in the dplane thread */
|
||||
case RTM_NEWADDR:
|
||||
@ -1640,10 +1649,17 @@ static enum netlink_msg_status nl_put_msg(struct nl_batch *bth,
|
||||
case DPLANE_OP_INTF_DELETE:
|
||||
return netlink_put_intf_update_msg(bth, ctx);
|
||||
|
||||
case DPLANE_OP_TC_INSTALL:
|
||||
case DPLANE_OP_TC_UPDATE:
|
||||
case DPLANE_OP_TC_DELETE:
|
||||
return netlink_put_tc_update_msg(bth, ctx);
|
||||
case DPLANE_OP_TC_QDISC_INSTALL:
|
||||
case DPLANE_OP_TC_QDISC_UNINSTALL:
|
||||
return netlink_put_tc_qdisc_update_msg(bth, ctx);
|
||||
case DPLANE_OP_TC_CLASS_ADD:
|
||||
case DPLANE_OP_TC_CLASS_DELETE:
|
||||
case DPLANE_OP_TC_CLASS_UPDATE:
|
||||
return netlink_put_tc_class_update_msg(bth, ctx);
|
||||
case DPLANE_OP_TC_FILTER_ADD:
|
||||
case DPLANE_OP_TC_FILTER_DELETE:
|
||||
case DPLANE_OP_TC_FILTER_UPDATE:
|
||||
return netlink_put_tc_filter_update_msg(bth, ctx);
|
||||
}
|
||||
|
||||
return FRR_NETLINK_ERROR;
|
||||
@ -1757,15 +1773,16 @@ void kernel_init(struct zebra_ns *zns)
|
||||
* RTNLGRP_XXX to a bit position for ourself
|
||||
*/
|
||||
groups = RTMGRP_LINK |
|
||||
RTMGRP_IPV4_ROUTE |
|
||||
RTMGRP_IPV4_IFADDR |
|
||||
RTMGRP_IPV6_ROUTE |
|
||||
RTMGRP_IPV6_IFADDR |
|
||||
RTMGRP_IPV4_MROUTE |
|
||||
RTMGRP_NEIGH |
|
||||
((uint32_t) 1 << (RTNLGRP_IPV4_RULE - 1)) |
|
||||
((uint32_t) 1 << (RTNLGRP_IPV6_RULE - 1)) |
|
||||
((uint32_t) 1 << (RTNLGRP_NEXTHOP - 1));
|
||||
RTMGRP_IPV4_ROUTE |
|
||||
RTMGRP_IPV4_IFADDR |
|
||||
RTMGRP_IPV6_ROUTE |
|
||||
RTMGRP_IPV6_IFADDR |
|
||||
RTMGRP_IPV4_MROUTE |
|
||||
RTMGRP_NEIGH |
|
||||
((uint32_t) 1 << (RTNLGRP_IPV4_RULE - 1)) |
|
||||
((uint32_t) 1 << (RTNLGRP_IPV6_RULE - 1)) |
|
||||
((uint32_t) 1 << (RTNLGRP_NEXTHOP - 1)) |
|
||||
((uint32_t) 1 << (RTNLGRP_TC - 1));
|
||||
|
||||
dplane_groups = (RTMGRP_LINK |
|
||||
RTMGRP_IPV4_IFADDR |
|
||||
|
@ -1594,9 +1594,14 @@ void kernel_update_multi(struct dplane_ctx_q *ctx_list)
|
||||
res = kernel_intf_update(ctx);
|
||||
break;
|
||||
|
||||
case DPLANE_OP_TC_INSTALL:
|
||||
case DPLANE_OP_TC_UPDATE:
|
||||
case DPLANE_OP_TC_DELETE:
|
||||
case DPLANE_OP_TC_QDISC_INSTALL:
|
||||
case DPLANE_OP_TC_QDISC_UNINSTALL:
|
||||
case DPLANE_OP_TC_CLASS_ADD:
|
||||
case DPLANE_OP_TC_CLASS_DELETE:
|
||||
case DPLANE_OP_TC_CLASS_UPDATE:
|
||||
case DPLANE_OP_TC_FILTER_ADD:
|
||||
case DPLANE_OP_TC_FILTER_DELETE:
|
||||
case DPLANE_OP_TC_FILTER_UPDATE:
|
||||
res = kernel_tc_update(ctx);
|
||||
break;
|
||||
|
||||
|
@ -26,8 +26,10 @@
|
||||
#include "vty.h"
|
||||
#include "zebra/rt.h"
|
||||
#include "zebra/zebra_pbr.h"
|
||||
#include "zebra/zebra_tc.h"
|
||||
#include "zebra/rt_netlink.h"
|
||||
#include "zebra/rule_netlink.h"
|
||||
#include "zebra/tc_netlink.h"
|
||||
|
||||
void route_read(struct zebra_ns *zns)
|
||||
{
|
||||
@ -71,4 +73,9 @@ void kernel_read_pbr_rules(struct zebra_ns *zns)
|
||||
netlink_rules_read(zns);
|
||||
}
|
||||
|
||||
void kernel_read_tc_qdisc(struct zebra_ns *zns)
|
||||
{
|
||||
netlink_qdisc_read(zns);
|
||||
}
|
||||
|
||||
#endif /* GNU_LINUX */
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "zebra/rt.h"
|
||||
#include "zebra/kernel_socket.h"
|
||||
#include "zebra/zebra_pbr.h"
|
||||
#include "zebra/zebra_tc.h"
|
||||
#include "zebra/zebra_errors.h"
|
||||
|
||||
/* Kernel routing table read up by sysctl function. */
|
||||
@ -108,4 +109,8 @@ void kernel_read_pbr_rules(struct zebra_ns *zns)
|
||||
{
|
||||
}
|
||||
|
||||
void kernel_read_tc_qdisc(struct zebra_ns *zns)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* !defined(GNU_LINUX) */
|
||||
|
@ -100,6 +100,7 @@ zebra_zebra_SOURCES = \
|
||||
zebra/zebra_routemap_nb_config.c \
|
||||
zebra/zebra_script.c \
|
||||
zebra/zebra_srte.c \
|
||||
zebra/zebra_tc.c \
|
||||
zebra/zebra_trace.c \
|
||||
zebra/zebra_vrf.c \
|
||||
zebra/zebra_vty.c \
|
||||
@ -175,6 +176,7 @@ noinst_HEADERS += \
|
||||
zebra/zebra_router.h \
|
||||
zebra/zebra_script.h \
|
||||
zebra/zebra_srte.h \
|
||||
zebra/zebra_tc.h \
|
||||
zebra/zebra_trace.h \
|
||||
zebra/zebra_vrf.h \
|
||||
zebra/zebra_vxlan.h \
|
||||
|
@ -22,6 +22,8 @@
|
||||
|
||||
#ifdef HAVE_NETLINK
|
||||
|
||||
#include <linux/pkt_cls.h>
|
||||
#include <linux/pkt_sched.h>
|
||||
#include <netinet/if_ether.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
@ -29,34 +31,24 @@
|
||||
#include "prefix.h"
|
||||
#include "vrf.h"
|
||||
|
||||
#include <linux/fib_rules.h>
|
||||
#include <linux/pkt_cls.h>
|
||||
#include <linux/pkt_sched.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/tc_netlink.h"
|
||||
#include "zebra/zebra_errors.h"
|
||||
#include "zebra/zebra_dplane.h"
|
||||
#include "zebra/zebra_tc.h"
|
||||
#include "zebra/zebra_trace.h"
|
||||
|
||||
/* TODO: move these bitflags to zebra_tc.h */
|
||||
#define TC_FILTER_SRC_IP (1 << 0)
|
||||
#define TC_FILTER_DST_IP (1 << 1)
|
||||
#define TC_FILTER_IP_PROTOCOL (1 << 9)
|
||||
|
||||
#define TC_FREQ_DEFAULT (100)
|
||||
|
||||
#define TC_MAJOR_BASE (0x1000u)
|
||||
/* some magic number */
|
||||
#define TC_QDISC_MAJOR_ZEBRA (0xbeef0000u)
|
||||
#define TC_MINOR_NOCLASS (0xffffu)
|
||||
|
||||
#define TC_FILTER_MASK (0x8000u)
|
||||
|
||||
#define TIME_UNITS_PER_SEC (1000000)
|
||||
#define xmittime(r, s) (TIME_UNITS_PER_SEC * ((double)(s) / (double)(r)))
|
||||
|
||||
@ -78,19 +70,6 @@ static uint32_t tc_get_freq(void)
|
||||
return freq == 0 ? TC_FREQ_DEFAULT : freq;
|
||||
}
|
||||
|
||||
static inline uint32_t tc_make_handle(uint16_t major, uint16_t minor)
|
||||
{
|
||||
return (major) << 16 | (minor);
|
||||
}
|
||||
|
||||
static inline uint32_t tc_get_handle(struct zebra_dplane_ctx *ctx,
|
||||
uint16_t minor)
|
||||
{
|
||||
uint16_t major = TC_MAJOR_BASE + (uint16_t)dplane_ctx_get_ifindex(ctx);
|
||||
|
||||
return tc_make_handle(major, minor);
|
||||
}
|
||||
|
||||
static void tc_calc_rate_table(struct tc_ratespec *ratespec, uint32_t *table,
|
||||
uint32_t mtu)
|
||||
{
|
||||
@ -186,11 +165,7 @@ static ssize_t netlink_qdisc_msg_encode(int cmd, struct zebra_dplane_ctx *ctx,
|
||||
void *data, size_t datalen)
|
||||
{
|
||||
struct nlsock *nl;
|
||||
|
||||
const char *kind = "htb";
|
||||
|
||||
struct tc_htb_glob htb_glob = {
|
||||
.rate2quantum = 10, .version = 3, .defcls = TC_MINOR_NOCLASS};
|
||||
const char *kind_str = NULL;
|
||||
|
||||
struct rtattr *nest;
|
||||
|
||||
@ -218,16 +193,41 @@ static ssize_t netlink_qdisc_msg_encode(int cmd, struct zebra_dplane_ctx *ctx,
|
||||
|
||||
req->t.tcm_family = AF_UNSPEC;
|
||||
req->t.tcm_ifindex = dplane_ctx_get_ifindex(ctx);
|
||||
req->t.tcm_handle = tc_get_handle(ctx, 0);
|
||||
req->t.tcm_info = 0;
|
||||
req->t.tcm_handle = 0;
|
||||
req->t.tcm_parent = TC_H_ROOT;
|
||||
|
||||
nl_attr_put(&req->n, datalen, TCA_KIND, kind, strlen(kind) + 1);
|
||||
if (cmd == RTM_NEWQDISC) {
|
||||
req->t.tcm_handle = TC_H_MAKE(TC_QDISC_MAJOR_ZEBRA, 0);
|
||||
|
||||
nest = nl_attr_nest(&req->n, datalen, TCA_OPTIONS);
|
||||
kind_str = dplane_ctx_tc_qdisc_get_kind_str(ctx);
|
||||
|
||||
nl_attr_put(&req->n, datalen, TCA_HTB_INIT, &htb_glob,
|
||||
sizeof(htb_glob));
|
||||
nl_attr_nest_end(&req->n, nest);
|
||||
nl_attr_put(&req->n, datalen, TCA_KIND, kind_str,
|
||||
strlen(kind_str) + 1);
|
||||
|
||||
nest = nl_attr_nest(&req->n, datalen, TCA_OPTIONS);
|
||||
|
||||
switch (dplane_ctx_tc_qdisc_get_kind(ctx)) {
|
||||
case TC_QDISC_HTB: {
|
||||
struct tc_htb_glob htb_glob = {
|
||||
.rate2quantum = 10,
|
||||
.version = 3,
|
||||
.defcls = TC_MINOR_NOCLASS};
|
||||
nl_attr_put(&req->n, datalen, TCA_HTB_INIT, &htb_glob,
|
||||
sizeof(htb_glob));
|
||||
break;
|
||||
}
|
||||
case TC_QDISC_NOQUEUE:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
/* not implemented */
|
||||
}
|
||||
|
||||
nl_attr_nest_end(&req->n, nest);
|
||||
} else {
|
||||
/* ifindex are enough for del/get qdisc */
|
||||
}
|
||||
|
||||
return NLMSG_ALIGN(req->n.nlmsg_len);
|
||||
}
|
||||
@ -238,17 +238,10 @@ static ssize_t netlink_qdisc_msg_encode(int cmd, struct zebra_dplane_ctx *ctx,
|
||||
static ssize_t netlink_tclass_msg_encode(int cmd, struct zebra_dplane_ctx *ctx,
|
||||
void *data, size_t datalen)
|
||||
{
|
||||
enum dplane_op_e op = dplane_ctx_get_op(ctx);
|
||||
|
||||
struct nlsock *nl;
|
||||
struct tc_htb_opt htb_opt = {};
|
||||
|
||||
uint64_t rate, ceil;
|
||||
uint64_t buffer, cbuffer;
|
||||
|
||||
/* TODO: fetch mtu from interface */
|
||||
uint32_t mtu = 0;
|
||||
|
||||
uint32_t rtab[256];
|
||||
uint32_t ctab[256];
|
||||
const char *kind_str = NULL;
|
||||
|
||||
struct rtattr *nest;
|
||||
|
||||
@ -268,167 +261,299 @@ static ssize_t netlink_tclass_msg_encode(int cmd, struct zebra_dplane_ctx *ctx,
|
||||
req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
|
||||
req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
|
||||
|
||||
if (op == DPLANE_OP_TC_CLASS_UPDATE)
|
||||
req->n.nlmsg_flags |= NLM_F_REPLACE;
|
||||
|
||||
req->n.nlmsg_type = cmd;
|
||||
|
||||
req->n.nlmsg_pid = nl->snl.nl_pid;
|
||||
|
||||
req->t.tcm_family = AF_UNSPEC;
|
||||
req->t.tcm_ifindex = dplane_ctx_get_ifindex(ctx);
|
||||
req->t.tcm_handle = tc_get_handle(ctx, 1);
|
||||
req->t.tcm_parent = tc_get_handle(ctx, 0);
|
||||
|
||||
rate = dplane_ctx_tc_get_rate(ctx);
|
||||
ceil = dplane_ctx_tc_get_ceil(ctx);
|
||||
req->t.tcm_handle = TC_H_MAKE(TC_QDISC_MAJOR_ZEBRA,
|
||||
dplane_ctx_tc_class_get_handle(ctx));
|
||||
req->t.tcm_parent = TC_H_MAKE(TC_QDISC_MAJOR_ZEBRA, 0);
|
||||
req->t.tcm_info = 0;
|
||||
|
||||
ceil = ceil < rate ? rate : ceil;
|
||||
kind_str = dplane_ctx_tc_class_get_kind_str(ctx);
|
||||
|
||||
htb_opt.rate.rate = (rate >> 32 != 0) ? ~0U : rate;
|
||||
htb_opt.ceil.rate = (ceil >> 32 != 0) ? ~0U : ceil;
|
||||
if (op == DPLANE_OP_TC_CLASS_ADD || op == DPLANE_OP_TC_CLASS_UPDATE) {
|
||||
zlog_debug("netlink tclass encoder: op: %s kind: %s handle: %u",
|
||||
op == DPLANE_OP_TC_CLASS_UPDATE ? "update" : "add",
|
||||
kind_str, dplane_ctx_tc_class_get_handle(ctx));
|
||||
|
||||
buffer = rate / tc_get_freq(), cbuffer = ceil / tc_get_freq();
|
||||
nl_attr_put(&req->n, datalen, TCA_KIND, kind_str,
|
||||
strlen(kind_str) + 1);
|
||||
|
||||
htb_opt.buffer = buffer;
|
||||
htb_opt.cbuffer = cbuffer;
|
||||
nest = nl_attr_nest(&req->n, datalen, TCA_OPTIONS);
|
||||
|
||||
tc_calc_rate_table(&htb_opt.rate, rtab, mtu);
|
||||
tc_calc_rate_table(&htb_opt.ceil, ctab, mtu);
|
||||
switch (dplane_ctx_tc_class_get_kind(ctx)) {
|
||||
case TC_QDISC_HTB: {
|
||||
struct tc_htb_opt htb_opt = {};
|
||||
|
||||
htb_opt.ceil.mpu = htb_opt.rate.mpu = 0;
|
||||
htb_opt.ceil.overhead = htb_opt.rate.overhead = 0;
|
||||
uint64_t rate = dplane_ctx_tc_class_get_rate(ctx),
|
||||
ceil = dplane_ctx_tc_class_get_ceil(ctx);
|
||||
|
||||
nest = nl_attr_nest(&req->n, datalen, TCA_OPTIONS);
|
||||
uint64_t buffer, cbuffer;
|
||||
|
||||
if (rate >> 32 != 0) {
|
||||
nl_attr_put(&req->n, datalen, TCA_HTB_CEIL64, &rate,
|
||||
sizeof(rate));
|
||||
/* TODO: fetch mtu from interface */
|
||||
uint32_t mtu = 1500;
|
||||
|
||||
uint32_t rtab[256];
|
||||
uint32_t ctab[256];
|
||||
|
||||
ceil = MAX(rate, ceil);
|
||||
|
||||
htb_opt.rate.rate = (rate >> 32 != 0) ? ~0U : rate;
|
||||
htb_opt.ceil.rate = (ceil >> 32 != 0) ? ~0U : ceil;
|
||||
|
||||
buffer = rate / tc_get_freq() + mtu;
|
||||
cbuffer = ceil / tc_get_freq() + mtu;
|
||||
|
||||
htb_opt.buffer = buffer;
|
||||
htb_opt.cbuffer = cbuffer;
|
||||
|
||||
tc_calc_rate_table(&htb_opt.rate, rtab, mtu);
|
||||
tc_calc_rate_table(&htb_opt.ceil, ctab, mtu);
|
||||
|
||||
htb_opt.ceil.mpu = htb_opt.rate.mpu = 0;
|
||||
htb_opt.ceil.overhead = htb_opt.rate.overhead = 0;
|
||||
|
||||
if (rate >> 32 != 0) {
|
||||
nl_attr_put(&req->n, datalen, TCA_HTB_RATE64,
|
||||
&rate, sizeof(rate));
|
||||
}
|
||||
|
||||
if (ceil >> 32 != 0) {
|
||||
nl_attr_put(&req->n, datalen, TCA_HTB_CEIL64,
|
||||
&ceil, sizeof(ceil));
|
||||
}
|
||||
|
||||
nl_attr_put(&req->n, datalen, TCA_HTB_PARMS, &htb_opt,
|
||||
sizeof(htb_opt));
|
||||
|
||||
nl_attr_put(&req->n, datalen, TCA_HTB_RTAB, rtab,
|
||||
sizeof(rtab));
|
||||
nl_attr_put(&req->n, datalen, TCA_HTB_CTAB, ctab,
|
||||
sizeof(ctab));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
nl_attr_nest_end(&req->n, nest);
|
||||
}
|
||||
|
||||
if (ceil >> 32 != 0) {
|
||||
nl_attr_put(&req->n, datalen, TCA_HTB_CEIL64, &ceil,
|
||||
sizeof(ceil));
|
||||
}
|
||||
|
||||
nl_attr_put(&req->n, datalen, TCA_HTB_PARMS, &htb_opt, sizeof(htb_opt));
|
||||
|
||||
nl_attr_put(&req->n, datalen, TCA_HTB_RTAB, rtab, sizeof(rtab));
|
||||
nl_attr_put(&req->n, datalen, TCA_HTB_CTAB, ctab, sizeof(ctab));
|
||||
nl_attr_nest_end(&req->n, nest);
|
||||
|
||||
return NLMSG_ALIGN(req->n.nlmsg_len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Traffic control filter encoding (only "flower" supported)
|
||||
*/
|
||||
static ssize_t netlink_tfilter_msg_encode(int cmd, struct zebra_dplane_ctx *ctx,
|
||||
void *data, size_t datalen)
|
||||
static int netlink_tfilter_flower_port_type(uint8_t ip_proto, bool src)
|
||||
{
|
||||
struct nlsock *nl;
|
||||
struct rtattr *nest;
|
||||
|
||||
const char *kind = "flower";
|
||||
|
||||
uint16_t priority;
|
||||
uint16_t protocol;
|
||||
uint32_t classid;
|
||||
uint32_t filter_bm;
|
||||
uint32_t flags = 0;
|
||||
if (ip_proto == IPPROTO_TCP)
|
||||
return src ? TCA_FLOWER_KEY_TCP_SRC : TCA_FLOWER_KEY_TCP_DST;
|
||||
else if (ip_proto == IPPROTO_UDP)
|
||||
return src ? TCA_FLOWER_KEY_UDP_SRC : TCA_FLOWER_KEY_UDP_DST;
|
||||
else if (ip_proto == IPPROTO_SCTP)
|
||||
return src ? TCA_FLOWER_KEY_SCTP_SRC : TCA_FLOWER_KEY_SCTP_DST;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void netlink_tfilter_flower_put_options(struct nlmsghdr *n,
|
||||
size_t datalen,
|
||||
struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
struct inet_prefix addr;
|
||||
uint32_t flags = 0, classid;
|
||||
uint8_t protocol = htons(dplane_ctx_tc_filter_get_eth_proto(ctx));
|
||||
uint32_t filter_bm = dplane_ctx_tc_filter_get_filter_bm(ctx);
|
||||
|
||||
struct {
|
||||
struct nlmsghdr n;
|
||||
struct tcmsg t;
|
||||
char buf[0];
|
||||
} *req = (void *)data;
|
||||
|
||||
if (datalen < sizeof(*req))
|
||||
return 0;
|
||||
|
||||
nl = kernel_netlink_nlsock_lookup(dplane_ctx_get_ns_sock(ctx));
|
||||
|
||||
memset(req, 0, sizeof(*req));
|
||||
|
||||
req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
|
||||
req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
|
||||
|
||||
req->n.nlmsg_flags |= NLM_F_EXCL;
|
||||
|
||||
req->n.nlmsg_type = cmd;
|
||||
|
||||
req->n.nlmsg_pid = nl->snl.nl_pid;
|
||||
|
||||
req->t.tcm_family = AF_UNSPEC;
|
||||
req->t.tcm_ifindex = dplane_ctx_get_ifindex(ctx);
|
||||
|
||||
/* TODO: priority and layer-3 protocol support */
|
||||
priority = 0;
|
||||
protocol = htons(ETH_P_IP);
|
||||
classid = tc_get_handle(ctx, 1);
|
||||
filter_bm = dplane_ctx_tc_get_filter_bm(ctx);
|
||||
|
||||
req->t.tcm_info = tc_make_handle(priority, protocol);
|
||||
|
||||
req->t.tcm_handle = 1;
|
||||
req->t.tcm_parent = tc_get_handle(ctx, 0);
|
||||
|
||||
nl_attr_put(&req->n, datalen, TCA_KIND, kind, strlen(kind) + 1);
|
||||
nest = nl_attr_nest(&req->n, datalen, TCA_OPTIONS);
|
||||
|
||||
nl_attr_put(&req->n, datalen, TCA_FLOWER_CLASSID, &classid,
|
||||
sizeof(classid));
|
||||
|
||||
if (filter_bm & TC_FILTER_SRC_IP) {
|
||||
const struct prefix *src_p = dplane_ctx_tc_get_src_ip(ctx);
|
||||
if (filter_bm & TC_FLOWER_SRC_IP) {
|
||||
const struct prefix *src_p =
|
||||
dplane_ctx_tc_filter_get_src_ip(ctx);
|
||||
|
||||
if (tc_flower_get_inet_prefix(src_p, &addr) != 0)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
nl_attr_put(&req->n, datalen,
|
||||
nl_attr_put(n, datalen,
|
||||
(addr.family == AF_INET) ? TCA_FLOWER_KEY_IPV4_SRC
|
||||
: TCA_FLOWER_KEY_IPV6_SRC,
|
||||
addr.data, addr.bytelen);
|
||||
|
||||
if (tc_flower_get_inet_mask(src_p, &addr) != 0)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
nl_attr_put(&req->n, datalen,
|
||||
nl_attr_put(n, datalen,
|
||||
(addr.family == AF_INET)
|
||||
? TCA_FLOWER_KEY_IPV4_SRC_MASK
|
||||
: TCA_FLOWER_KEY_IPV6_SRC_MASK,
|
||||
addr.data, addr.bytelen);
|
||||
}
|
||||
|
||||
if (filter_bm & TC_FILTER_DST_IP) {
|
||||
const struct prefix *dst_p = dplane_ctx_tc_get_dst_ip(ctx);
|
||||
if (filter_bm & TC_FLOWER_DST_IP) {
|
||||
const struct prefix *dst_p =
|
||||
dplane_ctx_tc_filter_get_dst_ip(ctx);
|
||||
|
||||
if (tc_flower_get_inet_prefix(dst_p, &addr) != 0)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
nl_attr_put(&req->n, datalen,
|
||||
nl_attr_put(n, datalen,
|
||||
(addr.family == AF_INET) ? TCA_FLOWER_KEY_IPV4_DST
|
||||
: TCA_FLOWER_KEY_IPV6_DST,
|
||||
addr.data, addr.bytelen);
|
||||
|
||||
if (tc_flower_get_inet_mask(dst_p, &addr) != 0)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
nl_attr_put(&req->n, datalen,
|
||||
nl_attr_put(n, datalen,
|
||||
(addr.family == AF_INET)
|
||||
? TCA_FLOWER_KEY_IPV4_DST_MASK
|
||||
: TCA_FLOWER_KEY_IPV6_DST_MASK,
|
||||
addr.data, addr.bytelen);
|
||||
}
|
||||
|
||||
if (filter_bm & TC_FILTER_IP_PROTOCOL) {
|
||||
nl_attr_put8(&req->n, datalen, TCA_FLOWER_KEY_IP_PROTO,
|
||||
dplane_ctx_tc_get_ip_proto(ctx));
|
||||
if (filter_bm & TC_FLOWER_IP_PROTOCOL) {
|
||||
nl_attr_put8(n, datalen, TCA_FLOWER_KEY_IP_PROTO,
|
||||
dplane_ctx_tc_filter_get_ip_proto(ctx));
|
||||
}
|
||||
|
||||
nl_attr_put32(&req->n, datalen, TCA_FLOWER_FLAGS, flags);
|
||||
if (filter_bm & TC_FLOWER_SRC_PORT) {
|
||||
uint16_t min, max;
|
||||
|
||||
nl_attr_put16(&req->n, datalen, TCA_FLOWER_KEY_ETH_TYPE, protocol);
|
||||
nl_attr_nest_end(&req->n, nest);
|
||||
min = dplane_ctx_tc_filter_get_src_port_min(ctx);
|
||||
max = dplane_ctx_tc_filter_get_src_port_max(ctx);
|
||||
|
||||
if (max > min) {
|
||||
nl_attr_put16(n, datalen, TCA_FLOWER_KEY_PORT_SRC_MIN,
|
||||
htons(min));
|
||||
|
||||
nl_attr_put16(n, datalen, TCA_FLOWER_KEY_PORT_SRC_MAX,
|
||||
htons(max));
|
||||
} else {
|
||||
int type = netlink_tfilter_flower_port_type(
|
||||
dplane_ctx_tc_filter_get_ip_proto(ctx), true);
|
||||
|
||||
if (type < 0)
|
||||
return;
|
||||
|
||||
nl_attr_put16(n, datalen, type, htons(min));
|
||||
}
|
||||
}
|
||||
|
||||
if (filter_bm & TC_FLOWER_DST_PORT) {
|
||||
uint16_t min = dplane_ctx_tc_filter_get_dst_port_min(ctx),
|
||||
max = dplane_ctx_tc_filter_get_dst_port_max(ctx);
|
||||
|
||||
if (max > min) {
|
||||
nl_attr_put16(n, datalen, TCA_FLOWER_KEY_PORT_DST_MIN,
|
||||
htons(min));
|
||||
|
||||
nl_attr_put16(n, datalen, TCA_FLOWER_KEY_PORT_DST_MAX,
|
||||
htons(max));
|
||||
} else {
|
||||
int type = netlink_tfilter_flower_port_type(
|
||||
dplane_ctx_tc_filter_get_ip_proto(ctx), false);
|
||||
|
||||
if (type < 0)
|
||||
return;
|
||||
|
||||
nl_attr_put16(n, datalen, type, htons(min));
|
||||
}
|
||||
}
|
||||
|
||||
if (filter_bm & TC_FLOWER_DSFIELD) {
|
||||
nl_attr_put8(n, datalen, TCA_FLOWER_KEY_IP_TOS,
|
||||
dplane_ctx_tc_filter_get_dsfield(ctx));
|
||||
nl_attr_put8(n, datalen, TCA_FLOWER_KEY_IP_TOS_MASK,
|
||||
dplane_ctx_tc_filter_get_dsfield_mask(ctx));
|
||||
}
|
||||
|
||||
classid = TC_H_MAKE(TC_QDISC_MAJOR_ZEBRA,
|
||||
dplane_ctx_tc_filter_get_classid(ctx));
|
||||
nl_attr_put32(n, datalen, TCA_FLOWER_CLASSID, classid);
|
||||
|
||||
nl_attr_put32(n, datalen, TCA_FLOWER_FLAGS, flags);
|
||||
|
||||
nl_attr_put16(n, datalen, TCA_FLOWER_KEY_ETH_TYPE, protocol);
|
||||
}
|
||||
|
||||
/*
|
||||
* Traffic control filter encoding
|
||||
*/
|
||||
static ssize_t netlink_tfilter_msg_encode(int cmd, struct zebra_dplane_ctx *ctx,
|
||||
void *data, size_t datalen)
|
||||
{
|
||||
enum dplane_op_e op = dplane_ctx_get_op(ctx);
|
||||
|
||||
struct nlsock *nl;
|
||||
const char *kind_str = NULL;
|
||||
|
||||
struct rtattr *nest;
|
||||
|
||||
uint16_t priority;
|
||||
uint16_t protocol;
|
||||
|
||||
struct {
|
||||
struct nlmsghdr n;
|
||||
struct tcmsg t;
|
||||
char buf[0];
|
||||
} *req = (void *)data;
|
||||
|
||||
if (datalen < sizeof(*req))
|
||||
return 0;
|
||||
|
||||
nl = kernel_netlink_nlsock_lookup(dplane_ctx_get_ns_sock(ctx));
|
||||
|
||||
memset(req, 0, sizeof(*req));
|
||||
|
||||
req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
|
||||
req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
|
||||
|
||||
if (op == DPLANE_OP_TC_FILTER_UPDATE)
|
||||
req->n.nlmsg_flags |= NLM_F_REPLACE;
|
||||
|
||||
req->n.nlmsg_type = cmd;
|
||||
|
||||
req->n.nlmsg_pid = nl->snl.nl_pid;
|
||||
|
||||
req->t.tcm_family = AF_UNSPEC;
|
||||
req->t.tcm_ifindex = dplane_ctx_get_ifindex(ctx);
|
||||
|
||||
priority = dplane_ctx_tc_filter_get_priority(ctx);
|
||||
protocol = htons(dplane_ctx_tc_filter_get_eth_proto(ctx));
|
||||
|
||||
req->t.tcm_info = TC_H_MAKE(priority << 16, protocol);
|
||||
req->t.tcm_handle = dplane_ctx_tc_filter_get_handle(ctx);
|
||||
req->t.tcm_parent = TC_H_MAKE(TC_QDISC_MAJOR_ZEBRA, 0);
|
||||
|
||||
kind_str = dplane_ctx_tc_filter_get_kind_str(ctx);
|
||||
|
||||
if (op == DPLANE_OP_TC_FILTER_ADD || op == DPLANE_OP_TC_FILTER_UPDATE) {
|
||||
nl_attr_put(&req->n, datalen, TCA_KIND, kind_str,
|
||||
strlen(kind_str) + 1);
|
||||
|
||||
zlog_debug(
|
||||
"netlink tfilter encoder: op: %s priority: %u protocol: %u kind: %s handle: %u filter_bm: %u ip_proto: %u",
|
||||
op == DPLANE_OP_TC_FILTER_UPDATE ? "update" : "add",
|
||||
priority, protocol, kind_str,
|
||||
dplane_ctx_tc_filter_get_handle(ctx),
|
||||
dplane_ctx_tc_filter_get_filter_bm(ctx),
|
||||
dplane_ctx_tc_filter_get_ip_proto(ctx));
|
||||
|
||||
nest = nl_attr_nest(&req->n, datalen, TCA_OPTIONS);
|
||||
switch (dplane_ctx_tc_filter_get_kind(ctx)) {
|
||||
case TC_FILTER_FLOWER: {
|
||||
netlink_tfilter_flower_put_options(&req->n, datalen,
|
||||
ctx);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
nl_attr_nest_end(&req->n, nest);
|
||||
}
|
||||
|
||||
return NLMSG_ALIGN(req->n.nlmsg_len);
|
||||
}
|
||||
@ -439,27 +564,318 @@ static ssize_t netlink_newqdisc_msg_encoder(struct zebra_dplane_ctx *ctx,
|
||||
return netlink_qdisc_msg_encode(RTM_NEWQDISC, ctx, buf, buflen);
|
||||
}
|
||||
|
||||
static ssize_t netlink_delqdisc_msg_encoder(struct zebra_dplane_ctx *ctx,
|
||||
void *buf, size_t buflen)
|
||||
{
|
||||
return netlink_qdisc_msg_encode(RTM_DELQDISC, ctx, buf, buflen);
|
||||
}
|
||||
|
||||
static ssize_t netlink_newtclass_msg_encoder(struct zebra_dplane_ctx *ctx,
|
||||
void *buf, size_t buflen)
|
||||
{
|
||||
return netlink_tclass_msg_encode(RTM_NEWTCLASS, ctx, buf, buflen);
|
||||
}
|
||||
|
||||
static ssize_t netlink_deltclass_msg_encoder(struct zebra_dplane_ctx *ctx,
|
||||
void *buf, size_t buflen)
|
||||
{
|
||||
return netlink_tclass_msg_encode(RTM_DELTCLASS, ctx, buf, buflen);
|
||||
}
|
||||
|
||||
static ssize_t netlink_newtfilter_msg_encoder(struct zebra_dplane_ctx *ctx,
|
||||
void *buf, size_t buflen)
|
||||
{
|
||||
return netlink_tfilter_msg_encode(RTM_NEWTFILTER, ctx, buf, buflen);
|
||||
}
|
||||
|
||||
enum netlink_msg_status netlink_put_tc_update_msg(struct nl_batch *bth,
|
||||
struct zebra_dplane_ctx *ctx)
|
||||
static ssize_t netlink_deltfilter_msg_encoder(struct zebra_dplane_ctx *ctx,
|
||||
void *buf, size_t buflen)
|
||||
{
|
||||
/* TODO: error handling and other actions (delete, replace, ...) */
|
||||
return netlink_tfilter_msg_encode(RTM_DELTFILTER, ctx, buf, buflen);
|
||||
}
|
||||
|
||||
netlink_batch_add_msg(bth, ctx, netlink_newqdisc_msg_encoder, false);
|
||||
netlink_batch_add_msg(bth, ctx, netlink_newtclass_msg_encoder, false);
|
||||
return netlink_batch_add_msg(bth, ctx, netlink_newtfilter_msg_encoder,
|
||||
false);
|
||||
enum netlink_msg_status
|
||||
netlink_put_tc_qdisc_update_msg(struct nl_batch *bth,
|
||||
struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
enum dplane_op_e op;
|
||||
enum netlink_msg_status ret;
|
||||
|
||||
op = dplane_ctx_get_op(ctx);
|
||||
|
||||
if (op == DPLANE_OP_TC_QDISC_INSTALL) {
|
||||
ret = netlink_batch_add_msg(
|
||||
bth, ctx, netlink_newqdisc_msg_encoder, false);
|
||||
} else if (op == DPLANE_OP_TC_QDISC_UNINSTALL) {
|
||||
ret = netlink_batch_add_msg(
|
||||
bth, ctx, netlink_delqdisc_msg_encoder, false);
|
||||
} else {
|
||||
return FRR_NETLINK_ERROR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
enum netlink_msg_status
|
||||
netlink_put_tc_class_update_msg(struct nl_batch *bth,
|
||||
struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
enum dplane_op_e op;
|
||||
enum netlink_msg_status ret;
|
||||
|
||||
op = dplane_ctx_get_op(ctx);
|
||||
|
||||
if (op == DPLANE_OP_TC_CLASS_ADD || op == DPLANE_OP_TC_CLASS_UPDATE) {
|
||||
ret = netlink_batch_add_msg(
|
||||
bth, ctx, netlink_newtclass_msg_encoder, false);
|
||||
} else if (op == DPLANE_OP_TC_CLASS_DELETE) {
|
||||
ret = netlink_batch_add_msg(
|
||||
bth, ctx, netlink_deltclass_msg_encoder, false);
|
||||
} else {
|
||||
return FRR_NETLINK_ERROR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
enum netlink_msg_status
|
||||
netlink_put_tc_filter_update_msg(struct nl_batch *bth,
|
||||
struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
enum dplane_op_e op;
|
||||
enum netlink_msg_status ret;
|
||||
|
||||
op = dplane_ctx_get_op(ctx);
|
||||
|
||||
if (op == DPLANE_OP_TC_FILTER_ADD) {
|
||||
ret = netlink_batch_add_msg(
|
||||
bth, ctx, netlink_newtfilter_msg_encoder, false);
|
||||
} else if (op == DPLANE_OP_TC_FILTER_UPDATE) {
|
||||
/*
|
||||
* Replace will fail if either filter type or the number of
|
||||
* filter options is changed, so DEL then NEW
|
||||
*
|
||||
* TFILTER may have refs to TCLASS.
|
||||
*/
|
||||
|
||||
(void)netlink_batch_add_msg(
|
||||
bth, ctx, netlink_deltfilter_msg_encoder, false);
|
||||
ret = netlink_batch_add_msg(
|
||||
bth, ctx, netlink_newtfilter_msg_encoder, false);
|
||||
} else if (op == DPLANE_OP_TC_FILTER_DELETE) {
|
||||
ret = netlink_batch_add_msg(
|
||||
bth, ctx, netlink_deltfilter_msg_encoder, false);
|
||||
} else {
|
||||
return FRR_NETLINK_ERROR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Request filters from the kernel
|
||||
*/
|
||||
static int netlink_request_filters(struct zebra_ns *zns, int family, int type,
|
||||
ifindex_t ifindex)
|
||||
{
|
||||
struct {
|
||||
struct nlmsghdr n;
|
||||
struct tcmsg tc;
|
||||
} req;
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.n.nlmsg_type = type;
|
||||
req.n.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
|
||||
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
|
||||
req.tc.tcm_family = family;
|
||||
req.tc.tcm_ifindex = ifindex;
|
||||
|
||||
return netlink_request(&zns->netlink_cmd, &req);
|
||||
}
|
||||
|
||||
/*
|
||||
* Request queue discipline from the kernel
|
||||
*/
|
||||
static int netlink_request_qdiscs(struct zebra_ns *zns, int family, int type)
|
||||
{
|
||||
struct {
|
||||
struct nlmsghdr n;
|
||||
struct tcmsg tc;
|
||||
} req;
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.n.nlmsg_type = type;
|
||||
req.n.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
|
||||
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
|
||||
req.tc.tcm_family = family;
|
||||
|
||||
return netlink_request(&zns->netlink_cmd, &req);
|
||||
}
|
||||
|
||||
int netlink_qdisc_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
|
||||
{
|
||||
struct tcmsg *tcm;
|
||||
struct zebra_tc_qdisc qdisc = {};
|
||||
|
||||
int len;
|
||||
struct rtattr *tb[TCA_MAX + 1];
|
||||
|
||||
frrtrace(3, frr_zebra, netlink_tc_qdisc_change, h, ns_id, startup);
|
||||
|
||||
len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct tcmsg));
|
||||
|
||||
if (len < 0) {
|
||||
zlog_err(
|
||||
"%s: Message received from netlink is of a broken size %d %zu",
|
||||
__func__, h->nlmsg_len,
|
||||
(size_t)NLMSG_LENGTH(sizeof(struct tcmsg)));
|
||||
return -1;
|
||||
}
|
||||
|
||||
tcm = NLMSG_DATA(h);
|
||||
netlink_parse_rtattr(tb, TCA_MAX, TCA_RTA(tcm), len);
|
||||
|
||||
const char *kind_str = (const char *)RTA_DATA(tb[TCA_KIND]);
|
||||
|
||||
enum tc_qdisc_kind kind = tc_qdisc_str2kind(kind_str);
|
||||
|
||||
qdisc.qdisc.ifindex = tcm->tcm_ifindex;
|
||||
|
||||
switch (kind) {
|
||||
case TC_QDISC_NOQUEUE:
|
||||
/* "noqueue" is the default qdisc */
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (tb[TCA_OPTIONS] != NULL) {
|
||||
struct rtattr *options[TCA_HTB_MAX + 1];
|
||||
|
||||
netlink_parse_rtattr_nested(options, TCA_HTB_MAX,
|
||||
tb[TCA_OPTIONS]);
|
||||
|
||||
/* TODO: more details */
|
||||
/* struct tc_htb_glob *glob = RTA_DATA(options[TCA_HTB_INIT]);
|
||||
*/
|
||||
}
|
||||
|
||||
if (h->nlmsg_type == RTM_NEWQDISC) {
|
||||
if (startup &&
|
||||
TC_H_MAJ(tcm->tcm_handle) == TC_QDISC_MAJOR_ZEBRA) {
|
||||
enum zebra_dplane_result ret;
|
||||
|
||||
ret = dplane_tc_qdisc_uninstall(&qdisc);
|
||||
|
||||
zlog_debug("%s: %s leftover qdisc: ifindex %d kind %s",
|
||||
__func__,
|
||||
((ret == ZEBRA_DPLANE_REQUEST_FAILURE)
|
||||
? "Failed to remove"
|
||||
: "Removed"),
|
||||
qdisc.qdisc.ifindex, kind_str);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int netlink_tclass_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
|
||||
{
|
||||
struct tcmsg *tcm;
|
||||
|
||||
int len;
|
||||
struct rtattr *tb[TCA_MAX + 1];
|
||||
|
||||
frrtrace(3, frr_zebra, netlink_tc_class_change, h, ns_id, startup);
|
||||
|
||||
len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct tcmsg));
|
||||
|
||||
if (len < 0) {
|
||||
zlog_err(
|
||||
"%s: Message received from netlink is of a broken size %d %zu",
|
||||
__func__, h->nlmsg_len,
|
||||
(size_t)NLMSG_LENGTH(sizeof(struct tcmsg)));
|
||||
return -1;
|
||||
}
|
||||
|
||||
tcm = NLMSG_DATA(h);
|
||||
netlink_parse_rtattr(tb, TCA_MAX, TCA_RTA(tcm), len);
|
||||
|
||||
|
||||
if (tb[TCA_OPTIONS] != NULL) {
|
||||
struct rtattr *options[TCA_HTB_MAX + 1];
|
||||
|
||||
netlink_parse_rtattr_nested(options, TCA_HTB_MAX,
|
||||
tb[TCA_OPTIONS]);
|
||||
|
||||
/* TODO: more details */
|
||||
/* struct tc_htb_opt *opt = RTA_DATA(options[TCA_HTB_PARMS]); */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int netlink_tfilter_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
|
||||
{
|
||||
struct tcmsg *tcm;
|
||||
|
||||
int len;
|
||||
struct rtattr *tb[TCA_MAX + 1];
|
||||
|
||||
frrtrace(3, frr_zebra, netlink_tc_filter_change, h, ns_id, startup);
|
||||
|
||||
len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct tcmsg));
|
||||
|
||||
if (len < 0) {
|
||||
zlog_err(
|
||||
"%s: Message received from netlink is of a broken size %d %zu",
|
||||
__func__, h->nlmsg_len,
|
||||
(size_t)NLMSG_LENGTH(sizeof(struct tcmsg)));
|
||||
return -1;
|
||||
}
|
||||
|
||||
tcm = NLMSG_DATA(h);
|
||||
netlink_parse_rtattr(tb, TCA_MAX, TCA_RTA(tcm), len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int netlink_qdisc_read(struct zebra_ns *zns)
|
||||
{
|
||||
int ret;
|
||||
struct zebra_dplane_info dp_info;
|
||||
|
||||
zebra_dplane_info_from_zns(&dp_info, zns, true);
|
||||
|
||||
ret = netlink_request_qdiscs(zns, AF_UNSPEC, RTM_GETQDISC);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = netlink_parse_info(netlink_qdisc_change, &zns->netlink_cmd,
|
||||
&dp_info, 0, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int netlink_tfilter_read_for_interface(struct zebra_ns *zns, ifindex_t ifindex)
|
||||
{
|
||||
int ret;
|
||||
struct zebra_dplane_info dp_info;
|
||||
|
||||
zebra_dplane_info_from_zns(&dp_info, zns, true);
|
||||
|
||||
ret = netlink_request_filters(zns, AF_UNSPEC, RTM_GETTFILTER, ifindex);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = netlink_parse_info(netlink_tfilter_change, &zns->netlink_cmd,
|
||||
&dp_info, 0, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* HAVE_NETLINK */
|
||||
|
@ -48,7 +48,30 @@ enum {
|
||||
};
|
||||
|
||||
extern enum netlink_msg_status
|
||||
netlink_put_tc_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx);
|
||||
netlink_put_tc_qdisc_update_msg(struct nl_batch *bth,
|
||||
struct zebra_dplane_ctx *ctx);
|
||||
extern enum netlink_msg_status
|
||||
netlink_put_tc_class_update_msg(struct nl_batch *bth,
|
||||
struct zebra_dplane_ctx *ctx);
|
||||
extern enum netlink_msg_status
|
||||
netlink_put_tc_filter_update_msg(struct nl_batch *bth,
|
||||
struct zebra_dplane_ctx *ctx);
|
||||
|
||||
/**
|
||||
* "filter" & "class" in the following become "tfilter" & "tclass" for
|
||||
* the sake of consistency with kernel message types (RTM_NEWTFILTER etc.)
|
||||
*/
|
||||
|
||||
extern int netlink_qdisc_read(struct zebra_ns *zns);
|
||||
extern int netlink_tfilter_read_for_interface(struct zebra_ns *zns,
|
||||
ifindex_t ifindex);
|
||||
|
||||
extern int netlink_tfilter_change(struct nlmsghdr *h, ns_id_t ns_id,
|
||||
int startup);
|
||||
extern int netlink_tclass_change(struct nlmsghdr *h, ns_id_t ns_id,
|
||||
int startup);
|
||||
extern int netlink_qdisc_change(struct nlmsghdr *h, ns_id_t ns_id, int startup);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "zebra/rt.h"
|
||||
#include "zebra/zebra_dplane.h"
|
||||
#include "zebra/zebra_errors.h"
|
||||
#include "zebra/zebra_tc.h"
|
||||
|
||||
enum zebra_dplane_result kernel_tc_update(struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "zebra/debug.h"
|
||||
#include "zebra/zebra_pbr.h"
|
||||
#include "zebra/zebra_neigh.h"
|
||||
#include "zebra/zebra_tc.h"
|
||||
#include "printfrr.h"
|
||||
|
||||
/* Memory types */
|
||||
@ -313,23 +314,36 @@ struct dplane_netconf_info {
|
||||
enum dplane_netconf_status_e linkdown_val;
|
||||
};
|
||||
|
||||
/*
|
||||
* Traffic control contexts for the dplane
|
||||
*/
|
||||
struct dplane_tc_info {
|
||||
/* Rate spec (unit: Bytes/s) */
|
||||
struct dplane_tc_qdisc_info {
|
||||
enum tc_qdisc_kind kind;
|
||||
const char *kind_str;
|
||||
};
|
||||
|
||||
struct dplane_tc_class_info {
|
||||
uint32_t handle;
|
||||
enum tc_qdisc_kind kind;
|
||||
const char *kind_str;
|
||||
uint64_t rate;
|
||||
uint64_t ceil;
|
||||
};
|
||||
|
||||
/* TODO: custom burst */
|
||||
|
||||
/* Filter components for "tfilter" */
|
||||
struct dplane_tc_filter_info {
|
||||
uint32_t handle;
|
||||
uint16_t priority;
|
||||
enum tc_filter_kind kind;
|
||||
const char *kind_str;
|
||||
uint32_t filter_bm;
|
||||
uint16_t eth_proto;
|
||||
uint8_t ip_proto;
|
||||
struct prefix src_ip;
|
||||
struct prefix dst_ip;
|
||||
uint8_t ip_proto;
|
||||
|
||||
/* TODO: more filter components */
|
||||
uint16_t src_port_min;
|
||||
uint16_t src_port_max;
|
||||
uint16_t dst_port_min;
|
||||
uint16_t dst_port_max;
|
||||
uint8_t dsfield;
|
||||
uint8_t dsfield_mask;
|
||||
uint32_t classid;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -381,7 +395,9 @@ struct zebra_dplane_ctx {
|
||||
struct dplane_mac_info macinfo;
|
||||
struct dplane_neigh_info neigh;
|
||||
struct dplane_rule_info rule;
|
||||
struct dplane_tc_info tc;
|
||||
struct dplane_tc_qdisc_info tc_qdisc;
|
||||
struct dplane_tc_class_info tc_class;
|
||||
struct dplane_tc_filter_info tc_filter;
|
||||
struct zebra_pbr_iptable iptable;
|
||||
struct zebra_pbr_ipset ipset;
|
||||
struct {
|
||||
@ -800,9 +816,14 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx)
|
||||
case DPLANE_OP_INTF_INSTALL:
|
||||
case DPLANE_OP_INTF_UPDATE:
|
||||
case DPLANE_OP_INTF_DELETE:
|
||||
case DPLANE_OP_TC_INSTALL:
|
||||
case DPLANE_OP_TC_UPDATE:
|
||||
case DPLANE_OP_TC_DELETE:
|
||||
case DPLANE_OP_TC_QDISC_INSTALL:
|
||||
case DPLANE_OP_TC_QDISC_UNINSTALL:
|
||||
case DPLANE_OP_TC_CLASS_ADD:
|
||||
case DPLANE_OP_TC_CLASS_DELETE:
|
||||
case DPLANE_OP_TC_CLASS_UPDATE:
|
||||
case DPLANE_OP_TC_FILTER_ADD:
|
||||
case DPLANE_OP_TC_FILTER_DELETE:
|
||||
case DPLANE_OP_TC_FILTER_UPDATE:
|
||||
break;
|
||||
|
||||
case DPLANE_OP_IPSET_ENTRY_ADD:
|
||||
@ -1127,14 +1148,29 @@ const char *dplane_op2str(enum dplane_op_e op)
|
||||
ret = "INTF_DELETE";
|
||||
break;
|
||||
|
||||
case DPLANE_OP_TC_INSTALL:
|
||||
ret = "TC_INSTALL";
|
||||
case DPLANE_OP_TC_QDISC_INSTALL:
|
||||
ret = "TC_QDISC_INSTALL";
|
||||
break;
|
||||
case DPLANE_OP_TC_UPDATE:
|
||||
ret = "TC_UPDATE";
|
||||
case DPLANE_OP_TC_QDISC_UNINSTALL:
|
||||
ret = "TC_QDISC_UNINSTALL";
|
||||
break;
|
||||
case DPLANE_OP_TC_DELETE:
|
||||
ret = "TC_DELETE";
|
||||
case DPLANE_OP_TC_CLASS_ADD:
|
||||
ret = "TC_CLASS_ADD";
|
||||
break;
|
||||
case DPLANE_OP_TC_CLASS_DELETE:
|
||||
ret = "TC_CLASS_DELETE";
|
||||
break;
|
||||
case DPLANE_OP_TC_CLASS_UPDATE:
|
||||
ret = "TC_CLASS_UPDATE";
|
||||
break;
|
||||
case DPLANE_OP_TC_FILTER_ADD:
|
||||
ret = "TC_FILTER_ADD";
|
||||
break;
|
||||
case DPLANE_OP_TC_FILTER_DELETE:
|
||||
ret = "TC_FILTER_DELETE";
|
||||
break;
|
||||
case DPLANE_OP_TC_FILTER_UPDATE:
|
||||
ret = "TC__FILTER_UPDATE";
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1455,48 +1491,175 @@ uint8_t dplane_ctx_get_old_distance(const struct zebra_dplane_ctx *ctx)
|
||||
return ctx->u.rinfo.zd_old_distance;
|
||||
}
|
||||
|
||||
uint64_t dplane_ctx_tc_get_rate(const struct zebra_dplane_ctx *ctx)
|
||||
int dplane_ctx_tc_qdisc_get_kind(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return ctx->u.tc.rate;
|
||||
return ctx->u.tc_qdisc.kind;
|
||||
}
|
||||
|
||||
uint64_t dplane_ctx_tc_get_ceil(const struct zebra_dplane_ctx *ctx)
|
||||
const char *dplane_ctx_tc_qdisc_get_kind_str(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return ctx->u.tc.ceil;
|
||||
return ctx->u.tc_qdisc.kind_str;
|
||||
}
|
||||
|
||||
uint32_t dplane_ctx_tc_get_filter_bm(const struct zebra_dplane_ctx *ctx)
|
||||
uint32_t dplane_ctx_tc_class_get_handle(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return ctx->u.tc.filter_bm;
|
||||
return ctx->u.tc_class.handle;
|
||||
}
|
||||
|
||||
int dplane_ctx_tc_class_get_kind(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return ctx->u.tc_class.kind;
|
||||
}
|
||||
|
||||
const char *dplane_ctx_tc_class_get_kind_str(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return ctx->u.tc_class.kind_str;
|
||||
}
|
||||
|
||||
uint64_t dplane_ctx_tc_class_get_rate(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return ctx->u.tc_class.rate;
|
||||
}
|
||||
|
||||
uint64_t dplane_ctx_tc_class_get_ceil(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return ctx->u.tc_class.ceil;
|
||||
}
|
||||
|
||||
int dplane_ctx_tc_filter_get_kind(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return ctx->u.tc_filter.kind;
|
||||
}
|
||||
|
||||
const char *
|
||||
dplane_ctx_tc_filter_get_kind_str(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return ctx->u.tc_filter.kind_str;
|
||||
}
|
||||
|
||||
uint32_t dplane_ctx_tc_filter_get_priority(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return ctx->u.tc_filter.priority;
|
||||
}
|
||||
|
||||
uint32_t dplane_ctx_tc_filter_get_handle(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return ctx->u.tc_filter.handle;
|
||||
}
|
||||
|
||||
uint16_t dplane_ctx_tc_filter_get_eth_proto(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return ctx->u.tc_filter.eth_proto;
|
||||
}
|
||||
|
||||
uint32_t dplane_ctx_tc_filter_get_filter_bm(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return ctx->u.tc_filter.filter_bm;
|
||||
}
|
||||
|
||||
const struct prefix *
|
||||
dplane_ctx_tc_get_src_ip(const struct zebra_dplane_ctx *ctx)
|
||||
dplane_ctx_tc_filter_get_src_ip(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return &(ctx->u.tc.src_ip);
|
||||
return &ctx->u.tc_filter.src_ip;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
dplane_ctx_tc_filter_get_src_port_min(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return ctx->u.tc_filter.src_port_min;
|
||||
}
|
||||
|
||||
|
||||
uint16_t
|
||||
dplane_ctx_tc_filter_get_src_port_max(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return ctx->u.tc_filter.src_port_max;
|
||||
}
|
||||
|
||||
const struct prefix *
|
||||
dplane_ctx_tc_get_dst_ip(const struct zebra_dplane_ctx *ctx)
|
||||
dplane_ctx_tc_filter_get_dst_ip(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return &(ctx->u.tc.dst_ip);
|
||||
return &ctx->u.tc_filter.dst_ip;
|
||||
}
|
||||
|
||||
uint8_t dplane_ctx_tc_get_ip_proto(const struct zebra_dplane_ctx *ctx)
|
||||
uint16_t
|
||||
dplane_ctx_tc_filter_get_dst_port_min(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return ctx->u.tc.ip_proto;
|
||||
return ctx->u.tc_filter.dst_port_min;
|
||||
}
|
||||
|
||||
|
||||
uint16_t
|
||||
dplane_ctx_tc_filter_get_dst_port_max(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return ctx->u.tc_filter.dst_port_max;
|
||||
}
|
||||
|
||||
uint8_t dplane_ctx_tc_filter_get_ip_proto(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return ctx->u.tc_filter.ip_proto;
|
||||
}
|
||||
|
||||
uint8_t dplane_ctx_tc_filter_get_dsfield(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return ctx->u.tc_filter.dsfield;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
dplane_ctx_tc_filter_get_dsfield_mask(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return ctx->u.tc_filter.dsfield_mask;
|
||||
}
|
||||
|
||||
uint32_t dplane_ctx_tc_filter_get_classid(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return ctx->u.tc_filter.classid;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2771,7 +2934,9 @@ done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dplane_ctx_tc_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op)
|
||||
static int dplane_ctx_tc_qdisc_init(struct zebra_dplane_ctx *ctx,
|
||||
enum dplane_op_e op,
|
||||
const struct zebra_tc_qdisc *qdisc)
|
||||
{
|
||||
int ret = EINVAL;
|
||||
|
||||
@ -2779,6 +2944,9 @@ int dplane_ctx_tc_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op)
|
||||
|
||||
ctx->zd_op = op;
|
||||
ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
|
||||
ctx->zd_ifindex = qdisc->qdisc.ifindex;
|
||||
ctx->u.tc_qdisc.kind = qdisc->qdisc.kind;
|
||||
ctx->u.tc_qdisc.kind_str = tc_qdisc_kind2str(qdisc->qdisc.kind);
|
||||
|
||||
/* TODO: init traffic control qdisc */
|
||||
zns = zebra_ns_lookup(NS_DEFAULT);
|
||||
@ -2790,6 +2958,74 @@ int dplane_ctx_tc_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dplane_ctx_tc_class_init(struct zebra_dplane_ctx *ctx,
|
||||
enum dplane_op_e op,
|
||||
struct zebra_tc_class *class)
|
||||
{
|
||||
int ret = EINVAL;
|
||||
|
||||
struct zebra_ns *zns = NULL;
|
||||
|
||||
ctx->zd_op = op;
|
||||
ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
|
||||
ctx->zd_ifindex = class->class.ifindex;
|
||||
|
||||
ctx->u.tc_class.handle = class->class.handle;
|
||||
ctx->u.tc_class.kind = class->class.kind;
|
||||
ctx->u.tc_class.kind_str = tc_qdisc_kind2str(class->class.kind);
|
||||
ctx->u.tc_class.rate = class->class.u.htb.rate;
|
||||
ctx->u.tc_class.ceil = class->class.u.htb.ceil;
|
||||
|
||||
zns = zebra_ns_lookup(NS_DEFAULT);
|
||||
|
||||
dplane_ctx_ns_init(ctx, zns, true);
|
||||
|
||||
ret = AOK;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dplane_ctx_tc_filter_init(struct zebra_dplane_ctx *ctx,
|
||||
enum dplane_op_e op,
|
||||
struct zebra_tc_filter *filter)
|
||||
{
|
||||
int ret = EINVAL;
|
||||
|
||||
struct zebra_ns *zns = NULL;
|
||||
|
||||
ctx->zd_op = op;
|
||||
ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
|
||||
ctx->zd_ifindex = filter->filter.ifindex;
|
||||
|
||||
ctx->u.tc_filter.eth_proto = filter->filter.protocol;
|
||||
ctx->u.tc_filter.ip_proto = filter->filter.u.flower.ip_proto;
|
||||
|
||||
ctx->u.tc_filter.kind = filter->filter.kind;
|
||||
ctx->u.tc_filter.kind_str = tc_filter_kind2str(filter->filter.kind);
|
||||
|
||||
ctx->u.tc_filter.filter_bm = filter->filter.u.flower.filter_bm;
|
||||
prefix_copy(&ctx->u.tc_filter.src_ip, &filter->filter.u.flower.src_ip);
|
||||
ctx->u.tc_filter.src_port_min = filter->filter.u.flower.src_port_min;
|
||||
ctx->u.tc_filter.src_port_max = filter->filter.u.flower.src_port_max;
|
||||
prefix_copy(&ctx->u.tc_filter.dst_ip, &filter->filter.u.flower.dst_ip);
|
||||
ctx->u.tc_filter.dst_port_min = filter->filter.u.flower.dst_port_min;
|
||||
ctx->u.tc_filter.dst_port_max = filter->filter.u.flower.dst_port_max;
|
||||
ctx->u.tc_filter.dsfield = filter->filter.u.flower.dsfield;
|
||||
ctx->u.tc_filter.dsfield_mask = filter->filter.u.flower.dsfield_mask;
|
||||
ctx->u.tc_filter.classid = filter->filter.u.flower.classid;
|
||||
|
||||
ctx->u.tc_filter.priority = filter->filter.priority;
|
||||
ctx->u.tc_filter.handle = filter->filter.handle;
|
||||
|
||||
zns = zebra_ns_lookup(NS_DEFAULT);
|
||||
|
||||
dplane_ctx_ns_init(ctx, zns, true);
|
||||
|
||||
ret = AOK;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dplane_ctx_nexthop_init() - Initialize a context block for a nexthop update
|
||||
*
|
||||
@ -3509,7 +3745,9 @@ dplane_route_update_internal(struct route_node *rn,
|
||||
return result;
|
||||
}
|
||||
|
||||
static enum zebra_dplane_result dplane_tc_update_internal(enum dplane_op_e op)
|
||||
static enum zebra_dplane_result
|
||||
tc_qdisc_update_internal(enum dplane_op_e op,
|
||||
const struct zebra_tc_qdisc *qdisc)
|
||||
{
|
||||
enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
|
||||
int ret;
|
||||
@ -3524,7 +3762,7 @@ static enum zebra_dplane_result dplane_tc_update_internal(enum dplane_op_e op)
|
||||
}
|
||||
|
||||
/* Init context with info from zebra data structs */
|
||||
ret = dplane_ctx_tc_init(ctx, op);
|
||||
ret = dplane_ctx_tc_qdisc_init(ctx, op, qdisc);
|
||||
|
||||
if (ret == AOK)
|
||||
ret = dplane_update_enqueue(ctx);
|
||||
@ -3545,9 +3783,118 @@ done:
|
||||
return result;
|
||||
}
|
||||
|
||||
enum zebra_dplane_result dplane_tc_update(void)
|
||||
static enum zebra_dplane_result
|
||||
tc_class_update_internal(enum dplane_op_e op, struct zebra_tc_class *class)
|
||||
{
|
||||
return dplane_tc_update_internal(DPLANE_OP_TC_UPDATE);
|
||||
enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
|
||||
int ret;
|
||||
struct zebra_dplane_ctx *ctx = NULL;
|
||||
|
||||
/* Obtain context block */
|
||||
ctx = dplane_ctx_alloc();
|
||||
|
||||
if (!ctx) {
|
||||
ret = ENOMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Init context with info from zebra data structs */
|
||||
ret = dplane_ctx_tc_class_init(ctx, op, class);
|
||||
|
||||
if (ret == AOK)
|
||||
ret = dplane_update_enqueue(ctx);
|
||||
|
||||
done:
|
||||
/* Update counter */
|
||||
atomic_fetch_add_explicit(&zdplane_info.dg_tcs_in, 1,
|
||||
memory_order_relaxed);
|
||||
if (ret == AOK) {
|
||||
result = ZEBRA_DPLANE_REQUEST_QUEUED;
|
||||
} else {
|
||||
atomic_fetch_add_explicit(&zdplane_info.dg_tcs_errors, 1,
|
||||
memory_order_relaxed);
|
||||
if (ctx)
|
||||
dplane_ctx_free(&ctx);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static enum zebra_dplane_result
|
||||
tc_filter_update_internal(enum dplane_op_e op, struct zebra_tc_filter *filter)
|
||||
{
|
||||
enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
|
||||
int ret;
|
||||
struct zebra_dplane_ctx *ctx = NULL;
|
||||
|
||||
/* Obtain context block */
|
||||
ctx = dplane_ctx_alloc();
|
||||
|
||||
if (!ctx) {
|
||||
ret = ENOMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Init context with info from zebra data structs */
|
||||
ret = dplane_ctx_tc_filter_init(ctx, op, filter);
|
||||
|
||||
if (ret == AOK)
|
||||
ret = dplane_update_enqueue(ctx);
|
||||
|
||||
done:
|
||||
/* Update counter */
|
||||
atomic_fetch_add_explicit(&zdplane_info.dg_tcs_in, 1,
|
||||
memory_order_relaxed);
|
||||
if (ret == AOK) {
|
||||
result = ZEBRA_DPLANE_REQUEST_QUEUED;
|
||||
} else {
|
||||
atomic_fetch_add_explicit(&zdplane_info.dg_tcs_errors, 1,
|
||||
memory_order_relaxed);
|
||||
if (ctx)
|
||||
dplane_ctx_free(&ctx);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
enum zebra_dplane_result dplane_tc_qdisc_install(struct zebra_tc_qdisc *qdisc)
|
||||
{
|
||||
return tc_qdisc_update_internal(DPLANE_OP_TC_QDISC_INSTALL, qdisc);
|
||||
}
|
||||
|
||||
enum zebra_dplane_result dplane_tc_qdisc_uninstall(struct zebra_tc_qdisc *qdisc)
|
||||
{
|
||||
return tc_qdisc_update_internal(DPLANE_OP_TC_QDISC_UNINSTALL, qdisc);
|
||||
}
|
||||
|
||||
enum zebra_dplane_result dplane_tc_class_add(struct zebra_tc_class *class)
|
||||
{
|
||||
return tc_class_update_internal(DPLANE_OP_TC_CLASS_ADD, class);
|
||||
}
|
||||
|
||||
enum zebra_dplane_result dplane_tc_class_delete(struct zebra_tc_class *class)
|
||||
{
|
||||
return tc_class_update_internal(DPLANE_OP_TC_CLASS_DELETE, class);
|
||||
}
|
||||
|
||||
enum zebra_dplane_result dplane_tc_class_update(struct zebra_tc_class *class)
|
||||
{
|
||||
return tc_class_update_internal(DPLANE_OP_TC_CLASS_UPDATE, class);
|
||||
}
|
||||
|
||||
enum zebra_dplane_result dplane_tc_filter_add(struct zebra_tc_filter *filter)
|
||||
{
|
||||
return tc_filter_update_internal(DPLANE_OP_TC_FILTER_ADD, filter);
|
||||
}
|
||||
|
||||
enum zebra_dplane_result dplane_tc_filter_delete(struct zebra_tc_filter *filter)
|
||||
{
|
||||
return tc_filter_update_internal(DPLANE_OP_TC_FILTER_DELETE, filter);
|
||||
}
|
||||
|
||||
enum zebra_dplane_result dplane_tc_filter_update(struct zebra_tc_filter *filter)
|
||||
{
|
||||
return tc_filter_update_internal(DPLANE_OP_TC_FILTER_UPDATE, filter);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -5733,10 +6080,18 @@ static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx)
|
||||
break;
|
||||
|
||||
/* TODO: more detailed log */
|
||||
case DPLANE_OP_TC_INSTALL:
|
||||
case DPLANE_OP_TC_UPDATE:
|
||||
case DPLANE_OP_TC_DELETE:
|
||||
zlog_debug("Dplane tc ifidx %u", dplane_ctx_get_ifindex(ctx));
|
||||
case DPLANE_OP_TC_QDISC_INSTALL:
|
||||
case DPLANE_OP_TC_QDISC_UNINSTALL:
|
||||
zlog_debug("Dplane tc qdisc ifidx %u",
|
||||
dplane_ctx_get_ifindex(ctx));
|
||||
break;
|
||||
case DPLANE_OP_TC_CLASS_ADD:
|
||||
case DPLANE_OP_TC_CLASS_DELETE:
|
||||
case DPLANE_OP_TC_CLASS_UPDATE:
|
||||
break;
|
||||
case DPLANE_OP_TC_FILTER_ADD:
|
||||
case DPLANE_OP_TC_FILTER_DELETE:
|
||||
case DPLANE_OP_TC_FILTER_UPDATE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -5881,9 +6236,14 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx)
|
||||
1, memory_order_relaxed);
|
||||
break;
|
||||
|
||||
case DPLANE_OP_TC_INSTALL:
|
||||
case DPLANE_OP_TC_UPDATE:
|
||||
case DPLANE_OP_TC_DELETE:
|
||||
case DPLANE_OP_TC_QDISC_INSTALL:
|
||||
case DPLANE_OP_TC_QDISC_UNINSTALL:
|
||||
case DPLANE_OP_TC_CLASS_ADD:
|
||||
case DPLANE_OP_TC_CLASS_DELETE:
|
||||
case DPLANE_OP_TC_CLASS_UPDATE:
|
||||
case DPLANE_OP_TC_FILTER_ADD:
|
||||
case DPLANE_OP_TC_FILTER_DELETE:
|
||||
case DPLANE_OP_TC_FILTER_UPDATE:
|
||||
if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
|
||||
atomic_fetch_add_explicit(&zdplane_info.dg_tcs_errors,
|
||||
1, memory_order_relaxed);
|
||||
|
@ -195,9 +195,14 @@ enum dplane_op_e {
|
||||
DPLANE_OP_INTF_DELETE,
|
||||
|
||||
/* Traffic control */
|
||||
DPLANE_OP_TC_INSTALL,
|
||||
DPLANE_OP_TC_UPDATE,
|
||||
DPLANE_OP_TC_DELETE,
|
||||
DPLANE_OP_TC_QDISC_INSTALL,
|
||||
DPLANE_OP_TC_QDISC_UNINSTALL,
|
||||
DPLANE_OP_TC_CLASS_ADD,
|
||||
DPLANE_OP_TC_CLASS_DELETE,
|
||||
DPLANE_OP_TC_CLASS_UPDATE,
|
||||
DPLANE_OP_TC_FILTER_ADD,
|
||||
DPLANE_OP_TC_FILTER_DELETE,
|
||||
DPLANE_OP_TC_FILTER_UPDATE
|
||||
};
|
||||
|
||||
/*
|
||||
@ -384,14 +389,42 @@ void dplane_ctx_set_distance(struct zebra_dplane_ctx *ctx, uint8_t distance);
|
||||
uint8_t dplane_ctx_get_old_distance(const struct zebra_dplane_ctx *ctx);
|
||||
|
||||
/* Accessors for traffic control context */
|
||||
uint64_t dplane_ctx_tc_get_rate(const struct zebra_dplane_ctx *ctx);
|
||||
uint64_t dplane_ctx_tc_get_ceil(const struct zebra_dplane_ctx *ctx);
|
||||
uint32_t dplane_ctx_tc_get_filter_bm(const struct zebra_dplane_ctx *ctx);
|
||||
int dplane_ctx_tc_qdisc_get_kind(const struct zebra_dplane_ctx *ctx);
|
||||
const char *
|
||||
dplane_ctx_tc_qdisc_get_kind_str(const struct zebra_dplane_ctx *ctx);
|
||||
|
||||
uint32_t dplane_ctx_tc_class_get_handle(const struct zebra_dplane_ctx *ctx);
|
||||
int dplane_ctx_tc_class_get_kind(const struct zebra_dplane_ctx *ctx);
|
||||
const char *
|
||||
dplane_ctx_tc_class_get_kind_str(const struct zebra_dplane_ctx *ctx);
|
||||
uint64_t dplane_ctx_tc_class_get_rate(const struct zebra_dplane_ctx *ctx);
|
||||
uint64_t dplane_ctx_tc_class_get_ceil(const struct zebra_dplane_ctx *ctx);
|
||||
|
||||
int dplane_ctx_tc_filter_get_kind(const struct zebra_dplane_ctx *ctx);
|
||||
const char *
|
||||
dplane_ctx_tc_filter_get_kind_str(const struct zebra_dplane_ctx *ctx);
|
||||
uint32_t dplane_ctx_tc_filter_get_priority(const struct zebra_dplane_ctx *ctx);
|
||||
uint32_t dplane_ctx_tc_filter_get_handle(const struct zebra_dplane_ctx *ctx);
|
||||
uint16_t dplane_ctx_tc_filter_get_minor(const struct zebra_dplane_ctx *ctx);
|
||||
uint16_t dplane_ctx_tc_filter_get_eth_proto(const struct zebra_dplane_ctx *ctx);
|
||||
uint32_t dplane_ctx_tc_filter_get_filter_bm(const struct zebra_dplane_ctx *ctx);
|
||||
const struct prefix *
|
||||
dplane_ctx_tc_get_src_ip(const struct zebra_dplane_ctx *ctx);
|
||||
dplane_ctx_tc_filter_get_src_ip(const struct zebra_dplane_ctx *ctx);
|
||||
uint16_t
|
||||
dplane_ctx_tc_filter_get_src_port_min(const struct zebra_dplane_ctx *ctx);
|
||||
uint16_t
|
||||
dplane_ctx_tc_filter_get_src_port_max(const struct zebra_dplane_ctx *ctx);
|
||||
const struct prefix *
|
||||
dplane_ctx_tc_get_dst_ip(const struct zebra_dplane_ctx *ctx);
|
||||
uint8_t dplane_ctx_tc_get_ip_proto(const struct zebra_dplane_ctx *ctx);
|
||||
dplane_ctx_tc_filter_get_dst_ip(const struct zebra_dplane_ctx *ctx);
|
||||
uint16_t
|
||||
dplane_ctx_tc_filter_get_dst_port_min(const struct zebra_dplane_ctx *ctx);
|
||||
uint16_t
|
||||
dplane_ctx_tc_filter_get_dst_port_max(const struct zebra_dplane_ctx *ctx);
|
||||
uint8_t dplane_ctx_tc_filter_get_ip_proto(const struct zebra_dplane_ctx *ctx);
|
||||
uint8_t dplane_ctx_tc_filter_get_dsfield(const struct zebra_dplane_ctx *ctx);
|
||||
uint8_t
|
||||
dplane_ctx_tc_filter_get_dsfield_mask(const struct zebra_dplane_ctx *ctx);
|
||||
uint32_t dplane_ctx_tc_filter_get_classid(const struct zebra_dplane_ctx *ctx);
|
||||
|
||||
void dplane_ctx_set_nexthops(struct zebra_dplane_ctx *ctx, struct nexthop *nh);
|
||||
void dplane_ctx_set_backup_nhg(struct zebra_dplane_ctx *ctx,
|
||||
@ -723,11 +756,23 @@ enum zebra_dplane_result dplane_intf_update(const struct interface *ifp);
|
||||
enum zebra_dplane_result dplane_intf_delete(const struct interface *ifp);
|
||||
|
||||
/*
|
||||
* Enqueue interface link changes for the dataplane.
|
||||
* Enqueue tc link changes for the dataplane.
|
||||
*/
|
||||
enum zebra_dplane_result dplane_tc_add(void);
|
||||
enum zebra_dplane_result dplane_tc_update(void);
|
||||
enum zebra_dplane_result dplane_tc_delete(void);
|
||||
|
||||
struct zebra_tc_qdisc;
|
||||
struct zebra_tc_class;
|
||||
struct zebra_tc_filter;
|
||||
enum zebra_dplane_result dplane_tc_qdisc_install(struct zebra_tc_qdisc *qdisc);
|
||||
enum zebra_dplane_result
|
||||
dplane_tc_qdisc_uninstall(struct zebra_tc_qdisc *qdisc);
|
||||
enum zebra_dplane_result dplane_tc_class_add(struct zebra_tc_class *class);
|
||||
enum zebra_dplane_result dplane_tc_class_delete(struct zebra_tc_class *class);
|
||||
enum zebra_dplane_result dplane_tc_class_update(struct zebra_tc_class *class);
|
||||
enum zebra_dplane_result dplane_tc_filter_add(struct zebra_tc_filter *filter);
|
||||
enum zebra_dplane_result
|
||||
dplane_tc_filter_delete(struct zebra_tc_filter *filter);
|
||||
enum zebra_dplane_result
|
||||
dplane_tc_filter_update(struct zebra_tc_filter *filter);
|
||||
|
||||
/*
|
||||
* Link layer operations for the dataplane.
|
||||
|
@ -3168,9 +3168,14 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
|
||||
case DPLANE_OP_INTF_INSTALL:
|
||||
case DPLANE_OP_INTF_UPDATE:
|
||||
case DPLANE_OP_INTF_DELETE:
|
||||
case DPLANE_OP_TC_INSTALL:
|
||||
case DPLANE_OP_TC_UPDATE:
|
||||
case DPLANE_OP_TC_DELETE:
|
||||
case DPLANE_OP_TC_QDISC_INSTALL:
|
||||
case DPLANE_OP_TC_QDISC_UNINSTALL:
|
||||
case DPLANE_OP_TC_CLASS_ADD:
|
||||
case DPLANE_OP_TC_CLASS_DELETE:
|
||||
case DPLANE_OP_TC_CLASS_UPDATE:
|
||||
case DPLANE_OP_TC_FILTER_ADD:
|
||||
case DPLANE_OP_TC_FILTER_DELETE:
|
||||
case DPLANE_OP_TC_FILTER_UPDATE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "zebra_netns_notify.h"
|
||||
#include "zebra_netns_id.h"
|
||||
#include "zebra_pbr.h"
|
||||
#include "zebra_tc.h"
|
||||
#include "rib.h"
|
||||
#include "table_manager.h"
|
||||
#include "zebra_errors.h"
|
||||
@ -127,6 +128,7 @@ int zebra_ns_enable(ns_id_t ns_id, void **info)
|
||||
interface_list(zns);
|
||||
route_read(zns);
|
||||
kernel_read_pbr_rules(zns);
|
||||
kernel_read_tc_qdisc(zns);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -4710,9 +4710,14 @@ static void rib_process_dplane_results(struct thread *thread)
|
||||
zebra_if_dplane_result(ctx);
|
||||
break;
|
||||
|
||||
case DPLANE_OP_TC_INSTALL:
|
||||
case DPLANE_OP_TC_UPDATE:
|
||||
case DPLANE_OP_TC_DELETE:
|
||||
case DPLANE_OP_TC_QDISC_INSTALL:
|
||||
case DPLANE_OP_TC_QDISC_UNINSTALL:
|
||||
case DPLANE_OP_TC_CLASS_ADD:
|
||||
case DPLANE_OP_TC_CLASS_DELETE:
|
||||
case DPLANE_OP_TC_CLASS_UPDATE:
|
||||
case DPLANE_OP_TC_FILTER_ADD:
|
||||
case DPLANE_OP_TC_FILTER_DELETE:
|
||||
case DPLANE_OP_TC_FILTER_UPDATE:
|
||||
break;
|
||||
|
||||
/* Some op codes not handled here */
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "zebra_mlag.h"
|
||||
#include "zebra_nhg.h"
|
||||
#include "zebra_neigh.h"
|
||||
#include "zebra/zebra_tc.h"
|
||||
#include "debug.h"
|
||||
#include "zebra_script.h"
|
||||
|
||||
@ -312,6 +313,20 @@ void zebra_router_init(bool asic_offload, bool notify_on_ack)
|
||||
hash_create_size(8, zebra_nhg_id_key, zebra_nhg_hash_id_equal,
|
||||
"Zebra Router Nexthop Groups ID index");
|
||||
|
||||
zrouter.rules_hash =
|
||||
hash_create_size(8, zebra_pbr_rules_hash_key,
|
||||
zebra_pbr_rules_hash_equal, "Rules Hash");
|
||||
|
||||
zrouter.qdisc_hash =
|
||||
hash_create_size(8, zebra_tc_qdisc_hash_key,
|
||||
zebra_tc_qdisc_hash_equal, "TC (qdisc) Hash");
|
||||
zrouter.class_hash = hash_create_size(8, zebra_tc_class_hash_key,
|
||||
zebra_tc_class_hash_equal,
|
||||
"TC (classes) Hash");
|
||||
zrouter.filter_hash = hash_create_size(8, zebra_tc_filter_hash_key,
|
||||
zebra_tc_filter_hash_equal,
|
||||
"TC (filter) Hash");
|
||||
|
||||
zrouter.asic_offloaded = asic_offload;
|
||||
zrouter.notify_on_ack = notify_on_ack;
|
||||
|
||||
|
@ -172,6 +172,10 @@ struct zebra_router {
|
||||
|
||||
struct hash *iptable_hash;
|
||||
|
||||
struct hash *qdisc_hash;
|
||||
struct hash *class_hash;
|
||||
struct hash *filter_hash;
|
||||
|
||||
/* A sequence number used for tracking routes */
|
||||
_Atomic uint32_t sequence_num;
|
||||
|
||||
|
444
zebra/zebra_tc.c
Normal file
444
zebra/zebra_tc.c
Normal file
@ -0,0 +1,444 @@
|
||||
/*
|
||||
* Zebra Traffic Control (TC) main handling.
|
||||
*
|
||||
* Copyright (C) 2022 Shichu Yang
|
||||
*
|
||||
* 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 <jhash.h>
|
||||
#include <hash.h>
|
||||
#include <memory.h>
|
||||
#include <hook.h>
|
||||
|
||||
#include "zebra/zebra_router.h"
|
||||
#include "zebra/zebra_dplane.h"
|
||||
#include "zebra/zebra_tc.h"
|
||||
#include "zebra/debug.h"
|
||||
|
||||
DEFINE_MTYPE_STATIC(ZEBRA, TC_QDISC, "TC queue discipline");
|
||||
DEFINE_MTYPE_STATIC(ZEBRA, TC_CLASS, "TC class");
|
||||
DEFINE_MTYPE_STATIC(ZEBRA, TC_FILTER, "TC filter");
|
||||
|
||||
const struct message tc_qdisc_kinds[] = {
|
||||
{TC_QDISC_HTB, "htb"},
|
||||
{TC_QDISC_NOQUEUE, "noqueue"},
|
||||
{0},
|
||||
};
|
||||
|
||||
const struct message tc_filter_kinds[] = {
|
||||
{TC_FILTER_BPF, "bpf"},
|
||||
{TC_FILTER_FLOW, "flow"},
|
||||
{TC_FILTER_FLOWER, "flower"},
|
||||
{TC_FILTER_U32, "u32"},
|
||||
{0},
|
||||
};
|
||||
|
||||
const struct message *tc_class_kinds = tc_qdisc_kinds;
|
||||
|
||||
static uint32_t lookup_key(const struct message *mz, const char *msg,
|
||||
uint32_t nf)
|
||||
{
|
||||
static struct message nt = {0};
|
||||
uint32_t rz = nf ? nf : UINT32_MAX;
|
||||
const struct message *pnt;
|
||||
|
||||
for (pnt = mz; memcmp(pnt, &nt, sizeof(struct message)); pnt++)
|
||||
if (strcmp(pnt->str, msg) == 0) {
|
||||
rz = pnt->key;
|
||||
break;
|
||||
}
|
||||
return rz;
|
||||
}
|
||||
|
||||
const char *tc_qdisc_kind2str(uint32_t type)
|
||||
{
|
||||
return lookup_msg(tc_qdisc_kinds, type, "Unrecognized QDISC Type");
|
||||
}
|
||||
|
||||
enum tc_qdisc_kind tc_qdisc_str2kind(const char *type)
|
||||
{
|
||||
return lookup_key(tc_qdisc_kinds, type, TC_QDISC_UNSPEC);
|
||||
}
|
||||
|
||||
uint32_t zebra_tc_qdisc_hash_key(const void *arg)
|
||||
{
|
||||
const struct zebra_tc_qdisc *qdisc;
|
||||
uint32_t key;
|
||||
|
||||
qdisc = arg;
|
||||
|
||||
key = jhash_1word(qdisc->qdisc.ifindex, 0);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
bool zebra_tc_qdisc_hash_equal(const void *arg1, const void *arg2)
|
||||
{
|
||||
const struct zebra_tc_qdisc *q1, *q2;
|
||||
|
||||
q1 = (const struct zebra_tc_qdisc *)arg1;
|
||||
q2 = (const struct zebra_tc_qdisc *)arg2;
|
||||
|
||||
if (q1->qdisc.ifindex != q2->qdisc.ifindex)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct tc_qdisc_ifindex_lookup {
|
||||
struct zebra_tc_qdisc *qdisc;
|
||||
ifindex_t ifindex;
|
||||
};
|
||||
|
||||
|
||||
static int tc_qdisc_lookup_ifindex_walker(struct hash_bucket *b, void *data)
|
||||
{
|
||||
struct tc_qdisc_ifindex_lookup *lookup = data;
|
||||
struct zebra_tc_qdisc *qdisc = b->data;
|
||||
|
||||
if (lookup->ifindex == qdisc->qdisc.ifindex) {
|
||||
lookup->qdisc = qdisc;
|
||||
return HASHWALK_ABORT;
|
||||
}
|
||||
|
||||
return HASHWALK_CONTINUE;
|
||||
}
|
||||
|
||||
static struct zebra_tc_qdisc *
|
||||
tc_qdisc_lookup_ifindex(struct zebra_tc_qdisc *qdisc)
|
||||
{
|
||||
struct tc_qdisc_ifindex_lookup lookup;
|
||||
|
||||
lookup.ifindex = qdisc->qdisc.ifindex;
|
||||
lookup.qdisc = NULL;
|
||||
hash_walk(zrouter.rules_hash, &tc_qdisc_lookup_ifindex_walker, &lookup);
|
||||
|
||||
return lookup.qdisc;
|
||||
}
|
||||
|
||||
static void *tc_qdisc_alloc_intern(void *arg)
|
||||
{
|
||||
struct zebra_tc_qdisc *ztq;
|
||||
struct zebra_tc_qdisc *new;
|
||||
|
||||
ztq = (struct zebra_tc_qdisc *)arg;
|
||||
|
||||
new = XCALLOC(MTYPE_TC_QDISC, sizeof(*new));
|
||||
|
||||
memcpy(new, ztq, sizeof(*ztq));
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
static struct zebra_tc_qdisc *tc_qdisc_free(struct zebra_tc_qdisc *hash_data,
|
||||
bool free_data)
|
||||
{
|
||||
hash_release(zrouter.qdisc_hash, hash_data);
|
||||
|
||||
if (free_data) {
|
||||
XFREE(MTYPE_TC_QDISC, hash_data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return hash_data;
|
||||
}
|
||||
|
||||
static struct zebra_tc_qdisc *tc_qdisc_release(struct zebra_tc_qdisc *qdisc,
|
||||
bool free_data)
|
||||
{
|
||||
struct zebra_tc_qdisc *lookup;
|
||||
|
||||
lookup = hash_lookup(zrouter.qdisc_hash, qdisc);
|
||||
|
||||
if (!lookup)
|
||||
return NULL;
|
||||
|
||||
return tc_qdisc_free(lookup, free_data);
|
||||
}
|
||||
|
||||
void zebra_tc_qdisc_install(struct zebra_tc_qdisc *qdisc)
|
||||
{
|
||||
if (IS_ZEBRA_DEBUG_TC)
|
||||
zlog_debug("%s: install tc qdisc ifindex %d kind %s", __func__,
|
||||
qdisc->qdisc.ifindex,
|
||||
tc_qdisc_kind2str(qdisc->qdisc.kind));
|
||||
|
||||
struct zebra_tc_qdisc *found;
|
||||
struct zebra_tc_qdisc *old;
|
||||
struct zebra_tc_qdisc *new;
|
||||
|
||||
found = tc_qdisc_lookup_ifindex(qdisc);
|
||||
|
||||
if (found) {
|
||||
if (!zebra_tc_qdisc_hash_equal(qdisc, found)) {
|
||||
old = tc_qdisc_release(found, false);
|
||||
(void)dplane_tc_qdisc_uninstall(old);
|
||||
new = hash_get(zrouter.qdisc_hash, qdisc,
|
||||
tc_qdisc_alloc_intern);
|
||||
(void)dplane_tc_qdisc_install(new);
|
||||
XFREE(MTYPE_TC_QDISC, old);
|
||||
}
|
||||
} else {
|
||||
new = hash_get(zrouter.qdisc_hash, qdisc,
|
||||
tc_qdisc_alloc_intern);
|
||||
(void)dplane_tc_qdisc_install(new);
|
||||
}
|
||||
}
|
||||
|
||||
void zebra_tc_qdisc_uninstall(struct zebra_tc_qdisc *qdisc)
|
||||
{
|
||||
if (IS_ZEBRA_DEBUG_TC)
|
||||
zlog_debug("%s: uninstall tc qdisc ifindex %d kind %s",
|
||||
__func__, qdisc->qdisc.ifindex,
|
||||
tc_qdisc_kind2str(qdisc->qdisc.kind));
|
||||
|
||||
(void)dplane_tc_qdisc_uninstall(qdisc);
|
||||
|
||||
if (tc_qdisc_release(qdisc, true))
|
||||
zlog_debug("%s: tc qdisc being deleted we know nothing about",
|
||||
__func__);
|
||||
}
|
||||
|
||||
uint32_t zebra_tc_class_hash_key(const void *arg)
|
||||
{
|
||||
const struct zebra_tc_class *class;
|
||||
uint32_t key;
|
||||
|
||||
class = arg;
|
||||
|
||||
key = jhash_2words(class->class.ifindex, class->class.handle, 0);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
bool zebra_tc_class_hash_equal(const void *arg1, const void *arg2)
|
||||
{
|
||||
const struct zebra_tc_class *c1, *c2;
|
||||
|
||||
c1 = (const struct zebra_tc_class *)arg1;
|
||||
c2 = (const struct zebra_tc_class *)arg2;
|
||||
|
||||
if (c1->class.ifindex != c2->class.ifindex)
|
||||
return false;
|
||||
|
||||
if (c1->class.handle != c2->class.handle)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void *tc_class_alloc_intern(void *arg)
|
||||
{
|
||||
struct zebra_tc_class *class;
|
||||
struct zebra_tc_class *new;
|
||||
|
||||
class = (struct zebra_tc_class *)arg;
|
||||
|
||||
new = XCALLOC(MTYPE_TC_CLASS, sizeof(*new));
|
||||
|
||||
memcpy(new, class, sizeof(*class));
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
static struct zebra_tc_class *tc_class_free(struct zebra_tc_class *hash_data,
|
||||
bool free_data)
|
||||
{
|
||||
hash_release(zrouter.class_hash, hash_data);
|
||||
|
||||
if (free_data) {
|
||||
XFREE(MTYPE_TC_CLASS, hash_data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return hash_data;
|
||||
}
|
||||
|
||||
static struct zebra_tc_class *tc_class_release(struct zebra_tc_class *class,
|
||||
bool free_data)
|
||||
{
|
||||
struct zebra_tc_class *lookup;
|
||||
|
||||
lookup = hash_lookup(zrouter.class_hash, class);
|
||||
|
||||
if (!lookup)
|
||||
return NULL;
|
||||
|
||||
return tc_class_free(lookup, free_data);
|
||||
}
|
||||
|
||||
void zebra_tc_class_add(struct zebra_tc_class *class)
|
||||
{
|
||||
if (IS_ZEBRA_DEBUG_TC)
|
||||
zlog_debug(
|
||||
"%s: add tc class ifindex %d handle %04x:%04x kind %s",
|
||||
__func__, class->class.ifindex,
|
||||
(class->class.handle & 0xffff0000u) >> 16,
|
||||
class->class.handle & 0x0000ffffu,
|
||||
tc_qdisc_kind2str(class->class.kind));
|
||||
|
||||
struct zebra_tc_class *found;
|
||||
struct zebra_tc_class *new;
|
||||
|
||||
/*
|
||||
* We find the class in the hash by (ifindex, handle) directly, and by
|
||||
* testing their deep equality to seek out whether it's an update.
|
||||
*
|
||||
* Currently deep equality is not checked since it will be okay to
|
||||
* update the totally same class again.
|
||||
*/
|
||||
found = hash_lookup(zrouter.class_hash, class);
|
||||
new = hash_get(zrouter.class_hash, class, tc_class_alloc_intern);
|
||||
|
||||
if (found)
|
||||
(void)dplane_tc_class_update(new);
|
||||
else
|
||||
(void)dplane_tc_class_add(new);
|
||||
}
|
||||
|
||||
void zebra_tc_class_delete(struct zebra_tc_class *class)
|
||||
{
|
||||
if (IS_ZEBRA_DEBUG_TC)
|
||||
zlog_debug(
|
||||
"%s: delete tc class ifindex %d handle %04x:%04x kind %s",
|
||||
__func__, class->class.ifindex,
|
||||
(class->class.handle & 0xffff0000u) >> 16,
|
||||
class->class.handle & 0x0000ffffu,
|
||||
tc_qdisc_kind2str(class->class.kind));
|
||||
|
||||
(void)dplane_tc_class_delete(class);
|
||||
|
||||
if (tc_class_release(class, true))
|
||||
zlog_debug("%s: tc class being deleted we know nothing about",
|
||||
__func__);
|
||||
}
|
||||
|
||||
const char *tc_filter_kind2str(uint32_t type)
|
||||
{
|
||||
return lookup_msg(tc_filter_kinds, type, "Unrecognized TFILTER Type");
|
||||
}
|
||||
|
||||
enum tc_qdisc_kind tc_filter_str2kind(const char *type)
|
||||
{
|
||||
return lookup_key(tc_filter_kinds, type, TC_FILTER_UNSPEC);
|
||||
}
|
||||
|
||||
uint32_t zebra_tc_filter_hash_key(const void *arg)
|
||||
{
|
||||
const struct zebra_tc_filter *filter;
|
||||
uint32_t key;
|
||||
|
||||
filter = arg;
|
||||
|
||||
key = jhash_2words(filter->filter.ifindex, filter->filter.handle, 0);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
bool zebra_tc_filter_hash_equal(const void *arg1, const void *arg2)
|
||||
{
|
||||
const struct zebra_tc_filter *f1, *f2;
|
||||
|
||||
f1 = (const struct zebra_tc_filter *)arg1;
|
||||
f2 = (const struct zebra_tc_filter *)arg2;
|
||||
|
||||
if (f1->filter.ifindex != f2->filter.ifindex)
|
||||
return false;
|
||||
|
||||
if (f1->filter.handle != f2->filter.handle)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct zebra_tc_filter *tc_filter_free(struct zebra_tc_filter *hash_data,
|
||||
bool free_data)
|
||||
{
|
||||
hash_release(zrouter.filter_hash, hash_data);
|
||||
|
||||
if (free_data) {
|
||||
XFREE(MTYPE_TC_FILTER, hash_data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return hash_data;
|
||||
}
|
||||
|
||||
static struct zebra_tc_filter *tc_filter_release(struct zebra_tc_filter *filter,
|
||||
bool free_data)
|
||||
{
|
||||
struct zebra_tc_filter *lookup;
|
||||
|
||||
lookup = hash_lookup(zrouter.filter_hash, filter);
|
||||
|
||||
if (!lookup)
|
||||
return NULL;
|
||||
|
||||
return tc_filter_free(lookup, free_data);
|
||||
}
|
||||
|
||||
static void *tc_filter_alloc_intern(void *arg)
|
||||
{
|
||||
struct zebra_tc_filter *ztf;
|
||||
struct zebra_tc_filter *new;
|
||||
|
||||
ztf = (struct zebra_tc_filter *)arg;
|
||||
|
||||
new = XCALLOC(MTYPE_TC_FILTER, sizeof(*new));
|
||||
|
||||
memcpy(new, ztf, sizeof(*ztf));
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
void zebra_tc_filter_add(struct zebra_tc_filter *filter)
|
||||
{
|
||||
if (IS_ZEBRA_DEBUG_TC)
|
||||
zlog_debug(
|
||||
"%s: add tc filter ifindex %d priority %u handle %08x kind %s",
|
||||
__func__, filter->filter.ifindex,
|
||||
filter->filter.priority, filter->filter.handle,
|
||||
tc_filter_kind2str(filter->filter.kind));
|
||||
|
||||
struct zebra_tc_filter *found;
|
||||
struct zebra_tc_filter *new;
|
||||
|
||||
found = hash_lookup(zrouter.filter_hash, filter);
|
||||
new = hash_get(zrouter.filter_hash, filter, tc_filter_alloc_intern);
|
||||
|
||||
if (found)
|
||||
(void)dplane_tc_filter_update(new);
|
||||
else
|
||||
(void)dplane_tc_filter_add(new);
|
||||
}
|
||||
|
||||
void zebra_tc_filter_delete(struct zebra_tc_filter *filter)
|
||||
{
|
||||
if (IS_ZEBRA_DEBUG_PBR)
|
||||
zlog_debug(
|
||||
"%s: delete tc filter ifindex %d priority %u handle %08x kind %s",
|
||||
__func__, filter->filter.ifindex,
|
||||
filter->filter.priority, filter->filter.handle,
|
||||
tc_filter_kind2str(filter->filter.kind));
|
||||
|
||||
(void)dplane_tc_filter_delete(filter);
|
||||
|
||||
if (tc_filter_release(filter, true))
|
||||
zlog_debug("%s: tc filter being deleted we know nothing about",
|
||||
__func__);
|
||||
}
|
79
zebra/zebra_tc.h
Normal file
79
zebra/zebra_tc.h
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Zebra Traffic Control (TC) Data structures and definitions
|
||||
* These are public definitions referenced by multiple files.
|
||||
*
|
||||
* Copyright (C) 2022 Shichu Yang
|
||||
*
|
||||
* 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_TC_H
|
||||
#define _ZEBRA_TC_H
|
||||
|
||||
#include <zebra.h>
|
||||
#include "rt.h"
|
||||
#include "tc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct zebra_tc_qdisc {
|
||||
int sock;
|
||||
|
||||
struct tc_qdisc qdisc;
|
||||
};
|
||||
|
||||
struct zebra_tc_class {
|
||||
int sock;
|
||||
|
||||
struct tc_class class;
|
||||
};
|
||||
|
||||
struct zebra_tc_filter {
|
||||
int sock;
|
||||
|
||||
struct tc_filter filter;
|
||||
};
|
||||
|
||||
const char *tc_qdisc_kind2str(uint32_t type);
|
||||
enum tc_qdisc_kind tc_qdisc_str2kind(const char *type);
|
||||
|
||||
uint32_t zebra_tc_qdisc_hash_key(const void *arg);
|
||||
bool zebra_tc_qdisc_hash_equal(const void *arg1, const void *arg2);
|
||||
void zebra_tc_qdisc_install(struct zebra_tc_qdisc *qdisc);
|
||||
void zebra_tc_qdisc_uninstall(struct zebra_tc_qdisc *qdisc);
|
||||
|
||||
uint32_t zebra_tc_class_hash_key(const void *arg);
|
||||
bool zebra_tc_class_hash_equal(const void *arg1, const void *arg2);
|
||||
void zebra_tc_class_add(struct zebra_tc_class *class);
|
||||
void zebra_tc_class_delete(struct zebra_tc_class *class);
|
||||
|
||||
const char *tc_filter_kind2str(uint32_t type);
|
||||
enum tc_qdisc_kind tc_filter_str2kind(const char *type);
|
||||
void zebra_tc_filter_add(struct zebra_tc_filter *filter);
|
||||
void zebra_tc_filter_delete(struct zebra_tc_filter *filter);
|
||||
|
||||
void zebra_tc_filters_free(void *arg);
|
||||
uint32_t zebra_tc_filter_hash_key(const void *arg);
|
||||
bool zebra_tc_filter_hash_equal(const void *arg1, const void *arg2);
|
||||
|
||||
void kernel_read_tc_qdisc(struct zebra_ns *zns);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _ZEBRA_TC_H */
|
Loading…
Reference in New Issue
Block a user