mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-07 09:22:03 +00:00
zebra: handle STP state change for SVD per vlan ID
Read in STP state changes for a Single Vxlan Device via bridge vlan netlink messages. Map the vlanid to a VNI in the SVD table and treat it similar to how we handle proto down of the Vxlan device traditionally in a non-SVD device scenario. Forwarding == Interface UP Blocking == Interface DOWN Signed-off-by: Stephen Worley <sworley@nvidia.com>
This commit is contained in:
parent
313c1c8e95
commit
a26daa77cc
@ -2522,4 +2522,236 @@ int netlink_tunneldump_read(struct zebra_ns *zns)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *port_state2str(uint8_t state)
|
||||||
|
{
|
||||||
|
switch (state) {
|
||||||
|
case BR_STATE_DISABLED:
|
||||||
|
return "DISABLED";
|
||||||
|
case BR_STATE_LISTENING:
|
||||||
|
return "LISTENING";
|
||||||
|
case BR_STATE_LEARNING:
|
||||||
|
return "LEARNING";
|
||||||
|
case BR_STATE_FORWARDING:
|
||||||
|
return "FORWARDING";
|
||||||
|
case BR_STATE_BLOCKING:
|
||||||
|
return "BLOCKING";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "UNKNOWN";
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vxlan_vni_state_change(struct zebra_if *zif, uint16_t id,
|
||||||
|
uint8_t state)
|
||||||
|
{
|
||||||
|
struct zebra_vxlan_vni *vnip;
|
||||||
|
|
||||||
|
vnip = zebra_vxlan_if_vlanid_vni_find(zif, id);
|
||||||
|
|
||||||
|
if (!vnip) {
|
||||||
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
||||||
|
zlog_debug(
|
||||||
|
"Cannot find VNI for VID (%u) IF %s for vlan state update",
|
||||||
|
id, zif->ifp->name);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case BR_STATE_FORWARDING:
|
||||||
|
zebra_vxlan_if_vni_up(zif->ifp, vnip);
|
||||||
|
break;
|
||||||
|
case BR_STATE_BLOCKING:
|
||||||
|
zebra_vxlan_if_vni_down(zif->ifp, vnip);
|
||||||
|
break;
|
||||||
|
case BR_STATE_DISABLED:
|
||||||
|
case BR_STATE_LISTENING:
|
||||||
|
case BR_STATE_LEARNING:
|
||||||
|
default:
|
||||||
|
/* Not used for anything at the moment */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vlan_id_range_state_change(struct interface *ifp, uint16_t id_start,
|
||||||
|
uint16_t id_end, uint8_t state)
|
||||||
|
{
|
||||||
|
struct zebra_if *zif;
|
||||||
|
|
||||||
|
zif = (struct zebra_if *)ifp->info;
|
||||||
|
|
||||||
|
if (!zif)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (uint16_t i = id_start; i <= id_end; i++)
|
||||||
|
vxlan_vni_state_change(zif, i, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* netlink_vlan_change() - Read in change about vlans from the kernel
|
||||||
|
*
|
||||||
|
* @h: Netlink message header
|
||||||
|
* @ns_id: Namspace id
|
||||||
|
* @startup: Are we reading under startup conditions?
|
||||||
|
*
|
||||||
|
* Return: Result status
|
||||||
|
*/
|
||||||
|
int netlink_vlan_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
|
||||||
|
{
|
||||||
|
int len, rem;
|
||||||
|
struct interface *ifp;
|
||||||
|
struct br_vlan_msg *bvm;
|
||||||
|
struct bridge_vlan_info *vinfo;
|
||||||
|
struct rtattr *vtb[BRIDGE_VLANDB_ENTRY_MAX + 1] = {};
|
||||||
|
struct rtattr *attr;
|
||||||
|
uint8_t state;
|
||||||
|
uint32_t vrange;
|
||||||
|
int type;
|
||||||
|
|
||||||
|
/* We only care about state changes for now */
|
||||||
|
if (!(h->nlmsg_type == RTM_NEWVLAN))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct br_vlan_msg));
|
||||||
|
if (len < 0) {
|
||||||
|
zlog_warn(
|
||||||
|
"%s: Message received from netlink is of a broken size %d %zu",
|
||||||
|
__func__, h->nlmsg_len,
|
||||||
|
(size_t)NLMSG_LENGTH(sizeof(struct br_vlan_msg)));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bvm = NLMSG_DATA(h);
|
||||||
|
|
||||||
|
if (bvm->family != AF_BRIDGE)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), bvm->ifindex);
|
||||||
|
if (!ifp) {
|
||||||
|
zlog_debug("Cannot find bridge-vlan IF (%u) for vlan update",
|
||||||
|
bvm->ifindex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IS_ZEBRA_IF_VXLAN(ifp)) {
|
||||||
|
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||||
|
zlog_debug("Ignoring non-vxlan IF (%s) for vlan update",
|
||||||
|
ifp->name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_VXLAN)
|
||||||
|
zlog_debug("%s %s IF %s NS %u",
|
||||||
|
nl_msg_type_to_str(h->nlmsg_type),
|
||||||
|
nl_family_to_str(bvm->family), ifp->name, ns_id);
|
||||||
|
|
||||||
|
/* Loop over "ALL" BRIDGE_VLANDB_ENTRY */
|
||||||
|
rem = len;
|
||||||
|
for (attr = BRVLAN_RTA(bvm); RTA_OK(attr, rem);
|
||||||
|
attr = RTA_NEXT(attr, rem)) {
|
||||||
|
vinfo = NULL;
|
||||||
|
state = 0;
|
||||||
|
vrange = 0;
|
||||||
|
|
||||||
|
type = attr->rta_type & NLA_TYPE_MASK;
|
||||||
|
|
||||||
|
if (type != BRIDGE_VLANDB_ENTRY)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Parse nested entry data */
|
||||||
|
netlink_parse_rtattr_nested(vtb, BRIDGE_VLANDB_ENTRY_MAX, attr);
|
||||||
|
|
||||||
|
/* It must have info for the ID */
|
||||||
|
if (!vtb[BRIDGE_VLANDB_ENTRY_INFO])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
vinfo = (struct bridge_vlan_info *)RTA_DATA(
|
||||||
|
vtb[BRIDGE_VLANDB_ENTRY_INFO]);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We only care about state info, if there is none, just ignore
|
||||||
|
* it.
|
||||||
|
*/
|
||||||
|
if (!vtb[BRIDGE_VLANDB_ENTRY_STATE])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
state = *(uint8_t *)RTA_DATA(vtb[BRIDGE_VLANDB_ENTRY_STATE]);
|
||||||
|
|
||||||
|
if (vtb[BRIDGE_VLANDB_ENTRY_RANGE])
|
||||||
|
vrange = *(uint32_t *)RTA_DATA(
|
||||||
|
vtb[BRIDGE_VLANDB_ENTRY_RANGE]);
|
||||||
|
|
||||||
|
if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_VXLAN) {
|
||||||
|
if (vrange)
|
||||||
|
zlog_debug("VLANDB_ENTRY: VID (%u-%u) state=%s",
|
||||||
|
vinfo->vid, vrange,
|
||||||
|
port_state2str(state));
|
||||||
|
else
|
||||||
|
zlog_debug("VLANDB_ENTRY: VID (%u) state=%s",
|
||||||
|
vinfo->vid, port_state2str(state));
|
||||||
|
}
|
||||||
|
|
||||||
|
vlan_id_range_state_change(
|
||||||
|
ifp, vinfo->vid, (vrange ? vrange : vinfo->vid), state);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* netlink_request_vlan() - Request vlan information from the kernel
|
||||||
|
* @zns: Zebra namespace
|
||||||
|
* @family: AF_* netlink family
|
||||||
|
* @type: RTM_* type
|
||||||
|
*
|
||||||
|
* Return: Result status
|
||||||
|
*/
|
||||||
|
static int netlink_request_vlan(struct zebra_ns *zns, int family, int type)
|
||||||
|
{
|
||||||
|
struct {
|
||||||
|
struct nlmsghdr n;
|
||||||
|
struct br_vlan_msg bvm;
|
||||||
|
char buf[256];
|
||||||
|
} req;
|
||||||
|
|
||||||
|
/* Form the request, specifying filter (rtattr) if needed. */
|
||||||
|
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 br_vlan_msg));
|
||||||
|
req.bvm.family = family;
|
||||||
|
|
||||||
|
nl_attr_put32(&req.n, sizeof(req), BRIDGE_VLANDB_DUMP_FLAGS,
|
||||||
|
BRIDGE_VLANDB_DUMPF_STATS);
|
||||||
|
|
||||||
|
return netlink_request(&zns->netlink_cmd, &req);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* netlink_vlan_read() - Vlan read function using netlink interface
|
||||||
|
*
|
||||||
|
* @zns: Zebra name space
|
||||||
|
*
|
||||||
|
* Return: Result status
|
||||||
|
* Only called at bootstrap time.
|
||||||
|
*/
|
||||||
|
int netlink_vlan_read(struct zebra_ns *zns)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct zebra_dplane_info dp_info;
|
||||||
|
|
||||||
|
zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/);
|
||||||
|
|
||||||
|
/* Get bridg vlan info */
|
||||||
|
ret = netlink_request_vlan(zns, PF_BRIDGE, RTM_GETVLAN);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = netlink_parse_info(netlink_vlan_change, &zns->netlink_cmd,
|
||||||
|
&dp_info, 0, 1);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* GNU_LINUX */
|
#endif /* GNU_LINUX */
|
||||||
|
@ -40,6 +40,9 @@ int netlink_interface_addr_dplane(struct nlmsghdr *h, ns_id_t ns_id,
|
|||||||
extern int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup);
|
extern int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup);
|
||||||
extern int interface_lookup_netlink(struct zebra_ns *zns);
|
extern int interface_lookup_netlink(struct zebra_ns *zns);
|
||||||
|
|
||||||
|
extern int netlink_vlan_change(struct nlmsghdr *h, ns_id_t ns_id, int startup);
|
||||||
|
extern int netlink_vlan_read(struct zebra_ns *zns);
|
||||||
|
|
||||||
extern ssize_t netlink_intf_msg_encode(uint16_t cmd,
|
extern ssize_t netlink_intf_msg_encode(uint16_t cmd,
|
||||||
const struct zebra_dplane_ctx *ctx,
|
const struct zebra_dplane_ctx *ctx,
|
||||||
void *buf, size_t buflen);
|
void *buf, size_t buflen);
|
||||||
|
@ -124,6 +124,9 @@ static const struct message nlmsg_str[] = {{RTM_NEWROUTE, "RTM_NEWROUTE"},
|
|||||||
{RTM_NEWTFILTER, "RTM_NEWTFILTER"},
|
{RTM_NEWTFILTER, "RTM_NEWTFILTER"},
|
||||||
{RTM_DELTFILTER, "RTM_DELTFILTER"},
|
{RTM_DELTFILTER, "RTM_DELTFILTER"},
|
||||||
{RTM_GETTFILTER, "RTM_GETTFILTER"},
|
{RTM_GETTFILTER, "RTM_GETTFILTER"},
|
||||||
|
{RTM_NEWVLAN, "RTM_NEWVLAN"},
|
||||||
|
{RTM_DELVLAN, "RTM_DELVLAN"},
|
||||||
|
{RTM_GETVLAN, "RTM_GETVLAN"},
|
||||||
{0}};
|
{0}};
|
||||||
|
|
||||||
static const struct message rtproto_str[] = {
|
static const struct message rtproto_str[] = {
|
||||||
@ -432,6 +435,10 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id,
|
|||||||
case RTM_NEWTFILTER:
|
case RTM_NEWTFILTER:
|
||||||
case RTM_DELTFILTER:
|
case RTM_DELTFILTER:
|
||||||
return netlink_tfilter_change(h, ns_id, startup);
|
return netlink_tfilter_change(h, ns_id, startup);
|
||||||
|
case RTM_NEWVLAN:
|
||||||
|
return netlink_vlan_change(h, ns_id, startup);
|
||||||
|
case RTM_DELVLAN:
|
||||||
|
return netlink_vlan_change(h, ns_id, startup);
|
||||||
|
|
||||||
/* Messages handled in the dplane thread */
|
/* Messages handled in the dplane thread */
|
||||||
case RTM_NEWADDR:
|
case RTM_NEWADDR:
|
||||||
|
@ -129,6 +129,7 @@ extern void kernel_update_multi(struct dplane_ctx_list_head *ctx_list);
|
|||||||
* Called by the dplane pthread to read incoming OS messages and dispatch them.
|
* Called by the dplane pthread to read incoming OS messages and dispatch them.
|
||||||
*/
|
*/
|
||||||
int kernel_dplane_read(struct zebra_dplane_info *info);
|
int kernel_dplane_read(struct zebra_dplane_info *info);
|
||||||
|
extern void vlan_read(struct zebra_ns *zns);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "zebra/zebra_pbr.h"
|
#include "zebra/zebra_pbr.h"
|
||||||
#include "zebra/zebra_tc.h"
|
#include "zebra/zebra_tc.h"
|
||||||
#include "zebra/rt_netlink.h"
|
#include "zebra/rt_netlink.h"
|
||||||
|
#include "zebra/if_netlink.h"
|
||||||
#include "zebra/rule_netlink.h"
|
#include "zebra/rule_netlink.h"
|
||||||
#include "zebra/tc_netlink.h"
|
#include "zebra/tc_netlink.h"
|
||||||
|
|
||||||
@ -84,4 +85,9 @@ void kernel_read_tc_qdisc(struct zebra_ns *zns)
|
|||||||
netlink_qdisc_read(zns);
|
netlink_qdisc_read(zns);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void vlan_read(struct zebra_ns *zns)
|
||||||
|
{
|
||||||
|
netlink_vlan_read(zns);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* GNU_LINUX */
|
#endif /* GNU_LINUX */
|
||||||
|
@ -118,4 +118,8 @@ void kernel_read_tc_qdisc(struct zebra_ns *zns)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void vlan_read(struct zebra_ns *zns)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* !defined(GNU_LINUX) */
|
#endif /* !defined(GNU_LINUX) */
|
||||||
|
@ -127,6 +127,8 @@ int zebra_ns_enable(ns_id_t ns_id, void **info)
|
|||||||
zebra_dplane_ns_enable(zns, true);
|
zebra_dplane_ns_enable(zns, true);
|
||||||
interface_list(zns);
|
interface_list(zns);
|
||||||
route_read(zns);
|
route_read(zns);
|
||||||
|
|
||||||
|
vlan_read(zns);
|
||||||
kernel_read_pbr_rules(zns);
|
kernel_read_pbr_rules(zns);
|
||||||
kernel_read_tc_qdisc(zns);
|
kernel_read_tc_qdisc(zns);
|
||||||
|
|
||||||
|
@ -672,6 +672,36 @@ struct zebra_vxlan_vni *zebra_vxlan_if_vni_find(const struct zebra_if *zif,
|
|||||||
return vnip;
|
return vnip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int zif_vlanid_vni_walker(struct zebra_if *zif,
|
||||||
|
struct zebra_vxlan_vni *vnip, void *arg)
|
||||||
|
{
|
||||||
|
struct zebra_vxlan_if_vlan_ctx *ctx;
|
||||||
|
|
||||||
|
ctx = (struct zebra_vxlan_if_vlan_ctx *)arg;
|
||||||
|
|
||||||
|
if (vnip->access_vlan == ctx->vid) {
|
||||||
|
ctx->vni = vnip;
|
||||||
|
return HASHWALK_ABORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return HASHWALK_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct zebra_vxlan_vni *zebra_vxlan_if_vlanid_vni_find(struct zebra_if *zif,
|
||||||
|
vlanid_t vid)
|
||||||
|
{
|
||||||
|
struct zebra_vxlan_if_vlan_ctx ctx = {};
|
||||||
|
|
||||||
|
if (!IS_ZEBRA_VXLAN_IF_SVD(zif))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ctx.vid = vid;
|
||||||
|
|
||||||
|
zebra_vxlan_if_vni_walk(zif, zif_vlanid_vni_walker, &ctx);
|
||||||
|
|
||||||
|
return ctx.vni;
|
||||||
|
}
|
||||||
|
|
||||||
void zebra_vxlan_if_vni_iterate(struct zebra_if *zif,
|
void zebra_vxlan_if_vni_iterate(struct zebra_if *zif,
|
||||||
int (*func)(struct zebra_if *zif,
|
int (*func)(struct zebra_if *zif,
|
||||||
struct zebra_vxlan_vni *, void *),
|
struct zebra_vxlan_vni *, void *),
|
||||||
|
@ -50,6 +50,8 @@ extern int zebra_vxlan_if_vni_table_create(struct zebra_if *zif);
|
|||||||
extern int zebra_vxlan_if_vni_table_destroy(struct zebra_if *zif);
|
extern int zebra_vxlan_if_vni_table_destroy(struct zebra_if *zif);
|
||||||
extern struct zebra_vxlan_vni *
|
extern struct zebra_vxlan_vni *
|
||||||
zebra_vxlan_if_vni_find(const struct zebra_if *zif, vni_t vni);
|
zebra_vxlan_if_vni_find(const struct zebra_if *zif, vni_t vni);
|
||||||
|
extern struct zebra_vxlan_vni *
|
||||||
|
zebra_vxlan_if_vlanid_vni_find(struct zebra_if *zif, vlanid_t vni);
|
||||||
extern void zebra_vxlan_if_vni_iterate(struct zebra_if *zif,
|
extern void zebra_vxlan_if_vni_iterate(struct zebra_if *zif,
|
||||||
int (*func)(struct zebra_if *zif,
|
int (*func)(struct zebra_if *zif,
|
||||||
struct zebra_vxlan_vni *,
|
struct zebra_vxlan_vni *,
|
||||||
|
Loading…
Reference in New Issue
Block a user