summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--zebra/if_netlink.c232
-rw-r--r--zebra/if_netlink.h3
-rw-r--r--zebra/kernel_netlink.c7
-rw-r--r--zebra/rt.h1
-rw-r--r--zebra/rtread_netlink.c6
-rw-r--r--zebra/rtread_sysctl.c4
-rw-r--r--zebra/zebra_ns.c2
-rw-r--r--zebra/zebra_vxlan_if.c30
-rw-r--r--zebra/zebra_vxlan_if.h2
9 files changed, 287 insertions, 0 deletions
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index 02b9ab9d7f..22dd2b956d 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -2522,4 +2522,236 @@ int netlink_tunneldump_read(struct zebra_ns *zns)
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 */
diff --git a/zebra/if_netlink.h b/zebra/if_netlink.h
index 21ae1713be..f215968657 100644
--- a/zebra/if_netlink.h
+++ b/zebra/if_netlink.h
@@ -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 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,
const struct zebra_dplane_ctx *ctx,
void *buf, size_t buflen);
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c
index 45fb24a210..2fd1543b31 100644
--- a/zebra/kernel_netlink.c
+++ b/zebra/kernel_netlink.c
@@ -124,6 +124,9 @@ static const struct message nlmsg_str[] = {{RTM_NEWROUTE, "RTM_NEWROUTE"},
{RTM_NEWTFILTER, "RTM_NEWTFILTER"},
{RTM_DELTFILTER, "RTM_DELTFILTER"},
{RTM_GETTFILTER, "RTM_GETTFILTER"},
+ {RTM_NEWVLAN, "RTM_NEWVLAN"},
+ {RTM_DELVLAN, "RTM_DELVLAN"},
+ {RTM_GETVLAN, "RTM_GETVLAN"},
{0}};
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_DELTFILTER:
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 */
case RTM_NEWADDR:
diff --git a/zebra/rt.h b/zebra/rt.h
index f17d11a5fb..4ebf479754 100644
--- a/zebra/rt.h
+++ b/zebra/rt.h
@@ -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.
*/
int kernel_dplane_read(struct zebra_dplane_info *info);
+extern void vlan_read(struct zebra_ns *zns);
#ifdef __cplusplus
}
diff --git a/zebra/rtread_netlink.c b/zebra/rtread_netlink.c
index a85d8a4894..f9d4605562 100644
--- a/zebra/rtread_netlink.c
+++ b/zebra/rtread_netlink.c
@@ -28,6 +28,7 @@
#include "zebra/zebra_pbr.h"
#include "zebra/zebra_tc.h"
#include "zebra/rt_netlink.h"
+#include "zebra/if_netlink.h"
#include "zebra/rule_netlink.h"
#include "zebra/tc_netlink.h"
@@ -84,4 +85,9 @@ void kernel_read_tc_qdisc(struct zebra_ns *zns)
netlink_qdisc_read(zns);
}
+void vlan_read(struct zebra_ns *zns)
+{
+ netlink_vlan_read(zns);
+}
+
#endif /* GNU_LINUX */
diff --git a/zebra/rtread_sysctl.c b/zebra/rtread_sysctl.c
index c8a89b3a55..f5b918c022 100644
--- a/zebra/rtread_sysctl.c
+++ b/zebra/rtread_sysctl.c
@@ -118,4 +118,8 @@ void kernel_read_tc_qdisc(struct zebra_ns *zns)
{
}
+void vlan_read(struct zebra_ns *zns)
+{
+}
+
#endif /* !defined(GNU_LINUX) */
diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c
index 7b076b8a4a..457a4955b4 100644
--- a/zebra/zebra_ns.c
+++ b/zebra/zebra_ns.c
@@ -127,6 +127,8 @@ int zebra_ns_enable(ns_id_t ns_id, void **info)
zebra_dplane_ns_enable(zns, true);
interface_list(zns);
route_read(zns);
+
+ vlan_read(zns);
kernel_read_pbr_rules(zns);
kernel_read_tc_qdisc(zns);
diff --git a/zebra/zebra_vxlan_if.c b/zebra/zebra_vxlan_if.c
index df9ad7795f..e01d06c71a 100644
--- a/zebra/zebra_vxlan_if.c
+++ b/zebra/zebra_vxlan_if.c
@@ -672,6 +672,36 @@ struct zebra_vxlan_vni *zebra_vxlan_if_vni_find(const struct zebra_if *zif,
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,
int (*func)(struct zebra_if *zif,
struct zebra_vxlan_vni *, void *),
diff --git a/zebra/zebra_vxlan_if.h b/zebra/zebra_vxlan_if.h
index a09e3dbe8c..e5ee6dc2d9 100644
--- a/zebra/zebra_vxlan_if.h
+++ b/zebra/zebra_vxlan_if.h
@@ -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 struct zebra_vxlan_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,
int (*func)(struct zebra_if *zif,
struct zebra_vxlan_vni *,