zebra: triggers for maintaining a list of access vlans per-ES

The linux kernel sends the VLAN list per-access port as bitmap. This
needs to be translated into a per-ES VNI list for generation of
EAD-EVI routes.

Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
This commit is contained in:
Anuradha Karuppiah 2020-03-27 17:32:46 -07:00
parent ce5160c081
commit 42b5663925

View File

@ -70,6 +70,7 @@
#include "zebra/if_netlink.h"
#include "zebra/zebra_errors.h"
#include "zebra/zebra_vxlan.h"
#include "zebra/zebra_evpn_mh.h"
extern struct zebra_privs_t zserv_privs;
@ -245,6 +246,26 @@ static enum zebra_link_type netlink_to_zebra_link_type(unsigned int hwt)
}
}
static inline void zebra_if_set_ziftype(struct interface *ifp,
zebra_iftype_t zif_type,
zebra_slave_iftype_t zif_slave_type)
{
struct zebra_if *zif;
zif = (struct zebra_if *)ifp->info;
zif->zif_slave_type = zif_slave_type;
if (zif->zif_type != zif_type) {
zif->zif_type = zif_type;
/* If the if_type has been set to bond initialize ES info
* against it. XXX - note that we don't handle the case where
* a zif changes from bond to non-bond; it is really
* an unexpected/error condition.
*/
zebra_evpn_if_init(zif);
}
}
static void netlink_determine_zebra_iftype(const char *kind,
zebra_iftype_t *zif_type)
{
@ -557,6 +578,74 @@ static void netlink_interface_update_l2info(struct interface *ifp,
}
}
static int netlink_bridge_vxlan_update(struct interface *ifp,
struct rtattr *af_spec)
{
struct rtattr *aftb[IFLA_BRIDGE_MAX + 1];
struct bridge_vlan_info *vinfo;
vlanid_t access_vlan;
/* There is a 1-to-1 mapping of VLAN to VxLAN - hence
* only 1 access VLAN is accepted.
*/
memset(aftb, 0, sizeof(aftb));
parse_rtattr_nested(aftb, IFLA_BRIDGE_MAX, af_spec);
if (!aftb[IFLA_BRIDGE_VLAN_INFO])
return 0;
vinfo = RTA_DATA(aftb[IFLA_BRIDGE_VLAN_INFO]);
if (!(vinfo->flags & BRIDGE_VLAN_INFO_PVID))
return 0;
access_vlan = (vlanid_t)vinfo->vid;
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("Access VLAN %u for VxLAN IF %s(%u)", access_vlan,
ifp->name, ifp->ifindex);
zebra_l2_vxlanif_update_access_vlan(ifp, access_vlan);
return 0;
}
static void netlink_bridge_vlan_update(struct interface *ifp,
struct rtattr *af_spec)
{
struct rtattr *i;
int rem;
uint16_t vid_range_start = 0;
struct zebra_if *zif;
bitfield_t old_vlan_bitmap;
struct bridge_vlan_info *vinfo;
zif = (struct zebra_if *)ifp->info;
/* cache the old bitmap addrs */
old_vlan_bitmap = zif->vlan_bitmap;
/* create a new bitmap space for re-eval */
bf_init(zif->vlan_bitmap, IF_VLAN_BITMAP_MAX);
for (i = RTA_DATA(af_spec), rem = RTA_PAYLOAD(af_spec);
RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
if (i->rta_type != IFLA_BRIDGE_VLAN_INFO)
continue;
vinfo = RTA_DATA(i);
if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
vid_range_start = vinfo->vid;
continue;
}
if (!(vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END))
vid_range_start = vinfo->vid;
zebra_vlan_bitmap_compute(ifp, vid_range_start, vinfo->vid);
}
zebra_vlan_mbr_re_eval(ifp, old_vlan_bitmap);
bf_free(old_vlan_bitmap);
}
static int netlink_bridge_interface(struct nlmsghdr *h, int len, ns_id_t ns_id,
int startup)
{
@ -564,12 +653,8 @@ static int netlink_bridge_interface(struct nlmsghdr *h, int len, ns_id_t ns_id,
struct ifinfomsg *ifi;
struct rtattr *tb[IFLA_MAX + 1];
struct interface *ifp;
struct rtattr *aftb[IFLA_BRIDGE_MAX + 1];
struct {
uint16_t flags;
uint16_t vid;
} * vinfo;
vlanid_t access_vlan;
struct zebra_if *zif;
struct rtattr *af_spec;
/* Fetch name and ifindex */
ifi = NLMSG_DATA(h);
@ -587,30 +672,22 @@ static int netlink_bridge_interface(struct nlmsghdr *h, int len, ns_id_t ns_id,
ifi->ifi_index);
return 0;
}
if (!IS_ZEBRA_IF_VXLAN(ifp))
return 0;
/* We are only interested in the access VLAN i.e., AF_SPEC */
if (!tb[IFLA_AF_SPEC])
return 0;
af_spec = tb[IFLA_AF_SPEC];
if (!af_spec)
return 0;
/* There is a 1-to-1 mapping of VLAN to VxLAN - hence
* only 1 access VLAN is accepted.
if (IS_ZEBRA_IF_VXLAN(ifp))
return netlink_bridge_vxlan_update(ifp, af_spec);
/* build vlan bitmap associated with this interface if that
* device type is interested in the vlans
*/
memset(aftb, 0, sizeof(aftb));
parse_rtattr_nested(aftb, IFLA_BRIDGE_MAX, tb[IFLA_AF_SPEC]);
if (!aftb[IFLA_BRIDGE_VLAN_INFO])
return 0;
zif = (struct zebra_if *)ifp->info;
if (bf_is_inited(zif->vlan_bitmap))
netlink_bridge_vlan_update(ifp, af_spec);
vinfo = RTA_DATA(aftb[IFLA_BRIDGE_VLAN_INFO]);
if (!(vinfo->flags & BRIDGE_VLAN_INFO_PVID))
return 0;
access_vlan = (vlanid_t)vinfo->vid;
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("Access VLAN %u for VxLAN IF %s(%u)", access_vlan,
name, ifi->ifi_index);
zebra_l2_vxlanif_update_access_vlan(ifp, access_vlan);
return 0;
}