zebra_ns.c zebra_vrf.c zebra_static.c zebra_mpls.c zebra_mpls_vty.c \
zebra_mroute.c \
label_manager.c \
+ zebra_l2.c \
# end
noinst_HEADERS = \
rt_netlink.h zebra_fpm_private.h zebra_rnh.h \
zebra_ptm_redistribute.h zebra_ptm.h zebra_routemap.h \
zebra_ns.h zebra_vrf.h ioctl_solaris.h zebra_static.h zebra_mpls.h \
- kernel_netlink.h if_netlink.h zebra_mroute.h label_manager.h
+ kernel_netlink.h if_netlink.h zebra_mroute.h label_manager.h \
+ zebra_l2.h
zebra_LDADD = $(otherobj) ../lib/libfrr.la $(LIBCAP)
*/
#include <zebra.h>
+
+/* The following definition is to workaround an issue in the Linux kernel
+ * header files with redefinition of 'struct in6_addr' in both
+ * netinet/in.h and linux/in6.h.
+ * Reference - https://sourceware.org/ml/libc-alpha/2013-01/msg00599.html
+ */
+#define _LINUX_IN6_H
+
+#include <linux/if_bridge.h>
#include <net/if_arp.h>
#include <linux/sockios.h>
#include <linux/ethtool.h>
}
}
+static void
+netlink_determine_zebra_iftype (char *kind, zebra_iftype_t *zif_type)
+{
+ *zif_type = ZEBRA_IF_OTHER;
+
+ if (!kind)
+ return;
+
+ if (strcmp(kind, "vrf") == 0)
+ *zif_type = ZEBRA_IF_VRF;
+ else if (strcmp(kind, "bridge") == 0)
+ *zif_type = ZEBRA_IF_BRIDGE;
+ else if (strcmp(kind, "vlan") == 0)
+ *zif_type = ZEBRA_IF_VLAN;
+ else if (strcmp(kind, "vxlan") == 0)
+ *zif_type = ZEBRA_IF_VXLAN;
+}
//Temporary Assignments to compile on older platforms.
#ifndef IFLA_BR_MAX
return (ecmd.speed_hi << 16 ) | ecmd.speed;
}
+static int
+netlink_extract_bridge_info (struct rtattr *link_data,
+ struct zebra_l2info_bridge *bridge_info)
+{
+ struct rtattr *attr[IFLA_BR_MAX+1];
+
+ memset (bridge_info, 0, sizeof (*bridge_info));
+ memset (attr, 0, sizeof attr);
+ parse_rtattr_nested(attr, IFLA_BR_MAX, link_data);
+ if (attr[IFLA_BR_VLAN_FILTERING])
+ bridge_info->vlan_aware = *(u_char *)RTA_DATA(attr[IFLA_BR_VLAN_FILTERING]);
+ return 0;
+}
+
+static int
+netlink_extract_vlan_info (struct rtattr *link_data,
+ struct zebra_l2info_vlan *vlan_info)
+{
+ struct rtattr *attr[IFLA_VLAN_MAX+1];
+ vlanid_t vid_in_msg;
+
+ memset (vlan_info, 0, sizeof (*vlan_info));
+ memset (attr, 0, sizeof attr);
+ parse_rtattr_nested(attr, IFLA_VLAN_MAX, link_data);
+ if (!attr[IFLA_VLAN_ID])
+ {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug ("IFLA_VLAN_ID missing from VLAN IF message");
+ return -1;
+ }
+
+ vid_in_msg = *(vlanid_t *)RTA_DATA(attr[IFLA_VLAN_ID]);
+ vlan_info->vid = vid_in_msg;
+ return 0;
+}
+
+static int
+netlink_extract_vxlan_info (struct rtattr *link_data,
+ struct zebra_l2info_vxlan *vxl_info)
+{
+ struct rtattr *attr[IFLA_VXLAN_MAX+1];
+ vni_t vni_in_msg;
+ struct in_addr vtep_ip_in_msg;
+
+ memset (vxl_info, 0, sizeof (*vxl_info));
+ memset (attr, 0, sizeof attr);
+ parse_rtattr_nested(attr, IFLA_VXLAN_MAX, link_data);
+ if (!attr[IFLA_VXLAN_ID])
+ {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug ("IFLA_VXLAN_ID missing from VXLAN IF message");
+ return -1;
+ }
+
+ vni_in_msg = *(vni_t *)RTA_DATA(attr[IFLA_VXLAN_ID]);
+ vxl_info->vni = vni_in_msg;
+ if (!attr[IFLA_VXLAN_LOCAL])
+ {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug ("IFLA_VXLAN_LOCAL missing from VXLAN IF message");
+ }
+ else
+ {
+ vtep_ip_in_msg = *(struct in_addr *)RTA_DATA(attr[IFLA_VXLAN_LOCAL]);
+ vxl_info->vtep_ip = vtep_ip_in_msg;
+ }
+
+ return 0;
+}
+
+/*
+ * Extract and save L2 params (of interest) for an interface. When a
+ * bridge interface is added or updated, take further actions to map
+ * its members. Likewise, for VxLAN interface.
+ */
+static void
+netlink_interface_update_l2info (struct interface *ifp,
+ struct rtattr *link_data,
+ int add)
+{
+ if (!link_data)
+ return;
+
+ if (IS_ZEBRA_IF_BRIDGE(ifp))
+ {
+ struct zebra_l2info_bridge bridge_info;
+
+ netlink_extract_bridge_info (link_data, &bridge_info);
+ zebra_l2_bridge_add_update (ifp, &bridge_info, add);
+ }
+ else if (IS_ZEBRA_IF_VLAN(ifp))
+ {
+ struct zebra_l2info_vlan vlan_info;
+
+ netlink_extract_vlan_info (link_data, &vlan_info);
+ zebra_l2_vlanif_update (ifp, &vlan_info);
+ }
+ else if (IS_ZEBRA_IF_VXLAN(ifp))
+ {
+ struct zebra_l2info_vxlan vxlan_info;
+
+ netlink_extract_vxlan_info (link_data, &vxlan_info);
+ zebra_l2_vxlanif_add_update (ifp, &vxlan_info, add);
+ }
+}
+
+static int
+netlink_bridge_interface (struct nlmsghdr *h, int len,
+ ns_id_t ns_id, int startup)
+{
+ char *name = NULL;
+ struct ifinfomsg *ifi;
+ struct rtattr *tb[IFLA_MAX + 1];
+ struct interface *ifp;
+ struct rtattr *aftb[IFLA_BRIDGE_MAX + 1];
+ struct
+ {
+ u_int16_t flags;
+ u_int16_t vid;
+ } *vinfo;
+ vlanid_t access_vlan;
+
+ /* Fetch name and ifindex */
+ ifi = NLMSG_DATA (h);
+ memset (tb, 0, sizeof tb);
+ netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
+
+ if (tb[IFLA_IFNAME] == NULL)
+ return -1;
+ name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
+
+ /* The interface should already be known, if not discard. */
+ ifp = if_lookup_by_index_per_ns (zebra_ns_lookup (ns_id),
+ ifi->ifi_index);
+ if (!ifp)
+ {
+ zlog_warn ("Cannot find bridge IF %s(%u)",
+ name, 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;
+
+ /* 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, tb[IFLA_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, name, ifi->ifi_index);
+ zebra_l2_vxlanif_update_access_vlan (ifp, access_vlan);
+ return 0;
+}
+
/* Called from interface_lookup_netlink(). This function is only used
during bootstrap. */
static int
char *name = NULL;
char *kind = NULL;
char *slave_kind = NULL;
- int vrf_device = 0;
struct zebra_ns *zns;
vrf_id_t vrf_id = VRF_DEFAULT;
+ zebra_iftype_t zif_type = ZEBRA_IF_OTHER;
+ zebra_slave_iftype_t zif_slave_type = ZEBRA_IF_SLAVE_NONE;
+ ifindex_t bridge_ifindex = IFINDEX_INTERNAL;
+ ifindex_t link_ifindex = IFINDEX_INTERNAL;
zns = zebra_ns_lookup (ns_id);
ifi = NLMSG_DATA (h);
if (len < 0)
return -1;
+ /* We are interested in some AF_BRIDGE notifications. */
if (ifi->ifi_family == AF_BRIDGE)
- return 0;
+ return netlink_bridge_interface (h, len, ns_id, startup);
/* Looking up interface name. */
memset (tb, 0, sizeof tb);
+ memset (linkinfo, 0, sizeof linkinfo);
netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
#ifdef IFLA_WIRELESS
if (tb[IFLA_LINKINFO])
{
- memset (linkinfo, 0, sizeof linkinfo);
parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
if (linkinfo[IFLA_INFO_KIND])
slave_kind = RTA_DATA(linkinfo[IFLA_INFO_SLAVE_KIND]);
#endif
- if (kind && strcmp(kind, "vrf") == 0)
- {
- vrf_device = 1;
- netlink_vrf_change(h, tb[IFLA_LINKINFO], name);
- vrf_id = (vrf_id_t)ifi->ifi_index;
- }
+ netlink_determine_zebra_iftype (kind, &zif_type);
+ }
+
+ /* If VRF, create the VRF structure itself. */
+ if (zif_type == ZEBRA_IF_VRF)
+ {
+ netlink_vrf_change(h, tb[IFLA_LINKINFO], name);
+ vrf_id = (vrf_id_t)ifi->ifi_index;
}
if (tb[IFLA_MASTER])
{
if (slave_kind && (strcmp(slave_kind, "vrf") == 0))
- vrf_id = *(u_int32_t *)RTA_DATA(tb[IFLA_MASTER]);
+ {
+ zif_slave_type = ZEBRA_IF_SLAVE_VRF;
+ vrf_id = *(u_int32_t *)RTA_DATA(tb[IFLA_MASTER]);
+ }
+ else if (slave_kind && (strcmp(slave_kind, "bridge") == 0))
+ {
+ zif_slave_type = ZEBRA_IF_SLAVE_BRIDGE;
+ bridge_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_MASTER]);
+ }
+ else
+ zif_slave_type = ZEBRA_IF_SLAVE_OTHER;
}
+ /* If linking to another interface, note it. */
+ if (tb[IFLA_LINK])
+ link_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_LINK]);
+
/* Add interface. */
ifp = if_get_by_name (name, vrf_id);
set_ifindex(ifp, ifi->ifi_index, zns);
ifp->flags = ifi->ifi_flags & 0x0000fffff;
- if (vrf_device)
+ if (IS_ZEBRA_IF_VRF(ifp))
SET_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK);
ifp->mtu6 = ifp->mtu = *(uint32_t *) RTA_DATA (tb[IFLA_MTU]);
ifp->metric = 0;
ifp->speed = get_iflink_speed (name);
ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN;
+ /* Set zebra interface type */
+ zebra_if_set_ziftype (ifp, zif_type, zif_slave_type);
+
+ /* Update link. */
+ zebra_if_update_link (ifp, link_ifindex);
+
/* Hardware type and address. */
ifp->ll_type = netlink_to_zebra_link_type (ifi->ifi_type);
netlink_interface_update_hw_addr (tb, ifp);
if_add_update (ifp);
+ /* Extract and save L2 interface information, take additional actions. */
+ netlink_interface_update_l2info (ifp, linkinfo[IFLA_INFO_DATA], 1);
+ if (IS_ZEBRA_IF_BRIDGE_SLAVE (ifp))
+ zebra_l2if_update_bridge_slave (ifp, bridge_ifindex);
+
return 0;
}
if (ret < 0)
return ret;
+ /* Get interface information - for bridge interfaces. */
+ ret = netlink_request_intf_addr (zns, AF_BRIDGE, RTM_GETLINK,
+ RTEXT_FILTER_BRVLAN);
+ if (ret < 0)
+ return ret;
+ ret = netlink_parse_info (netlink_interface, &zns->netlink_cmd, zns, 0, 0);
+ if (ret < 0)
+ return ret;
+
/* Get IPv4 address of the interfaces. */
ret = netlink_request_intf_addr (zns, AF_INET, RTM_GETADDR, 0);
if (ret < 0)
char *name = NULL;
char *kind = NULL;
char *slave_kind = NULL;
- int vrf_device = 0;
struct zebra_ns *zns;
vrf_id_t vrf_id = VRF_DEFAULT;
+ zebra_iftype_t zif_type = ZEBRA_IF_OTHER;
+ zebra_slave_iftype_t zif_slave_type = ZEBRA_IF_SLAVE_NONE;
+ ifindex_t bridge_ifindex = IFINDEX_INTERNAL;
+ ifindex_t link_ifindex = IFINDEX_INTERNAL;
+
zns = zebra_ns_lookup (ns_id);
ifi = NLMSG_DATA (h);
if (len < 0)
return -1;
+ /* We are interested in some AF_BRIDGE notifications. */
if (ifi->ifi_family == AF_BRIDGE)
- return 0;
+ return netlink_bridge_interface (h, len, ns_id, startup);
/* Looking up interface name. */
memset (tb, 0, sizeof tb);
+ memset (linkinfo, 0, sizeof linkinfo);
netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
#ifdef IFLA_WIRELESS
if (tb[IFLA_LINKINFO])
{
- memset (linkinfo, 0, sizeof linkinfo);
parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
if (linkinfo[IFLA_INFO_KIND])
slave_kind = RTA_DATA(linkinfo[IFLA_INFO_SLAVE_KIND]);
#endif
- if (kind && strcmp(kind, "vrf") == 0)
- {
- vrf_device = 1;
- netlink_vrf_change(h, tb[IFLA_LINKINFO], name);
- vrf_id = (vrf_id_t)ifi->ifi_index;
- }
+ netlink_determine_zebra_iftype (kind, &zif_type);
+ }
+
+ /* If linking to another interface, note it. */
+ if (tb[IFLA_LINK])
+ link_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_LINK]);
+
+ /* If VRF, create or update the VRF structure itself. */
+ if (zif_type == ZEBRA_IF_VRF)
+ {
+ netlink_vrf_change(h, tb[IFLA_LINKINFO], name);
+ vrf_id = (vrf_id_t)ifi->ifi_index;
}
/* See if interface is present. */
if (tb[IFLA_MASTER])
{
if (slave_kind && (strcmp(slave_kind, "vrf") == 0))
- vrf_id = *(u_int32_t *)RTA_DATA(tb[IFLA_MASTER]);
+ {
+ zif_slave_type = ZEBRA_IF_SLAVE_VRF;
+ vrf_id = *(u_int32_t *)RTA_DATA(tb[IFLA_MASTER]);
+ }
+ else if (slave_kind && (strcmp(slave_kind, "bridge") == 0))
+ {
+ zif_slave_type = ZEBRA_IF_SLAVE_BRIDGE;
+ bridge_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_MASTER]);
+ }
+ else
+ zif_slave_type = ZEBRA_IF_SLAVE_OTHER;
}
if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
{
/* Add interface notification from kernel */
if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug ("RTM_NEWLINK for %s(%u) (ifp %p) vrf_id %u flags 0x%x",
- name, ifi->ifi_index, ifp, vrf_id, ifi->ifi_flags);
+ zlog_debug ("RTM_NEWLINK ADD for %s(%u) vrf_id %u type %d "
+ "sl_type %d master %u flags 0x%x",
+ name, ifi->ifi_index, vrf_id, zif_type, zif_slave_type,
+ bridge_ifindex, ifi->ifi_flags);
if (ifp == NULL)
{
/* Update interface information. */
set_ifindex(ifp, ifi->ifi_index, zns);
ifp->flags = ifi->ifi_flags & 0x0000fffff;
- if (vrf_device)
+ if (IS_ZEBRA_IF_VRF(ifp))
SET_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK);
ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
ifp->metric = 0;
ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN;
+ /* Set interface type */
+ zebra_if_set_ziftype (ifp, zif_type, zif_slave_type);
+
+ /* Update link. */
+ zebra_if_update_link (ifp, link_ifindex);
+
netlink_interface_update_hw_addr (tb, ifp);
/* Inform clients, install any configured addresses. */
if_add_update (ifp);
+
+ /* Extract and save L2 interface information, take additional actions. */
+ netlink_interface_update_l2info (ifp, linkinfo[IFLA_INFO_DATA], 1);
+ if (IS_ZEBRA_IF_BRIDGE_SLAVE (ifp))
+ zebra_l2if_update_bridge_slave (ifp, bridge_ifindex);
}
else if (ifp->vrf_id != vrf_id)
{
}
else
{
- /* Interface status change. */
+ int was_bridge_slave;
+
+ /* Interface update. */
if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug ("RTM_NEWLINK status for %s(%u) flags 0x%x",
- name, ifp->ifindex, ifi->ifi_flags);
+ zlog_debug ("RTM_NEWLINK update for %s(%u) "
+ "sl_type %d master %u flags 0x%x",
+ name, ifp->ifindex, zif_slave_type,
+ bridge_ifindex, ifi->ifi_flags);
set_ifindex(ifp, ifi->ifi_index, zns);
ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
ifp->metric = 0;
+ /* Update interface type - NOTE: Only slave_type can change. */
+ was_bridge_slave = IS_ZEBRA_IF_BRIDGE_SLAVE (ifp);
+ zebra_if_set_ziftype (ifp, zif_type, zif_slave_type);
+
netlink_interface_update_hw_addr (tb, ifp);
if (if_is_no_ptm_operative (ifp))
{
ifp->flags = ifi->ifi_flags & 0x0000fffff;
if (!if_is_no_ptm_operative (ifp))
- if_down (ifp);
+ {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug ("Intf %s(%u) has gone DOWN",
+ name, ifp->ifindex);
+ if_down (ifp);
+ }
else if (if_is_operative (ifp))
- /* Must notify client daemons of new interface status. */
- zebra_interface_up_update (ifp);
+ {
+ /* Must notify client daemons of new interface status. */
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug ("Intf %s(%u) PTM up, notifying clients",
+ name, ifp->ifindex);
+ zebra_interface_up_update (ifp);
+ }
}
else
{
ifp->flags = ifi->ifi_flags & 0x0000fffff;
if (if_is_operative (ifp))
- if_up (ifp);
+ {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug ("Intf %s(%u) has come UP", name, ifp->ifindex);
+ if_up (ifp);
+ }
}
+
+ /* Extract and save L2 interface information, take additional actions. */
+ netlink_interface_update_l2info (ifp, linkinfo[IFLA_INFO_DATA], 0);
+ if (IS_ZEBRA_IF_BRIDGE_SLAVE (ifp) || was_bridge_slave)
+ zebra_l2if_update_bridge_slave (ifp, bridge_ifindex);
}
}
else
UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK);
- if (!vrf_device)
+ /* Special handling for bridge or VxLAN interfaces. */
+ if (IS_ZEBRA_IF_BRIDGE (ifp))
+ zebra_l2_bridge_del (ifp);
+ else if (IS_ZEBRA_IF_VXLAN (ifp))
+ zebra_l2_vxlanif_del (ifp);
+
+ if (!IS_ZEBRA_IF_VRF(ifp))
if_delete_update (ifp);
}
void
if_delete_update (struct interface *ifp)
{
+ struct zebra_if *zif;
+
if (if_is_up(ifp))
{
zlog_err ("interface %s vrf %u index %d is still up while being deleted.",
/* if the ifp is in a vrf, move it to default so vrf can be deleted if desired */
if (ifp->vrf_id)
if_handle_vrf_change (ifp, VRF_DEFAULT);
+
+ /* Reset some zebra interface params to default values. */
+ zif = ifp->info;
+ if (zif)
+ {
+ zif->zif_type = ZEBRA_IF_OTHER;
+ zif->zif_slave_type = ZEBRA_IF_SLAVE_NONE;
+ memset (&zif->l2info, 0, sizeof (union zebra_l2if_info));
+ memset (&zif->brslave_info, 0, sizeof (struct zebra_l2info_brslave));
+ }
}
/* VRF change for an interface */
if_get_flags (ifp);
}
+void
+zebra_if_update_link (struct interface *ifp, ifindex_t link_ifindex)
+{
+ struct zebra_if *zif;
+
+ zif = (struct zebra_if *)ifp->info;
+ zif->link_ifindex = link_ifindex;
+ zif->link = if_lookup_by_index_per_ns (zebra_ns_lookup (NS_DEFAULT),
+ link_ifindex);
+}
+
/* Output prefix string to vty. */
static int
}
#endif /* HAVE_RTADV */
+static const char *
+zebra_ziftype_2str (zebra_iftype_t zif_type)
+{
+ switch (zif_type)
+ {
+ case ZEBRA_IF_OTHER:
+ return "Other";
+ break;
+
+ case ZEBRA_IF_BRIDGE:
+ return "Bridge";
+ break;
+
+ case ZEBRA_IF_VLAN:
+ return "Vlan";
+ break;
+
+ case ZEBRA_IF_VXLAN:
+ return "Vxlan";
+ break;
+
+ case ZEBRA_IF_VRF:
+ return "VRF";
+ break;
+
+ default:
+ return "Unknown";
+ break;
+ }
+}
+
/* Interface's information print out to vty interface. */
static void
if_dump_vty (struct vty *vty, struct interface *ifp)
connected_dump_vty (vty, connected);
}
+ vty_out(vty, " Interface Type %s%s",
+ zebra_ziftype_2str (zebra_if->zif_type), VTY_NEWLINE);
+ if (IS_ZEBRA_IF_BRIDGE (ifp))
+ {
+ struct zebra_l2info_bridge *bridge_info;
+
+ bridge_info = &zebra_if->l2info.br;
+ vty_out(vty, " Bridge VLAN-aware: %s%s",
+ bridge_info->vlan_aware ? "yes" : "no", VTY_NEWLINE);
+ }
+ else if (IS_ZEBRA_IF_VLAN(ifp))
+ {
+ struct zebra_l2info_vlan *vlan_info;
+
+ vlan_info = &zebra_if->l2info.vl;
+ vty_out(vty, " VLAN Id %u%s",
+ vlan_info->vid, VTY_NEWLINE);
+ }
+ else if (IS_ZEBRA_IF_VXLAN (ifp))
+ {
+ struct zebra_l2info_vxlan *vxlan_info;
+
+ vxlan_info = &zebra_if->l2info.vxl;
+ vty_out(vty, " VxLAN Id %u", vxlan_info->vni);
+ if (vxlan_info->vtep_ip.s_addr != INADDR_ANY)
+ vty_out(vty, " VTEP IP: %s", inet_ntoa (vxlan_info->vtep_ip));
+ if (vxlan_info->access_vlan)
+ vty_out(vty, " Access VLAN Id %u", vxlan_info->access_vlan);
+ vty_out(vty, "%s", VTY_NEWLINE);
+ }
+
+ if (IS_ZEBRA_IF_BRIDGE_SLAVE (ifp))
+ {
+ struct zebra_l2info_brslave *br_slave;
+
+ br_slave = &zebra_if->brslave_info;
+ if (br_slave->bridge_ifindex != IFINDEX_INTERNAL)
+ vty_out(vty, " Master (bridge) ifindex %u%s",
+ br_slave->bridge_ifindex, VTY_NEWLINE);
+ }
+
+ if (zebra_if->link_ifindex != IFINDEX_INTERNAL)
+ vty_out(vty, " Link ifindex %u%s",
+ zebra_if->link_ifindex, VTY_NEWLINE);
+
if (HAS_LINK_PARAMS(ifp))
{
int i;
#include "zebra/irdp.h"
#endif
+#include "zebra/zebra_l2.h"
+
/* For interface multicast configuration. */
#define IF_ZEBRA_MULTICAST_UNSPEC 0
#define IF_ZEBRA_MULTICAST_ON 1
#endif /* HAVE_RTADV */
+/* Zebra interface type - ones of interest. */
+typedef enum
+{
+ ZEBRA_IF_VXLAN, /* VxLAN interface */
+ ZEBRA_IF_VRF, /* VRF device */
+ ZEBRA_IF_BRIDGE, /* bridge device */
+ ZEBRA_IF_VLAN, /* VLAN sub-interface */
+ ZEBRA_IF_OTHER, /* Anything else */
+} zebra_iftype_t;
+
+/* Zebra "slave" interface type */
+typedef enum
+{
+ ZEBRA_IF_SLAVE_NONE, /* Not a slave */
+ ZEBRA_IF_SLAVE_VRF, /* Member of a VRF */
+ ZEBRA_IF_SLAVE_BRIDGE, /* Member of a bridge */
+ ZEBRA_IF_SLAVE_OTHER, /* Something else - e.g., bond slave */
+} zebra_slave_iftype_t;
+
/* `zebra' daemon local interface structure. */
struct zebra_if
{
/* ptm enable configuration */
u_char ptm_enable;
+
+ /* Zebra interface and "slave" interface type */
+ zebra_iftype_t zif_type;
+ zebra_slave_iftype_t zif_slave_type;
+
+ /* Additional L2 info, depends on zif_type */
+ union zebra_l2if_info l2info;
+
+ /* For members of a bridge, link to bridge. */
+ /* Note: If additional fields become necessary, this can be modified to
+ * be a pointer to a dynamically allocd struct.
+ */
+ struct zebra_l2info_brslave brslave_info;
+
+ /* Link fields - for sub-interfaces. */
+ ifindex_t link_ifindex;
+ struct interface *link;
};
+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_type = zif_type;
+ zif->zif_slave_type = zif_slave_type;
+}
+
+#define IS_ZEBRA_IF_VRF(ifp) \
+ (((struct zebra_if *)(ifp->info))->zif_type == ZEBRA_IF_VRF)
+
+#define IS_ZEBRA_IF_BRIDGE(ifp) \
+ (((struct zebra_if *)(ifp->info))->zif_type == ZEBRA_IF_BRIDGE)
+
+#define IS_ZEBRA_IF_VLAN(ifp) \
+ (((struct zebra_if *)(ifp->info))->zif_type == ZEBRA_IF_VLAN)
+
+#define IS_ZEBRA_IF_VXLAN(ifp) \
+ (((struct zebra_if *)(ifp->info))->zif_type == ZEBRA_IF_VXLAN)
+
+#define IS_ZEBRA_IF_BRIDGE_SLAVE(ifp) \
+ (((struct zebra_if *)(ifp->info))->zif_slave_type == ZEBRA_IF_SLAVE_BRIDGE)
+
+#define IS_ZEBRA_IF_VRF_SLAVE(ifp) \
+ (((struct zebra_if *)(ifp->info))->zif_slave_type == ZEBRA_IF_SLAVE_VRF)
extern struct interface *if_lookup_by_index_per_ns (struct zebra_ns *, u_int32_t);
extern struct interface *if_lookup_by_name_per_ns (struct zebra_ns *, const char *);
extern int if_subnet_delete (struct interface *, struct connected *);
extern int ipv6_address_configured (struct interface *ifp);
extern void if_handle_vrf_change (struct interface *ifp, vrf_id_t vrf_id);
+extern void zebra_if_update_link (struct interface *ifp, ifindex_t link_ifindex);
extern void vrf_add_update (struct vrf *vrfp);
--- /dev/null
+/*
+ * Zebra Layer-2 interface handling code
+ * Copyright (C) 2016, 2017 Cumulus Networks, Inc.
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "prefix.h"
+#include "table.h"
+#include "memory.h"
+#include "log.h"
+#include "linklist.h"
+#include "stream.h"
+#include "hash.h"
+#include "jhash.h"
+
+#include "zebra/rib.h"
+#include "zebra/rt.h"
+#include "zebra/zebra_ns.h"
+#include "zebra/zserv.h"
+#include "zebra/debug.h"
+#include "zebra/interface.h"
+#include "zebra/zebra_memory.h"
+#include "zebra/zebra_vrf.h"
+#include "zebra/rt_netlink.h"
+#include "zebra/zebra_l2.h"
+
+/* definitions */
+
+/* static function declarations */
+
+/* Private functions */
+static void
+map_slaves_to_bridge (struct interface *br_if, int link)
+{
+ struct vrf *vrf;
+ struct listnode *node;
+ struct interface *ifp;
+
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name)
+ {
+ for (ALL_LIST_ELEMENTS_RO (vrf->iflist, node, ifp))
+ {
+ struct zebra_if *zif;
+ struct zebra_l2info_brslave *br_slave;
+
+ if (ifp->ifindex == IFINDEX_INTERNAL ||
+ !ifp->info)
+ continue;
+ if (!IS_ZEBRA_IF_BRIDGE_SLAVE (ifp))
+ continue;
+
+ /* NOTE: This assumes 'zebra_l2info_brslave' is the first field
+ * for any L2 interface.
+ */
+ zif = (struct zebra_if *) ifp->info;
+ br_slave = &zif->brslave_info;
+
+ if (link)
+ {
+ if (br_slave->bridge_ifindex == br_if->ifindex)
+ br_slave->br_if = br_if;
+ }
+ else
+ {
+ if (br_slave->br_if == br_if)
+ br_slave->br_if = NULL;
+ }
+ }
+ }
+}
+
+/* Public functions */
+void
+zebra_l2_map_slave_to_bridge (struct zebra_l2info_brslave *br_slave)
+{
+ struct interface *br_if;
+
+ /* TODO: Handle change of master */
+ br_if = if_lookup_by_index_per_ns (zebra_ns_lookup (NS_DEFAULT),
+ br_slave->bridge_ifindex);
+ if (br_if)
+ br_slave->br_if = br_if;
+}
+
+void
+zebra_l2_unmap_slave_from_bridge (struct zebra_l2info_brslave *br_slave)
+{
+ br_slave->br_if = NULL;
+}
+
+/*
+ * Handle Bridge interface add or update. Update relevant info,
+ * map slaves (if any) to the bridge.
+ */
+void
+zebra_l2_bridge_add_update (struct interface *ifp,
+ struct zebra_l2info_bridge *bridge_info,
+ int add)
+{
+ struct zebra_if *zif;
+
+ zif = ifp->info;
+ assert(zif);
+
+ /* Copy over the L2 information. */
+ memcpy (&zif->l2info.br, bridge_info, sizeof (*bridge_info));
+
+ /* Link all slaves to this bridge */
+ map_slaves_to_bridge (ifp, 1);
+}
+
+/*
+ * Handle Bridge interface delete.
+ */
+void
+zebra_l2_bridge_del (struct interface *ifp)
+{
+ /* Unlink all slaves to this bridge */
+ map_slaves_to_bridge (ifp, 0);
+}
+
+/*
+ * Update L2 info for a VLAN interface. Only relevant parameter is the
+ * VLAN Id and this cannot change.
+ */
+void
+zebra_l2_vlanif_update (struct interface *ifp,
+ struct zebra_l2info_vlan *vlan_info)
+{
+ struct zebra_if *zif;
+
+ zif = ifp->info;
+ assert(zif);
+
+ /* Copy over the L2 information. */
+ memcpy (&zif->l2info.vl, vlan_info, sizeof (*vlan_info));
+}
+
+/*
+ * Update L2 info for a VxLAN interface. This is called upon interface
+ * addition as well as update. Upon add, need to invoke the VNI create
+ * function. Upon update, the params of interest are the local tunnel
+ * IP and VLAN mapping, but the latter is handled separately.
+ */
+void
+zebra_l2_vxlanif_add_update (struct interface *ifp,
+ struct zebra_l2info_vxlan *vxlan_info,
+ int add)
+{
+ struct zebra_if *zif;
+ struct in_addr old_vtep_ip;
+
+ zif = ifp->info;
+ assert(zif);
+
+ if (add)
+ {
+ memcpy (&zif->l2info.vxl, vxlan_info, sizeof (*vxlan_info));
+ return;
+ }
+
+ old_vtep_ip = zif->l2info.vxl.vtep_ip;
+ if (IPV4_ADDR_SAME(&old_vtep_ip, &vxlan_info->vtep_ip))
+ return;
+
+ zif->l2info.vxl.vtep_ip = vxlan_info->vtep_ip;
+}
+
+/*
+ * Handle change to VLAN to VNI mapping.
+ */
+void
+zebra_l2_vxlanif_update_access_vlan (struct interface *ifp,
+ vlanid_t access_vlan)
+{
+ struct zebra_if *zif;
+
+ zif = ifp->info;
+ assert(zif);
+
+ zif->l2info.vxl.access_vlan = access_vlan;
+}
+
+/*
+ * Handle VxLAN interface delete.
+ */
+void
+zebra_l2_vxlanif_del (struct interface *ifp)
+{
+ /* No action currently. */
+}
+
+/*
+ * Map or unmap interface from bridge.
+ * NOTE: It is currently assumped that an interface has to be unmapped
+ * from a bridge before it can be mapped to another bridge.
+ */
+void
+zebra_l2if_update_bridge_slave (struct interface *ifp,
+ ifindex_t bridge_ifindex)
+{
+ struct zebra_if *zif;
+ ifindex_t old_bridge_ifindex;
+
+ zif = ifp->info;
+ assert(zif);
+
+ old_bridge_ifindex = zif->brslave_info.bridge_ifindex;
+ if (old_bridge_ifindex == bridge_ifindex)
+ return;
+
+ zif->brslave_info.bridge_ifindex = bridge_ifindex;
+
+ /* Set up or remove link with master */
+ if (bridge_ifindex != IFINDEX_INTERNAL)
+ zebra_l2_map_slave_to_bridge (&zif->brslave_info);
+ else if (old_bridge_ifindex != IFINDEX_INTERNAL)
+ zebra_l2_unmap_slave_from_bridge (&zif->brslave_info);
+}
--- /dev/null
+/*
+ * Zebra Layer-2 interface Data structures and definitions
+ * Copyright (C) 2016, 2017 Cumulus Networks, Inc.
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_L2_H
+#define _ZEBRA_L2_H
+
+#include <zebra.h>
+
+#include "if.h"
+#include "vlan.h"
+#include "vxlan.h"
+
+/* zebra L2 interface information - bridge slave (linkage to bridge) */
+struct zebra_l2info_brslave
+{
+ ifindex_t bridge_ifindex; /* Bridge Master */
+ struct interface *br_if; /* Pointer to master */
+};
+
+/* zebra L2 interface information - bridge interface */
+struct zebra_l2info_bridge
+{
+ u_char vlan_aware; /* VLAN-aware bridge? */
+};
+
+/* zebra L2 interface information - VLAN interface */
+struct zebra_l2info_vlan
+{
+ vlanid_t vid; /* VLAN id */
+};
+
+/* zebra L2 interface information - VXLAN interface */
+struct zebra_l2info_vxlan
+{
+ vni_t vni; /* VNI */
+ struct in_addr vtep_ip; /* Local tunnel IP */
+ vlanid_t access_vlan; /* Access VLAN - for VLAN-aware bridge. */
+};
+
+union zebra_l2if_info
+{
+ struct zebra_l2info_bridge br;
+ struct zebra_l2info_vlan vl;
+ struct zebra_l2info_vxlan vxl;
+};
+
+/* NOTE: These macros are to be invoked only in the "correct" context.
+ * IOW, the macro VNI_FROM_ZEBRA_IF() will assume the interface is
+ * of type ZEBRA_IF_VXLAN.
+ */
+#define VNI_FROM_ZEBRA_IF(zif) (zif)->l2info.vxl.vni
+#define VLAN_ID_FROM_ZEBRA_IF(zif) (zif)->l2info.vl.vid
+
+#define IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(zif) \
+ ((zif)->l2info.br.vlan_aware == 1)
+
+
+extern void zebra_l2_map_slave_to_bridge (struct zebra_l2info_brslave *br_slave);
+extern void zebra_l2_unmap_slave_from_bridge (struct zebra_l2info_brslave *br_slave);
+extern void zebra_l2_bridge_add_update (struct interface *ifp,
+ struct zebra_l2info_bridge *bridge_info,
+ int add);
+extern void zebra_l2_bridge_del (struct interface *ifp);
+extern void zebra_l2_vlanif_update (struct interface *ifp,
+ struct zebra_l2info_vlan *vlan_info);
+extern void zebra_l2_vxlanif_add_update (struct interface *ifp,
+ struct zebra_l2info_vxlan *vxlan_info,
+ int add);
+extern void zebra_l2_vxlanif_update_access_vlan (struct interface *ifp,
+ vlanid_t access_vlan);
+extern void zebra_l2_vxlanif_del (struct interface *ifp);
+extern void zebra_l2if_update_bridge_slave (struct interface *ifp,
+ ifindex_t bridge_ifindex);
+
+#endif /* _ZEBRA_L2_H */
--- /dev/null
+/*
+ * Zebra Layer-2 interface Data structures and definitions
+ * Copyright (C) 2016, 2017 Cumulus Networks, Inc.
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "zebra/debug.h"
+#include "zebra/zserv.h"
+#include "zebra/rib.h"
+#include "zebra/zebra_vrf.h"
+#include "zebra/zebra_l2.h"
+
+void zebra_l2_map_slave_to_bridge (struct zebra_l2info_brslave *br_slave)
+{
+}
+
+void
+zebra_l2_unmap_slave_from_bridge (struct zebra_l2info_brslave *br_slave)
+{
+}
+
+void zebra_l2_bridge_add_update (struct interface *ifp,
+ struct zebra_l2info_bridge *bridge_info,
+ int add)
+{
+}
+
+void zebra_l2_bridge_del (struct interface *ifp)
+{
+}
+
+void zebra_l2_vlanif_update (struct interface *ifp,
+ struct zebra_l2info_vlan *vlan_info)
+{
+}
+
+void zebra_l2_vxlanif_add_update (struct interface *ifp,
+ struct zebra_l2info_vxlan *vxlan_info,
+ int add)
+{
+}
+
+void
+zebra_l2_vxlanif_update_access_vlan (struct interface *ifp,
+ vlanid_t access_vlan)
+{
+}
+
+void zebra_l2_vxlanif_del (struct interface *ifp)
+{
+}
+
+void
+zebra_l2if_update_bridge_slave (struct interface *ifp,
+ ifindex_t bridge_ifindex)
+{
+}