]> git.puffer.fish Git - matthieu/frr.git/commitdiff
zebra: Layer-2 interface handling
authorvivek <vivek@cumulusnetworks.com>
Mon, 15 May 2017 05:31:08 +0000 (22:31 -0700)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Wed, 12 Jul 2017 16:22:19 +0000 (12:22 -0400)
Define interface types of interest and recognize the types. Store layer-2
information (VLAN Id, VNI etc.) for interfaces, process bridge interfaces
and map bridge members to bridge. Display all the additional information
to user (through "show interface").

Note: Only implemented for the netlink interface.

Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
zebra/Makefile.am
zebra/if_netlink.c
zebra/interface.c
zebra/interface.h
zebra/zebra_l2.c [new file with mode: 0644]
zebra/zebra_l2.h [new file with mode: 0644]
zebra/zebra_l2_null.c [new file with mode: 0644]

index 541496174afb545003345a4f2d12f2987248f05b..a19e6e708c2925eb222fa6212a859883389cd18b 100644 (file)
@@ -33,6 +33,7 @@ zebra_SOURCES = \
        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 = \
@@ -42,7 +43,8 @@ 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)
 
index 5af6c3a08fbc80a474d1658c3b06dd2a7cab5756..972e6447f6cf6b2f15c7fae61ec5d4678448c1ee 100644 (file)
  */
 
 #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>
@@ -175,6 +184,23 @@ netlink_to_zebra_link_type (unsigned int hwt)
   }
 }
 
+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
@@ -341,6 +367,173 @@ get_iflink_speed (const char *ifname)
   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
@@ -355,9 +548,12 @@ netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h,
   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);
@@ -369,11 +565,13 @@ netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *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
@@ -392,7 +590,6 @@ netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h,
 
   if (tb[IFLA_LINKINFO])
     {
-      memset (linkinfo, 0, sizeof linkinfo);
       parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
 
       if (linkinfo[IFLA_INFO_KIND])
@@ -403,37 +600,64 @@ netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h,
          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;
 }
 
@@ -477,6 +701,15 @@ interface_lookup_netlink (struct zebra_ns *zns)
   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)
@@ -712,9 +945,13 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
   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);
@@ -731,11 +968,13 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *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
@@ -754,7 +993,6 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
 
   if (tb[IFLA_LINKINFO])
     {
-      memset (linkinfo, 0, sizeof linkinfo);
       parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
 
       if (linkinfo[IFLA_INFO_KIND])
@@ -765,12 +1003,18 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
           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. */
@@ -781,15 +1025,27 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
       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)
             {
@@ -806,16 +1062,27 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
           /* 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)
         {
@@ -830,32 +1097,59 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
         }
       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
@@ -873,7 +1167,13 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
 
       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);
     }
 
index b8426c6890b73f0cdc6700bd9b8442dcf187fda2..78ba8cdde814c55c41707d8c187e579a00727895 100644 (file)
@@ -680,6 +680,8 @@ if_delete_connected (struct interface *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.",
@@ -713,6 +715,16 @@ if_delete_update (struct interface *ifp)
   /* 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 */
@@ -904,6 +916,17 @@ if_refresh (struct interface *ifp)
   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
@@ -1020,6 +1043,37 @@ nd_dump_vty (struct vty *vty, struct interface *ifp)
 }
 #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)
@@ -1115,6 +1169,51 @@ 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;
index b276edc3531f17f889708861509a68119d8e7d01..f5ca00c4aa4f17f9d8caeee6e9f661b9daabd551 100644 (file)
@@ -28,6 +28,8 @@
 #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
@@ -180,6 +182,25 @@ struct rtadvconf
 
 #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
 {
@@ -231,8 +252,53 @@ 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 *);
@@ -253,6 +319,7 @@ extern int if_subnet_add (struct interface *, struct connected *);
 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);
 
diff --git a/zebra/zebra_l2.c b/zebra/zebra_l2.c
new file mode 100644 (file)
index 0000000..5dd83ba
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * 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);
+}
diff --git a/zebra/zebra_l2.h b/zebra/zebra_l2.h
new file mode 100644 (file)
index 0000000..5cfc6de
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * 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 */
diff --git a/zebra/zebra_l2_null.c b/zebra/zebra_l2_null.c
new file mode 100644 (file)
index 0000000..d50107f
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * 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)
+{
+}