From: vivek Date: Mon, 15 May 2017 05:31:08 +0000 (-0700) Subject: zebra: Layer-2 interface handling X-Git-Tag: reindent-master-before~6^2~32 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=6675513d00b8cb59942ecb05f990852d14ef3e41;p=matthieu%2Ffrr.git zebra: Layer-2 interface handling 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 Reviewed-by: Donald Sharp --- diff --git a/zebra/Makefile.am b/zebra/Makefile.am index 541496174a..a19e6e708c 100644 --- a/zebra/Makefile.am +++ b/zebra/Makefile.am @@ -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) diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 5af6c3a08f..972e6447f6 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -20,6 +20,15 @@ */ #include + +/* 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 #include #include #include @@ -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); } diff --git a/zebra/interface.c b/zebra/interface.c index b8426c6890..78ba8cdde8 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -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; diff --git a/zebra/interface.h b/zebra/interface.h index b276edc353..f5ca00c4aa 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -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 index 0000000000..5dd83baedd --- /dev/null +++ b/zebra/zebra_l2.c @@ -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 + +#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 index 0000000000..5cfc6dee44 --- /dev/null +++ b/zebra/zebra_l2.h @@ -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 + +#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 index 0000000000..d50107f65d --- /dev/null +++ b/zebra/zebra_l2_null.c @@ -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 + +#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) +{ +}