From 6675513d00b8cb59942ecb05f990852d14ef3e41 Mon Sep 17 00:00:00 2001 From: vivek Date: Sun, 14 May 2017 22:31:08 -0700 Subject: [PATCH 01/31] 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 --- zebra/Makefile.am | 4 +- zebra/if_netlink.c | 364 ++++++++++++++++++++++++++++++++++++++---- zebra/interface.c | 99 ++++++++++++ zebra/interface.h | 67 ++++++++ zebra/zebra_l2.c | 238 +++++++++++++++++++++++++++ zebra/zebra_l2.h | 94 +++++++++++ zebra/zebra_l2_null.c | 76 +++++++++ 7 files changed, 909 insertions(+), 33 deletions(-) create mode 100644 zebra/zebra_l2.c create mode 100644 zebra/zebra_l2.h create mode 100644 zebra/zebra_l2_null.c 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) +{ +} From 18a7a601c713ab1cc7fa91a7f883e18a25cc2fa1 Mon Sep 17 00:00:00 2001 From: vivek Date: Sun, 14 May 2017 22:37:42 -0700 Subject: [PATCH 02/31] zebra: VNI and VTEP definition Define the base data structures for a VxLAN Network Identifier (VNI) and VxLAN Tunnel End Point (VTEP). These will be used by the EVPN function. Signed-off-by: Vivek Venkatraman Reviewed-by: Donald Sharp --- zebra/Makefile.am | 2 +- zebra/zebra_vxlan_private.h | 76 +++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 zebra/zebra_vxlan_private.h diff --git a/zebra/Makefile.am b/zebra/Makefile.am index a19e6e708c..25e6b1bc1b 100644 --- a/zebra/Makefile.am +++ b/zebra/Makefile.am @@ -44,7 +44,7 @@ noinst_HEADERS = \ 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 \ - zebra_l2.h + zebra_l2.h zebra_vxlan_private.h zebra_LDADD = $(otherobj) ../lib/libfrr.la $(LIBCAP) diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h new file mode 100644 index 0000000000..c33eba54e8 --- /dev/null +++ b/zebra/zebra_vxlan_private.h @@ -0,0 +1,76 @@ +/* + * Zebra VxLAN (EVPN) Data structures and definitions + * These are "internal" to this function. + * 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_VXLAN_PRIVATE_H +#define _ZEBRA_VXLAN_PRIVATE_H + +#include + +#include + +#include "if.h" +#include "linklist.h" + +/* definitions */ +typedef struct zebra_vni_t_ zebra_vni_t; +typedef struct zebra_vtep_t_ zebra_vtep_t; + +/* + * VTEP info + * + * Right now, this just has each remote VTEP's IP address. + */ +struct zebra_vtep_t_ +{ + /* Remote IP. */ + /* NOTE: Can only be IPv4 right now. */ + struct in_addr vtep_ip; + + /* Links. */ + struct zebra_vtep_t_ *next; + struct zebra_vtep_t_ *prev; +}; + + +/* + * VNI hash table + * + * Contains information pertaining to a VNI: + * - the list of remote VTEPs (with this VNI) + */ +struct zebra_vni_t_ +{ + /* VNI - key */ + vni_t vni; + + /* Corresponding VxLAN interface. */ + struct interface *vxlan_if; + + /* List of remote VTEPs */ + zebra_vtep_t *vteps; + + /* Local IP */ + struct in_addr local_vtep_ip; +}; + +#endif /* _ZEBRA_VXLAN_PRIVATE_H */ From 13d60d351c4c70e8a2949ef45d88ec4efe382367 Mon Sep 17 00:00:00 2001 From: vivek Date: Sun, 14 May 2017 22:38:26 -0700 Subject: [PATCH 03/31] zebra: VNI and VTEP handling Implement fundamental handling for VNIs and VTEPs: - Handle EVPN enable/disable by client (advertise-all-vni) - Create/update/delete VNIs based on VxLAN interface events and inform client - Handle VTEP add/delete from client and install into kernel - New debug command for VxLAN/EVPN - kernel interface (Linux/netlink only) Signed-off-by: Vivek Venkatraman Reviewed-by: Donald Sharp --- lib/log.c | 5 + lib/zclient.h | 5 + zebra/Makefile.am | 3 +- zebra/debug.c | 34 ++ zebra/debug.h | 4 + zebra/if_netlink.c | 9 + zebra/interface.c | 7 + zebra/rt.h | 5 + zebra/rt_netlink.c | 67 +++ zebra/rt_socket.c | 13 + zebra/zebra_l2.c | 15 +- zebra/zebra_vrf.c | 5 + zebra/zebra_vrf.h | 9 + zebra/zebra_vxlan.c | 905 +++++++++++++++++++++++++++++++++++++++ zebra/zebra_vxlan.h | 59 +++ zebra/zebra_vxlan_null.c | 89 ++++ zebra/zserv.c | 13 +- zebra/zserv.h | 2 + 18 files changed, 1246 insertions(+), 3 deletions(-) create mode 100644 zebra/zebra_vxlan.c create mode 100644 zebra/zebra_vxlan.h create mode 100644 zebra/zebra_vxlan_null.c diff --git a/lib/log.c b/lib/log.c index 1c61d72168..7a7545201d 100644 --- a/lib/log.c +++ b/lib/log.c @@ -946,6 +946,11 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY (ZEBRA_LABEL_MANAGER_CONNECT), DESC_ENTRY (ZEBRA_GET_LABEL_CHUNK), DESC_ENTRY (ZEBRA_RELEASE_LABEL_CHUNK), + DESC_ENTRY (ZEBRA_ADVERTISE_ALL_VNI), + DESC_ENTRY (ZEBRA_VNI_ADD), + DESC_ENTRY (ZEBRA_VNI_DEL), + DESC_ENTRY (ZEBRA_REMOTE_VTEP_ADD), + DESC_ENTRY (ZEBRA_REMOTE_VTEP_DEL), }; #undef DESC_ENTRY diff --git a/lib/zclient.h b/lib/zclient.h index 59412fdd4c..0c9f70751c 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -96,6 +96,11 @@ typedef enum { ZEBRA_FEC_REGISTER, ZEBRA_FEC_UNREGISTER, ZEBRA_FEC_UPDATE, + ZEBRA_ADVERTISE_ALL_VNI, + ZEBRA_VNI_ADD, + ZEBRA_VNI_DEL, + ZEBRA_REMOTE_VTEP_ADD, + ZEBRA_REMOTE_VTEP_DEL, } zebra_message_types_t; struct redist_proto diff --git a/zebra/Makefile.am b/zebra/Makefile.am index 25e6b1bc1b..2bb9da0a9e 100644 --- a/zebra/Makefile.am +++ b/zebra/Makefile.am @@ -34,6 +34,7 @@ zebra_SOURCES = \ zebra_mroute.c \ label_manager.c \ zebra_l2.c \ + zebra_vxlan.c \ # end noinst_HEADERS = \ @@ -44,7 +45,7 @@ noinst_HEADERS = \ 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 \ - zebra_l2.h zebra_vxlan_private.h + zebra_l2.h zebra_vxlan_private.h zebra_vxlan.h zebra_LDADD = $(otherobj) ../lib/libfrr.la $(LIBCAP) diff --git a/zebra/debug.c b/zebra/debug.c index ba2a9ad2a3..0b0a0e9886 100644 --- a/zebra/debug.c +++ b/zebra/debug.c @@ -31,6 +31,7 @@ unsigned long zebra_debug_rib; unsigned long zebra_debug_fpm; unsigned long zebra_debug_nht; unsigned long zebra_debug_mpls; +unsigned long zebra_debug_vxlan; DEFUN (show_debugging_zebra, show_debugging_zebra_cmd, @@ -121,6 +122,17 @@ DEFUN (debug_zebra_mpls, return CMD_WARNING; } +DEFUN (debug_zebra_vxlan, + debug_zebra_vxlan_cmd, + "debug zebra vxlan", + DEBUG_STR + "Zebra configuration\n" + "Debug option set for zebra VxLAN (EVPN)\n") +{ + zebra_debug_vxlan = ZEBRA_DEBUG_VXLAN; + return CMD_WARNING; +} + DEFUN (debug_zebra_packet, debug_zebra_packet_cmd, "debug zebra packet [] [detail]", @@ -251,6 +263,18 @@ DEFUN (no_debug_zebra_mpls, return CMD_SUCCESS; } +DEFUN (no_debug_zebra_vxlan, + no_debug_zebra_vxlan_cmd, + "no debug zebra vxlan", + NO_STR + DEBUG_STR + "Zebra configuration\n" + "Debug option set for zebra VxLAN (EVPN)\n") +{ + zebra_debug_vxlan = 0; + return CMD_SUCCESS; +} + DEFUN (no_debug_zebra_packet, no_debug_zebra_packet_cmd, "no debug zebra packet []", @@ -419,6 +443,11 @@ config_write_debug (struct vty *vty) vty_out (vty, "debug zebra mpls%s", VTYNL); write++; } + if (IS_ZEBRA_DEBUG_VXLAN) + { + vty_out (vty, "debug zebra vxlan%s", VTY_NEWLINE); + write++; + } return write; } @@ -431,6 +460,7 @@ zebra_debug_init (void) zebra_debug_rib = 0; zebra_debug_fpm = 0; zebra_debug_mpls = 0; + zebra_debug_vxlan = 0; install_node (&debug_node, config_write_debug); @@ -439,6 +469,7 @@ zebra_debug_init (void) install_element (ENABLE_NODE, &debug_zebra_events_cmd); install_element (ENABLE_NODE, &debug_zebra_nht_cmd); install_element (ENABLE_NODE, &debug_zebra_mpls_cmd); + install_element (ENABLE_NODE, &debug_zebra_vxlan_cmd); install_element (ENABLE_NODE, &debug_zebra_packet_cmd); install_element (ENABLE_NODE, &debug_zebra_kernel_cmd); install_element (ENABLE_NODE, &debug_zebra_kernel_msgdump_cmd); @@ -448,6 +479,7 @@ zebra_debug_init (void) install_element (ENABLE_NODE, &no_debug_zebra_events_cmd); install_element (ENABLE_NODE, &no_debug_zebra_nht_cmd); install_element (ENABLE_NODE, &no_debug_zebra_mpls_cmd); + install_element (ENABLE_NODE, &no_debug_zebra_vxlan_cmd); install_element (ENABLE_NODE, &no_debug_zebra_packet_cmd); install_element (ENABLE_NODE, &no_debug_zebra_kernel_cmd); install_element (ENABLE_NODE, &no_debug_zebra_kernel_msgdump_cmd); @@ -458,6 +490,7 @@ zebra_debug_init (void) install_element (CONFIG_NODE, &debug_zebra_events_cmd); install_element (CONFIG_NODE, &debug_zebra_nht_cmd); install_element (CONFIG_NODE, &debug_zebra_mpls_cmd); + install_element (CONFIG_NODE, &debug_zebra_vxlan_cmd); install_element (CONFIG_NODE, &debug_zebra_packet_cmd); install_element (CONFIG_NODE, &debug_zebra_kernel_cmd); install_element (CONFIG_NODE, &debug_zebra_kernel_msgdump_cmd); @@ -467,6 +500,7 @@ zebra_debug_init (void) install_element (CONFIG_NODE, &no_debug_zebra_events_cmd); install_element (CONFIG_NODE, &no_debug_zebra_nht_cmd); install_element (CONFIG_NODE, &no_debug_zebra_mpls_cmd); + install_element (CONFIG_NODE, &no_debug_zebra_vxlan_cmd); install_element (CONFIG_NODE, &no_debug_zebra_packet_cmd); install_element (CONFIG_NODE, &no_debug_zebra_kernel_cmd); install_element (CONFIG_NODE, &no_debug_zebra_kernel_msgdump_cmd); diff --git a/zebra/debug.h b/zebra/debug.h index 0a50da8176..5687a3516b 100644 --- a/zebra/debug.h +++ b/zebra/debug.h @@ -42,6 +42,8 @@ #define ZEBRA_DEBUG_MPLS 0x01 +#define ZEBRA_DEBUG_VXLAN 0x01 + /* Debug related macro. */ #define IS_ZEBRA_DEBUG_EVENT (zebra_debug_event & ZEBRA_DEBUG_EVENT) @@ -63,6 +65,7 @@ #define IS_ZEBRA_DEBUG_FPM (zebra_debug_fpm & ZEBRA_DEBUG_FPM) #define IS_ZEBRA_DEBUG_NHT (zebra_debug_nht & ZEBRA_DEBUG_NHT) #define IS_ZEBRA_DEBUG_MPLS (zebra_debug_mpls & ZEBRA_DEBUG_MPLS) +#define IS_ZEBRA_DEBUG_VXLAN (zebra_debug_vxlan & ZEBRA_DEBUG_VXLAN) extern unsigned long zebra_debug_event; extern unsigned long zebra_debug_packet; @@ -71,6 +74,7 @@ extern unsigned long zebra_debug_rib; extern unsigned long zebra_debug_fpm; extern unsigned long zebra_debug_nht; extern unsigned long zebra_debug_mpls; +extern unsigned long zebra_debug_vxlan; extern void zebra_debug_init (void); diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 972e6447f6..d0907a2670 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -710,6 +710,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) diff --git a/zebra/interface.c b/zebra/interface.c index 78ba8cdde8..87b0896f9f 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -47,6 +47,7 @@ #include "zebra/zebra_ptm.h" #include "zebra/rt_netlink.h" #include "zebra/interface.h" +#include "zebra/zebra_vxlan.h" #define ZEBRA_PTM_SUPPORT @@ -880,6 +881,9 @@ if_up (struct interface *ifp) rib_update (ifp->vrf_id, RIB_UPDATE_IF_CHANGE); zebra_vrf_static_route_interface_fixup (ifp); + + if (IS_ZEBRA_IF_VXLAN (ifp)) + zebra_vxlan_if_up (ifp); } /* Interface goes down. We have to manage different behavior of based @@ -893,6 +897,9 @@ if_down (struct interface *ifp) zif->down_count++; quagga_timestamp (2, zif->down_last, sizeof (zif->down_last)); + if (IS_ZEBRA_IF_VXLAN (ifp)) + zebra_vxlan_if_down (ifp); + /* Notify to the protocol daemons. */ zebra_interface_down_update (ifp); diff --git a/zebra/rt.h b/zebra/rt.h index a39af87b5a..10ca6c95cf 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -24,6 +24,7 @@ #include "prefix.h" #include "if.h" +#include "vxlan.h" #include "zebra/rib.h" #include "zebra/zebra_ns.h" #include "zebra/zebra_mpls.h" @@ -41,4 +42,8 @@ extern int kernel_del_lsp (zebra_lsp_t *); extern int mpls_kernel_init (void); extern int kernel_get_ipmr_sg_stats (void *mroute); +extern int kernel_add_vtep (vni_t vni, struct interface *ifp, + struct in_addr *vtep_ip); +extern int kernel_del_vtep (vni_t vni, struct interface *ifp, + struct in_addr *vtep_ip); #endif /* _ZEBRA_RT_H */ diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 471f650588..7ff03e7c04 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -41,6 +41,7 @@ #include "vrf.h" #include "vty.h" #include "mpls.h" +#include "vxlan.h" #include "zebra/zserv.h" #include "zebra/zebra_ns.h" @@ -1555,6 +1556,72 @@ kernel_neigh_update (int add, int ifindex, uint32_t addr, char *lla, int llalen) lla, llalen); } +/* + * Add remote VTEP to the flood list for this VxLAN interface (VNI). This + * is done by adding an FDB entry with a MAC of 00:00:00:00:00:00. + */ +static int +netlink_vxlan_flood_list_update (struct interface *ifp, + struct in_addr *vtep_ip, + int cmd) +{ + struct zebra_ns *zns = zebra_ns_lookup (NS_DEFAULT); + struct + { + struct nlmsghdr n; + struct ndmsg ndm; + char buf[256]; + } req; + u_char dst_mac[6] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; + + memset(&req.n, 0, sizeof(req.n)); + memset(&req.ndm, 0, sizeof(req.ndm)); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + if (cmd == RTM_NEWNEIGH) + req.n.nlmsg_flags |= (NLM_F_CREATE | NLM_F_APPEND); + req.n.nlmsg_type = cmd; + req.ndm.ndm_family = PF_BRIDGE; + req.ndm.ndm_state = NUD_NOARP | NUD_PERMANENT; + req.ndm.ndm_flags |= NTF_SELF; // Handle by "self", not "master" + + + addattr_l (&req.n, sizeof (req), NDA_LLADDR, &dst_mac, 6); + req.ndm.ndm_ifindex = ifp->ifindex; + addattr_l (&req.n, sizeof (req), NDA_DST, &vtep_ip->s_addr, 4); + + return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0); +} + +/* + * Add remote VTEP for this VxLAN interface (VNI). In Linux, this involves adding + * a "flood" MAC FDB entry. + */ +int +kernel_add_vtep (vni_t vni, struct interface *ifp, struct in_addr *vtep_ip) +{ + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug ("Install %s into flood list for VNI %u intf %s(%u)", + inet_ntoa (*vtep_ip), vni, ifp->name, ifp->ifindex); + + return netlink_vxlan_flood_list_update (ifp, vtep_ip, RTM_NEWNEIGH); +} + +/* + * Remove remote VTEP for this VxLAN interface (VNI). In Linux, this involves + * deleting the "flood" MAC FDB entry. + */ +int +kernel_del_vtep (vni_t vni, struct interface *ifp, struct in_addr *vtep_ip) +{ + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug ("Uninstall %s from flood list for VNI %u intf %s(%u)", + inet_ntoa (*vtep_ip), vni, ifp->name, ifp->ifindex); + + return netlink_vxlan_flood_list_update (ifp, vtep_ip, RTM_DELNEIGH); +} + /* * MPLS label forwarding table change via netlink interface. */ diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index 9859a31627..bf7e3403e4 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -29,6 +29,7 @@ #include "sockunion.h" #include "log.h" #include "privs.h" +#include "vxlan.h" #include "zebra/debug.h" #include "zebra/rib.h" @@ -428,3 +429,15 @@ kernel_get_ipmr_sg_stats (void *mroute) { return 0; } + +int +kernel_add_vtep (vni_t vni, struct interface *ifp, struct in_addr *vtep_ip) +{ + return 0; +} + +int +kernel_del_vtep (vni_t vni, struct interface *ifp, struct in_addr *vtep_ip) +{ + return 0; +} diff --git a/zebra/zebra_l2.c b/zebra/zebra_l2.c index 5dd83baedd..b71b96a18b 100644 --- a/zebra/zebra_l2.c +++ b/zebra/zebra_l2.c @@ -42,6 +42,7 @@ #include "zebra/zebra_vrf.h" #include "zebra/rt_netlink.h" #include "zebra/zebra_l2.h" +#include "zebra/zebra_vxlan.h" /* definitions */ @@ -175,6 +176,7 @@ zebra_l2_vxlanif_add_update (struct interface *ifp, if (add) { memcpy (&zif->l2info.vxl, vxlan_info, sizeof (*vxlan_info)); + zebra_vxlan_if_add (ifp); return; } @@ -183,6 +185,7 @@ zebra_l2_vxlanif_add_update (struct interface *ifp, return; zif->l2info.vxl.vtep_ip = vxlan_info->vtep_ip; + zebra_vxlan_if_update (ifp, ZEBRA_VXLIF_LOCAL_IP_CHANGE); } /* @@ -193,11 +196,17 @@ zebra_l2_vxlanif_update_access_vlan (struct interface *ifp, vlanid_t access_vlan) { struct zebra_if *zif; + vlanid_t old_access_vlan; zif = ifp->info; assert(zif); + old_access_vlan = zif->l2info.vxl.access_vlan; + if (old_access_vlan == access_vlan) + return; + zif->l2info.vxl.access_vlan = access_vlan; + zebra_vxlan_if_update (ifp, ZEBRA_VXLIF_VLAN_CHANGE); } /* @@ -206,7 +215,7 @@ zebra_l2_vxlanif_update_access_vlan (struct interface *ifp, void zebra_l2_vxlanif_del (struct interface *ifp) { - /* No action currently. */ + zebra_vxlan_if_del (ifp); } /* @@ -235,4 +244,8 @@ zebra_l2if_update_bridge_slave (struct interface *ifp, 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); + + /* In the case of VxLAN, invoke the handler for EVPN. */ + if (zif->zif_type == ZEBRA_IF_VXLAN) + zebra_vxlan_if_update (ifp, ZEBRA_VXLIF_MASTER_CHANGE); } diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index 1656892675..32c636e5e7 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -37,6 +37,7 @@ #include "zebra/zebra_static.h" #include "zebra/interface.h" #include "zebra/zebra_mpls.h" +#include "zebra/zebra_vxlan.h" extern struct zebra_t zebrad; @@ -244,6 +245,9 @@ zebra_vrf_delete (struct vrf *vrf) rib_close_table (zvrf->other_table[afi][table_id]); } + /* Cleanup Vxlan table and update kernel */ + zebra_vxlan_close_tables (zvrf); + zebra_mpls_close_tables (zvrf); for (ALL_LIST_ELEMENTS_RO (vrf->iflist, node, ifp)) @@ -421,6 +425,7 @@ zebra_vrf_alloc (void) zvrf->import_check_table[afi] = table; } + zebra_vxlan_init_tables (zvrf); zebra_mpls_init_tables (zvrf); return zvrf; diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h index 790e2e53d2..29f7df00fd 100644 --- a/zebra/zebra_vrf.h +++ b/zebra/zebra_vrf.h @@ -95,6 +95,15 @@ struct zebra_vrf u_int16_t mpls_flags; #define MPLS_FLAG_SCHEDULE_LSPS (1 << 0) + /* + * VNI hash table (for EVPN). Only in default instance. + */ + struct hash *vni_table; + /* + * Whether EVPN is enabled or not. + */ + int advertise_all_vni; + /* Route Installs */ uint64_t installs; uint64_t removals; diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c new file mode 100644 index 0000000000..fcf4328478 --- /dev/null +++ b/zebra/zebra_vxlan.c @@ -0,0 +1,905 @@ +/* + * Zebra EVPN for VxLAN 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 "vlan.h" +#include "vxlan.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_vrf.h" +#include "zebra/rt_netlink.h" +#include "zebra/zebra_vxlan_private.h" +#include "zebra/zebra_vxlan.h" +#include "zebra/zebra_memory.h" +#include "zebra/zebra_l2.h" + +DEFINE_MTYPE_STATIC(ZEBRA, ZVNI, "VNI hash"); +DEFINE_MTYPE_STATIC(ZEBRA, ZVNI_VTEP, "VNI remote VTEP"); + +/* definitions */ + + +/* static function declarations */ +static unsigned int +vni_hash_keymake (void *p); +static int +vni_hash_cmp (const void *p1, const void *p2); +static void * +zvni_alloc (void *p); +static zebra_vni_t * +zvni_lookup (struct zebra_vrf *zvrf, vni_t vni); +static zebra_vni_t * +zvni_add (struct zebra_vrf *zvrf, vni_t vni); +static int +zvni_del (struct zebra_vrf *zvrf, zebra_vni_t *zvni); +static int +zvni_send_add_to_client (struct zebra_vrf *zvrf, zebra_vni_t *zvni); +static int +zvni_send_del_to_client (struct zebra_vrf *zvrf, vni_t vni); +static void +zvni_build_hash_table (struct zebra_vrf *zvrf); +static int +zvni_vtep_match (struct in_addr *vtep_ip, zebra_vtep_t *zvtep); +static zebra_vtep_t * +zvni_vtep_find (zebra_vni_t *zvni, struct in_addr *vtep_ip); +static zebra_vtep_t * +zvni_vtep_add (zebra_vni_t *zvni, struct in_addr *vtep_ip); +static int +zvni_vtep_del (zebra_vni_t *zvni, zebra_vtep_t *zvtep); +static int +zvni_vtep_del_all (zebra_vni_t *zvni, int uninstall); +static int +zvni_vtep_install (zebra_vni_t *zvni, struct in_addr *vtep_ip); +static int +zvni_vtep_uninstall (zebra_vni_t *zvni, struct in_addr *vtep_ip); + + +/* Private functions */ + +/* + * Hash function for VNI. + */ +static unsigned int +vni_hash_keymake (void *p) +{ + const zebra_vni_t *zvni = p; + + return (jhash_1word(zvni->vni, 0)); +} + +/* + * Compare 2 VNI hash entries. + */ +static int +vni_hash_cmp (const void *p1, const void *p2) +{ + const zebra_vni_t *zvni1 = p1; + const zebra_vni_t *zvni2 = p2; + + return (zvni1->vni == zvni2->vni); +} + +/* + * Callback to allocate VNI hash entry. + */ +static void * +zvni_alloc (void *p) +{ + const zebra_vni_t *tmp_vni = p; + zebra_vni_t *zvni; + + zvni = XCALLOC (MTYPE_ZVNI, sizeof(zebra_vni_t)); + zvni->vni = tmp_vni->vni; + return ((void *)zvni); +} + +/* + * Look up VNI hash entry. + */ +static zebra_vni_t * +zvni_lookup (struct zebra_vrf *zvrf, vni_t vni) +{ + zebra_vni_t tmp_vni; + zebra_vni_t *zvni = NULL; + + memset (&tmp_vni, 0, sizeof (zebra_vni_t)); + tmp_vni.vni = vni; + zvni = hash_lookup (zvrf->vni_table, &tmp_vni); + + return zvni; +} + +/* + * Add VNI hash entry. + */ +static zebra_vni_t * +zvni_add (struct zebra_vrf *zvrf, vni_t vni) +{ + zebra_vni_t tmp_zvni; + zebra_vni_t *zvni = NULL; + + memset (&tmp_zvni, 0, sizeof (zebra_vni_t)); + tmp_zvni.vni = vni; + zvni = hash_get (zvrf->vni_table, &tmp_zvni, zvni_alloc); + assert (zvni); + + return zvni; +} + +/* + * Delete VNI hash entry. + */ +static int +zvni_del (struct zebra_vrf *zvrf, zebra_vni_t *zvni) +{ + zebra_vni_t *tmp_zvni; + + zvni->vxlan_if = NULL; + + /* Free the VNI hash entry and allocated memory. */ + tmp_zvni = hash_release (zvrf->vni_table, zvni); + if (tmp_zvni) + XFREE(MTYPE_ZVNI, tmp_zvni); + + return 0; +} + +/* + * Inform BGP about local VNI addition. + */ +static int +zvni_send_add_to_client (struct zebra_vrf *zvrf, + zebra_vni_t *zvni) +{ + struct zserv *client; + struct stream *s; + + client = zebra_find_client (ZEBRA_ROUTE_BGP); + /* BGP may not be running. */ + if (!client) + return 0; + + s = client->obuf; + stream_reset (s); + + zserv_create_header (s, ZEBRA_VNI_ADD, zvrf_id (zvrf)); + stream_putl (s, zvni->vni); + stream_put_in_addr (s, &zvni->local_vtep_ip); + + /* Write packet size. */ + stream_putw_at (s, 0, stream_get_endp (s)); + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug ("%u:Send VNI_ADD %u %s to %s", + zvrf_id (zvrf), zvni->vni, + inet_ntoa(zvni->local_vtep_ip), + zebra_route_string (client->proto)); + + client->vniadd_cnt++; + return zebra_server_send_message(client); +} + +/* + * Inform BGP about local VNI deletion. + */ +static int +zvni_send_del_to_client (struct zebra_vrf *zvrf, vni_t vni) +{ + struct zserv *client; + struct stream *s; + + client = zebra_find_client (ZEBRA_ROUTE_BGP); + /* BGP may not be running. */ + if (!client) + return 0; + + s = client->obuf; + stream_reset (s); + + zserv_create_header (s, ZEBRA_VNI_DEL, zvrf_id (zvrf)); + stream_putl (s, vni); + + /* Write packet size. */ + stream_putw_at (s, 0, stream_get_endp (s)); + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug ("%u:Send VNI_DEL %u to %s", zvrf_id (zvrf), vni, + zebra_route_string (client->proto)); + + client->vnidel_cnt++; + return zebra_server_send_message(client); +} + +/* + * Build the VNI hash table by going over the VxLAN interfaces. This + * is called when EVPN (advertise-all-vni) is enabled. + */ +static void +zvni_build_hash_table (struct zebra_vrf *zvrf) +{ + struct listnode *node; + struct interface *ifp; + + /* Walk VxLAN interfaces and create VNI hash. */ + for (ALL_LIST_ELEMENTS_RO (vrf_iflist (zvrf_id (zvrf)), node, ifp)) + { + struct zebra_if *zif; + struct zebra_l2info_vxlan *vxl; + zebra_vni_t *zvni; + vni_t vni; + + zif = ifp->info; + if (!zif || zif->zif_type != ZEBRA_IF_VXLAN) + continue; + vxl = &zif->l2info.vxl; + + vni = vxl->vni; + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug ("%u:Create VNI hash for intf %s(%u) VNI %u local IP %s", + zvrf_id (zvrf), ifp->name, ifp->ifindex, vni, + inet_ntoa (vxl->vtep_ip)); + + /* VNI hash entry is not expected to exist. */ + zvni = zvni_lookup (zvrf, vni); + if (zvni) + { + zlog_err ("VNI hash already present for VRF %d IF %s(%u) VNI %u", + zvrf_id (zvrf), ifp->name, ifp->ifindex, vni); + continue; + } + + zvni = zvni_add (zvrf, vni); + if (!zvni) + { + zlog_err ("Failed to add VNI hash, VRF %d IF %s(%u) VNI %u", + zvrf_id (zvrf), ifp->name, ifp->ifindex, vni); + return; + } + + zvni->local_vtep_ip = vxl->vtep_ip; + zvni->vxlan_if = ifp; + + /* Inform BGP if interface is up and mapped to bridge. */ + if (if_is_operative (ifp) && + zif->brslave_info.br_if) + zvni_send_add_to_client (zvrf, zvni); + } +} + +/* + * See if remote VTEP matches with prefix. + */ +static int +zvni_vtep_match (struct in_addr *vtep_ip, zebra_vtep_t *zvtep) +{ + return (IPV4_ADDR_SAME (vtep_ip, &zvtep->vtep_ip)); +} + +/* + * Locate remote VTEP in VNI hash table. + */ +static zebra_vtep_t * +zvni_vtep_find (zebra_vni_t *zvni, struct in_addr *vtep_ip) +{ + zebra_vtep_t *zvtep; + + if (!zvni) + return NULL; + + for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) + { + if (zvni_vtep_match (vtep_ip, zvtep)) + break; + } + + return zvtep; +} + +/* + * Add remote VTEP to VNI hash table. + */ +static zebra_vtep_t * +zvni_vtep_add (zebra_vni_t *zvni, struct in_addr *vtep_ip) +{ + zebra_vtep_t *zvtep; + + zvtep = XCALLOC (MTYPE_ZVNI_VTEP, sizeof(zebra_vtep_t)); + if (!zvtep) + { + zlog_err ("Failed to alloc VTEP entry, VNI %u", zvni->vni); + return NULL; + } + + zvtep->vtep_ip = *vtep_ip; + + if (zvni->vteps) + zvni->vteps->prev = zvtep; + zvtep->next = zvni->vteps; + zvni->vteps = zvtep; + + return zvtep; +} + +/* + * Remove remote VTEP from VNI hash table. + */ +static int +zvni_vtep_del (zebra_vni_t *zvni, zebra_vtep_t *zvtep) +{ + if (zvtep->next) + zvtep->next->prev = zvtep->prev; + if (zvtep->prev) + zvtep->prev->next = zvtep->next; + else + zvni->vteps = zvtep->next; + + zvtep->prev = zvtep->next = NULL; + XFREE (MTYPE_ZVNI_VTEP, zvtep); + + return 0; +} + +/* + * Delete all remote VTEPs for this VNI (upon VNI delete). Also + * uninstall from kernel if asked to. + */ +static int +zvni_vtep_del_all (zebra_vni_t *zvni, int uninstall) +{ + zebra_vtep_t *zvtep, *zvtep_next; + + if (!zvni) + return -1; + + for (zvtep = zvni->vteps; zvtep; zvtep = zvtep_next) + { + zvtep_next = zvtep->next; + if (uninstall) + zvni_vtep_uninstall (zvni, &zvtep->vtep_ip); + zvni_vtep_del (zvni, zvtep); + } + + return 0; +} + +/* + * Install remote VTEP into the kernel. + */ +static int +zvni_vtep_install (zebra_vni_t *zvni, struct in_addr *vtep_ip) +{ + return kernel_add_vtep (zvni->vni, zvni->vxlan_if, vtep_ip); +} + +/* + * Uninstall remote VTEP from the kernel. + */ +static int +zvni_vtep_uninstall (zebra_vni_t *zvni, struct in_addr *vtep_ip) +{ + if (!zvni->vxlan_if) + { + zlog_err ("VNI %u hash %p couldn't be uninstalled - no intf", + zvni->vni, zvni); + return -1; + } + + return kernel_del_vtep (zvni->vni, zvni->vxlan_if, vtep_ip); +} + +/* + * Cleanup VNI/VTEP and update kernel + */ +static void +zvni_cleanup_all (struct hash_backet *backet, void *zvrf) +{ + zebra_vni_t *zvni; + + zvni = (zebra_vni_t *) backet->data; + if (!zvni) + return; + + /* Free up all remote VTEPs, if any. */ + zvni_vtep_del_all (zvni, 1); + + /* Delete the hash entry. */ + zvni_del (zvrf, zvni); +} + + +/* Public functions */ + +/* + * Handle message from client to delete a remote VTEP for a VNI. + */ +int zebra_vxlan_remote_vtep_del (struct zserv *client, int sock, + u_short length, struct zebra_vrf *zvrf) +{ + struct stream *s; + u_short l = 0; + vni_t vni; + struct in_addr vtep_ip; + zebra_vni_t *zvni; + zebra_vtep_t *zvtep; + + s = client->ibuf; + + while (l < length) + { + /* Obtain each remote VTEP and process. */ + vni = (vni_t) stream_getl (s); + l += 4; + vtep_ip.s_addr = stream_get_ipv4 (s); + l += IPV4_MAX_BYTELEN; + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug ("%u:Recv VTEP_DEL %s VNI %u from %s", + zvrf_id (zvrf), inet_ntoa (vtep_ip), + vni, zebra_route_string (client->proto)); + + /* Locate VNI hash entry - expected to exist. */ + zvni = zvni_lookup (zvrf, vni); + if (!zvni) + { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug ("Failed to locate VNI hash upon remote VTEP DEL, " + "VRF %d VNI %u", zvrf_id (zvrf), vni); + continue; + } + + /* If the remote VTEP does not exist, there's nothing more to do. + * Otherwise, uninstall any remote MACs pointing to this VTEP and + * then, the VTEP entry itself and remove it. + */ + zvtep = zvni_vtep_find (zvni, &vtep_ip); + if (!zvtep) + continue; + + zvni_vtep_uninstall (zvni, &vtep_ip); + zvni_vtep_del (zvni, zvtep); + } + + return 0; +} + +/* + * Handle message from client to add a remote VTEP for a VNI. + */ +int zebra_vxlan_remote_vtep_add (struct zserv *client, int sock, + u_short length, struct zebra_vrf *zvrf) +{ + struct stream *s; + u_short l = 0; + vni_t vni; + struct in_addr vtep_ip; + zebra_vni_t *zvni; + + assert (EVPN_ENABLED (zvrf)); + + s = client->ibuf; + + while (l < length) + { + /* Obtain each remote VTEP and process. */ + vni = (vni_t) stream_getl (s); + l += 4; + vtep_ip.s_addr = stream_get_ipv4 (s); + l += IPV4_MAX_BYTELEN; + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug ("%u:Recv VTEP_ADD %s VNI %u from %s", + zvrf_id (zvrf), inet_ntoa (vtep_ip), + vni, zebra_route_string (client->proto)); + + /* Locate VNI hash entry - expected to exist. */ + zvni = zvni_lookup (zvrf, vni); + if (!zvni) + { + zlog_err ("Failed to locate VNI hash upon remote VTEP ADD, VRF %d VNI %u", + zvrf_id (zvrf), vni); + continue; + } + if (!zvni->vxlan_if) + { + zlog_err ("VNI %u hash %p doesn't have intf upon remote VTEP ADD", + zvni->vni, zvni); + continue; + } + + + /* If the remote VTEP already exists, or the local VxLAN interface is + * not up (should be a transient event), there's nothing more to do. + * Otherwise, add and install the entry. + */ + if (zvni_vtep_find (zvni, &vtep_ip)) + continue; + + if (!if_is_operative (zvni->vxlan_if)) + continue; + + if (zvni_vtep_add (zvni, &vtep_ip) == NULL) + { + zlog_err ("Failed to add remote VTEP, VRF %d VNI %u zvni %p", + zvrf_id (zvrf), vni, zvni); + continue; + } + + zvni_vtep_install (zvni, &vtep_ip); + } + + return 0; +} + +/* + * Handle VxLAN interface down - update BGP if required, and do + * internal cleanup. + */ +int +zebra_vxlan_if_down (struct interface *ifp) +{ + struct zebra_if *zif; + struct zebra_vrf *zvrf; + zebra_vni_t *zvni; + struct zebra_l2info_vxlan *vxl; + vni_t vni; + + /* Locate VRF corresponding to interface. */ + zvrf = vrf_info_lookup(ifp->vrf_id); + assert(zvrf); + + /* If EVPN is not enabled, nothing further to be done. */ + if (!EVPN_ENABLED(zvrf)) + return 0; + + zif = ifp->info; + assert(zif); + vxl = &zif->l2info.vxl; + vni = vxl->vni; + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug ("%u:Intf %s(%u) VNI %u is DOWN", + ifp->vrf_id, ifp->name, ifp->ifindex, vni); + + /* Locate hash entry; it is expected to exist. */ + zvni = zvni_lookup (zvrf, vni); + if (!zvni) + { + zlog_err ("Failed to locate VNI hash at DOWN, VRF %d IF %s(%u) VNI %u", + ifp->vrf_id, ifp->name, ifp->ifindex, vni); + return -1; + } + + assert (zvni->vxlan_if == ifp); + + /* Delete this VNI from BGP. */ + zvni_send_del_to_client (zvrf, zvni->vni); + + /* Free up all remote VTEPs, if any. */ + zvni_vtep_del_all (zvni, 1); + + return 0; +} + +/* + * Handle VxLAN interface up - update BGP if required. + */ +int +zebra_vxlan_if_up (struct interface *ifp) +{ + struct zebra_if *zif; + struct zebra_vrf *zvrf; + zebra_vni_t *zvni; + struct zebra_l2info_vxlan *vxl; + vni_t vni; + + /* Locate VRF corresponding to interface. */ + zvrf = vrf_info_lookup(ifp->vrf_id); + assert(zvrf); + + /* If EVPN is not enabled, nothing further to be done. */ + if (!EVPN_ENABLED(zvrf)) + return 0; + + zif = ifp->info; + assert(zif); + vxl = &zif->l2info.vxl; + vni = vxl->vni; + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug ("%u:Intf %s(%u) VNI %u is UP", + ifp->vrf_id, ifp->name, ifp->ifindex, vni); + + /* Locate hash entry; it is expected to exist. */ + zvni = zvni_lookup (zvrf, vni); + if (!zvni) + { + zlog_err ("Failed to locate VNI hash at UP, VRF %d IF %s(%u) VNI %u", + ifp->vrf_id, ifp->name, ifp->ifindex, vni); + return -1; + } + + assert (zvni->vxlan_if == ifp); + + /* If part of a bridge, inform BGP about this VNI. */ + if (zif->brslave_info.br_if) + zvni_send_add_to_client (zvrf, zvni); + + return 0; +} + +/* + * Handle VxLAN interface delete. Locate and remove entry in hash table + * and update BGP, if required. + */ +int +zebra_vxlan_if_del (struct interface *ifp) +{ + struct zebra_if *zif; + struct zebra_vrf *zvrf; + zebra_vni_t *zvni; + struct zebra_l2info_vxlan *vxl; + vni_t vni; + + /* Locate VRF corresponding to interface. */ + zvrf = vrf_info_lookup(ifp->vrf_id); + assert(zvrf); + + /* If EVPN is not enabled, nothing further to be done. */ + if (!EVPN_ENABLED(zvrf)) + return 0; + + zif = ifp->info; + assert(zif); + vxl = &zif->l2info.vxl; + vni = vxl->vni; + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug ("%u:Del intf %s(%u) VNI %u", + ifp->vrf_id, ifp->name, ifp->ifindex, vni); + + /* Locate hash entry; it is expected to exist. */ + zvni = zvni_lookup (zvrf, vni); + if (!zvni) + { + zlog_err ("Failed to locate VNI hash at del, VRF %d IF %s(%u) VNI %u", + ifp->vrf_id, ifp->name, ifp->ifindex, vni); + return 0; + } + + /* Delete VNI from BGP. */ + zvni_send_del_to_client (zvrf, zvni->vni); + + /* Free up all remote VTEPs, if any. */ + zvni_vtep_del_all (zvni, 0); + + /* Delete the hash entry. */ + if (zvni_del (zvrf, zvni)) + { + zlog_err ("Failed to del VNI hash %p, VRF %d IF %s(%u) VNI %u", + zvni, ifp->vrf_id, ifp->name, ifp->ifindex, zvni->vni); + return -1; + } + + return 0; +} + +/* + * Handle VxLAN interface update - change to tunnel IP, master or VLAN. + */ +int +zebra_vxlan_if_update (struct interface *ifp, u_int16_t chgflags) +{ + struct zebra_if *zif; + struct zebra_vrf *zvrf; + zebra_vni_t *zvni; + struct zebra_l2info_vxlan *vxl; + vni_t vni; + + /* Locate VRF corresponding to interface. */ + zvrf = vrf_info_lookup(ifp->vrf_id); + assert(zvrf); + + /* If EVPN is not enabled, nothing further to be done. */ + if (!EVPN_ENABLED(zvrf)) + return 0; + + zif = ifp->info; + assert(zif); + vxl = &zif->l2info.vxl; + vni = vxl->vni; + + /* Update VNI hash. */ + zvni = zvni_lookup (zvrf, vni); + if (!zvni) + { + zlog_err ("Failed to find VNI hash on update, VRF %d IF %s(%u) VNI %u", + ifp->vrf_id, ifp->name, ifp->ifindex, vni); + return -1; + } + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug ("%u:Update intf %s(%u) VNI %u VLAN %u local IP %s " + "master %u chg 0x%x", + ifp->vrf_id, ifp->name, ifp->ifindex, + vni, vxl->access_vlan, + inet_ntoa (vxl->vtep_ip), + zif->brslave_info.bridge_ifindex, chgflags); + + /* Removed from bridge? */ + if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE) && + (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) + { + /* Delete from client, remove all remote VTEPs */ + zvni_send_del_to_client (zvrf, zvni->vni); + zvni_vtep_del_all (zvni, 1); + } + + zvni->local_vtep_ip = vxl->vtep_ip; + zvni->vxlan_if = ifp; + + /* Take further actions needed. Note that if we are here, there is a + * change of interest. + */ + /* If down or not mapped to a bridge, we're done. */ + if (!if_is_operative (ifp) || !zif->brslave_info.br_if) + return 0; + + /* Inform BGP. */ + zvni_send_add_to_client (zvrf, zvni); + + return 0; +} + +/* + * Handle VxLAN interface add. + */ +int +zebra_vxlan_if_add (struct interface *ifp) +{ + struct zebra_if *zif; + struct zebra_vrf *zvrf; + zebra_vni_t *zvni; + struct zebra_l2info_vxlan *vxl; + vni_t vni; + + /* Locate VRF corresponding to interface. */ + zvrf = vrf_info_lookup(ifp->vrf_id); + assert(zvrf); + + /* If EVPN is not enabled, nothing further to be done. */ + if (!EVPN_ENABLED(zvrf)) + return 0; + + zif = ifp->info; + assert(zif); + vxl = &zif->l2info.vxl; + vni = vxl->vni; + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug ("%u:Add intf %s(%u) VNI %u VLAN %u local IP %s master %u", + ifp->vrf_id, ifp->name, ifp->ifindex, + vni, vxl->access_vlan, + inet_ntoa (vxl->vtep_ip), + zif->brslave_info.bridge_ifindex); + + /* Create or update VNI hash. */ + zvni = zvni_lookup (zvrf, vni); + if (!zvni) + { + zvni = zvni_add (zvrf, vni); + if (!zvni) + { + zlog_err ("Failed to add VNI hash, VRF %d IF %s(%u) VNI %u", + ifp->vrf_id, ifp->name, ifp->ifindex, vni); + return -1; + } + } + + zvni->local_vtep_ip = vxl->vtep_ip; + zvni->vxlan_if = ifp; + + /* If down or not mapped to a bridge, we're done. */ + if (!if_is_operative (ifp) || !zif->brslave_info.br_if) + return 0; + + /* Inform BGP */ + zvni_send_add_to_client (zvrf, zvni); + + return 0; +} + +/* + * Handle message from client to learn (or stop learning) about VNIs and MACs. + * When enabled, the VNI hash table will be built and MAC FDB table read; + * when disabled, the entries should be deleted and remote VTEPs and MACs + * uninstalled from the kernel. + */ +int zebra_vxlan_advertise_all_vni (struct zserv *client, int sock, + u_short length, struct zebra_vrf *zvrf) +{ + struct stream *s; + int advertise; + + s = client->ibuf; + advertise = stream_getc (s); + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug ("%u:EVPN VNI Adv %s, currently %s", + zvrf_id (zvrf), advertise ? "enabled" : "disabled", + EVPN_ENABLED(zvrf) ? "enabled" : "disabled"); + + if (zvrf->advertise_all_vni == advertise) + return 0; + + zvrf->advertise_all_vni = advertise; + if (EVPN_ENABLED(zvrf)) + { + /* Build VNI hash table and inform BGP. */ + zvni_build_hash_table (zvrf); + } + else + { + /* Cleanup VTEPs for all VNIs - uninstall from + * kernel and free entries. + */ + hash_iterate (zvrf->vni_table, zvni_cleanup_all, zvrf); + } + + return 0; +} + +/* + * Allocate VNI hash table for this VRF and do other initialization. + * NOTE: Currently supported only for default VRF. + */ +void +zebra_vxlan_init_tables (struct zebra_vrf *zvrf) +{ + if (!zvrf) + return; + zvrf->vni_table = hash_create(vni_hash_keymake, + vni_hash_cmp, + "Zebra VRF VNI Table"); +} + +/* Close all VNI handling */ +void +zebra_vxlan_close_tables (struct zebra_vrf *zvrf) +{ + hash_iterate (zvrf->vni_table, zvni_cleanup_all, zvrf); +} diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h new file mode 100644 index 0000000000..0e8d783a3c --- /dev/null +++ b/zebra/zebra_vxlan.h @@ -0,0 +1,59 @@ +/* + * Zebra VxLAN (EVPN) Data structures and definitions + * These are public definitions referenced by other files. + * 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_VXLAN_H +#define _ZEBRA_VXLAN_H + +#include + +#include "linklist.h" +#include "if.h" +#include "vlan.h" +#include "vxlan.h" + +#include "zebra/interface.h" +#include "zebra/zebra_vrf.h" + +/* Is EVPN enabled? */ +#define EVPN_ENABLED(zvrf) (zvrf)->advertise_all_vni + +/* VxLAN interface change flags of interest. */ +#define ZEBRA_VXLIF_LOCAL_IP_CHANGE 0x1 +#define ZEBRA_VXLIF_MASTER_CHANGE 0x2 +#define ZEBRA_VXLIF_VLAN_CHANGE 0x4 + +extern int zebra_vxlan_if_up (struct interface *ifp); +extern int zebra_vxlan_if_down (struct interface *ifp); +extern int zebra_vxlan_if_add (struct interface *ifp); +extern int zebra_vxlan_if_update (struct interface *ifp, u_int16_t chgflags); +extern int zebra_vxlan_if_del (struct interface *ifp); +extern int zebra_vxlan_remote_vtep_add (struct zserv *client, int sock, + u_short length, struct zebra_vrf *zvrf); +extern int zebra_vxlan_remote_vtep_del (struct zserv *client, int sock, + u_short length, struct zebra_vrf *zvrf); +extern int zebra_vxlan_advertise_all_vni (struct zserv *client, int sock, + u_short length, struct zebra_vrf *zvrf); +extern void zebra_vxlan_init_tables (struct zebra_vrf *zvrf); +extern void zebra_vxlan_close_tables (struct zebra_vrf *); + +#endif /* _ZEBRA_VXLAN_H */ diff --git a/zebra/zebra_vxlan_null.c b/zebra/zebra_vxlan_null.c new file mode 100644 index 0000000000..532ab64290 --- /dev/null +++ b/zebra/zebra_vxlan_null.c @@ -0,0 +1,89 @@ +/* + * Zebra VxLAN (EVPN) + * 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" +#include "zebra/zebra_vxlan.h" + +int +zebra_vxlan_if_up (struct interface *ifp) +{ + return 0; +} + +int +zebra_vxlan_if_down (struct interface *ifp) +{ + return 0; +} + +int +zebra_vxlan_if_add (struct interface *ifp) +{ + return 0; +} + +int +zebra_vxlan_if_update (struct interface *ifp, u_int16_t chgflags) +{ + return 0; +} + +int +zebra_vxlan_if_del (struct interface *ifp) +{ + return 0; +} + +int zebra_vxlan_remote_vtep_add (struct zserv *client, int sock, + u_short length, struct zebra_vrf *zvrf) +{ + return 0; +} + +int zebra_vxlan_remote_vtep_del (struct zserv *client, int sock, + u_short length, struct zebra_vrf *zvrf) +{ + return 0; +} + +int zebra_vxlan_advertise_all_vni (struct zserv *client, int sock, + u_short length, struct zebra_vrf *zvrf) +{ + return 0; +} + +void +zebra_vxlan_init_tables (struct zebra_vrf *zvrf) +{ +} + +void +zebra_vxlan_close_tables (struct zebra_vrf *zvrf) +{ +} diff --git a/zebra/zserv.c b/zebra/zserv.c index 3da94459f7..c6a9c38c35 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -54,6 +54,7 @@ #include "zebra/zebra_mpls.h" #include "zebra/zebra_mroute.h" #include "zebra/label_manager.h" +#include "zebra/zebra_vxlan.h" /* Event list of zebra. */ enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE }; @@ -2434,6 +2435,15 @@ zebra_client_read (struct thread *thread) case ZEBRA_FEC_UNREGISTER: zserv_fec_unregister (client, sock, length); break; + case ZEBRA_ADVERTISE_ALL_VNI: + zebra_vxlan_advertise_all_vni (client, sock, length, zvrf); + break; + case ZEBRA_REMOTE_VTEP_ADD: + zebra_vxlan_remote_vtep_add (client, sock, length, zvrf); + break; + case ZEBRA_REMOTE_VTEP_DEL: + zebra_vxlan_remote_vtep_del (client, sock, length, zvrf); + break; default: zlog_info ("Zebra received unknown command %d", command); break; @@ -2725,7 +2735,8 @@ zebra_show_client_detail (struct vty *vty, struct zserv *client) client->bfd_peer_upd8_cnt, client->bfd_peer_del_cnt); vty_outln (vty, "Interface Up Notifications: %d",client->ifup_cnt); vty_outln (vty, "Interface Down Notifications: %d",client->ifdown_cnt); - + vty_outln (vty, "VNI add notifications: %d", client->vniadd_cnt); + vty_outln (vty, "VNI delete notifications: %d", client->vnidel_cnt); vty_out (vty, VTYNL); return; } diff --git a/zebra/zserv.h b/zebra/zserv.h index dcc98d83f7..c8f006d44b 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -105,6 +105,8 @@ struct zserv u_int32_t vrfdel_cnt; u_int32_t if_vrfchg_cnt; u_int32_t bfd_client_reg_cnt; + u_int32_t vniadd_cnt; + u_int32_t vnidel_cnt; time_t connect_time; time_t last_read_time; From 4122e2528618539c0620e1e3a3090654b8752ba0 Mon Sep 17 00:00:00 2001 From: vivek Date: Sun, 14 May 2017 22:41:04 -0700 Subject: [PATCH 04/31] zebra: MAC and Neighbor hash table definition Define the MAC and Neighbor (ARP/ND) data structures. These are maintained as hash tables against the VNI. Also, define context structures used for performing various operations on these two tables. Signed-off-by: Vivek Venkatraman Reviewed-by: Donald Sharp --- zebra/zebra_vxlan_private.h | 122 ++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h index c33eba54e8..6d72edcb03 100644 --- a/zebra/zebra_vxlan_private.h +++ b/zebra/zebra_vxlan_private.h @@ -34,6 +34,8 @@ /* definitions */ typedef struct zebra_vni_t_ zebra_vni_t; typedef struct zebra_vtep_t_ zebra_vtep_t; +typedef struct zebra_mac_t_ zebra_mac_t; +typedef struct zebra_neigh_t_ zebra_neigh_t; /* * VTEP info @@ -71,6 +73,126 @@ struct zebra_vni_t_ /* Local IP */ struct in_addr local_vtep_ip; + + /* List of local or remote MAC */ + struct hash *mac_table; + + /* List of local or remote neighbors (MAC+IP) */ + struct hash *neigh_table; +}; + +/* + * MAC hash table. + * + * This table contains the MAC addresses pertaining to this VNI. + * This includes local MACs learnt on an attached VLAN that maps + * to this VNI as well as remote MACs learnt and installed by BGP. + * Local MACs will be known either on a VLAN sub-interface or + * on (port, VLAN); however, it is sufficient for zebra to maintain + * against the VNI i.e., it does not need to retain the local "port" + * information. The correct VNI will be obtained as zebra maintains + * the mapping (of VLAN to VNI). + */ +struct zebra_mac_t_ +{ + /* MAC address. */ + struct ethaddr macaddr; + + u_int32_t flags; +#define ZEBRA_MAC_LOCAL 0x01 +#define ZEBRA_MAC_REMOTE 0x02 +#define ZEBRA_MAC_AUTO 0x04 /* Auto created for neighbor. */ + + /* Local or remote info. */ + union + { + struct + { + ifindex_t ifindex; + vlanid_t vid; + } local; + + struct in_addr r_vtep_ip; + } fwd_info; + + u_int32_t neigh_refcnt; +}; + +/* + * Context for MAC hash walk - used by callbacks. + */ +struct mac_walk_ctx +{ + zebra_vni_t *zvni; /* VNI hash */ + struct zebra_vrf *zvrf; /* VRF - for client notification. */ + int uninstall; /* uninstall from kernel? */ + int upd_client; /* uninstall from client? */ + + u_int32_t flags; +#define DEL_LOCAL_MAC 0x1 +#define DEL_REMOTE_MAC 0x2 +#define DEL_ALL_MAC (DEL_LOCAL_MAC | DEL_REMOTE_MAC) +#define DEL_REMOTE_MAC_FROM_VTEP 0x4 +#define SHOW_REMOTE_MAC_FROM_VTEP 0x8 + + struct in_addr r_vtep_ip; /* To walk MACs from specific VTEP */ + + struct vty *vty; /* Used by VTY handlers */ + u_int32_t count; /* Used by VTY handlers */ +}; + +/* + * Neighbor hash table. + * + * This table contains the neighbors (IP to MAC bindings) pertaining to + * this VNI. This includes local neighbors learnt on the attached VLAN + * device that maps to this VNI as well as remote neighbors learnt and + * installed by BGP. + * Local neighbors will be known against the VLAN device (SVI); however, + * it is sufficient for zebra to maintain against the VNI. The correct + * VNI will be obtained as zebra maintains the mapping (of VLAN to VNI). + */ +struct zebra_neigh_t_ +{ + /* IP address. */ + struct ipaddr ip; + + /* MAC address. */ + struct ethaddr emac; + + /* Underlying interface. */ + ifindex_t ifindex; + + u_int32_t flags; +#define ZEBRA_NEIGH_LOCAL 0x01 +#define ZEBRA_NEIGH_REMOTE 0x02 + + /* Remote VTEP IP - applicable only for remote neighbors. */ + struct in_addr r_vtep_ip; +}; + +/* + * Context for neighbor hash walk - used by callbacks. + */ +struct neigh_walk_ctx +{ + zebra_vni_t *zvni; /* VNI hash */ + struct zebra_vrf *zvrf; /* VRF - for client notification. */ + int uninstall; /* uninstall from kernel? */ + int upd_client; /* uninstall from client? */ + + u_int32_t flags; +#define DEL_LOCAL_NEIGH 0x1 +#define DEL_REMOTE_NEIGH 0x2 +#define DEL_ALL_NEIGH (DEL_LOCAL_NEIGH | DEL_REMOTE_NEIGH) +#define DEL_REMOTE_NEIGH_FROM_VTEP 0x4 +#define SHOW_REMOTE_NEIGH_FROM_VTEP 0x8 + + struct in_addr r_vtep_ip; /* To walk neighbors from specific VTEP */ + + struct vty *vty; /* Used by VTY handlers */ + u_int32_t count; /* Used by VTY handlers */ + u_char addr_width; /* Used by VTY handlers */ }; #endif /* _ZEBRA_VXLAN_PRIVATE_H */ From 2232a77c2bb35586fbdc8156e9c0781fc7020066 Mon Sep 17 00:00:00 2001 From: vivek Date: Sun, 14 May 2017 22:44:13 -0700 Subject: [PATCH 05/31] zebra: MAC and Neighbor (ARP/ND) handling Implement handling of MACs and Neighbors (ARP/ND entries) in zebra: - MAC and Neighbor database handlers - Read MACs and Neighbors from the kernel, when needed and create entries in zebra's MAC and Neighbor databases. - Handle add/update/delete notifications from the kernel for MACs and Neighbors and update zebra's database appropriately - Inform locally learnt MACs and Neighbors to client - Handle MACIP add/delete from client and install appriporiate entries into the kernel - Since Neighbor entries will be installed on an SVI, implement the needed mappings NOTE: kernel interface is only implemented for Linux/netlink Signed-off-by: Vivek Venkatraman Reviewed-by: Donald Sharp --- lib/log.c | 4 + lib/zclient.h | 4 + zebra/interface.c | 33 + zebra/kernel_netlink.c | 28 +- zebra/rt.h | 10 + zebra/rt_netlink.c | 645 ++++++++++++++ zebra/rt_netlink.h | 9 + zebra/rt_socket.c | 25 + zebra/rtread_getmsg.c | 20 + zebra/rtread_netlink.c | 21 + zebra/rtread_sysctl.c | 20 + zebra/zebra_vxlan.c | 1815 +++++++++++++++++++++++++++++++++++++- zebra/zebra_vxlan.h | 27 + zebra/zebra_vxlan_null.c | 50 ++ zebra/zserv.c | 9 + zebra/zserv.h | 7 + 16 files changed, 2706 insertions(+), 21 deletions(-) diff --git a/lib/log.c b/lib/log.c index 7a7545201d..0628b163bf 100644 --- a/lib/log.c +++ b/lib/log.c @@ -951,6 +951,10 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY (ZEBRA_VNI_DEL), DESC_ENTRY (ZEBRA_REMOTE_VTEP_ADD), DESC_ENTRY (ZEBRA_REMOTE_VTEP_DEL), + DESC_ENTRY (ZEBRA_MACIP_ADD), + DESC_ENTRY (ZEBRA_MACIP_DEL), + DESC_ENTRY (ZEBRA_REMOTE_MACIP_ADD), + DESC_ENTRY (ZEBRA_REMOTE_MACIP_DEL), }; #undef DESC_ENTRY diff --git a/lib/zclient.h b/lib/zclient.h index 0c9f70751c..2191be2c2f 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -101,6 +101,10 @@ typedef enum { ZEBRA_VNI_DEL, ZEBRA_REMOTE_VTEP_ADD, ZEBRA_REMOTE_VTEP_DEL, + ZEBRA_MACIP_ADD, + ZEBRA_MACIP_DEL, + ZEBRA_REMOTE_MACIP_ADD, + ZEBRA_REMOTE_MACIP_DEL, } zebra_message_types_t; struct redist_proto diff --git a/zebra/interface.c b/zebra/interface.c index 87b0896f9f..f4ed93f7b8 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -847,6 +847,7 @@ void if_up (struct interface *ifp) { struct zebra_if *zif; + struct interface *link_if; zif = ifp->info; zif->up_count++; @@ -882,8 +883,23 @@ if_up (struct interface *ifp) zebra_vrf_static_route_interface_fixup (ifp); + /* Handle interface up for specific types for EVPN. Non-VxLAN interfaces + * are checked to see if (remote) neighbor entries need to be installed + * on them for ARP suppression. + */ if (IS_ZEBRA_IF_VXLAN (ifp)) zebra_vxlan_if_up (ifp); + else if (IS_ZEBRA_IF_BRIDGE (ifp)) + { + link_if = ifp; + zebra_vxlan_svi_up (ifp, link_if); + } + else if (IS_ZEBRA_IF_VLAN (ifp)) + { + link_if = zif->link; + if (link_if) + zebra_vxlan_svi_up (ifp, link_if); + } } /* Interface goes down. We have to manage different behavior of based @@ -892,13 +908,30 @@ void if_down (struct interface *ifp) { struct zebra_if *zif; + struct interface *link_if; zif = ifp->info; zif->down_count++; quagga_timestamp (2, zif->down_last, sizeof (zif->down_last)); + /* Handle interface down for specific types for EVPN. Non-VxLAN interfaces + * are checked to see if (remote) neighbor entries need to be purged + * for ARP suppression. + */ if (IS_ZEBRA_IF_VXLAN (ifp)) zebra_vxlan_if_down (ifp); + else if (IS_ZEBRA_IF_BRIDGE (ifp)) + { + link_if = ifp; + zebra_vxlan_svi_down (ifp, link_if); + } + else if (IS_ZEBRA_IF_VLAN (ifp)) + { + link_if = zif->link; + if (link_if) + zebra_vxlan_svi_down (ifp, link_if); + } + /* Notify to the protocol daemons. */ zebra_interface_down_update (ifp); diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 3570676a4a..91d4946b5f 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -269,6 +269,12 @@ netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h, case RTM_DELADDR: return netlink_interface_addr (snl, h, ns_id, startup); break; + case RTM_NEWNEIGH: + return netlink_neigh_change (snl, h, ns_id); + break; + case RTM_DELNEIGH: + return netlink_neigh_change (snl, h, ns_id); + break; default: zlog_warn ("Unknown netlink nlmsg_type %d vrf %u\n", h->nlmsg_type, ns_id); @@ -297,17 +303,21 @@ static void netlink_install_filter (int sock, __u32 pid) struct sock_filter filter[] = { /* 0: ldh [4] */ BPF_STMT(BPF_LD|BPF_ABS|BPF_H, offsetof(struct nlmsghdr, nlmsg_type)), - /* 1: jeq 0x18 jt 3 jf 6 */ - BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 1, 0), - /* 2: jeq 0x19 jt 3 jf 6 */ - BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_DELROUTE), 0, 3), - /* 3: ldw [12] */ + /* 1: jeq 0x18 jt 5 jf next */ + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 3, 0), + /* 2: jeq 0x19 jt 5 jf next */ + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_DELROUTE), 2, 0), + /* 3: jeq 0x19 jt 5 jf next */ + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWNEIGH), 1, 0), + /* 4: jeq 0x19 jt 5 jf 8 */ + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_DELNEIGH), 0, 3), + /* 5: ldw [12] */ BPF_STMT(BPF_LD|BPF_ABS|BPF_W, offsetof(struct nlmsghdr, nlmsg_pid)), - /* 4: jeq XX jt 5 jf 6 */ + /* 6: jeq XX jt 7 jf 8 */ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htonl(pid), 0, 1), - /* 5: ret 0 (skip) */ + /* 7: ret 0 (skip) */ BPF_STMT(BPF_RET|BPF_K, 0), - /* 6: ret 0xffff (keep) */ + /* 8: ret 0xffff (keep) */ BPF_STMT(BPF_RET|BPF_K, 0xffff), }; @@ -786,7 +796,7 @@ kernel_init (struct zebra_ns *zns) /* Initialize netlink sockets */ groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR | - RTMGRP_IPV4_MROUTE; + RTMGRP_IPV4_MROUTE | RTMGRP_NEIGH; snprintf (zns->netlink.name, sizeof (zns->netlink.name), "netlink-listen (NS %u)", zns->ns_id); diff --git a/zebra/rt.h b/zebra/rt.h index 10ca6c95cf..ee85eceeca 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -24,6 +24,7 @@ #include "prefix.h" #include "if.h" +#include "vlan.h" #include "vxlan.h" #include "zebra/rib.h" #include "zebra/zebra_ns.h" @@ -46,4 +47,13 @@ extern int kernel_add_vtep (vni_t vni, struct interface *ifp, struct in_addr *vtep_ip); extern int kernel_del_vtep (vni_t vni, struct interface *ifp, struct in_addr *vtep_ip); +extern int kernel_add_mac (struct interface *ifp, vlanid_t vid, + struct ethaddr *mac, struct in_addr vtep_ip); +extern int kernel_del_mac (struct interface *ifp, vlanid_t vid, + struct ethaddr *mac, struct in_addr vtep_ip, int local); + +extern int kernel_add_neigh (struct interface *ifp, struct ipaddr *ip, + struct ethaddr *mac); +extern int kernel_del_neigh (struct interface *ifp, struct ipaddr *ip); + #endif /* _ZEBRA_RT_H */ diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 7ff03e7c04..4be1e96ce5 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -56,6 +56,7 @@ #include "zebra/kernel_netlink.h" #include "zebra/rt_netlink.h" #include "zebra/zebra_mroute.h" +#include "zebra/zebra_vxlan.h" /* TODO - Temporary definitions, need to refine. */ @@ -94,8 +95,22 @@ #ifndef NDA_MASTER #define NDA_MASTER 9 #endif + +#ifndef NTF_SELF +#define NTF_SELF 0x02 +#endif + +#ifndef NTF_EXT_LEARNED +#define NTF_EXT_LEARNED 0x10 +#endif + +#ifndef NDA_VLAN +#define NDA_VLAN 5 +#endif /* End of temporary definitions */ +static vlanid_t filter_vlan = 0; + struct gw_family_t { u_int16_t filler; @@ -1622,6 +1637,636 @@ kernel_del_vtep (vni_t vni, struct interface *ifp, struct in_addr *vtep_ip) return netlink_vxlan_flood_list_update (ifp, vtep_ip, RTM_DELNEIGH); } +#ifndef NDA_RTA +#define NDA_RTA(r) \ + ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg)))) +#endif + +static int +netlink_macfdb_change (struct sockaddr_nl *snl, struct nlmsghdr *h, int len) +{ + struct ndmsg *ndm; + struct interface *ifp; + struct zebra_if *zif; + struct zebra_vrf *zvrf; + struct rtattr *tb[NDA_MAX + 1]; + struct interface *br_if; + struct ethaddr mac; + vlanid_t vid = 0; + struct prefix vtep_ip; + int vid_present = 0, dst_present = 0; + char buf[ETHER_ADDR_STRLEN]; + char vid_buf[20]; + char dst_buf[30]; + + ndm = NLMSG_DATA (h); + + /* The interface should exist. */ + ifp = if_lookup_by_index_per_ns (zebra_ns_lookup (NS_DEFAULT), ndm->ndm_ifindex); + if (!ifp) + return 0; + + /* Locate VRF corresponding to interface. We only process MAC notifications + * if EVPN is enabled on this VRF. + */ + zvrf = vrf_info_lookup(ifp->vrf_id); + if (!zvrf || !EVPN_ENABLED(zvrf)) + return 0; + if (!ifp->info) + return 0; + + /* The interface should be something we're interested in. */ + if (!IS_ZEBRA_IF_BRIDGE_SLAVE(ifp)) + return 0; + + /* Drop "permanent" entries. */ + if (ndm->ndm_state & NUD_PERMANENT) + return 0; + + zif = (struct zebra_if *)ifp->info; + if ((br_if = zif->brslave_info.br_if) == NULL) + { + zlog_warn ("%s family %s IF %s(%u) brIF %u - no bridge master", + nl_msg_type_to_str (h->nlmsg_type), + nl_family_to_str (ndm->ndm_family), + ifp->name, ndm->ndm_ifindex, + zif->brslave_info.bridge_ifindex); + return 0; + } + + /* Parse attributes and extract fields of interest. */ + memset (tb, 0, sizeof tb); + netlink_parse_rtattr (tb, NDA_MAX, NDA_RTA (ndm), len); + + if (!tb[NDA_LLADDR]) + { + zlog_warn ("%s family %s IF %s(%u) brIF %u - no LLADDR", + nl_msg_type_to_str (h->nlmsg_type), + nl_family_to_str (ndm->ndm_family), + ifp->name, ndm->ndm_ifindex, + zif->brslave_info.bridge_ifindex); + return 0; + } + + if (RTA_PAYLOAD (tb[NDA_LLADDR]) != ETHER_ADDR_LEN) + { + zlog_warn ("%s family %s IF %s(%u) brIF %u - LLADDR is not MAC, len %ld", + nl_msg_type_to_str (h->nlmsg_type), + nl_family_to_str (ndm->ndm_family), + ifp->name, ndm->ndm_ifindex, + zif->brslave_info.bridge_ifindex, + RTA_PAYLOAD (tb[NDA_LLADDR])); + return 0; + } + + memcpy (&mac, RTA_DATA (tb[NDA_LLADDR]), ETHER_ADDR_LEN); + + if ((NDA_VLAN <= NDA_MAX) && tb[NDA_VLAN]) + { + vid_present = 1; + vid = *(u_int16_t *) RTA_DATA(tb[NDA_VLAN]); + sprintf (vid_buf, " VLAN %u", vid); + } + + if (tb[NDA_DST]) + { + /* TODO: Only IPv4 supported now. */ + dst_present = 1; + vtep_ip.family = AF_INET; + vtep_ip.prefixlen = IPV4_MAX_BITLEN; + memcpy (&(vtep_ip.u.prefix4.s_addr), RTA_DATA (tb[NDA_DST]), IPV4_MAX_BYTELEN); + sprintf (dst_buf, " dst %s", inet_ntoa (vtep_ip.u.prefix4)); + } + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug ("Rx %s family %s IF %s(%u)%s MAC %s%s", + nl_msg_type_to_str (h->nlmsg_type), + nl_family_to_str (ndm->ndm_family), + ifp->name, ndm->ndm_ifindex, + vid_present ? vid_buf : "", + prefix_mac2str (&mac, buf, sizeof (buf)), + dst_present ? dst_buf: ""); + + if (filter_vlan && vid != filter_vlan) + return 0; + + /* If add or update, do accordingly if learnt on a "local" interface; if + * the notification is over VxLAN, this has to be related to multi-homing, + * so perform an implicit delete of any local entry (if it exists). + */ + if (h->nlmsg_type == RTM_NEWNEIGH) + { + /* Drop "permanent" entries. */ + if (ndm->ndm_state & NUD_PERMANENT) + return 0; + + if (IS_ZEBRA_IF_VXLAN(ifp)) + return zebra_vxlan_check_del_local_mac (ifp, br_if, &mac, vid); + + return zebra_vxlan_local_mac_add_update (ifp, br_if, &mac, vid); + } + + /* This is a delete notification. + * 1. For a MAC over VxLan, check if it needs to be refreshed(readded) + * 2. For a MAC over "local" interface, delete the mac + * Note: We will get notifications from both bridge driver and VxLAN driver. + * Ignore the notification from VxLan driver as it is also generated + * when mac moves from remote to local. + */ + if (dst_present) + return 0; + + if (IS_ZEBRA_IF_VXLAN(ifp)) + return zebra_vxlan_check_readd_remote_mac (ifp, br_if, &mac, vid); + + return zebra_vxlan_local_mac_del (ifp, br_if, &mac, vid); +} + +static int +netlink_macfdb_table (struct sockaddr_nl *snl, struct nlmsghdr *h, + ns_id_t ns_id, int startup) +{ + int len; + struct ndmsg *ndm; + + if (h->nlmsg_type != RTM_NEWNEIGH) + return 0; + + /* Length validity. */ + len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ndmsg)); + if (len < 0) + return -1; + + /* We are interested only in AF_BRIDGE notifications. */ + ndm = NLMSG_DATA (h); + if (ndm->ndm_family != AF_BRIDGE) + return 0; + + return netlink_macfdb_change (snl, h, len); +} + +/* Request for MAC FDB information from the kernel */ +static int +netlink_request_macs (struct zebra_ns *zns, int family, int type, + ifindex_t master_ifindex) +{ + struct + { + struct nlmsghdr n; + struct ifinfomsg ifm; + char buf[256]; + } req; + + /* Form the request, specifying filter (rtattr) if needed. */ + memset (&req, 0, sizeof (req)); + req.n.nlmsg_type = type; + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.ifm.ifi_family = family; + if (master_ifindex) + addattr32 (&req.n, sizeof(req), IFLA_MASTER, master_ifindex); + + return netlink_request (&zns->netlink_cmd, &req.n); +} + +/* + * MAC forwarding database read using netlink interface. This is invoked + * at startup. + */ +int +netlink_macfdb_read (struct zebra_ns *zns) +{ + int ret; + + /* Get bridge FDB table. */ + ret = netlink_request_macs (zns, AF_BRIDGE, RTM_GETNEIGH, 0); + if (ret < 0) + return ret; + /* We are reading entire table. */ + filter_vlan = 0; + ret = netlink_parse_info (netlink_macfdb_table, &zns->netlink_cmd, zns, 0, 1); + + return ret; +} + +/* + * MAC forwarding database read using netlink interface. This is for a + * specific bridge and matching specific access VLAN (if VLAN-aware bridge). + */ +int +netlink_macfdb_read_for_bridge (struct zebra_ns *zns, struct interface *ifp, + struct interface *br_if) +{ + struct zebra_if *br_zif; + struct zebra_if *zif; + struct zebra_l2info_vxlan *vxl; + int ret = 0; + + + /* Save VLAN we're filtering on, if needed. */ + br_zif = (struct zebra_if *) br_if->info; + zif = (struct zebra_if *) ifp->info; + vxl = &zif->l2info.vxl; + if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif)) + filter_vlan = vxl->access_vlan; + + /* Get bridge FDB table for specific bridge - we do the VLAN filtering. */ + ret = netlink_request_macs (zns, AF_BRIDGE, RTM_GETNEIGH, br_if->ifindex); + if (ret < 0) + return ret; + ret = netlink_parse_info (netlink_macfdb_table, &zns->netlink_cmd, zns, 0, 0); + + /* Reset VLAN filter. */ + filter_vlan = 0; + return ret; +} + +static int +netlink_macfdb_update (struct interface *ifp, vlanid_t vid, + struct ethaddr *mac, + struct in_addr vtep_ip, + int local, int cmd) +{ + struct zebra_ns *zns = zebra_ns_lookup (NS_DEFAULT); + struct + { + struct nlmsghdr n; + struct ndmsg ndm; + char buf[256]; + } req; + int dst_alen; + struct zebra_if *zif; + struct interface *br_if; + struct zebra_if *br_zif; + char buf[ETHER_ADDR_STRLEN]; + int vid_present = 0, dst_present = 0; + char vid_buf[20]; + char dst_buf[30]; + + zif = ifp->info; + if ((br_if = zif->brslave_info.br_if) == NULL) + { + zlog_warn ("MAC %s on IF %s(%u) - no mapping to bridge", + (cmd == RTM_NEWNEIGH) ? "add" : "del", + ifp->name, ifp->ifindex); + return -1; + } + + memset(&req.n, 0, sizeof(req.n)); + memset(&req.ndm, 0, sizeof(req.ndm)); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + if (cmd == RTM_NEWNEIGH) + req.n.nlmsg_flags |= (NLM_F_CREATE | NLM_F_REPLACE); + req.n.nlmsg_type = cmd; + req.ndm.ndm_family = AF_BRIDGE; + req.ndm.ndm_flags |= NTF_SELF | NTF_MASTER; + req.ndm.ndm_state = NUD_REACHABLE; + + req.ndm.ndm_flags |= NTF_EXT_LEARNED; + + addattr_l (&req.n, sizeof (req), NDA_LLADDR, mac, 6); + req.ndm.ndm_ifindex = ifp->ifindex; + if (!local) + { + dst_alen = 4; // TODO: hardcoded + addattr_l (&req.n, sizeof (req), NDA_DST, &vtep_ip, dst_alen); + dst_present = 1; + sprintf (dst_buf, " dst %s", inet_ntoa (vtep_ip)); + } + br_zif = (struct zebra_if *) br_if->info; + if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif) && vid > 0) + { + addattr16 (&req.n, sizeof (req), NDA_VLAN, vid); + vid_present = 1; + sprintf (vid_buf, " VLAN %u", vid); + } + addattr32 (&req.n, sizeof (req), NDA_MASTER, br_if->ifindex); + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug ("Tx %s family %s IF %s(%u)%s MAC %s%s", + nl_msg_type_to_str (cmd), + nl_family_to_str (req.ndm.ndm_family), + ifp->name, ifp->ifindex, + vid_present ? vid_buf : "", + prefix_mac2str (mac, buf, sizeof (buf)), + dst_present ? dst_buf : ""); + + return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0); +} + +#define NUD_VALID (NUD_PERMANENT | NUD_NOARP | NUD_REACHABLE | \ + NUD_PROBE | NUD_STALE | NUD_DELAY) + +static int +netlink_ipneigh_change (struct sockaddr_nl *snl, struct nlmsghdr *h, int len) +{ + struct ndmsg *ndm; + struct interface *ifp; + struct zebra_if *zif; + struct zebra_vrf *zvrf; + struct rtattr *tb[NDA_MAX + 1]; + struct interface *link_if; + struct ethaddr mac; + struct ipaddr ip; + char buf[ETHER_ADDR_STRLEN]; + char buf2[INET6_ADDRSTRLEN]; + int mac_present = 0; + u_char ext_learned; + + ndm = NLMSG_DATA (h); + + /* The interface should exist. */ + ifp = if_lookup_by_index_per_ns (zebra_ns_lookup (NS_DEFAULT), ndm->ndm_ifindex); + if (!ifp) + return 0; + + /* Locate VRF corresponding to interface. We only process neigh notifications + * if EVPN is enabled on this VRF. + */ + zvrf = vrf_info_lookup(ifp->vrf_id); + if (!zvrf || !EVPN_ENABLED(zvrf)) + return 0; + if (!ifp->info) + return 0; + + /* Drop "permanent" entries. */ + if (ndm->ndm_state & NUD_PERMANENT) + return 0; + + zif = (struct zebra_if *)ifp->info; + /* The neighbor is present on an SVI. From this, we locate the underlying + * bridge because we're only interested in neighbors on a VxLAN bridge. + * The bridge is located based on the nature of the SVI: + * (a) In the case of a VLAN-aware bridge, the SVI is a L3 VLAN interface + * and is linked to the bridge + * (b) In the case of a VLAN-unaware bridge, the SVI is the bridge inteface + * itself + */ + if (IS_ZEBRA_IF_VLAN(ifp)) + { + link_if = zif->link; + if (!link_if) + return 0; + } + else if (IS_ZEBRA_IF_BRIDGE(ifp)) + link_if = ifp; + else + return 0; + + /* Parse attributes and extract fields of interest. */ + memset (tb, 0, sizeof tb); + netlink_parse_rtattr (tb, NDA_MAX, NDA_RTA (ndm), len); + + if (!tb[NDA_DST]) + { + zlog_warn ("%s family %s IF %s(%u) - no DST", + nl_msg_type_to_str (h->nlmsg_type), + nl_family_to_str (ndm->ndm_family), + ifp->name, ndm->ndm_ifindex); + return 0; + } + memset (&mac, 0, sizeof (struct ethaddr)); + memset (&ip, 0, sizeof (struct ipaddr)); + ip.ipa_type = (ndm->ndm_family == AF_INET) ? IPADDR_V4 : IPADDR_V6; + memcpy (&ip.ip.addr, RTA_DATA(tb[NDA_DST]), RTA_PAYLOAD(tb[NDA_DST])); + + if (h->nlmsg_type == RTM_NEWNEIGH) + { + if (tb[NDA_LLADDR]) + { + if (RTA_PAYLOAD (tb[NDA_LLADDR]) != ETHER_ADDR_LEN) + { + zlog_warn ("%s family %s IF %s(%u) - LLADDR is not MAC, len %ld", + nl_msg_type_to_str (h->nlmsg_type), + nl_family_to_str (ndm->ndm_family), + ifp->name, ndm->ndm_ifindex, + RTA_PAYLOAD (tb[NDA_LLADDR])); + return 0; + } + + mac_present = 1; + memcpy (&mac, RTA_DATA (tb[NDA_LLADDR]), ETHER_ADDR_LEN); + } + + ext_learned = (ndm->ndm_flags & NTF_EXT_LEARNED) ? 1 : 0; + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug ("Rx %s family %s IF %s(%u) IP %s MAC %s state 0x%x flags 0x%x", + nl_msg_type_to_str (h->nlmsg_type), + nl_family_to_str (ndm->ndm_family), + ifp->name, ndm->ndm_ifindex, + ipaddr2str (&ip, buf2, sizeof(buf2)), + mac_present ? prefix_mac2str (&mac, buf, sizeof (buf)) : "", + ndm->ndm_state, ndm->ndm_flags); + + /* If the neighbor state is valid for use, process as an add or update + * else process as a delete. Note that the delete handling may result + * in re-adding the neighbor if it is a valid "remote" neighbor. + */ + if (ndm->ndm_state & NUD_VALID) + return zebra_vxlan_local_neigh_add_update (ifp, link_if, + &ip, &mac, + ndm->ndm_state, ext_learned); + + return zebra_vxlan_local_neigh_del (ifp, link_if, &ip); + } + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug ("Rx %s family %s IF %s(%u) IP %s", + nl_msg_type_to_str (h->nlmsg_type), + nl_family_to_str (ndm->ndm_family), + ifp->name, ndm->ndm_ifindex, + ipaddr2str (&ip, buf2, sizeof(buf2))); + + /* Process the delete - it may result in re-adding the neighbor if it is + * a valid "remote" neighbor. + */ + return zebra_vxlan_local_neigh_del (ifp, link_if, &ip); +} + +static int +netlink_neigh_table (struct sockaddr_nl *snl, struct nlmsghdr *h, + ns_id_t ns_id, int startup) +{ + int len; + struct ndmsg *ndm; + + if (h->nlmsg_type != RTM_NEWNEIGH) + return 0; + + /* Length validity. */ + len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ndmsg)); + if (len < 0) + return -1; + + /* We are interested only in AF_INET or AF_INET6 notifications. */ + ndm = NLMSG_DATA (h); + if (ndm->ndm_family != AF_INET && ndm->ndm_family != AF_INET6) + return 0; + + return netlink_neigh_change (snl, h, len); +} + +/* Request for IP neighbor information from the kernel */ +static int +netlink_request_neigh (struct zebra_ns *zns, int family, int type, + ifindex_t ifindex) +{ + struct + { + struct nlmsghdr n; + struct ndmsg ndm; + char buf[256]; + } req; + + /* Form the request, specifying filter (rtattr) if needed. */ + memset (&req, 0, sizeof (req)); + req.n.nlmsg_type = type; + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); + req.ndm.ndm_family = family; + if (ifindex) + addattr32 (&req.n, sizeof(req), NDA_IFINDEX, ifindex); + + return netlink_request (&zns->netlink_cmd, &req.n); +} + +/* + * IP Neighbor table read using netlink interface. This is invoked + * at startup. + */ +int +netlink_neigh_read (struct zebra_ns *zns) +{ + int ret; + + /* Get IP neighbor table. */ + ret = netlink_request_neigh (zns, AF_UNSPEC, RTM_GETNEIGH, 0); + if (ret < 0) + return ret; + ret = netlink_parse_info (netlink_neigh_table, &zns->netlink_cmd, zns, 0, 1); + + return ret; +} + +/* + * IP Neighbor table read using netlink interface. This is for a specific + * VLAN device. + */ +int +netlink_neigh_read_for_vlan (struct zebra_ns *zns, struct interface *vlan_if) +{ + int ret = 0; + + ret = netlink_request_neigh (zns, AF_UNSPEC, RTM_GETNEIGH, vlan_if->ifindex); + if (ret < 0) + return ret; + ret = netlink_parse_info (netlink_neigh_table, &zns->netlink_cmd, zns, 0, 0); + + return ret; +} + +int +netlink_neigh_change (struct sockaddr_nl *snl, struct nlmsghdr *h, + ns_id_t ns_id) +{ + int len; + struct ndmsg *ndm; + + if (!(h->nlmsg_type == RTM_NEWNEIGH || h->nlmsg_type == RTM_DELNEIGH)) + return 0; + + /* Length validity. */ + len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ndmsg)); + if (len < 0) + return -1; + + /* Is this a notification for the MAC FDB or IP neighbor table? */ + ndm = NLMSG_DATA (h); + if (ndm->ndm_family == AF_BRIDGE) + return netlink_macfdb_change (snl, h, len); + + if (ndm->ndm_type != RTN_UNICAST) + return 0; + + if (ndm->ndm_family == AF_INET || ndm->ndm_family == AF_INET6) + return netlink_ipneigh_change (snl, h, len); + + return 0; +} + +static int +netlink_neigh_update2 (struct interface *ifp, struct ipaddr *ip, + struct ethaddr *mac, u_int32_t flags, int cmd) +{ + struct { + struct nlmsghdr n; + struct ndmsg ndm; + char buf[256]; + } req; + int ipa_len; + + struct zebra_ns *zns = zebra_ns_lookup (NS_DEFAULT); + char buf[INET6_ADDRSTRLEN]; + char buf2[ETHER_ADDR_STRLEN]; + + memset(&req.n, 0, sizeof(req.n)); + memset(&req.ndm, 0, sizeof(req.ndm)); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + if (cmd == RTM_NEWNEIGH) + req.n.nlmsg_flags |= (NLM_F_CREATE | NLM_F_REPLACE); + req.n.nlmsg_type = cmd; //RTM_NEWNEIGH or RTM_DELNEIGH + req.ndm.ndm_family = IS_IPADDR_V4(ip) ? AF_INET : AF_INET6; + req.ndm.ndm_state = flags; + req.ndm.ndm_ifindex = ifp->ifindex; + req.ndm.ndm_type = RTN_UNICAST; + req.ndm.ndm_flags = NTF_EXT_LEARNED; + + + ipa_len = IS_IPADDR_V4(ip) ? IPV4_MAX_BYTELEN : IPV6_MAX_BYTELEN; + addattr_l(&req.n, sizeof(req), NDA_DST, &ip->ip.addr, ipa_len); + if (mac) + addattr_l (&req.n, sizeof (req), NDA_LLADDR, mac, 6); + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug ("Tx %s family %s IF %s(%u) Neigh %s MAC %s", + nl_msg_type_to_str (cmd), + nl_family_to_str (req.ndm.ndm_family), + ifp->name, ifp->ifindex, + ipaddr2str (ip, buf, sizeof(buf)), + mac ? prefix_mac2str (mac, buf2, sizeof (buf2)) : "null"); + + return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0); +} + +int +kernel_add_mac (struct interface *ifp, vlanid_t vid, + struct ethaddr *mac, struct in_addr vtep_ip) +{ + return netlink_macfdb_update (ifp, vid, mac, vtep_ip, 0, RTM_NEWNEIGH); +} + +int +kernel_del_mac (struct interface *ifp, vlanid_t vid, + struct ethaddr *mac, struct in_addr vtep_ip, int local) +{ + return netlink_macfdb_update (ifp, vid, mac, vtep_ip, local, RTM_DELNEIGH); +} + +int kernel_add_neigh (struct interface *ifp, struct ipaddr *ip, + struct ethaddr *mac) +{ + return netlink_neigh_update2 (ifp, ip, mac, NUD_REACHABLE, + RTM_NEWNEIGH); +} + +int kernel_del_neigh (struct interface *ifp, struct ipaddr *ip) +{ + return netlink_neigh_update2 (ifp, ip, NULL, 0, RTM_DELNEIGH); +} + /* * MPLS label forwarding table change via netlink interface. */ diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h index 9ba86003b8..8b061fc2ed 100644 --- a/zebra/rt_netlink.h +++ b/zebra/rt_netlink.h @@ -51,6 +51,15 @@ extern int netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, ns_id_t ns_id, int startup); extern int netlink_route_read (struct zebra_ns *zns); +extern int netlink_neigh_change (struct sockaddr_nl *snl, struct nlmsghdr *h, + ns_id_t ns_id); +extern int netlink_macfdb_read (struct zebra_ns *zns); +extern int netlink_macfdb_read_for_bridge (struct zebra_ns *zns, + struct interface *ifp, struct interface *br_if); +extern int netlink_neigh_read (struct zebra_ns *zns); +extern int netlink_neigh_read_for_vlan (struct zebra_ns *zns, + struct interface *vlan_if); + #endif /* HAVE_NETLINK */ #endif /* _ZEBRA_RT_NETLINK_H */ diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index bf7e3403e4..c03ed27c63 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -441,3 +441,28 @@ kernel_del_vtep (vni_t vni, struct interface *ifp, struct in_addr *vtep_ip) { return 0; } + +int +kernel_add_mac (struct interface *ifp, vlanid_t vid, + struct ethaddr *mac, struct in_addr vtep_ip) +{ + return 0; +} + +int +kernel_del_mac (struct interface *ifp, vlanid_t vid, + struct ethaddr *mac, struct in_addr vtep_ip, int local) +{ + return 0; +} + +int kernel_add_neigh (struct interface *ifp, struct ipaddr *ip, + struct ethaddr *mac) +{ + return 0; +} + +int kernel_del_neigh (struct interface *ifp, struct ipaddr *ip) +{ + return 0; +} diff --git a/zebra/rtread_getmsg.c b/zebra/rtread_getmsg.c index 1fb2984ddf..b1bef571be 100644 --- a/zebra/rtread_getmsg.c +++ b/zebra/rtread_getmsg.c @@ -237,3 +237,23 @@ route_read (struct zebra_ns *zns) exit: close (dev); } + +/* Only implemented for netlink method */ +void +macfdb_read (struct zebra_ns *zns) +{ +} + +void macfdb_read_for_bridge (struct zebra_ns *zns, struct interface *ifp, + struct interface *br_if) +{ +} + +void +neigh_read (struct zebra_ns *zns) +{ +} + +void neigh_read_for_vlan (struct zebra_ns *zns, struct interface *vlan_if) +{ +} diff --git a/zebra/rtread_netlink.c b/zebra/rtread_netlink.c index d59883445d..d26aa59f87 100644 --- a/zebra/rtread_netlink.c +++ b/zebra/rtread_netlink.c @@ -29,3 +29,24 @@ void route_read (struct zebra_ns *zns) { netlink_route_read (zns); } + +void macfdb_read (struct zebra_ns *zns) +{ + netlink_macfdb_read (zns); +} + +void macfdb_read_for_bridge (struct zebra_ns *zns, struct interface *ifp, + struct interface *br_if) +{ + netlink_macfdb_read_for_bridge (zns, ifp, br_if); +} + +void neigh_read (struct zebra_ns *zns) +{ + netlink_neigh_read (zns); +} + +void neigh_read_for_vlan (struct zebra_ns *zns, struct interface *vlan_if) +{ + netlink_neigh_read_for_vlan (zns, vlan_if); +} diff --git a/zebra/rtread_sysctl.c b/zebra/rtread_sysctl.c index cabb1f7714..30e593d87e 100644 --- a/zebra/rtread_sysctl.c +++ b/zebra/rtread_sysctl.c @@ -83,3 +83,23 @@ route_read (struct zebra_ns *zns) return; } + +/* Only implemented for the netlink method. */ +void +macfdb_read (struct zebra_ns *zns) +{ +} + +void macfdb_read_for_bridge (struct zebra_ns *zns, struct interface *ifp, + struct interface *br_if) +{ +} + +void +neigh_read (struct zebra_ns *zns) +{ +} + +void neigh_read_for_vlan (struct zebra_ns *zns, struct interface *vlan_if) +{ +} diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index fcf4328478..808d7eb07e 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -49,11 +49,89 @@ DEFINE_MTYPE_STATIC(ZEBRA, ZVNI, "VNI hash"); DEFINE_MTYPE_STATIC(ZEBRA, ZVNI_VTEP, "VNI remote VTEP"); +DEFINE_MTYPE_STATIC(ZEBRA, MAC, "VNI MAC"); +DEFINE_MTYPE_STATIC(ZEBRA, NEIGH, "VNI Neighbor"); /* definitions */ /* static function declarations */ +static int +zvni_macip_send_msg_to_client (struct zebra_vrf *zvrf, vni_t vni, + struct ethaddr *macaddr, + struct ipaddr *ip, + u_int16_t cmd); +static unsigned int +neigh_hash_keymake (void *p); +static int +neigh_cmp (const void *p1, const void *p2); +static void * +zvni_neigh_alloc (void *p); +static zebra_neigh_t * +zvni_neigh_add (zebra_vni_t *zvni, struct ipaddr *ip); +static int +zvni_neigh_del (zebra_vni_t *zvni, zebra_neigh_t *n); +static int +zvni_neigh_del_hash_entry (struct hash_backet *backet, void *arg); +static void +zvni_neigh_del_from_vtep (zebra_vni_t *zvni, int uninstall, + struct in_addr *r_vtep_ip); +static void +zvni_neigh_del_all (struct zebra_vrf *zvrf, zebra_vni_t *zvni, + int uninstall, int upd_client, u_int32_t flags); +static zebra_neigh_t * +zvni_neigh_lookup (zebra_vni_t *zvni, struct ipaddr *ip); +static int +zvni_neigh_send_add_to_client (struct zebra_vrf *zvrf, vni_t vni, + struct ipaddr *ip, struct ethaddr *macaddr); +static int +zvni_neigh_send_del_to_client (struct zebra_vrf *zvrf, vni_t vni, + struct ipaddr *ip, struct ethaddr *macaddr); +static int +zvni_neigh_install (zebra_vni_t *zvni, zebra_neigh_t *n); +static int +zvni_neigh_uninstall (zebra_vni_t *zvni, zebra_neigh_t *n); +static zebra_vni_t * +zvni_map_svi (struct interface *ifp, struct interface *br_if); +static struct interface * +zvni_map_to_svi (struct zebra_vrf *zvrf, vlanid_t vid, + struct interface *br_if); + +static unsigned int +mac_hash_keymake (void *p); +static int +mac_cmp (const void *p1, const void *p2); +static void * +zvni_mac_alloc (void *p); +static zebra_mac_t * +zvni_mac_add (zebra_vni_t *zvni, struct ethaddr *macaddr); +static int +zvni_mac_del (zebra_vni_t *zvni, zebra_mac_t *mac); +static int +zvni_mac_del_hash_entry (struct hash_backet *backet, void *arg); +static void +zvni_mac_del_from_vtep (zebra_vni_t *zvni, int uninstall, + struct in_addr *r_vtep_ip); +static void +zvni_mac_del_all (struct zebra_vrf *zvrf, zebra_vni_t *zvni, + int uninstall, int upd_client, u_int32_t flags); +static zebra_mac_t * +zvni_mac_lookup (zebra_vni_t *zvni, struct ethaddr *macaddr); +static int +zvni_mac_send_add_to_client (struct zebra_vrf *zvrf, vni_t vni, + struct ethaddr *macaddr); +static int +zvni_mac_send_del_to_client (struct zebra_vrf *zvrf, vni_t vni, + struct ethaddr *macaddr); +static zebra_vni_t * +zvni_map_vlan (struct interface *ifp, struct interface *br_if, vlanid_t vid); +static int +zvni_mac_install (zebra_vni_t *zvni, zebra_mac_t *mac); +static int +zvni_mac_uninstall (zebra_vni_t *zvni, zebra_mac_t *mac, int local); +static void +zvni_install_mac_hash (struct hash_backet *backet, void *ctxt); + static unsigned int vni_hash_keymake (void *p); static int @@ -90,6 +168,850 @@ zvni_vtep_uninstall (zebra_vni_t *zvni, struct in_addr *vtep_ip); /* Private functions */ +/* + * Inform BGP about local MACIP. + */ +static int +zvni_macip_send_msg_to_client (struct zebra_vrf *zvrf, vni_t vni, + struct ethaddr *macaddr, + struct ipaddr *ip, + u_int16_t cmd) +{ + struct zserv *client; + struct stream *s; + int ipa_len; + char buf[ETHER_ADDR_STRLEN]; + char buf2[INET6_ADDRSTRLEN]; + + client = zebra_find_client (ZEBRA_ROUTE_BGP); + /* BGP may not be running. */ + if (!client) + return 0; + + s = client->obuf; + stream_reset (s); + + zserv_create_header (s, cmd, zvrf_id (zvrf)); + stream_putl (s, vni); + stream_put (s, macaddr->octet, ETHER_ADDR_LEN); + if (ip) + { + ipa_len = 0; + if (IS_IPADDR_V4(ip)) + ipa_len = IPV4_MAX_BYTELEN; + else if (IS_IPADDR_V6(ip)) + ipa_len = IPV6_MAX_BYTELEN; + + stream_putl (s, ipa_len); /* IP address length */ + if (ipa_len) + stream_put (s, &ip->ip.addr, ipa_len); /* IP address */ + } + else + stream_putl (s, 0); /* Just MAC. */ + + /* Write packet size. */ + stream_putw_at (s, 0, stream_get_endp (s)); + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug ("%u:Send MACIP %s MAC %s IP %s VNI %u to %s", + zvrf_id (zvrf), (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del", + prefix_mac2str (macaddr, buf, sizeof (buf)), + ipaddr2str (ip, buf2, sizeof(buf2)), vni, + zebra_route_string (client->proto)); + + if (cmd == ZEBRA_MACIP_ADD) + client->macipadd_cnt++; + else + client->macipdel_cnt++; + + return zebra_server_send_message(client); +} + +/* + * Make hash key for neighbors. + */ +static unsigned int +neigh_hash_keymake (void *p) +{ + zebra_neigh_t *n = p; + struct ipaddr *ip = &n->ip; + + if (IS_IPADDR_V4(ip)) + return jhash_1word (ip->ipaddr_v4.s_addr, 0); + + return jhash2 (ip->ipaddr_v6.s6_addr32, + ZEBRA_NUM_OF(ip->ipaddr_v6.s6_addr32), 0); +} + +/* + * Compare two neighbor hash structures. + */ +static int +neigh_cmp (const void *p1, const void *p2) +{ + const zebra_neigh_t *n1 = p1; + const zebra_neigh_t *n2 = p2; + + if (n1 == NULL && n2 == NULL) + return 1; + + if (n1 == NULL || n2 == NULL) + return 0; + + return (memcmp(&n1->ip, &n2->ip, sizeof (struct ipaddr)) == 0); +} + +/* + * Callback to allocate neighbor hash entry. + */ +static void * +zvni_neigh_alloc (void *p) +{ + const zebra_neigh_t *tmp_n = p; + zebra_neigh_t *n; + + n = XCALLOC (MTYPE_NEIGH, sizeof(zebra_neigh_t)); + *n = *tmp_n; + + return ((void *)n); +} + +/* + * Add neighbor entry. + */ +static zebra_neigh_t * +zvni_neigh_add (zebra_vni_t *zvni, struct ipaddr *ip) +{ + zebra_neigh_t tmp_n; + zebra_neigh_t *n = NULL; + + memset (&tmp_n, 0, sizeof (zebra_neigh_t)); + memcpy (&tmp_n.ip, ip, sizeof (struct ipaddr)); + n = hash_get (zvni->neigh_table, &tmp_n, zvni_neigh_alloc); + assert (n); + + return n; +} + +/* + * Delete neighbor entry. + */ +static int +zvni_neigh_del (zebra_vni_t *zvni, zebra_neigh_t *n) +{ + zebra_neigh_t *tmp_n; + + /* Free the VNI hash entry and allocated memory. */ + tmp_n = hash_release (zvni->neigh_table, n); + if (tmp_n) + XFREE(MTYPE_NEIGH, tmp_n); + + return 0; +} + +/* + * Free neighbor hash entry (callback) + */ +static int +zvni_neigh_del_hash_entry (struct hash_backet *backet, void *arg) +{ + struct neigh_walk_ctx *wctx = arg; + zebra_neigh_t *n = backet->data; + + if (((wctx->flags & DEL_LOCAL_NEIGH) && (n->flags & ZEBRA_NEIGH_LOCAL)) || + ((wctx->flags & DEL_REMOTE_NEIGH) && (n->flags & ZEBRA_NEIGH_REMOTE)) || + ((wctx->flags & DEL_REMOTE_NEIGH_FROM_VTEP) && + (n->flags & ZEBRA_NEIGH_REMOTE) && + IPV4_ADDR_SAME(&n->r_vtep_ip, &wctx->r_vtep_ip) + )) + { + if (wctx->upd_client && (n->flags & ZEBRA_NEIGH_LOCAL)) + zvni_neigh_send_del_to_client (wctx->zvrf, wctx->zvni->vni, &n->ip, + &n->emac); + + if (wctx->uninstall) + zvni_neigh_uninstall (wctx->zvni, n); + + return zvni_neigh_del (wctx->zvni, n); + } + + return 0; +} + +/* + * Delete all neighbor entries from specific VTEP for a particular VNI. + */ +static void +zvni_neigh_del_from_vtep (zebra_vni_t *zvni, int uninstall, + struct in_addr *r_vtep_ip) +{ + struct neigh_walk_ctx wctx; + + if (!zvni->neigh_table) + return; + + memset (&wctx, 0, sizeof (struct neigh_walk_ctx)); + wctx.zvni = zvni; + wctx.uninstall = uninstall; + wctx.flags = DEL_REMOTE_NEIGH_FROM_VTEP; + wctx.r_vtep_ip = *r_vtep_ip; + + hash_iterate (zvni->neigh_table, + (void (*) (struct hash_backet *, void *)) + zvni_neigh_del_hash_entry, &wctx); +} + +/* + * Delete all neighbor entries for this VNI. + */ +static void +zvni_neigh_del_all (struct zebra_vrf *zvrf, zebra_vni_t *zvni, + int uninstall, int upd_client, u_int32_t flags) +{ + struct neigh_walk_ctx wctx; + + if (!zvni->neigh_table) + return; + + memset (&wctx, 0, sizeof (struct neigh_walk_ctx)); + wctx.zvni = zvni; + wctx.zvrf = zvrf; + wctx.uninstall = uninstall; + wctx.upd_client = upd_client; + wctx.flags = flags; + + hash_iterate (zvni->neigh_table, + (void (*) (struct hash_backet *, void *)) + zvni_neigh_del_hash_entry, &wctx); +} + +/* + * Look up neighbor hash entry. + */ +static zebra_neigh_t * +zvni_neigh_lookup (zebra_vni_t *zvni, struct ipaddr *ip) +{ + zebra_neigh_t tmp; + zebra_neigh_t *n; + + memset (&tmp, 0, sizeof(tmp)); + memcpy (&tmp.ip, ip, sizeof (struct ipaddr)); + n = hash_lookup (zvni->neigh_table, &tmp); + + return n; +} + +/* + * Inform BGP about local neighbor addition. + */ +static int +zvni_neigh_send_add_to_client (struct zebra_vrf *zvrf, vni_t vni, + struct ipaddr *ip, struct ethaddr *macaddr) +{ + return zvni_macip_send_msg_to_client (zvrf, vni, macaddr, ip, + ZEBRA_MACIP_ADD); +} + +/* + * Inform BGP about local neighbor deletion. + */ +static int +zvni_neigh_send_del_to_client (struct zebra_vrf *zvrf, vni_t vni, + struct ipaddr *ip, struct ethaddr *macaddr) +{ + return zvni_macip_send_msg_to_client (zvrf, vni, macaddr, ip, + ZEBRA_MACIP_DEL); +} + +/* + * Install remote neighbor into the kernel. + */ +static int +zvni_neigh_install (zebra_vni_t *zvni, zebra_neigh_t *n) +{ + struct zebra_vrf *zvrf; + struct zebra_if *zif; + struct zebra_l2info_vxlan *vxl; + struct interface *vlan_if; + + if (!(n->flags & ZEBRA_NEIGH_REMOTE)) + return 0; + + zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); + assert(zvrf); + zif = zvni->vxlan_if->info; + if (!zif) + return -1; + vxl = &zif->l2info.vxl; + + vlan_if = zvni_map_to_svi (zvrf, vxl->access_vlan, + zif->brslave_info.br_if); + if (!vlan_if) + return -1; + + return kernel_add_neigh (vlan_if, &n->ip, &n->emac); +} + +/* + * Uninstall remote neighbor from the kernel. + */ +static int +zvni_neigh_uninstall (zebra_vni_t *zvni, zebra_neigh_t *n) +{ + struct zebra_vrf *zvrf; + struct zebra_if *zif; + struct zebra_l2info_vxlan *vxl; + struct interface *vlan_if; + + if (!(n->flags & ZEBRA_NEIGH_REMOTE)) + return 0; + + zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); + assert(zvrf); + if (!zvni->vxlan_if) + { + zlog_err ("VNI %u hash %p couldn't be uninstalled - no intf", + zvni->vni, zvni); + return -1; + } + + zif = zvni->vxlan_if->info; + if (!zif) + return -1; + vxl = &zif->l2info.vxl; + vlan_if = zvni_map_to_svi (zvrf, vxl->access_vlan, + zif->brslave_info.br_if); + if (!vlan_if) + return -1; + + return kernel_del_neigh (vlan_if, &n->ip); +} + +/* + * Install neighbor hash entry - called upon access VLAN change. + */ +static void +zvni_install_neigh_hash (struct hash_backet *backet, void *ctxt) +{ + zebra_neigh_t *n; + struct neigh_walk_ctx *wctx = ctxt; + + n = (zebra_neigh_t *) backet->data; + if (!n) + return; + + if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) + zvni_neigh_install (wctx->zvni, n); +} + +/* + * Make hash key for MAC. + */ +static unsigned int +mac_hash_keymake (void *p) +{ + zebra_mac_t *pmac = p; + char *pnt = (char *) pmac->macaddr.octet; + unsigned int key = 0; + int c = 0; + + key += pnt[c]; + key += pnt[c + 1]; + key += pnt[c + 2]; + key += pnt[c + 3]; + key += pnt[c + 4]; + key += pnt[c + 5]; + + return (key); +} + +/* + * Compare two MAC addresses. + */ +static int +mac_cmp (const void *p1, const void *p2) +{ + const zebra_mac_t *pmac1 = p1; + const zebra_mac_t *pmac2 = p2; + + if (pmac1 == NULL && pmac2 == NULL) + return 1; + + if (pmac1 == NULL || pmac2 == NULL) + return 0; + + return(memcmp(pmac1->macaddr.octet, pmac2->macaddr.octet, ETHER_ADDR_LEN) == 0); +} + +/* + * Callback to allocate MAC hash entry. + */ +static void * +zvni_mac_alloc (void *p) +{ + const zebra_mac_t *tmp_mac = p; + zebra_mac_t *mac; + + mac = XCALLOC (MTYPE_MAC, sizeof(zebra_mac_t)); + *mac = *tmp_mac; + + return ((void *)mac); +} + +/* + * Add MAC entry. + */ +static zebra_mac_t * +zvni_mac_add (zebra_vni_t *zvni, struct ethaddr *macaddr) +{ + zebra_mac_t tmp_mac; + zebra_mac_t *mac = NULL; + + memset (&tmp_mac, 0, sizeof (zebra_mac_t)); + memcpy(&tmp_mac.macaddr, macaddr, ETHER_ADDR_LEN); + mac = hash_get (zvni->mac_table, &tmp_mac, zvni_mac_alloc); + assert (mac); + + return mac; +} + +/* + * Delete MAC entry. + */ +static int +zvni_mac_del (zebra_vni_t *zvni, zebra_mac_t *mac) +{ + zebra_mac_t *tmp_mac; + + /* Free the VNI hash entry and allocated memory. */ + tmp_mac = hash_release (zvni->mac_table, mac); + if (tmp_mac) + XFREE(MTYPE_MAC, tmp_mac); + + return 0; +} + +/* + * Free MAC hash entry (callback) + */ +static int +zvni_mac_del_hash_entry (struct hash_backet *backet, void *arg) +{ + struct mac_walk_ctx *wctx = arg; + zebra_mac_t *mac = backet->data; + + if (((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_LOCAL)) || + ((wctx->flags & DEL_REMOTE_MAC) && (mac->flags & ZEBRA_MAC_REMOTE)) || + ((wctx->flags & DEL_REMOTE_MAC_FROM_VTEP) && + (mac->flags & ZEBRA_MAC_REMOTE) && + IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &wctx->r_vtep_ip) + )) + { + if (wctx->upd_client && (mac->flags & ZEBRA_MAC_LOCAL)) + { + zvni_mac_send_del_to_client (wctx->zvrf, wctx->zvni->vni, + &mac->macaddr); + } + + if (wctx->uninstall) + zvni_mac_uninstall (wctx->zvni, mac, 0); + + return zvni_mac_del (wctx->zvni, mac); + } + + return 0; +} + +/* + * Delete all MAC entries from specific VTEP for a particular VNI. + */ +static void +zvni_mac_del_from_vtep (zebra_vni_t *zvni, int uninstall, + struct in_addr *r_vtep_ip) +{ + struct mac_walk_ctx wctx; + + if (!zvni->mac_table) + return; + + memset (&wctx, 0, sizeof (struct mac_walk_ctx)); + wctx.zvni = zvni; + wctx.uninstall = uninstall; + wctx.flags = DEL_REMOTE_MAC_FROM_VTEP; + wctx.r_vtep_ip = *r_vtep_ip; + + hash_iterate (zvni->mac_table, + (void (*) (struct hash_backet *, void *)) + zvni_mac_del_hash_entry, &wctx); +} + +/* + * Delete all MAC entries for this VNI. + */ +static void +zvni_mac_del_all (struct zebra_vrf *zvrf, zebra_vni_t *zvni, + int uninstall, int upd_client, u_int32_t flags) +{ + struct mac_walk_ctx wctx; + + if (!zvni->mac_table) + return; + + memset (&wctx, 0, sizeof (struct mac_walk_ctx)); + wctx.zvni = zvni; + wctx.zvrf = zvrf; + wctx.uninstall = uninstall; + wctx.upd_client = upd_client; + wctx.flags = flags; + + hash_iterate (zvni->mac_table, + (void (*) (struct hash_backet *, void *)) + zvni_mac_del_hash_entry, &wctx); +} + +/* + * Look up MAC hash entry. + */ +static zebra_mac_t * +zvni_mac_lookup (zebra_vni_t *zvni, struct ethaddr *mac) +{ + zebra_mac_t tmp; + zebra_mac_t *pmac; + + memset(&tmp, 0, sizeof(tmp)); + memcpy(&tmp.macaddr, mac, ETHER_ADDR_LEN); + pmac = hash_lookup (zvni->mac_table, &tmp); + + return pmac; +} + +/* + * Inform BGP about local MAC addition. + */ +static int +zvni_mac_send_add_to_client (struct zebra_vrf *zvrf, vni_t vni, + struct ethaddr *macaddr) +{ + return zvni_macip_send_msg_to_client (zvrf, vni, macaddr, NULL, + ZEBRA_MACIP_ADD); +} + +/* + * Inform BGP about local MAC deletion. + */ +static int +zvni_mac_send_del_to_client (struct zebra_vrf *zvrf, vni_t vni, + struct ethaddr *macaddr) +{ + return zvni_macip_send_msg_to_client (zvrf, vni, macaddr, NULL, + ZEBRA_MACIP_DEL); +} + +/* + * Map port or (port, VLAN) to a VNI. This is invoked upon getting MAC + * notifications, to see if there are of interest. + * TODO: Need to make this as a hash table. + */ +static zebra_vni_t * +zvni_map_vlan (struct interface *ifp, struct interface *br_if, vlanid_t vid) +{ + struct zebra_vrf *zvrf; + struct listnode *node; + struct interface *tmp_if; + struct zebra_if *zif; + struct zebra_l2info_bridge *br; + struct zebra_l2info_vxlan *vxl; + u_char bridge_vlan_aware; + zebra_vni_t *zvni; + + /* Locate VRF corresponding to interface. */ + zvrf = vrf_info_lookup(ifp->vrf_id); + assert(zvrf); + + /* Determine if bridge is VLAN-aware or not */ + zif = br_if->info; + assert (zif); + br = &zif->l2info.br; + bridge_vlan_aware = br->vlan_aware; + + /* See if this interface (or interface plus VLAN Id) maps to a VxLAN */ + /* TODO: Optimize with a hash. */ + for (ALL_LIST_ELEMENTS_RO (vrf_iflist (zvrf_id (zvrf)), node, tmp_if)) + { + zif = tmp_if->info; + if (!zif || zif->zif_type != ZEBRA_IF_VXLAN) + continue; + if (!if_is_operative (tmp_if)) + continue; + vxl = &zif->l2info.vxl; + + if (zif->brslave_info.br_if != br_if) + continue; + + if (!bridge_vlan_aware) + break; + + if (vxl->access_vlan == vid) + break; + } + + if (!tmp_if) + return NULL; + + zvni = zvni_lookup (zvrf, vxl->vni); + return zvni; +} + +/* + * Map SVI and associated bridge to a VNI. This is invoked upon getting + * neighbor notifications, to see if they are of interest. + * TODO: Need to make this as a hash table. + */ +static zebra_vni_t * +zvni_map_svi (struct interface *ifp, struct interface *br_if) +{ + struct zebra_vrf *zvrf; + struct listnode *node; + struct interface *tmp_if; + struct zebra_if *zif; + struct zebra_l2info_bridge *br; + struct zebra_l2info_vxlan *vxl; + u_char bridge_vlan_aware; + vlanid_t vid = 0; + zebra_vni_t *zvni; + + /* Make sure the linked interface is a bridge. */ + if (!IS_ZEBRA_IF_BRIDGE (br_if)) + return NULL; + + /* Locate VRF corresponding to interface. */ + zvrf = vrf_info_lookup(ifp->vrf_id); + assert(zvrf); + + /* Determine if bridge is VLAN-aware or not */ + zif = br_if->info; + assert (zif); + br = &zif->l2info.br; + bridge_vlan_aware = br->vlan_aware; + if (bridge_vlan_aware) + { + struct zebra_l2info_vlan *vl; + + if (!IS_ZEBRA_IF_VLAN(ifp)) + return NULL; + + zif = ifp->info; + assert (zif); + vl = &zif->l2info.vl; + vid = vl->vid; + } + + /* See if this interface (or interface plus VLAN Id) maps to a VxLAN */ + /* TODO: Optimize with a hash. */ + for (ALL_LIST_ELEMENTS_RO (vrf_iflist (zvrf_id (zvrf)), node, tmp_if)) + { + zif = tmp_if->info; + if (!zif || zif->zif_type != ZEBRA_IF_VXLAN) + continue; + if (!if_is_operative (tmp_if)) + continue; + vxl = &zif->l2info.vxl; + + if (zif->brslave_info.br_if != br_if) + continue; + + if (!bridge_vlan_aware) + break; + + if (vxl->access_vlan == vid) + break; + } + + if (!tmp_if) + return NULL; + + zvni = zvni_lookup (zvrf, vxl->vni); + return zvni; +} + +/* Map to SVI on bridge corresponding to specified VLAN. This can be one + * of two cases: + * (a) In the case of a VLAN-aware bridge, the SVI is a L3 VLAN interface + * linked to the bridge + * (b) In the case of a VLAN-unaware bridge, the SVI is the bridge inteface + * itself + */ +static struct interface * +zvni_map_to_svi (struct zebra_vrf *zvrf, vlanid_t vid, + struct interface *br_if) +{ + struct listnode *node; + struct interface *tmp_if; + struct zebra_if *zif; + struct zebra_l2info_bridge *br; + struct zebra_l2info_vlan *vl; + u_char bridge_vlan_aware; + + /* Determine if bridge is VLAN-aware or not */ + zif = br_if->info; + assert (zif); + br = &zif->l2info.br; + bridge_vlan_aware = br->vlan_aware; + + /* Check oper status of the SVI. */ + if (!bridge_vlan_aware) + return if_is_operative (br_if) ? br_if : NULL; + + /* Identify corresponding VLAN interface. */ + /* TODO: Optimize with a hash. */ + for (ALL_LIST_ELEMENTS_RO (vrf_iflist (zvrf_id (zvrf)), node, tmp_if)) + { + /* Check oper status of the SVI. */ + if (!if_is_operative (tmp_if)) + continue; + zif = tmp_if->info; + if (!zif || + zif->zif_type != ZEBRA_IF_VLAN || + zif->link != br_if) + continue; + vl = (struct zebra_l2info_vlan *)&zif->l2info.vl; + + if (vl->vid == vid) + break; + } + + return tmp_if; +} + +/* + * Install remote MAC into the kernel. + */ +static int +zvni_mac_install (zebra_vni_t *zvni, zebra_mac_t *mac) +{ + struct zebra_if *zif; + struct zebra_l2info_vxlan *vxl; + + if (!(mac->flags & ZEBRA_MAC_REMOTE)) + return 0; + + zif = zvni->vxlan_if->info; + if (!zif) + return -1; + vxl = &zif->l2info.vxl; + + return kernel_add_mac (zvni->vxlan_if, vxl->access_vlan, + &mac->macaddr, mac->fwd_info.r_vtep_ip); +} + +/* + * Uninstall remote MAC from the kernel. In the scenario where the MAC + * moves to remote, we have to uninstall any existing local entry first. + */ +static int +zvni_mac_uninstall (zebra_vni_t *zvni, zebra_mac_t *mac, int local) +{ + struct zebra_if *zif; + struct zebra_l2info_vxlan *vxl; + struct in_addr vtep_ip = { .s_addr = 0 }; + struct zebra_ns *zns; + struct interface *ifp; + + if (!local && !(mac->flags & ZEBRA_MAC_REMOTE)) + return 0; + + if (!zvni->vxlan_if) + { + zlog_err ("VNI %u hash %p couldn't be uninstalled - no intf", + zvni->vni, zvni); + return -1; + } + + zif = zvni->vxlan_if->info; + if (!zif) + return -1; + vxl = &zif->l2info.vxl; + + if (local) + { + zns = zebra_ns_lookup (NS_DEFAULT); + ifp = if_lookup_by_index_per_ns (zns, mac->fwd_info.local.ifindex); + if (!ifp) // unexpected + return -1; + } + else + { + ifp = zvni->vxlan_if; + vtep_ip = mac->fwd_info.r_vtep_ip; + } + + return kernel_del_mac (ifp, vxl->access_vlan, + &mac->macaddr, vtep_ip, local); +} + +/* + * Install MAC hash entry - called upon access VLAN change. + */ +static void +zvni_install_mac_hash (struct hash_backet *backet, void *ctxt) +{ + zebra_mac_t *mac; + struct mac_walk_ctx *wctx = ctxt; + + mac = (zebra_mac_t *) backet->data; + if (!mac) + return; + + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) + zvni_mac_install (wctx->zvni, mac); +} + +/* + * Decrement neighbor refcount of MAC; uninstall and free it if + * appropriate. + */ +static void +zvni_deref_ip2mac (zebra_vni_t *zvni, zebra_mac_t *mac, int uninstall) +{ + if (mac->neigh_refcnt) + mac->neigh_refcnt--; + + if (!CHECK_FLAG (mac->flags, ZEBRA_MAC_AUTO) || + mac->neigh_refcnt > 0) + return; + + if (uninstall) + zvni_mac_uninstall (zvni, mac, 0); + + zvni_mac_del (zvni, mac); +} + +/* + * Read and populate local MACs and neighbors corresponding to this VNI. + */ +static void +zvni_read_mac_neigh (struct zebra_vrf *zvrf, zebra_vni_t *zvni, + struct interface *ifp) +{ + struct zebra_if *zif; + struct interface *vlan_if; + struct zebra_l2info_vxlan *vxl; + + zif = ifp->info; + vxl = &zif->l2info.vxl; + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug ("%u:Reading MAC FDB and Neighbors for intf %s(%u) VNI %u master %u", + ifp->vrf_id, ifp->name, ifp->ifindex, zvni->vni, + zif->brslave_info.bridge_ifindex); + + macfdb_read_for_bridge (zvrf->zns, ifp, zif->brslave_info.br_if); + vlan_if = zvni_map_to_svi (zvrf, vxl->access_vlan, + zif->brslave_info.br_if); + if (vlan_if) + neigh_read_for_vlan (zvrf->zns, vlan_if); +} + /* * Hash function for VNI. */ @@ -157,6 +1079,16 @@ zvni_add (struct zebra_vrf *zvrf, vni_t vni) zvni = hash_get (zvrf->vni_table, &tmp_zvni, zvni_alloc); assert (zvni); + /* Create hash table for MAC */ + zvni->mac_table = hash_create(mac_hash_keymake, + mac_cmp, + "Zebra VNI MAC Table"); + + /* Create hash table for neighbors */ + zvni->neigh_table = hash_create(neigh_hash_keymake, + neigh_cmp, + "Zebra VNI Neighbor Table"); + return zvni; } @@ -170,6 +1102,14 @@ zvni_del (struct zebra_vrf *zvrf, zebra_vni_t *zvni) zvni->vxlan_if = NULL; + /* Free the neighbor hash table. */ + hash_free(zvni->neigh_table); + zvni->neigh_table = NULL; + + /* Free the MAC hash table. */ + hash_free(zvni->mac_table); + zvni->mac_table = NULL; + /* Free the VNI hash entry and allocated memory. */ tmp_zvni = hash_release (zvrf->vni_table, zvni); if (tmp_zvni) @@ -434,6 +1374,10 @@ zvni_cleanup_all (struct hash_backet *backet, void *zvrf) if (!zvni) return; + /* Free up all neighbors and MACs, if any. */ + zvni_neigh_del_all (zvrf, zvni, 1, 0, DEL_ALL_NEIGH); + zvni_mac_del_all (zvrf, zvni, 1, 0, DEL_ALL_MAC); + /* Free up all remote VTEPs, if any. */ zvni_vtep_del_all (zvni, 1); @@ -444,6 +1388,754 @@ zvni_cleanup_all (struct hash_backet *backet, void *zvrf) /* Public functions */ +/* + * Handle neighbor delete (on a VLAN device / L3 interface) from the + * kernel. This may result in either the neighbor getting deleted from + * our database or being re-added to the kernel (if it is a valid + * remote neighbor). + */ +int +zebra_vxlan_local_neigh_del (struct interface *ifp, + struct interface *link_if, + struct ipaddr *ip) +{ + zebra_vni_t *zvni; + zebra_neigh_t *n; + struct zebra_vrf *zvrf; + char buf[INET6_ADDRSTRLEN]; + + /* We are only interested in neighbors on an SVI that resides on top + * of a VxLAN bridge. + */ + zvni = zvni_map_svi (ifp, link_if); + if (!zvni) + return 0; + if (!zvni->vxlan_if) + { + zlog_err ("VNI %u hash %p doesn't have intf upon local neighbor DEL", + zvni->vni, zvni); + return -1; + } + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug ("%u:Del neighbor %s intf %s(%u) -> VNI %u", + ifp->vrf_id, ipaddr2str (ip, buf, sizeof(buf)), + ifp->name, ifp->ifindex, zvni->vni); + + /* If entry doesn't exist, nothing to do. */ + n = zvni_neigh_lookup (zvni, ip); + if (!n) + return 0; + + /* If it is a remote entry, the kernel has aged this out or someone has + * deleted it, it needs to be re-installed as Quagga is the owner. + */ + if (CHECK_FLAG (n->flags, ZEBRA_NEIGH_REMOTE)) + { + zvni_neigh_install (zvni, n); + return 0; + } + + /* Locate VRF corresponding to interface. */ + zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); + assert(zvrf); + + /* Remove neighbor from BGP. */ + zvni_neigh_send_del_to_client (zvrf, zvni->vni, &n->ip, &n->emac); + + /* Delete this neighbor entry. */ + zvni_neigh_del (zvni, n); + + return 0; +} + +/* + * Handle neighbor add or update (on a VLAN device / L3 interface) + * from the kernel. + */ +int +zebra_vxlan_local_neigh_add_update (struct interface *ifp, + struct interface *link_if, + struct ipaddr *ip, + struct ethaddr *macaddr, + u_int16_t state, + u_char ext_learned) +{ + zebra_vni_t *zvni; + zebra_neigh_t *n; + struct zebra_vrf *zvrf; + char buf[ETHER_ADDR_STRLEN]; + char buf2[INET6_ADDRSTRLEN]; + int send_upd = 1, send_del = 0; + + /* We are only interested in neighbors on an SVI that resides on top + * of a VxLAN bridge. + */ + zvni = zvni_map_svi (ifp, link_if); + if (!zvni) + return 0; + + /* Locate VRF corresponding to interface. */ + zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); + assert(zvrf); + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug ("%u:Add/Update neighbor %s MAC %s intf %s(%u) state 0x%x " + "%s-> VNI %u", + ifp->vrf_id, ipaddr2str (ip, buf2, sizeof(buf2)), + prefix_mac2str (macaddr, buf, sizeof (buf)), + ifp->name, ifp->ifindex, state, + ext_learned ? "ext-learned " : "", zvni->vni); + + /* If same entry already exists, it might be a change or it might be a + * move from remote to local. + */ + n = zvni_neigh_lookup (zvni, ip); + if (n) + { + if (CHECK_FLAG (n->flags, ZEBRA_NEIGH_LOCAL)) + { + if (memcmp (n->emac.octet, macaddr->octet, ETHER_ADDR_LEN) == 0) + { + if (n->ifindex == ifp->ifindex) + /* we're not interested in whatever has changed. */ + return 0; + /* client doesn't care about a purely local change. */ + send_upd = 0; + } + else + /* If the MAC has changed, issue a delete first as this means a + * different MACIP route. + */ + send_del = 1; + } + else if (ext_learned) + /* The neighbor is remote and that is the notification we got. */ + { + /* TODO: Evaluate if we need to do anything here. */ + return 0; + } + else + /* Neighbor has moved from remote to local. */ + { + UNSET_FLAG (n->flags, ZEBRA_NEIGH_REMOTE); + n->r_vtep_ip.s_addr = 0; + } + } + else + { + n = zvni_neigh_add (zvni, ip); + if (!n) + { + zlog_err ("%u:Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u", + ifp->vrf_id, ipaddr2str (ip, buf2, sizeof(buf2)), + prefix_mac2str (macaddr, buf, sizeof (buf)), + ifp->name, ifp->ifindex, zvni->vni); + return -1; + } + } + + /* Issue delete for older info, if needed. */ + if (send_del) + zvni_neigh_send_del_to_client (zvrf, zvni->vni, &n->ip, &n->emac); + + /* Set "local" forwarding info. */ + SET_FLAG (n->flags, ZEBRA_NEIGH_LOCAL); + memcpy (&n->emac, macaddr, ETHER_ADDR_LEN); + n->ifindex = ifp->ifindex; + + /* Inform BGP if required. */ + if (send_upd) + return zvni_neigh_send_add_to_client (zvrf, zvni->vni, ip, macaddr); + + return 0; +} + +/* + * Handle message from client to delete a remote MACIP for a VNI. + */ +int zebra_vxlan_remote_macip_del (struct zserv *client, int sock, + u_short length, struct zebra_vrf *zvrf) +{ + struct stream *s; + vni_t vni; + struct ethaddr macaddr; + struct ipaddr ip; + struct in_addr vtep_ip; + zebra_vni_t *zvni; + zebra_mac_t *mac; + zebra_neigh_t *n; + u_short l = 0, ipa_len; + char buf[ETHER_ADDR_STRLEN]; + char buf1[INET6_ADDRSTRLEN]; + + s = client->ibuf; + + while (l < length) + { + /* Obtain each remote MACIP and process. */ + /* Message contains VNI, followed by MAC followed by IP (if any) + * followed by remote VTEP IP. + */ + mac = NULL; + n = NULL; + memset (&ip, 0, sizeof (ip)); + vni = (vni_t) stream_getl (s); + stream_get (&macaddr.octet, s, ETHER_ADDR_LEN); + ipa_len = stream_getl (s); + if (ipa_len) + { + ip.ipa_type = (ipa_len == IPV4_MAX_BYTELEN) ? IPADDR_V4: IPADDR_V6; + stream_get (&ip.ip.addr, s, ipa_len); + } + l += 4 + ETHER_ADDR_LEN + 4 + ipa_len; + vtep_ip.s_addr = stream_get_ipv4(s); + l += IPV4_MAX_BYTELEN; + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug ("%u:Recv MACIP Del MAC %s IP %s VNI %u Remote VTEP %s from %s", + zvrf_id (zvrf), + prefix_mac2str (&macaddr, buf, sizeof (buf)), + ipaddr2str (&ip, buf1, sizeof (buf1)), + vni, inet_ntoa (vtep_ip), + zebra_route_string (client->proto)); + + /* Locate VNI hash entry - expected to exist. */ + zvni = zvni_lookup (zvrf, vni); + if (!zvni) + { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug ("Failed to locate VNI hash upon remote MACIP DEL, " + "VRF %d VNI %u", zvrf_id (zvrf), vni); + continue; + } + if (!zvni->vxlan_if) + { + zlog_err ("VNI %u hash %p doesn't have intf upon remote MACIP DEL", + vni, zvni); + continue; + } + + /* The remote VTEP specified is normally expected to exist, but it is + * possible that the peer may delete the VTEP before deleting any MACs + * referring to the VTEP, in which case the handler (see remote_vtep_del) + * would have already deleted the MACs. + */ + if (!zvni_vtep_find (zvni, &vtep_ip)) + continue; + + /* If the local VxLAN interface is not up (should be a transient + * event), there's nothing more to do. + */ + if (!if_is_operative (zvni->vxlan_if)) + continue; + + mac = zvni_mac_lookup (zvni, &macaddr); + if (ipa_len) + n = zvni_neigh_lookup (zvni, &ip); + + if (n && !mac) + { + zlog_err ("failed to locate MAC %s for neigh %s in VRF %u VNI %u", + prefix_mac2str (&macaddr, buf, sizeof (buf)), + ipaddr2str (&ip, buf1, sizeof (buf1)), + zvrf_id (zvrf), vni); + continue; + } + + /* If the remote mac or neighbor doesn't exist there is nothing more + * to do. Otherwise, uninstall the entry and then remove it. + */ + if (!mac && !n) + continue; + + /* Uninstall remote neighbor or MAC. */ + if (n) + { + /* When the MAC changes for an IP, it is possible the client may + * update the new MAC before trying to delete the "old" neighbor + * (as these are two different MACIP routes). Do the delete only + * if the MAC matches. + */ + if (CHECK_FLAG (n->flags, ZEBRA_NEIGH_REMOTE) && + (memcmp (n->emac.octet, macaddr.octet, ETHER_ADDR_LEN) == 0)) + { + zvni_neigh_uninstall (zvni, n); + zvni_neigh_del (zvni, n); + zvni_deref_ip2mac (zvni, mac, 1); + } + } + else + { + if (CHECK_FLAG (mac->flags, ZEBRA_MAC_REMOTE)) + { + if (!mac->neigh_refcnt) + { + zvni_mac_uninstall (zvni, mac, 0); + zvni_mac_del (zvni, mac); + } + else + SET_FLAG (mac->flags, ZEBRA_MAC_AUTO); + } + } + } + + return 0; +} + +/* + * Handle message from client to add a remote MACIP for a VNI. This + * could be just the add of a MAC address or the add of a neighbor + * (IP+MAC). + */ +int +zebra_vxlan_remote_macip_add (struct zserv *client, int sock, + u_short length, struct zebra_vrf *zvrf) +{ + struct stream *s; + vni_t vni; + struct ethaddr macaddr; + struct ipaddr ip; + struct in_addr vtep_ip; + zebra_vni_t *zvni; + zebra_vtep_t *zvtep; + zebra_mac_t *mac, *old_mac; + zebra_neigh_t *n; + u_short l = 0, ipa_len; + int update_mac = 0, update_neigh = 0; + char buf[ETHER_ADDR_STRLEN]; + char buf1[INET6_ADDRSTRLEN]; + + assert (EVPN_ENABLED (zvrf)); + + s = client->ibuf; + + while (l < length) + { + /* Obtain each remote MACIP and process. */ + /* Message contains VNI, followed by MAC followed by IP (if any) + * followed by remote VTEP IP. + */ + update_mac = update_neigh = 0; + mac = NULL; + n = NULL; + memset (&ip, 0, sizeof (ip)); + vni = (vni_t) stream_getl (s); + stream_get (&macaddr.octet, s, ETHER_ADDR_LEN); + ipa_len = stream_getl (s); + if (ipa_len) + { + ip.ipa_type = (ipa_len == IPV4_MAX_BYTELEN) ? IPADDR_V4: IPADDR_V6; + stream_get (&ip.ip.addr, s, ipa_len); + } + l += 4 + ETHER_ADDR_LEN + 4 + ipa_len; + vtep_ip.s_addr = stream_get_ipv4 (s); + l += IPV4_MAX_BYTELEN; + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug ("%u:Recv MACIP Add MAC %s IP %s VNI %u Remote VTEP %s from %s", + zvrf_id (zvrf), + prefix_mac2str (&macaddr, buf, sizeof (buf)), + ipaddr2str (&ip, buf1, sizeof (buf1)), + vni, inet_ntoa (vtep_ip), + zebra_route_string (client->proto)); + + /* Locate VNI hash entry - expected to exist. */ + zvni = zvni_lookup (zvrf, vni); + if (!zvni) + { + zlog_err ("Failed to locate VNI hash upon remote MACIP ADD, VRF %d VNI %u", + zvrf_id (zvrf), vni); + continue; + } + if (!zvni->vxlan_if) + { + zlog_err ("VNI %u hash %p doesn't have intf upon remote MACIP add", + vni, zvni); + continue; + } + /* If the local VxLAN interface is not up (should be a transient + * event), there's nothing more to do. + */ + if (!if_is_operative (zvni->vxlan_if)) + continue; + + /* The remote VTEP specified should normally exist, but it is possible + * that when peering comes up, peer may advertise MACIP routes before + * advertising type-3 routes. + */ + zvtep = zvni_vtep_find (zvni, &vtep_ip); + if (!zvtep) + { + if (zvni_vtep_add (zvni, &vtep_ip) == NULL) + { + zlog_err ("Failed to add remote VTEP, VRF %d VNI %u zvni %p", + zvrf_id (zvrf), vni, zvni); + continue; + } + + zvni_vtep_install (zvni, &vtep_ip); + } + + /* First, check if the remote MAC is unknown or has a change. If so, + * that needs to be updated first. Note that client could install + * MAC and MACIP separately or just install the latter. + */ + mac = zvni_mac_lookup (zvni, &macaddr); + if (!mac || !CHECK_FLAG (mac->flags, ZEBRA_MAC_REMOTE) || + !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip)) + update_mac = 1; + + if (update_mac) + { + if (!mac) + { + mac = zvni_mac_add (zvni, &macaddr); + if (!mac) + { + zlog_warn ("%u:Failed to add MAC %s VNI %u Remote VTEP %s", + zvrf_id (zvrf), + prefix_mac2str (&macaddr, buf, sizeof (buf)), + vni, inet_ntoa (vtep_ip)); + return -1; + } + + /* Is this MAC created for a MACIP? */ + if (ipa_len) + SET_FLAG (mac->flags, ZEBRA_MAC_AUTO); + } + else if (CHECK_FLAG (mac->flags, ZEBRA_MAC_LOCAL)) + { + /* Moving from local to remote, issue delete. */ + zvni_mac_uninstall (zvni, mac, 1); + } + + /* Set "auto" and "remote" forwarding info. */ + UNSET_FLAG (mac->flags, ZEBRA_MAC_LOCAL); + memset (&mac->fwd_info, 0, sizeof (mac->fwd_info)); + SET_FLAG (mac->flags, ZEBRA_MAC_REMOTE); + mac->fwd_info.r_vtep_ip = vtep_ip; + + /* Install the entry. */ + zvni_mac_install (zvni, mac); + } + + /* If there is no IP, continue - after clearing AUTO flag of MAC. */ + if (!ipa_len) + { + UNSET_FLAG (mac->flags, ZEBRA_MAC_AUTO); + continue; + } + + /* Check if the remote neighbor itself is unknown or has a change. + * If so, create or update and then install the entry. + */ + n = zvni_neigh_lookup (zvni, &ip); + if (!n || !CHECK_FLAG (n->flags, ZEBRA_NEIGH_REMOTE) || + (memcmp(&n->emac, &macaddr, sizeof (macaddr)) != 0) || + !IPV4_ADDR_SAME(&n->r_vtep_ip, &vtep_ip)) + update_neigh = 1; + + if (update_neigh) + { + if (!n) + { + n = zvni_neigh_add (zvni, &ip); + if (!n) + { + zlog_warn ("%u:Failed to add Neigh %s MAC %s VNI %u Remote VTEP %s", + zvrf_id (zvrf), ipaddr2str (&ip, buf1, sizeof (buf1)), + prefix_mac2str (&macaddr, buf, sizeof (buf)), + vni, inet_ntoa (vtep_ip)); + return -1; + } + + /* New neighbor referring to this MAC. */ + mac->neigh_refcnt++; + } + else if (memcmp(&n->emac, &macaddr, sizeof (macaddr)) != 0) + { + /* MAC change, update ref counts for old and new MAC. */ + old_mac = zvni_mac_lookup (zvni, &n->emac); + if (old_mac) + zvni_deref_ip2mac (zvni, old_mac, 1); + mac->neigh_refcnt++; + } + + /* Set "remote" forwarding info. */ + UNSET_FLAG (n->flags, ZEBRA_NEIGH_LOCAL); + /* TODO: Handle MAC change. */ + memcpy (&n->emac, &macaddr, ETHER_ADDR_LEN); + n->r_vtep_ip = vtep_ip; + SET_FLAG (n->flags, ZEBRA_NEIGH_REMOTE); + + /* Install the entry. */ + zvni_neigh_install (zvni, n); + } + } + + return 0; +} + +/* + * Handle notification of MAC add/update over VxLAN. If the kernel is notifying + * us, this must involve a multihoming scenario. Treat this as implicit delete + * of any prior local MAC. + */ +int +zebra_vxlan_check_del_local_mac (struct interface *ifp, + struct interface *br_if, + struct ethaddr *macaddr, + vlanid_t vid) +{ + struct zebra_if *zif; + struct zebra_vrf *zvrf; + struct zebra_l2info_vxlan *vxl; + vni_t vni; + zebra_vni_t *zvni; + zebra_mac_t *mac; + char buf[ETHER_ADDR_STRLEN]; + + zif = ifp->info; + assert(zif); + vxl = &zif->l2info.vxl; + vni = vxl->vni; + + /* Locate VRF corresponding to interface. */ + zvrf = vrf_info_lookup(ifp->vrf_id); + assert(zvrf); + + /* If EVPN is not enabled, nothing to do. */ + if (!EVPN_ENABLED(zvrf)) + return 0; + + /* Locate hash entry; it is expected to exist. */ + zvni = zvni_lookup (zvrf, vni); + if (!zvni) + return 0; + + /* If entry doesn't exist, nothing to do. */ + mac = zvni_mac_lookup (zvni, macaddr); + if (!mac) + return 0; + + /* Is it a local entry? */ + if (!CHECK_FLAG (mac->flags, ZEBRA_MAC_LOCAL)) + return 0; + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug ("%u:Add/update remote MAC %s intf %s(%u) VNI %u - del local", + ifp->vrf_id, prefix_mac2str (macaddr, buf, sizeof (buf)), + ifp->name, ifp->ifindex, vni); + + /* Remove MAC from BGP. */ + zvni_mac_send_del_to_client (zvrf, zvni->vni, macaddr); + + /* Delete this MAC entry. */ + zvni_mac_del (zvni, mac); + + return 0; +} + +/* + * Handle remote MAC delete by kernel; readd the remote MAC if we have it. + * This can happen because the remote MAC entries are also added as "dynamic", + * so the kernel can ageout the entry. + */ +int +zebra_vxlan_check_readd_remote_mac (struct interface *ifp, + struct interface *br_if, + struct ethaddr *macaddr, + vlanid_t vid) +{ + struct zebra_if *zif; + struct zebra_vrf *zvrf; + struct zebra_l2info_vxlan *vxl; + vni_t vni; + zebra_vni_t *zvni; + zebra_mac_t *mac; + char buf[ETHER_ADDR_STRLEN]; + + zif = ifp->info; + assert(zif); + vxl = &zif->l2info.vxl; + vni = vxl->vni; + + /* Locate VRF corresponding to interface. */ + zvrf = vrf_info_lookup(ifp->vrf_id); + assert(zvrf); + + /* If EVPN is not enabled, nothing to do. */ + if (!EVPN_ENABLED(zvrf)) + return 0; + + /* Locate hash entry; it is expected to exist. */ + zvni = zvni_lookup (zvrf, vni); + if (!zvni) + return 0; + + /* If entry doesn't exist, nothing to do. */ + mac = zvni_mac_lookup (zvni, macaddr); + if (!mac) + return 0; + + /* Is it a remote entry? */ + if (!CHECK_FLAG (mac->flags, ZEBRA_MAC_REMOTE)) + return 0; + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug ("%u:Del remote MAC %s intf %s(%u) VNI %u - readd", + ifp->vrf_id, prefix_mac2str (macaddr, buf, sizeof (buf)), + ifp->name, ifp->ifindex, vni); + + zvni_mac_install (zvni, mac); + return 0; +} + +/* + * Handle local MAC delete (on a port or VLAN corresponding to this VNI). + */ +int +zebra_vxlan_local_mac_del (struct interface *ifp, struct interface *br_if, + struct ethaddr *macaddr, vlanid_t vid) +{ + zebra_vni_t *zvni; + zebra_mac_t *mac; + struct zebra_vrf *zvrf; + char buf[ETHER_ADDR_STRLEN]; + + /* We are interested in MACs only on ports or (port, VLAN) that + * map to a VNI. + */ + zvni = zvni_map_vlan (ifp, br_if, vid); + if (!zvni) + return 0; + if (!zvni->vxlan_if) + { + zlog_err ("VNI %u hash %p doesn't have intf upon local MAC DEL", + zvni->vni, zvni); + return -1; + } + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug ("%u:Del MAC %s intf %s(%u) VID %u -> VNI %u", + ifp->vrf_id, prefix_mac2str (macaddr, buf, sizeof (buf)), + ifp->name, ifp->ifindex, vid, zvni->vni); + + /* If entry doesn't exist, nothing to do. */ + mac = zvni_mac_lookup (zvni, macaddr); + if (!mac) + return 0; + + /* Is it a local entry? */ + if (!CHECK_FLAG (mac->flags, ZEBRA_MAC_LOCAL)) + return 0; + + /* Locate VRF corresponding to interface. */ + zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); + assert(zvrf); + + /* Remove MAC from BGP. */ + zvni_mac_send_del_to_client (zvrf, zvni->vni, macaddr); + + /* Delete this MAC entry. */ + zvni_mac_del (zvni, mac); + + return 0; +} + +/* + * Handle local MAC add (on a port or VLAN corresponding to this VNI). + */ +int +zebra_vxlan_local_mac_add_update (struct interface *ifp, struct interface *br_if, + struct ethaddr *macaddr, vlanid_t vid) +{ + zebra_vni_t *zvni; + zebra_mac_t *mac; + struct zebra_vrf *zvrf; + char buf[ETHER_ADDR_STRLEN]; + int add = 1; + + /* We are interested in MACs only on ports or (port, VLAN) that + * map to a VNI. + */ + zvni = zvni_map_vlan (ifp, br_if, vid); + if (!zvni) + { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug ("%u:Add/Update MAC %s intf %s(%u) VID %u, could not find VNI", + ifp->vrf_id, + prefix_mac2str (macaddr, buf, sizeof (buf)), + ifp->name, ifp->ifindex, vid); + return 0; + } + + if (!zvni->vxlan_if) + { + zlog_err ("VNI %u hash %p doesn't have intf upon local MAC ADD", + zvni->vni, zvni); + return -1; + } + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug ("%u:Add/Update MAC %s intf %s(%u) VID %u -> VNI %u", + ifp->vrf_id, + prefix_mac2str (macaddr, buf, sizeof (buf)), + ifp->name, ifp->ifindex, vid, zvni->vni); + + /* If same entry already exists, nothing to do. */ + mac = zvni_mac_lookup (zvni, macaddr); + if (mac) + { + if (CHECK_FLAG (mac->flags, ZEBRA_MAC_LOCAL)) + { + if (mac->fwd_info.local.ifindex == ifp->ifindex && + mac->fwd_info.local.vid == vid) + { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug ("%u:Add/Update MAC %s intf %s(%u) VID %u -> VNI %u, " + "entry exists and has not changed ", + ifp->vrf_id, + prefix_mac2str (macaddr, buf, sizeof (buf)), + ifp->name, ifp->ifindex, vid, zvni->vni); + return 0; + } + + add = 0; /* This is an update of local interface. */ + } + } + + /* Locate VRF corresponding to interface. */ + zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); + assert(zvrf); + + if (!mac) + { + mac = zvni_mac_add (zvni, macaddr); + if (!mac) + { + zlog_err ("%u:Failed to add MAC %s intf %s(%u) VID %u", + ifp->vrf_id, prefix_mac2str (macaddr, buf, sizeof (buf)), + ifp->name, ifp->ifindex, vid); + return -1; + } + } + + /* Set "local" forwarding info. */ + UNSET_FLAG (mac->flags, ZEBRA_MAC_REMOTE); + memset (&mac->fwd_info, 0, sizeof (mac->fwd_info)); + SET_FLAG (mac->flags, ZEBRA_MAC_LOCAL); + mac->fwd_info.local.ifindex = ifp->ifindex; + mac->fwd_info.local.vid = vid; + + /* Inform BGP if required. */ + if (add) + return zvni_mac_send_add_to_client (zvrf, zvni->vni, macaddr); + + return 0; +} + /* * Handle message from client to delete a remote VTEP for a VNI. */ @@ -490,6 +2182,8 @@ int zebra_vxlan_remote_vtep_del (struct zserv *client, int sock, if (!zvtep) continue; + zvni_neigh_del_from_vtep (zvni, 1, &vtep_ip); + zvni_mac_del_from_vtep (zvni, 1, &vtep_ip); zvni_vtep_uninstall (zvni, &vtep_ip); zvni_vtep_del (zvni, zvtep); } @@ -565,6 +2259,50 @@ int zebra_vxlan_remote_vtep_add (struct zserv *client, int sock, return 0; } +/* + * Handle SVI interface going down. At this point, this is a NOP since + * the kernel deletes the neighbor entries on this SVI (if any). + */ +int +zebra_vxlan_svi_down (struct interface *ifp, struct interface *link_if) +{ + return 0; +} + +/* + * Handle SVI interface coming up. This may or may not be of interest, + * but if this is a SVI on a VxLAN bridge, we need to install any remote + * neighbor entries (which will be used for EVPN ARP suppression). + */ +int +zebra_vxlan_svi_up (struct interface *ifp, struct interface *link_if) +{ + zebra_vni_t *zvni; + struct neigh_walk_ctx n_wctx; + + zvni = zvni_map_svi (ifp, link_if); + if (!zvni) + return 0; + + if (!zvni->vxlan_if) + { + zlog_err ("VNI %u hash %p doesn't have intf upon SVI up", + zvni->vni, zvni); + return -1; + } + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug ("%u:SVI %s(%u) VNI %u is UP, installing neighbors", + ifp->vrf_id, ifp->name, ifp->ifindex, zvni->vni); + + /* Install any remote neighbors for this VNI. */ + memset (&n_wctx, 0, sizeof (struct neigh_walk_ctx)); + n_wctx.zvni = zvni; + hash_iterate(zvni->neigh_table, zvni_install_neigh_hash, &n_wctx); + + return 0; +} + /* * Handle VxLAN interface down - update BGP if required, and do * internal cleanup. @@ -609,6 +2347,10 @@ zebra_vxlan_if_down (struct interface *ifp) /* Delete this VNI from BGP. */ zvni_send_del_to_client (zvrf, zvni->vni); + /* Free up all neighbors and MACs, if any. */ + zvni_neigh_del_all (zvrf, zvni, 1, 0, DEL_ALL_NEIGH); + zvni_mac_del_all (zvrf, zvni, 1, 0, DEL_ALL_MAC); + /* Free up all remote VTEPs, if any. */ zvni_vtep_del_all (zvni, 1); @@ -656,8 +2398,12 @@ zebra_vxlan_if_up (struct interface *ifp) assert (zvni->vxlan_if == ifp); /* If part of a bridge, inform BGP about this VNI. */ + /* Also, read and populate local MACs and neighbors. */ if (zif->brslave_info.br_if) - zvni_send_add_to_client (zvrf, zvni); + { + zvni_send_add_to_client (zvrf, zvni); + zvni_read_mac_neigh (zvrf, zvni, ifp); + } return 0; } @@ -689,8 +2435,8 @@ zebra_vxlan_if_del (struct interface *ifp) vni = vxl->vni; if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug ("%u:Del intf %s(%u) VNI %u", - ifp->vrf_id, ifp->name, ifp->ifindex, vni); + zlog_debug ("%u:Del VNI %u intf %s(%u)", + ifp->vrf_id, vni, ifp->name, ifp->ifindex); /* Locate hash entry; it is expected to exist. */ zvni = zvni_lookup (zvrf, vni); @@ -704,6 +2450,10 @@ zebra_vxlan_if_del (struct interface *ifp) /* Delete VNI from BGP. */ zvni_send_del_to_client (zvrf, zvni->vni); + /* Free up all neighbors and MAC, if any. */ + zvni_neigh_del_all (zvrf, zvni, 0, 0, DEL_ALL_NEIGH); + zvni_mac_del_all (zvrf, zvni, 0, 0, DEL_ALL_MAC); + /* Free up all remote VTEPs, if any. */ zvni_vtep_del_all (zvni, 0); @@ -753,11 +2503,10 @@ zebra_vxlan_if_update (struct interface *ifp, u_int16_t chgflags) } if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug ("%u:Update intf %s(%u) VNI %u VLAN %u local IP %s " + zlog_debug ("%u:Update VNI %u intf %s(%u) VLAN %u local IP %s " "master %u chg 0x%x", - ifp->vrf_id, ifp->name, ifp->ifindex, - vni, vxl->access_vlan, - inet_ntoa (vxl->vtep_ip), + ifp->vrf_id, vni, ifp->name, ifp->ifindex, + vxl->access_vlan, inet_ntoa (vxl->vtep_ip), zif->brslave_info.bridge_ifindex, chgflags); /* Removed from bridge? */ @@ -765,9 +2514,20 @@ zebra_vxlan_if_update (struct interface *ifp, u_int16_t chgflags) (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) { /* Delete from client, remove all remote VTEPs */ + /* Also, free up all MACs and neighbors. */ zvni_send_del_to_client (zvrf, zvni->vni); + zvni_neigh_del_all (zvrf, zvni, 1, 0, DEL_ALL_NEIGH); + zvni_mac_del_all (zvrf, zvni, 1, 0, DEL_ALL_MAC); zvni_vtep_del_all (zvni, 1); } + else if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) + { + /* Remove all existing local neighbors and MACs for this VNI + * (including from BGP) + */ + zvni_neigh_del_all (zvrf, zvni, 0, 1, DEL_LOCAL_MAC); + zvni_mac_del_all (zvrf, zvni, 0, 1, DEL_LOCAL_MAC); + } zvni->local_vtep_ip = vxl->vtep_ip; zvni->vxlan_if = ifp; @@ -779,9 +2539,32 @@ zebra_vxlan_if_update (struct interface *ifp, u_int16_t chgflags) if (!if_is_operative (ifp) || !zif->brslave_info.br_if) return 0; - /* Inform BGP. */ + /* Inform BGP, if there is a change of interest. */ + if (chgflags & (ZEBRA_VXLIF_MASTER_CHANGE | ZEBRA_VXLIF_LOCAL_IP_CHANGE)) zvni_send_add_to_client (zvrf, zvni); + /* If there is a valid new master or a VLAN mapping change, read and + * populate local MACs and neighbors. Also, reinstall any remote MACs + * and neighbors for this VNI (based on new VLAN). + */ + if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) + zvni_read_mac_neigh (zvrf, zvni, ifp); + else if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) + { + struct mac_walk_ctx m_wctx; + struct neigh_walk_ctx n_wctx; + + zvni_read_mac_neigh (zvrf, zvni, ifp); + + memset (&m_wctx, 0, sizeof (struct mac_walk_ctx)); + m_wctx.zvni = zvni; + hash_iterate(zvni->mac_table, zvni_install_mac_hash, &m_wctx); + + memset (&n_wctx, 0, sizeof (struct neigh_walk_ctx)); + n_wctx.zvni = zvni; + hash_iterate(zvni->neigh_table, zvni_install_neigh_hash, &n_wctx); + } + return 0; } @@ -811,10 +2594,9 @@ zebra_vxlan_if_add (struct interface *ifp) vni = vxl->vni; if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug ("%u:Add intf %s(%u) VNI %u VLAN %u local IP %s master %u", - ifp->vrf_id, ifp->name, ifp->ifindex, - vni, vxl->access_vlan, - inet_ntoa (vxl->vtep_ip), + zlog_debug ("%u:Add VNI %u intf %s(%u) VLAN %u local IP %s master %u", + ifp->vrf_id, vni, ifp->name, ifp->ifindex, + vxl->access_vlan, inet_ntoa (vxl->vtep_ip), zif->brslave_info.bridge_ifindex); /* Create or update VNI hash. */ @@ -840,6 +2622,9 @@ zebra_vxlan_if_add (struct interface *ifp) /* Inform BGP */ zvni_send_add_to_client (zvrf, zvni); + /* Read and populate local MACs and neighbors */ + zvni_read_mac_neigh (zvrf, zvni, ifp); + return 0; } @@ -871,6 +2656,12 @@ int zebra_vxlan_advertise_all_vni (struct zserv *client, int sock, { /* Build VNI hash table and inform BGP. */ zvni_build_hash_table (zvrf); + + /* Read the MAC FDB */ + macfdb_read (zvrf->zns); + + /* Read neighbors */ + neigh_read (zvrf->zns); } else { diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h index 0e8d783a3c..be991f426c 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -42,6 +42,33 @@ #define ZEBRA_VXLIF_MASTER_CHANGE 0x2 #define ZEBRA_VXLIF_VLAN_CHANGE 0x4 +extern int zebra_vxlan_svi_up (struct interface *ifp, struct interface *link_if); +extern int zebra_vxlan_svi_down (struct interface *ifp, struct interface *link_if); +extern int zebra_vxlan_local_neigh_add_update (struct interface *ifp, + struct interface *link_if, + struct ipaddr *ip, + struct ethaddr *macaddr, + u_int16_t state, + u_char ext_learned); +extern int zebra_vxlan_local_neigh_del (struct interface *ifp, + struct interface *link_if, + struct ipaddr *ip); +extern int zebra_vxlan_remote_macip_add (struct zserv *client, int sock, + u_short length, struct zebra_vrf *zvrf); +extern int zebra_vxlan_remote_macip_del (struct zserv *client, int sock, + u_short length, struct zebra_vrf *zvrf); +extern int zebra_vxlan_local_mac_add_update (struct interface *ifp, + struct interface *br_if, + struct ethaddr *mac, vlanid_t vid); +extern int zebra_vxlan_local_mac_del (struct interface *ifp, + struct interface *br_if, + struct ethaddr *mac, vlanid_t vid); +extern int zebra_vxlan_check_readd_remote_mac (struct interface *ifp, + struct interface *br_if, + struct ethaddr *mac, vlanid_t vid); +extern int zebra_vxlan_check_del_local_mac (struct interface *ifp, + struct interface *br_if, + struct ethaddr *mac, vlanid_t vid); extern int zebra_vxlan_if_up (struct interface *ifp); extern int zebra_vxlan_if_down (struct interface *ifp); extern int zebra_vxlan_if_add (struct interface *ifp); diff --git a/zebra/zebra_vxlan_null.c b/zebra/zebra_vxlan_null.c index 532ab64290..23bbddfcea 100644 --- a/zebra/zebra_vxlan_null.c +++ b/zebra/zebra_vxlan_null.c @@ -30,6 +30,56 @@ #include "zebra/zebra_l2.h" #include "zebra/zebra_vxlan.h" +int zebra_vxlan_svi_up (struct interface *ifp, struct interface *link_if) +{ + return 0; +} + +int zebra_vxlan_svi_down (struct interface *ifp, struct interface *link_if) +{ + return 0; +} + +int zebra_vxlan_remote_macip_add (struct zserv *client, int sock, + u_short length, struct zebra_vrf *zvrf) +{ + return 0; +} + +int zebra_vxlan_remote_macip_del (struct zserv *client, int sock, + u_short length, struct zebra_vrf *zvrf) +{ + return 0; +} + +int zebra_vxlan_local_mac_add_update (struct interface *ifp, + struct interface *br_if, + struct ethaddr *mac, vlanid_t vid) +{ + return 0; +} + +int zebra_vxlan_local_mac_del (struct interface *ifp, + struct interface *br_if, + struct ethaddr *mac, vlanid_t vid) +{ + return 0; +} + +int zebra_vxlan_check_readd_remote_mac (struct interface *ifp, + struct interface *br_if, + struct ethaddr *mac, vlanid_t vid) +{ + return 0; +} + +int zebra_vxlan_check_del_local_mac (struct interface *ifp, + struct interface *br_if, + struct ethaddr *mac, vlanid_t vid) +{ + return 0; +} + int zebra_vxlan_if_up (struct interface *ifp) { diff --git a/zebra/zserv.c b/zebra/zserv.c index c6a9c38c35..a2dbefee0a 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -2444,6 +2444,12 @@ zebra_client_read (struct thread *thread) case ZEBRA_REMOTE_VTEP_DEL: zebra_vxlan_remote_vtep_del (client, sock, length, zvrf); break; + case ZEBRA_REMOTE_MACIP_ADD: + zebra_vxlan_remote_macip_add (client, sock, length, zvrf); + break; + case ZEBRA_REMOTE_MACIP_DEL: + zebra_vxlan_remote_macip_del (client, sock, length, zvrf); + break; default: zlog_info ("Zebra received unknown command %d", command); break; @@ -2737,6 +2743,9 @@ zebra_show_client_detail (struct vty *vty, struct zserv *client) vty_outln (vty, "Interface Down Notifications: %d",client->ifdown_cnt); vty_outln (vty, "VNI add notifications: %d", client->vniadd_cnt); vty_outln (vty, "VNI delete notifications: %d", client->vnidel_cnt); + vty_outln (vty, "MAC-IP add notifications: %d", client->macipadd_cnt); + vty_outln (vty, "MAC-IP delete notifications: %d", client->macipdel_cnt); + vty_out (vty, VTYNL); return; } diff --git a/zebra/zserv.h b/zebra/zserv.h index c8f006d44b..2d6f6fae77 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -107,6 +107,8 @@ struct zserv u_int32_t bfd_client_reg_cnt; u_int32_t vniadd_cnt; u_int32_t vnidel_cnt; + u_int32_t macipadd_cnt; + u_int32_t macipdel_cnt; time_t connect_time; time_t last_read_time; @@ -147,6 +149,11 @@ extern void hostinfo_get (void); extern void rib_init (void); extern void interface_list (struct zebra_ns *); extern void route_read (struct zebra_ns *); +extern void macfdb_read (struct zebra_ns *); +extern void macfdb_read_for_bridge (struct zebra_ns *, struct interface *, + struct interface *); +extern void neigh_read (struct zebra_ns *); +extern void neigh_read_for_vlan (struct zebra_ns *, struct interface *); extern void kernel_init (struct zebra_ns *); extern void kernel_terminate (struct zebra_ns *); extern void zebra_route_map_init (void); From cec2e17d276a4f87a25003b58ebd2e3be12ce973 Mon Sep 17 00:00:00 2001 From: vivek Date: Sun, 14 May 2017 22:45:55 -0700 Subject: [PATCH 06/31] zebra: EVPN/VxLAN UI definitions and handling Implement various UI (vty) commands for EVPN/VxLAN. Signed-off-by: Vivek Venkatraman Signed-off-by: Mitesh Kanjariya Reviewed-by: Donald Sharp --- zebra/zebra_vty.c | 248 +++++++++++++++ zebra/zebra_vxlan.c | 648 +++++++++++++++++++++++++++++++++++++++ zebra/zebra_vxlan.h | 23 +- zebra/zebra_vxlan_null.c | 57 ++++ 4 files changed, 975 insertions(+), 1 deletion(-) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 6ba4c1b9d5..608c9d8d26 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -32,6 +32,7 @@ #include "mpls.h" #include "routemap.h" #include "srcdest_table.h" +#include "vxlan.h" #include "zebra/zserv.h" #include "zebra/zebra_vrf.h" @@ -41,6 +42,7 @@ #include "zebra/zebra_routemap.h" #include "zebra/zebra_static.h" #include "lib/json.h" +#include "zebra/zebra_vxlan.h" extern int allow_delete; @@ -54,6 +56,9 @@ static void vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, #define ONE_DAY_SECOND 60*60*24 #define ONE_WEEK_SECOND 60*60*24*7 +/* VNI range as per RFC 7432 */ +#define CMD_VNI_RANGE "(1-16777215)" + /* General function for static route. */ int zebra_static_ipv4 (struct vty *vty, safi_t safi, int add_cmd, @@ -3047,6 +3052,237 @@ DEFUN (show_vrf, return CMD_SUCCESS; } +DEFUN (show_evpn_vni, + show_evpn_vni_cmd, + "show evpn vni", + SHOW_STR + "EVPN\n" + "VxLAN information\n") +{ + struct zebra_vrf *zvrf; + + zvrf = vrf_info_lookup(VRF_DEFAULT); + zebra_vxlan_print_vnis(vty, zvrf); + return CMD_SUCCESS; +} + +DEFUN (show_evpn_vni_vni, + show_evpn_vni_vni_cmd, + "show evpn vni " CMD_VNI_RANGE, + SHOW_STR + "EVPN\n" + "VxLAN Network Identifier\n" + "VNI number\n") +{ + struct zebra_vrf *zvrf; + vni_t vni; + + VTY_GET_INTEGER_RANGE ("VNI", vni, argv[3]->arg, 1, VNI_MAX); + zvrf = vrf_info_lookup(VRF_DEFAULT); + zebra_vxlan_print_vni(vty, zvrf, vni); + return CMD_SUCCESS; +} + +DEFUN (show_evpn_mac_vni, + show_evpn_mac_vni_cmd, + "show evpn mac vni " CMD_VNI_RANGE, + SHOW_STR + "EVPN\n" + "MAC addresses\n" + "VxLAN Network Identifier\n" + "VNI number\n") +{ + struct zebra_vrf *zvrf; + vni_t vni; + + VTY_GET_INTEGER_RANGE ("VNI", vni, argv[4]->arg, 1, VNI_MAX); + zvrf = vrf_info_lookup(VRF_DEFAULT); + zebra_vxlan_print_macs_vni(vty, zvrf, vni); + return CMD_SUCCESS; +} + +DEFUN (show_evpn_mac_vni_all, + show_evpn_mac_vni_all_cmd, + "show evpn mac vni all", + SHOW_STR + "EVPN\n" + "MAC addresses\n" + "VxLAN Network Identifier\n" + "All VNIs\n") +{ + struct zebra_vrf *zvrf; + + zvrf = vrf_info_lookup(VRF_DEFAULT); + zebra_vxlan_print_macs_all_vni(vty, zvrf); + return CMD_SUCCESS; +} + +DEFUN (show_evpn_mac_vni_all_vtep, + show_evpn_mac_vni_all_vtep_cmd, + "show evpn mac vni all vtep A.B.C.D", + SHOW_STR + "EVPN\n" + "MAC addresses\n" + "VxLAN Network Identifier\n" + "All VNIs\n" + "Remote VTEP\n" + "Remote VTEP IP address\n") +{ + struct zebra_vrf *zvrf; + struct in_addr vtep_ip; + + if (!inet_aton (argv[6]->arg, &vtep_ip)) + { + vty_out (vty, "%% Malformed VTEP IP address%s", VTY_NEWLINE); + return CMD_WARNING; + } + zvrf = vrf_info_lookup(VRF_DEFAULT); + zebra_vxlan_print_macs_all_vni_vtep(vty, zvrf, vtep_ip); + + return CMD_SUCCESS; +} + + +DEFUN (show_evpn_mac_vni_mac, + show_evpn_mac_vni_mac_cmd, + "show evpn mac vni " CMD_VNI_RANGE " mac WORD", + SHOW_STR + "EVPN\n" + "MAC addresses\n" + "VxLAN Network Identifier\n" + "VNI number\n" + "MAC\n" + "MAC address (e.g., 00:e0:ec:20:12:62)\n") +{ + struct zebra_vrf *zvrf; + vni_t vni; + struct ethaddr mac; + + VTY_GET_INTEGER_RANGE ("VNI", vni, argv[4]->arg, 1, VNI_MAX); + if (!prefix_str2mac (argv[6]->arg, &mac)) + { + vty_out (vty, "%% Malformed MAC address%s", VTY_NEWLINE); + return CMD_WARNING; + } + zvrf = vrf_info_lookup(VRF_DEFAULT); + zebra_vxlan_print_specific_mac_vni(vty, zvrf, vni, &mac); + return CMD_SUCCESS; +} + +DEFUN (show_evpn_mac_vni_vtep, + show_evpn_mac_vni_vtep_cmd, + "show evpn mac vni " CMD_VNI_RANGE " vtep A.B.C.D", + SHOW_STR + "EVPN\n" + "MAC addresses\n" + "VxLAN Network Identifier\n" + "VNI number\n" + "Remote VTEP\n" + "Remote VTEP IP address\n") +{ + struct zebra_vrf *zvrf; + vni_t vni; + struct in_addr vtep_ip; + + VTY_GET_INTEGER_RANGE ("VNI", vni, argv[4]->arg, 1, VNI_MAX); + if (!inet_aton (argv[6]->arg, &vtep_ip)) + { + vty_out (vty, "%% Malformed VTEP IP address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + zvrf = vrf_info_lookup(VRF_DEFAULT); + zebra_vxlan_print_macs_vni_vtep(vty, zvrf, vni, vtep_ip); + return CMD_SUCCESS; +} + +DEFUN (show_evpn_neigh_vni, + show_evpn_neigh_vni_cmd, + "show evpn arp-cache vni " CMD_VNI_RANGE, + SHOW_STR + "EVPN\n" + "ARP and ND cache\n" + "VxLAN Network Identifier\n" + "VNI number\n") +{ + struct zebra_vrf *zvrf; + vni_t vni; + + VTY_GET_INTEGER_RANGE ("VNI", vni, argv[4]->arg, 1, VNI_MAX); + zvrf = vrf_info_lookup(VRF_DEFAULT); + zebra_vxlan_print_neigh_vni(vty, zvrf, vni); + return CMD_SUCCESS; +} + +DEFUN (show_evpn_neigh_vni_all, + show_evpn_neigh_vni_all_cmd, + "show evpn arp-cache vni all", + SHOW_STR + "EVPN\n" + "ARP and ND cache\n" + "VxLAN Network Identifier\n" + "All VNIs\n") +{ + struct zebra_vrf *zvrf; + + zvrf = vrf_info_lookup(VRF_DEFAULT); + zebra_vxlan_print_neigh_all_vni(vty, zvrf); + return CMD_SUCCESS; +} + +DEFUN (show_evpn_neigh_vni_neigh, + show_evpn_neigh_vni_neigh_cmd, + "show evpn arp-cache vni " CMD_VNI_RANGE " ip WORD", + SHOW_STR + "EVPN\n" + "ARP and ND cache\n" + "VxLAN Network Identifier\n" + "VNI number\n" + "Neighbor\n" + "Neighbor address (IPv4 or IPv6 address)\n") +{ + struct zebra_vrf *zvrf; + vni_t vni; + struct ipaddr ip; + + VTY_GET_INTEGER_RANGE ("VNI", vni, argv[4]->arg, 1, VNI_MAX); + if (str2ipaddr (argv[6]->arg, &ip) != 0) + { + vty_out (vty, "%% Malformed Neighbor address%s", VTY_NEWLINE); + return CMD_WARNING; + } + zvrf = vrf_info_lookup(VRF_DEFAULT); + zebra_vxlan_print_specific_neigh_vni(vty, zvrf, vni, &ip); + return CMD_SUCCESS; +} + +DEFUN (show_evpn_neigh_vni_vtep, + show_evpn_neigh_vni_vtep_cmd, + "show evpn arp-cache vni " CMD_VNI_RANGE " vtep A.B.C.D", + SHOW_STR + "EVPN\n" + "ARP and ND cache\n" + "VxLAN Network Identifier\n" + "VNI number\n" + "Remote VTEP\n" + "Remote VTEP IP address\n") +{ + struct zebra_vrf *zvrf; + vni_t vni; + struct in_addr vtep_ip; + + VTY_GET_INTEGER_RANGE ("VNI", vni, argv[4]->arg, 1, VNI_MAX); + if (!inet_aton (argv[6]->arg, &vtep_ip)) + { + vty_out (vty, "%% Malformed VTEP IP address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + zvrf = vrf_info_lookup(VRF_DEFAULT); + zebra_vxlan_print_neigh_vni_vtep(vty, zvrf, vni, vtep_ip); + return CMD_SUCCESS; +} + /* Static ip route configuration write function. */ static int zebra_ip_config (struct vty *vty) @@ -3237,4 +3473,16 @@ zebra_vty_init (void) install_element (VIEW_NODE, &show_ipv6_route_vrf_all_prefix_cmd); install_element (VIEW_NODE, &show_ipv6_mroute_vrf_all_cmd); + + install_element (VIEW_NODE, &show_evpn_vni_cmd); + install_element (VIEW_NODE, &show_evpn_vni_vni_cmd); + install_element (VIEW_NODE, &show_evpn_mac_vni_cmd); + install_element (VIEW_NODE, &show_evpn_mac_vni_all_cmd); + install_element (VIEW_NODE, &show_evpn_mac_vni_all_vtep_cmd); + install_element (VIEW_NODE, &show_evpn_mac_vni_mac_cmd); + install_element (VIEW_NODE, &show_evpn_mac_vni_vtep_cmd); + install_element (VIEW_NODE, &show_evpn_neigh_vni_cmd); + install_element (VIEW_NODE, &show_evpn_neigh_vni_all_cmd); + install_element (VIEW_NODE, &show_evpn_neigh_vni_neigh_cmd); + install_element (VIEW_NODE, &show_evpn_neigh_vni_vtep_cmd); } diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 808d7eb07e..633083f42b 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -56,6 +56,23 @@ DEFINE_MTYPE_STATIC(ZEBRA, NEIGH, "VNI Neighbor"); /* static function declarations */ +static void +zvni_print_neigh (zebra_neigh_t *n, void *ctxt); +static void +zvni_print_neigh_hash (struct hash_backet *backet, void *ctxt); +static void +zvni_print_neigh_hash_all_vni (struct hash_backet *backet, void *ctxt); +static void +zvni_print_mac (zebra_mac_t *mac, void *ctxt); +static void +zvni_print_mac_hash (struct hash_backet *backet, void *ctxt); +static void +zvni_print_mac_hash_all_vni (struct hash_backet *backet, void *ctxt); +static void +zvni_print (zebra_vni_t *zvni, void *ctxt); +static void +zvni_print_hash (struct hash_backet *backet, void *ctxt); + static int zvni_macip_send_msg_to_client (struct zebra_vrf *zvrf, vni_t vni, struct ethaddr *macaddr, @@ -168,6 +185,357 @@ zvni_vtep_uninstall (zebra_vni_t *zvni, struct in_addr *vtep_ip); /* Private functions */ +/* + * Helper function to determine maximum width of neighbor IP address for + * display - just because we're dealing with IPv6 addresses that can + * widely vary. + */ +static void +zvni_find_neigh_addr_width (struct hash_backet *backet, void *ctxt) +{ + zebra_neigh_t *n; + char buf[INET6_ADDRSTRLEN]; + struct neigh_walk_ctx *wctx = ctxt; + int width; + + n = (zebra_neigh_t *) backet->data; + if (!n) + return; + + ipaddr2str (&n->ip, buf, sizeof(buf)), + width = strlen (buf); + if (width > wctx->addr_width) + wctx->addr_width = width; +} + +/* + * Print a specific neighbor entry. + */ +static void +zvni_print_neigh (zebra_neigh_t *n, void *ctxt) +{ + struct vty *vty; + char buf1[ETHER_ADDR_STRLEN]; + char buf2[INET6_ADDRSTRLEN]; + + ipaddr2str (&n->ip, buf2, sizeof(buf2)), + vty = (struct vty *) ctxt; + vty_out(vty, "IP: %s%s", + ipaddr2str (&n->ip, buf2, sizeof(buf2)), VTY_NEWLINE); + vty_out(vty, " MAC: %s", prefix_mac2str (&n->emac, buf1, sizeof (buf1))); + if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) + vty_out(vty, " Remote VTEP: %s", inet_ntoa (n->r_vtep_ip)); + vty_out(vty, "%s", VTY_NEWLINE); +} + +/* + * Print neighbor hash entry - called for display of all neighbors. + */ +static void +zvni_print_neigh_hash (struct hash_backet *backet, void *ctxt) +{ + struct vty *vty; + zebra_neigh_t *n; + char buf1[ETHER_ADDR_STRLEN]; + char buf2[INET6_ADDRSTRLEN]; + struct neigh_walk_ctx *wctx = ctxt; + + vty = wctx->vty; + n = (zebra_neigh_t *) backet->data; + if (!n) + return; + + prefix_mac2str (&n->emac, buf1, sizeof (buf1)); + ipaddr2str (&n->ip, buf2, sizeof(buf2)); + if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL) && + !(wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP)) + { + vty_out(vty, "%*s %-6s %-17s %s", + -wctx->addr_width, buf2, "local", buf1, VTY_NEWLINE); + wctx->count++; + } + else + { + if (wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP) + { + if (IPV4_ADDR_SAME(&n->r_vtep_ip, &wctx->r_vtep_ip)) + { + if (wctx->count == 0) + vty_out(vty, "%*s %-6s %-17s %-21s%s", + -wctx->addr_width, "Neighbor", "Type", "MAC", + "Remote VTEP", VTY_NEWLINE); + vty_out(vty, "%*s %-6s %-17s %-21s%s", + -wctx->addr_width, buf2, "remote", buf1, + inet_ntoa (n->r_vtep_ip), VTY_NEWLINE); + wctx->count++; + } + } + else + { + vty_out(vty, "%*s %-6s %-17s %-21s%s", + -wctx->addr_width, buf2, "remote", buf1, + inet_ntoa (n->r_vtep_ip), VTY_NEWLINE); + wctx->count++; + } + } +} + +/* + * Print neighbors for all VNI. + */ +static void +zvni_print_neigh_hash_all_vni (struct hash_backet *backet, void *ctxt) +{ + struct vty *vty; + zebra_vni_t *zvni; + u_int32_t num_neigh; + struct neigh_walk_ctx wctx; + + vty = (struct vty *) ctxt; + zvni = (zebra_vni_t *) backet->data; + if (!zvni) + return; + + num_neigh = hashcount(zvni->neigh_table); + vty_out(vty, "%sVNI %u #ARP (IPv4 and IPv6, local and remote) %u%s%s", + VTY_NEWLINE, zvni->vni, num_neigh, VTY_NEWLINE, VTY_NEWLINE); + if (!num_neigh) + return; + + /* Since we have IPv6 addresses to deal with which can vary widely in + * size, we try to be a bit more elegant in display by first computing + * the maximum width. + */ + memset (&wctx, 0, sizeof (struct neigh_walk_ctx)); + wctx.zvni = zvni; + wctx.vty = vty; + wctx.addr_width = 15; + hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx); + + vty_out(vty, "%*s %-6s %-17s %-21s%s", + -wctx.addr_width, "IP", "Type", "MAC", + "Remote VTEP", VTY_NEWLINE); + hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx); +} + +/* + * Print a specific MAC entry. + */ +static void +zvni_print_mac (zebra_mac_t *mac, void *ctxt) +{ + struct vty *vty; + char buf1[20]; + + vty = (struct vty *) ctxt; + vty_out(vty, "MAC: %s%s", + prefix_mac2str (&mac->macaddr, buf1, sizeof (buf1)), VTY_NEWLINE); + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) + { + struct zebra_ns *zns; + struct interface *ifp; + ifindex_t ifindex; + + ifindex = mac->fwd_info.local.ifindex; + zns = zebra_ns_lookup (NS_DEFAULT); + ifp = if_lookup_by_index_per_ns (zns, ifindex); + if (!ifp) // unexpected + return; + vty_out(vty, " Intf: %s(%u)", ifp->name, ifindex); + if (mac->fwd_info.local.vid) + vty_out(vty, " VLAN: %u", mac->fwd_info.local.vid); + } + else + { + vty_out(vty, " Remote VTEP: %s", + inet_ntoa (mac->fwd_info.r_vtep_ip)); + } + vty_out(vty, " ARP ref: %u", mac->neigh_refcnt); + vty_out(vty, "%s", VTY_NEWLINE); +} + +/* + * Print MAC hash entry - called for display of all MACs. + */ +static void +zvni_print_mac_hash (struct hash_backet *backet, void *ctxt) +{ + struct vty *vty; + zebra_mac_t *mac; + char buf1[20]; + struct mac_walk_ctx *wctx = ctxt; + + vty = wctx->vty; + mac = (zebra_mac_t *) backet->data; + if (!mac) + return; + + prefix_mac2str (&mac->macaddr, buf1, sizeof (buf1)); + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) && + !(wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP)) + { + struct zebra_ns *zns; + ifindex_t ifindex; + struct interface *ifp; + vlanid_t vid; + + zns = zebra_ns_lookup (NS_DEFAULT); + ifindex = mac->fwd_info.local.ifindex; + ifp = if_lookup_by_index_per_ns (zns, ifindex); + if (!ifp) // unexpected + return; + vid = mac->fwd_info.local.vid; + vty_out(vty, "%-17s %-6s %-21s", + buf1, "local", ifp->name); + if (vid) + vty_out(vty, " %-5u", vid); + vty_out(vty, "%s", VTY_NEWLINE); + wctx->count++; + } + else + { + if (wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP) + { + if (IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, + &wctx->r_vtep_ip)) + { + if (wctx->count == 0) + { + vty_out(vty, "%sVNI %u%s%s", + VTY_NEWLINE, wctx->zvni->vni,VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "%-17s %-6s %-21s %-5s%s", + "MAC", "Type", "Intf/Remote VTEP", + "VLAN", VTY_NEWLINE); + } + vty_out(vty, "%-17s %-6s %-21s%s", + buf1, "remote", + inet_ntoa (mac->fwd_info.r_vtep_ip), + VTY_NEWLINE); + wctx->count++; + } + } + else + { + vty_out(vty, "%-17s %-6s %-21s%s", + buf1, "remote", + inet_ntoa (mac->fwd_info.r_vtep_ip), VTY_NEWLINE); + wctx->count++; + } + } + +} + +/* + * Print MACs for all VNI. + */ +static void +zvni_print_mac_hash_all_vni (struct hash_backet *backet, void *ctxt) +{ + struct vty *vty; + zebra_vni_t *zvni; + u_int32_t num_macs; + struct mac_walk_ctx *wctx = ctxt; + + vty = (struct vty *) wctx->vty; + + zvni = (zebra_vni_t *) backet->data; + if (!zvni) + return; + wctx->zvni = zvni; + + /*We are iterating over a new VNI, set the count to 0*/ + wctx->count = 0; + + num_macs = hashcount(zvni->mac_table); + if (!num_macs) + return; + if (!CHECK_FLAG(wctx->flags, SHOW_REMOTE_MAC_FROM_VTEP)) + { + vty_out(vty, "%sVNI %u #MACs (local and remote) %u%s%s", + VTY_NEWLINE, zvni->vni, num_macs, VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "%-17s %-6s %-21s %-5s%s", + "MAC", "Type", "Intf/Remote VTEP", "VLAN", VTY_NEWLINE); + } + + hash_iterate(zvni->mac_table, zvni_print_mac_hash, wctx); +} + +/* + * Print a specific VNI entry. + */ +static void +zvni_print (zebra_vni_t *zvni, void *ctxt) +{ + struct vty *vty; + zebra_vtep_t *zvtep; + u_int32_t num_macs; + u_int32_t num_neigh; + + vty = (struct vty *) ctxt; + + vty_out(vty, "VNI: %u%s", zvni->vni, VTY_NEWLINE); + if (!zvni->vxlan_if) + { // unexpected + vty_out(vty, " VxLAN interface: unknown%s", VTY_NEWLINE); + return; + } + vty_out(vty, " VxLAN interface: %s ifIndex: %u VTEP IP: %s%s", + zvni->vxlan_if->name, zvni->vxlan_if->ifindex, + inet_ntoa(zvni->local_vtep_ip), VTY_NEWLINE); + + if (!zvni->vteps) + { + vty_out(vty, " No remote VTEPs known for this VNI%s", VTY_NEWLINE); + } + else + { + vty_out(vty, " Remote VTEPs for this VNI:%s", VTY_NEWLINE); + for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) + vty_out(vty, " %s%s", + inet_ntoa (zvtep->vtep_ip), VTY_NEWLINE); + } + num_macs = hashcount(zvni->mac_table); + vty_out(vty, " Number of MACs (local and remote) known for this VNI: %u%s", + num_macs, VTY_NEWLINE); + num_neigh = hashcount(zvni->neigh_table); + vty_out(vty, " Number of ARPs (IPv4 and IPv6, local and remote) " + "known for this VNI: %u%s", num_neigh, VTY_NEWLINE); +} + +/* + * Print a VNI hash entry - called for display of all VNIs. + */ +static void +zvni_print_hash (struct hash_backet *backet, void *ctxt) +{ + struct vty *vty; + zebra_vni_t *zvni; + zebra_vtep_t *zvtep; + u_int32_t num_vteps = 0; + u_int32_t num_macs = 0; + u_int32_t num_neigh = 0; + + vty = (struct vty *) ctxt; + zvni = (zebra_vni_t *) backet->data; + if (!zvni) + return; + + zvtep = zvni->vteps; + while (zvtep) + { + num_vteps++; + zvtep = zvtep->next; + } + + num_macs = hashcount(zvni->mac_table); + num_neigh = hashcount(zvni->neigh_table); + vty_out(vty, "%-10u %-21s %-15s %-8u %-8u %-15u%s", + zvni->vni, + zvni->vxlan_if ? zvni->vxlan_if->name : "unknown", + inet_ntoa(zvni->local_vtep_ip), + num_macs, num_neigh, num_vteps, VTY_NEWLINE); +} + /* * Inform BGP about local MACIP. */ @@ -1388,6 +1756,286 @@ zvni_cleanup_all (struct hash_backet *backet, void *zvrf) /* Public functions */ +/* + * Display Neighbors for a VNI (VTY command handler). + */ +void +zebra_vxlan_print_neigh_vni (struct vty *vty, struct zebra_vrf *zvrf, vni_t vni) +{ + zebra_vni_t *zvni; + u_int32_t num_neigh; + struct neigh_walk_ctx wctx; + + if (!EVPN_ENABLED(zvrf)) + return; + zvni = zvni_lookup (zvrf, vni); + if (!zvni) + { + vty_out (vty, "%% VNI %u does not exist%s", vni, VTY_NEWLINE); + return; + } + num_neigh = hashcount(zvni->neigh_table); + if (!num_neigh) + return; + + /* Since we have IPv6 addresses to deal with which can vary widely in + * size, we try to be a bit more elegant in display by first computing + * the maximum width. + */ + memset (&wctx, 0, sizeof (struct neigh_walk_ctx)); + wctx.zvni = zvni; + wctx.vty = vty; + wctx.addr_width = 15; + hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx); + + vty_out(vty, "Number of ARPs (local and remote) known for this VNI: %u%s", + num_neigh, VTY_NEWLINE); + vty_out(vty, "%*s %-6s %-17s %-21s%s", + -wctx.addr_width, "IP", "Type", "MAC", + "Remote VTEP", VTY_NEWLINE); + + hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx); +} + +/* + * Display neighbors across all VNIs (VTY command handler). + */ +void +zebra_vxlan_print_neigh_all_vni (struct vty *vty, struct zebra_vrf *zvrf) +{ + if (!EVPN_ENABLED(zvrf)) + return; + hash_iterate(zvrf->vni_table, zvni_print_neigh_hash_all_vni, vty); +} + +/* + * Display specific neighbor for a VNI, if present (VTY command handler). + */ +void +zebra_vxlan_print_specific_neigh_vni (struct vty *vty, struct zebra_vrf *zvrf, + vni_t vni, struct ipaddr *ip) +{ + zebra_vni_t *zvni; + zebra_neigh_t *n; + + if (!EVPN_ENABLED(zvrf)) + return; + zvni = zvni_lookup (zvrf, vni); + if (!zvni) + { + vty_out (vty, "%% VNI %u does not exist%s", vni, VTY_NEWLINE); + return; + } + n = zvni_neigh_lookup (zvni, ip); + if (!n) + { + vty_out (vty, "%% Requested neighbor does not exist in VNI %u%s", + vni, VTY_NEWLINE); + return; + } + + zvni_print_neigh (n, vty); +} + +/* + * Display neighbors for a VNI from specific VTEP (VTY command handler). + * By definition, these are remote neighbors. + */ +void +zebra_vxlan_print_neigh_vni_vtep (struct vty *vty, struct zebra_vrf *zvrf, + vni_t vni, struct in_addr vtep_ip) +{ + zebra_vni_t *zvni; + u_int32_t num_neigh; + struct neigh_walk_ctx wctx; + + if (!EVPN_ENABLED(zvrf)) + return; + zvni = zvni_lookup (zvrf, vni); + if (!zvni) + { + vty_out (vty, "%% VNI %u does not exist%s", vni, VTY_NEWLINE); + return; + } + num_neigh = hashcount(zvni->neigh_table); + if (!num_neigh) + return; + + memset (&wctx, 0, sizeof (struct neigh_walk_ctx)); + wctx.zvni = zvni; + wctx.vty = vty; + wctx.flags = SHOW_REMOTE_NEIGH_FROM_VTEP; + wctx.r_vtep_ip = vtep_ip; + + hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx); +} + +/* + * Display MACs for a VNI (VTY command handler). + */ +void +zebra_vxlan_print_macs_vni (struct vty *vty, struct zebra_vrf *zvrf, vni_t vni) +{ + zebra_vni_t *zvni; + u_int32_t num_macs; + struct mac_walk_ctx wctx; + + if (!EVPN_ENABLED(zvrf)) + return; + zvni = zvni_lookup (zvrf, vni); + if (!zvni) + { + vty_out (vty, "%% VNI %u does not exist%s", vni, VTY_NEWLINE); + return; + } + num_macs = hashcount(zvni->mac_table); + if (!num_macs) + return; + + memset (&wctx, 0, sizeof (struct mac_walk_ctx)); + wctx.zvni = zvni; + wctx.vty = vty; + + vty_out(vty, "Number of MACs (local and remote) known for this VNI: %u%s", + num_macs, VTY_NEWLINE); + vty_out(vty, "%-17s %-6s %-21s %-5s%s", + "MAC", "Type", "Intf/Remote VTEP", "VLAN", VTY_NEWLINE); + + hash_iterate(zvni->mac_table, zvni_print_mac_hash, &wctx); +} + +/* + * Display MACs for all VNIs (VTY command handler). + */ +void +zebra_vxlan_print_macs_all_vni (struct vty *vty, struct zebra_vrf *zvrf) +{ + struct mac_walk_ctx wctx; + + if (!EVPN_ENABLED(zvrf)) + return; + memset (&wctx, 0, sizeof (struct mac_walk_ctx)); + wctx.vty = vty; + hash_iterate(zvrf->vni_table, zvni_print_mac_hash_all_vni, &wctx); +} + +/* + * Display MACs for all VNIs (VTY command handler). + */ +void +zebra_vxlan_print_macs_all_vni_vtep (struct vty *vty, struct zebra_vrf *zvrf, + struct in_addr vtep_ip) +{ + struct mac_walk_ctx wctx; + + if (!EVPN_ENABLED(zvrf)) + return; + memset (&wctx, 0, sizeof (struct mac_walk_ctx)); + wctx.vty = vty; + wctx.flags = SHOW_REMOTE_MAC_FROM_VTEP; + wctx.r_vtep_ip = vtep_ip; + hash_iterate(zvrf->vni_table, zvni_print_mac_hash_all_vni, &wctx); +} + +/* + * Display specific MAC for a VNI, if present (VTY command handler). + */ +void +zebra_vxlan_print_specific_mac_vni (struct vty *vty, struct zebra_vrf *zvrf, + vni_t vni, struct ethaddr *macaddr) +{ + zebra_vni_t *zvni; + zebra_mac_t *mac; + + if (!EVPN_ENABLED(zvrf)) + return; + zvni = zvni_lookup (zvrf, vni); + if (!zvni) + { + vty_out (vty, "%% VNI %u does not exist%s", vni, VTY_NEWLINE); + return; + } + mac = zvni_mac_lookup (zvni, macaddr); + if (!mac) + { + vty_out (vty, "%% Requested MAC does not exist in VNI %u%s", + vni, VTY_NEWLINE); + return; + } + + zvni_print_mac (mac, vty); +} + +/* + * Display MACs for a VNI from specific VTEP (VTY command handler). + */ +void +zebra_vxlan_print_macs_vni_vtep (struct vty *vty, struct zebra_vrf *zvrf, + vni_t vni, struct in_addr vtep_ip) +{ + zebra_vni_t *zvni; + u_int32_t num_macs; + struct mac_walk_ctx wctx; + + if (!EVPN_ENABLED(zvrf)) + return; + zvni = zvni_lookup (zvrf, vni); + if (!zvni) + { + vty_out (vty, "%% VNI %u does not exist%s", vni, VTY_NEWLINE); + return; + } + num_macs = hashcount(zvni->mac_table); + if (!num_macs) + return; + memset (&wctx, 0, sizeof (struct mac_walk_ctx)); + wctx.zvni = zvni; + wctx.vty = vty; + wctx.flags = SHOW_REMOTE_MAC_FROM_VTEP; + wctx.r_vtep_ip = vtep_ip; + hash_iterate(zvni->mac_table, zvni_print_mac_hash, &wctx); +} + + +/* + * Display VNI information (VTY command handler). + */ +void +zebra_vxlan_print_vni (struct vty *vty, struct zebra_vrf *zvrf, vni_t vni) +{ + zebra_vni_t *zvni; + + if (!EVPN_ENABLED(zvrf)) + return; + zvni = zvni_lookup (zvrf, vni); + if (!zvni) + { + vty_out (vty, "%% VNI %u does not exist%s", vni, VTY_NEWLINE); + return; + } + zvni_print (zvni, (void *)vty); +} + +/* + * Display VNI hash table (VTY command handler). + */ +void +zebra_vxlan_print_vnis (struct vty *vty, struct zebra_vrf *zvrf) +{ + u_int32_t num_vnis; + + if (!EVPN_ENABLED(zvrf)) + return; + num_vnis = hashcount(zvrf->vni_table); + if (!num_vnis) + return; + vty_out(vty, "Number of VNIs: %u%s", num_vnis, VTY_NEWLINE); + vty_out(vty, "%-10s %-21s %-15s %-8s %-8s %-15s%s", + "VNI", "VxLAN IF", "VTEP IP", "# MACs", "# ARPs", + "# Remote VTEPs", VTY_NEWLINE); + hash_iterate(zvrf->vni_table, zvni_print_hash, vty); +} + /* * Handle neighbor delete (on a VLAN device / L3 interface) from the * kernel. This may result in either the neighbor getting deleted from diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h index be991f426c..37af55e1ea 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -31,7 +31,6 @@ #include "vlan.h" #include "vxlan.h" -#include "zebra/interface.h" #include "zebra/zebra_vrf.h" /* Is EVPN enabled? */ @@ -42,6 +41,28 @@ #define ZEBRA_VXLIF_MASTER_CHANGE 0x2 #define ZEBRA_VXLIF_VLAN_CHANGE 0x4 +extern void zebra_vxlan_print_macs_vni (struct vty *vty, struct zebra_vrf *zvrf, + vni_t vni); +extern void zebra_vxlan_print_macs_all_vni (struct vty *vty, + struct zebra_vrf *zvrf); +extern void zebra_vxlan_print_macs_all_vni_vtep (struct vty *vty, + struct zebra_vrf *zvrf, + struct in_addr vtep_ip); +extern void zebra_vxlan_print_specific_mac_vni (struct vty *vty, + struct zebra_vrf *zvrf, vni_t vni, struct ethaddr *mac); +extern void zebra_vxlan_print_macs_vni_vtep (struct vty *vty, + struct zebra_vrf *zvrf, vni_t vni, struct in_addr vtep_ip); +extern void zebra_vxlan_print_neigh_vni (struct vty *vty, struct zebra_vrf *zvrf, + vni_t vni); +extern void zebra_vxlan_print_neigh_all_vni (struct vty *vty, + struct zebra_vrf *zvrf); +extern void zebra_vxlan_print_specific_neigh_vni (struct vty *vty, + struct zebra_vrf *zvrf, vni_t vni, struct ipaddr *ip); +extern void zebra_vxlan_print_neigh_vni_vtep (struct vty *vty, + struct zebra_vrf *zvrf, vni_t vni, struct in_addr vtep_ip); +extern void zebra_vxlan_print_vni (struct vty *vty, struct zebra_vrf *zvrf, vni_t vni); +extern void zebra_vxlan_print_vnis (struct vty *vty, struct zebra_vrf *zvrf); + extern int zebra_vxlan_svi_up (struct interface *ifp, struct interface *link_if); extern int zebra_vxlan_svi_down (struct interface *ifp, struct interface *link_if); extern int zebra_vxlan_local_neigh_add_update (struct interface *ifp, diff --git a/zebra/zebra_vxlan_null.c b/zebra/zebra_vxlan_null.c index 23bbddfcea..75aab40870 100644 --- a/zebra/zebra_vxlan_null.c +++ b/zebra/zebra_vxlan_null.c @@ -30,6 +30,63 @@ #include "zebra/zebra_l2.h" #include "zebra/zebra_vxlan.h" +void +zebra_vxlan_print_macs_vni (struct vty *vty, struct zebra_vrf *zvrf, vni_t vni) +{ +} + +void zebra_vxlan_print_macs_all_vni (struct vty *vty, struct zebra_vrf *zvrf) +{ +} + +void zebra_vxlan_print_macs_all_vni_vtep (struct vty *vty, struct zebra_vrf *zvrf, struct in_addr vtep_ip) +{ +} + +void +zebra_vxlan_print_specific_mac_vni (struct vty *vty, struct zebra_vrf *zvrf, + vni_t vni, struct ethaddr *mac) +{ +} + +void +zebra_vxlan_print_macs_vni_vtep (struct vty *vty, struct zebra_vrf *zvrf, + vni_t vni, struct in_addr vtep_ip) +{ +} + +void +zebra_vxlan_print_neigh_vni (struct vty *vty, struct zebra_vrf *zvrf, + vni_t vni) +{ +} + +void +zebra_vxlan_print_neigh_all_vni (struct vty *vty, struct zebra_vrf *zvrf) +{ +} + +void +zebra_vxlan_print_specific_neigh_vni (struct vty *vty, struct zebra_vrf *zvrf, + vni_t vni, struct ipaddr *ip) +{ +} + +void zebra_vxlan_print_neigh_vni_vtep (struct vty *vty, struct zebra_vrf *zvrf, + vni_t vni, struct in_addr vtep_ip) +{ +} + +void +zebra_vxlan_print_vni (struct vty *vty, struct zebra_vrf *zvrf, vni_t vni) +{ +} + +void +zebra_vxlan_print_vnis (struct vty *vty, struct zebra_vrf *zvrf) +{ +} + int zebra_vxlan_svi_up (struct interface *ifp, struct interface *link_if) { return 0; From c5900768674b99a11d187e3584dc577bc05765b2 Mon Sep 17 00:00:00 2001 From: vivek Date: Mon, 15 May 2017 12:31:01 -0700 Subject: [PATCH 07/31] bgpd: Refine extended community handling Define helper functions to form different kinds of route targets. Also, refine functions that encode extended communities as well as generate a string from an extended community. Signed-off-by: Vivek Venkatraman Reviewed-by: Donald Sharp --- bgpd/bgp_ecommunity.c | 327 ++++++++++++++++++++++-------------------- bgpd/bgp_ecommunity.h | 48 +++++++ 2 files changed, 221 insertions(+), 154 deletions(-) diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 0555d1bbe3..bb2ef260ee 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -304,6 +304,61 @@ enum ecommunity_token ecommunity_token_val, }; +/* + * Encode BGP extended community from passed values. Supports types + * defined in RFC 4360 and well-known sub-types. + */ +static int +ecommunity_encode (u_char type, u_char sub_type, int trans, + as_t as, struct in_addr ip, u_int32_t val, + struct ecommunity_val *eval) +{ + assert (eval); + if (type == ECOMMUNITY_ENCODE_AS) + { + if (as > BGP_AS_MAX) + return -1; + } + else if (type == ECOMMUNITY_ENCODE_IP + || type == ECOMMUNITY_ENCODE_AS4) + { + if (val > UINT16_MAX) + return -1; + } + + /* Fill in the values. */ + eval->val[0] = type; + if (!trans) + eval->val[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE; + eval->val[1] = sub_type; + if (type == ECOMMUNITY_ENCODE_AS) + { + eval->val[2] = (as >> 8) & 0xff; + eval->val[3] = as & 0xff; + eval->val[4] = (val >> 24) & 0xff; + eval->val[5] = (val >> 16) & 0xff; + eval->val[6] = (val >> 8) & 0xff; + eval->val[7] = val & 0xff; + } + else if (type == ECOMMUNITY_ENCODE_IP) + { + memcpy (&eval->val[2], &ip, sizeof (struct in_addr)); + eval->val[6] = (val >> 8) & 0xff; + eval->val[7] = val & 0xff; + } + else + { + eval->val[2] = (as >> 24) & 0xff; + eval->val[3] = (as >> 16) & 0xff; + eval->val[4] = (as >> 8) & 0xff; + eval->val[5] = as & 0xff; + eval->val[6] = (val >> 8) & 0xff; + eval->val[7] = val & 0xff; + } + + return 0; +} + /* Get next Extended Communities token from the string. */ static const char * ecommunity_gettoken (const char *str, struct ecommunity_val *eval, @@ -318,6 +373,7 @@ ecommunity_gettoken (const char *str, struct ecommunity_val *eval, struct in_addr ip; as_t as = 0; u_int32_t val = 0; + u_char ecomm_type; char buf[INET_ADDRSTRLEN + 1]; /* Skip white space. */ @@ -452,44 +508,15 @@ ecommunity_gettoken (const char *str, struct ecommunity_val *eval, if (!digit || !separator) goto error; - /* Encode result into routing distinguisher. */ + /* Encode result into extended community. */ if (dot) - { - if (val > UINT16_MAX) - goto error; - - eval->val[0] = ECOMMUNITY_ENCODE_IP; - eval->val[1] = 0; - memcpy (&eval->val[2], &ip, sizeof (struct in_addr)); - eval->val[6] = (val >> 8) & 0xff; - eval->val[7] = val & 0xff; - } + ecomm_type = ECOMMUNITY_ENCODE_IP; else if (as > BGP_AS_MAX) - { - if (val > UINT16_MAX) - goto error; - - eval->val[0] = ECOMMUNITY_ENCODE_AS4; - eval->val[1] = 0; - eval->val[2] = (as >>24) & 0xff; - eval->val[3] = (as >>16) & 0xff; - eval->val[4] = (as >>8) & 0xff; - eval->val[5] = as & 0xff; - eval->val[6] = (val >> 8) & 0xff; - eval->val[7] = val & 0xff; - } + ecomm_type = ECOMMUNITY_ENCODE_AS4; else - { - eval->val[0] = ECOMMUNITY_ENCODE_AS; - eval->val[1] = 0; - - eval->val[2] = (as >>8) & 0xff; - eval->val[3] = as & 0xff; - eval->val[4] = (val >>24) & 0xff; - eval->val[5] = (val >>16) & 0xff; - eval->val[6] = (val >>8) & 0xff; - eval->val[7] = val & 0xff; - } + ecomm_type = ECOMMUNITY_ENCODE_AS; + if (ecommunity_encode (ecomm_type, 0, 1, as, ip, val, eval)) + goto error; *token = ecommunity_token_val; return p; @@ -581,6 +608,81 @@ ecommunity_str2com (const char *str, int type, int keyword_included) return ecom; } +static int +ecommunity_rt_soo_str (char *buf, u_int8_t *pnt, int type, + int sub_type, int format) +{ + int len = 0; + const char *prefix; + + /* For parse Extended Community attribute tupple. */ + struct ecommunity_as + { + as_t as; + u_int32_t val; + } eas; + + struct ecommunity_ip + { + struct in_addr ip; + u_int16_t val; + } eip; + + + /* Determine prefix for string, if any. */ + switch (format) + { + case ECOMMUNITY_FORMAT_COMMUNITY_LIST: + prefix = (sub_type == ECOMMUNITY_ROUTE_TARGET ? "rt " : "soo "); + break; + case ECOMMUNITY_FORMAT_DISPLAY: + prefix = (sub_type == ECOMMUNITY_ROUTE_TARGET ? "RT:" : "SoO:"); + break; + case ECOMMUNITY_FORMAT_ROUTE_MAP: + prefix = ""; + break; + default: + prefix = ""; + break; + } + + /* Put string into buffer. */ + if (type == ECOMMUNITY_ENCODE_AS4) + { + eas.as = (*pnt++ << 24); + eas.as |= (*pnt++ << 16); + eas.as |= (*pnt++ << 8); + eas.as |= (*pnt++); + eas.val = (*pnt++ << 8); + eas.val |= (*pnt++); + + len = sprintf (buf, "%s%u:%u", prefix, eas.as, eas.val); + } + else if (type == ECOMMUNITY_ENCODE_AS) + { + eas.as = (*pnt++ << 8); + eas.as |= (*pnt++); + + eas.val = (*pnt++ << 24); + eas.val |= (*pnt++ << 16); + eas.val |= (*pnt++ << 8); + eas.val |= (*pnt++); + + len = sprintf (buf, "%s%u:%u", prefix, eas.as, eas.val); + } + else if (type == ECOMMUNITY_ENCODE_IP) + { + memcpy (&eip.ip, pnt, 4); + pnt += 4; + eip.val = (*pnt++ << 8); + eip.val |= (*pnt++); + + len = sprintf (buf, "%s%s:%u", prefix, inet_ntoa (eip.ip), eip.val); + } + + return len; +} + /* Convert extended community attribute to string. Due to historical reason of industry standard implementation, there @@ -610,29 +712,15 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format, int filter) { int i; u_int8_t *pnt; - int encode = 0; int type = 0; + int sub_type = 0; #define ECOMMUNITY_STR_DEFAULT_LEN 27 int str_size; int str_pnt; char *str_buf; - const char *prefix; int len = 0; int first = 1; - /* For parse Extended Community attribute tupple. */ - struct ecommunity_as - { - as_t as; - u_int32_t val; - } eas; - - struct ecommunity_ip - { - struct in_addr ip; - u_int16_t val; - } eip; - if (ecom->size == 0) { str_buf = XMALLOC (MTYPE_ECOMMUNITY_STR, 1); @@ -648,6 +736,8 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format, int filter) for (i = 0; i < ecom->size; i++) { + int unk_ecom = 0; + /* Make it sure size is enough. */ while (str_pnt + ECOMMUNITY_STR_DEFAULT_LEN >= str_size) { @@ -662,39 +752,39 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format, int filter) pnt = ecom->val + (i * 8); /* High-order octet of type. */ - encode = *pnt++; + type = *pnt++; - switch (encode) + if (type == ECOMMUNITY_ENCODE_AS || + type == ECOMMUNITY_ENCODE_IP || + type == ECOMMUNITY_ENCODE_AS4) { - case ECOMMUNITY_ENCODE_AS: - case ECOMMUNITY_ENCODE_IP: - case ECOMMUNITY_ENCODE_AS4: - break; - - case ECOMMUNITY_ENCODE_OPAQUE: - if(filter == ECOMMUNITY_ROUTE_TARGET) - { - continue; - } + /* Low-order octet of type. */ + sub_type = *pnt++; + if (sub_type != ECOMMUNITY_ROUTE_TARGET && + sub_type != ECOMMUNITY_SITE_ORIGIN) + unk_ecom = 1; + else + len = ecommunity_rt_soo_str (str_buf + str_pnt, pnt, type, + sub_type, format); + } + else if (type == ECOMMUNITY_ENCODE_OPAQUE) + { + if (filter == ECOMMUNITY_ROUTE_TARGET) + continue; if (*pnt == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP) { uint16_t tunneltype; memcpy (&tunneltype, pnt + 5, 2); tunneltype = ntohs(tunneltype); len = sprintf (str_buf + str_pnt, "ET:%d", tunneltype); - str_pnt += len; - first = 0; - continue; - } - len = sprintf (str_buf + str_pnt, "?"); - str_pnt += len; - first = 0; - continue; - case ECOMMUNITY_ENCODE_EVPN: - if(filter == ECOMMUNITY_ROUTE_TARGET) - { - continue; } + else + unk_ecom = 1; + } + else if (type == ECOMMUNITY_ENCODE_EVPN) + { + if (filter == ECOMMUNITY_ROUTE_TARGET) + continue; if (*pnt == ECOMMUNITY_SITE_ORIGIN) { char macaddr[6]; @@ -703,91 +793,20 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format, int filter) len = sprintf(str_buf + str_pnt, "EVPN:%02x:%02x:%02x:%02x:%02x:%02x", macaddr[0], macaddr[1], macaddr[2], macaddr[3], macaddr[4], macaddr[5]); - str_pnt += len; - first = 0; - continue; } - len = sprintf (str_buf + str_pnt, "?"); - str_pnt += len; - first = 0; - continue; - default: - len = sprintf (str_buf + str_pnt, "?"); - str_pnt += len; - first = 0; - continue; + else + unk_ecom = 1; } + else + unk_ecom = 1; - /* Low-order octet of type. */ - type = *pnt++; - if (type != ECOMMUNITY_ROUTE_TARGET && type != ECOMMUNITY_SITE_ORIGIN) - { - len = sprintf (str_buf + str_pnt, "?"); - str_pnt += len; - first = 0; - continue; - } + if (unk_ecom) + len = sprintf (str_buf + str_pnt, "?"); - switch (format) - { - case ECOMMUNITY_FORMAT_COMMUNITY_LIST: - prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "rt " : "soo "); - break; - case ECOMMUNITY_FORMAT_DISPLAY: - prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "RT:" : "SoO:"); - break; - case ECOMMUNITY_FORMAT_ROUTE_MAP: - prefix = ""; - break; - default: - prefix = ""; - break; - } - - /* Put string into buffer. */ - if (encode == ECOMMUNITY_ENCODE_AS4) - { - eas.as = (*pnt++ << 24); - eas.as |= (*pnt++ << 16); - eas.as |= (*pnt++ << 8); - eas.as |= (*pnt++); - - eas.val = (*pnt++ << 8); - eas.val |= (*pnt++); - - len = sprintf( str_buf + str_pnt, "%s%u:%u", prefix, - eas.as, eas.val ); - str_pnt += len; - first = 0; - } - if (encode == ECOMMUNITY_ENCODE_AS) - { - eas.as = (*pnt++ << 8); - eas.as |= (*pnt++); - - eas.val = (*pnt++ << 24); - eas.val |= (*pnt++ << 16); - eas.val |= (*pnt++ << 8); - eas.val |= (*pnt++); - - len = sprintf (str_buf + str_pnt, "%s%u:%u", prefix, - eas.as, eas.val); - str_pnt += len; - first = 0; - } - else if (encode == ECOMMUNITY_ENCODE_IP) - { - memcpy (&eip.ip, pnt, 4); - pnt += 4; - eip.val = (*pnt++ << 8); - eip.val |= (*pnt++); - - len = sprintf (str_buf + str_pnt, "%s%s:%u", prefix, - inet_ntoa (eip.ip), eip.val); - str_pnt += len; - first = 0; - } + str_pnt += len; + first = 0; } + return str_buf; } diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index d6006e81d5..8981ea3465 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -76,6 +76,54 @@ struct ecommunity_val #define ecom_length(X) ((X)->size * ECOMMUNITY_SIZE) +/* + * Encode BGP Route Target AS:nn. + */ +static inline void +encode_route_target_as (as_t as, u_int32_t val, + struct ecommunity_val *eval) +{ + eval->val[0] = ECOMMUNITY_ENCODE_AS; + eval->val[1] = ECOMMUNITY_ROUTE_TARGET; + eval->val[2] = (as >> 8) & 0xff; + eval->val[3] = as & 0xff; + eval->val[4] = (val >> 24) & 0xff; + eval->val[5] = (val >> 16) & 0xff; + eval->val[6] = (val >> 8) & 0xff; + eval->val[7] = val & 0xff; +} + +/* + * Encode BGP Route Target IP:nn. + */ +static inline void +encode_route_target_ip (struct in_addr ip, u_int16_t val, + struct ecommunity_val *eval) +{ + eval->val[0] = ECOMMUNITY_ENCODE_IP; + eval->val[1] = ECOMMUNITY_ROUTE_TARGET; + memcpy (&eval->val[2], &ip, sizeof (struct in_addr)); + eval->val[6] = (val >> 8) & 0xff; + eval->val[7] = val & 0xff; +} + +/* + * Encode BGP Route Target AS4:nn. + */ +static inline void +encode_route_target_as4 (as_t as, u_int16_t val, + struct ecommunity_val *eval) +{ + eval->val[0] = ECOMMUNITY_ENCODE_AS4; + eval->val[1] = ECOMMUNITY_ROUTE_TARGET; + eval->val[2] = (as >> 24) & 0xff; + eval->val[3] = (as >> 16) & 0xff; + eval->val[4] = (as >> 8) & 0xff; + eval->val[5] = as & 0xff; + eval->val[6] = (val >> 8) & 0xff; + eval->val[7] = val & 0xff; +} + extern void ecommunity_init (void); extern void ecommunity_finish (void); extern void ecommunity_free (struct ecommunity **); From 8557760ca8d05af9864a02bc2f4a244d02adf10c Mon Sep 17 00:00:00 2001 From: vivek Date: Mon, 15 May 2017 12:33:59 -0700 Subject: [PATCH 08/31] bgpd: Separate out RD handling functions BGP Route Distinguisher (RD) handling is common for different flavors of BGP VPNs such as BGP/MPLS IP VPNs (RFC 4364) and BGP EVPNs (RFC 7432). Separate out the RD handling functions into its own files. Note: No functional change introduced with this commit. Signed-off-by: Vivek Venkatraman Reviewed-by: Donald Sharp --- bgpd/Makefile.am | 4 +- bgpd/bgp_mplsvpn.c | 196 -------------------------------------- bgpd/bgp_mplsvpn.h | 46 +-------- bgpd/bgp_rd.c | 232 +++++++++++++++++++++++++++++++++++++++++++++ bgpd/bgp_rd.h | 74 +++++++++++++++ 5 files changed, 310 insertions(+), 242 deletions(-) create mode 100644 bgpd/bgp_rd.c create mode 100644 bgpd/bgp_rd.h diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index f096f0ff11..9a4e5fd6aa 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -83,7 +83,7 @@ libbgp_a_SOURCES = \ bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c \ bgp_nht.c bgp_updgrp.c bgp_updgrp_packet.c bgp_updgrp_adv.c bgp_bfd.c \ bgp_encap_tlv.c $(BGP_VNC_RFAPI_SRC) bgp_attr_evpn.c \ - bgp_evpn.c bgp_evpn_vty.c bgp_vpn.c bgp_label.c + bgp_evpn.c bgp_evpn_vty.c bgp_vpn.c bgp_label.c bgp_rd.c noinst_HEADERS = \ bgp_memory.h \ @@ -95,7 +95,7 @@ noinst_HEADERS = \ bgp_advertise.h bgp_vty.h bgp_mpath.h bgp_nht.h \ bgp_updgrp.h bgp_bfd.h bgp_encap_tlv.h bgp_encap_types.h \ $(BGP_VNC_RFAPI_HD) bgp_attr_evpn.h bgp_evpn.h bgp_evpn_vty.h \ - bgp_vpn.h bgp_label.h + bgp_vpn.h bgp_label.h bgp_rd.h bgpd_SOURCES = bgp_main.c bgpd_LDADD = libbgp.a $(BGP_VNC_RFP_LIB) ../lib/libfrr.la @LIBCAP@ @LIBM@ diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index b5fbfd8bb6..3973663e9d 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -62,31 +62,6 @@ argv_find_and_parse_vpnvx(struct cmd_token **argv, int argc, int *index, afi_t * return ret; } -u_int16_t -decode_rd_type (u_char *pnt) -{ - u_int16_t v; - - v = ((u_int16_t) *pnt++ << 8); -#if ENABLE_BGP_VNC - /* - * VNC L2 stores LHI in lower byte, so omit it - */ - if (v != RD_TYPE_VNC_ETH) - v |= (u_int16_t) *pnt; -#else /* duplicate code for clarity */ - v |= (u_int16_t) *pnt; -#endif - - return v; -} - -void -encode_rd_type (u_int16_t v, u_char *pnt) -{ - *((u_int16_t *)pnt) = htons(v); -} - u_int32_t decode_label (mpls_label_t *label_pnt) { @@ -111,54 +86,6 @@ encode_label(mpls_label_t label, *pnt++ = ((label<<4)+1) & 0xff; /* S=1 */ } -/* type == RD_TYPE_AS */ -void -decode_rd_as (u_char *pnt, struct rd_as *rd_as) -{ - rd_as->as = (u_int16_t) *pnt++ << 8; - rd_as->as |= (u_int16_t) *pnt++; - - rd_as->val = ((u_int32_t) *pnt++ << 24); - rd_as->val |= ((u_int32_t) *pnt++ << 16); - rd_as->val |= ((u_int32_t) *pnt++ << 8); - rd_as->val |= (u_int32_t) *pnt; -} - -/* type == RD_TYPE_AS4 */ -void -decode_rd_as4 (u_char *pnt, struct rd_as *rd_as) -{ - rd_as->as = (u_int32_t) *pnt++ << 24; - rd_as->as |= (u_int32_t) *pnt++ << 16; - rd_as->as |= (u_int32_t) *pnt++ << 8; - rd_as->as |= (u_int32_t) *pnt++; - - rd_as->val = ((u_int16_t) *pnt++ << 8); - rd_as->val |= (u_int16_t) *pnt; -} - -/* type == RD_TYPE_IP */ -void -decode_rd_ip (u_char *pnt, struct rd_ip *rd_ip) -{ - memcpy (&rd_ip->ip, pnt, 4); - pnt += 4; - - rd_ip->val = ((u_int16_t) *pnt++ << 8); - rd_ip->val |= (u_int16_t) *pnt; -} - -#if ENABLE_BGP_VNC -/* type == RD_TYPE_VNC_ETH */ -void -decode_rd_vnc_eth (u_char *pnt, struct rd_vnc_eth *rd_vnc_eth) -{ - rd_vnc_eth->type = RD_TYPE_VNC_ETH; - rd_vnc_eth->local_nve_id = pnt[1]; - memcpy (rd_vnc_eth->macaddr.octet, pnt + 2, ETHER_ADDR_LEN); -} -#endif - int bgp_nlri_parse_vpn (struct peer *peer, struct attr *attr, struct bgp_nlri *packet) @@ -313,129 +240,6 @@ bgp_nlri_parse_vpn (struct peer *peer, struct attr *attr, #undef VPN_PREFIXLEN_MIN_BYTES } -int -str2prefix_rd (const char *str, struct prefix_rd *prd) -{ - int ret; /* ret of called functions */ - int lret; /* local ret, of this func */ - char *p; - char *p2; - struct stream *s = NULL; - char *half = NULL; - struct in_addr addr; - - s = stream_new (8); - - prd->family = AF_UNSPEC; - prd->prefixlen = 64; - - lret = 0; - p = strchr (str, ':'); - if (! p) - goto out; - - if (! all_digit (p + 1)) - goto out; - - half = XMALLOC (MTYPE_TMP, (p - str) + 1); - memcpy (half, str, (p - str)); - half[p - str] = '\0'; - - p2 = strchr (str, '.'); - - if (! p2) - { - unsigned long as_val; - - if (! all_digit (half)) - goto out; - - as_val = atol(half); - if (as_val > 0xffff) - { - stream_putw (s, RD_TYPE_AS4); - stream_putl (s, as_val); - stream_putw (s, atol (p + 1)); - } - else - { - stream_putw (s, RD_TYPE_AS); - stream_putw (s, as_val); - stream_putl (s, atol (p + 1)); - } - } - else - { - ret = inet_aton (half, &addr); - if (! ret) - goto out; - - stream_putw (s, RD_TYPE_IP); - stream_put_in_addr (s, &addr); - stream_putw (s, atol (p + 1)); - } - memcpy (prd->val, s->data, 8); - lret = 1; - -out: - if (s) - stream_free (s); - if (half) - XFREE(MTYPE_TMP, half); - return lret; -} - -char * -prefix_rd2str (struct prefix_rd *prd, char *buf, size_t size) -{ - u_char *pnt; - u_int16_t type; - struct rd_as rd_as; - struct rd_ip rd_ip; - - if (size < RD_ADDRSTRLEN) - return NULL; - - pnt = prd->val; - - type = decode_rd_type (pnt); - - if (type == RD_TYPE_AS) - { - decode_rd_as (pnt + 2, &rd_as); - snprintf (buf, size, "%u:%d", rd_as.as, rd_as.val); - return buf; - } - else if (type == RD_TYPE_AS4) - { - decode_rd_as4 (pnt + 2, &rd_as); - snprintf (buf, size, "%u:%d", rd_as.as, rd_as.val); - return buf; - } - else if (type == RD_TYPE_IP) - { - decode_rd_ip (pnt + 2, &rd_ip); - snprintf (buf, size, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); - return buf; - } -#if ENABLE_BGP_VNC - else if (type == RD_TYPE_VNC_ETH) - { - snprintf(buf, size, "LHI:%d, %02x:%02x:%02x:%02x:%02x:%02x", - *(pnt+1), /* LHI */ - *(pnt+2), /* MAC[0] */ - *(pnt+3), - *(pnt+4), - *(pnt+5), - *(pnt+6), - *(pnt+7)); - - return buf; - } -#endif - return NULL; -} - /* For testing purpose, static route of MPLS-VPN. */ DEFUN (vpnv4_network, vpnv4_network_cmd, diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h index 4ba4597d06..eeb2f63ff3 100644 --- a/bgpd/bgp_mplsvpn.h +++ b/bgpd/bgp_mplsvpn.h @@ -1,7 +1,7 @@ /* MPLS-VPN * Copyright (C) 2000 Kunihiro Ishiguro * - * This file is part of GNU Zebra. + * This file is part of GxNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -22,15 +22,7 @@ #define _QUAGGA_BGP_MPLSVPN_H #include "bgpd/bgp_route.h" - -#define RD_TYPE_AS 0 -#define RD_TYPE_IP 1 -#define RD_TYPE_AS4 2 -#if ENABLE_BGP_VNC -#define RD_TYPE_VNC_ETH 0xff00 /* VNC L2VPN */ -#endif - -#define RD_ADDRSTRLEN 28 +#include "bgpd/bgp_rd.h" #ifdef MPLS_LABEL_MAX # undef MPLS_LABEL_MAX @@ -74,44 +66,10 @@ typedef enum { #define V4_HEADER_OVERLAY \ " Network Next Hop EthTag Overlay Index RouterMac" -struct rd_as -{ - u_int16_t type; - as_t as; - u_int32_t val; -}; - -struct rd_ip -{ - u_int16_t type; - struct in_addr ip; - u_int16_t val; -}; - -#if ENABLE_BGP_VNC -struct rd_vnc_eth -{ - u_int16_t type; - uint8_t local_nve_id; - struct ethaddr macaddr; -}; -#endif - -extern u_int16_t decode_rd_type (u_char *); -extern void encode_rd_type (u_int16_t, u_char *); extern void bgp_mplsvpn_init (void); extern int bgp_nlri_parse_vpn (struct peer *, struct attr *, struct bgp_nlri *); extern u_int32_t decode_label (mpls_label_t *); extern void encode_label(mpls_label_t, mpls_label_t *); -extern void decode_rd_as (u_char *, struct rd_as *); -extern void decode_rd_as4 (u_char *, struct rd_as *); -extern void decode_rd_ip (u_char *, struct rd_ip *); -#if ENABLE_BGP_VNC -extern void -decode_rd_vnc_eth (u_char *pnt, struct rd_vnc_eth *rd_vnc_eth); -#endif -extern int str2prefix_rd (const char *, struct prefix_rd *); -extern char *prefix_rd2str (struct prefix_rd *, char *, size_t); extern int argv_find_and_parse_vpnvx(struct cmd_token **argv, int argc, int *index, afi_t *afi); diff --git a/bgpd/bgp_rd.c b/bgpd/bgp_rd.c new file mode 100644 index 0000000000..03257a292f --- /dev/null +++ b/bgpd/bgp_rd.c @@ -0,0 +1,232 @@ +/* BGP RD definitions for BGP-based VPNs (IP/EVPN) + * -- brought over from bgpd/bgp_mplsvpn.c + * Copyright (C) 2000 Kunihiro Ishiguro + * + * 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 "command.h" +#include "log.h" +#include "prefix.h" +#include "memory.h" +#include "stream.h" +#include "filter.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_rd.h" +#include "bgpd/bgp_attr.h" + +#if ENABLE_BGP_VNC +#include "bgpd/rfapi/rfapi_backend.h" +#endif + +u_int16_t +decode_rd_type (u_char *pnt) +{ + u_int16_t v; + + v = ((u_int16_t) *pnt++ << 8); +#if ENABLE_BGP_VNC + /* + * VNC L2 stores LHI in lower byte, so omit it + */ + if (v != RD_TYPE_VNC_ETH) + v |= (u_int16_t) *pnt; +#else /* duplicate code for clarity */ + v |= (u_int16_t) *pnt; +#endif + return v; +} + +void +encode_rd_type (u_int16_t v, u_char *pnt) +{ + *((u_int16_t *)pnt) = htons(v); +} + +/* type == RD_TYPE_AS */ +void +decode_rd_as (u_char *pnt, struct rd_as *rd_as) +{ + rd_as->as = (u_int16_t) *pnt++ << 8; + rd_as->as |= (u_int16_t) *pnt++; + + rd_as->val = ((u_int32_t) *pnt++ << 24); + rd_as->val |= ((u_int32_t) *pnt++ << 16); + rd_as->val |= ((u_int32_t) *pnt++ << 8); + rd_as->val |= (u_int32_t) *pnt; +} + +/* type == RD_TYPE_AS4 */ +void +decode_rd_as4 (u_char *pnt, struct rd_as *rd_as) +{ + rd_as->as = (u_int32_t) *pnt++ << 24; + rd_as->as |= (u_int32_t) *pnt++ << 16; + rd_as->as |= (u_int32_t) *pnt++ << 8; + rd_as->as |= (u_int32_t) *pnt++; + + rd_as->val = ((u_int16_t) *pnt++ << 8); + rd_as->val |= (u_int16_t) *pnt; +} + +/* type == RD_TYPE_IP */ +void +decode_rd_ip (u_char *pnt, struct rd_ip *rd_ip) +{ + memcpy (&rd_ip->ip, pnt, 4); + pnt += 4; + + rd_ip->val = ((u_int16_t) *pnt++ << 8); + rd_ip->val |= (u_int16_t) *pnt; +} + +#if ENABLE_BGP_VNC +/* type == RD_TYPE_VNC_ETH */ +void +decode_rd_vnc_eth (u_char *pnt, struct rd_vnc_eth *rd_vnc_eth) +{ + rd_vnc_eth->type = RD_TYPE_VNC_ETH; + rd_vnc_eth->local_nve_id = pnt[1]; + memcpy (rd_vnc_eth->macaddr.octet, pnt + 2, ETHER_ADDR_LEN); +} +#endif + +int +str2prefix_rd (const char *str, struct prefix_rd *prd) +{ + int ret; /* ret of called functions */ + int lret; /* local ret, of this func */ + char *p; + char *p2; + struct stream *s = NULL; + char *half = NULL; + struct in_addr addr; + + s = stream_new (8); + + prd->family = AF_UNSPEC; + prd->prefixlen = 64; + + lret = 0; + p = strchr (str, ':'); + if (! p) + goto out; + + if (! all_digit (p + 1)) + goto out; + + half = XMALLOC (MTYPE_TMP, (p - str) + 1); + memcpy (half, str, (p - str)); + half[p - str] = '\0'; + + p2 = strchr (str, '.'); + + if (! p2) + { + unsigned long as_val; + + if (! all_digit (half)) + goto out; + + as_val = atol(half); + if (as_val > 0xffff) + { + stream_putw (s, RD_TYPE_AS4); + stream_putl (s, as_val); + stream_putw (s, atol (p + 1)); + } + else + { + stream_putw (s, RD_TYPE_AS); + stream_putw (s, as_val); + stream_putl (s, atol (p + 1)); + } + } + else + { + ret = inet_aton (half, &addr); + if (! ret) + goto out; + + stream_putw (s, RD_TYPE_IP); + stream_put_in_addr (s, &addr); + stream_putw (s, atol (p + 1)); + } + memcpy (prd->val, s->data, 8); + lret = 1; + +out: + if (s) + stream_free (s); + if (half) + XFREE(MTYPE_TMP, half); + return lret; +} + +char * +prefix_rd2str (struct prefix_rd *prd, char *buf, size_t size) +{ + u_char *pnt; + u_int16_t type; + struct rd_as rd_as; + struct rd_ip rd_ip; + + if (size < RD_ADDRSTRLEN) + return NULL; + + pnt = prd->val; + + type = decode_rd_type (pnt); + + if (type == RD_TYPE_AS) + { + decode_rd_as (pnt + 2, &rd_as); + snprintf (buf, size, "%u:%d", rd_as.as, rd_as.val); + return buf; + } + else if (type == RD_TYPE_AS4) + { + decode_rd_as4 (pnt + 2, &rd_as); + snprintf (buf, size, "%u:%d", rd_as.as, rd_as.val); + return buf; + } + else if (type == RD_TYPE_IP) + { + decode_rd_ip (pnt + 2, &rd_ip); + snprintf (buf, size, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); + return buf; + } +#if ENABLE_BGP_VNC + else if (type == RD_TYPE_VNC_ETH) + { + snprintf(buf, size, "LHI:%d, %02x:%02x:%02x:%02x:%02x:%02x", + *(pnt+1), /* LHI */ + *(pnt+2), /* MAC[0] */ + *(pnt+3), + *(pnt+4), + *(pnt+5), + *(pnt+6), + *(pnt+7)); + + return buf; + } +#endif + return NULL; +} diff --git a/bgpd/bgp_rd.h b/bgpd/bgp_rd.h new file mode 100644 index 0000000000..2c7df9d742 --- /dev/null +++ b/bgpd/bgp_rd.h @@ -0,0 +1,74 @@ +/* BGP RD definitions for BGP-based VPNs (IP/EVPN) + * -- brought over from bgpd/bgp_mplsvpn.h + * Copyright (C) 2000 Kunihiro Ishiguro + * + * 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 _QUAGGA_BGP_RD_H +#define _QUAGGA_BGP_RD_H + +/* RD types */ +#define RD_TYPE_AS 0 +#define RD_TYPE_IP 1 +#define RD_TYPE_AS4 2 + +#if ENABLE_BGP_VNC +#define RD_TYPE_VNC_ETH 0xff00 /* VNC L2VPN */ +#endif + +#define RD_ADDRSTRLEN 28 + +struct rd_as +{ + u_int16_t type; + as_t as; + u_int32_t val; +}; + +struct rd_ip +{ + u_int16_t type; + struct in_addr ip; + u_int16_t val; +}; + +#if ENABLE_BGP_VNC +struct rd_vnc_eth +{ + u_int16_t type; + uint8_t local_nve_id; + struct ethaddr macaddr; +}; +#endif + +extern u_int16_t decode_rd_type (u_char *pnt); +extern void encode_rd_type (u_int16_t, u_char *); + +extern void decode_rd_as (u_char *pnt, struct rd_as *rd_as); +extern void decode_rd_as4 (u_char *pnt, struct rd_as *rd_as); +extern void decode_rd_ip (u_char *pnt, struct rd_ip *rd_ip); +#if ENABLE_BGP_VNC +extern void +decode_rd_vnc_eth (u_char *pnt, struct rd_vnc_eth *rd_vnc_eth); +#endif + +extern int str2prefix_rd (const char *, struct prefix_rd *); +extern char *prefix_rd2str (struct prefix_rd *, char *, size_t); + +#endif /* _QUAGGA_BGP_RD_H */ From a463860968519d5399470b77eb9ac239e8e8e75c Mon Sep 17 00:00:00 2001 From: vivek Date: Mon, 15 May 2017 12:35:15 -0700 Subject: [PATCH 09/31] bgpd: Display extended communities in debug log Signed-off-by: Vivek Venkatraman Reviewed-by: Donald Sharp --- bgpd/bgp_debug.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 5538402070..450f68fec4 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -39,6 +39,7 @@ #include "bgpd/bgp_community.h" #include "bgpd/bgp_updgrp.h" #include "bgpd/bgp_mplsvpn.h" +#include "bgpd/bgp_ecommunity.h" unsigned long conf_bgp_debug_as4; unsigned long conf_bgp_debug_neighbor_events; @@ -423,6 +424,10 @@ bgp_dump_attr (struct attr *attr, char *buf, size_t size) snprintf (buf + strlen (buf), size - strlen (buf), ", community %s", community_str (attr->community)); + if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES))) + snprintf (buf + strlen (buf), size - strlen (buf), ", extcommunity %s", + ecommunity_str (attr->extra->ecommunity)); + if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))) snprintf (buf + strlen (buf), size - strlen (buf), ", atomic-aggregate"); From 86f6f09e2e546ea93e550cf9028bd8f6237bcb38 Mon Sep 17 00:00:00 2001 From: vivek Date: Mon, 15 May 2017 13:47:36 -0700 Subject: [PATCH 10/31] bgpd: Function to encode Encapsulation type extended community Signed-off-by: Vivek Venkatraman --- bgpd/bgp_encap_types.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/bgpd/bgp_encap_types.h b/bgpd/bgp_encap_types.h index ffeb2f61ea..03664fe7a0 100644 --- a/bgpd/bgp_encap_types.h +++ b/bgpd/bgp_encap_types.h @@ -19,6 +19,8 @@ #ifndef _QUAGGA_BGP_ENCAP_TYPES_H #define _QUAGGA_BGP_ENCAP_TYPES_H +#include "bgpd/bgp_ecommunity.h" + /* from http://www.iana.org/assignments/bgp-parameters/bgp-parameters.xhtml#tunnel-types */ typedef enum { BGP_ENCAP_TYPE_RESERVED=0, @@ -213,4 +215,15 @@ struct bgp_encap_type_pbb { struct bgp_tea_subtlv_encap_pbb st_encap; }; +static inline void +encode_encap_extcomm (bgp_encap_types tnl_type, + struct ecommunity_val *eval) +{ + memset (eval, 0, sizeof (*eval)); + eval->val[0] = ECOMMUNITY_ENCODE_OPAQUE; + eval->val[1] = ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP; + eval->val[6] = ((tnl_type) >> 8) & 0xff; + eval->val[7] = (tnl_type) & 0xff; +} + #endif /* _QUAGGA_BGP_ENCAP_TYPES_H */ From 58cf4b28ff00d1ebb6a64e79393f5faa11567ac3 Mon Sep 17 00:00:00 2001 From: vivek Date: Mon, 15 May 2017 13:48:18 -0700 Subject: [PATCH 11/31] bgpd: Fix check for martian next hops Ensure that the check for martian next hop is correct, including for MP nexthops, if IPv4. Signed-off-by: Vivek Venkatraman Reviewed-by: Donald Sharp --- bgpd/bgp_nexthop.c | 4 ++-- bgpd/bgp_nexthop.h | 2 +- bgpd/bgp_route.c | 7 ++++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index d0c4d2c945..ed3594e7a0 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -329,11 +329,11 @@ bgp_connected_delete (struct bgp *bgp, struct connected *ifc) } int -bgp_nexthop_self (struct bgp *bgp, struct attr *attr) +bgp_nexthop_self (struct bgp *bgp, struct in_addr nh_addr) { struct bgp_addr tmp, *addr; - tmp.addr = attr->nexthop; + tmp.addr = nh_addr; addr = hash_lookup (bgp->address_hash, &tmp); if (addr) diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h index c5d9232e33..3aa20a9d5b 100644 --- a/bgpd/bgp_nexthop.h +++ b/bgpd/bgp_nexthop.h @@ -74,7 +74,7 @@ extern void bgp_connected_add (struct bgp *bgp, struct connected *c); extern void bgp_connected_delete (struct bgp *bgp, struct connected *c); extern int bgp_multiaccess_check_v4 (struct in_addr, struct peer *); extern int bgp_config_write_scan_time (struct vty *); -extern int bgp_nexthop_self (struct bgp *, struct attr *); +extern int bgp_nexthop_self (struct bgp *, struct in_addr); extern struct bgp_nexthop_cache *bnc_new(void); extern void bnc_free(struct bgp_nexthop_cache *bnc); extern void bnc_nexthop_free(struct bgp_nexthop_cache *bnc); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 12ad65883e..d72da431f1 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2442,8 +2442,8 @@ bgp_update_martian_nexthop (struct bgp *bgp, afi_t afi, safi_t safi, struct attr { if (attr->nexthop.s_addr == 0 || IPV4_CLASS_DE (ntohl (attr->nexthop.s_addr)) || - bgp_nexthop_self (bgp, attr)) - ret = 1; + bgp_nexthop_self (bgp, attr->nexthop)) + return 1; } /* If MP_NEXTHOP is present, validate it. */ @@ -2458,7 +2458,8 @@ bgp_update_martian_nexthop (struct bgp *bgp, afi_t afi, safi_t safi, struct attr case BGP_ATTR_NHLEN_IPV4: case BGP_ATTR_NHLEN_VPNV4: ret = (attre->mp_nexthop_global_in.s_addr == 0 || - IPV4_CLASS_DE (ntohl (attre->mp_nexthop_global_in.s_addr))); + IPV4_CLASS_DE (ntohl (attre->mp_nexthop_global_in.s_addr)) || + bgp_nexthop_self (bgp, attre->mp_nexthop_global_in)); break; case BGP_ATTR_NHLEN_IPV6_GLOBAL: From 3684a40babc05156b84ff4a28842f43a98c65ecc Mon Sep 17 00:00:00 2001 From: vivek Date: Wed, 24 May 2017 14:57:34 -0700 Subject: [PATCH 12/31] bgpd: Fix next hop setting for EVPN The next hop for EVPN routes must be an IPv4 or IPv6 address as per RFC 7432. Ensure this is correctly handled. Also, ensure there are correct checks for AFI_L2VPN and nexthop AFI is not AFI_L2VPN. Signed-off-by: Vivek Venkatraman --- bgpd/bgp_attr.c | 55 +++++++++------------------------------- bgpd/bgp_updgrp_packet.c | 10 +++----- 2 files changed, 16 insertions(+), 49 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 439469d61e..9ceded921a 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2841,16 +2841,14 @@ bgp_packet_mpattr_start (struct stream *s, struct peer *peer, stream_putc (s, pkt_safi); /* SAFI */ /* Nexthop AFI */ - if (peer_cap_enhe(peer, afi, safi)) { - nh_afi = AFI_IP6; - } else { - if (afi == AFI_L2VPN) - nh_afi = AFI_L2VPN; - else if (safi == SAFI_LABELED_UNICAST) - nh_afi = afi; - else - nh_afi = BGP_NEXTHOP_AFI_FROM_NHLEN(attr->extra->mp_nexthop_len); - } + if (afi == AFI_IP && safi == SAFI_UNICAST) + { + nh_afi = peer_cap_enhe (peer, afi, safi) ? AFI_IP6 : AFI_IP; + } + else if (safi == SAFI_LABELED_UNICAST) + nh_afi = afi; + else + nh_afi = BGP_NEXTHOP_AFI_FROM_NHLEN(attr->extra->mp_nexthop_len); /* Nexthop */ bpacket_attr_vec_arr_set_vec (vecarr, BGP_ATTR_VEC_NH, s, attr); @@ -2872,6 +2870,7 @@ bgp_packet_mpattr_start (struct stream *s, struct peer *peer, stream_put (s, &attr->extra->mp_nexthop_global_in, 4); break; case SAFI_ENCAP: + case SAFI_EVPN: stream_putc (s, 4); stream_put (s, &attr->extra->mp_nexthop_global_in, 4); break; @@ -2885,6 +2884,7 @@ bgp_packet_mpattr_start (struct stream *s, struct peer *peer, case SAFI_UNICAST: case SAFI_MULTICAST: case SAFI_LABELED_UNICAST: + case SAFI_EVPN: { struct attr_extra *attre = attr->extra; @@ -2930,40 +2930,9 @@ bgp_packet_mpattr_start (struct stream *s, struct peer *peer, break; } break; - case AFI_L2VPN: - switch (safi) - { - case SAFI_EVPN: - if (attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV4) - { - stream_putc (s, 12); - stream_putl (s, 0); /* RD = 0, per RFC */ - stream_putl (s, 0); - stream_put (s, &attr->extra->mp_nexthop_global_in, 4); - } - else if (attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL) - { - stream_putc (s, 24); - stream_putl (s, 0); /* RD = 0, per RFC */ - stream_putl (s, 0); - stream_put (s, &attr->extra->mp_nexthop_global, IPV6_MAX_BYTELEN); - } - else if (attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) - { - stream_putc (s, 48); - stream_putl (s, 0); /* RD = 0, per RFC */ - stream_putl (s, 0); - stream_put (s, &attr->extra->mp_nexthop_global, IPV6_MAX_BYTELEN); - stream_putl (s, 0); /* RD = 0, per RFC */ - stream_putl (s, 0); - stream_put (s, &attr->extra->mp_nexthop_local, IPV6_MAX_BYTELEN); - } - break; - break; - default: - break; - } default: + zlog_err ("Bad nexthop when sening to %s, AFI %u SAFI %u nhlen %d", + peer->host, afi, safi, attr->extra->mp_nexthop_len); break; } diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index dff46a9466..cecb844fce 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -423,12 +423,10 @@ bpacket_reformat_for_peer (struct bpacket *pkt, struct peer_af *paf) afi_t nhafi = AFI_MAX; /* NH AFI is based on nhlen! */ int route_map_sets_nh; nhlen = stream_getc_from (s, vec->offset); - if (paf->afi == AFI_IP || paf->afi == AFI_IP6) - { - nhafi = BGP_NEXTHOP_AFI_FROM_NHLEN(nhlen); - if (peer_cap_enhe(peer, paf->afi, paf->safi)) - nhafi = AFI_IP6; - } + if (peer_cap_enhe(peer, paf->afi, paf->safi)) + nhafi = AFI_IP6; + else + nhafi = BGP_NEXTHOP_AFI_FROM_NHLEN(nhlen); if (nhafi == AFI_IP) { From a4168ebce797e7cc6a2ef716a1d2ef371d9791b9 Mon Sep 17 00:00:00 2001 From: vivek Date: Mon, 15 May 2017 14:27:09 -0700 Subject: [PATCH 13/31] bgpd: EVPN definitions Define the EVPN (EVI) hash table and objects for mapping route targets to EVIs. Signed-off-by: Vivek Venkatraman Signed-off-by: Mitesh Kanjariya Signed-off-by: Daniel Walton --- bgpd/Makefile.am | 2 +- bgpd/bgp_evpn_private.h | 97 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 bgpd/bgp_evpn_private.h diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index 9a4e5fd6aa..0ec5a778bb 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -95,7 +95,7 @@ noinst_HEADERS = \ bgp_advertise.h bgp_vty.h bgp_mpath.h bgp_nht.h \ bgp_updgrp.h bgp_bfd.h bgp_encap_tlv.h bgp_encap_types.h \ $(BGP_VNC_RFAPI_HD) bgp_attr_evpn.h bgp_evpn.h bgp_evpn_vty.h \ - bgp_vpn.h bgp_label.h bgp_rd.h + bgp_vpn.h bgp_label.h bgp_rd.h bgp_evpn_private.h bgpd_SOURCES = bgp_main.c bgpd_LDADD = libbgp.a $(BGP_VNC_RFP_LIB) ../lib/libfrr.la @LIBCAP@ @LIBM@ diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h new file mode 100644 index 0000000000..e9e8a75e28 --- /dev/null +++ b/bgpd/bgp_evpn_private.h @@ -0,0 +1,97 @@ +/* BGP EVPN internal definitions + * Copyright (C) 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 _BGP_EVPN_PRIVATE_H +#define _BGP_EVPN_PRIVATE_H + +#include "vxlan.h" +#include "zebra.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_ecommunity.h" + +/* EVPN prefix lengths. */ +#define EVPN_TYPE_2_ROUTE_PREFIXLEN 224 +#define EVPN_TYPE_3_ROUTE_PREFIXLEN 224 + +/* EVPN route types. */ +typedef enum +{ + BGP_EVPN_AD_ROUTE = 1, /* Ethernet Auto-Discovery (A-D) route */ + BGP_EVPN_MAC_IP_ROUTE, /* MAC/IP Advertisement route */ + BGP_EVPN_IMET_ROUTE, /* Inclusive Multicast Ethernet Tag route */ + BGP_EVPN_ES_ROUTE, /* Ethernet Segment route */ + BGP_EVPN_IP_PREFIX_ROUTE, /* IP Prefix route */ +} bgp_evpn_route_type; + +/* + * Hash table of EVIs. Right now, the only type of EVI supported is with + * VxLAN encapsulation, hence each EVI corresponds to a L2 VNI. + * The VNIs are not "created" through BGP but through some other interface + * on the system. This table stores VNIs that BGP comes to know as present + * on the system (through interaction with zebra) as well as pre-configured + * VNIs (which need to be defined in the system to become "live"). + */ +struct bgpevpn +{ + vni_t vni; + u_int32_t flags; +#define VNI_FLAG_CFGD 0x1 /* VNI is user configured */ +#define VNI_FLAG_LIVE 0x2 /* VNI is "live" */ +#define VNI_FLAG_RD_CFGD 0x4 /* RD is user configured. */ +#define VNI_FLAG_IMPRT_CFGD 0x8 /* Import RT is user configured */ +#define VNI_FLAG_EXPRT_CFGD 0x10 /* Export RT is user configured */ + + /* Id for deriving the RD automatically for this VNI */ + u_int16_t rd_id; + + /* RD for this VNI. */ + struct prefix_rd prd; + + /* Route type 3 field */ + struct in_addr originator_ip; + + /* Import and Export RTs. */ + struct list *import_rtl; + struct list *export_rtl; + + /* Route table for EVPN routes for this VNI. */ + struct bgp_table *route_table; + + QOBJ_FIELDS +}; + +DECLARE_QOBJ_TYPE(bgpevpn) + +/* Mapping of Import RT to VNIs. + * The Import RTs of all VNIs are maintained in a hash table with each + * RT linking to all VNIs that will import routes matching this RT. + */ +struct irt_node +{ + /* RT */ + struct ecommunity_val rt; + + /* List of VNIs importing routes matching this RT. */ + struct list *vnis; +}; + +#endif /* _BGP_EVPN_PRIVATE_H */ From 14c1a7bf91f39b72d60df322518bfc48114798b6 Mon Sep 17 00:00:00 2001 From: vivek Date: Mon, 15 May 2017 14:27:51 -0700 Subject: [PATCH 14/31] bgpd: EVPN initialization and cleanup Define the EVPN (EVI) hash table and related structures and initialize and cleanup. Signed-off-by: Vivek Venkatraman Reviewed-by: Donald Sharp --- bgpd/bgp_evpn.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++++ bgpd/bgp_evpn.h | 6 +++ bgpd/bgpd.c | 4 ++ bgpd/bgpd.h | 15 ++++++ 4 files changed, 152 insertions(+) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 34a3315c0c..6e6e696a9a 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -26,6 +26,9 @@ #include "log.h" #include "memory.h" #include "stream.h" +#include "hash.h" +#include "jhash.h" +#include "bitfield.h" #include "bgpd/bgp_attr_evpn.h" #include "bgpd/bgpd.h" @@ -35,6 +38,92 @@ #include "bgpd/bgp_mplsvpn.h" #include "bgpd/bgp_label.h" #include "bgpd/bgp_evpn.h" +#include "bgpd/bgp_evpn_private.h" +#include "bgpd/bgp_ecommunity.h" + +/* + * Private functions. + */ + +/* + * Make vni hash key. + */ +static unsigned int +vni_hash_key_make(void *p) +{ + struct bgpevpn *vpn = p; + return (jhash_1word(vpn->vni, 0)); +} + +/* + * Comparison function for vni hash + */ +static int +vni_hash_cmp (const void *p1, const void *p2) +{ + const struct bgpevpn *vpn1 = p1; + const struct bgpevpn *vpn2 = p2; + + if (!vpn1 && !vpn2) + return 1; + if (!vpn1 || !vpn2) + return 0; + return(vpn1->vni == vpn2->vni); +} + +/* + * Make import route target hash key. + */ +static unsigned int +import_rt_hash_key_make (void *p) +{ + struct irt_node *irt = p; + char *pnt = irt->rt.val; + unsigned int key = 0; + int c=0; + + key += pnt[c]; + key += pnt[c + 1]; + key += pnt[c + 2]; + key += pnt[c + 3]; + key += pnt[c + 4]; + key += pnt[c + 5]; + key += pnt[c + 6]; + key += pnt[c + 7]; + + return (key); +} + +/* + * Comparison function for import rt hash + */ +static int +import_rt_hash_cmp (const void *p1, const void *p2) +{ + const struct irt_node *irt1 = p1; + const struct irt_node *irt2 = p2; + + if (irt1 == NULL && irt2 == NULL) + return 1; + + if (irt1 == NULL || irt2 == NULL) + return 0; + + return(memcmp(irt1->rt.val, irt2->rt.val, ECOMMUNITY_SIZE) == 0); +} + +/* + * Free a VNI entry; iterator function called during cleanup. + */ +static void +free_vni_entry (struct hash_backet *backet, struct bgp *bgp) +{ +} + + +/* + * Public functions. + */ int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr, @@ -225,3 +314,41 @@ bgp_packet_mpattr_route_type_5(struct stream *s, stream_put3(s, 0); return; } + +/* + * Cleanup EVPN information - invoked at the time of bgpd exit or when the + * BGP instance (default) is being freed. + */ +void +bgp_evpn_cleanup (struct bgp *bgp) +{ + hash_iterate (bgp->vnihash, + (void (*) (struct hash_backet *, void *)) + free_vni_entry, bgp); + hash_free (bgp->import_rt_hash); + bgp->import_rt_hash = NULL; + hash_free (bgp->vnihash); + bgp->vnihash = NULL; + bf_free (bgp->rd_idspace); +} + +/* + * Initialization for EVPN + * Create + * VNI hash table + * hash for RT to VNI + * unique rd id space for auto derivation of RD for VNIs + */ +void +bgp_evpn_init (struct bgp *bgp) +{ + bgp->vnihash = hash_create (vni_hash_key_make, + vni_hash_cmp, + "BGP VNI Hash"); + bgp->import_rt_hash = hash_create (import_rt_hash_key_make, + import_rt_hash_cmp, + "BGP Import RT Hash"); + bf_init (bgp->rd_idspace, UINT16_MAX); + /*assign 0th index in the bitfield, so that we start with id 1*/ + bf_assign_zero_index (bgp->rd_idspace); +} diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index feabc9cd27..8a4e27c0cb 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -28,6 +28,12 @@ extern void bgp_packet_mpattr_route_type_5(struct stream *s, struct prefix *p, struct prefix_rd *prd, mpls_label_t *label, struct attr *attr); + +extern void +bgp_evpn_cleanup (struct bgp *bgp); +extern void +bgp_evpn_init (struct bgp *bgp); + /* EVPN route types as per RFC7432 and * as per draft-ietf-bess-evpn-prefix-advertisement-02 */ diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index d7ddd5db8a..87912693f2 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -241,6 +241,7 @@ bgp_router_id_set (struct bgp *bgp, const struct in_addr *id) BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } + return 0; } @@ -3004,6 +3005,7 @@ bgp_create (as_t *as, const char *name, enum bgp_instance_type inst_type) QOBJ_REG (bgp, bgp); update_bgp_group_init(bgp); + bgp_evpn_init(bgp); return bgp; } @@ -3355,6 +3357,8 @@ bgp_free (struct bgp *bgp) bgp_scan_finish (bgp); bgp_address_destroy (bgp); + bgp_evpn_cleanup (bgp); + if (bgp->name) XFREE(MTYPE_BGP, bgp->name); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 5dc25d00a9..31aa6163b0 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -33,6 +33,7 @@ #include "linklist.h" #include "defaults.h" #include "bgp_memory.h" +#include "bitfield.h" #define BGP_MAX_HOSTNAME 64 /* Linux max, is larger than most other sys */ @@ -367,6 +368,20 @@ struct bgp struct rfapi *rfapi; #endif + /* EVPN related information */ + + /* EVI hash table */ + struct hash *vnihash; + + /* EVPN enable - advertise local VNIs and their MACs etc. */ + int advertise_all_vni; + + /* Hash table of Import RTs to EVIs */ + struct hash *import_rt_hash; + + /* Id space for automatic RD derivation for an EVI */ + bitfield_t rd_idspace; + QOBJ_FIELDS }; DECLARE_QOBJ_TYPE(bgp) From 7724c0a1a7e40a70fe3c3dd51c4a0c0792892264 Mon Sep 17 00:00:00 2001 From: vivek Date: Mon, 15 May 2017 14:30:19 -0700 Subject: [PATCH 15/31] bgpd: Implement EVPN enable/disable Implement the command 'advertise-all-vni' under the EVPN address-family in order to allow the local system to learn about local VNIs (and MACs and Neighbors corresponding to those VNIs) and exchange with other EVPN speakers. Signed-off-by: Vivek Venkatraman Reviewed-by: Donald Sharp Reviewed-by: Dinesh Dutt --- bgpd/bgp_evpn.c | 20 +++++++++++ bgpd/bgp_evpn.h | 2 ++ bgpd/bgp_evpn_vty.c | 83 ++++++++++++++++++++++++++++++++++++--------- bgpd/bgp_vty.c | 4 +++ bgpd/bgp_zebra.c | 33 ++++++++++++++++++ bgpd/bgp_zebra.h | 2 ++ 6 files changed, 128 insertions(+), 16 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 6e6e696a9a..0e191ffff1 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -112,6 +112,14 @@ import_rt_hash_cmp (const void *p1, const void *p2) return(memcmp(irt1->rt.val, irt2->rt.val, ECOMMUNITY_SIZE) == 0); } +/* + * Cleanup specific VNI upon EVPN (advertise-all-vni) being disabled. + */ +static void +cleanup_vni_on_disable (struct hash_backet *backet, struct bgp *bgp) +{ +} + /* * Free a VNI entry; iterator function called during cleanup. */ @@ -315,6 +323,18 @@ bgp_packet_mpattr_route_type_5(struct stream *s, return; } +/* + * Cleanup EVPN information on disable - Need to delete and withdraw + * EVPN routes from peers. + */ +void +bgp_evpn_cleanup_on_disable (struct bgp *bgp) +{ + hash_iterate (bgp->vnihash, + (void (*) (struct hash_backet *, void *)) + cleanup_vni_on_disable, bgp); +} + /* * Cleanup EVPN information - invoked at the time of bgpd exit or when the * BGP instance (default) is being freed. diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index 8a4e27c0cb..c87f3ffc77 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -29,6 +29,8 @@ bgp_packet_mpattr_route_type_5(struct stream *s, struct prefix *p, struct prefix_rd *prd, mpls_label_t *label, struct attr *attr); +extern void +bgp_evpn_cleanup_on_disable (struct bgp *bgp); extern void bgp_evpn_cleanup (struct bgp *bgp); extern void diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index d22a07ed31..ac1faf9de1 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -31,6 +31,8 @@ #include "bgpd/bgp_vpn.h" #include "bgpd/bgp_evpn_vty.h" #include "bgpd/bgp_evpn.h" +#include "bgpd/bgp_evpn_private.h" +#include "bgpd/bgp_zebra.h" #define SHOW_DISPLAY_STANDARD 0 #define SHOW_DISPLAY_TAGS 1 @@ -716,22 +718,71 @@ DEFUN(no_evpnrt5_network, argv[idx_ethtag]->arg); } +/* + * EVPN (VNI advertisement) enabled. Register with zebra. + */ +static void +evpn_set_advertise_all_vni (struct bgp *bgp) +{ + bgp->advertise_all_vni = 1; + bgp_zebra_advertise_all_vni (bgp, bgp->advertise_all_vni); +} + +/* + * EVPN (VNI advertisement) disabled. De-register with zebra. Cleanup VNI + * cache, EVPN routes (delete and withdraw from peers). + */ +static void +evpn_unset_advertise_all_vni (struct bgp *bgp) +{ + bgp->advertise_all_vni = 0; + bgp_zebra_advertise_all_vni (bgp, bgp->advertise_all_vni); + bgp_evpn_cleanup_on_disable (bgp); +} + +DEFUN (bgp_evpn_advertise_all_vni, + bgp_evpn_advertise_all_vni_cmd, + "advertise-all-vni", + "Advertise All local VNIs\n") +{ + struct bgp *bgp = VTY_GET_CONTEXT(bgp); + + if (!bgp) + return CMD_WARNING; + evpn_set_advertise_all_vni (bgp); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_evpn_advertise_all_vni, + no_bgp_evpn_advertise_all_vni_cmd, + "no advertise-all-vni", + NO_STR + "Advertise All local VNIs\n") +{ + struct bgp *bgp = VTY_GET_CONTEXT(bgp); + + if (!bgp) + return CMD_WARNING; + evpn_unset_advertise_all_vni (bgp); + return CMD_SUCCESS; +} + void bgp_ethernetvpn_init(void) { - install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_cmd); - install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_cmd); - install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_tags_cmd); - install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_tags_cmd); - install_element(VIEW_NODE, - &show_ip_bgp_l2vpn_evpn_all_neighbor_routes_cmd); - install_element(VIEW_NODE, - &show_ip_bgp_l2vpn_evpn_rd_neighbor_routes_cmd); - install_element(VIEW_NODE, - &show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes_cmd); - install_element(VIEW_NODE, - &show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes_cmd); - install_element(VIEW_NODE, &show_ip_bgp_evpn_rd_overlay_cmd); - install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_overlay_cmd); - install_element(BGP_EVPN_NODE, &no_evpnrt5_network_cmd); - install_element(BGP_EVPN_NODE, &evpnrt5_network_cmd); + install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_cmd); + install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_cmd); + install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_tags_cmd); + install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_tags_cmd); + install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_neighbor_routes_cmd); + install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_neighbor_routes_cmd); + install_element(VIEW_NODE, + &show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes_cmd); + install_element(VIEW_NODE, + &show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes_cmd); + install_element(VIEW_NODE, &show_ip_bgp_evpn_rd_overlay_cmd); + install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_overlay_cmd); + install_element(BGP_EVPN_NODE, &no_evpnrt5_network_cmd); + install_element(BGP_EVPN_NODE, &evpnrt5_network_cmd); + install_element (BGP_EVPN_NODE, &bgp_evpn_advertise_all_vni_cmd); + install_element (BGP_EVPN_NODE, &no_bgp_evpn_advertise_all_vni_cmd); } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 83135fb5dc..75b4739956 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -11286,6 +11286,8 @@ bgp_vty_init (void) install_element (BGP_VPNV4_NODE, &no_neighbor_route_reflector_client_cmd); install_element (BGP_VPNV6_NODE, &neighbor_route_reflector_client_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_route_reflector_client_cmd); + install_element (BGP_EVPN_NODE, &neighbor_route_reflector_client_cmd); + install_element (BGP_EVPN_NODE, &no_neighbor_route_reflector_client_cmd); /* "neighbor route-server" commands.*/ install_element (BGP_NODE, &neighbor_route_server_client_hidden_cmd); @@ -11659,6 +11661,8 @@ bgp_vty_init (void) install_element (BGP_VPNV4_NODE, &no_neighbor_allowas_in_cmd); install_element (BGP_VPNV6_NODE, &neighbor_allowas_in_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_allowas_in_cmd); + install_element (BGP_EVPN_NODE, &neighbor_allowas_in_cmd); + install_element (BGP_EVPN_NODE, &no_neighbor_allowas_in_cmd); /* address-family commands. */ install_element (BGP_NODE, &address_family_ipv4_safi_cmd); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 71a4d4317a..19f0dd98ff 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -2033,6 +2033,11 @@ bgp_zebra_instance_register (struct bgp *bgp) /* Register for router-id, interfaces, redistributed routes. */ zclient_send_reg_requests (zclient, bgp->vrf_id); + + /* For default instance, register to learn about VNIs, if appropriate. */ + if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT + && bgp->advertise_all_vni) + bgp_zebra_advertise_all_vni (bgp, 1); } /* Deregister this instance with Zebra. Invoked upon the instance @@ -2048,6 +2053,11 @@ bgp_zebra_instance_deregister (struct bgp *bgp) if (BGP_DEBUG (zebra, ZEBRA)) zlog_debug("Deregistering VRF %u", bgp->vrf_id); + /* For default instance, unregister learning about VNIs, if appropriate. */ + if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT + && bgp->advertise_all_vni) + bgp_zebra_advertise_all_vni (bgp, 0); + /* Deregister for router-id, interfaces, redistributed routes. */ zclient_send_dereg_requests (zclient, bgp->vrf_id); } @@ -2080,6 +2090,29 @@ bgp_zebra_terminate_radv (struct bgp *bgp, struct peer *peer) zclient_send_interface_radv_req (zclient, bgp->vrf_id, peer->ifp, 0, 0); } +int +bgp_zebra_advertise_all_vni (struct bgp *bgp, int advertise) +{ + struct stream *s; + + /* Check socket. */ + if (!zclient || zclient->sock < 0) + return 0; + + /* Don't try to register if Zebra doesn't know of this instance. */ + if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) + return 0; + + s = zclient->obuf; + stream_reset (s); + + zclient_create_header (s, ZEBRA_ADVERTISE_ALL_VNI, bgp->vrf_id); + stream_putc(s, advertise); + stream_putw_at (s, 0, stream_get_endp (s)); + + return zclient_send_message(zclient); +} + /* BGP has established connection with Zebra. */ static void bgp_zebra_connected (struct zclient *zclient) diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index 3d634ed695..7ad1f706d6 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -54,6 +54,8 @@ extern struct interface *if_lookup_by_ipv4_exact (struct in_addr *, vrf_id_t); extern struct interface *if_lookup_by_ipv6 (struct in6_addr *, ifindex_t, vrf_id_t); extern struct interface *if_lookup_by_ipv6_exact (struct in6_addr *, ifindex_t, vrf_id_t); +extern int bgp_zebra_advertise_all_vni (struct bgp *, int); + extern int bgp_zebra_num_connects(void); #endif /* _QUAGGA_BGP_ZEBRA_H */ From abddf7583c3f174aec7d4d6cdbef6dc15fb07723 Mon Sep 17 00:00:00 2001 From: vivek Date: Mon, 15 May 2017 14:31:57 -0700 Subject: [PATCH 16/31] bgpd: Install or remove only relevant routes from zebra Ensure that the AFI/SAFI is relevant to the FIB before attempting to install or remove the route from zebra. Signed-off-by: Vivek Venkatraman --- bgpd/bgp_route.c | 12 ++++++++---- bgpd/bgp_routemap.c | 3 +++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index d72da431f1..ca6d138eaa 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1933,7 +1933,8 @@ bgp_process_main (struct work_queue *wq, void *data) for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { - bgp_zebra_announce_table(bgp, afi, safi); + if (bgp_fibupd_safi(safi)) + bgp_zebra_announce_table(bgp, afi, safi); } bgp->main_peers_update_hold = 0; @@ -3562,7 +3563,8 @@ bgp_cleanup_table(struct bgp_table *table, safi_t safi) && (ri->sub_type == BGP_ROUTE_NORMAL || ri->sub_type == BGP_ROUTE_AGGREGATE)) { - bgp_zebra_withdraw (&rn->p, ri, safi); + if (bgp_fibupd_safi(safi)) + bgp_zebra_withdraw (&rn->p, ri, safi); bgp_info_reap (rn, ri); } } @@ -4787,7 +4789,8 @@ bgp_table_map_set (struct vty *vty, afi_t afi, safi_t safi, rmap->map = NULL; } - bgp_zebra_announce_table(bgp, afi, safi); + if (bgp_fibupd_safi(safi)) + bgp_zebra_announce_table(bgp, afi, safi); return CMD_SUCCESS; } @@ -4805,7 +4808,8 @@ bgp_table_map_unset (struct vty *vty, afi_t afi, safi_t safi, rmap->name = NULL; rmap->map = NULL; - bgp_zebra_announce_table(bgp, afi, safi); + if (bgp_fibupd_safi(safi)) + bgp_zebra_announce_table(bgp, afi, safi); return CMD_SUCCESS; } diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index f2c94371a4..b0a3cc677d 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -3112,6 +3112,9 @@ bgp_route_map_process_update (struct bgp *bgp, const char *rmap_name, int route_ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { /* For table route-map updates. */ + if (!bgp_fibupd_safi(safi)) + continue; + if (bgp->table_map[afi][safi].name && (strcmp(rmap_name, bgp->table_map[afi][safi].name) == 0)) { From 5b4168879d8e0cd663e4a4a7660f841d1e038d66 Mon Sep 17 00:00:00 2001 From: vivek Date: Mon, 15 May 2017 14:32:38 -0700 Subject: [PATCH 17/31] lib: Define handlers for VNI and MACIP Define client handlers for processing add or delete of local VNIs and local MACIPs. Signed-off-by: Vivek Venkatraman --- lib/zclient.c | 16 ++++++++++++++++ lib/zclient.h | 4 ++++ 2 files changed, 20 insertions(+) diff --git a/lib/zclient.c b/lib/zclient.c index 679b7004c0..efe8f56628 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -2047,6 +2047,22 @@ zclient_read (struct thread *thread) if (zclient->fec_update) (*zclient->fec_update) (command, zclient, length); break; + case ZEBRA_VNI_ADD: + if (zclient->local_vni_add) + (*zclient->local_vni_add) (command, zclient, length, vrf_id); + break; + case ZEBRA_VNI_DEL: + if (zclient->local_vni_del) + (*zclient->local_vni_del) (command, zclient, length, vrf_id); + break; + case ZEBRA_MACIP_ADD: + if (zclient->local_macip_add) + (*zclient->local_macip_add) (command, zclient, length, vrf_id); + break; + case ZEBRA_MACIP_DEL: + if (zclient->local_macip_del) + (*zclient->local_macip_del) (command, zclient, length, vrf_id); + break; default: break; } diff --git a/lib/zclient.h b/lib/zclient.h index 2191be2c2f..c7cc857ef7 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -176,6 +176,10 @@ struct zclient int (*redistribute_route_ipv6_add) (int, struct zclient *, uint16_t, vrf_id_t); int (*redistribute_route_ipv6_del) (int, struct zclient *, uint16_t, vrf_id_t); int (*fec_update) (int, struct zclient *, uint16_t); + int (*local_vni_add) (int, struct zclient *, uint16_t, vrf_id_t); + int (*local_vni_del) (int, struct zclient *, uint16_t, vrf_id_t); + int (*local_macip_add) (int, struct zclient *, uint16_t, vrf_id_t); + int (*local_macip_del) (int, struct zclient *, uint16_t, vrf_id_t); }; /* Zebra API message flag. */ From 0ee26848f37d44ca5f1285e05f06bedd975a851c Mon Sep 17 00:00:00 2001 From: vivek Date: Wed, 24 May 2017 17:50:29 -0700 Subject: [PATCH 18/31] bgpd: Additional check on presence of tag/label In the case of EVPN, not all EVPN routes will necessarily have a tag/label. Do an additional check on presence of tag, where needed. Signed-off-by: Vivek Venkatraman --- bgpd/bgp_label.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bgpd/bgp_label.h b/bgpd/bgp_label.h index c98f4531f6..a0994d68a3 100644 --- a/bgpd/bgp_label.h +++ b/bgpd/bgp_label.h @@ -41,6 +41,9 @@ extern int bgp_nlri_parse_label (struct peer *peer, struct attr *attr, static inline int bgp_labeled_safi (safi_t safi) { + /* NOTE: This API really says a label (tag) MAY be present. Not all EVPN + * routes will have a label. + */ if ((safi == SAFI_LABELED_UNICAST) || (safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN)) return 1; From 128ea8abbd38eddd2a9bfa18b596acd95f081353 Mon Sep 17 00:00:00 2001 From: vivek Date: Mon, 15 May 2017 14:34:04 -0700 Subject: [PATCH 19/31] bgpd: EVPN route handling Core EVPN route handling functionality. This includes support for the following: - interface with zebra to learn about local VNIs and MACIPs as well as to install remote VTEPs (per VNI) and remote MACIPs - create/update/delete EVPN type-2 and type-3 routes - attribute creation, route selection and install - route handling per VNI and for the global routing table - parsing of received EVPN routes and handling by route type - encoding attributes for EVPN routes and EVPN prefix creation (for Updates) Signed-off-by: Vivek Venkatraman Reviewed-by: Donald Sharp Reviewed-by: Daniel Walton --- bgpd/bgp_attr.c | 11 +- bgpd/bgp_attr.h | 12 + bgpd/bgp_attr_evpn.c | 186 +-- bgpd/bgp_attr_evpn.h | 42 +- bgpd/bgp_ecommunity.h | 3 + bgpd/bgp_evpn.c | 2465 ++++++++++++++++++++++++++++++++++--- bgpd/bgp_evpn.h | 40 +- bgpd/bgp_evpn_private.h | 127 ++ bgpd/bgp_evpn_vty.c | 4 +- bgpd/bgp_memory.c | 4 + bgpd/bgp_memory.h | 4 + bgpd/bgp_route.c | 194 ++- bgpd/bgp_route.h | 32 +- bgpd/bgp_updgrp_packet.c | 24 + bgpd/bgp_zebra.c | 82 ++ bgpd/rfapi/rfapi_import.c | 4 +- 16 files changed, 2923 insertions(+), 311 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 9ceded921a..e5bebfff7d 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2136,6 +2136,9 @@ bgp_attr_ext_communities (struct bgp_attr_parser_args *args) attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); + /* Extract MAC mobility sequence number, if any. */ + attr->extra->mm_seqnum = bgp_attr_mac_mobility_seqnum (attr); + return BGP_ATTR_PARSE_PROCEED; } @@ -2957,9 +2960,11 @@ bgp_packet_mpattr_prefix (struct stream *s, afi_t afi, safi_t safi, stream_put (s, prd->val, 8); stream_put (s, &p->u.prefix, PSIZE (p->prefixlen)); } - else if (safi == SAFI_EVPN) + else if (afi == AFI_L2VPN && safi == SAFI_EVPN) { - bgp_packet_mpattr_route_type_5(s, p, prd, label, attr); + /* EVPN prefix - contents depend on type */ + bgp_evpn_encode_prefix (s, p, prd, label, attr, + addpath_encode, addpath_tx_id); } else if (safi == SAFI_LABELED_UNICAST) { @@ -2976,6 +2981,8 @@ bgp_packet_mpattr_prefix_size (afi_t afi, safi_t safi, struct prefix *p) int size = PSIZE (p->prefixlen); if (safi == SAFI_MPLS_VPN) size += 88; + else if (afi == AFI_L2VPN && safi == SAFI_EVPN) + size += 232; // TODO: Maximum possible for type-2, type-3 and type-5 return size; } diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index f3c1b5e3c2..c7dca435ba 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -140,6 +140,9 @@ struct attr_extra /* MP Nexthop preference */ u_char mp_nexthop_prefer_global; + /* Static MAC for EVPN */ + u_char sticky; + /* route tag */ route_tag_t tag; @@ -157,6 +160,9 @@ struct attr_extra #endif /* EVPN */ struct overlay_index evpn_overlay; + + /* EVPN MAC Mobility sequence number, if any. */ + u_int32_t mm_seqnum; }; /* BGP core attribute structure. */ @@ -333,4 +339,10 @@ bgp_rmap_nhop_changed(u_int32_t out_rmap_flags, u_int32_t in_rmap_flags) CHECK_FLAG(in_rmap_flags, BATTR_RMAP_NEXTHOP_UNCHANGED)) ? 1 : 0); } +static inline u_int32_t +mac_mobility_seqnum (struct attr *attr) +{ + return (attr && attr->extra) ? attr->extra->mm_seqnum : 0; +} + #endif /* _QUAGGA_BGP_ATTR_H */ diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index 6970d5a679..740f517a9e 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -33,21 +33,23 @@ #include "bgpd/bgp_attr_evpn.h" #include "bgpd/bgp_ecommunity.h" #include "bgpd/bgp_evpn.h" +#include "bgpd/bgp_evpn_private.h" void bgp_add_routermac_ecom(struct attr *attr, struct ethaddr *routermac) { - struct ecommunity_val routermac_ecom; + struct ecommunity_val routermac_ecom; - if (attr->extra) { - memset(&routermac_ecom, 0, sizeof(struct ecommunity_val)); - routermac_ecom.val[0] = ECOMMUNITY_ENCODE_EVPN; - routermac_ecom.val[1] = ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC; - memcpy(&routermac_ecom.val[2], routermac->octet, ETHER_ADDR_LEN); - if (!attr->extra->ecommunity) - attr->extra->ecommunity = ecommunity_new(); - ecommunity_add_val(attr->extra->ecommunity, &routermac_ecom); - ecommunity_str (attr->extra->ecommunity); - } + if (attr->extra) + { + memset(&routermac_ecom, 0, sizeof(struct ecommunity_val)); + routermac_ecom.val[0] = ECOMMUNITY_ENCODE_EVPN; + routermac_ecom.val[1] = ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC; + memcpy(&routermac_ecom.val[2], routermac->octet, ETHER_ADDR_LEN); + if (!attr->extra->ecommunity) + attr->extra->ecommunity = ecommunity_new(); + ecommunity_add_val(attr->extra->ecommunity, &routermac_ecom); + ecommunity_str (attr->extra->ecommunity); + } } /* converts to an esi @@ -57,85 +59,131 @@ void bgp_add_routermac_ecom(struct attr *attr, struct ethaddr *routermac) */ int str2esi(const char *str, struct eth_segment_id *id) { - unsigned int a[ESI_LEN]; - int i; + unsigned int a[ESI_LEN]; + int i; - if (!str) - return 0; - if (sscanf (str, "%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x", - a + 0, a + 1, a + 2, a + 3, a + 4, a + 5, - a + 6, a + 7, a + 8, a + 9) != ESI_LEN) - { - /* error in incoming str length */ - return 0; - } - /* valid mac address */ - if (!id) - return 1; - for (i = 0; i < ESI_LEN; ++i) - id->val[i] = a[i] & 0xff; - return 1; + if (!str) + return 0; + if (sscanf (str, "%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x", + a + 0, a + 1, a + 2, a + 3, a + 4, a + 5, + a + 6, a + 7, a + 8, a + 9) != ESI_LEN) + { + /* error in incoming str length */ + return 0; + } + /* valid mac address */ + if (!id) + return 1; + for (i = 0; i < ESI_LEN; ++i) + id->val[i] = a[i] & 0xff; + return 1; } char *esi2str(struct eth_segment_id *id) { - char *ptr; - u_char *val; + char *ptr; + u_char *val; - if (!id) - return NULL; + if (!id) + return NULL; - val = id->val; - ptr = (char *)XMALLOC(MTYPE_TMP, (ESI_LEN * 2 + ESI_LEN - 1 + 1) * sizeof(char)); + val = id->val; + ptr = (char *)XMALLOC(MTYPE_TMP, (ESI_LEN * 2 + ESI_LEN - 1 + 1) * sizeof(char)); - snprintf(ptr, (ESI_LEN * 2 + ESI_LEN - 1 + 1), - "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", - val[0], val[1], val[2], val[3], val[4], - val[5], val[6], val[7], val[8], val[9]); + snprintf(ptr, (ESI_LEN * 2 + ESI_LEN - 1 + 1), + "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", + val[0], val[1], val[2], val[3], val[4], + val[5], val[6], val[7], val[8], val[9]); - return ptr; + return ptr; } char *ecom_mac2str(char *ecom_mac) { - char *en; + char *en; - en = ecom_mac; - en += 2; - return prefix_mac2str((struct ethaddr *)en, NULL, 0); + en = ecom_mac; + en += 2; + + return prefix_mac2str((struct ethaddr *)en, NULL, 0); +} + +/* + * Fetch and return the sequence number from MAC Mobility extended + * community, if present, else 0. + */ +u_int32_t +bgp_attr_mac_mobility_seqnum (struct attr *attr) +{ + struct ecommunity *ecom; + int i; + + ecom = attr->extra->ecommunity; + if (!ecom || !ecom->size) + return 0; + + /* If there is a MAC Mobility extended community, return its + * sequence number. + * TODO: RFC is silent on handling of multiple MAC mobility extended + * communities for the same route. We will bail out upon the first + * one. + */ + for (i = 0; i < ecom->size; i++) + { + u_char *pnt; + u_char type, sub_type; + u_int32_t seq_num; + + pnt = (ecom->val + (i * ECOMMUNITY_SIZE)); + type = *pnt++; + sub_type = *pnt++; + if (!(type == ECOMMUNITY_ENCODE_EVPN && + sub_type == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY)) + continue; + pnt++; + pnt++; + seq_num = (*pnt++ << 24); + seq_num |= (*pnt++ << 16); + seq_num |= (*pnt++ << 8); + seq_num |= (*pnt++); + + return seq_num; + } + + return 0; } /* dst prefix must be AF_INET or AF_INET6 prefix, to forge EVPN prefix */ extern int bgp_build_evpn_prefix(int evpn_type, uint32_t eth_tag, struct prefix *dst) { - struct evpn_addr *p_evpn_p; - struct prefix p2; - struct prefix *src = &p2; + struct evpn_addr *p_evpn_p; + struct prefix p2; + struct prefix *src = &p2; - if (!dst || dst->family == 0) - return -1; - /* store initial prefix in src */ - prefix_copy(src, dst); - memset(dst, 0, sizeof(struct prefix)); - p_evpn_p = &(dst->u.prefix_evpn); - dst->family = AF_ETHERNET; - p_evpn_p->route_type = evpn_type; - if (evpn_type == EVPN_IP_PREFIX) { - p_evpn_p->eth_tag = eth_tag; - p_evpn_p->ip_prefix_length = p2.prefixlen; - if (src->family == AF_INET) { + if (!dst || dst->family == 0) + return -1; + /* store initial prefix in src */ + prefix_copy(src, dst); + memset(dst, 0, sizeof(struct prefix)); + p_evpn_p = &(dst->u.prefix_evpn); + dst->family = AF_ETHERNET; + p_evpn_p->route_type = evpn_type; + if (evpn_type == BGP_EVPN_IP_PREFIX_ROUTE) { + p_evpn_p->eth_tag = eth_tag; + p_evpn_p->ip_prefix_length = p2.prefixlen; + if (src->family == AF_INET) { SET_IPADDR_V4 (&p_evpn_p->ip); - memcpy(&p_evpn_p->ip.ipaddr_v4, &src->u.prefix4, - sizeof(struct in_addr)); - dst->prefixlen = (u_char) PREFIX_LEN_ROUTE_TYPE_5_IPV4; - } else { + memcpy(&p_evpn_p->ip.ipaddr_v4, &src->u.prefix4, + sizeof(struct in_addr)); + dst->prefixlen = (u_char) PREFIX_LEN_ROUTE_TYPE_5_IPV4; + } else { SET_IPADDR_V6 (&p_evpn_p->ip); - memcpy(&p_evpn_p->ip.ipaddr_v6, &src->u.prefix6, - sizeof(struct in6_addr)); - dst->prefixlen = (u_char) PREFIX_LEN_ROUTE_TYPE_5_IPV6; - } - } else - return -1; - return 0; + memcpy(&p_evpn_p->ip.ipaddr_v6, &src->u.prefix6, + sizeof(struct in6_addr)); + dst->prefixlen = (u_char) PREFIX_LEN_ROUTE_TYPE_5_IPV6; + } + } else + return -1; + return 0; } diff --git a/bgpd/bgp_attr_evpn.h b/bgpd/bgp_attr_evpn.h index 3a93f6ae62..8978731d5c 100644 --- a/bgpd/bgp_attr_evpn.h +++ b/bgpd/bgp_attr_evpn.h @@ -22,31 +22,37 @@ #define _QUAGGA_BGP_ATTR_EVPN_H /* value of first byte of ESI */ -#define ESI_TYPE_ARBITRARY 0 /* */ -#define ESI_TYPE_LACP 1 /* <> */ -#define ESI_TYPE_BRIDGE 2 /* ::00 */ -#define ESI_TYPE_MAC 3 /* : */ -#define ESI_TYPE_ROUTER 4 /* : */ -#define ESI_TYPE_AS 5 /* : */ +#define ESI_TYPE_ARBITRARY 0 /* */ +#define ESI_TYPE_LACP 1 /* <> */ +#define ESI_TYPE_BRIDGE 2 /* ::00 */ +#define ESI_TYPE_MAC 3 /* : */ +#define ESI_TYPE_ROUTER 4 /* : */ +#define ESI_TYPE_AS 5 /* : */ + + #define MAX_ESI {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff} #define ESI_LEN 10 #define MAX_ET 0xffffffff + u_long eth_tag_id; struct attr; -struct eth_segment_id { - u_char val[ESI_LEN]; +struct eth_segment_id +{ + u_char val[ESI_LEN]; }; -union gw_addr { - struct in_addr ipv4; - struct in6_addr ipv6; +union gw_addr +{ + struct in_addr ipv4; + struct in6_addr ipv6; }; -struct bgp_route_evpn { - struct eth_segment_id eth_s_id; - union gw_addr gw_ip; +struct bgp_route_evpn +{ + struct eth_segment_id eth_s_id; + union gw_addr gw_ip; }; extern int str2esi(const char *str, struct eth_segment_id *id); @@ -55,5 +61,9 @@ extern char *ecom_mac2str(char *ecom_mac); extern void bgp_add_routermac_ecom(struct attr *attr, struct ethaddr *routermac); extern int bgp_build_evpn_prefix(int type, uint32_t eth_tag, - struct prefix *dst); -#endif /* _QUAGGA_BGP_ATTR_EVPN_H */ + struct prefix *dst); + +extern u_int32_t +bgp_attr_mac_mobility_seqnum (struct attr *attr); + +#endif /* _QUAGGA_BGP_ATTR_EVPN_H */ diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index 8981ea3465..9281c0d995 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -32,12 +32,15 @@ #define ECOMMUNITY_ROUTE_TARGET 0x02 #define ECOMMUNITY_SITE_ORIGIN 0x03 +/* Low-order octet of the Extended Communities type field for EVPN types */ #define ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY 0x00 #define ECOMMUNITY_EVPN_SUBTYPE_ESI_LABEL 0x01 #define ECOMMUNITY_EVPN_SUBTYPE_ES_IMPORT_RT 0x02 #define ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC 0x03 #define ECOMMUNITY_EVPN_SUBTYPE_DEF_GW 0x0d +#define ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY 0x01 + /* Low-order octet of the Extended Communities type field for OPAQUE types */ #define ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP 0x0c diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 0e191ffff1..d021def1b8 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1,7 +1,8 @@ /* Ethernet-VPN Packet and vty Processing File * Copyright (C) 2016 6WIND + * Copyright (C) 2017 Cumulus Networks, Inc. * - * This file is part of FRRouting. + * This file is part of FRR. * * FRRouting is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -29,6 +30,7 @@ #include "hash.h" #include "jhash.h" #include "bitfield.h" +#include "zclient.h" #include "bgpd/bgp_attr_evpn.h" #include "bgpd/bgpd.h" @@ -40,6 +42,27 @@ #include "bgpd/bgp_evpn.h" #include "bgpd/bgp_evpn_private.h" #include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_encap_types.h" +#include "bgpd/bgp_debug.h" +#include "bgpd/bgp_aspath.h" + +/* + * Definitions and external declarations. + */ +extern struct zclient *zclient; + +DEFINE_QOBJ_TYPE(bgpevpn) + + +/* + * Static function declarations + */ +static void +delete_evpn_route_entry (struct bgp *bgp, struct bgpevpn *vpn, + afi_t afi, safi_t safi, struct bgp_node *rn, + struct bgp_info **ri); +static int +delete_all_vni_routes (struct bgp *bgp, struct bgpevpn *vpn); /* * Private functions. @@ -112,12 +135,1758 @@ import_rt_hash_cmp (const void *p1, const void *p2) return(memcmp(irt1->rt.val, irt2->rt.val, ECOMMUNITY_SIZE) == 0); } +/* + * Create a new import_rt + */ +static struct irt_node * +import_rt_new (struct bgp *bgp, struct ecommunity_val *rt) +{ + struct irt_node *irt; + + if (!bgp) + return NULL; + + irt = XCALLOC (MTYPE_BGP_EVPN_IMPORT_RT, sizeof (struct irt_node)); + if (!irt) + return NULL; + + irt->rt = *rt; + irt->vnis = list_new (); + + /* Add to hash */ + if (!hash_get(bgp->import_rt_hash, irt, hash_alloc_intern)) + { + XFREE(MTYPE_BGP_EVPN_IMPORT_RT, irt); + return NULL; + } + + return irt; +} + +/* + * Free the import rt node + */ +static void +import_rt_free (struct bgp *bgp, struct irt_node *irt) +{ + hash_release(bgp->import_rt_hash, irt); + XFREE(MTYPE_BGP_EVPN_IMPORT_RT, irt); +} + +/* + * Function to lookup Import RT node - used to map a RT to set of + * VNIs importing routes with that RT. + */ +static struct irt_node * +lookup_import_rt (struct bgp *bgp, struct ecommunity_val *rt) +{ + struct irt_node *irt; + struct irt_node tmp; + + memset(&tmp, 0, sizeof(struct irt_node)); + memcpy(&tmp.rt, rt, ECOMMUNITY_SIZE); + irt = hash_lookup(bgp->import_rt_hash, &tmp); + return irt; +} + +/* + * Is specified VNI present on the RT's list of "importing" VNIs? + */ +static int +is_vni_present_in_irt_vnis (struct list *vnis, struct bgpevpn *vpn) +{ + struct listnode *node, *nnode; + struct bgpevpn *tmp_vpn; + + for (ALL_LIST_ELEMENTS (vnis, node, nnode, tmp_vpn)) + { + if (tmp_vpn == vpn) + return 1; + } + + return 0; +} + +/* + * Compare Route Targets. + */ +static int +evpn_route_target_cmp (struct ecommunity *ecom1, struct ecommunity *ecom2) +{ + if (ecom1 && !ecom2) + return -1; + + if (!ecom1 && ecom2) + return 1; + + if (!ecom1 && !ecom2) + return 0; + + if (ecom1->str && !ecom2->str) + return -1; + + if (!ecom1->str && ecom2->str) + return 1; + + if (!ecom1->str && !ecom2->str) + return 0; + + return strcmp(ecom1->str, ecom2->str); +} + +/* + * Mask off global-admin field of specified extended community (RT), + * just retain the local-admin field. + */ +static inline void +mask_ecom_global_admin (struct ecommunity_val *dst, + struct ecommunity_val *src) +{ + u_char type; + + type = src->val[0]; + dst->val[0] = 0; + if (type == ECOMMUNITY_ENCODE_AS) + { + dst->val[2] = dst->val[3] = 0; + } + else if (type == ECOMMUNITY_ENCODE_AS4 || + type == ECOMMUNITY_ENCODE_IP) + { + dst->val[2] = dst->val[3] = 0; + dst->val[4] = dst->val[5] = 0; + } +} + +/* + * Map one RT to specified VNI. + */ +static void +map_vni_to_rt (struct bgp *bgp, struct bgpevpn *vpn, + struct ecommunity_val *eval) +{ + struct irt_node *irt; + struct ecommunity_val eval_tmp; + + /* If using "automatic" RT, we only care about the local-admin sub-field. + * This is to facilitate using VNI as the RT for EBGP peering too. + */ + memcpy (&eval_tmp, eval, ECOMMUNITY_SIZE); + if (!is_import_rt_configured (vpn)) + mask_ecom_global_admin (&eval_tmp, eval); + + irt = lookup_import_rt (bgp, &eval_tmp); + if (irt && irt->vnis) + if (is_vni_present_in_irt_vnis (irt->vnis, vpn)) + /* Already mapped. */ + return; + + if (!irt) + { + irt = import_rt_new (bgp, &eval_tmp); + assert (irt); + } + + /* Add VNI to the hash list for this RT. */ + listnode_add (irt->vnis, vpn); +} + +/* + * Unmap specified VNI from specified RT. If there are no other + * VNIs for this RT, then the RT hash is deleted. + */ +static void +unmap_vni_from_rt (struct bgp *bgp, struct bgpevpn *vpn, + struct irt_node *irt) +{ + /* Delete VNI from hash list for this RT. */ + listnode_delete (irt->vnis, vpn); + if (!listnode_head (irt->vnis)) + { + list_free (irt->vnis); + import_rt_free (bgp, irt); + } +} + +/* + * Create RT extended community automatically from passed information: + * of the form AS:VNI. + * NOTE: We use only the lower 16 bits of the AS. This is sufficient as + * the need is to get a RT value that will be unique across different + * VNIs but the same across routers (in the same AS) for a particular + * VNI. + */ +static void +form_auto_rt (struct bgp *bgp, struct bgpevpn *vpn, + struct list *rtl) +{ + struct ecommunity_val eval; + struct ecommunity *ecomadd; + + encode_route_target_as ((bgp->as & 0xFFFF), vpn->vni, &eval); + + ecomadd = ecommunity_new (); + ecommunity_add_val (ecomadd, &eval); + listnode_add_sort (rtl, ecomadd); +} + +/* + * Derive RD and RT for a VNI automatically. Invoked at the time of + * creation of a VNI. + */ +static void +derive_rd_rt_for_vni (struct bgp *bgp, struct bgpevpn *vpn) +{ + bgp_evpn_derive_auto_rd (bgp, vpn); + bgp_evpn_derive_auto_rt_import (bgp, vpn); + bgp_evpn_derive_auto_rt_export (bgp, vpn); +} + +/* + * Add (update) or delete MACIP from zebra. + */ +static int +bgp_zebra_send_remote_macip (struct bgp *bgp, struct bgpevpn *vpn, + struct prefix_evpn *p, + struct in_addr remote_vtep_ip, + int add) +{ + struct stream *s; + int ipa_len; + char buf1[ETHER_ADDR_STRLEN]; + char buf2[INET6_ADDRSTRLEN]; + char buf3[INET6_ADDRSTRLEN]; + + /* Check socket. */ + if (!zclient || zclient->sock < 0) + return 0; + + /* Don't try to register if Zebra doesn't know of this instance. */ + if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) + return 0; + + s = zclient->obuf; + stream_reset (s); + + zclient_create_header (s, add ? ZEBRA_REMOTE_MACIP_ADD : ZEBRA_REMOTE_MACIP_DEL, + bgp->vrf_id); + stream_putl(s, vpn->vni); + stream_put (s, &p->prefix.mac.octet, ETHER_ADDR_LEN); /* Mac Addr */ + /* IP address length and IP address, if any. */ + if (IS_EVPN_PREFIX_IPADDR_NONE(p)) + stream_putl(s, 0); + else + { + ipa_len = IS_EVPN_PREFIX_IPADDR_V4(p) ? + IPV4_MAX_BYTELEN : IPV6_MAX_BYTELEN; + stream_putl(s, ipa_len); + stream_put (s, &p->prefix.ip.ip.addr, ipa_len); + } + stream_put_in_addr(s, &remote_vtep_ip); + + stream_putw_at (s, 0, stream_get_endp (s)); + + if (bgp_debug_zebra (NULL)) + zlog_debug("Tx %s MACIP, VNI %u MAC %s IP %s remote VTEP %s", + add ? "ADD" : "DEL", vpn->vni, + prefix_mac2str (&p->prefix.mac, buf1, sizeof(buf1)), + ipaddr2str (&p->prefix.ip, buf3, sizeof(buf3)), + inet_ntop(AF_INET, &remote_vtep_ip, buf2, sizeof(buf2))); + + return zclient_send_message(zclient); +} + +/* + * Add (update) or delete remote VTEP from zebra. + */ +static int +bgp_zebra_send_remote_vtep (struct bgp *bgp, struct bgpevpn *vpn, + struct prefix_evpn *p, int add) +{ + struct stream *s; + + /* Check socket. */ + if (!zclient || zclient->sock < 0) + return 0; + + /* Don't try to register if Zebra doesn't know of this instance. */ + if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) + return 0; + + s = zclient->obuf; + stream_reset (s); + + zclient_create_header (s, add ? ZEBRA_REMOTE_VTEP_ADD : ZEBRA_REMOTE_VTEP_DEL, + bgp->vrf_id); + stream_putl(s, vpn->vni); + if (IS_EVPN_PREFIX_IPADDR_V4(p)) + stream_put_in_addr(s, &p->prefix.ip.ipaddr_v4); + else if (IS_EVPN_PREFIX_IPADDR_V6(p)) + { + zlog_err ("Bad remote IP when trying to %s remote VTEP for VNI %u", + add ? "ADD" : "DEL", vpn->vni); + return -1; + } + + stream_putw_at (s, 0, stream_get_endp (s)); + + if (bgp_debug_zebra (NULL)) + zlog_debug("Tx %s Remote VTEP, VNI %u remote VTEP %s", + add ? "ADD" : "DEL", vpn->vni, + inet_ntoa (p->prefix.ip.ipaddr_v4)); + + return zclient_send_message(zclient); +} + +/* + * Build extended communities for EVPN route. RT and ENCAP are + * applicable to all routes. + */ +static void +build_evpn_route_extcomm (struct bgpevpn *vpn, struct attr *attr) +{ + struct attr_extra *attre; + struct ecommunity ecom_encap; + struct ecommunity_val eval; + bgp_encap_types tnl_type; + struct listnode *node, *nnode; + struct ecommunity *ecom; + + attre = bgp_attr_extra_get (attr); + + /* Encap */ + tnl_type = BGP_ENCAP_TYPE_VXLAN; + memset (&ecom_encap, 0, sizeof (ecom_encap)); + encode_encap_extcomm (tnl_type, &eval); + ecom_encap.size = 1; + ecom_encap.val = (u_int8_t *)eval.val; + + /* Add Encap */ + attre->ecommunity = ecommunity_dup (&ecom_encap); + + /* Add the export RTs */ + for (ALL_LIST_ELEMENTS (vpn->export_rtl, node, nnode, ecom)) + attre->ecommunity = ecommunity_merge (attre->ecommunity, ecom); + + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); +} + +/* + * Add MAC mobility extended community to attribute. + */ +static void +add_mac_mobility_to_attr (u_int32_t seq_num, struct attr *attr) +{ + struct attr_extra *attre; + struct ecommunity ecom_tmp; + struct ecommunity_val eval; + struct ecommunity *ecom_mm; + int i; + u_int8_t *pnt; + int type = 0; + int sub_type = 0; + + attre = bgp_attr_extra_get (attr); + + /* Build MM */ + encode_mac_mobility_extcomm (0, seq_num, &eval); + + /* Find current MM ecommunity */ + ecom_mm = NULL; + + if (attre->ecommunity) + { + for (i = 0; i < attre->ecommunity->size; i++) + { + pnt = attre->ecommunity->val + (i * 8); + type = *pnt++; + sub_type = *pnt++; + + if (type == ECOMMUNITY_ENCODE_EVPN && sub_type == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY) + { + ecom_mm = (struct ecommunity*) attre->ecommunity->val + (i * 8); + break; + } + } + } + + /* Update the existing MM ecommunity */ + if (ecom_mm) + { + memcpy(ecom_mm->val, eval.val, sizeof(char) * ECOMMUNITY_SIZE); + } + + /* Add MM to existing */ + else + { + memset (&ecom_tmp, 0, sizeof (ecom_tmp)); + ecom_tmp.size = 1; + ecom_tmp.val = (u_int8_t *)eval.val; + + attre->ecommunity = ecommunity_merge (attre->ecommunity, &ecom_tmp); + } +} + +/* Install EVPN route into zebra. */ +static int +evpn_zebra_install (struct bgp *bgp, struct bgpevpn *vpn, + struct prefix_evpn *p, struct in_addr remote_vtep_ip) +{ + int ret; + + if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) + ret = bgp_zebra_send_remote_macip (bgp, vpn, p, remote_vtep_ip, 1); + else + ret = bgp_zebra_send_remote_vtep (bgp, vpn, p, 1); + + return ret; +} + +/* Uninstall EVPN route from zebra. */ +static int +evpn_zebra_uninstall (struct bgp *bgp, struct bgpevpn *vpn, + struct prefix_evpn *p, struct in_addr remote_vtep_ip) +{ + int ret; + + if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) + ret = bgp_zebra_send_remote_macip (bgp, vpn, p, remote_vtep_ip, 0); + else + ret = bgp_zebra_send_remote_vtep (bgp, vpn, p, 0); + + return ret; +} + +/* + * Due to MAC mobility, the prior "local" best route has been supplanted + * by a "remote" best route. The prior route has to be deleted and withdrawn + * from peers. + */ +static void +evpn_delete_old_local_route (struct bgp *bgp, struct bgpevpn *vpn, + struct bgp_node *rn, struct bgp_info *old_local) +{ + struct bgp_node *global_rn; + struct bgp_info *ri; + afi_t afi = AFI_L2VPN; + safi_t safi = SAFI_EVPN; + + /* Locate route node in the global EVPN routing table. Note that + * this table is a 2-level tree (RD-level + Prefix-level) similar to + * L3VPN routes. + */ + global_rn = bgp_afi_node_lookup (bgp->rib[afi][safi], afi, safi, + (struct prefix *)&rn->p, &vpn->prd); + if (global_rn) + { + /* Delete route entry in the global EVPN table. */ + delete_evpn_route_entry (bgp, vpn, afi, safi, global_rn, &ri); + + /* Schedule for processing - withdraws to peers happen from + * this table. + */ + if (ri) + bgp_process (bgp, global_rn, afi, safi); + bgp_unlock_node (global_rn); + } + + /* Delete route entry in the VNI route table, caller to remove. */ + bgp_info_delete (rn, old_local); +} + +/* + * Calculate the best path for an EVPN route. Install/update best path in zebra, + * if appropriate. + */ +static int +evpn_route_select_install (struct bgp *bgp, struct bgpevpn *vpn, + struct bgp_node *rn) +{ + struct bgp_info *old_select, *new_select; + struct bgp_info_pair old_and_new; + afi_t afi = AFI_L2VPN; + safi_t safi = SAFI_EVPN; + int ret = 0; + + /* Compute the best path. */ + bgp_best_selection (bgp, rn, &bgp->maxpaths[afi][safi], + &old_and_new, afi, safi); + old_select = old_and_new.old; + new_select = old_and_new.new; + + /* If the best path hasn't changed - see if there is still something to update + * to zebra RIB. + */ + if (old_select && old_select == new_select && + old_select->type == ZEBRA_ROUTE_BGP && + old_select->sub_type == BGP_ROUTE_NORMAL && + !CHECK_FLAG(rn->flags, BGP_NODE_USER_CLEAR) && + !CHECK_FLAG(old_select->flags, BGP_INFO_ATTR_CHANGED) && + !bgp->addpath_tx_used[afi][safi]) + { + if (bgp_zebra_has_route_changed (rn, old_select)) + ret = evpn_zebra_install (bgp, vpn, (struct prefix_evpn *)&rn->p, + old_select->attr->nexthop); + UNSET_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG); + bgp_zebra_clear_route_change_flags (rn); + return ret; + } + + /* If the user did a "clear" this flag will be set */ + UNSET_FLAG(rn->flags, BGP_NODE_USER_CLEAR); + + /* bestpath has changed; update relevant fields and install or uninstall + * into the zebra RIB. + */ + if (old_select || new_select) + bgp_bump_version(rn); + + if (old_select) + bgp_info_unset_flag (rn, old_select, BGP_INFO_SELECTED); + if (new_select) + { + bgp_info_set_flag (rn, new_select, BGP_INFO_SELECTED); + bgp_info_unset_flag (rn, new_select, BGP_INFO_ATTR_CHANGED); + UNSET_FLAG (new_select->flags, BGP_INFO_MULTIPATH_CHG); + } + + if (new_select + && new_select->type == ZEBRA_ROUTE_BGP + && new_select->sub_type == BGP_ROUTE_NORMAL) + { + ret = evpn_zebra_install (bgp, vpn, (struct prefix_evpn *) &rn->p, + new_select->attr->nexthop); + /* If an old best existed and it was a "local" route, the only reason + * it would be supplanted is due to MAC mobility procedures. So, we + * need to do an implicit delete and withdraw that route from peers. + */ + if (old_select + && old_select->peer == bgp->peer_self + && old_select->type == ZEBRA_ROUTE_BGP + && old_select->sub_type == BGP_ROUTE_STATIC) + evpn_delete_old_local_route (bgp, vpn, rn, old_select); + } + else + { + if (old_select + && old_select->type == ZEBRA_ROUTE_BGP + && old_select->sub_type == BGP_ROUTE_NORMAL) + ret = evpn_zebra_uninstall (bgp, vpn, (struct prefix_evpn *) &rn->p, + old_select->attr->nexthop); + } + + /* Clear any route change flags. */ + bgp_zebra_clear_route_change_flags (rn); + + /* Reap old select bgp_info, if it has been removed */ + if (old_select && CHECK_FLAG (old_select->flags, BGP_INFO_REMOVED)) + bgp_info_reap (rn, old_select); + + return ret; +} + +/* + * Create or update EVPN route entry. This could be in the VNI route table + * or the global route table. + */ +static int +update_evpn_route_entry (struct bgp *bgp, struct bgpevpn *vpn, afi_t afi, + safi_t safi, struct bgp_node *rn, struct attr *attr, + int add, int vni_table, struct bgp_info **ri) +{ + struct bgp_info *tmp_ri; + struct bgp_info *local_ri, *remote_ri; + struct attr *attr_new; + mpls_label_t label = MPLS_INVALID_LABEL; + int route_change = 1; + + *ri = NULL; + + /* See if this is an update of an existing route, or a new add. Also, + * identify if already known from remote, and if so, the one with the + * highest sequence number; this is only when adding to the VNI routing + * table. + */ + local_ri = remote_ri = NULL; + for (tmp_ri = rn->info; tmp_ri; tmp_ri = tmp_ri->next) + { + if (tmp_ri->peer == bgp->peer_self + && tmp_ri->type == ZEBRA_ROUTE_BGP + && tmp_ri->sub_type == BGP_ROUTE_STATIC) + local_ri = tmp_ri; + if (vni_table) + { + if (tmp_ri->type == ZEBRA_ROUTE_BGP + && tmp_ri->sub_type == BGP_ROUTE_NORMAL + && CHECK_FLAG (tmp_ri->flags, BGP_INFO_VALID)) + { + if (!remote_ri) + remote_ri = tmp_ri; + else if (mac_mobility_seqnum (tmp_ri->attr) > + mac_mobility_seqnum (remote_ri->attr)) + remote_ri = tmp_ri; + } + } + } + + /* If route doesn't exist already, create a new one, if told to. + * Otherwise act based on whether the attributes of the route have + * changed or not. + */ + if (!local_ri && !add) + return 0; + + if (!local_ri) + { + /* When learnt locally for the first time but already known from + * remote, we have to initiate appropriate MAC mobility steps. This + * is applicable when updating the VNI routing table. + */ + if (remote_ri) + { + u_int32_t cur_seqnum; + + /* Add MM extended community to route. */ + cur_seqnum = mac_mobility_seqnum (remote_ri->attr); + add_mac_mobility_to_attr (cur_seqnum + 1, attr); + } + + /* Add (or update) attribute to hash. */ + attr_new = bgp_attr_intern (attr); + + /* Extract MAC mobility sequence number, if any. */ + attr_new->extra->mm_seqnum = bgp_attr_mac_mobility_seqnum (attr_new); + + /* Create new route with its attribute. */ + tmp_ri = info_make (ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, 0, + bgp->peer_self, attr_new, rn); + SET_FLAG (tmp_ri->flags, BGP_INFO_VALID); + bgp_info_extra_get(tmp_ri); + + /* The VNI goes into the 'label' field of the route */ + vni2label (vpn->vni, &label); + + memcpy (&tmp_ri->extra->label, &label, BGP_LABEL_BYTES); + bgp_info_add (rn, tmp_ri); + } + else + { + tmp_ri = local_ri; + if (attrhash_cmp (tmp_ri->attr, attr) && + !CHECK_FLAG(tmp_ri->flags, BGP_INFO_REMOVED)) + route_change = 0; + else + { + /* The attribute has changed. */ + /* Add (or update) attribute to hash. */ + attr_new = bgp_attr_intern (attr); + bgp_info_set_flag (rn, tmp_ri, BGP_INFO_ATTR_CHANGED); + + /* Restore route, if needed. */ + if (CHECK_FLAG(tmp_ri->flags, BGP_INFO_REMOVED)) + bgp_info_restore(rn, tmp_ri); + + /* Unintern existing, set to new. */ + bgp_attr_unintern (&tmp_ri->attr); + tmp_ri->attr = attr_new; + tmp_ri->uptime = bgp_clock (); + } + } + + /* Return back the route entry. */ + *ri = tmp_ri; + return route_change; +} + +/* + * Create or update EVPN route (of type based on prefix) for specified VNI + * and schedule for processing. + */ +static int +update_evpn_route (struct bgp *bgp, struct bgpevpn *vpn, + struct prefix_evpn *p) +{ + struct bgp_node *rn; + struct attr attr; + struct attr *attr_new; + struct bgp_info *ri; + afi_t afi = AFI_L2VPN; + safi_t safi = SAFI_EVPN; + int route_change; + + memset (&attr, 0, sizeof (struct attr)); + + /* Build path-attribute for this route. */ + bgp_attr_default_set (&attr, BGP_ORIGIN_IGP); + attr.nexthop = vpn->originator_ip; + attr.extra->mp_nexthop_global_in = vpn->originator_ip; + attr.extra->mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; + + /* Set up RT and ENCAP extended community. */ + build_evpn_route_extcomm (vpn, &attr); + + /* First, create (or fetch) route node within the VNI. */ + /* NOTE: There is no RD here. */ + rn = bgp_node_get (vpn->route_table, (struct prefix *)p); + + /* Create or update route entry. */ + route_change = update_evpn_route_entry (bgp, vpn, afi, safi, + rn, &attr, 1, 1, &ri); + assert (ri); + attr_new = ri->attr; + + /* Perform route selection; this is just to set the flags correctly + * as local route in the VNI always wins. + */ + evpn_route_select_install (bgp, vpn, rn); + bgp_unlock_node (rn); + + /* If this is a new route or some attribute has changed, export the + * route to the global table. The route will be advertised to peers + * from there. Note that this table is a 2-level tree (RD-level + + * Prefix-level) similar to L3VPN routes. + */ + if (route_change) + { + struct bgp_info *global_ri; + + rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, + (struct prefix *)p, &vpn->prd); + update_evpn_route_entry (bgp, vpn, afi, safi, rn, + attr_new, 1, 0, &global_ri); + + /* Schedule for processing and unlock node. */ + bgp_process (bgp, rn, afi, safi); + bgp_unlock_node (rn); + } + + /* Unintern temporary. */ + aspath_unintern (&attr.aspath); + bgp_attr_extra_free (&attr); + + return 0; +} + +/* + * Delete EVPN route entry. This could be in the VNI route table + * or the global route table. + */ +static void +delete_evpn_route_entry (struct bgp *bgp, struct bgpevpn *vpn, + afi_t afi, safi_t safi, struct bgp_node *rn, + struct bgp_info **ri) +{ + struct bgp_info *tmp_ri; + + *ri = NULL; + + /* Now, find matching route. */ + for (tmp_ri = rn->info; tmp_ri; tmp_ri = tmp_ri->next) + if (tmp_ri->peer == bgp->peer_self + && tmp_ri->type == ZEBRA_ROUTE_BGP + && tmp_ri->sub_type == BGP_ROUTE_STATIC) + break; + + *ri = tmp_ri; + + /* Mark route for delete. */ + if (tmp_ri) + bgp_info_delete (rn, tmp_ri); +} + +/* + * Delete EVPN route (of type based on prefix) for specified VNI and + * schedule for processing. + */ +static int +delete_evpn_route (struct bgp *bgp, struct bgpevpn *vpn, + struct prefix_evpn *p) +{ + struct bgp_node *rn, *global_rn; + struct bgp_info *ri; + afi_t afi = AFI_L2VPN; + safi_t safi = SAFI_EVPN; + + /* First, locate the route node within the VNI. If it doesn't exist, there + * is nothing further to do. + */ + /* NOTE: There is no RD here. */ + rn = bgp_node_lookup (vpn->route_table, (struct prefix *)p); + if (!rn) + return 0; + + /* Next, locate route node in the global EVPN routing table. Note that + * this table is a 2-level tree (RD-level + Prefix-level) similar to + * L3VPN routes. + */ + global_rn = bgp_afi_node_lookup (bgp->rib[afi][safi], afi, safi, + (struct prefix *)p, &vpn->prd); + if (global_rn) + { + /* Delete route entry in the global EVPN table. */ + delete_evpn_route_entry (bgp, vpn, afi, safi, global_rn, &ri); + + /* Schedule for processing - withdraws to peers happen from + * this table. + */ + if (ri) + bgp_process (bgp, global_rn, afi, safi); + bgp_unlock_node (global_rn); + } + + /* Delete route entry in the VNI route table. This can just be removed. */ + delete_evpn_route_entry (bgp, vpn, afi, safi, rn, &ri); + if (ri) + bgp_info_reap (rn, ri); + bgp_unlock_node (rn); + + return 0; +} + +/* + * Update all type-2 (MACIP) local routes for this VNI - these should also + * be scheduled for advertise to peers. + */ +static int +update_all_type2_routes (struct bgp *bgp, struct bgpevpn *vpn) +{ + afi_t afi; + safi_t safi; + struct bgp_node *rn; + struct bgp_info *ri; + struct attr attr; + struct attr *attr_new; + + afi = AFI_L2VPN; + safi = SAFI_EVPN; + memset (&attr, 0, sizeof (struct attr)); + + /* Build path-attribute - all type-2 routes for this VNI will share the + * same path attribute. + */ + bgp_attr_default_set (&attr, BGP_ORIGIN_IGP); + attr.nexthop = vpn->originator_ip; + attr.extra->mp_nexthop_global_in = vpn->originator_ip; + attr.extra->mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; + + /* Set up RT, ENCAP extended community. */ + build_evpn_route_extcomm (vpn, &attr); + + /* Walk this VNI's route table and update local type-2 routes. For any + * routes updated, update corresponding entry in the global table too. + */ + for (rn = bgp_table_top (vpn->route_table); rn; rn = bgp_route_next (rn)) + { + struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; + struct bgp_node *rd_rn; + struct bgp_info *global_ri; + + if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) + continue; + + update_evpn_route_entry (bgp, vpn, afi, safi, rn, &attr, 0, 1, &ri); + + /* If a local route exists for this prefix, we need to update + * the global routing table too. + */ + if (!ri) + continue; + + /* Perform route selection; this is just to set the flags correctly + * as local route in the VNI always wins. + */ + evpn_route_select_install (bgp, vpn, rn); + + attr_new = ri->attr; + + /* Update route in global routing table. */ + rd_rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, + (struct prefix *)evp, &vpn->prd); + assert (rd_rn); + update_evpn_route_entry (bgp, vpn, afi, safi, rd_rn, + attr_new, 0, 0, &global_ri); + + /* Schedule for processing and unlock node. */ + bgp_process (bgp, rd_rn, afi, safi); + bgp_unlock_node (rd_rn); + } + + /* Unintern temporary. */ + aspath_unintern (&attr.aspath); + bgp_attr_extra_free (&attr); + + return 0; +} + +/* + * Delete all type-2 (MACIP) local routes for this VNI - only from the + * global routing table. These are also scheduled for withdraw from peers. + */ +static int +delete_global_type2_routes (struct bgp *bgp, struct bgpevpn *vpn) +{ + afi_t afi; + safi_t safi; + struct bgp_node *rdrn, *rn; + struct bgp_table *table; + struct bgp_info *ri; + + afi = AFI_L2VPN; + safi = SAFI_EVPN; + + rdrn = bgp_node_lookup (bgp->rib[afi][safi], (struct prefix *) &vpn->prd); + if (rdrn && rdrn->info) + { + table = (struct bgp_table *)rdrn->info; + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) + { + struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; + + if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) + continue; + + delete_evpn_route_entry (bgp, vpn, afi, safi, rn, &ri); + if (ri) + bgp_process (bgp, rn, afi, safi); + } + } + + /* Unlock RD node. */ + if (rdrn) + bgp_unlock_node (rdrn); + + return 0; +} + +/* + * Delete all type-2 (MACIP) local routes for this VNI - from the global + * table as well as the per-VNI route table. + */ +static int +delete_all_type2_routes (struct bgp *bgp, struct bgpevpn *vpn) +{ + afi_t afi; + safi_t safi; + struct bgp_node *rn; + struct bgp_info *ri; + + afi = AFI_L2VPN; + safi = SAFI_EVPN; + + /* First, walk the global route table for this VNI's type-2 local routes. + * EVPN routes are a 2-level table, first get the RD table. + */ + delete_global_type2_routes (bgp, vpn); + + /* Next, walk this VNI's route table and delete local type-2 routes. */ + for (rn = bgp_table_top (vpn->route_table); rn; rn = bgp_route_next (rn)) + { + struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; + + if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) + continue; + + delete_evpn_route_entry (bgp, vpn, afi, safi, rn, &ri); + + /* Route entry in local table gets deleted immediately. */ + if (ri) + bgp_info_reap (rn, ri); + } + + return 0; +} + +/* + * Delete all routes in the per-VNI route table. + */ +static int +delete_all_vni_routes (struct bgp *bgp, struct bgpevpn *vpn) +{ + struct bgp_node *rn; + struct bgp_info *ri, *nextri; + + /* Walk this VNI's route table and delete all routes. */ + for (rn = bgp_table_top (vpn->route_table); rn; rn = bgp_route_next (rn)) + { + for (ri = rn->info; (ri != NULL) && (nextri = ri->next, 1); ri = nextri) + { + bgp_info_delete (rn, ri); + bgp_info_reap (rn, ri); + } + } + + return 0; +} + +/* + * Update (and advertise) local routes for a VNI. Invoked upon the VNI + * export RT getting modified or change to tunnel IP. Note that these + * situations need the route in the per-VNI table as well as the global + * table to be updated (as attributes change). + */ +static int +update_routes_for_vni (struct bgp *bgp, struct bgpevpn *vpn) +{ + int ret; + struct prefix_evpn p; + + /* Update and advertise the type-3 route (only one) followed by the + * locally learnt type-2 routes (MACIP) - for this VNI. + */ + build_evpn_type3_prefix (&p, vpn->originator_ip); + ret = update_evpn_route (bgp, vpn, &p); + if (ret) + return ret; + + return update_all_type2_routes (bgp, vpn); +} + +/* + * Delete (and withdraw) local routes for specified VNI from the global + * table and per-VNI table. After this, remove all other routes from + * the per-VNI table. Invoked upon the VNI being deleted or EVPN + * (advertise-all-vni) being disabled. + */ +static int +delete_routes_for_vni (struct bgp *bgp, struct bgpevpn *vpn) +{ + int ret; + struct prefix_evpn p; + + /* Delete and withdraw locally learnt type-2 routes (MACIP) + * followed by type-3 routes (only one) - for this VNI. + */ + ret = delete_all_type2_routes (bgp, vpn); + if (ret) + return ret; + + build_evpn_type3_prefix (&p, vpn->originator_ip); + ret = delete_evpn_route (bgp, vpn, &p); + if (ret) + return ret; + + /* Delete all routes from the per-VNI table. */ + return delete_all_vni_routes (bgp, vpn); +} + +/* + * There is a tunnel endpoint IP address change for this VNI, + * need to re-advertise routes with the new nexthop. + */ +static int +handle_tunnel_ip_change (struct bgp *bgp, struct bgpevpn *vpn, + struct in_addr originator_ip) +{ + struct prefix_evpn p; + + /* Need to withdraw type-3 route as the originator IP is part + * of the key. + */ + build_evpn_type3_prefix (&p, vpn->originator_ip); + delete_evpn_route (bgp, vpn, &p); + + /* Update the tunnel IP and re-advertise all routes for this VNI. */ + vpn->originator_ip = originator_ip; + return update_routes_for_vni (bgp, vpn); +} + +/* + * Install route entry into the VNI routing table and invoke route selection. + */ +static int +install_evpn_route_entry (struct bgp *bgp, struct bgpevpn *vpn, + struct prefix_evpn *p, struct bgp_info *parent_ri) +{ + struct bgp_node *rn; + struct bgp_info *ri; + struct attr *attr_new; + int ret; + + /* Create (or fetch) route within the VNI. */ + /* NOTE: There is no RD here. */ + rn = bgp_node_get (vpn->route_table, (struct prefix *)p); + + /* Check if route entry is already present. */ + for (ri = rn->info; ri; ri = ri->next) + if (ri->extra && + (struct bgp_info *)ri->extra->parent == parent_ri) + break; + + if (!ri) + { + /* Add (or update) attribute to hash. */ + attr_new = bgp_attr_intern (parent_ri->attr); + + /* Create new route with its attribute. */ + ri = info_make (parent_ri->type, parent_ri->sub_type, 0, + parent_ri->peer, attr_new, rn); + SET_FLAG (ri->flags, BGP_INFO_VALID); + bgp_info_extra_get(ri); + ri->extra->parent = parent_ri; + if (parent_ri->extra) + memcpy (&ri->extra->label, &parent_ri->extra->label, BGP_LABEL_BYTES); + bgp_info_add (rn, ri); + } + else + { + if (attrhash_cmp (ri->attr, parent_ri->attr) && + !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) + { + bgp_unlock_node (rn); + return 0; + } + /* The attribute has changed. */ + /* Add (or update) attribute to hash. */ + attr_new = bgp_attr_intern (parent_ri->attr); + + /* Restore route, if needed. */ + if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) + bgp_info_restore(rn, ri); + + /* Mark if nexthop has changed. */ + if (!IPV4_ADDR_SAME (&ri->attr->nexthop, &attr_new->nexthop)) + SET_FLAG(ri->flags, BGP_INFO_IGP_CHANGED); + + /* Unintern existing, set to new. */ + bgp_attr_unintern (&ri->attr); + ri->attr = attr_new; + ri->uptime = bgp_clock (); + } + + /* Perform route selection and update zebra, if required. */ + ret = evpn_route_select_install (bgp, vpn, rn); + + return ret; +} + +/* + * Uninstall route entry from the VNI routing table and send message + * to zebra, if appropriate. + */ +static int +uninstall_evpn_route_entry (struct bgp *bgp, struct bgpevpn *vpn, + struct prefix_evpn *p, struct bgp_info *parent_ri) +{ + struct bgp_node *rn; + struct bgp_info *ri; + int ret; + + /* Locate route within the VNI. */ + /* NOTE: There is no RD here. */ + rn = bgp_node_lookup (vpn->route_table, (struct prefix *)p); + if (!rn) + return 0; + + /* Find matching route entry. */ + for (ri = rn->info; ri; ri = ri->next) + if (ri->extra && + (struct bgp_info *)ri->extra->parent == parent_ri) + break; + + if (!ri) + return 0; + + /* Mark entry for deletion */ + bgp_info_delete (rn, ri); + + /* Perform route selection and update zebra, if required. */ + ret = evpn_route_select_install (bgp, vpn, rn); + + /* Unlock route node. */ + bgp_unlock_node (rn); + + return ret; +} + +/* + * Given a route entry and a VNI, see if this route entry should be + * imported into the VNI i.e., RTs match. + */ +static int +is_route_matching_for_vni (struct bgp *bgp, struct bgpevpn *vpn, + struct bgp_info *ri) +{ + struct attr *attr = ri->attr; + struct ecommunity *ecom; + int i; + + assert (attr); + /* Route should have valid RT to be even considered. */ + if (!(attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES))) + return 0; + + ecom = attr->extra->ecommunity; + if (!ecom || !ecom->size) + return 0; + + /* For each extended community RT, see if it matches this VNI. If any RT + * matches, we're done. + */ + for (i = 0; i < ecom->size; i++) + { + u_char *pnt; + u_char type, sub_type; + struct ecommunity_val *eval; + struct ecommunity_val eval_tmp; + struct irt_node *irt; + + /* Only deal with RTs */ + pnt = (ecom->val + (i * ECOMMUNITY_SIZE)); + eval = (struct ecommunity_val *) (ecom->val + (i * ECOMMUNITY_SIZE)); + type = *pnt++; + sub_type = *pnt++; + if (sub_type != ECOMMUNITY_ROUTE_TARGET) + continue; + + /* See if this RT matches specified VNIs import RTs */ + irt = lookup_import_rt (bgp, eval); + if (irt && irt->vnis) + if (is_vni_present_in_irt_vnis (irt->vnis, vpn)) + return 1; + + /* Also check for non-exact match. In this, we mask out the AS and + * only check on the local-admin sub-field. This is to facilitate using + * VNI as the RT for EBGP peering too. + */ + irt = NULL; + if (type == ECOMMUNITY_ENCODE_AS || + type == ECOMMUNITY_ENCODE_AS4 || + type == ECOMMUNITY_ENCODE_IP) + { + memcpy (&eval_tmp, eval, ECOMMUNITY_SIZE); + mask_ecom_global_admin (&eval_tmp, eval); + irt = lookup_import_rt (bgp, &eval_tmp); + } + if (irt && irt->vnis) + if (is_vni_present_in_irt_vnis (irt->vnis, vpn)) + return 1; + } + + return 0; +} + +/* + * Install or uninstall routes of specified type that are appropriate for this + * particular VNI. + */ +static int +install_uninstall_routes_for_vni (struct bgp *bgp, struct bgpevpn *vpn, + bgp_evpn_route_type rtype, int install) +{ + afi_t afi; + safi_t safi; + struct bgp_node *rd_rn, *rn; + struct bgp_table *table; + struct bgp_info *ri; + int ret; + + afi = AFI_L2VPN; + safi = SAFI_EVPN; + + /* Walk entire global routing table and evaluate routes which could be + * imported into this VPN. Note that we cannot just look at the routes for + * the VNI's RD - remote routes applicable for this VNI could have any RD. + */ + /* EVPN routes are a 2-level table. */ + for (rd_rn = bgp_table_top(bgp->rib[afi][safi]); rd_rn; rd_rn = bgp_route_next (rd_rn)) + { + table = (struct bgp_table *)(rd_rn->info); + if (!table) + continue; + + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) + { + struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; + + if (evp->prefix.route_type != rtype) + continue; + + for (ri = rn->info; ri; ri = ri->next) + { + /* Consider "valid" remote routes applicable for this VNI. */ + if (!(CHECK_FLAG (ri->flags, BGP_INFO_VALID) + && ri->type == ZEBRA_ROUTE_BGP + && ri->sub_type == BGP_ROUTE_NORMAL)) + continue; + + if (is_route_matching_for_vni (bgp, vpn, ri)) + { + if (install) + ret = install_evpn_route_entry (bgp, vpn, evp, ri); + else + ret = uninstall_evpn_route_entry (bgp, vpn, evp, ri); + + if (ret) + { + zlog_err ("%u: Failed to %s EVPN %s route in VNI %u", + bgp->vrf_id, install ? "install" : "uninstall", + rtype == BGP_EVPN_MAC_IP_ROUTE ? \ + "MACIP" : "IMET", vpn->vni); + return ret; + } + } + } + } + } + + return 0; +} + +/* + * Install any existing remote routes applicable for this VNI into its + * routing table. This is invoked when a VNI becomes "live" or its Import + * RT is changed. + */ +static int +install_routes_for_vni (struct bgp *bgp, struct bgpevpn *vpn) +{ + int ret; + + /* Install type-3 routes followed by type-2 routes - the ones applicable + * for this VNI. + */ + ret = install_uninstall_routes_for_vni (bgp, vpn, BGP_EVPN_IMET_ROUTE, 1); + if (ret) + return ret; + + return install_uninstall_routes_for_vni (bgp, vpn, BGP_EVPN_MAC_IP_ROUTE, 1); +} + +/* + * Install or uninstall route in matching VNIs (list). + */ +static int +install_uninstall_route_in_vnis (struct bgp *bgp, afi_t afi, safi_t safi, + struct prefix_evpn *evp, struct bgp_info *ri, + struct list *vnis, int install) +{ + struct bgpevpn *vpn; + struct listnode *node, *nnode; + + for (ALL_LIST_ELEMENTS (vnis, node, nnode, vpn)) + { + int ret; + + if (!is_vni_live (vpn)) + continue; + + if (install) + ret = install_evpn_route_entry (bgp, vpn, evp, ri); + else + ret = uninstall_evpn_route_entry (bgp, vpn, evp, ri); + + if (ret) + { + zlog_err ("%u: Failed to %s EVPN %s route in VNI %u", + bgp->vrf_id, install ? "install" : "uninstall", + evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE ? \ + "MACIP" : "IMET", vpn->vni); + return ret; + } + } + + return 0; +} + +/* + * Install or uninstall route for appropriate VNIs. + */ +static int +install_uninstall_evpn_route (struct bgp *bgp, afi_t afi, safi_t safi, + struct prefix *p, struct bgp_info *ri, + int import) +{ + struct prefix_evpn *evp = (struct prefix_evpn *)p; + struct attr *attr = ri->attr; + struct ecommunity *ecom; + int i; + + assert (attr); + + /* Only type-2 and type-3 routes go into a L2 VNI. */ + if (!(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE || + evp->prefix.route_type == BGP_EVPN_IMET_ROUTE)) + return 0; + + /* If we don't have Route Target, nothing much to do. */ + if (!(attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES))) + return 0; + + ecom = attr->extra->ecommunity; + if (!ecom || !ecom->size) + return -1; + + /* For each extended community RT, see which VNIs match and import + * the route into matching VNIs. + */ + for (i = 0; i < ecom->size; i++) + { + u_char *pnt; + u_char type, sub_type; + struct ecommunity_val *eval; + struct ecommunity_val eval_tmp; + struct irt_node *irt; + + /* Only deal with RTs */ + pnt = (ecom->val + (i * ECOMMUNITY_SIZE)); + eval = (struct ecommunity_val *) (ecom->val + (i * ECOMMUNITY_SIZE)); + type = *pnt++; + sub_type = *pnt++; + if (sub_type != ECOMMUNITY_ROUTE_TARGET) + continue; + + /* Are we interested in this RT? */ + irt = lookup_import_rt (bgp, eval); + if (irt && irt->vnis) + install_uninstall_route_in_vnis (bgp, afi, safi, evp, + ri, irt->vnis, import); + + /* Also check for non-exact match. In this, we mask out the AS and + * only check on the local-admin sub-field. This is to facilitate using + * VNI as the RT for EBGP peering too. + */ + irt = NULL; + if (type == ECOMMUNITY_ENCODE_AS || + type == ECOMMUNITY_ENCODE_AS4 || + type == ECOMMUNITY_ENCODE_IP) + { + memcpy (&eval_tmp, eval, ECOMMUNITY_SIZE); + mask_ecom_global_admin (&eval_tmp, eval); + irt = lookup_import_rt (bgp, &eval_tmp); + } + if (irt && irt->vnis) + install_uninstall_route_in_vnis (bgp, afi, safi, evp, + ri, irt->vnis, import); + } + + return 0; +} + +/* + * Process received EVPN type-2 route (advertise or withdraw). + */ +static int +process_type2_route (struct peer *peer, afi_t afi, safi_t safi, + struct attr *attr, u_char *pfx, int psize, + u_int32_t addpath_id) +{ + struct prefix_rd prd; + struct prefix_evpn p; + u_char ipaddr_len; + u_char macaddr_len; + mpls_label_t *label_pnt; + int ret; + + /* Type-2 route should be either 33, 37 or 49 bytes or an + * additional 3 bytes if there is a second label (VNI): + * RD (8), ESI (10), Eth Tag (4), MAC Addr Len (1), + * MAC Addr (6), IP len (1), IP (0, 4 or 16), + * MPLS Lbl1 (3), MPLS Lbl2 (0 or 3) + */ + if (psize != 33 && psize != 37 && psize != 49 && + psize != 36 && psize != 40 && psize != 52) + { + zlog_err ("%u:%s - Rx EVPN Type-2 NLRI with invalid length %d", + peer->bgp->vrf_id, peer->host, psize); + return -1; + } + + /* Make prefix_rd */ + prd.family = AF_UNSPEC; + prd.prefixlen = 64; + memcpy (&prd.val, pfx, 8); + pfx += 8; + + /* Make EVPN prefix. */ + memset (&p, 0, sizeof (struct prefix_evpn)); + p.family = AF_ETHERNET; + p.prefixlen = EVPN_TYPE_2_ROUTE_PREFIXLEN; + p.prefix.route_type = BGP_EVPN_MAC_IP_ROUTE; + + /* Skip over Ethernet Seg Identifier for now. */ + pfx += 10; + + /* Skip over Ethernet Tag for now. */ + pfx += 4; + + /* Get the MAC Addr len */ + macaddr_len = *pfx++; + + /* Get the MAC Addr */ + if (macaddr_len == (ETHER_ADDR_LEN * 8)) + { + memcpy (&p.prefix.mac.octet, pfx, ETHER_ADDR_LEN); + pfx += ETHER_ADDR_LEN; + } + else + { + zlog_err ("%u:%s - Rx EVPN Type-2 NLRI with unsupported MAC address length %d", + peer->bgp->vrf_id, peer->host, macaddr_len); + return -1; + } + + + /* Get the IP. */ + ipaddr_len = *pfx++; + if (ipaddr_len != 0 && + ipaddr_len != IPV4_MAX_BITLEN && + ipaddr_len != IPV6_MAX_BITLEN) + { + zlog_err ("%u:%s - Rx EVPN Type-2 NLRI with unsupported IP address length %d", + peer->bgp->vrf_id, peer->host, ipaddr_len); + return -1; + } + + if (ipaddr_len) + { + ipaddr_len /= 8; /* Convert to bytes. */ + p.prefix.ip.ipa_type = (ipaddr_len == IPV4_MAX_BYTELEN) ? + IPADDR_V4 : IPADDR_V6; + memcpy (&p.prefix.ip.ip.addr, pfx, ipaddr_len); + } + pfx += ipaddr_len; + + /* Get the VNI (in MPLS label field). */ + /* Note: We ignore the second VNI, if any. */ + label_pnt = (mpls_label_t *) pfx; + + /* Process the route. */ + if (attr) + ret = bgp_update (peer, (struct prefix *)&p, addpath_id, attr, afi, safi, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, label_pnt, 0, NULL); + else + ret = bgp_withdraw (peer, (struct prefix *)&p, addpath_id, attr, afi, safi, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, label_pnt, NULL); + return ret; +} + +/* + * Process received EVPN type-3 route (advertise or withdraw). + */ +static int +process_type3_route (struct peer *peer, afi_t afi, safi_t safi, + struct attr *attr, u_char *pfx, int psize, + u_int32_t addpath_id) +{ + struct prefix_rd prd; + struct prefix_evpn p; + u_char ipaddr_len; + int ret; + + /* Type-3 route should be either 17 or 29 bytes: RD (8), Eth Tag (4), + * IP len (1) and IP (4 or 16). + */ + if (psize != 17 && psize != 29) + { + zlog_err ("%u:%s - Rx EVPN Type-3 NLRI with invalid length %d", + peer->bgp->vrf_id, peer->host, psize); + return -1; + } + + /* Make prefix_rd */ + prd.family = AF_UNSPEC; + prd.prefixlen = 64; + memcpy (&prd.val, pfx, 8); + pfx += 8; + + /* Make EVPN prefix. */ + memset (&p, 0, sizeof (struct prefix_evpn)); + p.family = AF_ETHERNET; + p.prefixlen = EVPN_TYPE_3_ROUTE_PREFIXLEN; + p.prefix.route_type = BGP_EVPN_IMET_ROUTE; + + /* Skip over Ethernet Tag for now. */ + pfx += 4; + + /* Get the IP. */ + ipaddr_len = *pfx++; + if (ipaddr_len == IPV4_MAX_BITLEN) + { + p.prefix.ip.ipa_type = IPADDR_V4; + memcpy (&p.prefix.ip.ip.addr, pfx, IPV4_MAX_BYTELEN); + } + else + { + zlog_err ("%u:%s - Rx EVPN Type-3 NLRI with unsupported IP address length %d", + peer->bgp->vrf_id, peer->host, ipaddr_len); + return -1; + } + + /* Process the route. */ + if (attr) + ret = bgp_update (peer, (struct prefix *)&p, addpath_id, attr, afi, safi, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0, NULL); + else + ret = bgp_withdraw (peer, (struct prefix *)&p, addpath_id, attr, afi, safi, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, NULL); + return ret; +} + +/* + * Process received EVPN type-5 route (advertise or withdraw). + */ +static int +process_type5_route (struct peer *peer, afi_t afi, safi_t safi, + struct attr *attr, u_char *pfx, int psize, + u_int32_t addpath_id, int withdraw) +{ + struct prefix_rd prd; + struct prefix_evpn p; + struct bgp_route_evpn evpn; + u_char ippfx_len; + u_int32_t eth_tag; + mpls_label_t *label_pnt; + int ret; + + /* Type-5 route should be 34 or 58 bytes: + * RD (8), ESI (10), Eth Tag (4), IP len (1), IP (4 or 16), + * GW (4 or 16) and VNI (3). + * Note that the IP and GW should both be IPv4 or both IPv6. + */ + if (psize != 34 && psize != 58) + { + zlog_err ("%u:%s - Rx EVPN Type-5 NLRI with invalid length %d", + peer->bgp->vrf_id, peer->host, psize); + return -1; + } + + /* Make prefix_rd */ + prd.family = AF_UNSPEC; + prd.prefixlen = 64; + memcpy (&prd.val, pfx, 8); + pfx += 8; + + /* Make EVPN prefix. */ + memset (&p, 0, sizeof (struct prefix_evpn)); + p.family = AF_ETHERNET; + p.prefix.route_type = BGP_EVPN_IP_PREFIX_ROUTE; + + /* Additional information outside of prefix - ESI and GW IP */ + memset(&evpn, 0, sizeof(evpn)); + + /* Fetch ESI */ + memcpy (&evpn.eth_s_id.val, pfx, 10); + pfx += 10; + + /* Fetch Ethernet Tag. */ + memcpy (ð_tag, pfx, 4); + p.prefix.eth_tag = ntohl (eth_tag); + pfx += 4; + + /* Fetch IP prefix length. */ + ippfx_len = *pfx++; + if (ippfx_len > IPV6_MAX_BITLEN) + { + zlog_err ("%u:%s - Rx EVPN Type-5 NLRI with invalid IP Prefix length %d", + peer->bgp->vrf_id, peer->host, ippfx_len); + return -1; + } + p.prefix.ip_prefix_length = ippfx_len; + + /* Determine IPv4 or IPv6 prefix */ + /* Since the address and GW are from the same family, this just becomes + * a simple check on the total size. + */ + if (psize == 34) + { + SET_IPADDR_V4 (&p.prefix.ip); + memcpy (&p.prefix.ip.ipaddr_v4, pfx, 4); + pfx += 4; + memcpy (&evpn.gw_ip.ipv4, pfx, 4); + pfx += 4; + p.prefixlen = PREFIX_LEN_ROUTE_TYPE_5_IPV4; + } + else + { + SET_IPADDR_V6 (&p.prefix.ip); + memcpy (&p.prefix.ip.ipaddr_v6, pfx, 16); + pfx += 16; + memcpy (&evpn.gw_ip.ipv6, pfx, 16); + pfx += 16; + p.prefixlen = PREFIX_LEN_ROUTE_TYPE_5_IPV6; + } + + label_pnt = (mpls_label_t *) pfx; + + /* Process the route. */ + if (!withdraw) + ret = bgp_update (peer, (struct prefix *)&p, addpath_id, attr, afi, safi, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, label_pnt, 0, &evpn); + else + ret = bgp_withdraw (peer, (struct prefix *)&p, addpath_id, attr, afi, safi, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, label_pnt, &evpn); + + return ret; +} + +static void +evpn_mpattr_encode_type5 (struct stream *s, struct prefix *p, + struct prefix_rd *prd, mpls_label_t * label, + struct attr *attr) +{ + int len; + char temp[16]; + struct evpn_addr *p_evpn_p; + + memset(&temp, 0, 16); + if (p->family != AF_ETHERNET) + return; + p_evpn_p = &(p->u.prefix_evpn); + + if (IS_IPADDR_V4(&p_evpn_p->ip)) + len = 8; /* ipv4 */ + else + len = 32; /* ipv6 */ + stream_putc(s, BGP_EVPN_IP_PREFIX_ROUTE); + /* Prefix contains RD, ESI, EthTag, IP length, IP, GWIP and VNI */ + stream_putc(s, 8 + 10 + 4 + 1 + len + 3); + stream_put(s, prd->val, 8); + if (attr && attr->extra) + stream_put(s, &(attr->extra->evpn_overlay.eth_s_id), 10); + else + stream_put(s, &temp, 10); + stream_putl(s, p_evpn_p->eth_tag); + stream_putc(s, p_evpn_p->ip_prefix_length); + if (IS_IPADDR_V4(&p_evpn_p->ip)) + stream_put_ipv4(s, p_evpn_p->ip.ipaddr_v4.s_addr); + else + stream_put(s, &p_evpn_p->ip.ipaddr_v6, 16); + if (attr && attr->extra) + { + if (IS_IPADDR_V4(&p_evpn_p->ip)) + stream_put_ipv4(s, attr->extra->evpn_overlay.gw_ip.ipv4. s_addr); + else + stream_put(s, &(attr->extra->evpn_overlay.gw_ip.ipv6), 16); + } + else + { + if (IS_IPADDR_V4(&p_evpn_p->ip)) + stream_put_ipv4(s, 0); + else + stream_put(s, &temp, 16); + } + + if (label) + stream_put(s, label, 3); + else + stream_put3(s, 0); +} + /* * Cleanup specific VNI upon EVPN (advertise-all-vni) being disabled. */ static void cleanup_vni_on_disable (struct hash_backet *backet, struct bgp *bgp) { + struct bgpevpn *vpn = (struct bgpevpn *) backet->data; + + /* Remove EVPN routes and schedule for processing. */ + delete_routes_for_vni (bgp, vpn); + + /* Clear "live" flag and see if hash needs to be freed. */ + UNSET_FLAG (vpn->flags, VNI_FLAG_LIVE); + if (!is_vni_configured (vpn)) + bgp_evpn_free (bgp, vpn); } /* @@ -126,6 +1895,11 @@ cleanup_vni_on_disable (struct hash_backet *backet, struct bgp *bgp) static void free_vni_entry (struct hash_backet *backet, struct bgp *bgp) { + struct bgpevpn *vpn; + + vpn = (struct bgpevpn *) backet->data; + delete_all_vni_routes (bgp, vpn); + bgp_evpn_free(bgp, vpn); } @@ -133,194 +1907,529 @@ free_vni_entry (struct hash_backet *backet, struct bgp *bgp) * Public functions. */ -int -bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr, - struct bgp_nlri *packet, int withdraw) +/* + * Encode EVPN prefix in Update (MP_REACH) + */ +void +bgp_evpn_encode_prefix (struct stream *s, struct prefix *p, + struct prefix_rd *prd, mpls_label_t *label, + struct attr *attr, int addpath_encode, + u_int32_t addpath_tx_id) { - u_char *pnt; - u_char *lim; - struct prefix p; - struct prefix_rd prd; - struct evpn_addr *p_evpn_p; - struct bgp_route_evpn evpn; - uint8_t route_type, route_length; - mpls_label_t label; - u_int32_t addpath_id = 0; + struct prefix_evpn *evp = (struct prefix_evpn *)p; + int ipa_len = 0; - /* Check peer status. */ - if (peer->status != Established) - return 0; + if (addpath_encode) + stream_putl (s, addpath_tx_id); - /* Make prefix_rd */ - prd.family = AF_UNSPEC; - prd.prefixlen = 64; + /* Route type */ + stream_putc (s, evp->prefix.route_type); - p_evpn_p = &p.u.prefix_evpn; - pnt = packet->nlri; - lim = pnt + packet->length; - while (pnt < lim) { - /* clear evpn structure */ - memset(&evpn, 0, sizeof(evpn)); + switch (evp->prefix.route_type) + { + case BGP_EVPN_MAC_IP_ROUTE: + if (IS_EVPN_PREFIX_IPADDR_V4(evp)) + ipa_len = IPV4_MAX_BYTELEN; + else if (IS_EVPN_PREFIX_IPADDR_V6(evp)) + ipa_len = IPV6_MAX_BYTELEN; + stream_putc (s, 33 + ipa_len); // 1 VNI + stream_put (s, prd->val, 8); /* RD */ + stream_put (s, 0, 10); /* ESI */ + stream_putl (s, 0); /* Ethernet Tag ID */ + stream_putc (s, 8*ETHER_ADDR_LEN); /* Mac Addr Len - bits */ + stream_put (s, evp->prefix.mac.octet, 6); /* Mac Addr */ + stream_putc (s, 8*ipa_len); /* IP address Length */ + if (ipa_len) + stream_put (s, &evp->prefix.ip.ip.addr, ipa_len); /* IP */ + stream_put (s, label, BGP_LABEL_BYTES); /* VNI is contained in 'tag' */ + break; - /* Clear prefix structure. */ - memset(&p, 0, sizeof(struct prefix)); - memset(&evpn.gw_ip, 0, sizeof(union gw_addr)); - memset(&evpn.eth_s_id, 0, sizeof(struct eth_segment_id)); + case BGP_EVPN_IMET_ROUTE: + stream_putc (s, 17); // TODO: length - assumes IPv4 address + stream_put (s, prd->val, 8); /* RD */ + stream_putl (s, 0); /* Ethernet Tag ID */ + stream_putc (s, IPV4_MAX_BITLEN); /* IP address Length - bits */ + /* Originating Router's IP Addr */ + stream_put_in_addr (s, &evp->prefix.ip.ipaddr_v4); + break; - /* Fetch Route Type */ - route_type = *pnt++; - route_length = *pnt++; - /* simply ignore. goto next route type if any */ - if (route_type != EVPN_IP_PREFIX) { - if (pnt + route_length > lim) { - zlog_err - ("not enough bytes for New Route Type left in NLRI?"); - return -1; - } - pnt += route_length; - continue; - } + case BGP_EVPN_IP_PREFIX_ROUTE: + /* TODO: AddPath support. */ + evpn_mpattr_encode_type5 (s, p, prd, label, attr); + break; - /* Fetch RD */ - if (pnt + 8 > lim) { - zlog_err("not enough bytes for RD left in NLRI?"); - return -1; - } - - /* Copy routing distinguisher to rd. */ - memcpy(&prd.val, pnt, 8); - pnt += 8; - - /* Fetch ESI */ - if (pnt + 10 > lim) { - zlog_err("not enough bytes for ESI left in NLRI?"); - return -1; - } - memcpy(&evpn.eth_s_id.val, pnt, 10); - pnt += 10; - - /* Fetch Ethernet Tag */ - if (pnt + 4 > lim) { - zlog_err("not enough bytes for Eth Tag left in NLRI?"); - return -1; - } - - if (route_type == EVPN_IP_PREFIX) { - p_evpn_p->route_type = route_type; - memcpy(&(p_evpn_p->eth_tag), pnt, 4); - p_evpn_p->eth_tag = ntohl(p_evpn_p->eth_tag); - pnt += 4; - - /* Fetch IP prefix length. */ - p_evpn_p->ip_prefix_length = *pnt++; - - if (p_evpn_p->ip_prefix_length > 128) { - zlog_err("invalid prefixlen %d in EVPN NLRI?", - p.prefixlen); - return -1; - } - /* determine IPv4 or IPv6 prefix */ - if (route_length - 4 - 10 - 8 - - 3 /* label to be read */ >= 32) { - SET_IPADDR_V6 (&p_evpn_p->ip); - memcpy(&(p_evpn_p->ip.ipaddr_v6), pnt, 16); - pnt += 16; - memcpy(&evpn.gw_ip.ipv6, pnt, 16); - pnt += 16; - } else { - SET_IPADDR_V4 (&p_evpn_p->ip); - memcpy(&(p_evpn_p->ip.ipaddr_v4), pnt, 4); - pnt += 4; - memcpy(&evpn.gw_ip.ipv4, pnt, 4); - pnt += 4; - } - p.family = AFI_L2VPN; - if (IS_IPADDR_V4(&p_evpn_p->ip)) - p.prefixlen = - (u_char) PREFIX_LEN_ROUTE_TYPE_5_IPV4; - else - p.prefixlen = PREFIX_LEN_ROUTE_TYPE_5_IPV6; - p.family = AF_ETHERNET; - } - - /* Fetch Label */ - if (pnt + BGP_LABEL_BYTES > lim) { - zlog_err("not enough bytes for Label left in NLRI?"); - return -1; - } - - memcpy(&label, pnt, BGP_LABEL_BYTES); - bgp_set_valid_label(&label); - pnt += BGP_LABEL_BYTES; - - if (!withdraw) { - bgp_update(peer, &p, addpath_id, attr, AFI_L2VPN, - SAFI_EVPN, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, - &prd, &label, 0, &evpn); - } else { - bgp_withdraw(peer, &p, addpath_id, attr, AFI_L2VPN, - SAFI_EVPN, ZEBRA_ROUTE_BGP, - BGP_ROUTE_NORMAL, &prd, &label, &evpn); - } - } - - /* Packet length consistency check. */ - if (pnt != lim) - return -1; - return 0; + default: + break; + } } -void -bgp_packet_mpattr_route_type_5(struct stream *s, - struct prefix *p, struct prefix_rd *prd, - mpls_label_t *label, struct attr *attr) +int +bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr, + struct bgp_nlri *packet, int withdraw) { - int len; - char temp[16]; - struct evpn_addr *p_evpn_p; + u_char *pnt; + u_char *lim; + afi_t afi; + safi_t safi; + u_int32_t addpath_id; + int addpath_encoded; + int psize = 0; + u_char rtype; + u_char rlen; + struct prefix p; - memset(&temp, 0, 16); - if (p->family != AF_ETHERNET) - return; - p_evpn_p = &(p->u.prefix_evpn); - if (IS_IPADDR_V4(&p_evpn_p->ip)) - len = 8; /* ipv4 */ - else - len = 32; /* ipv6 */ - stream_putc(s, EVPN_IP_PREFIX); - stream_putc(s, - 8 /* RD */ + 10 /* ESI */ + 4 /* EthTag */ + 1 + len + - 3 /* label */ ); - stream_put(s, prd->val, 8); - if (attr && attr->extra) - stream_put(s, &(attr->extra->evpn_overlay.eth_s_id), 10); - else - stream_put(s, &temp, 10); - stream_putl(s, p_evpn_p->eth_tag); - stream_putc(s, p_evpn_p->ip_prefix_length); - if (IS_IPADDR_V4(&p_evpn_p->ip)) - stream_put_ipv4(s, p_evpn_p->ip.ipaddr_v4.s_addr); - else - stream_put(s, &p_evpn_p->ip.ipaddr_v6, 16); - if (attr && attr->extra) { - if (IS_IPADDR_V4(&p_evpn_p->ip)) - stream_put_ipv4(s, - attr->extra->evpn_overlay.gw_ip.ipv4. - s_addr); - else - stream_put(s, &(attr->extra->evpn_overlay.gw_ip.ipv6), - 16); - } else { - if (IS_IPADDR_V4(&p_evpn_p->ip)) - stream_put_ipv4(s, 0); - else - stream_put(s, &temp, 16); - } - if (label) - stream_put(s, label, 3); - else - stream_put3(s, 0); - return; + /* Check peer status. */ + if (peer->status != Established) + { + zlog_err ("%u:%s - EVPN update received in state %d", + peer->bgp->vrf_id, peer->host, peer->status); + return -1; + } + + /* Start processing the NLRI - there may be multiple in the MP_REACH */ + pnt = packet->nlri; + lim = pnt + packet->length; + afi = packet->afi; + safi = packet->safi; + addpath_id = 0; + + addpath_encoded = (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_RX_ADV) && + CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_TX_RCV)); + + for (; pnt < lim; pnt += psize) + { + /* Clear prefix structure. */ + memset (&p, 0, sizeof (struct prefix)); + + /* Deal with path-id if AddPath is supported. */ + if (addpath_encoded) + { + /* When packet overflow occurs return immediately. */ + if (pnt + BGP_ADDPATH_ID_LEN > lim) + return -1; + + addpath_id = ntohl(*((uint32_t*) pnt)); + pnt += BGP_ADDPATH_ID_LEN; + } + + /* All EVPN NLRI types start with type and length. */ + if (pnt + 2 > lim) + return -1; + + rtype = *pnt++; + psize = rlen = *pnt++; + + /* When packet overflow occur return immediately. */ + if (pnt + psize > lim) + return -1; + + switch (rtype) + { + case BGP_EVPN_MAC_IP_ROUTE: + if (process_type2_route (peer, afi, safi, + withdraw ? NULL : attr, + pnt, psize, addpath_id)) + { + zlog_err ("%u:%s - Error in processing EVPN type-2 NLRI size %d", + peer->bgp->vrf_id, peer->host, psize); + return -1; + } + break; + + case BGP_EVPN_IMET_ROUTE: + if (process_type3_route (peer, afi, safi, + withdraw ? NULL : attr, + pnt, psize, addpath_id)) + { + zlog_err ("%u:%s - Error in processing EVPN type-3 NLRI size %d", + peer->bgp->vrf_id, peer->host, psize); + return -1; + } + break; + + case BGP_EVPN_IP_PREFIX_ROUTE: + if (process_type5_route (peer, afi, safi, attr, + pnt, psize, addpath_id, withdraw)) + { + zlog_err ("%u:%s - Error in processing EVPN type-5 NLRI size %d", + peer->bgp->vrf_id, peer->host, psize); + return -1; + } + break; + + default: + break; + } + + } + + /* Packet length consistency check. */ + if (pnt != lim) + return -1; + + return 0; +} + + +/* + * Map the RTs (configured or automatically derived) of a VNI to the VNI. + * The mapping will be used during route processing. + */ +void +bgp_evpn_map_vni_to_its_rts (struct bgp *bgp, struct bgpevpn *vpn) +{ + int i; + struct ecommunity_val *eval; + struct listnode *node, *nnode; + struct ecommunity *ecom; + + for (ALL_LIST_ELEMENTS (vpn->import_rtl, node, nnode, ecom)) + { + for (i = 0; i < ecom->size; i++) + { + eval = (struct ecommunity_val *) (ecom->val + (i * ECOMMUNITY_SIZE)); + map_vni_to_rt (bgp, vpn, eval); + } + } +} + +/* + * Unmap the RTs (configured or automatically derived) of a VNI from the VNI. + */ +void +bgp_evpn_unmap_vni_from_its_rts (struct bgp *bgp, struct bgpevpn *vpn) +{ + int i; + struct ecommunity_val *eval; + struct listnode *node, *nnode; + struct ecommunity *ecom; + + for (ALL_LIST_ELEMENTS (vpn->import_rtl, node, nnode, ecom)) + { + for (i = 0; i < ecom->size; i++) + { + struct irt_node *irt; + struct ecommunity_val eval_tmp; + + eval = (struct ecommunity_val *) (ecom->val + (i * ECOMMUNITY_SIZE)); + /* If using "automatic" RT, we only care about the local-admin sub-field. + * This is to facilitate using VNI as the RT for EBGP peering too. + */ + memcpy (&eval_tmp, eval, ECOMMUNITY_SIZE); + if (!is_import_rt_configured (vpn)) + mask_ecom_global_admin (&eval_tmp, eval); + + irt = lookup_import_rt (bgp, &eval_tmp); + if (irt) + unmap_vni_from_rt (bgp, vpn, irt); + } + } +} + +/* + * Derive Import RT automatically for VNI and map VNI to RT. + * The mapping will be used during route processing. + */ +void +bgp_evpn_derive_auto_rt_import (struct bgp *bgp, struct bgpevpn *vpn) +{ + form_auto_rt (bgp, vpn, vpn->import_rtl); + UNSET_FLAG (vpn->flags, VNI_FLAG_IMPRT_CFGD); + + /* Map RT to VNI */ + bgp_evpn_map_vni_to_its_rts (bgp, vpn); +} + +/* + * Derive Export RT automatically for VNI. + */ +void +bgp_evpn_derive_auto_rt_export (struct bgp *bgp, struct bgpevpn *vpn) +{ + form_auto_rt (bgp, vpn, vpn->export_rtl); + UNSET_FLAG (vpn->flags, VNI_FLAG_EXPRT_CFGD); +} + +/* + * Derive RD automatically for VNI using passed information - it + * is of the form RouterId:unique-id-for-vni. + */ +void +bgp_evpn_derive_auto_rd (struct bgp *bgp, struct bgpevpn *vpn) +{ + char buf[100]; + + vpn->prd.family = AF_UNSPEC; + vpn->prd.prefixlen = 64; + sprintf (buf, "%s:%hu", inet_ntoa (bgp->router_id), vpn->rd_id); + str2prefix_rd (buf, &vpn->prd); + UNSET_FLAG (vpn->flags, VNI_FLAG_RD_CFGD); +} + +/* + * Lookup VNI. + */ +struct bgpevpn * +bgp_evpn_lookup_vni (struct bgp *bgp, vni_t vni) +{ + struct bgpevpn *vpn; + struct bgpevpn tmp; + + memset(&tmp, 0, sizeof(struct bgpevpn)); + tmp.vni = vni; + vpn = hash_lookup (bgp->vnihash, &tmp); + return vpn; +} + +/* + * Create a new vpn - invoked upon configuration or zebra notification. + */ +struct bgpevpn * +bgp_evpn_new (struct bgp *bgp, vni_t vni, struct in_addr originator_ip) +{ + struct bgpevpn *vpn; + + if (!bgp) + return NULL; + + vpn = XCALLOC (MTYPE_BGP_EVPN, sizeof (struct bgpevpn)); + if (!vpn) + return NULL; + + /* Set values - RD and RT set to defaults. */ + vpn->vni = vni; + vpn->originator_ip = originator_ip; + + /* Initialize route-target import and export lists */ + vpn->import_rtl = list_new (); + vpn->import_rtl->cmp = (int (*)(void *, void *)) evpn_route_target_cmp; + vpn->export_rtl = list_new (); + vpn->export_rtl->cmp = (int (*)(void *, void *)) evpn_route_target_cmp; + bf_assign_index(bgp->rd_idspace, vpn->rd_id); + derive_rd_rt_for_vni (bgp, vpn); + + /* Initialize EVPN route table. */ + vpn->route_table = bgp_table_init (AFI_L2VPN, SAFI_EVPN); + + /* Add to hash */ + if (!hash_get(bgp->vnihash, vpn, hash_alloc_intern)) + { + XFREE(MTYPE_BGP_EVPN, vpn); + return NULL; + } + QOBJ_REG (vpn, bgpevpn); + return vpn; +} + +/* + * Free a given VPN - called in multiple scenarios such as zebra + * notification, configuration being deleted, advertise-all-vni disabled etc. + * This just frees appropriate memory, caller should have taken other + * needed actions. + */ +void +bgp_evpn_free (struct bgp *bgp, struct bgpevpn *vpn) +{ + bgp_table_unlock (vpn->route_table); + bgp_evpn_unmap_vni_from_its_rts (bgp, vpn); + list_delete (vpn->import_rtl); + list_delete (vpn->export_rtl); + vpn->import_rtl = NULL; + vpn->export_rtl = NULL; + bf_release_index(bgp->rd_idspace, vpn->rd_id); + hash_release (bgp->vnihash, vpn); + QOBJ_UNREG (vpn); + XFREE(MTYPE_BGP_EVPN, vpn); +} + +/* + * Import route into matching VNI(s). + */ +int +bgp_evpn_import_route (struct bgp *bgp, afi_t afi, safi_t safi, + struct prefix *p, struct bgp_info *ri) +{ + return install_uninstall_evpn_route (bgp, afi, safi, p, ri, 1); +} + +/* + * Unimport route from matching VNI(s). + */ +int +bgp_evpn_unimport_route (struct bgp *bgp, afi_t afi, safi_t safi, + struct prefix *p, struct bgp_info *ri) +{ + return install_uninstall_evpn_route (bgp, afi, safi, p, ri, 0); +} + +/* + * Handle del of a local MACIP. + */ +int +bgp_evpn_local_macip_del (struct bgp *bgp, vni_t vni, + struct ethaddr *mac, struct ipaddr *ip) +{ + struct bgpevpn *vpn; + struct prefix_evpn p; + + if (!bgp->vnihash) + { + zlog_err ("%u: VNI hash not created", bgp->vrf_id); + return -1; + } + + /* Lookup VNI hash - should exist. */ + vpn = bgp_evpn_lookup_vni (bgp, vni); + if (!vpn || !is_vni_live (vpn)) + { + zlog_warn ("%u: VNI hash entry for VNI %u %s at MACIP DEL", + bgp->vrf_id, vni, vpn ? "not live" : "not found"); + return -1; + } + + /* Remove EVPN type-2 route and schedule for processing. */ + build_evpn_type2_prefix (&p, mac, ip); + delete_evpn_route (bgp, vpn, &p); + + return 0; +} + +/* + * Handle add of a local MACIP. + */ +int +bgp_evpn_local_macip_add (struct bgp *bgp, vni_t vni, + struct ethaddr *mac, struct ipaddr *ip) +{ + struct bgpevpn *vpn; + struct prefix_evpn p; + + if (!bgp->vnihash) + { + zlog_err ("%u: VNI hash not created", bgp->vrf_id); + return -1; + } + + /* Lookup VNI hash - should exist. */ + vpn = bgp_evpn_lookup_vni (bgp, vni); + if (!vpn || !is_vni_live (vpn)) + { + zlog_warn ("%u: VNI hash entry for VNI %u %s at MACIP ADD", + bgp->vrf_id, vni, vpn ? "not live" : "not found"); + return -1; + } + + /* Create EVPN type-2 route and schedule for processing. */ + build_evpn_type2_prefix (&p, mac, ip); + if (update_evpn_route (bgp, vpn, &p)) + { + char buf[ETHER_ADDR_STRLEN]; + char buf2[INET6_ADDRSTRLEN]; + + zlog_err ("%u:Failed to create Type-2 route, VNI %u MAC %s IP %s", + bgp->vrf_id, vpn->vni, + prefix_mac2str (mac, buf, sizeof (buf)), + ipaddr2str (ip, buf2, sizeof(buf2))); + return -1; + } + + return 0; +} + +/* + * Handle del of a local VNI. + */ +int +bgp_evpn_local_vni_del (struct bgp *bgp, vni_t vni) +{ + struct bgpevpn *vpn; + + if (!bgp->vnihash) + { + zlog_err ("%u: VNI hash not created", bgp->vrf_id); + return -1; + } + + /* Locate VNI hash */ + vpn = bgp_evpn_lookup_vni (bgp, vni); + if (!vpn) + { + zlog_warn ("%u: VNI hash entry for VNI %u not found at DEL", + bgp->vrf_id, vni); + return 0; + } + + /* Remove all local EVPN routes and schedule for processing (to + * withdraw from peers). + */ + delete_routes_for_vni (bgp, vpn); + + /* Clear "live" flag and see if hash needs to be freed. */ + UNSET_FLAG (vpn->flags, VNI_FLAG_LIVE); + if (!is_vni_configured (vpn)) + bgp_evpn_free (bgp, vpn); + + return 0; +} + +/* + * Handle add (or update) of a local VNI. The only VNI change we care + * about is change to local-tunnel-ip. + */ +int +bgp_evpn_local_vni_add (struct bgp *bgp, vni_t vni, struct in_addr originator_ip) +{ + struct bgpevpn *vpn; + struct prefix_evpn p; + + if (!bgp->vnihash) + { + zlog_err ("%u: VNI hash not created", bgp->vrf_id); + return -1; + } + + /* Lookup VNI. If present and no change, exit. */ + vpn = bgp_evpn_lookup_vni (bgp, vni); + if (vpn && is_vni_live (vpn)) + { + if (IPV4_ADDR_SAME (&vpn->originator_ip, &originator_ip)) + /* Probably some other param has changed that we don't care about. */ + return 0; + + /* Local tunnel endpoint IP address has changed */ + return handle_tunnel_ip_change (bgp, vpn, originator_ip); + } + + /* Create or update as appropriate. */ + if (!vpn) + { + vpn = bgp_evpn_new (bgp, vni, originator_ip); + if (!vpn) + { + zlog_err ("%u: Failed to allocate VNI entry for VNI %u - at Add", + bgp->vrf_id, vni); + return -1; + } + } + + /* Mark as "live" */ + SET_FLAG (vpn->flags, VNI_FLAG_LIVE); + + /* Create EVPN type-3 route and schedule for processing. */ + build_evpn_type3_prefix (&p, vpn->originator_ip); + if (update_evpn_route (bgp, vpn, &p)) + { + zlog_err ("%u: Type3 route creation failure for VNI %u", + bgp->vrf_id, vni); + return -1; + } + + /* If we have learnt and retained remote routes (VTEPs, MACs) for this VNI, + * install them. + */ + install_routes_for_vni (bgp, vpn); + + return 0; } /* diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index c87f3ffc77..40b61bb00c 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -21,14 +21,31 @@ #ifndef _QUAGGA_BGP_EVPN_H #define _QUAGGA_BGP_EVPN_H -extern int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr, - struct bgp_nlri *packet, int withdraw); +#include "vxlan.h" extern void -bgp_packet_mpattr_route_type_5(struct stream *s, - struct prefix *p, struct prefix_rd *prd, - mpls_label_t *label, struct attr *attr); - +bgp_evpn_encode_prefix (struct stream *s, struct prefix *p, + struct prefix_rd *prd, mpls_label_t *label, + struct attr *attr, int addpath_encode, + u_int32_t addpath_tx_id); +extern int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr, + struct bgp_nlri *packet, int withdraw); +extern int +bgp_evpn_import_route (struct bgp *bgp, afi_t afi, safi_t safi, + struct prefix *p, struct bgp_info *ri); +extern int +bgp_evpn_unimport_route (struct bgp *bgp, afi_t afi, safi_t safi, + struct prefix *p, struct bgp_info *ri); +extern int +bgp_evpn_local_macip_del (struct bgp *bgp, vni_t vni, + struct ethaddr *mac, struct ipaddr *ip); +extern int +bgp_evpn_local_macip_add (struct bgp *bgp, vni_t vni, + struct ethaddr *mac, struct ipaddr *ip); +extern int +bgp_evpn_local_vni_del (struct bgp *bgp, vni_t vni); +extern int +bgp_evpn_local_vni_add (struct bgp *bgp, vni_t vni, struct in_addr originator_ip); extern void bgp_evpn_cleanup_on_disable (struct bgp *bgp); extern void @@ -36,13 +53,4 @@ bgp_evpn_cleanup (struct bgp *bgp); extern void bgp_evpn_init (struct bgp *bgp); -/* EVPN route types as per RFC7432 and - * as per draft-ietf-bess-evpn-prefix-advertisement-02 - */ -#define EVPN_ETHERNET_AUTO_DISCOVERY 1 -#define EVPN_MACIP_ADVERTISEMENT 2 -#define EVPN_INCLUSIVE_MULTICAST_ETHERNET_TAG 3 -#define EVPN_ETHERNET_SEGMENT 4 -#define EVPN_IP_PREFIX 5 - -#endif /* _QUAGGA_BGP_EVPN_H */ +#endif /* _QUAGGA_BGP_EVPN_H */ diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index e9e8a75e28..f37e0ef2e3 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -94,4 +94,131 @@ struct irt_node struct list *vnis; }; +#define RT_TYPE_IMPORT 1 +#define RT_TYPE_EXPORT 2 +#define RT_TYPE_BOTH 3 + +static inline int +is_vni_configured (struct bgpevpn *vpn) +{ + return (CHECK_FLAG (vpn->flags, VNI_FLAG_CFGD)); +} + +static inline int +is_vni_live (struct bgpevpn *vpn) +{ + return (CHECK_FLAG (vpn->flags, VNI_FLAG_LIVE)); +} + +static inline int +is_rd_configured (struct bgpevpn *vpn) +{ + return (CHECK_FLAG (vpn->flags, VNI_FLAG_RD_CFGD)); +} + +static inline int +bgp_evpn_rd_matches_existing (struct bgpevpn *vpn, struct prefix_rd *prd) +{ + return(memcmp (&vpn->prd.val, prd->val, ECOMMUNITY_SIZE) == 0); +} + +static inline int +is_import_rt_configured (struct bgpevpn *vpn) +{ + return (CHECK_FLAG (vpn->flags, VNI_FLAG_IMPRT_CFGD)); +} + +static inline int +is_export_rt_configured (struct bgpevpn *vpn) +{ + return (CHECK_FLAG (vpn->flags, VNI_FLAG_EXPRT_CFGD)); +} + +static inline int +is_vni_param_configured (struct bgpevpn *vpn) +{ + return (is_rd_configured (vpn) || + is_import_rt_configured (vpn) || + is_export_rt_configured (vpn)); +} + +static inline void +vni2label (vni_t vni, mpls_label_t *label) +{ + u_char *tag = (u_char *) label; + tag[0] = (vni >> 16) & 0xFF; + tag[1] = (vni >> 8) & 0xFF; + tag[2] = vni & 0xFF; +} + +static inline vni_t +label2vni (mpls_label_t *label) +{ + u_char *tag = (u_char *) label; + vni_t vni; + + vni = ((u_int32_t) *tag++ << 16); + vni |= (u_int32_t) *tag++ << 8; + vni |= (u_int32_t) (*tag & 0xFF); + + return vni; +} + +static inline void +encode_mac_mobility_extcomm (int static_mac, u_int32_t seq, + struct ecommunity_val *eval) +{ + memset (eval, 0, sizeof (*eval)); + eval->val[0] = ECOMMUNITY_ENCODE_EVPN; + eval->val[1] = ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY; + if (static_mac) + eval->val[2] = ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY; + eval->val[4] = (seq >> 24) & 0xff; + eval->val[5] = (seq >> 16) & 0xff; + eval->val[6] = (seq >> 8) & 0xff; + eval->val[7] = seq & 0xff; +} + +static inline void +build_evpn_type2_prefix (struct prefix_evpn *p, struct ethaddr *mac, + struct ipaddr *ip) +{ + memset (p, 0, sizeof (struct prefix_evpn)); + p->family = AF_ETHERNET; + p->prefixlen = EVPN_TYPE_2_ROUTE_PREFIXLEN; + p->prefix.route_type = BGP_EVPN_MAC_IP_ROUTE; + memcpy(&p->prefix.mac.octet, mac->octet, ETHER_ADDR_LEN); + p->prefix.ip.ipa_type = IPADDR_NONE; + if (ip) + memcpy(&p->prefix.ip, ip, sizeof (*ip)); +} + +static inline void +build_evpn_type3_prefix (struct prefix_evpn *p, struct in_addr originator_ip) +{ + memset (p, 0, sizeof (struct prefix_evpn)); + p->family = AF_ETHERNET; + p->prefixlen = EVPN_TYPE_3_ROUTE_PREFIXLEN; + p->prefix.route_type = BGP_EVPN_IMET_ROUTE; + p->prefix.ip.ipa_type = IPADDR_V4; + p->prefix.ip.ipaddr_v4 = originator_ip; +} + + +extern void +bgp_evpn_map_vni_to_its_rts (struct bgp *bgp, struct bgpevpn *vpn); +extern void +bgp_evpn_unmap_vni_from_its_rts (struct bgp *bgp, struct bgpevpn *vpn); +extern void +bgp_evpn_derive_auto_rt_import (struct bgp *bgp, struct bgpevpn *vpn); +extern void +bgp_evpn_derive_auto_rt_export (struct bgp *bgp, struct bgpevpn *vpn); +extern void +bgp_evpn_derive_auto_rd (struct bgp *bgp, struct bgpevpn *vpn); +extern struct bgpevpn * +bgp_evpn_lookup_vni (struct bgp *bgp, vni_t vni); +extern struct bgpevpn * +bgp_evpn_new (struct bgp *bgp, vni_t vni, struct in_addr originator_ip); +extern void +bgp_evpn_free (struct bgp *bgp, struct bgpevpn *vpn); #endif /* _BGP_EVPN_PRIVATE_H */ diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index ac1faf9de1..6335b9d468 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -681,7 +681,7 @@ DEFUN(evpnrt5_network, argv[idx_ext_community]->arg, argv[idx_word]->arg, argv[idx_rmap] ? argv[idx_gwip]->arg : NULL, - EVPN_IP_PREFIX, argv[idx_esi]->arg, + BGP_EVPN_IP_PREFIX_ROUTE, argv[idx_esi]->arg, argv[idx_gwip]->arg, argv[idx_ethtag]->arg, argv[idx_routermac]->arg); } @@ -713,7 +713,7 @@ DEFUN(no_evpnrt5_network, return bgp_static_unset_safi(AFI_L2VPN, SAFI_EVPN, vty, argv[idx_ipv4_prefixlen]->arg, argv[idx_ext_community]->arg, - argv[idx_label]->arg, EVPN_IP_PREFIX, + argv[idx_label]->arg, BGP_EVPN_IP_PREFIX_ROUTE, argv[idx_esi]->arg, argv[idx_gwip]->arg, argv[idx_ethtag]->arg); } diff --git a/bgpd/bgp_memory.c b/bgpd/bgp_memory.c index c457f4b3e9..1913706587 100644 --- a/bgpd/bgp_memory.c +++ b/bgpd/bgp_memory.c @@ -114,3 +114,7 @@ DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS_VALUE, "BGP TEA Options Value") DEFINE_MTYPE(BGPD, LCOMMUNITY, "Large Community") DEFINE_MTYPE(BGPD, LCOMMUNITY_STR, "Large Community display string") DEFINE_MTYPE(BGPD, LCOMMUNITY_VAL, "Large Community value") + +DEFINE_MTYPE(BGPD, BGP_EVPN, "BGP EVPN Information") +DEFINE_MTYPE(BGPD, BGP_EVPN_IMPORT_RT, "BGP EVPN Import RT") +DEFINE_MTYPE(BGPD, BGP_EVPN_MACIP, "BGP EVPN MAC IP") diff --git a/bgpd/bgp_memory.h b/bgpd/bgp_memory.h index 454092cef3..185369d230 100644 --- a/bgpd/bgp_memory.h +++ b/bgpd/bgp_memory.h @@ -110,4 +110,8 @@ DECLARE_MTYPE(BGP_TEA_OPTIONS_VALUE) DECLARE_MTYPE(LCOMMUNITY) DECLARE_MTYPE(LCOMMUNITY_STR) DECLARE_MTYPE(LCOMMUNITY_VAL) + +DECLARE_MTYPE(BGP_EVPN) +DECLARE_MTYPE(BGP_EVPN_IMPORT_RT) +DECLARE_MTYPE(BGP_EVPN_MACIP) #endif /* _QUAGGA_BGP_MEMORY_H */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index ca6d138eaa..e55cd7b949 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -110,6 +110,36 @@ bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix return rn; } +struct bgp_node * +bgp_afi_node_lookup (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix *p, + struct prefix_rd *prd) +{ + struct bgp_node *rn; + struct bgp_node *prn = NULL; + + if (!table) + return NULL; + + if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) || (safi == SAFI_EVPN)) + { + prn = bgp_node_lookup (table, (struct prefix *) prd); + if (!prn) + return NULL; + + if (prn->info == NULL) + { + bgp_unlock_node (prn); + return NULL; + } + + table = prn->info; + } + + rn = bgp_node_lookup (table, p); + + return rn; +} + /* Allocate bgp_info_extra */ static struct bgp_info_extra * bgp_info_extra_new (void) @@ -224,7 +254,7 @@ bgp_info_add (struct bgp_node *rn, struct bgp_info *ri) /* Do the actual removal of info from RIB, for use by bgp_process completion callback *only* */ -static void +void bgp_info_reap (struct bgp_node *rn, struct bgp_info *ri) { if (ri->next) @@ -359,7 +389,7 @@ bgp_info_path_with_addpath_rx_str (struct bgp_info *ri, char *buf) static int bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, int *paths_eq, struct bgp_maxpaths_cfg *mpath_cfg, int debug, - const char *pfx_buf) + char *pfx_buf, afi_t afi, safi_t safi) { struct attr *newattr, *existattr; struct attr_extra *newattre, *existattre; @@ -381,6 +411,8 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, int ret; char new_buf[PATH_ADDPATH_STR_BUFFER]; char exist_buf[PATH_ADDPATH_STR_BUFFER]; + u_int32_t new_mm_seq; + u_int32_t exist_mm_seq; *paths_eq = 0; @@ -414,6 +446,61 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, newattre = newattr->extra; existattre = existattr->extra; + /* For EVPN routes, we cannot just go by local vs remote, we have to + * look at the MAC mobility sequence number, if present. + */ + if (safi == SAFI_EVPN) + { + /* This is an error condition described in RFC 7432 Section 15.2. The RFC + * states that in this scenario "the PE MUST alert the operator" but it + * does not state what other action to take. In order to provide some + * consistency in this scenario we are going to prefer the path with the + * sticky flag. + */ + if (newattre->sticky != existattre->sticky) + { + if (!debug) + { + prefix2str (&new->net->p, pfx_buf, sizeof (*pfx_buf) * PREFIX2STR_BUFFER); + bgp_info_path_with_addpath_rx_str (new, new_buf); + bgp_info_path_with_addpath_rx_str (exist, exist_buf); + } + + if (newattre->sticky && !existattre->sticky) + { + zlog_warn("%s: %s wins over %s due to sticky MAC flag", + pfx_buf, new_buf, exist_buf); + return 1; + } + + if (!newattre->sticky && existattre->sticky) + { + zlog_warn("%s: %s loses to %s due to sticky MAC flag", + pfx_buf, new_buf, exist_buf); + return 0; + } + } + + new_mm_seq = mac_mobility_seqnum (newattr); + exist_mm_seq = mac_mobility_seqnum (existattr); + + if (new_mm_seq > exist_mm_seq) + { + if (debug) + zlog_debug("%s: %s wins over %s due to MM seq %u > %u", + pfx_buf, new_buf, exist_buf, new_mm_seq, exist_mm_seq); + return 1; + } + + if (new_mm_seq < exist_mm_seq) + { + if (debug) + zlog_debug("%s: %s loses to %s due to MM seq %u < %u", + pfx_buf, new_buf, exist_buf, new_mm_seq, exist_mm_seq); + return 0; + } + } + /* 1. Weight check. */ new_weight = exist_weight = 0; @@ -891,11 +978,12 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, * This version is compatible with */ int bgp_info_cmp_compatible (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, - afi_t afi, safi_t safi) + char *pfx_buf, afi_t afi, safi_t safi) { int paths_eq; int ret; - ret = bgp_info_cmp (bgp, new, exist, &paths_eq, NULL, 0, __func__); + ret = bgp_info_cmp (bgp, new, exist, &paths_eq, NULL, 0, + pfx_buf, afi, safi); if (paths_eq) ret = 0; @@ -1599,16 +1687,11 @@ subgroup_announce_check (struct bgp_node *rn, struct bgp_info *ri, return 1; } -struct bgp_info_pair -{ - struct bgp_info *old; - struct bgp_info *new; -}; - -static void +void bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, struct bgp_maxpaths_cfg *mpath_cfg, - struct bgp_info_pair *result) + struct bgp_info_pair *result, + afi_t afi, safi_t safi) { struct bgp_info *new_select; struct bgp_info *old_select; @@ -1668,7 +1751,7 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, ri2->attr->aspath)) { if (bgp_info_cmp (bgp, ri2, new_select, &paths_eq, - mpath_cfg, debug, pfx_buf)) + mpath_cfg, debug, pfx_buf, afi, safi)) { bgp_info_unset_flag (rn, new_select, BGP_INFO_DMED_SELECTED); new_select = ri2; @@ -1725,7 +1808,8 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, bgp_info_unset_flag (rn, ri, BGP_INFO_DMED_CHECK); - if (bgp_info_cmp (bgp, ri, new_select, &paths_eq, mpath_cfg, debug, pfx_buf)) + if (bgp_info_cmp (bgp, ri, new_select, &paths_eq, mpath_cfg, + debug, pfx_buf, afi, safi)) { new_select = ri; } @@ -1779,7 +1863,8 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, continue; } - bgp_info_cmp (bgp, ri, new_select, &paths_eq, mpath_cfg, debug, pfx_buf); + bgp_info_cmp (bgp, ri, new_select, &paths_eq, mpath_cfg, + debug, pfx_buf, afi, safi); if (paths_eq) { @@ -1855,7 +1940,7 @@ subgroup_process_announce_selected (struct update_subgroup *subgrp, * Clear IGP changed flag and attribute changed flag for a route (all paths). * This is called at the end of route processing. */ -static void +void bgp_zebra_clear_route_change_flags (struct bgp_node *rn) { struct bgp_info *ri; @@ -1874,7 +1959,7 @@ bgp_zebra_clear_route_change_flags (struct bgp_node *rn) * if the route selection returns the same best route as earlier - to * determine if we need to update zebra or not. */ -static int +int bgp_zebra_has_route_changed (struct bgp_node *rn, struct bgp_info *selected) { struct bgp_info *mpinfo; @@ -1943,7 +2028,8 @@ bgp_process_main (struct work_queue *wq, void *data) } /* Best path selection. */ - bgp_best_selection (bgp, rn, &bgp->maxpaths[afi][safi], &old_and_new); + bgp_best_selection (bgp, rn, &bgp->maxpaths[afi][safi], + &old_and_new, afi, safi); old_select = old_and_new.old; new_select = old_and_new.new; @@ -2343,12 +2429,17 @@ bgp_rib_withdraw (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer, } } #endif + + /* If this is an EVPN route, process for un-import. */ + if (safi == SAFI_EVPN) + bgp_evpn_unimport_route (peer->bgp, afi, safi, &rn->p, ri); + bgp_rib_remove (rn, ri, peer, afi, safi); } -static struct bgp_info * -info_make (int type, int sub_type, u_short instance, struct peer *peer, struct attr *attr, - struct bgp_node *rn) +struct bgp_info * +info_make (int type, int sub_type, u_short instance, struct peer *peer, + struct attr *attr, struct bgp_node *rn) { struct bgp_info *new; @@ -2435,7 +2526,8 @@ bgp_update_martian_nexthop (struct bgp *bgp, afi_t afi, safi_t safi, struct attr int ret = 0; /* Only validated for unicast and multicast currently. */ - if (safi != SAFI_UNICAST && safi != SAFI_MULTICAST) + /* Also valid for EVPN where the nexthop is an IP address. */ + if (safi != SAFI_UNICAST && safi != SAFI_MULTICAST && safi != SAFI_EVPN) return 0; /* If NEXT_HOP is present, validate it. */ @@ -2504,6 +2596,7 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, #if ENABLE_BGP_VNC int vnc_implicit_withdraw = 0; #endif + int same_attr=0; memset (&new_attr, 0, sizeof(struct attr)); memset (&new_extra, 0, sizeof(struct attr_extra)); @@ -2613,6 +2706,7 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, if (ri) { ri->uptime = bgp_clock (); + same_attr = attrhash_cmp (ri->attr, attr_new); /* Same attribute comes in. */ if (!CHECK_FLAG (ri->flags, BGP_INFO_REMOVED) @@ -2734,7 +2828,32 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, } } #endif - + + /* Special handling for EVPN update of an existing route. If the + * extended community attribute has changed, we need to un-import + * the route using its existing extended community. It will be + * subsequently processed for import with the new extended community. + */ + if (safi == SAFI_EVPN && !same_attr) + { + if ((ri->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)) && + (attr_new->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES))) + { + int cmp; + + cmp = ecommunity_cmp (ri->attr->extra->ecommunity, + attr_new->extra->ecommunity); + if (!cmp) + { + if (bgp_debug_update(peer, p, NULL, 1)) + zlog_debug ("Change in EXT-COMM, existing %s new %s", + ecommunity_str (ri->attr->extra->ecommunity), + ecommunity_str (attr_new->extra->ecommunity)); + bgp_evpn_unimport_route (bgp, afi, safi, p, ri); + } + } + } + /* Update to new attribute. */ bgp_attr_unintern (&ri->attr); ri->attr = attr_new; @@ -2833,6 +2952,16 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, } #endif + /* If this is an EVPN route and some attribute has changed, process + * route for import. If the extended community has changed, we would + * have done the un-import earlier and the import would result in the + * route getting injected into appropriate L2 VNIs. If it is just + * some other attribute change, the import will result in updating + * the attributes for the route in the VNI(s). + */ + if (safi == SAFI_EVPN && !same_attr) + bgp_evpn_import_route (bgp, afi, safi, p, ri); + /* Process change. */ bgp_aggregate_increment (bgp, p, ri, afi, safi); @@ -2953,6 +3082,10 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, if (bgp_maximum_prefix_overflow (peer, afi, safi, 0)) return -1; + /* If this is an EVPN route, process for import. */ + if (safi == SAFI_EVPN) + bgp_evpn_import_route (bgp, afi, safi, p, new); + /* Process change. */ bgp_process (bgp, rn, afi, safi); @@ -2991,7 +3124,13 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, } if (ri) - bgp_rib_remove (rn, ri, peer, afi, safi); + { + /* If this is an EVPN route, un-import it as it is now filtered. */ + if (safi == SAFI_EVPN) + bgp_evpn_unimport_route (bgp, afi, safi, p, ri); + + bgp_rib_remove (rn, ri, peer, afi, safi); + } bgp_unlock_node (rn); @@ -3271,7 +3410,12 @@ bgp_clear_route_node (struct work_queue *wq, void *data) && ! CHECK_FLAG (ri->flags, BGP_INFO_UNUSEABLE)) bgp_info_set_flag (rn, ri, BGP_INFO_STALE); else - bgp_rib_remove (rn, ri, peer, afi, safi); + { + /* If this is an EVPN route, process for un-import. */ + if (safi == SAFI_EVPN) + bgp_evpn_unimport_route (peer->bgp, afi, safi, &rn->p, ri); + bgp_rib_remove (rn, ri, peer, afi, safi); + } } return WQ_SUCCESS; } diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 0c77cc1ee0..01d8e62d43 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -99,6 +99,9 @@ struct bgp_info_extra } vnc; #endif + + /* For imported routes into a VNI (or VRF), this points to the parent. */ + void *parent; }; struct bgp_info @@ -174,6 +177,13 @@ struct bgp_info }; +/* Structure used in BGP path selection */ +struct bgp_info_pair +{ + struct bgp_info *old; + struct bgp_info *new; +}; + /* BGP static route configuration. */ struct bgp_static { @@ -309,6 +319,7 @@ extern struct bgp_node *bgp_afi_node_get (struct bgp_table *table, afi_t afi, extern struct bgp_info *bgp_info_lock (struct bgp_info *); extern struct bgp_info *bgp_info_unlock (struct bgp_info *); extern void bgp_info_add (struct bgp_node *rn, struct bgp_info *ri); +extern void bgp_info_reap (struct bgp_node *rn, struct bgp_info *ri); extern void bgp_info_delete (struct bgp_node *rn, struct bgp_info *ri); extern struct bgp_info_extra *bgp_info_extra_get (struct bgp_info *); extern void bgp_info_set_flag (struct bgp_node *, struct bgp_info *, u_int32_t); @@ -372,6 +383,10 @@ extern u_char bgp_distance_apply (struct prefix *, struct bgp_info *, afi_t, saf extern afi_t bgp_node_afi (struct vty *); extern safi_t bgp_node_safi (struct vty *); +extern struct bgp_info * +info_make (int type, int sub_type, u_short instance, struct peer *peer, + struct attr *attr, struct bgp_node *rn); + extern void route_vty_out (struct vty *, struct prefix *, struct bgp_info *, int, safi_t, json_object *); extern void route_vty_out_tag (struct vty *, struct prefix *, struct bgp_info *, int, safi_t, json_object *); extern void route_vty_out_tmp (struct vty *, struct prefix *, struct attr *, safi_t, u_char, json_object *); @@ -396,10 +411,23 @@ extern void bgp_process_queues_drain_immediate (void); extern struct bgp_node * bgp_afi_node_get (struct bgp_table *, afi_t , safi_t , struct prefix *, struct prefix_rd *); +extern struct bgp_node * +bgp_afi_node_lookup (struct bgp_table *table, afi_t afi, safi_t safi, + struct prefix *p, struct prefix_rd *prd); extern struct bgp_info *bgp_info_new (void); extern void bgp_info_restore (struct bgp_node *, struct bgp_info *); -extern int bgp_info_cmp_compatible (struct bgp *, struct bgp_info *, - struct bgp_info *, afi_t, safi_t ); +extern int +bgp_info_cmp_compatible (struct bgp *, struct bgp_info *, struct bgp_info *, + char *pfx_buf, afi_t afi, safi_t safi); + +extern void +bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, + struct bgp_maxpaths_cfg *mpath_cfg, + struct bgp_info_pair *result, + afi_t afi, safi_t safi); +extern void bgp_zebra_clear_route_change_flags (struct bgp_node *rn); +extern int +bgp_zebra_has_route_changed (struct bgp_node *rn, struct bgp_info *selected); #endif /* _QUAGGA_BGP_ROUTE_H */ diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index cecb844fce..872ead000c 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -607,6 +607,30 @@ bpacket_reformat_for_peer (struct bpacket *pkt, struct peer_af *paf) (nhlen == 24 ? " and RD" : "")); } } + else if (paf->afi == AFI_L2VPN) + { + struct in_addr v4nh, *mod_v4nh; + int nh_modified = 0; + + stream_get_from (&v4nh, s, vec->offset + 1, 4); + mod_v4nh = &v4nh; + + /* No route-map changes allowed for EVPN nexthops. */ + if (!v4nh.s_addr) + { + mod_v4nh = &peer->nexthop.v4; + nh_modified = 1; + } + + if (nh_modified) + stream_put_in_addr_at (s, vec->offset + 1, mod_v4nh); + + if (bgp_debug_update(peer, NULL, NULL, 0)) + zlog_debug ("u%" PRIu64 ":s%" PRIu64 " %s send UPDATE w/ nexthop %s", + PAF_SUBGRP(paf)->update_group->id, PAF_SUBGRP(paf)->id, + peer->host, inet_ntoa (*mod_v4nh)); + + } } bgp_packet_add (peer, s); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 19f0dd98ff..a085fecc76 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -35,6 +35,7 @@ #include "lib/bfd.h" #include "filter.h" #include "mpls.h" +#include "vxlan.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_route.h" @@ -52,6 +53,7 @@ # include "bgpd/rfapi/rfapi_backend.h" # include "bgpd/rfapi/vnc_export_bgp.h" #endif +#include "bgpd/bgp_evpn.h" /* All information about zebra. */ struct zclient *zclient = NULL; @@ -2139,6 +2141,82 @@ bgp_zebra_connected (struct zclient *zclient) */ } +static int +bgp_zebra_process_local_vni (int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct stream *s; + vni_t vni; + struct bgp *bgp; + struct in_addr vtep_ip; + + s = zclient->ibuf; + vni = stream_getl (s); + if (command == ZEBRA_VNI_ADD) + vtep_ip.s_addr = stream_get_ipv4 (s); + bgp = bgp_lookup_by_vrf_id (vrf_id); + if (!bgp) + return 0; + + if (BGP_DEBUG (zebra, ZEBRA)) + zlog_debug("Rx VNI %s VRF %u VNI %u", + (command == ZEBRA_VNI_ADD) ? "add" : "del", vrf_id, vni); + + if (command == ZEBRA_VNI_ADD) + return bgp_evpn_local_vni_add (bgp, vni, vtep_ip.s_addr? vtep_ip : bgp->router_id); + else + return bgp_evpn_local_vni_del (bgp, vni); +} + +static int +bgp_zebra_process_local_macip (int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct stream *s; + vni_t vni; + struct bgp *bgp; + struct ethaddr mac; + struct ipaddr ip; + int ipa_len; + char buf[ETHER_ADDR_STRLEN]; + char buf1[INET6_ADDRSTRLEN]; + + memset (&ip, 0, sizeof (ip)); + s = zclient->ibuf; + vni = stream_getl (s); + stream_get (&mac.octet, s, ETHER_ADDR_LEN); + ipa_len = stream_getl (s); + if (ipa_len != 0 && + ipa_len != IPV4_MAX_BYTELEN && + ipa_len != IPV6_MAX_BYTELEN) + { + zlog_err ("%u:Recv MACIP %s with invalid IP addr length %d", + vrf_id, (command == ZEBRA_MACIP_ADD) ? "Add" : "Del", + ipa_len); + return -1; + } + + if (ipa_len) + { + ip.ipa_type = (ipa_len == IPV4_MAX_BYTELEN) ? IPADDR_V4: IPADDR_V6; + stream_get (&ip.ip.addr, s, ipa_len); + } + + bgp = bgp_lookup_by_vrf_id (vrf_id); + if (!bgp) + return 0; + + if (BGP_DEBUG (zebra, ZEBRA)) + zlog_debug ("%u:Recv MACIP %s MAC %s IP %s VNI %u", + vrf_id, (command == ZEBRA_MACIP_ADD) ? "Add" : "Del", + prefix_mac2str (&mac, buf, sizeof (buf)), + ipaddr2str (&ip, buf1, sizeof(buf1)), vni); + + if (command == ZEBRA_MACIP_ADD) + return bgp_evpn_local_macip_add (bgp, vni, &mac, &ip); + else + return bgp_evpn_local_macip_del (bgp, vni, &mac, &ip); +} void bgp_zebra_init (struct thread_master *master) @@ -2166,6 +2244,10 @@ bgp_zebra_init (struct thread_master *master) zclient->nexthop_update = bgp_read_nexthop_update; zclient->import_check_update = bgp_read_import_check_update; zclient->fec_update = bgp_read_fec_update; + zclient->local_vni_add = bgp_zebra_process_local_vni; + zclient->local_vni_del = bgp_zebra_process_local_vni; + zclient->local_macip_add = bgp_zebra_process_local_macip; + zclient->local_macip_del = bgp_zebra_process_local_macip; bgp_nexthop_buf = stream_new(multipath_num * sizeof (struct in6_addr)); bgp_ifindices_buf = stream_new(multipath_num * sizeof (unsigned int)); diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c index b0c6db2a1e..ec52b5742b 100644 --- a/bgpd/rfapi/rfapi_import.c +++ b/bgpd/rfapi/rfapi_import.c @@ -2121,6 +2121,8 @@ rfapiBgpInfoAttachSorted ( struct bgp *bgp; struct bgp_info *prev; struct bgp_info *next; + char pfx_buf[PREFIX2STR_BUFFER]; + bgp = bgp_get_default (); /* assume 1 instance for now */ @@ -2136,7 +2138,7 @@ rfapiBgpInfoAttachSorted ( if (!bgp || (!CHECK_FLAG (info_new->flags, BGP_INFO_REMOVED) && CHECK_FLAG (next->flags, BGP_INFO_REMOVED)) || - bgp_info_cmp_compatible (bgp, info_new, next, afi, safi) == -1) + bgp_info_cmp_compatible (bgp, info_new, next, pfx_buf, afi, safi) == -1) { /* -1 if 1st is better */ break; } From c85c03c7f90bfc6110c4621bfb096690c70b8bec Mon Sep 17 00:00:00 2001 From: vivek Date: Mon, 15 May 2017 14:42:57 -0700 Subject: [PATCH 20/31] bgpd, zebra: Support for sticky MACs Implement support for sticky (static) MACs. This includes the following: - Recognize MAC is static (using NUD_NOARP flag) and inform BGP - Construct MAC mobility extended community for sticky MACs as per RFC 7432 section 15.2 - Inform to zebra that remote MAC is sticky, where appropriate - Install sticky MACs into the kernel with the right flag - Appropriate handling in route selection Signed-off-by: Daniel Walton Reviewed-by: Vivek Venkatraman Reviewed-by: Donald Sharp --- bgpd/bgp_attr.c | 4 +- bgpd/bgp_attr_evpn.c | 11 ++++- bgpd/bgp_attr_evpn.h | 2 +- bgpd/bgp_evpn.c | 97 ++++++++++++++++++++++++++++++------- bgpd/bgp_evpn.h | 3 +- bgpd/bgp_zebra.c | 7 ++- zebra/rt.h | 3 +- zebra/rt_netlink.c | 26 +++++++--- zebra/rt_socket.c | 3 +- zebra/zebra_vxlan.c | 81 ++++++++++++++++++++++--------- zebra/zebra_vxlan.h | 3 +- zebra/zebra_vxlan_null.c | 3 +- zebra/zebra_vxlan_private.h | 1 + 13 files changed, 186 insertions(+), 58 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index e5bebfff7d..e62d1bb0aa 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2115,6 +2115,7 @@ bgp_attr_ext_communities (struct bgp_attr_parser_args *args) struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; + u_char sticky = 0; if (length == 0) { @@ -2137,7 +2138,8 @@ bgp_attr_ext_communities (struct bgp_attr_parser_args *args) attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); /* Extract MAC mobility sequence number, if any. */ - attr->extra->mm_seqnum = bgp_attr_mac_mobility_seqnum (attr); + attr->extra->mm_seqnum = bgp_attr_mac_mobility_seqnum (attr, &sticky); + attr->extra->sticky = sticky; return BGP_ATTR_PARSE_PROCEED; } diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index 740f517a9e..e66fdde5f6 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -113,10 +113,11 @@ char *ecom_mac2str(char *ecom_mac) * community, if present, else 0. */ u_int32_t -bgp_attr_mac_mobility_seqnum (struct attr *attr) +bgp_attr_mac_mobility_seqnum (struct attr *attr, u_char *sticky) { struct ecommunity *ecom; int i; + u_char flags = 0; ecom = attr->extra->ecommunity; if (!ecom || !ecom->size) @@ -140,7 +141,13 @@ bgp_attr_mac_mobility_seqnum (struct attr *attr) if (!(type == ECOMMUNITY_ENCODE_EVPN && sub_type == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY)) continue; - pnt++; + flags = *pnt++; + + if (flags & ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY) + *sticky = 1; + else + *sticky = 0; + pnt++; seq_num = (*pnt++ << 24); seq_num |= (*pnt++ << 16); diff --git a/bgpd/bgp_attr_evpn.h b/bgpd/bgp_attr_evpn.h index 8978731d5c..26650ef8bd 100644 --- a/bgpd/bgp_attr_evpn.h +++ b/bgpd/bgp_attr_evpn.h @@ -64,6 +64,6 @@ extern int bgp_build_evpn_prefix(int type, uint32_t eth_tag, struct prefix *dst); extern u_int32_t -bgp_attr_mac_mobility_seqnum (struct attr *attr); +bgp_attr_mac_mobility_seqnum (struct attr *attr, u_char *sticky); #endif /* _QUAGGA_BGP_ATTR_EVPN_H */ diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index d021def1b8..130017562e 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -349,7 +349,7 @@ static int bgp_zebra_send_remote_macip (struct bgp *bgp, struct bgpevpn *vpn, struct prefix_evpn *p, struct in_addr remote_vtep_ip, - int add) + int add, u_char sticky) { struct stream *s; int ipa_len; @@ -384,11 +384,16 @@ bgp_zebra_send_remote_macip (struct bgp *bgp, struct bgpevpn *vpn, } stream_put_in_addr(s, &remote_vtep_ip); + /* TX MAC sticky status */ + if (add) + stream_putc (s, sticky); + stream_putw_at (s, 0, stream_get_endp (s)); if (bgp_debug_zebra (NULL)) - zlog_debug("Tx %s MACIP, VNI %u MAC %s IP %s remote VTEP %s", + zlog_debug("Tx %s MACIP, VNI %u %sMAC %s IP %s remote VTEP %s", add ? "ADD" : "DEL", vpn->vni, + sticky ? "sticky " : "", prefix_mac2str (&p->prefix.mac, buf1, sizeof(buf1)), ipaddr2str (&p->prefix.ip, buf3, sizeof(buf3)), inet_ntop(AF_INET, &remote_vtep_ip, buf2, sizeof(buf2))); @@ -447,10 +452,13 @@ build_evpn_route_extcomm (struct bgpevpn *vpn, struct attr *attr) { struct attr_extra *attre; struct ecommunity ecom_encap; + struct ecommunity ecom_sticky; struct ecommunity_val eval; + struct ecommunity_val eval_sticky; bgp_encap_types tnl_type; struct listnode *node, *nnode; struct ecommunity *ecom; + u_int32_t seqnum; attre = bgp_attr_extra_get (attr); @@ -468,6 +476,16 @@ build_evpn_route_extcomm (struct bgpevpn *vpn, struct attr *attr) for (ALL_LIST_ELEMENTS (vpn->export_rtl, node, nnode, ecom)) attre->ecommunity = ecommunity_merge (attre->ecommunity, ecom); + if (attre->sticky) + { + seqnum = 0; + memset (&ecom_sticky, 0, sizeof (ecom_sticky)); + encode_mac_mobility_extcomm(1, seqnum, &eval_sticky); + ecom_sticky.size = 1; + ecom_sticky.val = (u_int8_t *)eval_sticky.val; + attre->ecommunity = ecommunity_merge (attre->ecommunity, &ecom_sticky); + } + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); } @@ -515,7 +533,6 @@ add_mac_mobility_to_attr (u_int32_t seq_num, struct attr *attr) { memcpy(ecom_mm->val, eval.val, sizeof(char) * ECOMMUNITY_SIZE); } - /* Add MM to existing */ else { @@ -530,12 +547,13 @@ add_mac_mobility_to_attr (u_int32_t seq_num, struct attr *attr) /* Install EVPN route into zebra. */ static int evpn_zebra_install (struct bgp *bgp, struct bgpevpn *vpn, - struct prefix_evpn *p, struct in_addr remote_vtep_ip) + struct prefix_evpn *p, struct in_addr remote_vtep_ip, + u_char sticky) { int ret; if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) - ret = bgp_zebra_send_remote_macip (bgp, vpn, p, remote_vtep_ip, 1); + ret = bgp_zebra_send_remote_macip (bgp, vpn, p, remote_vtep_ip, 1, sticky); else ret = bgp_zebra_send_remote_vtep (bgp, vpn, p, 1); @@ -550,7 +568,7 @@ evpn_zebra_uninstall (struct bgp *bgp, struct bgpevpn *vpn, int ret; if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) - ret = bgp_zebra_send_remote_macip (bgp, vpn, p, remote_vtep_ip, 0); + ret = bgp_zebra_send_remote_macip (bgp, vpn, p, remote_vtep_ip, 0, 0); else ret = bgp_zebra_send_remote_vtep (bgp, vpn, p, 0); @@ -626,7 +644,8 @@ evpn_route_select_install (struct bgp *bgp, struct bgpevpn *vpn, { if (bgp_zebra_has_route_changed (rn, old_select)) ret = evpn_zebra_install (bgp, vpn, (struct prefix_evpn *)&rn->p, - old_select->attr->nexthop); + old_select->attr->nexthop, + old_select->attr->extra->sticky); UNSET_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG); bgp_zebra_clear_route_change_flags (rn); return ret; @@ -655,7 +674,8 @@ evpn_route_select_install (struct bgp *bgp, struct bgpevpn *vpn, && new_select->sub_type == BGP_ROUTE_NORMAL) { ret = evpn_zebra_install (bgp, vpn, (struct prefix_evpn *) &rn->p, - new_select->attr->nexthop); + new_select->attr->nexthop, + new_select->attr->extra->sticky); /* If an old best existed and it was a "local" route, the only reason * it would be supplanted is due to MAC mobility procedures. So, we * need to do an implicit delete and withdraw that route from peers. @@ -685,6 +705,31 @@ evpn_route_select_install (struct bgp *bgp, struct bgpevpn *vpn, return ret; } + +/* + * Return true if the local ri for this rn has sticky set + */ +static int +evpn_route_is_sticky (struct bgp *bgp, struct bgp_node *rn) +{ + struct bgp_info *tmp_ri; + struct bgp_info *local_ri; + + local_ri = NULL; + for (tmp_ri = rn->info; tmp_ri; tmp_ri = tmp_ri->next) + { + if (tmp_ri->peer == bgp->peer_self + && tmp_ri->type == ZEBRA_ROUTE_BGP + && tmp_ri->sub_type == BGP_ROUTE_STATIC) + local_ri = tmp_ri; + } + + if (!local_ri) + return 0; + + return local_ri->attr->extra->sticky; +} + /* * Create or update EVPN route entry. This could be in the VNI route table * or the global route table. @@ -699,6 +744,7 @@ update_evpn_route_entry (struct bgp *bgp, struct bgpevpn *vpn, afi_t afi, struct attr *attr_new; mpls_label_t label = MPLS_INVALID_LABEL; int route_change = 1; + u_char sticky = 0; *ri = NULL; @@ -755,7 +801,8 @@ update_evpn_route_entry (struct bgp *bgp, struct bgpevpn *vpn, afi_t afi, attr_new = bgp_attr_intern (attr); /* Extract MAC mobility sequence number, if any. */ - attr_new->extra->mm_seqnum = bgp_attr_mac_mobility_seqnum (attr_new); + attr_new->extra->mm_seqnum = bgp_attr_mac_mobility_seqnum (attr_new, &sticky); + attr_new->extra->sticky = sticky; /* Create new route with its attribute. */ tmp_ri = info_make (ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, 0, @@ -804,7 +851,7 @@ update_evpn_route_entry (struct bgp *bgp, struct bgpevpn *vpn, afi_t afi, */ static int update_evpn_route (struct bgp *bgp, struct bgpevpn *vpn, - struct prefix_evpn *p) + struct prefix_evpn *p, u_char sticky) { struct bgp_node *rn; struct attr attr; @@ -821,6 +868,7 @@ update_evpn_route (struct bgp *bgp, struct bgpevpn *vpn, attr.nexthop = vpn->originator_ip; attr.extra->mp_nexthop_global_in = vpn->originator_ip; attr.extra->mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; + attr.extra->sticky = sticky; /* Set up RT and ENCAP extended community. */ build_evpn_route_extcomm (vpn, &attr); @@ -955,22 +1003,30 @@ update_all_type2_routes (struct bgp *bgp, struct bgpevpn *vpn) struct bgp_node *rn; struct bgp_info *ri; struct attr attr; + struct attr attr_sticky; struct attr *attr_new; afi = AFI_L2VPN; safi = SAFI_EVPN; memset (&attr, 0, sizeof (struct attr)); + memset (&attr_sticky, 0, sizeof (struct attr)); /* Build path-attribute - all type-2 routes for this VNI will share the * same path attribute. */ bgp_attr_default_set (&attr, BGP_ORIGIN_IGP); + bgp_attr_default_set (&attr_sticky, BGP_ORIGIN_IGP); attr.nexthop = vpn->originator_ip; attr.extra->mp_nexthop_global_in = vpn->originator_ip; attr.extra->mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; + attr_sticky.nexthop = vpn->originator_ip; + attr_sticky.extra->mp_nexthop_global_in = vpn->originator_ip; + attr_sticky.extra->mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; + attr_sticky.extra->sticky = 1; - /* Set up RT, ENCAP extended community. */ + /* Set up RT, ENCAP and sticky MAC extended community. */ build_evpn_route_extcomm (vpn, &attr); + build_evpn_route_extcomm (vpn, &attr_sticky); /* Walk this VNI's route table and update local type-2 routes. For any * routes updated, update corresponding entry in the global table too. @@ -984,7 +1040,10 @@ update_all_type2_routes (struct bgp *bgp, struct bgpevpn *vpn) if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) continue; - update_evpn_route_entry (bgp, vpn, afi, safi, rn, &attr, 0, 1, &ri); + if (evpn_route_is_sticky (bgp, rn)) + update_evpn_route_entry (bgp, vpn, afi, safi, rn, &attr_sticky, 0, 1, &ri); + else + update_evpn_route_entry (bgp, vpn, afi, safi, rn, &attr, 0, 1, &ri); /* If a local route exists for this prefix, we need to update * the global routing table too. @@ -1013,7 +1072,9 @@ update_all_type2_routes (struct bgp *bgp, struct bgpevpn *vpn) /* Unintern temporary. */ aspath_unintern (&attr.aspath); + aspath_unintern (&attr_sticky.aspath); bgp_attr_extra_free (&attr); + bgp_attr_extra_free (&attr_sticky); return 0; } @@ -1134,7 +1195,7 @@ update_routes_for_vni (struct bgp *bgp, struct bgpevpn *vpn) * locally learnt type-2 routes (MACIP) - for this VNI. */ build_evpn_type3_prefix (&p, vpn->originator_ip); - ret = update_evpn_route (bgp, vpn, &p); + ret = update_evpn_route (bgp, vpn, &p, 0); if (ret) return ret; @@ -2299,7 +2360,8 @@ bgp_evpn_local_macip_del (struct bgp *bgp, vni_t vni, */ int bgp_evpn_local_macip_add (struct bgp *bgp, vni_t vni, - struct ethaddr *mac, struct ipaddr *ip) + struct ethaddr *mac, struct ipaddr *ip, + u_char sticky) { struct bgpevpn *vpn; struct prefix_evpn p; @@ -2321,13 +2383,14 @@ bgp_evpn_local_macip_add (struct bgp *bgp, vni_t vni, /* Create EVPN type-2 route and schedule for processing. */ build_evpn_type2_prefix (&p, mac, ip); - if (update_evpn_route (bgp, vpn, &p)) + if (update_evpn_route (bgp, vpn, &p, sticky)) { char buf[ETHER_ADDR_STRLEN]; char buf2[INET6_ADDRSTRLEN]; - zlog_err ("%u:Failed to create Type-2 route, VNI %u MAC %s IP %s", + zlog_err ("%u:Failed to create Type-2 route, VNI %u %sMAC %s IP %s", bgp->vrf_id, vpn->vni, + sticky ? "sticky" : "", prefix_mac2str (mac, buf, sizeof (buf)), ipaddr2str (ip, buf2, sizeof(buf2))); return -1; @@ -2417,7 +2480,7 @@ bgp_evpn_local_vni_add (struct bgp *bgp, vni_t vni, struct in_addr originator_ip /* Create EVPN type-3 route and schedule for processing. */ build_evpn_type3_prefix (&p, vpn->originator_ip); - if (update_evpn_route (bgp, vpn, &p)) + if (update_evpn_route (bgp, vpn, &p, 0)) { zlog_err ("%u: Type3 route creation failure for VNI %u", bgp->vrf_id, vni); diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index 40b61bb00c..ed76bc3a4d 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -41,7 +41,8 @@ bgp_evpn_local_macip_del (struct bgp *bgp, vni_t vni, struct ethaddr *mac, struct ipaddr *ip); extern int bgp_evpn_local_macip_add (struct bgp *bgp, vni_t vni, - struct ethaddr *mac, struct ipaddr *ip); + struct ethaddr *mac, struct ipaddr *ip, + u_char sticky); extern int bgp_evpn_local_vni_del (struct bgp *bgp, vni_t vni); extern int diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index a085fecc76..91c155b3fd 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -2180,6 +2180,7 @@ bgp_zebra_process_local_macip (int command, struct zclient *zclient, int ipa_len; char buf[ETHER_ADDR_STRLEN]; char buf1[INET6_ADDRSTRLEN]; + u_char sticky; memset (&ip, 0, sizeof (ip)); s = zclient->ibuf; @@ -2201,19 +2202,21 @@ bgp_zebra_process_local_macip (int command, struct zclient *zclient, ip.ipa_type = (ipa_len == IPV4_MAX_BYTELEN) ? IPADDR_V4: IPADDR_V6; stream_get (&ip.ip.addr, s, ipa_len); } + sticky = stream_getc (s); bgp = bgp_lookup_by_vrf_id (vrf_id); if (!bgp) return 0; if (BGP_DEBUG (zebra, ZEBRA)) - zlog_debug ("%u:Recv MACIP %s MAC %s IP %s VNI %u", + zlog_debug ("%u:Recv MACIP %s %sMAC %s IP %s VNI %u", vrf_id, (command == ZEBRA_MACIP_ADD) ? "Add" : "Del", + sticky ? "sticky " : "", prefix_mac2str (&mac, buf, sizeof (buf)), ipaddr2str (&ip, buf1, sizeof(buf1)), vni); if (command == ZEBRA_MACIP_ADD) - return bgp_evpn_local_macip_add (bgp, vni, &mac, &ip); + return bgp_evpn_local_macip_add (bgp, vni, &mac, &ip, sticky); else return bgp_evpn_local_macip_del (bgp, vni, &mac, &ip); } diff --git a/zebra/rt.h b/zebra/rt.h index ee85eceeca..90654fb3eb 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -48,7 +48,8 @@ extern int kernel_add_vtep (vni_t vni, struct interface *ifp, extern int kernel_del_vtep (vni_t vni, struct interface *ifp, struct in_addr *vtep_ip); extern int kernel_add_mac (struct interface *ifp, vlanid_t vid, - struct ethaddr *mac, struct in_addr vtep_ip); + struct ethaddr *mac, struct in_addr vtep_ip, + u_char sticky); extern int kernel_del_mac (struct interface *ifp, vlanid_t vid, struct ethaddr *mac, struct in_addr vtep_ip, int local); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 4be1e96ce5..d676fc8296 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1658,6 +1658,7 @@ netlink_macfdb_change (struct sockaddr_nl *snl, struct nlmsghdr *h, int len) char buf[ETHER_ADDR_STRLEN]; char vid_buf[20]; char dst_buf[30]; + u_char sticky = 0; ndm = NLMSG_DATA (h); @@ -1738,12 +1739,15 @@ netlink_macfdb_change (struct sockaddr_nl *snl, struct nlmsghdr *h, int len) sprintf (dst_buf, " dst %s", inet_ntoa (vtep_ip.u.prefix4)); } + sticky = (ndm->ndm_state & NUD_NOARP) ? 1 : 0; + if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug ("Rx %s family %s IF %s(%u)%s MAC %s%s", + zlog_debug ("Rx %s family %s IF %s(%u)%s %sMAC %s%s", nl_msg_type_to_str (h->nlmsg_type), nl_family_to_str (ndm->ndm_family), ifp->name, ndm->ndm_ifindex, vid_present ? vid_buf : "", + sticky ? "sticky " : "", prefix_mac2str (&mac, buf, sizeof (buf)), dst_present ? dst_buf: ""); @@ -1763,7 +1767,7 @@ netlink_macfdb_change (struct sockaddr_nl *snl, struct nlmsghdr *h, int len) if (IS_ZEBRA_IF_VXLAN(ifp)) return zebra_vxlan_check_del_local_mac (ifp, br_if, &mac, vid); - return zebra_vxlan_local_mac_add_update (ifp, br_if, &mac, vid); + return zebra_vxlan_local_mac_add_update (ifp, br_if, &mac, vid, sticky); } /* This is a delete notification. @@ -1884,7 +1888,8 @@ static int netlink_macfdb_update (struct interface *ifp, vlanid_t vid, struct ethaddr *mac, struct in_addr vtep_ip, - int local, int cmd) + int local, int cmd, + u_char sticky) { struct zebra_ns *zns = zebra_ns_lookup (NS_DEFAULT); struct @@ -1923,7 +1928,10 @@ netlink_macfdb_update (struct interface *ifp, vlanid_t vid, req.ndm.ndm_flags |= NTF_SELF | NTF_MASTER; req.ndm.ndm_state = NUD_REACHABLE; - req.ndm.ndm_flags |= NTF_EXT_LEARNED; + if (sticky) + req.ndm.ndm_state |= NUD_NOARP; + else + req.ndm.ndm_flags |= NTF_EXT_LEARNED; addattr_l (&req.n, sizeof (req), NDA_LLADDR, mac, 6); req.ndm.ndm_ifindex = ifp->ifindex; @@ -1944,11 +1952,12 @@ netlink_macfdb_update (struct interface *ifp, vlanid_t vid, addattr32 (&req.n, sizeof (req), NDA_MASTER, br_if->ifindex); if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug ("Tx %s family %s IF %s(%u)%s MAC %s%s", + zlog_debug ("Tx %s family %s IF %s(%u)%s %sMAC %s%s", nl_msg_type_to_str (cmd), nl_family_to_str (req.ndm.ndm_family), ifp->name, ifp->ifindex, vid_present ? vid_buf : "", + sticky ? "sticky " : "", prefix_mac2str (mac, buf, sizeof (buf)), dst_present ? dst_buf : ""); @@ -2243,16 +2252,17 @@ netlink_neigh_update2 (struct interface *ifp, struct ipaddr *ip, int kernel_add_mac (struct interface *ifp, vlanid_t vid, - struct ethaddr *mac, struct in_addr vtep_ip) + struct ethaddr *mac, struct in_addr vtep_ip, + u_char sticky) { - return netlink_macfdb_update (ifp, vid, mac, vtep_ip, 0, RTM_NEWNEIGH); + return netlink_macfdb_update (ifp, vid, mac, vtep_ip, 0, RTM_NEWNEIGH, sticky); } int kernel_del_mac (struct interface *ifp, vlanid_t vid, struct ethaddr *mac, struct in_addr vtep_ip, int local) { - return netlink_macfdb_update (ifp, vid, mac, vtep_ip, local, RTM_DELNEIGH); + return netlink_macfdb_update (ifp, vid, mac, vtep_ip, local, RTM_DELNEIGH, 0); } int kernel_add_neigh (struct interface *ifp, struct ipaddr *ip, diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index c03ed27c63..93adf02298 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -444,7 +444,8 @@ kernel_del_vtep (vni_t vni, struct interface *ifp, struct in_addr *vtep_ip) int kernel_add_mac (struct interface *ifp, vlanid_t vid, - struct ethaddr *mac, struct in_addr vtep_ip) + struct ethaddr *mac, struct in_addr vtep_ip, + u_char sticky) { return 0; } diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 633083f42b..5eca8dc5d9 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -76,7 +76,7 @@ zvni_print_hash (struct hash_backet *backet, void *ctxt); static int zvni_macip_send_msg_to_client (struct zebra_vrf *zvrf, vni_t vni, struct ethaddr *macaddr, - struct ipaddr *ip, + struct ipaddr *ip, u_char sticky, u_int16_t cmd); static unsigned int neigh_hash_keymake (void *p); @@ -136,10 +136,10 @@ static zebra_mac_t * zvni_mac_lookup (zebra_vni_t *zvni, struct ethaddr *macaddr); static int zvni_mac_send_add_to_client (struct zebra_vrf *zvrf, vni_t vni, - struct ethaddr *macaddr); + struct ethaddr *macaddr, u_char sticky); static int zvni_mac_send_del_to_client (struct zebra_vrf *zvrf, vni_t vni, - struct ethaddr *macaddr); + struct ethaddr *macaddr, u_char sticky); static zebra_vni_t * zvni_map_vlan (struct interface *ifp, struct interface *br_if, vlanid_t vid); static int @@ -542,7 +542,7 @@ zvni_print_hash (struct hash_backet *backet, void *ctxt) static int zvni_macip_send_msg_to_client (struct zebra_vrf *zvrf, vni_t vni, struct ethaddr *macaddr, - struct ipaddr *ip, + struct ipaddr *ip, u_char sticky, u_int16_t cmd) { struct zserv *client; @@ -577,12 +577,15 @@ zvni_macip_send_msg_to_client (struct zebra_vrf *zvrf, vni_t vni, else stream_putl (s, 0); /* Just MAC. */ + stream_putc (s, sticky); /* Sticky MAC? */ + /* Write packet size. */ stream_putw_at (s, 0, stream_get_endp (s)); if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug ("%u:Send MACIP %s MAC %s IP %s VNI %u to %s", + zlog_debug ("%u:Send MACIP %s %sMAC %s IP %s VNI %u to %s", zvrf_id (zvrf), (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del", + sticky ? "sticky " : "", prefix_mac2str (macaddr, buf, sizeof (buf)), ipaddr2str (ip, buf2, sizeof(buf2)), vni, zebra_route_string (client->proto)); @@ -776,7 +779,7 @@ static int zvni_neigh_send_add_to_client (struct zebra_vrf *zvrf, vni_t vni, struct ipaddr *ip, struct ethaddr *macaddr) { - return zvni_macip_send_msg_to_client (zvrf, vni, macaddr, ip, + return zvni_macip_send_msg_to_client (zvrf, vni, macaddr, ip, 0, ZEBRA_MACIP_ADD); } @@ -787,7 +790,7 @@ static int zvni_neigh_send_del_to_client (struct zebra_vrf *zvrf, vni_t vni, struct ipaddr *ip, struct ethaddr *macaddr) { - return zvni_macip_send_msg_to_client (zvrf, vni, macaddr, ip, + return zvni_macip_send_msg_to_client (zvrf, vni, macaddr, ip, 0, ZEBRA_MACIP_DEL); } @@ -967,6 +970,7 @@ zvni_mac_del_hash_entry (struct hash_backet *backet, void *arg) { struct mac_walk_ctx *wctx = arg; zebra_mac_t *mac = backet->data; + u_char sticky = 0; if (((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_LOCAL)) || ((wctx->flags & DEL_REMOTE_MAC) && (mac->flags & ZEBRA_MAC_REMOTE)) || @@ -977,8 +981,9 @@ zvni_mac_del_hash_entry (struct hash_backet *backet, void *arg) { if (wctx->upd_client && (mac->flags & ZEBRA_MAC_LOCAL)) { + sticky = CHECK_FLAG (mac->flags, ZEBRA_MAC_STICKY) ? 1: 0; zvni_mac_send_del_to_client (wctx->zvrf, wctx->zvni->vni, - &mac->macaddr); + &mac->macaddr, sticky); } if (wctx->uninstall) @@ -1058,10 +1063,10 @@ zvni_mac_lookup (zebra_vni_t *zvni, struct ethaddr *mac) */ static int zvni_mac_send_add_to_client (struct zebra_vrf *zvrf, vni_t vni, - struct ethaddr *macaddr) + struct ethaddr *macaddr, u_char sticky) { return zvni_macip_send_msg_to_client (zvrf, vni, macaddr, NULL, - ZEBRA_MACIP_ADD); + sticky, ZEBRA_MACIP_ADD); } /* @@ -1069,10 +1074,10 @@ zvni_mac_send_add_to_client (struct zebra_vrf *zvrf, vni_t vni, */ static int zvni_mac_send_del_to_client (struct zebra_vrf *zvrf, vni_t vni, - struct ethaddr *macaddr) + struct ethaddr *macaddr, u_char sticky) { return zvni_macip_send_msg_to_client (zvrf, vni, macaddr, NULL, - ZEBRA_MACIP_DEL); + sticky, ZEBRA_MACIP_DEL); } /* @@ -1259,6 +1264,7 @@ zvni_mac_install (zebra_vni_t *zvni, zebra_mac_t *mac) { struct zebra_if *zif; struct zebra_l2info_vxlan *vxl; + u_char sticky; if (!(mac->flags & ZEBRA_MAC_REMOTE)) return 0; @@ -1268,8 +1274,10 @@ zvni_mac_install (zebra_vni_t *zvni, zebra_mac_t *mac) return -1; vxl = &zif->l2info.vxl; + sticky = CHECK_FLAG (mac->flags, ZEBRA_MAC_STICKY) ? 1: 0; + return kernel_add_mac (zvni->vxlan_if, vxl->access_vlan, - &mac->macaddr, mac->fwd_info.r_vtep_ip); + &mac->macaddr, mac->fwd_info.r_vtep_ip, sticky); } /* @@ -2353,6 +2361,7 @@ zebra_vxlan_remote_macip_add (struct zserv *client, int sock, int update_mac = 0, update_neigh = 0; char buf[ETHER_ADDR_STRLEN]; char buf1[INET6_ADDRSTRLEN]; + u_char sticky; assert (EVPN_ENABLED (zvrf)); @@ -2380,9 +2389,14 @@ zebra_vxlan_remote_macip_add (struct zserv *client, int sock, vtep_ip.s_addr = stream_get_ipv4 (s); l += IPV4_MAX_BYTELEN; + /* Get 'sticky' flag. */ + sticky = stream_getc(s); + l++; + if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug ("%u:Recv MACIP Add MAC %s IP %s VNI %u Remote VTEP %s from %s", + zlog_debug ("%u:Recv MACIP Add %sMAC %s IP %s VNI %u Remote VTEP %s from %s", zvrf_id (zvrf), + sticky ? "sticky " : "", prefix_mac2str (&macaddr, buf, sizeof (buf)), ipaddr2str (&ip, buf1, sizeof (buf1)), vni, inet_ntoa (vtep_ip), @@ -2431,6 +2445,7 @@ zebra_vxlan_remote_macip_add (struct zserv *client, int sock, */ mac = zvni_mac_lookup (zvni, &macaddr); if (!mac || !CHECK_FLAG (mac->flags, ZEBRA_MAC_REMOTE) || + (CHECK_FLAG (mac->flags, ZEBRA_MAC_STICKY) ? 1: 0) != sticky || !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip)) update_mac = 1; @@ -2464,6 +2479,11 @@ zebra_vxlan_remote_macip_add (struct zserv *client, int sock, SET_FLAG (mac->flags, ZEBRA_MAC_REMOTE); mac->fwd_info.r_vtep_ip = vtep_ip; + if (sticky) + SET_FLAG (mac->flags, ZEBRA_MAC_STICKY); + else + UNSET_FLAG (mac->flags, ZEBRA_MAC_STICKY); + /* Install the entry. */ zvni_mac_install (zvni, mac); } @@ -2543,6 +2563,7 @@ zebra_vxlan_check_del_local_mac (struct interface *ifp, zebra_vni_t *zvni; zebra_mac_t *mac; char buf[ETHER_ADDR_STRLEN]; + u_char sticky; zif = ifp->info; assert(zif); @@ -2577,7 +2598,8 @@ zebra_vxlan_check_del_local_mac (struct interface *ifp, ifp->name, ifp->ifindex, vni); /* Remove MAC from BGP. */ - zvni_mac_send_del_to_client (zvrf, zvni->vni, macaddr); + sticky = CHECK_FLAG (mac->flags, ZEBRA_MAC_STICKY) ? 1: 0; + zvni_mac_send_del_to_client (zvrf, zvni->vni, macaddr, sticky); /* Delete this MAC entry. */ zvni_mac_del (zvni, mac); @@ -2651,6 +2673,7 @@ zebra_vxlan_local_mac_del (struct interface *ifp, struct interface *br_if, zebra_mac_t *mac; struct zebra_vrf *zvrf; char buf[ETHER_ADDR_STRLEN]; + u_char sticky; /* We are interested in MACs only on ports or (port, VLAN) that * map to a VNI. @@ -2684,7 +2707,8 @@ zebra_vxlan_local_mac_del (struct interface *ifp, struct interface *br_if, assert(zvrf); /* Remove MAC from BGP. */ - zvni_mac_send_del_to_client (zvrf, zvni->vni, macaddr); + sticky = CHECK_FLAG (mac->flags, ZEBRA_MAC_STICKY) ? 1: 0; + zvni_mac_send_del_to_client (zvrf, zvni->vni, macaddr, sticky); /* Delete this MAC entry. */ zvni_mac_del (zvni, mac); @@ -2697,13 +2721,15 @@ zebra_vxlan_local_mac_del (struct interface *ifp, struct interface *br_if, */ int zebra_vxlan_local_mac_add_update (struct interface *ifp, struct interface *br_if, - struct ethaddr *macaddr, vlanid_t vid) + struct ethaddr *macaddr, vlanid_t vid, + u_char sticky) { zebra_vni_t *zvni; zebra_mac_t *mac; struct zebra_vrf *zvrf; char buf[ETHER_ADDR_STRLEN]; int add = 1; + u_char mac_sticky; /* We are interested in MACs only on ports or (port, VLAN) that * map to a VNI. @@ -2712,8 +2738,9 @@ zebra_vxlan_local_mac_add_update (struct interface *ifp, struct interface *br_if if (!zvni) { if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug ("%u:Add/Update MAC %s intf %s(%u) VID %u, could not find VNI", + zlog_debug ("%u:Add/Update %sMAC %s intf %s(%u) VID %u, could not find VNI", ifp->vrf_id, + sticky ? "sticky " : "", prefix_mac2str (macaddr, buf, sizeof (buf)), ifp->name, ifp->ifindex, vid); return 0; @@ -2727,8 +2754,9 @@ zebra_vxlan_local_mac_add_update (struct interface *ifp, struct interface *br_if } if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug ("%u:Add/Update MAC %s intf %s(%u) VID %u -> VNI %u", + zlog_debug ("%u:Add/Update %sMAC %s intf %s(%u) VID %u -> VNI %u", ifp->vrf_id, + sticky ? "sticky " : "", prefix_mac2str (macaddr, buf, sizeof (buf)), ifp->name, ifp->ifindex, vid, zvni->vni); @@ -2738,13 +2766,17 @@ zebra_vxlan_local_mac_add_update (struct interface *ifp, struct interface *br_if { if (CHECK_FLAG (mac->flags, ZEBRA_MAC_LOCAL)) { - if (mac->fwd_info.local.ifindex == ifp->ifindex && + mac_sticky = CHECK_FLAG (mac->flags, ZEBRA_MAC_STICKY) ? 1: 0; + + if (mac_sticky == sticky && + mac->fwd_info.local.ifindex == ifp->ifindex && mac->fwd_info.local.vid == vid) { if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug ("%u:Add/Update MAC %s intf %s(%u) VID %u -> VNI %u, " + zlog_debug ("%u:Add/Update %sMAC %s intf %s(%u) VID %u -> VNI %u, " "entry exists and has not changed ", ifp->vrf_id, + sticky ? "sticky " : "", prefix_mac2str (macaddr, buf, sizeof (buf)), ifp->name, ifp->ifindex, vid, zvni->vni); return 0; @@ -2777,9 +2809,14 @@ zebra_vxlan_local_mac_add_update (struct interface *ifp, struct interface *br_if mac->fwd_info.local.ifindex = ifp->ifindex; mac->fwd_info.local.vid = vid; + if (sticky) + SET_FLAG (mac->flags, ZEBRA_MAC_STICKY); + else + UNSET_FLAG (mac->flags, ZEBRA_MAC_STICKY); + /* Inform BGP if required. */ if (add) - return zvni_mac_send_add_to_client (zvrf, zvni->vni, macaddr); + return zvni_mac_send_add_to_client (zvrf, zvni->vni, macaddr, sticky); return 0; } diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h index 37af55e1ea..e5f0bd2f66 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -80,7 +80,8 @@ extern int zebra_vxlan_remote_macip_del (struct zserv *client, int sock, u_short length, struct zebra_vrf *zvrf); extern int zebra_vxlan_local_mac_add_update (struct interface *ifp, struct interface *br_if, - struct ethaddr *mac, vlanid_t vid); + struct ethaddr *mac, vlanid_t vid, + u_char sticky); extern int zebra_vxlan_local_mac_del (struct interface *ifp, struct interface *br_if, struct ethaddr *mac, vlanid_t vid); diff --git a/zebra/zebra_vxlan_null.c b/zebra/zebra_vxlan_null.c index 75aab40870..b0f09930bc 100644 --- a/zebra/zebra_vxlan_null.c +++ b/zebra/zebra_vxlan_null.c @@ -111,7 +111,8 @@ int zebra_vxlan_remote_macip_del (struct zserv *client, int sock, int zebra_vxlan_local_mac_add_update (struct interface *ifp, struct interface *br_if, - struct ethaddr *mac, vlanid_t vid) + struct ethaddr *mac, vlanid_t vid, + u_char sticky) { return 0; } diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h index 6d72edcb03..0de86c3bc2 100644 --- a/zebra/zebra_vxlan_private.h +++ b/zebra/zebra_vxlan_private.h @@ -102,6 +102,7 @@ struct zebra_mac_t_ #define ZEBRA_MAC_LOCAL 0x01 #define ZEBRA_MAC_REMOTE 0x02 #define ZEBRA_MAC_AUTO 0x04 /* Auto created for neighbor. */ +#define ZEBRA_MAC_STICKY 0x08 /* Static MAC */ /* Local or remote info. */ union From 11e2785d09f06a68fa169e374bc53f9772087a27 Mon Sep 17 00:00:00 2001 From: vivek Date: Mon, 15 May 2017 14:50:21 -0700 Subject: [PATCH 21/31] bgpd: MAC Mobility extended community string conversion Updates: d5b9da8a79cbf2acf287bda2600e86a5a3243c64 Updates: 749513cc9d7bf571b3049931057d544b4111c39d Signed-off-by: Vivek Venkatraman Signed-off-by: Daniel Walton --- bgpd/bgp_ecommunity.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index bb2ef260ee..9349214348 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -794,6 +794,18 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format, int filter) macaddr[0], macaddr[1], macaddr[2], macaddr[3], macaddr[4], macaddr[5]); } + else if (*pnt == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY) + { + u_int32_t seqnum; + u_char flags = *++pnt; + + memcpy (&seqnum, pnt + 2, 4); + seqnum = ntohl(seqnum); + if (flags & ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY) + len = sprintf (str_buf + str_pnt, "MM:%u, sticky MAC", seqnum); + else + len = sprintf (str_buf + str_pnt, "MM:%u", seqnum); + } else unk_ecom = 1; } From b16031a2ecdd354e0d74d7074987e7525d260e77 Mon Sep 17 00:00:00 2001 From: vivek Date: Mon, 15 May 2017 14:52:17 -0700 Subject: [PATCH 22/31] bgpd: Debug logging updates for EVPN Ensure VNI and EVPN nexthops are logged in debug logs. Updates: "bgpd: labeled unicast processing" Signed-off-by: Vivek Venkatraman --- bgpd/bgp_debug.c | 32 +++++++++++---- bgpd/bgp_debug.h | 3 +- bgpd/bgp_evpn.c | 13 ++++++ bgpd/bgp_evpn.h | 2 + bgpd/bgp_route.c | 86 ++++++++++++++++++++++++---------------- bgpd/bgp_updgrp_packet.c | 27 +++++-------- 6 files changed, 104 insertions(+), 59 deletions(-) diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 450f68fec4..a48df5c0c8 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -40,6 +40,8 @@ #include "bgpd/bgp_updgrp.h" #include "bgpd/bgp_mplsvpn.h" #include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_label.h" +#include "bgpd/bgp_evpn.h" unsigned long conf_bgp_debug_as4; unsigned long conf_bgp_debug_neighbor_events; @@ -410,6 +412,9 @@ bgp_dump_attr (struct attr *attr, char *buf, size_t size) snprintf (buf + strlen (buf), size - strlen (buf), "(%s)", inet_ntop (AF_INET6, &attr->extra->mp_nexthop_local, addrbuf, BUFSIZ)); + + if (attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV4) + snprintf (buf, size, "nexthop %s", inet_ntoa (attr->nexthop)); } if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))) @@ -2147,12 +2152,14 @@ bgp_debug_zebra (struct prefix *p) } const char * -bgp_debug_rdpfxpath2str (struct prefix_rd *prd, union prefixconstptr pu, - int addpath_valid, u_int32_t addpath_id, - char *str, int size) +bgp_debug_rdpfxpath2str (afi_t afi, safi_t safi, + struct prefix_rd *prd, union prefixconstptr pu, + mpls_label_t *label, int addpath_valid, + u_int32_t addpath_id, char *str, int size) { char rd_buf[RD_ADDRSTRLEN]; char pfx_buf[PREFIX_STRLEN]; + char tag_buf[30]; /* ' with addpath ID ' 17 * max strlen of uint32 + 10 * +/- (just in case) + 1 @@ -2168,13 +2175,24 @@ bgp_debug_rdpfxpath2str (struct prefix_rd *prd, union prefixconstptr pu, if (addpath_valid) snprintf(pathid_buf, sizeof(pathid_buf), " with addpath ID %u", addpath_id); + tag_buf[0] = '\0'; + if (bgp_labeled_safi (safi) && label) + { + u_int32_t label_value; + + label_value = decode_label (label); + sprintf (tag_buf, " label %u", label_value); + } + if (prd) - snprintf (str, size, "RD %s %s%s", + snprintf (str, size, "RD %s %s%s%s", prefix_rd2str(prd, rd_buf, sizeof (rd_buf)), - prefix2str (pu, pfx_buf, sizeof (pfx_buf)), pathid_buf); + prefix2str (pu, pfx_buf, sizeof (pfx_buf)), + tag_buf, pathid_buf); else - snprintf (str, size, "%s%s", - prefix2str (pu, pfx_buf, sizeof (pfx_buf)), pathid_buf); + snprintf (str, size, "%s%s%s", + prefix2str (pu, pfx_buf, sizeof (pfx_buf)), + tag_buf, pathid_buf); return str; } diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h index 5ec2eaa7c5..11ab4dbd65 100644 --- a/bgpd/bgp_debug.h +++ b/bgpd/bgp_debug.h @@ -153,7 +153,8 @@ extern int bgp_debug_bestpath(struct prefix *p); extern int bgp_debug_zebra(struct prefix *p); extern int bgp_debug_count(void); -extern const char *bgp_debug_rdpfxpath2str (struct prefix_rd *, union prefixconstptr, +extern const char *bgp_debug_rdpfxpath2str (afi_t, safi_t, struct prefix_rd *, + union prefixconstptr, mpls_label_t *, int, u_int32_t, char *, int); const char *bgp_notify_admin_message(char *buf, size_t bufsz, u_char *data, size_t datalen); diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 130017562e..5bff857236 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1968,6 +1968,19 @@ free_vni_entry (struct hash_backet *backet, struct bgp *bgp) * Public functions. */ +/* + * Function to display "tag" in route as a VNI. + */ +char * +bgp_evpn_label2str (mpls_label_t *label, char *buf, int len) +{ + vni_t vni; + + vni = label2vni (label); + snprintf (buf, len, "%u", vni); + return buf; +} + /* * Encode EVPN prefix in Update (MP_REACH) */ diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index ed76bc3a4d..9e471138f5 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -23,6 +23,8 @@ #include "vxlan.h" +extern char * +bgp_evpn_label2str (mpls_label_t *label, char *buf, int len); extern void bgp_evpn_encode_prefix (struct stream *s, struct prefix *p, struct prefix_rd *prd, mpls_label_t *label, diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index e55cd7b949..6a2cc8d4d3 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2605,8 +2605,6 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, bgp = peer->bgp; rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd); - label_buf[0] = '\0'; - has_valid_label = bgp_is_valid_label(label); if (has_valid_label) @@ -2721,9 +2719,12 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, && CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) { if (bgp_debug_update(peer, p, NULL, 1)) - zlog_debug ("%s rcvd %s %s", peer->host, - bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0, - addpath_id, pfx_buf, sizeof (pfx_buf)), label_buf); + { + bgp_debug_rdpfxpath2str (afi, safi, prd, p, label, + addpath_id ? 1 : 0, addpath_id, + pfx_buf, sizeof (pfx_buf)); + zlog_debug ("%s rcvd %s", peer->host, pfx_buf); + } if (bgp_damp_update (ri, rn, afi, safi) != BGP_DAMP_SUPPRESSED) { @@ -2741,10 +2742,11 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, peer->rcvd_attr_printed = 1; } - zlog_debug ("%s rcvd %s %s...duplicate ignored", - peer->host, - bgp_debug_rdpfxpath2str (prd, p, addpath_id ? - 1 : 0, addpath_id, pfx_buf, sizeof (pfx_buf)), label_buf); + bgp_debug_rdpfxpath2str (afi, safi, prd, p, label, + addpath_id ? 1 : 0, addpath_id, + pfx_buf, sizeof (pfx_buf)); + zlog_debug ("%s rcvd %s...duplicate ignored", + peer->host, pfx_buf); } /* graceful restart STALE flag unset. */ @@ -2765,18 +2767,25 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) { if (bgp_debug_update(peer, p, NULL, 1)) - zlog_debug ("%s rcvd %s %s, flapped quicker than processing", - peer->host, - bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0, - addpath_id, pfx_buf, sizeof (pfx_buf)), label_buf); + { + bgp_debug_rdpfxpath2str (afi, safi, prd, p, label, + addpath_id ? 1 : 0, addpath_id, + pfx_buf, sizeof (pfx_buf)); + zlog_debug ("%s rcvd %s, flapped quicker than processing", + peer->host, pfx_buf); + } + bgp_info_restore (rn, ri); } /* Received Logging. */ if (bgp_debug_update(peer, p, NULL, 1)) - zlog_debug ("%s rcvd %s %s", peer->host, - bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0, - addpath_id, pfx_buf, sizeof (pfx_buf)), label_buf); + { + bgp_debug_rdpfxpath2str (afi, safi, prd, p, label, + addpath_id ? 1 : 0, addpath_id, + pfx_buf, sizeof (pfx_buf)); + zlog_debug ("%s rcvd %s", peer->host, pfx_buf); + } /* graceful restart STALE flag unset. */ if (CHECK_FLAG (ri->flags, BGP_INFO_STALE)) @@ -2995,9 +3004,10 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, peer->rcvd_attr_printed = 1; } - zlog_debug ("%s rcvd %s %s ", peer->host, - bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0, - addpath_id, pfx_buf, sizeof (pfx_buf)), label_buf); + bgp_debug_rdpfxpath2str (afi, safi, prd, p, label, + addpath_id ? 1 : 0, addpath_id, + pfx_buf, sizeof (pfx_buf)); + zlog_debug ("%s rcvd %s", peer->host, pfx_buf); } /* Make new BGP info. */ @@ -3117,10 +3127,11 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, peer->rcvd_attr_printed = 1; } - zlog_debug ("%s rcvd UPDATE about %s %s -- DENIED due to: %s", - peer->host, - bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0, - addpath_id, pfx_buf, sizeof (pfx_buf)), label_buf, reason); + bgp_debug_rdpfxpath2str (afi, safi, prd, p, label, + addpath_id ? 1 : 0, addpath_id, + pfx_buf, sizeof (pfx_buf)); + zlog_debug ("%s rcvd UPDATE about %s -- DENIED due to: %s", + peer->host, pfx_buf, reason); } if (ri) @@ -3184,10 +3195,13 @@ bgp_withdraw (struct peer *peer, struct prefix *p, u_int32_t addpath_id, if (!bgp_adj_in_unset (rn, peer, addpath_id)) { if (bgp_debug_update (peer, p, NULL, 1)) - zlog_debug ("%s withdrawing route %s not in adj-in", - peer->host, - bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0, - addpath_id, pfx_buf, sizeof (pfx_buf))); + { + bgp_debug_rdpfxpath2str (afi, safi, prd, p, label, + addpath_id ? 1 : 0, addpath_id, + pfx_buf, sizeof (pfx_buf)); + zlog_debug ("%s withdrawing route %s not in adj-in", + peer->host, pfx_buf); + } bgp_unlock_node (rn); return 0; } @@ -3201,20 +3215,24 @@ bgp_withdraw (struct peer *peer, struct prefix *p, u_int32_t addpath_id, /* Logging. */ if (bgp_debug_update(peer, p, NULL, 1)) { + bgp_debug_rdpfxpath2str (afi, safi, prd, p, label, + addpath_id ? 1 : 0, addpath_id, + pfx_buf, sizeof (pfx_buf)); zlog_debug ("%s rcvd UPDATE about %s -- withdrawn", - peer->host, - bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0, - addpath_id, pfx_buf, sizeof (pfx_buf))); + peer->host, pfx_buf); } /* Withdraw specified route from routing table. */ if (ri && ! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) bgp_rib_withdraw (rn, ri, peer, afi, safi, prd); else if (bgp_debug_update(peer, p, NULL, 1)) - zlog_debug ("%s Can't find the route %s", - peer->host, - bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0, - addpath_id, pfx_buf, sizeof (pfx_buf))); + { + bgp_debug_rdpfxpath2str (afi, safi, prd, p, label, + addpath_id ? 1 : 0, addpath_id, + pfx_buf, sizeof (pfx_buf)); + zlog_debug ("%s Can't find the route %s", + peer->host, pfx_buf); + } /* Unlock bgp_node_get() lock. */ bgp_unlock_node (rn); diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index 872ead000c..df1bb1eab2 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -703,7 +703,7 @@ subgroup_update_packet (struct update_subgroup *subgrp) int addpath_encode = 0; u_int32_t addpath_tx_id = 0; struct prefix_rd *prd = NULL; - char label_buf[20]; + mpls_label_t label = MPLS_INVALID_LABEL; if (!subgrp) return NULL; @@ -718,7 +718,6 @@ subgroup_update_packet (struct update_subgroup *subgrp) stream_reset (s); snlri = subgrp->scratch; stream_reset (snlri); - label_buf[0] = '\0'; bpacket_attr_vec_arr_reset (&vecarr); @@ -807,8 +806,6 @@ subgroup_update_packet (struct update_subgroup *subgrp) else { /* Encode the prefix in MP_REACH_NLRI attribute */ - mpls_label_t label = MPLS_INVALID_LABEL; - if (rn->prn) prd = (struct prefix_rd *) &rn->prn->p; @@ -818,9 +815,6 @@ subgroup_update_packet (struct update_subgroup *subgrp) if (binfo && binfo->extra) label = binfo->extra->label; - if (bgp_labeled_safi(safi)) - sprintf (label_buf, "label %u", label_pton(&label)); - if (stream_empty (snlri)) mpattrlen_pos = bgp_packet_mpattr_start (snlri, peer, afi, safi, &vecarr, adv->baa->attr); @@ -853,12 +847,11 @@ subgroup_update_packet (struct update_subgroup *subgrp) send_attr_printed = 1; } - zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s %s", - subgrp->update_group->id, subgrp->id, - bgp_debug_rdpfxpath2str (prd, &rn->p, addpath_encode, - addpath_tx_id, - pfx_buf, sizeof (pfx_buf)), - label_buf); + bgp_debug_rdpfxpath2str (afi, safi, prd, &rn->p, &label, + addpath_encode, addpath_tx_id, + pfx_buf, sizeof (pfx_buf)); + zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s", + subgrp->update_group->id, subgrp->id, pfx_buf); } /* Synchnorize attribute. */ @@ -1011,11 +1004,11 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp) { char pfx_buf[BGP_PRD_PATH_STRLEN]; + bgp_debug_rdpfxpath2str (afi, safi, prd, &rn->p, NULL, + addpath_encode, addpath_tx_id, + pfx_buf, sizeof (pfx_buf)); zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s -- unreachable", - subgrp->update_group->id, subgrp->id, - bgp_debug_rdpfxpath2str (prd, &rn->p, - addpath_encode, addpath_tx_id, - pfx_buf, sizeof (pfx_buf))); + subgrp->update_group->id, subgrp->id, pfx_buf); } subgrp->scount--; From 520d5d768b996e96c375562d2b92c37801f9081b Mon Sep 17 00:00:00 2001 From: vivek Date: Mon, 15 May 2017 14:53:31 -0700 Subject: [PATCH 23/31] bgpd: Display (show) commands for EVPN Implement various operational/display commands for EVPN: - show bgp evpn summary - show bgp evpn vni [] - show bgp evpn route [type ] - show bgp evpn route [rd [type ]] - show bgp evpn route [rd [mac [ip ]]] - show bgp evpn route vni [type | vtep ] - show bgp evpn route vni [mac [ip ]]] - show bgp evpn route vni [multicast ] - show bgp evpn route vni all [vtep ] - show bgp evpn import-rt Signed-off-by: Vivek Venkatraman Signed-off-by: Daniel Walton Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_evpn.c | 45 ++ bgpd/bgp_evpn.h | 4 + bgpd/bgp_evpn_vty.c | 1064 +++++++++++++++++++++++++++++++++++++++++++ bgpd/bgp_route.c | 96 +++- bgpd/bgp_route.h | 9 + bgpd/bgp_vty.c | 2 +- bgpd/bgp_vty.h | 3 + 7 files changed, 1215 insertions(+), 8 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 5bff857236..f17bcfab1e 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1981,6 +1981,51 @@ bgp_evpn_label2str (mpls_label_t *label, char *buf, int len) return buf; } +/* + * Function to convert evpn route to string. + * NOTE: We don't use prefix2str as the output here is a bit different. + */ +char * +bgp_evpn_route2str (struct prefix_evpn *p, char *buf, int len) +{ + char buf1[ETHER_ADDR_STRLEN]; + char buf2[PREFIX2STR_BUFFER]; + + if (p->prefix.route_type == BGP_EVPN_IMET_ROUTE) + { + snprintf (buf, len, "[%d]:[0]:[%d]:[%s]", + p->prefix.route_type, IS_EVPN_PREFIX_IPADDR_V4(p) ? \ + IPV4_MAX_BITLEN : IPV6_MAX_BITLEN, + inet_ntoa(p->prefix.ip.ipaddr_v4)); + } + else if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) + { + if (IS_EVPN_PREFIX_IPADDR_NONE(p)) + snprintf (buf, len, "[%d]:[0]:[0]:[%d]:[%s]", + p->prefix.route_type, 8*ETHER_ADDR_LEN, + prefix_mac2str (&p->prefix.mac, buf1, sizeof(buf1))); + else + { + u_char family; + + family = IS_EVPN_PREFIX_IPADDR_V4(p) ? \ + AF_INET : AF_INET6; + snprintf (buf, len, "[%d]:[0]:[0]:[%d]:[%s]:[%d]:[%s]", + p->prefix.route_type, 8*ETHER_ADDR_LEN, + prefix_mac2str (&p->prefix.mac, buf1, sizeof(buf1)), + family == AF_INET ? IPV4_MAX_BITLEN : IPV6_MAX_BITLEN, + inet_ntop (family, &p->prefix.ip.ip.addr, + buf2, PREFIX2STR_BUFFER)); + } + } + else + { + /* Currently, this is to cater to other AF_ETHERNET code. */ + } + + return(buf); +} + /* * Encode EVPN prefix in Update (MP_REACH) */ diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index 9e471138f5..1a71ec284a 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -23,8 +23,12 @@ #include "vxlan.h" +#define EVPN_ROUTE_STRLEN 200 /* Must be >> MAC + IPv6 strings. */ + extern char * bgp_evpn_label2str (mpls_label_t *label, char *buf, int len); +extern char * +bgp_evpn_route2str (struct prefix_evpn *p, char *buf, int len); extern void bgp_evpn_encode_prefix (struct stream *s, struct prefix *p, struct prefix_rd *prd, mpls_label_t *label, diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 6335b9d468..9a8078ca99 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -33,11 +33,307 @@ #include "bgpd/bgp_evpn.h" #include "bgpd/bgp_evpn_private.h" #include "bgpd/bgp_zebra.h" +#include "bgpd/bgp_vty.h" #define SHOW_DISPLAY_STANDARD 0 #define SHOW_DISPLAY_TAGS 1 #define SHOW_DISPLAY_OVERLAY 2 +/* + * Context for VNI hash walk - used by callbacks. + */ +struct vni_walk_ctx +{ + struct bgp *bgp; + struct vty *vty; + struct in_addr vtep_ip; +}; + +static void +display_import_rt (struct vty *vty, struct irt_node *irt) +{ + u_char *pnt; + u_char type, sub_type; + struct ecommunity_as + { + as_t as; + u_int32_t val; + } eas; + struct ecommunity_ip + { + struct in_addr ip; + u_int16_t val; + } eip; + struct listnode *node, *nnode; + struct bgpevpn *tmp_vpn; + + + /* TODO: This needs to go into a function */ + + pnt = (u_char *)&irt->rt.val; + type = *pnt++; + sub_type = *pnt++; + if (sub_type != ECOMMUNITY_ROUTE_TARGET) + return; + + switch (type) + { + case ECOMMUNITY_ENCODE_AS: + eas.as = (*pnt++ << 8); + eas.as |= (*pnt++); + + eas.val = (*pnt++ << 24); + eas.val |= (*pnt++ << 16); + eas.val |= (*pnt++ << 8); + eas.val |= (*pnt++); + + vty_out (vty, "Route-target: %u:%u", eas.as, eas.val); + break; + + case ECOMMUNITY_ENCODE_IP: + memcpy (&eip.ip, pnt, 4); + pnt += 4; + eip.val = (*pnt++ << 8); + eip.val |= (*pnt++); + + vty_out (vty, "Route-target: %s:%u", + inet_ntoa (eip.ip), eip.val); + break; + + case ECOMMUNITY_ENCODE_AS4: + eas.as = (*pnt++ << 24); + eas.as |= (*pnt++ << 16); + eas.as |= (*pnt++ << 8); + eas.as |= (*pnt++); + + eas.val = (*pnt++ << 8); + eas.val |= (*pnt++); + + vty_out (vty, "Route-target: %u:%u", eas.as, eas.val); + break; + + default: + return; + } + + vty_out (vty, "%s", VTY_NEWLINE); + vty_out (vty, "List of VNIs importing routes with this route-target:%s", + VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS (irt->vnis, node, nnode, tmp_vpn)) + vty_out (vty, " %u%s", tmp_vpn->vni, VTY_NEWLINE); +} + +static void +show_import_rt_entry (struct hash_backet *backet, struct vty *vty) +{ + struct irt_node *irt = (struct irt_node *) backet->data; + display_import_rt (vty, irt); +} + +static void +bgp_evpn_show_route_rd_header (struct vty *vty, struct bgp_node *rd_rn) +{ + u_int16_t type; + struct rd_as rd_as; + struct rd_ip rd_ip; + u_char *pnt; + + pnt = rd_rn->p.u.val; + + /* Decode RD type. */ + type = decode_rd_type (pnt); + + vty_out (vty, "Route Distinguisher: "); + + switch (type) + { + case RD_TYPE_AS: + decode_rd_as (pnt + 2, &rd_as); + vty_out (vty, "%u:%d", rd_as.as, rd_as.val); + break; + + case RD_TYPE_IP: + decode_rd_ip (pnt + 2, &rd_ip); + vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); + break; + + default: + vty_out (vty, "Unknown RD type"); + break; + } + + vty_out (vty, "%s", VTY_NEWLINE); +} + +static void +bgp_evpn_show_route_header (struct vty *vty, struct bgp *bgp) +{ + char ri_header[] = " Network Next Hop Metric LocPrf Weight Path%s"; + + vty_out (vty, "BGP table version is 0, local router ID is %s%s", + inet_ntoa (bgp->router_id), VTY_NEWLINE); + vty_out (vty, "Status codes: s suppressed, d damped, h history, " + "* valid, > best, i - internal%s", VTY_NEWLINE); + vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s", + VTY_NEWLINE); + vty_out (vty, "EVPN type-2 prefix: [2]:[ESI]:[EthTag]:[MAClen]:[MAC]:[IPlen]:[IP]%s", + VTY_NEWLINE); + vty_out (vty, "EVPN type-3 prefix: [3]:[EthTag]:[IPlen]:[OrigIP]%s%s", + VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, ri_header, VTY_NEWLINE); +} + +static void +display_vni (struct vty *vty, struct bgpevpn *vpn) +{ + char buf1[INET6_ADDRSTRLEN]; + char *ecom_str; + struct listnode *node, *nnode; + struct ecommunity *ecom; + + vty_out (vty, "VNI: %d", vpn->vni); + if (is_vni_live (vpn)) + vty_out (vty, " (known to the kernel)"); + vty_out (vty, "%s", VTY_NEWLINE); + + vty_out (vty, " RD: %s%s", + prefix_rd2str (&vpn->prd, buf1, RD_ADDRSTRLEN), + VTY_NEWLINE); + vty_out (vty, " Originator IP: %s%s", + inet_ntoa(vpn->originator_ip), VTY_NEWLINE); + + vty_out (vty, " Import Route Target:%s", VTY_NEWLINE); + for (ALL_LIST_ELEMENTS (vpn->import_rtl, node, nnode, ecom)) + { + ecom_str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0); + vty_out (vty, " %s%s", ecom_str, VTY_NEWLINE); + XFREE (MTYPE_ECOMMUNITY_STR, ecom_str); + } + + vty_out (vty, " Export Route Target:%s", VTY_NEWLINE); + for (ALL_LIST_ELEMENTS (vpn->export_rtl, node, nnode, ecom)) + { + ecom_str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0); + vty_out (vty, " %s%s", ecom_str, VTY_NEWLINE); + XFREE (MTYPE_ECOMMUNITY_STR, ecom_str); + } +} + +static void +show_vni_routes (struct bgp *bgp, struct bgpevpn *vpn, int type, + struct vty *vty, struct in_addr vtep_ip) +{ + struct bgp_node *rn; + struct bgp_info *ri; + int header = 1; + u_int32_t prefix_cnt, path_cnt; + + prefix_cnt = path_cnt = 0; + + for (rn = bgp_table_top (vpn->route_table); rn; rn = bgp_route_next (rn)) + { + struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; + + if (type && + evp->prefix.route_type != type) + continue; + + if (rn->info) + { + /* Overall header/legend displayed once. */ + if (header) + { + bgp_evpn_show_route_header (vty, bgp); + header = 0; + } + + prefix_cnt++; + } + + /* For EVPN, the prefix is displayed for each path (to fit in + * with code that already exists). + */ + for (ri = rn->info; ri; ri = ri->next) + { + if (vtep_ip.s_addr && + !IPV4_ADDR_SAME(&(vtep_ip), &(ri->attr->nexthop))) + continue; + + path_cnt++; + route_vty_out (vty, &rn->p, ri, 0, SAFI_EVPN, NULL); + } + } + + if (prefix_cnt == 0) + vty_out (vty, "No EVPN prefixes %sexist for this VNI%s", + type ? "(of requested type) " : "", VTY_NEWLINE); + else + vty_out (vty, "%sDisplayed %u prefixes (%u paths)%s%s", + VTY_NEWLINE, prefix_cnt, path_cnt, + type ? " (of requested type)" : "", VTY_NEWLINE); +} + +static void +show_vni_routes_hash (struct hash_backet *backet, void *arg) +{ + struct bgpevpn *vpn = (struct bgpevpn *) backet->data; + struct vni_walk_ctx *wctx = arg; + struct vty *vty = wctx->vty; + + vty_out (vty, "%sVNI: %d%s%s", VTY_NEWLINE, vpn->vni, VTY_NEWLINE, VTY_NEWLINE); + show_vni_routes (wctx->bgp, vpn, 0, wctx->vty, wctx->vtep_ip); +} + +static void +show_vni_entry (struct hash_backet *backet, struct vty *vty) +{ + struct bgpevpn *vpn = (struct bgpevpn *) backet->data; + char buf1[10]; + char buf2[INET6_ADDRSTRLEN]; + char rt_buf[25]; + char *ecom_str; + struct listnode *node, *nnode; + struct ecommunity *ecom; + + buf1[0] = '\0'; + if (is_vni_live (vpn)) + sprintf (buf1, "*"); + + vty_out(vty, "%-1s %-10u %-15s %-21s", + buf1, vpn->vni, inet_ntoa(vpn->originator_ip), + prefix_rd2str (&vpn->prd, buf2, RD_ADDRSTRLEN)); + + for (ALL_LIST_ELEMENTS (vpn->import_rtl, node, nnode, ecom)) + { + ecom_str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0); + + if (listcount(vpn->import_rtl) > 1) + sprintf (rt_buf, "%s, ...", ecom_str); + else + sprintf (rt_buf, "%s", ecom_str); + vty_out (vty, " %-25s", rt_buf); + + XFREE (MTYPE_ECOMMUNITY_STR, ecom_str); + break; + } + + for (ALL_LIST_ELEMENTS (vpn->export_rtl, node, nnode, ecom)) + { + ecom_str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0); + + if (listcount(vpn->export_rtl) > 1) + sprintf (rt_buf, "%s, ...", ecom_str); + else + sprintf (rt_buf, "%s", ecom_str); + vty_out (vty, " %-25s", rt_buf); + + XFREE (MTYPE_ECOMMUNITY_STR, ecom_str); + break; + } + vty_out (vty, "%s", VTY_NEWLINE); +} + static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd, enum bgp_show_type type, void *output_arg, int option, @@ -718,6 +1014,397 @@ DEFUN(no_evpnrt5_network, argv[idx_ethtag]->arg); } +/* + * Display import RT mapping to VNIs (vty handler) + */ +static void +evpn_show_import_rts (struct vty *vty, struct bgp *bgp) +{ + hash_iterate (bgp->import_rt_hash, + (void (*) (struct hash_backet *, void *)) + show_import_rt_entry, vty); +} + +/* + * Display EVPN routes for all VNIs - vty handler. + */ +static void +evpn_show_routes_vni_all (struct vty *vty, struct bgp *bgp, struct in_addr vtep_ip) +{ + u_int32_t num_vnis; + struct vni_walk_ctx wctx; + + num_vnis = hashcount(bgp->vnihash); + if (!num_vnis) + return; + memset (&wctx, 0, sizeof (struct vni_walk_ctx)); + wctx.bgp = bgp; + wctx.vty = vty; + wctx.vtep_ip = vtep_ip; + hash_iterate (bgp->vnihash, + (void (*) (struct hash_backet *, void *)) + show_vni_routes_hash, &wctx); +} + +/* + * Display EVPN routes for a VNI -- for specific type-3 route (vty handler). + */ +static void +evpn_show_route_vni_multicast (struct vty *vty, struct bgp *bgp, + vni_t vni, struct in_addr orig_ip) +{ + struct bgpevpn *vpn; + struct prefix_evpn p; + struct bgp_node *rn; + struct bgp_info *ri; + u_int32_t path_cnt = 0; + afi_t afi; + safi_t safi; + + afi = AFI_L2VPN; + safi = SAFI_EVPN; + + /* Locate VNI. */ + vpn = bgp_evpn_lookup_vni (bgp, vni); + if (!vpn) + { + vty_out (vty, "VNI not found%s", VTY_NEWLINE); + return; + } + + /* See if route exists. */ + build_evpn_type3_prefix (&p, orig_ip); + rn = bgp_node_lookup (vpn->route_table, (struct prefix *)&p); + if (!rn || !rn->info) + { + vty_out (vty, "%% Network not in table%s", VTY_NEWLINE); + return; + } + + /* Prefix and num paths displayed once per prefix. */ + route_vty_out_detail_header (vty, bgp, rn, NULL, afi, safi, NULL); + + /* Display each path for this prefix. */ + for (ri = rn->info; ri; ri = ri->next) + { + route_vty_out_detail (vty, bgp, &rn->p, ri, afi, safi, NULL); + path_cnt++; + } + + vty_out (vty, "%sDisplayed %u paths for requested prefix%s", + VTY_NEWLINE, path_cnt, VTY_NEWLINE); +} + +/* + * Display EVPN routes for a VNI -- for specific MAC and/or IP (vty handler). + * By definition, only matching type-2 route will be displayed. + */ +static void +evpn_show_route_vni_macip (struct vty *vty, struct bgp *bgp, + vni_t vni, struct ethaddr *mac, + struct ipaddr *ip) +{ + struct bgpevpn *vpn; + struct prefix_evpn p; + struct bgp_node *rn; + struct bgp_info *ri; + u_int32_t path_cnt = 0; + afi_t afi; + safi_t safi; + + afi = AFI_L2VPN; + safi = SAFI_EVPN; + + /* Locate VNI. */ + vpn = bgp_evpn_lookup_vni (bgp, vni); + if (!vpn) + { + vty_out (vty, "VNI not found%s", VTY_NEWLINE); + return; + } + + /* See if route exists. Look for both non-sticky and sticky. */ + build_evpn_type2_prefix (&p, mac, ip); + rn = bgp_node_lookup (vpn->route_table, (struct prefix *)&p); + if (!rn || !rn->info) + { + vty_out (vty, "%% Network not in table%s", VTY_NEWLINE); + return; + } + + /* Prefix and num paths displayed once per prefix. */ + route_vty_out_detail_header (vty, bgp, rn, NULL, afi, safi, NULL); + + /* Display each path for this prefix. */ + for (ri = rn->info; ri; ri = ri->next) + { + route_vty_out_detail (vty, bgp, &rn->p, ri, afi, safi, NULL); + path_cnt++; + } + + vty_out (vty, "%sDisplayed %u paths for requested prefix%s", + VTY_NEWLINE, path_cnt, VTY_NEWLINE); +} + +/* + * Display EVPN routes for a VNI - vty handler. + * If 'type' is non-zero, only routes matching that type are shown. + * If the vtep_ip is non zero, only routes behind that vtep are shown + */ +static void +evpn_show_routes_vni (struct vty *vty, struct bgp *bgp, + vni_t vni, int type, struct in_addr vtep_ip) +{ + struct bgpevpn *vpn; + + /* Locate VNI. */ + vpn = bgp_evpn_lookup_vni (bgp, vni); + if (!vpn) + { + vty_out (vty, "VNI not found%s", VTY_NEWLINE); + return; + } + + /* Walk this VNI's route table and display appropriate routes. */ + show_vni_routes (bgp, vpn, type, vty, vtep_ip); +} + +/* + * Display BGP EVPN routing table -- for specific RD and MAC and/or + * IP (vty handler). By definition, only matching type-2 route will be + * displayed. + */ +static void +evpn_show_route_rd_macip (struct vty *vty, struct bgp *bgp, + struct prefix_rd *prd, struct ethaddr *mac, + struct ipaddr *ip) +{ + struct prefix_evpn p; + struct bgp_node *rn; + struct bgp_info *ri; + afi_t afi; + safi_t safi; + u_int32_t path_cnt = 0; + + afi = AFI_L2VPN; + safi = SAFI_EVPN; + + /* See if route exists. Look for both non-sticky and sticky. */ + build_evpn_type2_prefix (&p, mac, ip); + rn = bgp_afi_node_lookup (bgp->rib[afi][safi], afi, safi, + (struct prefix *)&p, prd); + if (!rn || !rn->info) + { + vty_out (vty, "%% Network not in table%s", VTY_NEWLINE); + return; + } + + /* Prefix and num paths displayed once per prefix. */ + route_vty_out_detail_header (vty, bgp, rn, prd, afi, safi, NULL); + + /* Display each path for this prefix. */ + for (ri = rn->info; ri; ri = ri->next) + { + route_vty_out_detail (vty, bgp, &rn->p, ri, afi, safi, NULL); + path_cnt++; + } + + vty_out (vty, "%sDisplayed %u paths for requested prefix%s", + VTY_NEWLINE, path_cnt, VTY_NEWLINE); +} + +/* + * Display BGP EVPN routing table -- for specific RD (vty handler) + * If 'type' is non-zero, only routes matching that type are shown. + */ +static void +evpn_show_route_rd (struct vty *vty, struct bgp *bgp, + struct prefix_rd *prd, int type) +{ + struct bgp_node *rd_rn; + struct bgp_table *table; + struct bgp_node *rn; + struct bgp_info *ri; + int rd_header = 1; + afi_t afi; + safi_t safi; + u_int32_t prefix_cnt, path_cnt; + + afi = AFI_L2VPN; + safi = SAFI_EVPN; + prefix_cnt = path_cnt = 0; + + rd_rn = bgp_node_lookup (bgp->rib[afi][safi], (struct prefix *) prd); + if (!rd_rn) + return; + table = (struct bgp_table *)rd_rn->info; + if (table == NULL) + return; + + /* Display all prefixes with this RD. */ + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) + { + struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; + + if (type && + evp->prefix.route_type != type) + continue; + + if (rn->info) + { + /* RD header and legend - once overall. */ + if (rd_header) + { + vty_out (vty, "EVPN type-2 prefix: [2]:[ESI]:[EthTag]:[MAClen]:" + "[MAC]%s", VTY_NEWLINE); + vty_out (vty, "EVPN type-3 prefix: [3]:[EthTag]:[IPlen]:" + "[OrigIP]%s%s", VTY_NEWLINE, VTY_NEWLINE); + rd_header = 0; + } + + /* Prefix and num paths displayed once per prefix. */ + route_vty_out_detail_header (vty, bgp, rn, prd, afi, safi, NULL); + + prefix_cnt++; + } + + /* Display each path for this prefix. */ + for (ri = rn->info; ri; ri = ri->next) + { + route_vty_out_detail (vty, bgp, &rn->p, ri, afi, safi, NULL); + path_cnt++; + } + } + + if (prefix_cnt == 0) + vty_out (vty, "No prefixes exist with this RD%s%s", + type ? " (of requested type)" : "", VTY_NEWLINE); + else + vty_out (vty, "%sDisplayed %u prefixes (%u paths) with this RD%s%s", + VTY_NEWLINE, prefix_cnt, path_cnt, + type ? " (of requested type)" : "", VTY_NEWLINE); +} + +/* + * Display BGP EVPN routing table - all routes (vty handler). + * If 'type' is non-zero, only routes matching that type are shown. + */ +static void +evpn_show_all_routes (struct vty *vty, struct bgp *bgp, int type) +{ + struct bgp_node *rd_rn; + struct bgp_table *table; + struct bgp_node *rn; + struct bgp_info *ri; + int header = 1; + int rd_header; + afi_t afi; + safi_t safi; + u_int32_t prefix_cnt, path_cnt; + + afi = AFI_L2VPN; + safi = SAFI_EVPN; + prefix_cnt = path_cnt = 0; + + /* EVPN routing table is a 2-level table with the first level being + * the RD. + */ + for (rd_rn = bgp_table_top (bgp->rib[afi][safi]); rd_rn; + rd_rn = bgp_route_next (rd_rn)) + { + table = (struct bgp_table *)rd_rn->info; + if (table == NULL) + continue; + + rd_header = 1; + + /* Display all prefixes for an RD */ + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) + { + struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; + + if (type && + evp->prefix.route_type != type) + continue; + + if (rn->info) + { + /* Overall header/legend displayed once. */ + if (header) + { + bgp_evpn_show_route_header (vty, bgp); + header = 0; + } + + /* RD header - per RD. */ + if (rd_header) + { + bgp_evpn_show_route_rd_header (vty, rd_rn); + rd_header = 0; + } + + prefix_cnt++; + } + + /* For EVPN, the prefix is displayed for each path (to fit in + * with code that already exists). + */ + for (ri = rn->info; ri; ri = ri->next) + { + path_cnt++; + route_vty_out (vty, &rn->p, ri, 0, SAFI_EVPN, NULL); + } + } + } + + if (prefix_cnt == 0) + vty_out (vty, "No EVPN prefixes %sexist%s", + type ? "(of requested type) " : "", VTY_NEWLINE); + else + vty_out (vty, "%sDisplayed %u prefixes (%u paths)%s%s", + VTY_NEWLINE, prefix_cnt, path_cnt, + type ? " (of requested type)" : "", VTY_NEWLINE); +} + +/* + * Display specified VNI (vty handler) + */ +static void +evpn_show_vni (struct vty *vty, struct bgp *bgp, vni_t vni) +{ + struct bgpevpn *vpn; + + vpn = bgp_evpn_lookup_vni (bgp, vni); + if (!vpn) + { + vty_out (vty, "VNI not found%s", VTY_NEWLINE); + return; + } + + display_vni (vty, vpn); +} + +/* + * Display a VNI (upon user query). + */ +static void +evpn_show_all_vnis (struct vty *vty, struct bgp *bgp) +{ + u_int32_t num_vnis; + + num_vnis = hashcount(bgp->vnihash); + if (!num_vnis) + return; + vty_out(vty, "Number of VNIs: %u%s", + num_vnis, VTY_NEWLINE); + vty_out(vty, "Flags: * - Kernel %s", VTY_NEWLINE); + vty_out(vty, " %-10s %-15s %-21s %-25s %-25s%s", + "VNI", "Orig IP", "RD", "Import RT", "Export RT", VTY_NEWLINE); + hash_iterate (bgp->vnihash, + (void (*) (struct hash_backet *, void *)) + show_vni_entry, vty); +} + /* * EVPN (VNI advertisement) enabled. Register with zebra. */ @@ -767,6 +1454,370 @@ DEFUN (no_bgp_evpn_advertise_all_vni, return CMD_SUCCESS; } +DEFUN (show_bgp_evpn_vni, + show_bgp_evpn_vni_cmd, + "show bgp evpn vni", + SHOW_STR + BGP_STR + EVPN_HELP_STR + "Show VNI\n") +{ + struct bgp *bgp; + + bgp = bgp_get_default(); + if (!bgp) + return CMD_WARNING; + + vty_out (vty, "Advertise All VNI flag: %s%s", + bgp->advertise_all_vni? "Enabled" : "Disabled", VTY_NEWLINE); + + evpn_show_all_vnis (vty, bgp); + return CMD_SUCCESS; +} + +DEFUN (show_bgp_evpn_vni_num, + show_bgp_evpn_vni_num_cmd, + "show bgp evpn vni (1-16777215)", + SHOW_STR + BGP_STR + "Address family modifier\n" + "Show VNI\n" + "VNI number\n") +{ + vni_t vni; + struct bgp *bgp; + + bgp = bgp_get_default(); + if (!bgp) + return CMD_WARNING; + + VTY_GET_INTEGER_RANGE ("VNI", vni, argv[4]->arg, 1, VNI_MAX); + + evpn_show_vni (vty, bgp, vni); + return CMD_SUCCESS; +} + +/* `show bgp evpn summary' commands. */ +DEFUN (show_bgp_evpn_summary, + show_bgp_evpn_summary_cmd, + "show bgp evpn summary [json]", + SHOW_STR + BGP_STR + "EVPN\n" + "Summary of BGP neighbor status\n" + "JavaScript Object Notation\n") +{ + u_char uj = use_json(argc, argv); + return bgp_show_summary_vty (vty, NULL, AFI_L2VPN, SAFI_EVPN, uj); +} + +/* Show bgp evpn route */ +DEFUN (show_bgp_evpn_route, + show_bgp_evpn_route_cmd, + "show bgp evpn route [type ]", + SHOW_STR + BGP_STR + "Address Family Modifier\n" + "Display EVPN route information\n" + "Specify Route type\n" + "MAC-IP (Type-2) route\n" + "Multicast (Type-3) route\n") +{ + struct bgp *bgp; + int type = 0; + + bgp = bgp_get_default(); + if (!bgp) + return CMD_WARNING; + + if (argc == 6) + { + if (strncmp (argv[5]->arg, "ma", 2) == 0) + type = BGP_EVPN_MAC_IP_ROUTE; + else if (strncmp (argv[5]->arg, "mu", 2) == 0) + type = BGP_EVPN_IMET_ROUTE; + else + return CMD_WARNING; + } + + evpn_show_all_routes (vty, bgp, type); + return CMD_SUCCESS; +} + +DEFUN (show_bgp_evpn_route_rd, + show_bgp_evpn_route_rd_cmd, + "show bgp evpn route rd ASN:nn_or_IP-address:nn [type ]", + SHOW_STR + BGP_STR + "Address Family Modifier\n" + "Display EVPN route information\n" + "Route Distinguisher\n" + "ASN:XX or A.B.C.D:XX\n" + "Specify Route type\n" + "MAC-IP (Type-2) route\n" + "Multicast (Type-3) route\n") +{ + struct bgp *bgp; + int ret; + struct prefix_rd prd; + int type = 0; + + bgp = bgp_get_default(); + if (!bgp) + return CMD_WARNING; + + ret = str2prefix_rd (argv[5]->arg, &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (argc == 8) + { + if (strncmp (argv[7]->arg, "ma", 2) == 0) + type = BGP_EVPN_MAC_IP_ROUTE; + else if (strncmp (argv[7]->arg, "mu", 2) == 0) + type = BGP_EVPN_IMET_ROUTE; + else + return CMD_WARNING; + } + + evpn_show_route_rd (vty, bgp, &prd, type); + return CMD_SUCCESS; +} + +DEFUN (show_bgp_evpn_route_rd_macip, + show_bgp_evpn_route_rd_macip_cmd, + "show bgp evpn route rd ASN:nn_or_IP-address:nn mac WORD [ip WORD]", + SHOW_STR + BGP_STR + "Address Family Modifier\n" + "Display EVPN route information\n" + "Route Distinguisher\n" + "ASN:XX or A.B.C.D:XX\n" + "MAC\n" + "MAC address (e.g., 00:e0:ec:20:12:62)\n" + "IP\n" + "IP address (IPv4 or IPv6)\n") +{ + struct bgp *bgp; + int ret; + struct prefix_rd prd; + struct ethaddr mac; + struct ipaddr ip; + + bgp = bgp_get_default(); + if (!bgp) + return CMD_WARNING; + + ret = str2prefix_rd (argv[5]->arg, &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + if (!prefix_str2mac (argv[7]->arg, &mac)) + { + vty_out (vty, "%% Malformed MAC address%s", VTY_NEWLINE); + return CMD_WARNING; + } + memset (&ip, 0, sizeof (ip)); + if (argc == 10 && argv[9]->arg != NULL) + { + if (str2ipaddr (argv[9]->arg, &ip) != 0) + { + vty_out (vty, "%% Malformed IP address%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + evpn_show_route_rd_macip (vty, bgp, &prd, &mac, &ip); + return CMD_SUCCESS; +} + +DEFUN (show_bgp_evpn_route_vni, + show_bgp_evpn_route_vni_cmd, + "show bgp evpn route vni (1-16777215) [ | vtep A.B.C.D>]", + SHOW_STR + BGP_STR + "Address Family Modifier\n" + "Display EVPN route information\n" + "VXLAN Network Identifier\n" + "VNI number\n" + "Specify Route type\n" + "MAC-IP (Type-2) route\n" + "Multicast (Type-3) route\n" + "Remote VTEP\n" + "Remote VTEP IP address\n") +{ + vni_t vni; + struct bgp *bgp; + struct in_addr vtep_ip; + int type = 0; + + bgp = bgp_get_default(); + if (!bgp) + return CMD_WARNING; + + vtep_ip.s_addr = 0; + + VTY_GET_INTEGER_RANGE ("VNI", vni, argv[5]->arg, 1, VNI_MAX); + + if (argc == 8 && argv[6]->arg) + { + if (strncmp (argv[6]->arg, "type", 4) == 0) + { + if (strncmp (argv[7]->arg, "ma", 2) == 0) + type = BGP_EVPN_MAC_IP_ROUTE; + else if (strncmp (argv[7]->arg, "mu", 2) == 0) + type = BGP_EVPN_IMET_ROUTE; + else + return CMD_WARNING; + } + else if (strncmp (argv[6]->arg, "vtep", 4) == 0) + { + if (!inet_aton (argv[7]->arg, &vtep_ip)) + { + vty_out (vty, "%% Malformed VTEP IP address%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + else + return CMD_WARNING; + } + + evpn_show_routes_vni (vty, bgp, vni, type, vtep_ip); + return CMD_SUCCESS; +} + +DEFUN (show_bgp_evpn_route_vni_macip, + show_bgp_evpn_route_vni_macip_cmd, + "show bgp evpn route vni (1-16777215) mac WORD [ip WORD]", + SHOW_STR + BGP_STR + "Address Family Modifier\n" + "Display EVPN route information\n" + "VXLAN Network Identifier\n" + "VNI number\n" + "MAC\n" + "MAC address (e.g., 00:e0:ec:20:12:62)\n" + "IP\n" + "IP address (IPv4 or IPv6)\n") +{ + vni_t vni; + struct bgp *bgp; + struct ethaddr mac; + struct ipaddr ip; + + bgp = bgp_get_default(); + if (!bgp) + return CMD_WARNING; + + VTY_GET_INTEGER_RANGE ("VNI", vni, argv[5]->arg, 1, VNI_MAX); + if (!prefix_str2mac (argv[7]->arg, &mac)) + { + vty_out (vty, "%% Malformed MAC address%s", VTY_NEWLINE); + return CMD_WARNING; + } + memset (&ip, 0, sizeof (ip)); + if (argc == 10 && argv[9]->arg != NULL) + { + if (str2ipaddr (argv[9]->arg, &ip) != 0) + { + vty_out (vty, "%% Malformed IP address%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + evpn_show_route_vni_macip (vty, bgp, vni, &mac, &ip); + return CMD_SUCCESS; +} + +DEFUN (show_bgp_evpn_route_vni_multicast, + show_bgp_evpn_route_vni_multicast_cmd, + "show bgp evpn route vni (1-16777215) multicast A.B.C.D", + SHOW_STR + BGP_STR + "Address Family Modifier\n" + "Display EVPN route information\n" + "VXLAN Network Identifier\n" + "VNI number\n" + "Multicast (Type-3) route\n" + "Originating Router IP address\n") +{ + vni_t vni; + struct bgp *bgp; + int ret; + struct in_addr orig_ip; + + bgp = bgp_get_default(); + if (!bgp) + return CMD_WARNING; + + VTY_GET_INTEGER_RANGE ("VNI", vni, argv[5]->arg, 1, VNI_MAX); + ret = inet_aton (argv[7]->arg, &orig_ip); + if (!ret) + { + vty_out (vty, "%% Malformed Originating Router IP address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + evpn_show_route_vni_multicast (vty, bgp, vni, orig_ip); + return CMD_SUCCESS; +} + +DEFUN (show_bgp_evpn_route_vni_all, + show_bgp_evpn_route_vni_all_cmd, + "show bgp evpn route vni all [vtep A.B.C.D]", + SHOW_STR + BGP_STR + "Address Family Modifier\n" + "Display EVPN route information\n" + "VXLAN Network Identifier\n" + "All VNIs\n" + "Remote VTEP\n" + "Remote VTEP IP address\n") +{ + struct bgp *bgp; + struct in_addr vtep_ip; + + bgp = bgp_get_default(); + if (!bgp) + return CMD_WARNING; + + vtep_ip.s_addr = 0; + if (argc == 8 && argv[7]->arg) + { + if (!inet_aton (argv[7]->arg, &vtep_ip)) + { + vty_out (vty, "%% Malformed VTEP IP address%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + evpn_show_routes_vni_all (vty, bgp, vtep_ip); + return CMD_SUCCESS; +} + +DEFUN (show_bgp_evpn_import_rt, + show_bgp_evpn_import_rt_cmd, + "show bgp evpn import-rt", + SHOW_STR + BGP_STR + "Address family modifier\n" + "Show import route target\n") +{ + struct bgp *bgp; + + bgp = bgp_get_default(); + if (!bgp) + return CMD_WARNING; + + evpn_show_import_rts (vty, bgp); + return CMD_SUCCESS; +} + void bgp_ethernetvpn_init(void) { install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_cmd); @@ -785,4 +1836,17 @@ void bgp_ethernetvpn_init(void) install_element(BGP_EVPN_NODE, &evpnrt5_network_cmd); install_element (BGP_EVPN_NODE, &bgp_evpn_advertise_all_vni_cmd); install_element (BGP_EVPN_NODE, &no_bgp_evpn_advertise_all_vni_cmd); + + /* "show bgp evpn" commands. */ + install_element (VIEW_NODE, &show_bgp_evpn_vni_cmd); + install_element (VIEW_NODE, &show_bgp_evpn_vni_num_cmd); + install_element (VIEW_NODE, &show_bgp_evpn_summary_cmd); + install_element (VIEW_NODE, &show_bgp_evpn_route_cmd); + install_element (VIEW_NODE, &show_bgp_evpn_route_rd_cmd); + install_element (VIEW_NODE, &show_bgp_evpn_route_rd_macip_cmd); + install_element (VIEW_NODE, &show_bgp_evpn_route_vni_cmd); + install_element (VIEW_NODE, &show_bgp_evpn_route_vni_multicast_cmd); + install_element (VIEW_NODE, &show_bgp_evpn_route_vni_macip_cmd); + install_element (VIEW_NODE, &show_bgp_evpn_route_vni_all_cmd); + install_element (VIEW_NODE, &show_bgp_evpn_import_rt_cmd); } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 6a2cc8d4d3..cd21c25c77 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -6349,8 +6349,13 @@ route_vty_out_route (struct prefix *p, struct vty *vty) } else if (p->family == AF_ETHERNET) { +#if defined (HAVE_CUMULUS) + len = vty_out (vty, "%s", + bgp_evpn_route2str((struct prefix_evpn *)p, buf, BUFSIZ)); +#else prefix2str(p, buf, PREFIX_STRLEN); len = vty_out (vty, "%s", buf); +#endif } else len = vty_out (vty, "%s/%d", inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), @@ -6477,11 +6482,14 @@ route_vty_out (struct vty *vty, struct prefix *p, if (attr) { /* - * For ENCAP routes, nexthop address family is not + * For ENCAP and EVPN routes, nexthop address family is not * neccessarily the same as the prefix address family. * Both SAFI_MPLS_VPN and SAFI_ENCAP use the MP nexthop field + * EVPN routes are also exchanged with a MP nexthop. Currently, this + * is only IPv4, the value will be present in either attr->nexthop or + * attr->extra->mp_nexthop_global_in */ - if ((safi == SAFI_ENCAP) || (safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN)) + if ((safi == SAFI_ENCAP) || (safi == SAFI_MPLS_VPN)) { if (attr->extra) { @@ -6506,6 +6514,19 @@ route_vty_out (struct vty *vty, struct prefix *p, else vty_out(vty, "?"); } + else if (safi == SAFI_EVPN) + { + if (json_paths) + { + json_nexthop_global = json_object_new_object(); + + json_object_string_add(json_nexthop_global, "ip", inet_ntoa (attr->nexthop)); + json_object_string_add(json_nexthop_global, "afi", "ipv4"); + json_object_boolean_true_add(json_nexthop_global, "used"); + } + else + vty_out (vty, "%-16s", inet_ntoa (attr->nexthop)); + } /* IPv4 Next Hop */ else if (p->family == AF_INET && !BGP_ATTR_NEXTHOP_AFI_IP6(attr)) { @@ -7240,13 +7261,14 @@ route_vty_out_advertised_to (struct vty *vty, struct peer *peer, int *first, } } -static void +void route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, struct bgp_info *binfo, afi_t afi, safi_t safi, json_object *json_paths) { char buf[INET6_ADDRSTRLEN]; char buf1[BUFSIZ]; + char buf2[EVPN_ROUTE_STRLEN]; struct attr *attr; int sockunion_vty_out (struct vty *, union sockunion *); time_t tbuf; @@ -7276,6 +7298,39 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, json_nexthop_global = json_object_new_object(); } +#if defined (HAVE_CUMULUS) + if (!json_paths && safi == SAFI_EVPN) + { + char tag_buf[20]; + + bgp_evpn_route2str ((struct prefix_evpn *)p, buf2, sizeof (buf2)); + vty_out (vty, " Route %s", buf2); + tag_buf[0] = '\0'; + if (binfo->extra) + { + bgp_evpn_label2str (&binfo->extra->label, tag_buf, sizeof (tag_buf)); + vty_out (vty, " VNI %s", tag_buf); + } + vty_out (vty, "%s", VTY_NEWLINE); + if (binfo->extra && binfo->extra->parent) + { + struct bgp_info *parent_ri; + struct bgp_node *rn, *prn; + + parent_ri = (struct bgp_info *)binfo->extra->parent; + rn = parent_ri->net; + if (rn && rn->prn) + { + prn = rn->prn; + vty_out (vty, " Imported from %s:%s%s", + prefix_rd2str ((struct prefix_rd *)&prn->p, + buf1, RD_ADDRSTRLEN), + buf2, VTY_NEWLINE); + } + } + } +#endif + attr = binfo->attr; if (attr) @@ -7442,7 +7497,8 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, if (binfo->peer == bgp->peer_self) { - if (p->family == AF_INET && !BGP_ATTR_NEXTHOP_AFI_IP6(attr)) + if (safi == SAFI_EVPN || + (p->family == AF_INET && !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) { if (json_paths) json_object_string_add(json_peer, "peerId", "0.0.0.0"); @@ -7823,7 +7879,11 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, bgp_damp_info_vty (vty, binfo, json_path); /* Remote Label */ +#if defined (HAVE_CUMULUS) + if (binfo->extra && bgp_is_valid_label(&binfo->extra->label) && safi != SAFI_EVPN) +#else if (binfo->extra && bgp_is_valid_label(&binfo->extra->label)) +#endif { mpls_label_t label = label_pton(&binfo->extra->label); if (json_paths) @@ -8285,7 +8345,7 @@ bgp_show_all_instances_routes_vty (struct vty *vty, afi_t afi, safi_t safi, } /* Header of detailed BGP route information */ -static void +void route_vty_out_detail_header (struct vty *vty, struct bgp *bgp, struct bgp_node *rn, struct prefix_rd *prd, afi_t afi, safi_t safi, @@ -8297,6 +8357,7 @@ route_vty_out_detail_header (struct vty *vty, struct bgp *bgp, struct listnode *node, *nnode; char buf1[INET6_ADDRSTRLEN]; char buf2[INET6_ADDRSTRLEN]; + char buf3[EVPN_ROUTE_STRLEN]; int count = 0; int best = 0; int suppress = 0; @@ -8324,6 +8385,22 @@ route_vty_out_detail_header (struct vty *vty, struct bgp *bgp, } else { +#if defined (HAVE_CUMULUS) + if (safi == SAFI_EVPN) + vty_out (vty, "BGP routing table entry for %s%s%s%s", + prd ? prefix_rd2str (prd, buf1, RD_ADDRSTRLEN) : "", + prd ? ":" : "", + bgp_evpn_route2str ((struct prefix_evpn *)p, + buf3, sizeof (buf3)), + VTY_NEWLINE); + else + vty_out (vty, "BGP routing table entry for %s%s%s/%d%s", + ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP) ? + prefix_rd2str (prd, buf1, RD_ADDRSTRLEN) : ""), + safi == SAFI_MPLS_VPN ? ":" : "", + inet_ntop (p->family, &p->u.prefix, buf2, INET6_ADDRSTRLEN), + p->prefixlen, VTY_NEWLINE); +#else if (p->family == AF_ETHERNET) prefix2str (p, buf2, INET6_ADDRSTRLEN); else @@ -8334,11 +8411,16 @@ route_vty_out_detail_header (struct vty *vty, struct bgp *bgp, ((safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN)) ? ":" : "", buf2, p->prefixlen); +#endif if (has_valid_label) vty_outln (vty, "Local label: %d", label); - else if (bgp_labeled_safi(safi)) - vty_outln (vty, "Local label: not allocated"); +#if defined (HAVE_CUMULUS) + if (bgp_labeled_safi(safi) && safi != SAFI_EVPN) +#else + if (bgp_labeled_safi(safi)) +#endif + vty_out(vty, "not allocated%s", VTY_NEWLINE); } for (ri = rn->info; ri; ri = ri->next) diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 01d8e62d43..cb918718fe 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -430,4 +430,13 @@ extern void bgp_zebra_clear_route_change_flags (struct bgp_node *rn); extern int bgp_zebra_has_route_changed (struct bgp_node *rn, struct bgp_info *selected); +extern void +route_vty_out_detail_header (struct vty *vty, struct bgp *bgp, + struct bgp_node *rn, + struct prefix_rd *prd, afi_t afi, safi_t safi, + json_object *json); +extern void +route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, + struct bgp_info *binfo, afi_t afi, safi_t safi, + json_object *json_paths); #endif /* _QUAGGA_BGP_ROUTE_H */ diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 75b4739956..183a5832dc 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -7282,7 +7282,7 @@ bgp_show_all_instances_summary_vty (struct vty *vty, afi_t afi, safi_t safi, } -static int +int bgp_show_summary_vty (struct vty *vty, const char *name, afi_t afi, safi_t safi, u_char use_json) { diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h index edc994a57c..62228c64ed 100644 --- a/bgpd/bgp_vty.h +++ b/bgpd/bgp_vty.h @@ -69,4 +69,7 @@ argv_find_and_parse_safi(struct cmd_token **argv, int argc, int *index, safi_t * extern int bgp_vty_find_and_parse_afi_safi_bgp (struct vty *vty, struct cmd_token **argv, int argc, int *idx, afi_t *afi, safi_t *safi, struct bgp **bgp); +extern int +bgp_show_summary_vty (struct vty *vty, const char *name, + afi_t afi, safi_t safi, u_char use_json); #endif /* _QUAGGA_BGP_VTY_H */ From 90e60aa7c9e2bf346c83b6c1757c060ab4859ad3 Mon Sep 17 00:00:00 2001 From: vivek Date: Mon, 15 May 2017 15:01:57 -0700 Subject: [PATCH 24/31] bgpd: Additional configuration for EVPN Implement configuration options for EVPN. The configuration options include VNI configuration with RD and Import and Export Route Targets. Also, display the EVPN configuration. Signed-off-by: Vivek Venkatraman Signed-off-by: Daniel Walton --- bgpd/bgp_evpn.c | 183 +++++++++ bgpd/bgp_evpn_private.h | 8 + bgpd/bgp_evpn_vty.c | 816 ++++++++++++++++++++++++++++++++++++++++ bgpd/bgp_evpn_vty.h | 3 + bgpd/bgp_vty.c | 9 + bgpd/bgpd.c | 3 + lib/command.c | 7 + lib/command.h | 1 + lib/vty.c | 1 + vtysh/vtysh.c | 74 +++- 10 files changed, 1101 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index f17bcfab1e..c787e21e83 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1513,6 +1513,25 @@ install_routes_for_vni (struct bgp *bgp, struct bgpevpn *vpn) return install_uninstall_routes_for_vni (bgp, vpn, BGP_EVPN_MAC_IP_ROUTE, 1); } +/* + * Uninstall any existing remote routes for this VNI. One scenario in which + * this is invoked is upon an import RT change. + */ +static int +uninstall_routes_for_vni (struct bgp *bgp, struct bgpevpn *vpn) +{ + int ret; + + /* Uninstall type-2 routes followed by type-3 routes - the ones applicable + * for this VNI. + */ + ret = install_uninstall_routes_for_vni (bgp, vpn, BGP_EVPN_MAC_IP_ROUTE, 0); + if (ret) + return ret; + + return install_uninstall_routes_for_vni (bgp, vpn, BGP_EVPN_IMET_ROUTE, 0); +} + /* * Install or uninstall route in matching VNIs (list). */ @@ -1623,6 +1642,125 @@ install_uninstall_evpn_route (struct bgp *bgp, afi_t afi, safi_t safi, return 0; } +/* + * Update and advertise local routes for a VNI. Invoked upon router-id + * change. Note that the processing is done only on the global route table + * using routes that already exist in the per-VNI table. + */ +static int +update_advertise_vni_routes (struct bgp *bgp, struct bgpevpn *vpn) +{ + struct prefix_evpn p; + struct bgp_node *rn, *global_rn; + struct bgp_info *ri, *global_ri; + struct attr *attr; + afi_t afi = AFI_L2VPN; + safi_t safi = SAFI_EVPN; + + /* Locate type-3 route for VNI in the per-VNI table and use its + * attributes to create and advertise the type-3 route for this VNI + * in the global table. + */ + build_evpn_type3_prefix (&p, vpn->originator_ip); + rn = bgp_node_lookup (vpn->route_table, (struct prefix *)&p); + if (!rn) /* unexpected */ + return 0; + for (ri = rn->info; ri; ri = ri->next) + if (ri->peer == bgp->peer_self + && ri->type == ZEBRA_ROUTE_BGP + && ri->sub_type == BGP_ROUTE_STATIC) + break; + if (!ri) /* unexpected */ + return 0; + attr = ri->attr; + + global_rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, + (struct prefix *)&p, &vpn->prd); + update_evpn_route_entry (bgp, vpn, afi, safi, global_rn, + attr, 1, 0, &ri); + + /* Schedule for processing and unlock node. */ + bgp_process (bgp, global_rn, afi, safi); + bgp_unlock_node (global_rn); + + /* Now, walk this VNI's route table and use the route and its attribute + * to create and schedule route in global table. + */ + for (rn = bgp_table_top (vpn->route_table); rn; rn = bgp_route_next (rn)) + { + struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; + + /* Identify MAC-IP local routes. */ + if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) + continue; + + for (ri = rn->info; ri; ri = ri->next) + if (ri->peer == bgp->peer_self + && ri->type == ZEBRA_ROUTE_BGP + && ri->sub_type == BGP_ROUTE_STATIC) + break; + if (!ri) + continue; + + /* Create route in global routing table using this route entry's + * attribute. + */ + attr = ri->attr; + global_rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, + (struct prefix *)evp, &vpn->prd); + assert (global_rn); + update_evpn_route_entry (bgp, vpn, afi, safi, global_rn, + attr, 1, 0, &global_ri); + + /* Schedule for processing and unlock node. */ + bgp_process (bgp, global_rn, afi, safi); + bgp_unlock_node (global_rn); + } + + return 0; +} + +/* + * Delete (and withdraw) local routes for a VNI - only from the global + * table. Invoked upon router-id change. + */ +static int +delete_withdraw_vni_routes (struct bgp *bgp, struct bgpevpn *vpn) +{ + int ret; + struct prefix_evpn p; + struct bgp_node *global_rn; + struct bgp_info *ri; + afi_t afi = AFI_L2VPN; + safi_t safi = SAFI_EVPN; + + /* Delete and withdraw locally learnt type-2 routes (MACIP) + * for this VNI - from the global table. + */ + ret = delete_global_type2_routes (bgp, vpn); + if (ret) + return ret; + + /* Remove type-3 route for this VNI from global table. */ + build_evpn_type3_prefix (&p, vpn->originator_ip); + global_rn = bgp_afi_node_lookup (bgp->rib[afi][safi], afi, safi, + (struct prefix *)&p, &vpn->prd); + if (global_rn) + { + /* Delete route entry in the global EVPN table. */ + delete_evpn_route_entry (bgp, vpn, afi, safi, global_rn, &ri); + + /* Schedule for processing - withdraws to peers happen from + * this table. + */ + if (ri) + bgp_process (bgp, global_rn, afi, safi); + bgp_unlock_node (global_rn); + } + + return 0; +} + /* * Process received EVPN type-2 route (advertise or withdraw). */ @@ -1968,6 +2106,51 @@ free_vni_entry (struct hash_backet *backet, struct bgp *bgp) * Public functions. */ +/* + * Handle change to export RT - update and advertise local routes. + */ +int +bgp_evpn_handle_export_rt_change (struct bgp *bgp, struct bgpevpn *vpn) +{ + return update_routes_for_vni (bgp, vpn); +} + +/* + * Handle change to RD. This is invoked twice by the change handler, + * first before the RD has been changed and then after the RD has + * been changed. The first invocation will result in local routes + * of this VNI being deleted and withdrawn and the next will result + * in the routes being re-advertised. + */ +void +bgp_evpn_handle_rd_change (struct bgp *bgp, struct bgpevpn *vpn, + int withdraw) +{ + if (withdraw) + delete_withdraw_vni_routes (bgp, vpn); + else + update_advertise_vni_routes (bgp, vpn); +} + +/* + * Install routes for this VNI. Invoked upon change to Import RT. + */ +int +bgp_evpn_install_routes (struct bgp *bgp, struct bgpevpn *vpn) +{ + return install_routes_for_vni (bgp, vpn); +} + +/* + * Uninstall all routes installed for this VNI. Invoked upon change + * to Import RT. + */ +int +bgp_evpn_uninstall_routes (struct bgp *bgp, struct bgpevpn *vpn) +{ + return uninstall_routes_for_vni (bgp, vpn); +} + /* * Function to display "tag" in route as a VNI. */ diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index f37e0ef2e3..cd40fa9f0e 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -205,6 +205,14 @@ build_evpn_type3_prefix (struct prefix_evpn *p, struct in_addr originator_ip) } +extern int +bgp_evpn_handle_export_rt_change (struct bgp *bgp, struct bgpevpn *vpn); +extern void +bgp_evpn_handle_rd_change (struct bgp *bgp, struct bgpevpn *vpn, int withdraw); +extern int +bgp_evpn_install_routes (struct bgp *bgp, struct bgpevpn *vpn); +extern int +bgp_evpn_uninstall_routes (struct bgp *bgp, struct bgpevpn *vpn); extern void bgp_evpn_map_vni_to_its_rts (struct bgp *bgp, struct bgpevpn *vpn); extern void diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 9a8078ca99..c533151ba7 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -49,6 +49,12 @@ struct vni_walk_ctx struct in_addr vtep_ip; }; +struct evpn_config_write +{ + int write; + struct vty *vty; +}; + static void display_import_rt (struct vty *vty, struct irt_node *irt) { @@ -1014,6 +1020,316 @@ DEFUN(no_evpnrt5_network, argv[idx_ethtag]->arg); } +static void +evpn_rt_delete_auto (struct bgp *bgp, struct bgpevpn *vpn, struct list *rtl) +{ + struct listnode *node, *nnode, *node_to_del; + struct ecommunity *ecom, *ecom_auto; + struct ecommunity_val eval; + + encode_route_target_as ((bgp->as & 0xFFFF), vpn->vni, &eval); + + ecom_auto = ecommunity_new (); + ecommunity_add_val (ecom_auto, &eval); + node_to_del = NULL; + + for (ALL_LIST_ELEMENTS (rtl, node, nnode, ecom)) + { + if (ecommunity_match (ecom, ecom_auto)) + { + ecommunity_free (&ecom); + node_to_del = node; + } + } + + if (node_to_del) + list_delete_node(rtl, node_to_del); + + ecommunity_free(&ecom_auto); +} + +static void +evpn_import_rt_delete_auto (struct bgp *bgp, struct bgpevpn *vpn) +{ + evpn_rt_delete_auto (bgp, vpn, vpn->import_rtl); +} + +static void +evpn_export_rt_delete_auto (struct bgp *bgp, struct bgpevpn *vpn) +{ + evpn_rt_delete_auto (bgp, vpn, vpn->export_rtl); +} + +/* + * Configure the Import RTs for a VNI (vty handler). Caller expected to + * check that this is a change. + */ +static void +evpn_configure_import_rt (struct bgp *bgp, struct bgpevpn *vpn, + struct ecommunity *ecomadd) +{ + /* If the VNI is "live", we need to uninstall routes using the current + * import RT(s) first before we update the import RT, and subsequently + * install routes. + */ + if (is_vni_live (vpn)) + bgp_evpn_uninstall_routes (bgp, vpn); + + /* Cleanup the RT to VNI mapping and get rid of existing import RT. */ + bgp_evpn_unmap_vni_from_its_rts (bgp, vpn); + + /* If the auto route-target is in use we must remove it */ + evpn_import_rt_delete_auto(bgp, vpn); + + /* Add new RT and rebuild the RT to VNI mapping */ + listnode_add_sort (vpn->import_rtl, ecomadd); + + SET_FLAG (vpn->flags, VNI_FLAG_IMPRT_CFGD); + bgp_evpn_map_vni_to_its_rts (bgp, vpn); + + /* Install routes that match new import RT */ + if (is_vni_live (vpn)) + bgp_evpn_install_routes (bgp, vpn); +} + +/* + * Unconfigure Import RT(s) for a VNI (vty handler). + */ +static void +evpn_unconfigure_import_rt (struct bgp *bgp, struct bgpevpn *vpn, + struct ecommunity *ecomdel) +{ + struct listnode *node, *nnode, *node_to_del; + struct ecommunity *ecom; + + /* Along the lines of "configure" except we have to reset to the + * automatic value. + */ + if (is_vni_live (vpn)) + bgp_evpn_uninstall_routes (bgp, vpn); + + /* Cleanup the RT to VNI mapping and get rid of existing import RT. */ + bgp_evpn_unmap_vni_from_its_rts (bgp, vpn); + + /* Delete all import RTs */ + if (ecomdel == NULL) + { + for (ALL_LIST_ELEMENTS (vpn->import_rtl, node, nnode, ecom)) + ecommunity_free (&ecom); + + list_delete_all_node(vpn->import_rtl); + } + + /* Delete a specific import RT */ + else + { + node_to_del = NULL; + + for (ALL_LIST_ELEMENTS (vpn->import_rtl, node, nnode, ecom)) + { + if (ecommunity_match (ecom, ecomdel)) + { + ecommunity_free (&ecom); + node_to_del = node; + break; + } + } + + if (node_to_del) + list_delete_node(vpn->import_rtl, node_to_del); + } + + /* Reset to auto RT - this also rebuilds the RT to VNI mapping */ + if (list_isempty(vpn->import_rtl)) + { + UNSET_FLAG (vpn->flags, VNI_FLAG_IMPRT_CFGD); + bgp_evpn_derive_auto_rt_import (bgp, vpn); + } + /* Rebuild the RT to VNI mapping */ + else + bgp_evpn_map_vni_to_its_rts (bgp, vpn); + + /* Install routes that match new import RT */ + if (is_vni_live (vpn)) + bgp_evpn_install_routes (bgp, vpn); +} + +/* + * Configure the Export RT for a VNI (vty handler). Caller expected to + * check that this is a change. Note that only a single export RT is + * allowed for a VNI and any change to configuration is implemented as + * a "replace" (similar to other configuration). + */ +static void +evpn_configure_export_rt (struct bgp *bgp, struct bgpevpn *vpn, + struct ecommunity *ecomadd) +{ + /* If the auto route-target is in use we must remove it */ + evpn_export_rt_delete_auto (bgp, vpn); + + listnode_add_sort (vpn->export_rtl, ecomadd); + SET_FLAG (vpn->flags, VNI_FLAG_EXPRT_CFGD); + + if (is_vni_live (vpn)) + bgp_evpn_handle_export_rt_change (bgp, vpn); +} + +/* + * Unconfigure the Export RT for a VNI (vty handler) + */ +static void +evpn_unconfigure_export_rt (struct bgp *bgp, struct bgpevpn *vpn, + struct ecommunity *ecomdel) +{ + struct listnode *node, *nnode, *node_to_del; + struct ecommunity *ecom; + + /* Delete all export RTs */ + if (ecomdel == NULL) + { + /* Reset to default and process all routes. */ + for (ALL_LIST_ELEMENTS (vpn->export_rtl, node, nnode, ecom)) + ecommunity_free (&ecom); + + list_delete_all_node(vpn->export_rtl); + } + + /* Delete a specific export RT */ + else + { + node_to_del = NULL; + + for (ALL_LIST_ELEMENTS (vpn->export_rtl, node, nnode, ecom)) + { + if (ecommunity_match (ecom, ecomdel)) + { + ecommunity_free (&ecom); + node_to_del = node; + break; + } + } + + if (node_to_del) + list_delete_node(vpn->export_rtl, node_to_del); + } + + if (list_isempty(vpn->export_rtl)) + { + UNSET_FLAG (vpn->flags, VNI_FLAG_EXPRT_CFGD); + bgp_evpn_derive_auto_rt_export (bgp, vpn); + } + + if (is_vni_live (vpn)) + bgp_evpn_handle_export_rt_change (bgp, vpn); +} + +/* + * Configure RD for a VNI (vty handler) + */ +static void +evpn_configure_rd (struct bgp *bgp, struct bgpevpn *vpn, + struct prefix_rd *rd) +{ + /* If the VNI is "live", we need to delete and withdraw this VNI's + * local routes with the prior RD first. Then, after updating RD, + * need to re-advertise. + */ + if (is_vni_live (vpn)) + bgp_evpn_handle_rd_change (bgp, vpn, 1); + + /* update RD */ + memcpy(&vpn->prd, rd, sizeof (struct prefix_rd)); + SET_FLAG (vpn->flags, VNI_FLAG_RD_CFGD); + + if (is_vni_live (vpn)) + bgp_evpn_handle_rd_change (bgp, vpn, 0); +} + +/* + * Unconfigure RD for a VNI (vty handler) + */ +static void +evpn_unconfigure_rd (struct bgp *bgp, struct bgpevpn *vpn) +{ + /* If the VNI is "live", we need to delete and withdraw this VNI's + * local routes with the prior RD first. Then, after resetting RD + * to automatic value, need to re-advertise. + */ + if (is_vni_live (vpn)) + bgp_evpn_handle_rd_change (bgp, vpn, 1); + + /* reset RD to default */ + bgp_evpn_derive_auto_rd (bgp, vpn); + + if (is_vni_live (vpn)) + bgp_evpn_handle_rd_change (bgp, vpn, 0); +} + +/* + * Create VNI, if not already present (VTY handler). Mark as configured. + */ +static struct bgpevpn * +evpn_create_update_vni (struct bgp *bgp, vni_t vni) +{ + struct bgpevpn *vpn; + + if (!bgp->vnihash) + return NULL; + + vpn = bgp_evpn_lookup_vni (bgp, vni); + if (!vpn) + { + vpn = bgp_evpn_new (bgp, vni, bgp->router_id); + if (!vpn) + { + zlog_err ("%u: Failed to allocate VNI entry for VNI %u - at Config", + bgp->vrf_id, vni); + return NULL; + } + } + + /* Mark as configured. */ + SET_FLAG (vpn->flags, VNI_FLAG_CFGD); + return vpn; +} + +/* + * Delete VNI. If VNI does not exist in the system (i.e., just + * configuration), all that is needed is to free it. Otherwise, + * any parameters configured for the VNI need to be reset (with + * appropriate action) and the VNI marked as unconfigured; the + * VNI will continue to exist, purely as a "learnt" entity. + */ +static int +evpn_delete_vni (struct bgp *bgp, struct bgpevpn *vpn) +{ + assert (bgp->vnihash); + + if (!is_vni_live (vpn)) + { + bgp_evpn_free (bgp, vpn); + return 0; + } + + /* We need to take the unconfigure action for each parameter of this VNI + * that is configured. Some optimization is possible, but not worth the + * additional code for an operation that should be pretty rare. + */ + UNSET_FLAG (vpn->flags, VNI_FLAG_CFGD); + + /* First, deal with the export side - RD and export RT changes. */ + if (is_rd_configured (vpn)) + evpn_unconfigure_rd (bgp, vpn); + if (is_export_rt_configured (vpn)) + evpn_unconfigure_export_rt (bgp, vpn, NULL); + + /* Next, deal with the import side. */ + if (is_import_rt_configured (vpn)) + evpn_unconfigure_import_rt (bgp, vpn, NULL); + + return 0; +} + /* * Display import RT mapping to VNIs (vty handler) */ @@ -1427,6 +1743,57 @@ evpn_unset_advertise_all_vni (struct bgp *bgp) bgp_evpn_cleanup_on_disable (bgp); } +static void +write_vni_config (struct vty *vty, struct bgpevpn *vpn, int *write) +{ + char buf1[INET6_ADDRSTRLEN]; + afi_t afi = AFI_L2VPN; + safi_t safi = SAFI_EVPN; + char *ecom_str; + struct listnode *node, *nnode; + struct ecommunity *ecom; + + if (is_vni_configured (vpn)) + { + bgp_config_write_family_header (vty, afi, safi, write); + vty_out (vty, " vni %d%s", vpn->vni, VTY_NEWLINE); + if (is_rd_configured (vpn)) + vty_out (vty, " rd %s%s", + prefix_rd2str (&vpn->prd, buf1, RD_ADDRSTRLEN), + VTY_NEWLINE); + + if (is_import_rt_configured (vpn)) + { + for (ALL_LIST_ELEMENTS (vpn->import_rtl, node, nnode, ecom)) + { + ecom_str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0); + vty_out (vty, " route-target import %s%s", ecom_str, VTY_NEWLINE); + XFREE (MTYPE_ECOMMUNITY_STR, ecom_str); + } + } + + if (is_export_rt_configured (vpn)) + { + for (ALL_LIST_ELEMENTS (vpn->export_rtl, node, nnode, ecom)) + { + ecom_str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0); + vty_out (vty, " route-target export %s%s", ecom_str, VTY_NEWLINE); + XFREE (MTYPE_ECOMMUNITY_STR, ecom_str); + } + } + + vty_out (vty, " exit-vni%s", VTY_NEWLINE); + } +} + +static void +write_vni_config_for_entry (struct hash_backet *backet, + struct evpn_config_write *cfg) +{ + struct bgpevpn *vpn = (struct bgpevpn *) backet->data; + write_vni_config (cfg->vty, vpn, &cfg->write); +} + DEFUN (bgp_evpn_advertise_all_vni, bgp_evpn_advertise_all_vni_cmd, "advertise-all-vni", @@ -1818,6 +2185,445 @@ DEFUN (show_bgp_evpn_import_rt, return CMD_SUCCESS; } +DEFUN_NOSH (bgp_evpn_vni, + bgp_evpn_vni_cmd, + "vni (1-16777215)", + "VXLAN Network Identifier\n" + "VNI number\n") +{ + vni_t vni; + struct bgp *bgp = VTY_GET_CONTEXT(bgp); + struct bgpevpn *vpn; + + if (!bgp) + return CMD_WARNING; + + VTY_GET_INTEGER_RANGE ("VNI", vni, argv[1]->arg, 1, VNI_MAX); + + /* Create VNI, or mark as configured. */ + vpn = evpn_create_update_vni (bgp, vni); + if (!vpn) + { + vty_out (vty, "%% Failed to create VNI %s", VTY_NEWLINE); + return CMD_WARNING; + } + + VTY_PUSH_CONTEXT_SUB (BGP_EVPN_VNI_NODE, vpn); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_evpn_vni, + no_bgp_evpn_vni_cmd, + "no vni (1-16777215)", + NO_STR + "VXLAN Network Identifier\n" + "VNI number\n") +{ + vni_t vni; + struct bgp *bgp = VTY_GET_CONTEXT(bgp); + struct bgpevpn *vpn; + + if (!bgp) + return CMD_WARNING; + + VTY_GET_INTEGER_RANGE ("VNI", vni, argv[2]->arg, 1, VNI_MAX); + + /* Check if we should disallow. */ + vpn = bgp_evpn_lookup_vni (bgp, vni); + if (!vpn) + { + vty_out (vty, "%% Specified VNI does not exist%s", VTY_NEWLINE); + return CMD_WARNING; + } + if (!is_vni_configured (vpn)) + { + vty_out (vty, "%% Specified VNI is not configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + + evpn_delete_vni (bgp, vpn); + return CMD_SUCCESS; +} + +DEFUN_NOSH (exit_vni, + exit_vni_cmd, + "exit-vni", + "Exit from VNI mode\n") +{ + if (vty->node == BGP_EVPN_VNI_NODE) + vty->node = BGP_EVPN_NODE; + return CMD_SUCCESS; +} + +DEFUN (bgp_evpn_vni_rd, + bgp_evpn_vni_rd_cmd, + "rd ASN:nn_or_IP-address:nn", + "Route Distinguisher\n" + "ASN:XX or A.B.C.D:XX\n") +{ + struct prefix_rd prd; + struct bgp *bgp = VTY_GET_CONTEXT(bgp); + VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn); + int ret; + + if (!bgp || !vpn) + return CMD_WARNING; + + ret = str2prefix_rd (argv[1]->arg, &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* If same as existing value, there is nothing more to do. */ + if (bgp_evpn_rd_matches_existing (vpn, &prd)) + return CMD_SUCCESS; + + /* Configure or update the RD. */ + evpn_configure_rd (bgp, vpn, &prd); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_evpn_vni_rd, + no_bgp_evpn_vni_rd_cmd, + "no rd ASN:nn_or_IP-address:nn", + NO_STR + "Route Distinguisher\n" + "ASN:XX or A.B.C.D:XX\n") +{ + struct prefix_rd prd; + struct bgp *bgp = VTY_GET_CONTEXT(bgp); + VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn); + int ret; + + if (!bgp || !vpn) + return CMD_WARNING; + + ret = str2prefix_rd (argv[2]->arg, &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check if we should disallow. */ + if (!is_rd_configured (vpn)) + { + vty_out (vty, "%% RD is not configured for this VNI%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (!bgp_evpn_rd_matches_existing(vpn, &prd)) + { + vty_out (vty, "%% RD specified does not match configuration for this VNI%s", VTY_NEWLINE); + return CMD_WARNING; + } + + evpn_unconfigure_rd (bgp, vpn); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_evpn_vni_rd_without_val, + no_bgp_evpn_vni_rd_without_val_cmd, + "no rd", + NO_STR + "Route Distinguisher\n") +{ + struct bgp *bgp = VTY_GET_CONTEXT(bgp); + VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn); + + if (!bgp || !vpn) + return CMD_WARNING; + + /* Check if we should disallow. */ + if (!is_rd_configured (vpn)) + { + vty_out (vty, "%% RD is not configured for this VNI%s", VTY_NEWLINE); + return CMD_WARNING; + } + + evpn_unconfigure_rd (bgp, vpn); + return CMD_SUCCESS; +} + +/* + * Loop over all extended-communities in the route-target list rtl and + * return 1 if we find ecomtarget + */ +static int +bgp_evpn_rt_matches_existing (struct list *rtl, + struct ecommunity *ecomtarget) +{ + struct listnode *node, *nnode; + struct ecommunity *ecom; + + for (ALL_LIST_ELEMENTS (rtl, node, nnode, ecom)) + { + if (ecommunity_match (ecom, ecomtarget)) + return 1; + } + + return 0; +} + + +DEFUN (bgp_evpn_vni_rt, + bgp_evpn_vni_rt_cmd, + "route-target RT", + "Route Target\n" + "import and export\n" + "import\n" + "export\n" + "Route target (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n") +{ + struct bgp *bgp = VTY_GET_CONTEXT(bgp); + VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn); + int rt_type; + struct ecommunity *ecomadd = NULL; + + if (!bgp || !vpn) + return CMD_WARNING; + + if (!strcmp (argv[1]->arg, "import")) + rt_type = RT_TYPE_IMPORT; + else if (!strcmp (argv[1]->arg, "export")) + rt_type = RT_TYPE_EXPORT; + else if (!strcmp (argv[1]->arg, "both")) + rt_type = RT_TYPE_BOTH; + else + { + vty_out (vty, "%% Invalid Route Target type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Add/update the import route-target */ + if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_IMPORT) + { + ecomadd = ecommunity_str2com (argv[2]->arg, + ECOMMUNITY_ROUTE_TARGET, 0); + ecommunity_str(ecomadd); + if (!ecomadd) + { + vty_out (vty, "%% Malformed Route Target list%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Do nothing if we already have this import route-target */ + if (! bgp_evpn_rt_matches_existing (vpn->import_rtl, ecomadd)) + evpn_configure_import_rt (bgp, vpn, ecomadd); + } + + /* Add/update the export route-target */ + if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_EXPORT) + { + ecomadd = ecommunity_str2com (argv[2]->arg, + ECOMMUNITY_ROUTE_TARGET, 0); + ecommunity_str(ecomadd); + if (!ecomadd) + { + vty_out (vty, "%% Malformed Route Target list%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Do nothing if we already have this export route-target */ + if (! bgp_evpn_rt_matches_existing (vpn->export_rtl, ecomadd)) + evpn_configure_export_rt (bgp, vpn, ecomadd); + } + + return CMD_SUCCESS; +} + +DEFUN (no_bgp_evpn_vni_rt, + no_bgp_evpn_vni_rt_cmd, + "no route-target RT", + NO_STR + "Route Target\n" + "import and export\n" + "import\n" + "export\n" + "ASN:XX or A.B.C.D:XX\n") +{ + struct bgp *bgp = VTY_GET_CONTEXT(bgp); + VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn); + int rt_type, found_ecomdel; + struct ecommunity *ecomdel = NULL; + + if (!bgp || !vpn) + return CMD_WARNING; + + if (!strcmp (argv[2]->arg, "import")) + rt_type = RT_TYPE_IMPORT; + else if (!strcmp (argv[2]->arg, "export")) + rt_type = RT_TYPE_EXPORT; + else if (!strcmp (argv[2]->arg, "both")) + rt_type = RT_TYPE_BOTH; + else + { + vty_out (vty, "%% Invalid Route Target type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* The user did "no route-target import", check to see if there are any + * import route-targets configured. */ + if (rt_type == RT_TYPE_IMPORT) + { + if (!is_import_rt_configured (vpn)) + { + vty_out (vty, "%% Import RT is not configured for this VNI%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + else if (rt_type == RT_TYPE_EXPORT) + { + if (!is_export_rt_configured (vpn)) + { + vty_out (vty, "%% Export RT is not configured for this VNI%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + else if (rt_type == RT_TYPE_BOTH) + { + if (!is_import_rt_configured (vpn) && !is_export_rt_configured (vpn)) + { + vty_out (vty, "%% Import/Export RT is not configured for this VNI%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + ecomdel = ecommunity_str2com (argv[3]->arg, ECOMMUNITY_ROUTE_TARGET, 0); + ecommunity_str(ecomdel); + if (!ecomdel) + { + vty_out (vty, "%% Malformed Route Target list%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (rt_type == RT_TYPE_IMPORT) + { + if (!bgp_evpn_rt_matches_existing (vpn->import_rtl, ecomdel)) + { + vty_out (vty, "%% RT specified does not match configuration for this VNI%s", VTY_NEWLINE); + return CMD_WARNING; + } + evpn_unconfigure_import_rt (bgp, vpn, ecomdel); + } + else if (rt_type == RT_TYPE_EXPORT) + { + if (!bgp_evpn_rt_matches_existing (vpn->export_rtl, ecomdel)) + { + vty_out (vty, "%% RT specified does not match configuration for this VNI%s", VTY_NEWLINE); + return CMD_WARNING; + } + evpn_unconfigure_export_rt (bgp, vpn, ecomdel); + } + else if (rt_type == RT_TYPE_BOTH) + { + found_ecomdel = 0; + + if (bgp_evpn_rt_matches_existing (vpn->import_rtl, ecomdel)) + { + evpn_unconfigure_import_rt (bgp, vpn, ecomdel); + found_ecomdel = 1; + } + + if (bgp_evpn_rt_matches_existing (vpn->export_rtl, ecomdel)) + { + evpn_unconfigure_export_rt (bgp, vpn, ecomdel); + found_ecomdel = 1; + } + + if (! found_ecomdel) + { + vty_out (vty, "%% RT specified does not match configuration for this VNI%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + return CMD_SUCCESS; +} + +DEFUN (no_bgp_evpn_vni_rt_without_val, + no_bgp_evpn_vni_rt_without_val_cmd, + "no route-target ", + NO_STR + "Route Target\n" + "import\n" + "export\n") +{ + struct bgp *bgp = VTY_GET_CONTEXT(bgp); + VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn); + int rt_type; + + if (!bgp || !vpn) + return CMD_WARNING; + + if (!strcmp (argv[2]->arg, "import")) + { + rt_type = RT_TYPE_IMPORT; + } + else if (!strcmp (argv[2]->arg, "export")) + { + rt_type = RT_TYPE_EXPORT; + } + else + { + vty_out (vty, "%% Invalid Route Target type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check if we should disallow. */ + if (rt_type == RT_TYPE_IMPORT) + { + if (!is_import_rt_configured (vpn)) + { + vty_out (vty, "%% Import RT is not configured for this VNI%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + else + { + if (!is_export_rt_configured (vpn)) + { + vty_out (vty, "%% Export RT is not configured for this VNI%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + /* Unconfigure the RT. */ + if (rt_type == RT_TYPE_IMPORT) + evpn_unconfigure_import_rt (bgp, vpn, NULL); + else + evpn_unconfigure_export_rt (bgp, vpn, NULL); + return CMD_SUCCESS; +} + +/* + * Output EVPN configuration information. + */ +void +bgp_config_write_evpn_info (struct vty *vty, struct bgp *bgp, afi_t afi, + safi_t safi, int *write) +{ + struct evpn_config_write cfg; + + if (bgp->vnihash) + { + cfg.write = *write; + cfg.vty = vty; + hash_iterate (bgp->vnihash, + (void (*) (struct hash_backet *, void *)) + write_vni_config_for_entry, &cfg); + *write = cfg.write; + } + + if (bgp->advertise_all_vni) + { + bgp_config_write_family_header (vty, afi, safi, write); + vty_out (vty, " advertise-all-vni%s", VTY_NEWLINE); + } +} + void bgp_ethernetvpn_init(void) { install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_cmd); @@ -1849,4 +2655,14 @@ void bgp_ethernetvpn_init(void) install_element (VIEW_NODE, &show_bgp_evpn_route_vni_macip_cmd); install_element (VIEW_NODE, &show_bgp_evpn_route_vni_all_cmd); install_element (VIEW_NODE, &show_bgp_evpn_import_rt_cmd); + + install_element (BGP_EVPN_NODE, &bgp_evpn_vni_cmd); + install_element (BGP_EVPN_NODE, &no_bgp_evpn_vni_cmd); + install_element (BGP_EVPN_VNI_NODE, &exit_vni_cmd); + install_element (BGP_EVPN_VNI_NODE, &bgp_evpn_vni_rd_cmd); + install_element (BGP_EVPN_VNI_NODE, &no_bgp_evpn_vni_rd_cmd); + install_element (BGP_EVPN_VNI_NODE, &no_bgp_evpn_vni_rd_without_val_cmd); + install_element (BGP_EVPN_VNI_NODE, &bgp_evpn_vni_rt_cmd); + install_element (BGP_EVPN_VNI_NODE, &no_bgp_evpn_vni_rt_cmd); + install_element (BGP_EVPN_VNI_NODE, &no_bgp_evpn_vni_rt_without_val_cmd); } diff --git a/bgpd/bgp_evpn_vty.h b/bgpd/bgp_evpn_vty.h index fe01e84e2b..4c8f63c2f0 100644 --- a/bgpd/bgp_evpn_vty.h +++ b/bgpd/bgp_evpn_vty.h @@ -21,6 +21,9 @@ #ifndef _FRR_BGP_EVPN_VTY_H #define _FRR_BGP_EVPN_VTY_H +extern void +bgp_config_write_evpn_info (struct vty *vty, struct bgp *bgp, afi_t afi, + safi_t safi, int *write); extern void bgp_ethernetvpn_init(void); #define L2VPN_HELP_STR "Layer 2 Virtual Private Network\n" diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 183a5832dc..b877d982c8 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -10715,6 +10715,13 @@ static struct cmd_node bgp_evpn_node = 1 }; +static struct cmd_node bgp_evpn_vni_node = +{ + BGP_EVPN_VNI_NODE, + "%s(config-router-af-vni)# ", + 1 +}; + static void community_list_vty (void); static void @@ -10784,6 +10791,7 @@ bgp_vty_init (void) install_node (&bgp_vpnv4_node, NULL); install_node (&bgp_vpnv6_node, NULL); install_node (&bgp_evpn_node, NULL); + install_node (&bgp_evpn_vni_node, NULL); /* Install default VTY commands to new nodes. */ install_default (BGP_NODE); @@ -10796,6 +10804,7 @@ bgp_vty_init (void) install_default (BGP_VPNV4_NODE); install_default (BGP_VPNV6_NODE); install_default (BGP_EVPN_NODE); + install_default (BGP_EVPN_VNI_NODE); /* "bgp multiple-instance" commands. */ install_element (CONFIG_NODE, &bgp_multiple_instance_cmd); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 87912693f2..723742eb3d 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -7371,6 +7371,9 @@ bgp_config_write_family (struct vty *vty, struct bgp *bgp, afi_t afi, bgp_config_write_maxpaths (vty, bgp, afi, safi, &write); bgp_config_write_table_map (vty, bgp, afi, safi, &write); + if (safi == SAFI_EVPN) + bgp_config_write_evpn_info (vty, bgp, afi, safi, &write); + if (write) vty_outln (vty, " exit-address-family"); diff --git a/lib/command.c b/lib/command.c index 5ca4a0fda9..c3324b4f93 100644 --- a/lib/command.c +++ b/lib/command.c @@ -875,6 +875,9 @@ node_parent ( enum node_type node ) case BGP_IPV6L_NODE: ret = BGP_NODE; break; + case BGP_EVPN_VNI_NODE: + ret = BGP_EVPN_NODE; + break; case KEYCHAIN_KEY_NODE: ret = KEYCHAIN_NODE; break; @@ -1244,6 +1247,9 @@ cmd_exit (struct vty *vty) case BGP_IPV6L_NODE: vty->node = BGP_NODE; break; + case BGP_EVPN_VNI_NODE: + vty->node = BGP_EVPN_NODE; + break; case LDP_IPV4_NODE: case LDP_IPV6_NODE: vty->node = LDP_NODE; @@ -1312,6 +1318,7 @@ DEFUN (config_end, case BGP_IPV6_NODE: case BGP_IPV6M_NODE: case BGP_EVPN_NODE: + case BGP_EVPN_VNI_NODE: case BGP_IPV6L_NODE: case RMAP_NODE: case OSPF_NODE: diff --git a/lib/command.h b/lib/command.h index 927c04006c..3ae4af629d 100644 --- a/lib/command.h +++ b/lib/command.h @@ -136,6 +136,7 @@ enum node_type MPLS_NODE, /* MPLS config node */ VTY_NODE, /* Vty node. */ LINK_PARAMS_NODE, /* Link-parameters node */ + BGP_EVPN_VNI_NODE, /* BGP EVPN VNI */ }; /* Node which has some commands and prompt string and configuration diff --git a/lib/vty.c b/lib/vty.c index e6497b3100..f97930e13a 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -786,6 +786,7 @@ vty_end_config (struct vty *vty) case MASC_NODE: case PIM_NODE: case VTY_NODE: + case BGP_EVPN_VNI_NODE: vty_config_unlock (vty); vty->node = ENABLE_NODE; break; diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index f02bd0c888..eaee61bdac 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -313,6 +313,10 @@ vtysh_execute_func (const char *line, int pager) { vtysh_execute("exit-address-family"); } + else if ((saved_node == BGP_EVPN_VNI_NODE) && (tried == 1)) + { + vtysh_execute("exit-vni"); + } else if (saved_node == BGP_VRF_POLICY_NODE && (tried == 1)) { vtysh_execute("exit-vrf-policy"); @@ -573,6 +577,10 @@ vtysh_mark_file (const char *filename) { fprintf(stdout, "exit-address-family\n"); } + else if ((prev_node == BGP_EVPN_VNI_NODE) && (tried == 1)) + { + fprintf(stdout, "exit-vni\n"); + } else if ((prev_node == KEYCHAIN_KEY_NODE) && (tried == 1)) { fprintf(stdout, "exit\n"); @@ -985,6 +993,12 @@ static struct cmd_node bgp_evpn_node = "%s(config-router-af)# " }; +static struct cmd_node bgp_evpn_vni_node = +{ + BGP_EVPN_VNI_NODE, + "%s(config-router-af-vni)# " +}; + static struct cmd_node bgp_ipv6l_node = { BGP_IPV6L_NODE, @@ -1271,14 +1285,38 @@ DEFUNSH (VTYSH_BGPD, address_family_evpn, address_family_evpn_cmd, "address-family ", - "Enter Address Family command mode\n" - "Address Family\n" - "Address Family modifier\n") + "Enter Address Family command mode\n" + "Address Family\n" + "Address Family modifier\n") { vty->node = BGP_EVPN_NODE; return CMD_SUCCESS; } +#if defined (HAVE_CUMULUS) +DEFUNSH (VTYSH_BGPD, + address_family_evpn2, + address_family_evpn2_cmd, + "address-family evpn", + "Enter Address Family command mode\n" + "EVPN Address family\n") +{ + vty->node = BGP_EVPN_NODE; + return CMD_SUCCESS; +} +#endif + +DEFUNSH (VTYSH_BGPD, + bgp_evpn_vni, + bgp_evpn_vni_cmd, + "vni (1-16777215)", + "VXLAN Network Identifier\n" + "VNI number\n") +{ + vty->node = BGP_EVPN_VNI_NODE; + return CMD_SUCCESS; +} + #if defined (ENABLE_BGP_VNC) DEFUNSH (VTYSH_BGPD, vnc_defaults, @@ -1618,6 +1656,9 @@ vtysh_exit (struct vty *vty) case BGP_VNC_L2_GROUP_NODE: vty->node = BGP_NODE; break; + case BGP_EVPN_VNI_NODE: + vty->node = BGP_EVPN_NODE; + break; case LDP_IPV4_NODE: case LDP_IPV6_NODE: vty->node = LDP_NODE; @@ -1674,11 +1715,23 @@ DEFUNSH (VTYSH_BGPD, || vty->node == BGP_VPNV6_NODE || vty->node == BGP_IPV6_NODE || vty->node == BGP_IPV6L_NODE - || vty->node == BGP_IPV6M_NODE) + || vty->node == BGP_IPV6M_NODE + || vty->node == BGP_EVPN_NODE) vty->node = BGP_NODE; return CMD_SUCCESS; } +DEFUNSH (VTYSH_BGPD, + exit_vni, + exit_vni_cmd, + "exit-vni", + "Exit from VNI mode\n") +{ + if (vty->node == BGP_EVPN_VNI_NODE) + vty->node = BGP_EVPN_NODE; + return CMD_SUCCESS; +} + DEFUNSH (VTYSH_BGPD, exit_vnc_config, exit_vnc_config_cmd, @@ -3306,6 +3359,7 @@ vtysh_init_vty (void) install_node (&bgp_ipv6l_node, NULL); install_node (&bgp_vrf_policy_node, NULL); install_node (&bgp_evpn_node, NULL); + install_node (&bgp_evpn_vni_node, NULL); install_node (&bgp_vnc_defaults_node, NULL); install_node (&bgp_vnc_nve_group_node, NULL); install_node (&bgp_vnc_l2_group_node, NULL); @@ -3344,6 +3398,7 @@ vtysh_init_vty (void) vtysh_install_default (BGP_IPV6_NODE); vtysh_install_default (BGP_IPV6M_NODE); vtysh_install_default (BGP_EVPN_NODE); + vtysh_install_default (BGP_EVPN_VNI_NODE); vtysh_install_default (BGP_IPV6L_NODE); #if ENABLE_BGP_VNC vtysh_install_default (BGP_VRF_POLICY_NODE); @@ -3422,6 +3477,9 @@ vtysh_init_vty (void) install_element (BGP_IPV6M_NODE, &vtysh_exit_bgpd_cmd); install_element (BGP_IPV6M_NODE, &vtysh_quit_bgpd_cmd); install_element (BGP_EVPN_NODE, &vtysh_quit_bgpd_cmd); + install_element (BGP_EVPN_NODE, &vtysh_exit_bgpd_cmd); + install_element (BGP_EVPN_VNI_NODE, &vtysh_exit_bgpd_cmd); + install_element (BGP_EVPN_VNI_NODE, &vtysh_quit_bgpd_cmd); install_element (BGP_IPV6L_NODE, &vtysh_exit_bgpd_cmd); install_element (BGP_IPV6L_NODE, &vtysh_quit_bgpd_cmd); #if defined (ENABLE_BGP_VNC) @@ -3472,6 +3530,7 @@ vtysh_init_vty (void) install_element (BGP_IPV6L_NODE, &vtysh_end_all_cmd); install_element (BGP_VRF_POLICY_NODE, &vtysh_end_all_cmd); install_element (BGP_EVPN_NODE, &vtysh_end_all_cmd); + install_element (BGP_EVPN_VNI_NODE, &vtysh_end_all_cmd); install_element (BGP_VNC_DEFAULTS_NODE, &vtysh_end_all_cmd); install_element (BGP_VNC_NVE_GROUP_NODE, &vtysh_end_all_cmd); install_element (BGP_VNC_L2_GROUP_NODE, &vtysh_end_all_cmd); @@ -3534,6 +3593,9 @@ vtysh_init_vty (void) install_element (BGP_NODE, &address_family_ipv6_vpn_cmd); install_element (BGP_NODE, &address_family_ipv6_labeled_unicast_cmd); install_element (BGP_NODE, &address_family_evpn_cmd); +#if defined (HAVE_CUMULUS) + install_element (BGP_NODE, &address_family_evpn2_cmd); +#endif install_element (BGP_VPNV4_NODE, &exit_address_family_cmd); install_element (BGP_VPNV6_NODE, &exit_address_family_cmd); install_element (BGP_IPV4_NODE, &exit_address_family_cmd); @@ -3544,6 +3606,10 @@ vtysh_init_vty (void) install_element (BGP_EVPN_NODE, &exit_address_family_cmd); install_element (BGP_IPV6L_NODE, &exit_address_family_cmd); + /* EVPN commands */ + install_element (BGP_EVPN_NODE, &bgp_evpn_vni_cmd); + install_element (BGP_EVPN_VNI_NODE, &exit_vni_cmd); + install_element (BGP_VRF_POLICY_NODE, &exit_vrf_policy_cmd); install_element (BGP_VNC_DEFAULTS_NODE, &exit_vnc_config_cmd); install_element (BGP_VNC_NVE_GROUP_NODE, &exit_vnc_config_cmd); From 2d48ee25bbd6999dd1e1e4703994fc1d81c4dadd Mon Sep 17 00:00:00 2001 From: vivek Date: Mon, 15 May 2017 15:02:33 -0700 Subject: [PATCH 25/31] bgpd: Handle change to router id for EVPN When the BGP router-id changes, EVPN routes need to be processed due to potential change to their RD. Signed-off-by: Vivek Venkatraman --- bgpd/bgp_evpn.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++ bgpd/bgp_evpn.h | 2 ++ bgpd/bgpd.c | 8 ++++++ 3 files changed, 85 insertions(+) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index c787e21e83..77dc2f2bc7 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1761,6 +1761,61 @@ delete_withdraw_vni_routes (struct bgp *bgp, struct bgpevpn *vpn) return 0; } +/* + * Handle router-id change. Update and advertise local routes corresponding + * to this VNI from peers. Note that this is invoked after updating the + * router-id. The routes in the per-VNI table are used to create routes in + * the global table and schedule them. + */ +static void +update_router_id_vni (struct hash_backet *backet, struct bgp *bgp) +{ + struct bgpevpn *vpn; + + vpn = (struct bgpevpn *) backet->data; + + if (!vpn) + { + zlog_warn ("%s: VNI hash entry for VNI not found", + __FUNCTION__); + return; + } + + /* Skip VNIs with configured RD. */ + if (is_rd_configured (vpn)) + return; + + bgp_evpn_derive_auto_rd (bgp, vpn); + update_advertise_vni_routes (bgp, vpn); +} + +/* + * Handle router-id change. Delete and withdraw local routes corresponding + * to this VNI from peers. Note that this is invoked prior to updating + * the router-id and is done only on the global route table, the routes + * are needed in the per-VNI table to re-advertise with new router id. + */ +static void +withdraw_router_id_vni (struct hash_backet *backet, struct bgp *bgp) +{ + struct bgpevpn *vpn; + + vpn = (struct bgpevpn *) backet->data; + + if (!vpn) + { + zlog_warn ("%s: VNI hash entry for VNI not found", + __FUNCTION__); + return; + } + + /* Skip VNIs with configured RD. */ + if (is_rd_configured (vpn)) + return; + + delete_withdraw_vni_routes (bgp, vpn); +} + /* * Process received EVPN type-2 route (advertise or withdraw). */ @@ -2106,6 +2161,26 @@ free_vni_entry (struct hash_backet *backet, struct bgp *bgp) * Public functions. */ +/* + * Handle change to BGP router id. This is invoked twice by the change + * handler, first before the router id has been changed and then after + * the router id has been changed. The first invocation will result in + * local routes for all VNIs being deleted and withdrawn and the next + * will result in the routes being re-advertised. + */ +void +bgp_evpn_handle_router_id_update (struct bgp *bgp, int withdraw) +{ + if (withdraw) + hash_iterate (bgp->vnihash, + (void (*) (struct hash_backet *, void *)) + withdraw_router_id_vni, bgp); + else + hash_iterate (bgp->vnihash, + (void (*) (struct hash_backet *, void *)) + update_router_id_vni, bgp); +} + /* * Handle change to export RT - update and advertise local routes. */ diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index 1a71ec284a..610710d845 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -25,6 +25,8 @@ #define EVPN_ROUTE_STRLEN 200 /* Must be >> MAC + IPv6 strings. */ +extern void +bgp_evpn_handle_router_id_update (struct bgp *bgp, int withdraw); extern char * bgp_evpn_label2str (mpls_label_t *label, char *buf, int len); extern char * diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 723742eb3d..3a4a3e6760 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -227,6 +227,10 @@ bgp_router_id_set (struct bgp *bgp, const struct in_addr *id) if (IPV4_ADDR_SAME (&bgp->router_id, id)) return 0; + /* EVPN uses router id in RD, withdraw them */ + if (bgp->advertise_all_vni) + bgp_evpn_handle_router_id_update (bgp, TRUE); + IPV4_ADDR_COPY (&bgp->router_id, id); /* Set all peer's local identifier with this value. */ @@ -242,6 +246,10 @@ bgp_router_id_set (struct bgp *bgp, const struct in_addr *id) } } + /* EVPN uses router id in RD, update them */ + if (bgp->advertise_all_vni) + bgp_evpn_handle_router_id_update (bgp, FALSE); + return 0; } From af0daa50be3f296648e47ae9a112c97736987500 Mon Sep 17 00:00:00 2001 From: vivek Date: Thu, 25 May 2017 23:06:38 -0700 Subject: [PATCH 26/31] bgpd: Ensure EVPN next hops are not overriden Updates: bgpd: Fix next hop setting for EVPN Signed-off-by: Vivek Venkatraman --- bgpd/bgp_updgrp_packet.c | 1 + 1 file changed, 1 insertion(+) diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index df1bb1eab2..20b334ab59 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -482,6 +482,7 @@ bpacket_reformat_for_peer (struct bpacket *pkt, struct peer_af *paf) nh_modified = 1; } else if (peer->sort == BGP_PEER_EBGP && + paf->safi != SAFI_EVPN && (bgp_multiaccess_check_v4 (v4nh, peer) == 0) && !CHECK_FLAG(vec->flags, BPKT_ATTRVEC_FLAGS_RMAP_NH_UNCHANGED) && From ea3ce9a1a5798511fbbe7905e9b2228f1954ae01 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 26 May 2017 11:54:07 -0400 Subject: [PATCH 27/31] bgpd: On cleanup make sure pointers exist Test cases create fake bgp structure that is passed to cleanup. The new evpn code assumed ( and probably rightly so) that if the bgp structure was created it actually initialized all useful data structures. Just make the evpn cleanup functions be smart about attempting to free memory never allocated. Signed-off-by: Donald Sharp --- bgpd/bgp_evpn.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 77dc2f2bc7..d012952784 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -2830,12 +2830,15 @@ bgp_evpn_cleanup_on_disable (struct bgp *bgp) void bgp_evpn_cleanup (struct bgp *bgp) { - hash_iterate (bgp->vnihash, - (void (*) (struct hash_backet *, void *)) - free_vni_entry, bgp); - hash_free (bgp->import_rt_hash); + if (bgp->vnihash) + hash_iterate (bgp->vnihash, + (void (*) (struct hash_backet *, void *)) + free_vni_entry, bgp); + if (bgp->import_rt_hash) + hash_free (bgp->import_rt_hash); bgp->import_rt_hash = NULL; - hash_free (bgp->vnihash); + if (bgp->vnihash) + hash_free (bgp->vnihash); bgp->vnihash = NULL; bf_free (bgp->rd_idspace); } From d5424e5356955e543cb31243f69e38cf68e05a33 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 26 May 2017 11:59:05 -0400 Subject: [PATCH 28/31] lib: Fix some defines for older platforms Signed-off-by: Donald Sharp --- zebra/rt_netlink.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index d676fc8296..db9cc3e184 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -96,6 +96,10 @@ #define NDA_MASTER 9 #endif +#ifndef NTF_MASTER +#define NTF_MASTER 0x04 +#endif + #ifndef NTF_SELF #define NTF_SELF 0x02 #endif @@ -104,6 +108,10 @@ #define NTF_EXT_LEARNED 0x10 #endif +#ifndef NDA_IFINDEX +#define NDA_IFINDEX 8 +#endif + #ifndef NDA_VLAN #define NDA_VLAN 5 #endif From aadc0905054edac0fe88b35ae29236875d586cd8 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 6 Jun 2017 13:20:38 -0400 Subject: [PATCH 29/31] bgpd: Refactor 'struct attr_extra' into 'struct attr' Most of the attributes in 'struct attr_extra' allow for the more interesting cases of using bgp. The extra overhead of managing it will induce errors as we add more attributes and the extra memory overhead is negligible on anything but full bgp feeds. Additionally this greatly simplifies the code for the handling of data. Signed-off-by: Donald Sharp bgpd: Fix missing label set Signed-off-by: Donald Sharp --- bgpd/bgp_attr.c | 799 ++++++++++++++--------------------- bgpd/bgp_attr.h | 72 ++-- bgpd/bgp_attr_evpn.c | 21 +- bgpd/bgp_debug.c | 53 ++- bgpd/bgp_encap_tlv.c | 65 ++- bgpd/bgp_evpn.c | 67 ++- bgpd/bgp_label.c | 6 +- bgpd/bgp_memory.c | 1 - bgpd/bgp_memory.h | 1 - bgpd/bgp_mpath.c | 62 ++- bgpd/bgp_nht.c | 6 +- bgpd/bgp_packet.c | 7 +- bgpd/bgp_route.c | 410 ++++++++---------- bgpd/bgp_route.h | 4 +- bgpd/bgp_routemap.c | 100 ++--- bgpd/bgp_snmp.c | 10 +- bgpd/bgp_updgrp_adv.c | 13 +- bgpd/bgp_vty.c | 5 - bgpd/bgp_zebra.c | 42 +- bgpd/rfapi/rfapi.c | 47 +-- bgpd/rfapi/rfapi_encap_tlv.c | 14 +- bgpd/rfapi/rfapi_import.c | 288 ++++++------- bgpd/rfapi/rfapi_rib.c | 8 +- bgpd/rfapi/rfapi_vty.c | 38 +- bgpd/rfapi/vnc_export_bgp.c | 62 +-- bgpd/rfapi/vnc_import_bgp.c | 37 +- 26 files changed, 923 insertions(+), 1315 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index e62d1bb0aa..4d828d2822 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -270,17 +270,17 @@ encap_free(struct bgp_attr_encap_subtlv *p) void bgp_attr_flush_encap(struct attr *attr) { - if (!attr || !attr->extra) + if (!attr) return; - if (attr->extra->encap_subtlvs) { - encap_free(attr->extra->encap_subtlvs); - attr->extra->encap_subtlvs = NULL; + if (attr->encap_subtlvs) { + encap_free(attr->encap_subtlvs); + attr->encap_subtlvs = NULL; } #if ENABLE_BGP_VNC - if (attr->extra->vnc_subtlvs) { - encap_free(attr->extra->vnc_subtlvs); - attr->extra->vnc_subtlvs = NULL; + if (attr->vnc_subtlvs) { + encap_free(attr->vnc_subtlvs); + attr->vnc_subtlvs = NULL; } #endif } @@ -424,15 +424,15 @@ encap_finish (void) } static bool -overlay_index_same(const struct attr_extra *ae1, const struct attr_extra *ae2) +overlay_index_same(const struct attr *a1, const struct attr *a2) { - if(!ae1 && ae2) + if(!a1 && a2) return false; - if(!ae2 && ae1) + if(!a2 && a1) return false; - if(!ae1 && !ae2) + if(!a1 && !a2) return true; - return !memcmp(&(ae1->evpn_overlay), &(ae2->evpn_overlay), sizeof(struct overlay_index)); + return !memcmp(&(a1->evpn_overlay), &(a2->evpn_overlay), sizeof(struct overlay_index)); } /* Unknown transit attribute. */ @@ -532,34 +532,6 @@ transit_finish (void) /* Attribute hash routines. */ static struct hash *attrhash; -static struct attr_extra * -bgp_attr_extra_new (void) -{ - struct attr_extra *extra; - extra = XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra)); - extra->label_index = BGP_INVALID_LABEL_INDEX; - extra->label = MPLS_INVALID_LABEL; - return extra; -} - -void -bgp_attr_extra_free (struct attr *attr) -{ - if (attr->extra) - { - XFREE (MTYPE_ATTR_EXTRA, attr->extra); - attr->extra = NULL; - } -} - -struct attr_extra * -bgp_attr_extra_get (struct attr *attr) -{ - if (!attr->extra) - attr->extra = bgp_attr_extra_new(); - return attr->extra; -} - /* Shallow copy of an attribute * Though, not so shallow that it doesn't copy the contents * of the attr_extra pointed to by 'extra' @@ -567,33 +539,7 @@ bgp_attr_extra_get (struct attr *attr) void bgp_attr_dup (struct attr *new, struct attr *orig) { - struct attr_extra *extra = new->extra; - *new = *orig; - /* if caller provided attr_extra space, use it in any case. - * - * This is neccesary even if orig->extra equals NULL, because otherwise - * memory may be later allocated on the heap by bgp_attr_extra_get. - * - * That memory would eventually be leaked, because the caller must not - * call bgp_attr_extra_free if he provided attr_extra on the stack. - */ - if (extra) - { - new->extra = extra; - memset(new->extra, 0, sizeof(struct attr_extra)); - new->extra->label_index = BGP_INVALID_LABEL_INDEX; - new->extra->label = MPLS_INVALID_LABEL; - - if (orig->extra) { - *new->extra = *orig->extra; - } - } - else if (orig->extra) - { - new->extra = bgp_attr_extra_new(); - *new->extra = *orig->extra; - } } void @@ -605,21 +551,18 @@ bgp_attr_deep_dup (struct attr *new, struct attr *orig) if (orig->community) new->community = community_dup(orig->community); - if (orig->extra) - { - if (orig->extra->ecommunity) - new->extra->ecommunity = ecommunity_dup(orig->extra->ecommunity); - if (orig->extra->cluster) - new->extra->cluster = cluster_dup(orig->extra->cluster); - if (orig->extra->transit) - new->extra->transit = transit_dup(orig->extra->transit); - if (orig->extra->encap_subtlvs) - new->extra->encap_subtlvs = encap_tlv_dup(orig->extra->encap_subtlvs); + if (orig->ecommunity) + new->ecommunity = ecommunity_dup(orig->ecommunity); + if (orig->cluster) + new->cluster = cluster_dup(orig->cluster); + if (orig->transit) + new->transit = transit_dup(orig->transit); + if (orig->encap_subtlvs) + new->encap_subtlvs = encap_tlv_dup(orig->encap_subtlvs); #if ENABLE_BGP_VNC - if (orig->extra->vnc_subtlvs) - new->extra->vnc_subtlvs = encap_tlv_dup(orig->extra->vnc_subtlvs); + if (orig->vnc_subtlvs) + new->vnc_subtlvs = encap_tlv_dup(orig->vnc_subtlvs); #endif - } } void @@ -631,21 +574,18 @@ bgp_attr_deep_free (struct attr *attr) if (attr->community) community_free(attr->community); - if (attr->extra) - { - if (attr->extra->ecommunity) - ecommunity_free(&attr->extra->ecommunity); - if (attr->extra->cluster) - cluster_free(attr->extra->cluster); - if (attr->extra->transit) - transit_free(attr->extra->transit); - if (attr->extra->encap_subtlvs) - encap_free(attr->extra->encap_subtlvs); + if (attr->ecommunity) + ecommunity_free(&attr->ecommunity); + if (attr->cluster) + cluster_free(attr->cluster); + if (attr->transit) + transit_free(attr->transit); + if (attr->encap_subtlvs) + encap_free(attr->encap_subtlvs); #if ENABLE_BGP_VNC - if (attr->extra->vnc_subtlvs) - encap_free(attr->extra->vnc_subtlvs); + if (attr->vnc_subtlvs) + encap_free(attr->vnc_subtlvs); #endif - } } unsigned long int @@ -664,7 +604,6 @@ unsigned int attrhash_key_make (void *p) { const struct attr *attr = (struct attr *) p; - const struct attr_extra *extra = attr->extra; uint32_t key = 0; #define MIX(val) key = jhash_1word(val, key) @@ -678,43 +617,37 @@ attrhash_key_make (void *p) key += attr->med; key += attr->local_pref; - if (extra) - { - MIX(extra->aggregator_as); - MIX(extra->aggregator_addr.s_addr); - MIX(extra->weight); - MIX(extra->mp_nexthop_global_in.s_addr); - MIX(extra->originator_id.s_addr); - MIX(extra->tag); - MIX(extra->label); - MIX(extra->label_index); - } - + MIX(attr->aggregator_as); + MIX(attr->aggregator_addr.s_addr); + MIX(attr->weight); + MIX(attr->mp_nexthop_global_in.s_addr); + MIX(attr->originator_id.s_addr); + MIX(attr->tag); + MIX(attr->label); + MIX(attr->label_index); + if (attr->aspath) MIX(aspath_key_make (attr->aspath)); if (attr->community) MIX(community_hash_make (attr->community)); - - if (extra) - { - if (extra->lcommunity) - MIX(lcommunity_hash_make (extra->lcommunity)); - if (extra->ecommunity) - MIX(ecommunity_hash_make (extra->ecommunity)); - if (extra->cluster) - MIX(cluster_hash_key_make (extra->cluster)); - if (extra->transit) - MIX(transit_hash_key_make (extra->transit)); - if (extra->encap_subtlvs) - MIX(encap_hash_key_make (extra->encap_subtlvs)); + + if (attr->lcommunity) + MIX(lcommunity_hash_make (attr->lcommunity)); + if (attr->ecommunity) + MIX(ecommunity_hash_make (attr->ecommunity)); + if (attr->cluster) + MIX(cluster_hash_key_make (attr->cluster)); + if (attr->transit) + MIX(transit_hash_key_make (attr->transit)); + if (attr->encap_subtlvs) + MIX(encap_hash_key_make (attr->encap_subtlvs)); #if ENABLE_BGP_VNC - if (extra->vnc_subtlvs) - MIX(encap_hash_key_make (extra->vnc_subtlvs)); + if (attr->vnc_subtlvs) + MIX(encap_hash_key_make (attr->vnc_subtlvs)); #endif - MIX(extra->mp_nexthop_len); - key = jhash(extra->mp_nexthop_global.s6_addr, IPV6_MAX_BYTELEN, key); - key = jhash(extra->mp_nexthop_local.s6_addr, IPV6_MAX_BYTELEN, key); - } + MIX(attr->mp_nexthop_len); + key = jhash(attr->mp_nexthop_global.s6_addr, IPV6_MAX_BYTELEN, key); + key = jhash(attr->mp_nexthop_local.s6_addr, IPV6_MAX_BYTELEN, key); return key; } @@ -734,38 +667,30 @@ attrhash_cmp (const void *p1, const void *p2) && attr1->local_pref == attr2->local_pref && attr1->rmap_change_flags == attr2->rmap_change_flags) { - const struct attr_extra *ae1 = attr1->extra; - const struct attr_extra *ae2 = attr2->extra; - - if (ae1 && ae2 - && ae1->aggregator_as == ae2->aggregator_as - && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr - && ae1->weight == ae2->weight - && ae1->tag == ae2->tag - && ae1->label_index == ae2->label_index - && ae1->mp_nexthop_len == ae2->mp_nexthop_len - && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global) - && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local) - && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in) - && ae1->ecommunity == ae2->ecommunity - && ae1->lcommunity == ae2->lcommunity - && ae1->cluster == ae2->cluster - && ae1->transit == ae2->transit - && (ae1->encap_tunneltype == ae2->encap_tunneltype) - && encap_same(ae1->encap_subtlvs, ae2->encap_subtlvs) + if (attr1->aggregator_as == attr2->aggregator_as + && attr1->aggregator_addr.s_addr == attr2->aggregator_addr.s_addr + && attr1->weight == attr2->weight + && attr1->tag == attr2->tag + && attr1->label_index == attr2->label_index + && attr1->mp_nexthop_len == attr2->mp_nexthop_len + && IPV6_ADDR_SAME (&attr1->mp_nexthop_global, &attr2->mp_nexthop_global) + && IPV6_ADDR_SAME (&attr1->mp_nexthop_local, &attr2->mp_nexthop_local) + && IPV4_ADDR_SAME (&attr1->mp_nexthop_global_in, &attr2->mp_nexthop_global_in) + && attr1->ecommunity == attr2->ecommunity + && attr1->lcommunity == attr2->lcommunity + && attr1->cluster == attr2->cluster + && attr1->transit == attr2->transit + && (attr1->encap_tunneltype == attr2->encap_tunneltype) + && encap_same(attr1->encap_subtlvs, attr2->encap_subtlvs) #if ENABLE_BGP_VNC - && encap_same(ae1->vnc_subtlvs, ae2->vnc_subtlvs) + && encap_same(attr1->vnc_subtlvs, attr2->vnc_subtlvs) #endif - && IPV4_ADDR_SAME (&ae1->originator_id, &ae2->originator_id) - && overlay_index_same(ae1, ae2)) + && IPV4_ADDR_SAME (&attr1->originator_id, &attr2->originator_id) + && overlay_index_same(attr1, attr2)) return 1; - else if (ae1 || ae2) - return 0; - /* neither attribute has extra attributes, so they're same */ - return 1; } - else - return 0; + + return 0; } static void @@ -780,7 +705,6 @@ attrhash_init (void) static void attr_vfree (void *attr) { - bgp_attr_extra_free ((struct attr *)attr); XFREE (MTYPE_ATTR, attr); } @@ -813,24 +737,19 @@ attr_show_all (struct vty *vty) static void * bgp_attr_hash_alloc (void *p) { - const struct attr * val = (const struct attr *) p; + struct attr * val = (struct attr *) p; struct attr *attr; attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr)); *attr = *val; - if (val->extra) - { - attr->extra = bgp_attr_extra_new (); - *attr->extra = *val->extra; - if (val->extra->encap_subtlvs) { - val->extra->encap_subtlvs = NULL; - } + if (val->encap_subtlvs) { + val->encap_subtlvs = NULL; + } #if ENABLE_BGP_VNC - if (val->extra->vnc_subtlvs) { - val->extra->vnc_subtlvs = NULL; - } + if (val->vnc_subtlvs) { + val->vnc_subtlvs = NULL; + } #endif - } attr->refcnt = 0; return attr; } @@ -856,56 +775,51 @@ bgp_attr_intern (struct attr *attr) else attr->community->refcnt++; } - if (attr->extra) + + if (attr->ecommunity) { - struct attr_extra *attre = attr->extra; - - if (attre->ecommunity) - { - if (! attre->ecommunity->refcnt) - attre->ecommunity = ecommunity_intern (attre->ecommunity); - else - attre->ecommunity->refcnt++; - - } - if (attre->lcommunity) - { - if (! attre->lcommunity->refcnt) - attre->lcommunity = lcommunity_intern (attre->lcommunity); - else - attre->lcommunity->refcnt++; - } - if (attre->cluster) - { - if (! attre->cluster->refcnt) - attre->cluster = cluster_intern (attre->cluster); - else - attre->cluster->refcnt++; - } - if (attre->transit) - { - if (! attre->transit->refcnt) - attre->transit = transit_intern (attre->transit); - else - attre->transit->refcnt++; - } - if (attre->encap_subtlvs) - { - if (! attre->encap_subtlvs->refcnt) - attre->encap_subtlvs = encap_intern (attre->encap_subtlvs, ENCAP_SUBTLV_TYPE); - else - attre->encap_subtlvs->refcnt++; - } -#if ENABLE_BGP_VNC - if (attre->vnc_subtlvs) - { - if (! attre->vnc_subtlvs->refcnt) - attre->vnc_subtlvs = encap_intern (attre->vnc_subtlvs, VNC_SUBTLV_TYPE); - else - attre->vnc_subtlvs->refcnt++; - } -#endif + if (! attr->ecommunity->refcnt) + attr->ecommunity = ecommunity_intern (attr->ecommunity); + else + attr->ecommunity->refcnt++; } + if (attr->lcommunity) + { + if (! attr->lcommunity->refcnt) + attr->lcommunity = lcommunity_intern (attr->lcommunity); + else + attr->lcommunity->refcnt++; + } + if (attr->cluster) + { + if (! attr->cluster->refcnt) + attr->cluster = cluster_intern (attr->cluster); + else + attr->cluster->refcnt++; + } + if (attr->transit) + { + if (! attr->transit->refcnt) + attr->transit = transit_intern (attr->transit); + else + attr->transit->refcnt++; + } + if (attr->encap_subtlvs) + { + if (! attr->encap_subtlvs->refcnt) + attr->encap_subtlvs = encap_intern (attr->encap_subtlvs, ENCAP_SUBTLV_TYPE); + else + attr->encap_subtlvs->refcnt++; + } +#if ENABLE_BGP_VNC + if (attr->vnc_subtlvs) + { + if (! attr->vnc_subtlvs->refcnt) + attr->vnc_subtlvs = encap_intern (attr->vnc_subtlvs, VNC_SUBTLV_TYPE); + else + attr->vnc_subtlvs->refcnt++; + } +#endif find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc); find->refcnt++; @@ -932,26 +846,23 @@ bgp_attr_refcount (struct attr *attr) if (attr->community) attr->community->refcnt++; - if (attr->extra) - { - struct attr_extra *attre = attr->extra; - if (attre->ecommunity) - attre->ecommunity->refcnt++; + if (attr->ecommunity) + attr->ecommunity->refcnt++; - if (attre->cluster) - attre->cluster->refcnt++; + if (attr->cluster) + attr->cluster->refcnt++; - if (attre->transit) - attre->transit->refcnt++; + if (attr->transit) + attr->transit->refcnt++; - if (attre->encap_subtlvs) - attre->encap_subtlvs->refcnt++; + if (attr->encap_subtlvs) + attr->encap_subtlvs->refcnt++; #if ENABLE_BGP_VNC - if (attre->vnc_subtlvs) - attre->vnc_subtlvs->refcnt++; + if (attr->vnc_subtlvs) + attr->vnc_subtlvs->refcnt++; #endif - } + attr->refcnt++; return attr; } @@ -961,18 +872,17 @@ struct attr * bgp_attr_default_set (struct attr *attr, u_char origin) { memset (attr, 0, sizeof (struct attr)); - bgp_attr_extra_get (attr); attr->origin = origin; attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN); attr->aspath = aspath_empty (); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH); - attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT; - attr->extra->tag = 0; - attr->extra->label_index = BGP_INVALID_LABEL_INDEX; - attr->extra->label = MPLS_INVALID_LABEL; + attr->weight = BGP_ATTR_DEFAULT_WEIGHT; + attr->tag = 0; + attr->label_index = BGP_INVALID_LABEL_INDEX; + attr->label = MPLS_INVALID_LABEL; attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); - attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN; + attr->mp_nexthop_len = IPV6_MAX_BYTELEN; return attr; } @@ -986,11 +896,8 @@ bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin, { struct attr attr; struct attr *new; - struct attr_extra attre; memset (&attr, 0, sizeof (struct attr)); - memset (&attre, 0, sizeof (struct attr_extra)); - attr.extra = &attre; /* Origin attribute. */ attr.origin = origin; @@ -1012,18 +919,20 @@ bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin, attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); } - attre.label_index = BGP_INVALID_LABEL_INDEX; - attre.label = MPLS_INVALID_LABEL; - attre.weight = BGP_ATTR_DEFAULT_WEIGHT; - attre.mp_nexthop_len = IPV6_MAX_BYTELEN; + attr.label_index = BGP_INVALID_LABEL_INDEX; + attr.label = MPLS_INVALID_LABEL; + attr.weight = BGP_ATTR_DEFAULT_WEIGHT; + attr.mp_nexthop_len = IPV6_MAX_BYTELEN; if (! as_set || atomic_aggregate) attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR); if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION)) - attre.aggregator_as = bgp->confed_id; + attr.aggregator_as = bgp->confed_id; else - attre.aggregator_as = bgp->as; - attre.aggregator_addr = bgp->router_id; + attr.aggregator_as = bgp->as; + attr.aggregator_addr = bgp->router_id; + attr.label_index = BGP_INVALID_LABEL_INDEX; + attr.label = MPLS_INVALID_LABEL; new = bgp_attr_intern (&attr); @@ -1044,31 +953,28 @@ bgp_attr_unintern_sub (struct attr *attr) community_unintern (&attr->community); UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)); - if (attr->extra) - { - if (attr->extra->ecommunity) - ecommunity_unintern (&attr->extra->ecommunity); - UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)); + if (attr->ecommunity) + ecommunity_unintern (&attr->ecommunity); + UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)); - if (attr->extra->lcommunity) - lcommunity_unintern (&attr->extra->lcommunity); - UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES)); + if (attr->lcommunity) + lcommunity_unintern (&attr->lcommunity); + UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES)); - if (attr->extra->cluster) - cluster_unintern (attr->extra->cluster); - UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST)); - - if (attr->extra->transit) - transit_unintern (attr->extra->transit); + if (attr->cluster) + cluster_unintern (attr->cluster); + UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST)); - if (attr->extra->encap_subtlvs) - encap_unintern (&attr->extra->encap_subtlvs, ENCAP_SUBTLV_TYPE); + if (attr->transit) + transit_unintern (attr->transit); + + if (attr->encap_subtlvs) + encap_unintern (&attr->encap_subtlvs, ENCAP_SUBTLV_TYPE); #if ENABLE_BGP_VNC - if (attr->extra->vnc_subtlvs) - encap_unintern (&attr->extra->vnc_subtlvs, VNC_SUBTLV_TYPE); + if (attr->vnc_subtlvs) + encap_unintern (&attr->vnc_subtlvs, VNC_SUBTLV_TYPE); #endif - } } /* Free bgp attribute and aspath. */ @@ -1078,25 +984,17 @@ bgp_attr_unintern (struct attr **pattr) struct attr *attr = *pattr; struct attr *ret; struct attr tmp; - struct attr_extra tmp_extra; - + /* Decrement attribute reference. */ attr->refcnt--; - + tmp = *attr; - if (attr->extra) - { - tmp.extra = &tmp_extra; - memcpy (tmp.extra, attr->extra, sizeof (struct attr_extra)); - } - /* If reference becomes zero then free attribute object. */ if (attr->refcnt == 0) { ret = hash_release (attrhash, attr); assert (ret != NULL); - bgp_attr_extra_free (attr); XFREE (MTYPE_ATTR, attr); *pattr = NULL; } @@ -1117,37 +1015,33 @@ bgp_attr_flush (struct attr *attr) community_free (attr->community); attr->community = NULL; } - if (attr->extra) - { - struct attr_extra *attre = attr->extra; - if (attre->ecommunity && ! attre->ecommunity->refcnt) - ecommunity_free (&attre->ecommunity); - if (attre->lcommunity && ! attre->lcommunity->refcnt) - lcommunity_free (&attre->lcommunity); - if (attre->cluster && ! attre->cluster->refcnt) - { - cluster_free (attre->cluster); - attre->cluster = NULL; - } - if (attre->transit && ! attre->transit->refcnt) - { - transit_free (attre->transit); - attre->transit = NULL; - } - if (attre->encap_subtlvs && ! attre->encap_subtlvs->refcnt) - { - encap_free(attre->encap_subtlvs); - attre->encap_subtlvs = NULL; - } -#if ENABLE_BGP_VNC - if (attre->vnc_subtlvs && ! attre->vnc_subtlvs->refcnt) - { - encap_free(attre->vnc_subtlvs); - attre->vnc_subtlvs = NULL; - } -#endif + if (attr->ecommunity && ! attr->ecommunity->refcnt) + ecommunity_free (&attr->ecommunity); + if (attr->lcommunity && ! attr->lcommunity->refcnt) + lcommunity_free (&attr->lcommunity); + if (attr->cluster && ! attr->cluster->refcnt) + { + cluster_free (attr->cluster); + attr->cluster = NULL; } + if (attr->transit && ! attr->transit->refcnt) + { + transit_free (attr->transit); + attr->transit = NULL; + } + if (attr->encap_subtlvs && ! attr->encap_subtlvs->refcnt) + { + encap_free(attr->encap_subtlvs); + attr->encap_subtlvs = NULL; + } +#if ENABLE_BGP_VNC + if (attr->vnc_subtlvs && ! attr->vnc_subtlvs->refcnt) + { + encap_free(attr->vnc_subtlvs); + attr->vnc_subtlvs = NULL; + } +#endif } /* Implement draft-scudder-idr-optional-transitive behaviour and @@ -1630,7 +1524,6 @@ bgp_attr_aggregator (struct bgp_attr_parser_args *args) const bgp_size_t length = args->length; int wantedlen = 6; - struct attr_extra *attre = bgp_attr_extra_get (attr); /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */ if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) @@ -1645,10 +1538,10 @@ bgp_attr_aggregator (struct bgp_attr_parser_args *args) } if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) ) - attre->aggregator_as = stream_getl (peer->ibuf); + attr->aggregator_as = stream_getl (peer->ibuf); else - attre->aggregator_as = stream_getw (peer->ibuf); - attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf); + attr->aggregator_as = stream_getw (peer->ibuf); + attr->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf); /* Set atomic aggregate flag. */ attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR); @@ -1692,7 +1585,6 @@ bgp_attr_munge_as4_attrs (struct peer *const peer, { int ignore_as4_path = 0; struct aspath *newpath; - struct attr_extra *attre = attr->extra; if (!attr->aspath) { @@ -1732,8 +1624,6 @@ bgp_attr_munge_as4_attrs (struct peer *const peer, { if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) ) { - assert (attre); - /* received both. * if the as_number in aggregator is not AS_TRANS, * then AS4_AGGREGATOR and AS4_PATH shall be ignored @@ -1746,7 +1636,7 @@ bgp_attr_munge_as4_attrs (struct peer *const peer, * Aggregating node and the AS_PATH is to be * constructed "as in all other cases" */ - if (attre->aggregator_as != BGP_AS_TRANS) + if (attr->aggregator_as != BGP_AS_TRANS) { /* ignore */ if ( BGP_DEBUG(as4, AS4)) @@ -1759,8 +1649,8 @@ bgp_attr_munge_as4_attrs (struct peer *const peer, else { /* "New_aggregator shall be taken as aggregator" */ - attre->aggregator_as = as4_aggregator; - attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr; + attr->aggregator_as = as4_aggregator; + attr->aggregator_addr.s_addr = as4_aggregator_addr->s_addr; } } else @@ -1774,7 +1664,7 @@ bgp_attr_munge_as4_attrs (struct peer *const peer, zlog_debug ("[AS4] %s BGP not AS4 capable peer send" " AS4_AGGREGATOR but no AGGREGATOR, will take" " it as if AGGREGATOR with AS_TRANS had been there", peer->host); - (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator; + attr->aggregator_as = as4_aggregator; /* sweep it under the carpet and simulate a "good" AGGREGATOR */ attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR)); } @@ -1838,8 +1728,7 @@ bgp_attr_originator_id (struct bgp_attr_parser_args *args) args->total); } - (bgp_attr_extra_get (attr))->originator_id.s_addr - = stream_get_ipv4 (peer->ibuf); + attr->originator_id.s_addr = stream_get_ipv4 (peer->ibuf); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID); @@ -1863,8 +1752,7 @@ bgp_attr_cluster_list (struct bgp_attr_parser_args *args) args->total); } - (bgp_attr_extra_get (attr))->cluster - = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length); + attr->cluster = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length); /* XXX: Fix cluster_parse to use stream API and then remove this */ stream_forward_getp (peer->ibuf, length); @@ -1888,7 +1776,6 @@ bgp_mp_reach_parse (struct bgp_attr_parser_args *args, struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; - struct attr_extra *attre = bgp_attr_extra_get(attr); /* Set end of packet. */ s = BGP_INPUT(peer); @@ -1921,53 +1808,53 @@ bgp_mp_reach_parse (struct bgp_attr_parser_args *args, } /* Get nexthop length. */ - attre->mp_nexthop_len = stream_getc (s); + attr->mp_nexthop_len = stream_getc (s); - if (LEN_LEFT < attre->mp_nexthop_len) + if (LEN_LEFT < attr->mp_nexthop_len) { zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute", - __func__, peer->host, attre->mp_nexthop_len); + __func__, peer->host, attr->mp_nexthop_len); return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } /* Nexthop length check. */ - switch (attre->mp_nexthop_len) + switch (attr->mp_nexthop_len) { case BGP_ATTR_NHLEN_IPV4: - stream_get (&attre->mp_nexthop_global_in, s, IPV4_MAX_BYTELEN); + stream_get (&attr->mp_nexthop_global_in, s, IPV4_MAX_BYTELEN); /* Probably needed for RFC 2283 */ if (attr->nexthop.s_addr == 0) - memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, IPV4_MAX_BYTELEN); + memcpy(&attr->nexthop.s_addr, &attr->mp_nexthop_global_in, IPV4_MAX_BYTELEN); break; case BGP_ATTR_NHLEN_VPNV4: stream_getl (s); /* RD high */ stream_getl (s); /* RD low */ - stream_get (&attre->mp_nexthop_global_in, s, IPV4_MAX_BYTELEN); + stream_get (&attr->mp_nexthop_global_in, s, IPV4_MAX_BYTELEN); break; case BGP_ATTR_NHLEN_IPV6_GLOBAL: case BGP_ATTR_NHLEN_VPNV6_GLOBAL: - if (attre->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL) + if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL) { stream_getl (s); /* RD high */ stream_getl (s); /* RD low */ } - stream_get (&attre->mp_nexthop_global, s, IPV6_MAX_BYTELEN); + stream_get (&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN); break; case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL: case BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL: - if (attre->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) + if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) { stream_getl (s); /* RD high */ stream_getl (s); /* RD low */ } - stream_get (&attre->mp_nexthop_global, s, IPV6_MAX_BYTELEN); - if (attre->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) + stream_get (&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN); + if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) { stream_getl (s); /* RD high */ stream_getl (s); /* RD low */ } - stream_get (&attre->mp_nexthop_local, s, IPV6_MAX_BYTELEN); - if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local)) + stream_get (&attr->mp_nexthop_local, s, IPV6_MAX_BYTELEN); + if (! IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_local)) { char buf1[INET6_ADDRSTRLEN]; char buf2[INET6_ADDRSTRLEN]; @@ -1975,17 +1862,17 @@ bgp_mp_reach_parse (struct bgp_attr_parser_args *args, if (bgp_debug_update(peer, NULL, NULL, 1)) zlog_debug ("%s rcvd nexthops %s, %s -- ignoring non-LL value", peer->host, - inet_ntop (AF_INET6, &attre->mp_nexthop_global, + inet_ntop (AF_INET6, &attr->mp_nexthop_global, buf1, INET6_ADDRSTRLEN), - inet_ntop (AF_INET6, &attre->mp_nexthop_local, + inet_ntop (AF_INET6, &attr->mp_nexthop_local, buf2, INET6_ADDRSTRLEN)); - attre->mp_nexthop_len = IPV6_MAX_BYTELEN; + attr->mp_nexthop_len = IPV6_MAX_BYTELEN; } break; default: zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d", - __func__, peer->host, attre->mp_nexthop_len); + __func__, peer->host, attr->mp_nexthop_len); return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } @@ -2087,18 +1974,16 @@ bgp_attr_large_community (struct bgp_attr_parser_args *args) */ if (length == 0) { - if (attr->extra) - attr->extra->lcommunity = NULL; + attr->lcommunity = NULL; /* Empty extcomm doesn't seem to be invalid per se */ return BGP_ATTR_PARSE_PROCEED; } - (bgp_attr_extra_get (attr))->lcommunity = - lcommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length); + attr->lcommunity = lcommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length); /* XXX: fix ecommunity_parse to use stream API */ stream_forward_getp (peer->ibuf, length); - if (attr->extra && !attr->extra->lcommunity) + if (!attr->lcommunity) return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, args->total); @@ -2119,18 +2004,16 @@ bgp_attr_ext_communities (struct bgp_attr_parser_args *args) if (length == 0) { - if (attr->extra) - attr->extra->ecommunity = NULL; + attr->ecommunity = NULL; /* Empty extcomm doesn't seem to be invalid per se */ return BGP_ATTR_PARSE_PROCEED; } - (bgp_attr_extra_get (attr))->ecommunity = - ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length); + attr->ecommunity = ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length); /* XXX: fix ecommunity_parse to use stream API */ stream_forward_getp (peer->ibuf, length); - if (attr->extra && !attr->extra->ecommunity) + if (!attr->ecommunity) return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, args->total); @@ -2138,8 +2021,8 @@ bgp_attr_ext_communities (struct bgp_attr_parser_args *args) attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); /* Extract MAC mobility sequence number, if any. */ - attr->extra->mm_seqnum = bgp_attr_mac_mobility_seqnum (attr, &sticky); - attr->extra->sticky = sticky; + attr->mm_seqnum = bgp_attr_mac_mobility_seqnum (attr, &sticky); + attr->sticky = sticky; return BGP_ATTR_PARSE_PROCEED; } @@ -2155,7 +2038,6 @@ bgp_attr_encap( u_char *startp) { bgp_size_t total; - struct attr_extra *attre = NULL; struct bgp_attr_encap_subtlv *stlv_last = NULL; uint16_t tunneltype = 0; @@ -2230,37 +2112,30 @@ bgp_attr_encap( length -= sublength; /* attach tlv to encap chain */ - if (!attre) { - attre = bgp_attr_extra_get(attr); - if (BGP_ATTR_ENCAP == type) { - for (stlv_last = attre->encap_subtlvs; stlv_last && stlv_last->next; - stlv_last = stlv_last->next); - if (stlv_last) { - stlv_last->next = tlv; - } else { - attre->encap_subtlvs = tlv; - } + if (BGP_ATTR_ENCAP == type) { + for (stlv_last = attr->encap_subtlvs; stlv_last && stlv_last->next; + stlv_last = stlv_last->next); + if (stlv_last) { + stlv_last->next = tlv; + } else { + attr->encap_subtlvs = tlv; + } #if ENABLE_BGP_VNC - } else { - for (stlv_last = attre->vnc_subtlvs; stlv_last && stlv_last->next; - stlv_last = stlv_last->next); - if (stlv_last) { - stlv_last->next = tlv; - } else { - attre->vnc_subtlvs = tlv; - } -#endif - } } else { - stlv_last->next = tlv; + for (stlv_last = attr->vnc_subtlvs; stlv_last && stlv_last->next; + stlv_last = stlv_last->next); + if (stlv_last) { + stlv_last->next = tlv; + } else { + attr->vnc_subtlvs = tlv; + } +#endif } - stlv_last = tlv; + stlv_last->next = tlv; } if (BGP_ATTR_ENCAP == type) { - if (!attre) - attre = bgp_attr_extra_get(attr); - attre->encap_tunneltype = tunneltype; + attr->encap_tunneltype = tunneltype; } if (length) { @@ -2319,14 +2194,14 @@ bgp_attr_prefix_sid (struct bgp_attr_parser_args *args, struct bgp_nlri *mp_upda args->total); /* Store label index; subsequently, we'll check on address-family */ - (bgp_attr_extra_get (attr))->label_index = label_index; + attr->label_index = label_index; /* * Ignore the Label index attribute unless received for labeled-unicast * SAFI. */ if (!mp_update->length || mp_update->safi != SAFI_LABELED_UNICAST) - attr->extra->label_index = BGP_INVALID_LABEL_INDEX; + attr->label_index = BGP_INVALID_LABEL_INDEX; } /* Placeholder code for the IPv6 SID type */ @@ -2382,7 +2257,6 @@ bgp_attr_unknown (struct bgp_attr_parser_args *args) { bgp_size_t total = args->total; struct transit *transit; - struct attr_extra *attre; struct peer *const peer = args->peer; struct attr *const attr = args->attr; u_char *const startp = args->startp; @@ -2420,10 +2294,10 @@ bgp_attr_unknown (struct bgp_attr_parser_args *args) SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL); /* Store transitive attribute to the end of attr->transit. */ - if (! ((attre = bgp_attr_extra_get(attr))->transit) ) - attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit)); + if (!attr->transit) + attr->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit)); - transit = attre->transit; + transit = attr->transit; if (transit->val) transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val, @@ -2805,18 +2679,15 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, if (ret != BGP_ATTR_PARSE_PROCEED) return ret; } - if (attr->extra) - { - /* Finally intern unknown attribute. */ - if (attr->extra->transit) - attr->extra->transit = transit_intern (attr->extra->transit); - if (attr->extra->encap_subtlvs) - attr->extra->encap_subtlvs = encap_intern (attr->extra->encap_subtlvs, ENCAP_SUBTLV_TYPE); + /* Finally intern unknown attribute. */ + if (attr->transit) + attr->transit = transit_intern (attr->transit); + if (attr->encap_subtlvs) + attr->encap_subtlvs = encap_intern (attr->encap_subtlvs, ENCAP_SUBTLV_TYPE); #if ENABLE_BGP_VNC - if (attr->extra->vnc_subtlvs) - attr->extra->vnc_subtlvs = encap_intern (attr->extra->vnc_subtlvs, VNC_SUBTLV_TYPE); + if (attr->vnc_subtlvs) + attr->vnc_subtlvs = encap_intern (attr->vnc_subtlvs, VNC_SUBTLV_TYPE); #endif - } return BGP_ATTR_PARSE_PROCEED; } @@ -2853,7 +2724,7 @@ bgp_packet_mpattr_start (struct stream *s, struct peer *peer, else if (safi == SAFI_LABELED_UNICAST) nh_afi = afi; else - nh_afi = BGP_NEXTHOP_AFI_FROM_NHLEN(attr->extra->mp_nexthop_len); + nh_afi = BGP_NEXTHOP_AFI_FROM_NHLEN(attr->mp_nexthop_len); /* Nexthop */ bpacket_attr_vec_arr_set_vec (vecarr, BGP_ATTR_VEC_NH, s, attr); @@ -2872,12 +2743,12 @@ bgp_packet_mpattr_start (struct stream *s, struct peer *peer, stream_putc (s, 12); stream_putl (s, 0); /* RD = 0, per RFC */ stream_putl (s, 0); - stream_put (s, &attr->extra->mp_nexthop_global_in, 4); + stream_put (s, &attr->mp_nexthop_global_in, 4); break; case SAFI_ENCAP: case SAFI_EVPN: stream_putc (s, 4); - stream_put (s, &attr->extra->mp_nexthop_global_in, 4); + stream_put (s, &attr->mp_nexthop_global_in, 4); break; default: break; @@ -2891,45 +2762,37 @@ bgp_packet_mpattr_start (struct stream *s, struct peer *peer, case SAFI_LABELED_UNICAST: case SAFI_EVPN: { - struct attr_extra *attre = attr->extra; - - assert (attr->extra); - - if (attre->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { + if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { stream_putc (s, BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL); - stream_put (s, &attre->mp_nexthop_global, IPV6_MAX_BYTELEN); - stream_put (s, &attre->mp_nexthop_local, IPV6_MAX_BYTELEN); + stream_put (s, &attr->mp_nexthop_global, IPV6_MAX_BYTELEN); + stream_put (s, &attr->mp_nexthop_local, IPV6_MAX_BYTELEN); } else { stream_putc (s, IPV6_MAX_BYTELEN); - stream_put (s, &attre->mp_nexthop_global, IPV6_MAX_BYTELEN); + stream_put (s, &attr->mp_nexthop_global, IPV6_MAX_BYTELEN); } } break; case SAFI_MPLS_VPN: { - struct attr_extra *attre = attr->extra; - - assert (attr->extra); - if (attre->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL) { + if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL) { stream_putc (s, 24); stream_putl (s, 0); /* RD = 0, per RFC */ stream_putl (s, 0); - stream_put (s, &attre->mp_nexthop_global, IPV6_MAX_BYTELEN); - } else if (attre->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { + stream_put (s, &attr->mp_nexthop_global, IPV6_MAX_BYTELEN); + } else if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { stream_putc (s, 48); stream_putl (s, 0); /* RD = 0, per RFC */ stream_putl (s, 0); - stream_put (s, &attre->mp_nexthop_global, IPV6_MAX_BYTELEN); + stream_put (s, &attr->mp_nexthop_global, IPV6_MAX_BYTELEN); stream_putl (s, 0); /* RD = 0, per RFC */ stream_putl (s, 0); - stream_put (s, &attre->mp_nexthop_local, IPV6_MAX_BYTELEN); + stream_put (s, &attr->mp_nexthop_local, IPV6_MAX_BYTELEN); } } break; case SAFI_ENCAP: - assert (attr->extra); stream_putc (s, IPV6_MAX_BYTELEN); - stream_put (s, &attr->extra->mp_nexthop_global, IPV6_MAX_BYTELEN); + stream_put (s, &attr->mp_nexthop_global, IPV6_MAX_BYTELEN); break; default: break; @@ -2937,7 +2800,7 @@ bgp_packet_mpattr_start (struct stream *s, struct peer *peer, break; default: zlog_err ("Bad nexthop when sening to %s, AFI %u SAFI %u nhlen %d", - peer->host, afi, safi, attr->extra->mp_nexthop_len); + peer->host, afi, safi, attr->mp_nexthop_len); break; } @@ -3007,16 +2870,16 @@ bgp_packet_mpattr_tea( struct bgp_attr_encap_subtlv *st; const char *attrname; - if (!attr || !attr->extra || + if (!attr || (attrtype == BGP_ATTR_ENCAP && - (!attr->extra->encap_tunneltype || - attr->extra->encap_tunneltype == BGP_ENCAP_TYPE_MPLS))) + (!attr->encap_tunneltype || + attr->encap_tunneltype == BGP_ENCAP_TYPE_MPLS))) return; switch (attrtype) { case BGP_ATTR_ENCAP: attrname = "Tunnel Encap"; - subtlvs = attr->extra->encap_subtlvs; + subtlvs = attr->encap_subtlvs; if (subtlvs == NULL) /* nothing to do */ return; /* @@ -3032,7 +2895,7 @@ bgp_packet_mpattr_tea( #if ENABLE_BGP_VNC case BGP_ATTR_VNC: attrname = "VNC"; - subtlvs = attr->extra->vnc_subtlvs; + subtlvs = attr->vnc_subtlvs; if (subtlvs == NULL) /* nothing to do */ return; attrlenfield = 0; /* no outer T + L */ @@ -3071,7 +2934,7 @@ bgp_packet_mpattr_tea( if (attrtype == BGP_ATTR_ENCAP) { /* write outer T+L */ - stream_putw(s, attr->extra->encap_tunneltype); + stream_putw(s, attr->encap_tunneltype); stream_putw(s, attrlenfield - 4); } @@ -3260,8 +3123,6 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, /* Aggregator. */ if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR)) { - assert (attr->extra); - /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_AGGREGATOR); @@ -3270,7 +3131,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, { /* AS4 capable peer */ stream_putc (s, 8); - stream_putl (s, attr->extra->aggregator_as); + stream_putl (s, attr->aggregator_as); } else { @@ -3278,7 +3139,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, stream_putc (s, 6); /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */ - if ( attr->extra->aggregator_as > 65535 ) + if ( attr->aggregator_as > 65535 ) { stream_putw (s, BGP_AS_TRANS); @@ -3289,9 +3150,9 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, send_as4_aggregator = 1; } else - stream_putw (s, (u_int16_t) attr->extra->aggregator_as); + stream_putw (s, (u_int16_t) attr->aggregator_as); } - stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr); + stream_put_ipv4 (s, attr->aggregator_addr.s_addr); } /* Community attribute. */ @@ -3316,23 +3177,22 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, /* * Large Community attribute. */ - if (attr->extra && - CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY) + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY) && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES))) { - if (attr->extra->lcommunity->size * 12 > 255) + if (attr->lcommunity->size * 12 > 255) { stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); stream_putc (s, BGP_ATTR_LARGE_COMMUNITIES); - stream_putw (s, attr->extra->lcommunity->size * 12); + stream_putw (s, attr->lcommunity->size * 12); } else { stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_LARGE_COMMUNITIES); - stream_putc (s, attr->extra->lcommunity->size * 12); + stream_putc (s, attr->lcommunity->size * 12); } - stream_put (s, attr->extra->lcommunity->val, attr->extra->lcommunity->size * 12); + stream_put (s, attr->lcommunity->val, attr->lcommunity->size * 12); } /* Route Reflector. */ @@ -3346,7 +3206,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, stream_putc (s, 4); if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) - stream_put_in_addr (s, &attr->extra->originator_id); + stream_put_in_addr (s, &attr->originator_id); else stream_put_in_addr (s, &from->remote_id); @@ -3354,16 +3214,16 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); stream_putc (s, BGP_ATTR_CLUSTER_LIST); - if (attr->extra && attr->extra->cluster) + if (attr->cluster) { - stream_putc (s, attr->extra->cluster->length + 4); + stream_putc (s, attr->cluster->length + 4); /* If this peer configuration's parent BGP has cluster_id. */ if (bgp->config & BGP_CONFIG_CLUSTER_ID) stream_put_in_addr (s, &bgp->cluster_id); else stream_put_in_addr (s, &bgp->router_id); - stream_put (s, attr->extra->cluster->list, - attr->extra->cluster->length); + stream_put (s, attr->cluster->list, + attr->cluster->length); } else { @@ -3380,26 +3240,22 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY) && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES))) { - struct attr_extra *attre = attr->extra; - - assert (attre); - if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED) { - if (attre->ecommunity->size * 8 > 255) + if (attr->ecommunity->size * 8 > 255) { stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); stream_putc (s, BGP_ATTR_EXT_COMMUNITIES); - stream_putw (s, attre->ecommunity->size * 8); + stream_putw (s, attr->ecommunity->size * 8); } else { stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_EXT_COMMUNITIES); - stream_putc (s, attre->ecommunity->size * 8); + stream_putc (s, attr->ecommunity->size * 8); } - stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8); + stream_put (s, attr->ecommunity->val, attr->ecommunity->size * 8); } else { @@ -3408,9 +3264,9 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, int ecom_tr_size = 0; int i; - for (i = 0; i < attre->ecommunity->size; i++) + for (i = 0; i < attr->ecommunity->size; i++) { - pnt = attre->ecommunity->val + (i * 8); + pnt = attr->ecommunity->val + (i * 8); tbit = *pnt; if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE)) @@ -3434,9 +3290,9 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, stream_putc (s, ecom_tr_size * 8); } - for (i = 0; i < attre->ecommunity->size; i++) + for (i = 0; i < attr->ecommunity->size; i++) { - pnt = attre->ecommunity->val + (i * 8); + pnt = attr->ecommunity->val + (i * 8); tbit = *pnt; if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE)) @@ -3455,8 +3311,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, { u_int32_t label_index; - assert (attr->extra); - label_index = attr->extra->label_index; + label_index = attr->label_index; if (label_index != BGP_INVALID_LABEL_INDEX) { @@ -3500,8 +3355,6 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, if ( send_as4_aggregator ) { - assert (attr->extra); - /* send AS4_AGGREGATOR, at this place */ /* this section of code moved here in order to ensure the correct * *ascending* order of attributes @@ -3509,8 +3362,8 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_AS4_AGGREGATOR); stream_putc (s, 8); - stream_putl (s, attr->extra->aggregator_as); - stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr); + stream_putl (s, attr->aggregator_as); + stream_put_ipv4 (s, attr->aggregator_addr.s_addr); } if (((afi == AFI_IP || afi == AFI_IP6) && @@ -3527,8 +3380,8 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, } /* Unknown transit attribute. */ - if (attr->extra && attr->extra->transit) - stream_put (s, attr->extra->transit->val, attr->extra->transit->length); + if (attr->transit) + stream_put (s, attr->transit->val, attr->transit->length); /* Return total size of attribute. */ return stream_get_endp (s) - cp; @@ -3678,12 +3531,11 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr, /* Aggregator. */ if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR)) { - assert (attr->extra); stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_AGGREGATOR); stream_putc (s, 8); - stream_putl (s, attr->extra->aggregator_as); - stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr); + stream_putl (s, attr->aggregator_as); + stream_put_ipv4 (s, attr->aggregator_addr.s_addr); } /* Community attribute. */ @@ -3705,32 +3557,31 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr, } /* Large Community attribute. */ - if (attr->extra && attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES)) + if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES)) { - if (attr->extra->lcommunity->size * 12 > 255) + if (attr->lcommunity->size * 12 > 255) { stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); stream_putc (s, BGP_ATTR_LARGE_COMMUNITIES); - stream_putw (s, attr->extra->lcommunity->size * 12); + stream_putw (s, attr->lcommunity->size * 12); } else { stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_LARGE_COMMUNITIES); - stream_putc (s, attr->extra->lcommunity->size * 12); + stream_putc (s, attr->lcommunity->size * 12); } - stream_put (s, attr->extra->lcommunity->val, attr->extra->lcommunity->size * 12); + stream_put (s, attr->lcommunity->val, attr->lcommunity->size * 12); } /* Add a MP_NLRI attribute to dump the IPv6 next hop */ - if (prefix != NULL && prefix->family == AF_INET6 && attr->extra && - (attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL || - attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) ) + if (prefix != NULL && prefix->family == AF_INET6 && + (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL || + attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) ) { int sizep; - struct attr_extra *attre = attr->extra; - + stream_putc(s, BGP_ATTR_FLAG_OPTIONAL); stream_putc(s, BGP_ATTR_MP_REACH_NLRI); sizep = stream_get_endp (s); @@ -3741,10 +3592,10 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr, stream_putc(s, SAFI_UNICAST); /* SAFI */ /* Next hop */ - stream_putc(s, attre->mp_nexthop_len); - stream_put(s, &attre->mp_nexthop_global, IPV6_MAX_BYTELEN); - if (attre->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) - stream_put(s, &attre->mp_nexthop_local, IPV6_MAX_BYTELEN); + stream_putc(s, attr->mp_nexthop_len); + stream_put(s, &attr->mp_nexthop_global, IPV6_MAX_BYTELEN); + if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) + stream_put(s, &attr->mp_nexthop_local, IPV6_MAX_BYTELEN); /* SNPA */ stream_putc(s, 0); @@ -3759,9 +3610,7 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr, /* Prefix SID */ if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_PREFIX_SID)) { - assert (attr->extra); - - if (attr->extra->label_index != BGP_INVALID_LABEL_INDEX) + if (attr->label_index != BGP_INVALID_LABEL_INDEX) { stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_PREFIX_SID); @@ -3770,7 +3619,7 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr, stream_putc (s, BGP_PREFIX_SID_LABEL_INDEX_LENGTH); stream_putc (s, 0); // reserved stream_putw (s, 0); // flags - stream_putl (s, attr->extra->label_index); + stream_putl (s, attr->label_index); } } diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index c7dca435ba..99c6a6b79f 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -98,13 +98,35 @@ struct overlay_index union gw_addr gw_ip; }; -/* Additional/uncommon BGP attributes. - * lazily allocated as and when a struct attr - * requires it. - */ -struct attr_extra +/* BGP core attribute structure. */ +struct attr { - /* Multi-Protocol Nexthop, AFI IPv6 */ + /* AS Path structure */ + struct aspath *aspath; + + /* Community structure */ + struct community *community; + + /* Reference count of this attribute. */ + unsigned long refcnt; + + /* Flag of attribute is set or not. */ + uint64_t flag; + + /* Apart from in6_addr, the remaining static attributes */ + struct in_addr nexthop; + u_int32_t med; + u_int32_t local_pref; + ifindex_t nh_ifindex; + + /* Path origin attribute */ + u_char origin; + + /* has the route-map changed any attribute? + Used on the peer outbound side. */ + u_int32_t rmap_change_flags; + + /* Multi-Protocol Nexthop, AFI IPv6 */ struct in6_addr mp_nexthop_global; struct in6_addr mp_nexthop_local; @@ -165,38 +187,6 @@ struct attr_extra u_int32_t mm_seqnum; }; -/* BGP core attribute structure. */ -struct attr -{ - /* AS Path structure */ - struct aspath *aspath; - - /* Community structure */ - struct community *community; - - /* Lazily allocated pointer to extra attributes */ - struct attr_extra *extra; - - /* Reference count of this attribute. */ - unsigned long refcnt; - - /* Flag of attribute is set or not. */ - uint64_t flag; - - /* Apart from in6_addr, the remaining static attributes */ - struct in_addr nexthop; - u_int32_t med; - u_int32_t local_pref; - ifindex_t nh_ifindex; - - /* Path origin attribute */ - u_char origin; - - /* has the route-map changed any attribute? - Used on the peer outbound side. */ - u_int32_t rmap_change_flags; -}; - /* rmap_change_flags definition */ #define BATTR_RMAP_IPV4_NHOP_CHANGED (1 << 0) #define BATTR_RMAP_NEXTHOP_PEER_ADDRESS (1 << 1) @@ -226,7 +216,7 @@ struct transit #define BGP_CLUSTER_LIST_LENGTH(attr) \ (((attr)->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) ? \ - (attr)->extra->cluster->length : 0) + (attr)->cluster->length : 0) typedef enum { BGP_ATTR_PARSE_PROCEED = 0, @@ -245,8 +235,6 @@ extern void bgp_attr_finish (void); extern bgp_attr_parse_ret_t bgp_attr_parse (struct peer *, struct attr *, bgp_size_t, struct bgp_nlri *, struct bgp_nlri *); -extern struct attr_extra *bgp_attr_extra_get (struct attr *); -extern void bgp_attr_extra_free (struct attr *); extern void bgp_attr_dup (struct attr *, struct attr *); extern void bgp_attr_deep_dup (struct attr *, struct attr *); extern void bgp_attr_deep_free (struct attr *); @@ -342,7 +330,7 @@ bgp_rmap_nhop_changed(u_int32_t out_rmap_flags, u_int32_t in_rmap_flags) static inline u_int32_t mac_mobility_seqnum (struct attr *attr) { - return (attr && attr->extra) ? attr->extra->mm_seqnum : 0; + return (attr) ? attr->mm_seqnum : 0; } #endif /* _QUAGGA_BGP_ATTR_H */ diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index e66fdde5f6..aa175bcf51 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -39,17 +39,14 @@ void bgp_add_routermac_ecom(struct attr *attr, struct ethaddr *routermac) { struct ecommunity_val routermac_ecom; - if (attr->extra) - { - memset(&routermac_ecom, 0, sizeof(struct ecommunity_val)); - routermac_ecom.val[0] = ECOMMUNITY_ENCODE_EVPN; - routermac_ecom.val[1] = ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC; - memcpy(&routermac_ecom.val[2], routermac->octet, ETHER_ADDR_LEN); - if (!attr->extra->ecommunity) - attr->extra->ecommunity = ecommunity_new(); - ecommunity_add_val(attr->extra->ecommunity, &routermac_ecom); - ecommunity_str (attr->extra->ecommunity); - } + memset(&routermac_ecom, 0, sizeof(struct ecommunity_val)); + routermac_ecom.val[0] = ECOMMUNITY_ENCODE_EVPN; + routermac_ecom.val[1] = ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC; + memcpy(&routermac_ecom.val[2], routermac->octet, ETHER_ADDR_LEN); + if (!attr->ecommunity) + attr->ecommunity = ecommunity_new(); + ecommunity_add_val(attr->ecommunity, &routermac_ecom); + ecommunity_str (attr->ecommunity); } /* converts to an esi @@ -119,7 +116,7 @@ bgp_attr_mac_mobility_seqnum (struct attr *attr, u_char *sticky) int i; u_char flags = 0; - ecom = attr->extra->ecommunity; + ecom = attr->ecommunity; if (!ecom || !ecom->size) return 0; diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index a48df5c0c8..e4495c488c 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -387,6 +387,8 @@ bgp_debug_peer_updout_enabled(char *host) int bgp_dump_attr (struct attr *attr, char *buf, size_t size) { + char addrbuf[BUFSIZ]; + if (! attr) return 0; @@ -397,73 +399,68 @@ bgp_dump_attr (struct attr *attr, char *buf, size_t size) snprintf (buf + strlen (buf), size - strlen (buf), ", origin %s", bgp_origin_str[attr->origin]); - if (attr->extra) - { - char addrbuf[BUFSIZ]; + /* Add MP case. */ + if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL + || attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) + snprintf (buf + strlen (buf), size - strlen (buf), ", mp_nexthop %s", + inet_ntop (AF_INET6, &attr->mp_nexthop_global, + addrbuf, BUFSIZ)); - /* Add MP case. */ - if (attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL - || attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) - snprintf (buf + strlen (buf), size - strlen (buf), ", mp_nexthop %s", - inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global, - addrbuf, BUFSIZ)); + if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) + snprintf (buf + strlen (buf), size - strlen (buf), "(%s)", + inet_ntop (AF_INET6, &attr->mp_nexthop_local, + addrbuf, BUFSIZ)); - if (attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) - snprintf (buf + strlen (buf), size - strlen (buf), "(%s)", - inet_ntop (AF_INET6, &attr->extra->mp_nexthop_local, - addrbuf, BUFSIZ)); - - if (attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV4) - snprintf (buf, size, "nexthop %s", inet_ntoa (attr->nexthop)); - } + if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV4) + snprintf (buf, size, "nexthop %s", inet_ntoa (attr->nexthop)); if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))) snprintf (buf + strlen (buf), size - strlen (buf), ", localpref %u", attr->local_pref); - if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))) + if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))) snprintf (buf + strlen (buf), size - strlen (buf), ", metric %u", attr->med); - if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))) + if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))) snprintf (buf + strlen (buf), size - strlen (buf), ", community %s", community_str (attr->community)); if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES))) snprintf (buf + strlen (buf), size - strlen (buf), ", extcommunity %s", - ecommunity_str (attr->extra->ecommunity)); + ecommunity_str (attr->ecommunity)); if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))) snprintf (buf + strlen (buf), size - strlen (buf), ", atomic-aggregate"); if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))) snprintf (buf + strlen (buf), size - strlen (buf), ", aggregated by %u %s", - attr->extra->aggregator_as, - inet_ntoa (attr->extra->aggregator_addr)); + attr->aggregator_as, + inet_ntoa (attr->aggregator_addr)); if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID))) snprintf (buf + strlen (buf), size - strlen (buf), ", originator %s", - inet_ntoa (attr->extra->originator_id)); + inet_ntoa (attr->originator_id)); if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST))) { int i; snprintf (buf + strlen (buf), size - strlen (buf), ", clusterlist"); - for (i = 0; i < attr->extra->cluster->length / 4; i++) + for (i = 0; i < attr->cluster->length / 4; i++) snprintf (buf + strlen (buf), size - strlen (buf), " %s", - inet_ntoa (attr->extra->cluster->list[i])); + inet_ntoa (attr->cluster->list[i])); } - if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))) + if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))) snprintf (buf + strlen (buf), size - strlen (buf), ", path %s", aspath_print (attr->aspath)); if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_PREFIX_SID))) { - if (attr->extra->label_index != BGP_INVALID_LABEL_INDEX) + if (attr->label_index != BGP_INVALID_LABEL_INDEX) snprintf (buf + strlen (buf), size - strlen (buf), ", label-index %u", - attr->extra->label_index); + attr->label_index); } if (strlen (buf) > 1) diff --git a/bgpd/bgp_encap_tlv.c b/bgpd/bgp_encap_tlv.c index eee2cb72c3..89194980d1 100644 --- a/bgpd/bgp_encap_tlv.c +++ b/bgpd/bgp_encap_tlv.c @@ -238,7 +238,7 @@ subtlv_encode_remote_endpoint( if (last) {\ last->next = new;\ } else {\ - extra->encap_subtlvs = new;\ + attr->encap_subtlvs = new;\ }\ last = new;\ }\ @@ -249,13 +249,12 @@ bgp_encap_type_l2tpv3overip_to_tlv( struct bgp_encap_type_l2tpv3_over_ip *bet, /* input structure */ struct attr *attr) { - struct attr_extra *extra = bgp_attr_extra_get(attr); struct bgp_attr_encap_subtlv *last; /* advance to last subtlv */ - for (last = extra->encap_subtlvs; last && last->next; last = last->next); + for (last = attr->encap_subtlvs; last && last->next; last = last->next); - extra->encap_tunneltype = BGP_ENCAP_TYPE_L2TPV3_OVER_IP; + attr->encap_tunneltype = BGP_ENCAP_TYPE_L2TPV3_OVER_IP; assert(CHECK_FLAG(bet->valid_subtlvs, BGP_TEA_SUBTLV_ENCAP)); @@ -270,13 +269,12 @@ bgp_encap_type_gre_to_tlv( struct bgp_encap_type_gre *bet, /* input structure */ struct attr *attr) { - struct attr_extra *extra = bgp_attr_extra_get(attr); struct bgp_attr_encap_subtlv *last; /* advance to last subtlv */ - for (last = extra->encap_subtlvs; last && last->next; last = last->next); + for (last = attr->encap_subtlvs; last && last->next; last = last->next); - extra->encap_tunneltype = BGP_ENCAP_TYPE_GRE; + attr->encap_tunneltype = BGP_ENCAP_TYPE_GRE; ENC_SUBTLV(BGP_TEA_SUBTLV_ENCAP, subtlv_encode_encap_gre, st_encap); ENC_SUBTLV(BGP_TEA_SUBTLV_PROTO_TYPE, subtlv_encode_proto_type, st_proto); @@ -289,13 +287,12 @@ bgp_encap_type_ip_in_ip_to_tlv( struct bgp_encap_type_ip_in_ip *bet, /* input structure */ struct attr *attr) { - struct attr_extra *extra = bgp_attr_extra_get(attr); struct bgp_attr_encap_subtlv *last; /* advance to last subtlv */ - for (last = extra->encap_subtlvs; last && last->next; last = last->next); + for (last = attr->encap_subtlvs; last && last->next; last = last->next); - extra->encap_tunneltype = BGP_ENCAP_TYPE_IP_IN_IP; + attr->encap_tunneltype = BGP_ENCAP_TYPE_IP_IN_IP; ENC_SUBTLV(BGP_TEA_SUBTLV_PROTO_TYPE, subtlv_encode_proto_type, st_proto); ENC_SUBTLV(BGP_TEA_SUBTLV_COLOR, subtlv_encode_color, st_color); @@ -307,13 +304,12 @@ bgp_encap_type_transmit_tunnel_endpoint( struct bgp_encap_type_transmit_tunnel_endpoint *bet, /* input structure */ struct attr *attr) { - struct attr_extra *extra = bgp_attr_extra_get(attr); struct bgp_attr_encap_subtlv *last; /* advance to last subtlv */ - for (last = extra->encap_subtlvs; last && last->next; last = last->next); + for (last = attr->encap_subtlvs; last && last->next; last = last->next); - extra->encap_tunneltype = BGP_ENCAP_TYPE_TRANSMIT_TUNNEL_ENDPOINT; + attr->encap_tunneltype = BGP_ENCAP_TYPE_TRANSMIT_TUNNEL_ENDPOINT; /* no subtlvs for this type */ } @@ -323,13 +319,12 @@ bgp_encap_type_ipsec_in_tunnel_mode_to_tlv( struct bgp_encap_type_ipsec_in_tunnel_mode *bet, /* input structure */ struct attr *attr) { - struct attr_extra *extra = bgp_attr_extra_get(attr); struct bgp_attr_encap_subtlv *last; /* advance to last subtlv */ - for (last = extra->encap_subtlvs; last && last->next; last = last->next); + for (last = attr->encap_subtlvs; last && last->next; last = last->next); - extra->encap_tunneltype = BGP_ENCAP_TYPE_IPSEC_IN_TUNNEL_MODE; + attr->encap_tunneltype = BGP_ENCAP_TYPE_IPSEC_IN_TUNNEL_MODE; ENC_SUBTLV(BGP_TEA_SUBTLV_IPSEC_TA, subtlv_encode_ipsec_ta, st_ipsec_ta); } @@ -339,13 +334,12 @@ bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode_to_tlv( struct bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode *bet, /* input structure */ struct attr *attr) { - struct attr_extra *extra = bgp_attr_extra_get(attr); struct bgp_attr_encap_subtlv *last; /* advance to last subtlv */ - for (last = extra->encap_subtlvs; last && last->next; last = last->next); + for (last = attr->encap_subtlvs; last && last->next; last = last->next); - extra->encap_tunneltype = BGP_ENCAP_TYPE_IP_IN_IP_TUNNEL_WITH_IPSEC_TRANSPORT_MODE; + attr->encap_tunneltype = BGP_ENCAP_TYPE_IP_IN_IP_TUNNEL_WITH_IPSEC_TRANSPORT_MODE; ENC_SUBTLV(BGP_TEA_SUBTLV_IPSEC_TA, subtlv_encode_ipsec_ta, st_ipsec_ta); } @@ -355,13 +349,12 @@ bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode_to_tlv( struct bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode *bet, /* input structure */ struct attr *attr) { - struct attr_extra *extra = bgp_attr_extra_get(attr); struct bgp_attr_encap_subtlv *last; /* advance to last subtlv */ - for (last = extra->encap_subtlvs; last && last->next; last = last->next); + for (last = attr->encap_subtlvs; last && last->next; last = last->next); - extra->encap_tunneltype = BGP_ENCAP_TYPE_MPLS_IN_IP_TUNNEL_WITH_IPSEC_TRANSPORT_MODE; + attr->encap_tunneltype = BGP_ENCAP_TYPE_MPLS_IN_IP_TUNNEL_WITH_IPSEC_TRANSPORT_MODE; ENC_SUBTLV(BGP_TEA_SUBTLV_IPSEC_TA, subtlv_encode_ipsec_ta, st_ipsec_ta); } @@ -371,13 +364,12 @@ bgp_encap_type_pbb_to_tlv( struct bgp_encap_type_pbb *bet, /* input structure */ struct attr *attr) { - struct attr_extra *extra = bgp_attr_extra_get(attr); struct bgp_attr_encap_subtlv *last; /* advance to last subtlv */ - for (last = extra->encap_subtlvs; last && last->next; last = last->next); + for (last = attr->encap_subtlvs; last && last->next; last = last->next); - extra->encap_tunneltype = BGP_ENCAP_TYPE_PBB; + attr->encap_tunneltype = BGP_ENCAP_TYPE_PBB; assert(CHECK_FLAG(bet->valid_subtlvs, BGP_TEA_SUBTLV_ENCAP)); ENC_SUBTLV(BGP_TEA_SUBTLV_ENCAP, subtlv_encode_encap_pbb, st_encap); @@ -388,16 +380,15 @@ bgp_encap_type_vxlan_to_tlv( struct bgp_encap_type_vxlan *bet, /* input structure */ struct attr *attr) { - struct attr_extra *extra = bgp_attr_extra_get(attr); struct bgp_attr_encap_subtlv *tlv; uint32_t vnid; - extra->encap_tunneltype = BGP_ENCAP_TYPE_VXLAN; + attr->encap_tunneltype = BGP_ENCAP_TYPE_VXLAN; if(bet == NULL ||!bet->vnid) return; - if(extra->encap_subtlvs) - XFREE(MTYPE_ENCAP_TLV, extra->encap_subtlvs); + if(attr->encap_subtlvs) + XFREE(MTYPE_ENCAP_TLV, attr->encap_subtlvs); tlv = XCALLOC (MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv)-1+12); tlv->type = 1; /* encapsulation type */ tlv->length = 12; @@ -411,7 +402,7 @@ bgp_encap_type_vxlan_to_tlv( char *ptr = (char *)&tlv->value + 4; memcpy( ptr, bet->mac_address, 6); } - extra->encap_subtlvs = tlv; + attr->encap_subtlvs = tlv; return; } @@ -420,9 +411,7 @@ bgp_encap_type_nvgre_to_tlv( struct bgp_encap_type_nvgre *bet, /* input structure */ struct attr *attr) { - struct attr_extra *extra = bgp_attr_extra_get(attr); - - extra->encap_tunneltype = BGP_ENCAP_TYPE_NVGRE; + attr->encap_tunneltype = BGP_ENCAP_TYPE_NVGRE; } void @@ -438,9 +427,7 @@ bgp_encap_type_mpls_in_gre_to_tlv( struct bgp_encap_type_mpls_in_gre *bet, /* input structure */ struct attr *attr) { - struct attr_extra *extra = bgp_attr_extra_get(attr); - - extra->encap_tunneltype = BGP_ENCAP_TYPE_MPLS_IN_GRE; + attr->encap_tunneltype = BGP_ENCAP_TYPE_MPLS_IN_GRE; } void @@ -448,9 +435,8 @@ bgp_encap_type_vxlan_gpe_to_tlv( struct bgp_encap_type_vxlan_gpe *bet, /* input structure */ struct attr *attr) { - struct attr_extra *extra = bgp_attr_extra_get(attr); - extra->encap_tunneltype = BGP_ENCAP_TYPE_VXLAN_GPE; + attr->encap_tunneltype = BGP_ENCAP_TYPE_VXLAN_GPE; } void @@ -458,9 +444,8 @@ bgp_encap_type_mpls_in_udp_to_tlv( struct bgp_encap_type_mpls_in_udp *bet, /* input structure */ struct attr *attr) { - struct attr_extra *extra = bgp_attr_extra_get(attr); - extra->encap_tunneltype = BGP_ENCAP_TYPE_MPLS_IN_UDP; + attr->encap_tunneltype = BGP_ENCAP_TYPE_MPLS_IN_UDP; } diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index d012952784..46e97cc50d 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -450,7 +450,6 @@ bgp_zebra_send_remote_vtep (struct bgp *bgp, struct bgpevpn *vpn, static void build_evpn_route_extcomm (struct bgpevpn *vpn, struct attr *attr) { - struct attr_extra *attre; struct ecommunity ecom_encap; struct ecommunity ecom_sticky; struct ecommunity_val eval; @@ -460,8 +459,6 @@ build_evpn_route_extcomm (struct bgpevpn *vpn, struct attr *attr) struct ecommunity *ecom; u_int32_t seqnum; - attre = bgp_attr_extra_get (attr); - /* Encap */ tnl_type = BGP_ENCAP_TYPE_VXLAN; memset (&ecom_encap, 0, sizeof (ecom_encap)); @@ -470,20 +467,20 @@ build_evpn_route_extcomm (struct bgpevpn *vpn, struct attr *attr) ecom_encap.val = (u_int8_t *)eval.val; /* Add Encap */ - attre->ecommunity = ecommunity_dup (&ecom_encap); + attr->ecommunity = ecommunity_dup (&ecom_encap); /* Add the export RTs */ for (ALL_LIST_ELEMENTS (vpn->export_rtl, node, nnode, ecom)) - attre->ecommunity = ecommunity_merge (attre->ecommunity, ecom); + attr->ecommunity = ecommunity_merge (attr->ecommunity, ecom); - if (attre->sticky) + if (attr->sticky) { seqnum = 0; memset (&ecom_sticky, 0, sizeof (ecom_sticky)); encode_mac_mobility_extcomm(1, seqnum, &eval_sticky); ecom_sticky.size = 1; ecom_sticky.val = (u_int8_t *)eval_sticky.val; - attre->ecommunity = ecommunity_merge (attre->ecommunity, &ecom_sticky); + attr->ecommunity = ecommunity_merge (attr->ecommunity, &ecom_sticky); } attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); @@ -495,7 +492,6 @@ build_evpn_route_extcomm (struct bgpevpn *vpn, struct attr *attr) static void add_mac_mobility_to_attr (u_int32_t seq_num, struct attr *attr) { - struct attr_extra *attre; struct ecommunity ecom_tmp; struct ecommunity_val eval; struct ecommunity *ecom_mm; @@ -504,25 +500,23 @@ add_mac_mobility_to_attr (u_int32_t seq_num, struct attr *attr) int type = 0; int sub_type = 0; - attre = bgp_attr_extra_get (attr); - /* Build MM */ encode_mac_mobility_extcomm (0, seq_num, &eval); /* Find current MM ecommunity */ ecom_mm = NULL; - if (attre->ecommunity) + if (attr->ecommunity) { - for (i = 0; i < attre->ecommunity->size; i++) + for (i = 0; i < attr->ecommunity->size; i++) { - pnt = attre->ecommunity->val + (i * 8); + pnt = attr->ecommunity->val + (i * 8); type = *pnt++; sub_type = *pnt++; if (type == ECOMMUNITY_ENCODE_EVPN && sub_type == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY) { - ecom_mm = (struct ecommunity*) attre->ecommunity->val + (i * 8); + ecom_mm = (struct ecommunity*) attr->ecommunity->val + (i * 8); break; } } @@ -540,7 +534,7 @@ add_mac_mobility_to_attr (u_int32_t seq_num, struct attr *attr) ecom_tmp.size = 1; ecom_tmp.val = (u_int8_t *)eval.val; - attre->ecommunity = ecommunity_merge (attre->ecommunity, &ecom_tmp); + attr->ecommunity = ecommunity_merge (attr->ecommunity, &ecom_tmp); } } @@ -645,7 +639,7 @@ evpn_route_select_install (struct bgp *bgp, struct bgpevpn *vpn, if (bgp_zebra_has_route_changed (rn, old_select)) ret = evpn_zebra_install (bgp, vpn, (struct prefix_evpn *)&rn->p, old_select->attr->nexthop, - old_select->attr->extra->sticky); + old_select->attr->sticky); UNSET_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG); bgp_zebra_clear_route_change_flags (rn); return ret; @@ -675,7 +669,7 @@ evpn_route_select_install (struct bgp *bgp, struct bgpevpn *vpn, { ret = evpn_zebra_install (bgp, vpn, (struct prefix_evpn *) &rn->p, new_select->attr->nexthop, - new_select->attr->extra->sticky); + new_select->attr->sticky); /* If an old best existed and it was a "local" route, the only reason * it would be supplanted is due to MAC mobility procedures. So, we * need to do an implicit delete and withdraw that route from peers. @@ -727,7 +721,7 @@ evpn_route_is_sticky (struct bgp *bgp, struct bgp_node *rn) if (!local_ri) return 0; - return local_ri->attr->extra->sticky; + return local_ri->attr->sticky; } /* @@ -801,8 +795,8 @@ update_evpn_route_entry (struct bgp *bgp, struct bgpevpn *vpn, afi_t afi, attr_new = bgp_attr_intern (attr); /* Extract MAC mobility sequence number, if any. */ - attr_new->extra->mm_seqnum = bgp_attr_mac_mobility_seqnum (attr_new, &sticky); - attr_new->extra->sticky = sticky; + attr_new->mm_seqnum = bgp_attr_mac_mobility_seqnum (attr_new, &sticky); + attr_new->sticky = sticky; /* Create new route with its attribute. */ tmp_ri = info_make (ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, 0, @@ -866,9 +860,9 @@ update_evpn_route (struct bgp *bgp, struct bgpevpn *vpn, /* Build path-attribute for this route. */ bgp_attr_default_set (&attr, BGP_ORIGIN_IGP); attr.nexthop = vpn->originator_ip; - attr.extra->mp_nexthop_global_in = vpn->originator_ip; - attr.extra->mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; - attr.extra->sticky = sticky; + attr.mp_nexthop_global_in = vpn->originator_ip; + attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; + attr.sticky = sticky; /* Set up RT and ENCAP extended community. */ build_evpn_route_extcomm (vpn, &attr); @@ -910,7 +904,6 @@ update_evpn_route (struct bgp *bgp, struct bgpevpn *vpn, /* Unintern temporary. */ aspath_unintern (&attr.aspath); - bgp_attr_extra_free (&attr); return 0; } @@ -1017,12 +1010,12 @@ update_all_type2_routes (struct bgp *bgp, struct bgpevpn *vpn) bgp_attr_default_set (&attr, BGP_ORIGIN_IGP); bgp_attr_default_set (&attr_sticky, BGP_ORIGIN_IGP); attr.nexthop = vpn->originator_ip; - attr.extra->mp_nexthop_global_in = vpn->originator_ip; - attr.extra->mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; + attr.mp_nexthop_global_in = vpn->originator_ip; + attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; attr_sticky.nexthop = vpn->originator_ip; - attr_sticky.extra->mp_nexthop_global_in = vpn->originator_ip; - attr_sticky.extra->mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; - attr_sticky.extra->sticky = 1; + attr_sticky.mp_nexthop_global_in = vpn->originator_ip; + attr_sticky.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; + attr_sticky.sticky = 1; /* Set up RT, ENCAP and sticky MAC extended community. */ build_evpn_route_extcomm (vpn, &attr); @@ -1073,8 +1066,6 @@ update_all_type2_routes (struct bgp *bgp, struct bgpevpn *vpn) /* Unintern temporary. */ aspath_unintern (&attr.aspath); aspath_unintern (&attr_sticky.aspath); - bgp_attr_extra_free (&attr); - bgp_attr_extra_free (&attr_sticky); return 0; } @@ -1376,7 +1367,7 @@ is_route_matching_for_vni (struct bgp *bgp, struct bgpevpn *vpn, if (!(attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES))) return 0; - ecom = attr->extra->ecommunity; + ecom = attr->ecommunity; if (!ecom || !ecom->size) return 0; @@ -1592,7 +1583,7 @@ install_uninstall_evpn_route (struct bgp *bgp, afi_t afi, safi_t safi, if (!(attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES))) return 0; - ecom = attr->extra->ecommunity; + ecom = attr->ecommunity; if (!ecom || !ecom->size) return -1; @@ -2095,8 +2086,8 @@ evpn_mpattr_encode_type5 (struct stream *s, struct prefix *p, /* Prefix contains RD, ESI, EthTag, IP length, IP, GWIP and VNI */ stream_putc(s, 8 + 10 + 4 + 1 + len + 3); stream_put(s, prd->val, 8); - if (attr && attr->extra) - stream_put(s, &(attr->extra->evpn_overlay.eth_s_id), 10); + if (attr && attr) + stream_put(s, &(attr->evpn_overlay.eth_s_id), 10); else stream_put(s, &temp, 10); stream_putl(s, p_evpn_p->eth_tag); @@ -2105,12 +2096,12 @@ evpn_mpattr_encode_type5 (struct stream *s, struct prefix *p, stream_put_ipv4(s, p_evpn_p->ip.ipaddr_v4.s_addr); else stream_put(s, &p_evpn_p->ip.ipaddr_v6, 16); - if (attr && attr->extra) + if (attr && attr) { if (IS_IPADDR_V4(&p_evpn_p->ip)) - stream_put_ipv4(s, attr->extra->evpn_overlay.gw_ip.ipv4. s_addr); + stream_put_ipv4(s, attr->evpn_overlay.gw_ip.ipv4. s_addr); else - stream_put(s, &(attr->extra->evpn_overlay.gw_ip.ipv6), 16); + stream_put(s, &(attr->evpn_overlay.gw_ip.ipv6), 16); } else { diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c index fc0654f186..27533a5815 100644 --- a/bgpd/bgp_label.c +++ b/bgpd/bgp_label.c @@ -151,12 +151,10 @@ bgp_reg_dereg_for_label (struct bgp_node *rn, struct bgp_info *ri, assert (ri); if (ri->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_PREFIX_SID)) { - assert (ri->attr->extra); - - if (ri->attr->extra->label_index != BGP_INVALID_LABEL_INDEX) + if (ri->attr->label_index != BGP_INVALID_LABEL_INDEX) { flags |= ZEBRA_FEC_REGISTER_LABEL_INDEX; - stream_putl (s, ri->attr->extra->label_index); + stream_putl (s, ri->attr->label_index); } } SET_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL); diff --git a/bgpd/bgp_memory.c b/bgpd/bgp_memory.c index 1913706587..6da9ff8682 100644 --- a/bgpd/bgp_memory.c +++ b/bgpd/bgp_memory.c @@ -43,7 +43,6 @@ DEFINE_MTYPE(BGPD, BGP_UPDGRP, "BGP update group") DEFINE_MTYPE(BGPD, BGP_UPD_SUBGRP, "BGP update subgroup") DEFINE_MTYPE(BGPD, BGP_PACKET, "BGP packet") DEFINE_MTYPE(BGPD, ATTR, "BGP attribute") -DEFINE_MTYPE(BGPD, ATTR_EXTRA, "BGP extra attributes") DEFINE_MTYPE(BGPD, AS_PATH, "BGP aspath") DEFINE_MTYPE(BGPD, AS_SEG, "BGP aspath seg") DEFINE_MTYPE(BGPD, AS_SEG_DATA, "BGP aspath segment data") diff --git a/bgpd/bgp_memory.h b/bgpd/bgp_memory.h index 185369d230..152cfaeaf2 100644 --- a/bgpd/bgp_memory.h +++ b/bgpd/bgp_memory.h @@ -39,7 +39,6 @@ DECLARE_MTYPE(BGP_UPDGRP) DECLARE_MTYPE(BGP_UPD_SUBGRP) DECLARE_MTYPE(BGP_PACKET) DECLARE_MTYPE(ATTR) -DECLARE_MTYPE(ATTR_EXTRA) DECLARE_MTYPE(AS_PATH) DECLARE_MTYPE(AS_SEG) DECLARE_MTYPE(AS_SEG_DATA) diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index 34690ac776..7ea5c9e773 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -106,35 +106,31 @@ bgp_maximum_paths_unset (struct bgp *bgp, afi_t afi, safi_t safi, int bgp_info_nexthop_cmp (struct bgp_info *bi1, struct bgp_info *bi2) { - struct attr_extra *ae1, *ae2; int compare; - ae1 = bi1->attr->extra; - ae2 = bi2->attr->extra; - compare = IPV4_ADDR_CMP (&bi1->attr->nexthop, &bi2->attr->nexthop); - if (!compare && ae1 && ae2) + if (!compare) { - if (ae1->mp_nexthop_len == ae2->mp_nexthop_len) + if (bi1->attr->mp_nexthop_len == bi2->attr->mp_nexthop_len) { - switch (ae1->mp_nexthop_len) + switch (bi1->attr->mp_nexthop_len) { case BGP_ATTR_NHLEN_IPV4: case BGP_ATTR_NHLEN_VPNV4: - compare = IPV4_ADDR_CMP (&ae1->mp_nexthop_global_in, - &ae2->mp_nexthop_global_in); + compare = IPV4_ADDR_CMP (&bi1->attr->mp_nexthop_global_in, + &bi2->attr->mp_nexthop_global_in); break; case BGP_ATTR_NHLEN_IPV6_GLOBAL: case BGP_ATTR_NHLEN_VPNV6_GLOBAL: - compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_global, - &ae2->mp_nexthop_global); + compare = IPV6_ADDR_CMP (&bi1->attr->mp_nexthop_global, + &bi2->attr->mp_nexthop_global); break; case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL: - compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_global, - &ae2->mp_nexthop_global); + compare = IPV6_ADDR_CMP (&bi1->attr->mp_nexthop_global, + &bi2->attr->mp_nexthop_global); if (!compare) - compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_local, - &ae2->mp_nexthop_local); + compare = IPV6_ADDR_CMP (&bi1->attr->mp_nexthop_local, + &bi2->attr->mp_nexthop_local); break; } } @@ -142,14 +138,14 @@ bgp_info_nexthop_cmp (struct bgp_info *bi1, struct bgp_info *bi2) /* This can happen if one IPv6 peer sends you global and link-local * nexthops but another IPv6 peer only sends you global */ - else if (ae1->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL || - ae1->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) + else if (bi1->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL || + bi1->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { - compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_global, - &ae2->mp_nexthop_global); + compare = IPV6_ADDR_CMP (&bi1->attr->mp_nexthop_global, + &bi2->attr->mp_nexthop_global); if (!compare) { - if (ae1->mp_nexthop_len < ae2->mp_nexthop_len) + if (bi1->attr->mp_nexthop_len < bi2->attr->mp_nexthop_len) compare = -1; else compare = 1; @@ -663,7 +659,6 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best, struct community *community, *commerge; struct ecommunity *ecomm, *ecommerge; struct lcommunity *lcomm, *lcommerge; - struct attr_extra *ae; struct attr attr = { 0 }; if (old_best && (old_best != new_best) && @@ -697,9 +692,8 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best, aspath = aspath_dup (attr.aspath); origin = attr.origin; community = attr.community ? community_dup (attr.community) : NULL; - ae = attr.extra; - ecomm = (ae && ae->ecommunity) ? ecommunity_dup (ae->ecommunity) : NULL; - lcomm = (ae && ae->lcommunity) ? lcommunity_dup (ae->lcommunity) : NULL; + ecomm = (attr.ecommunity) ? ecommunity_dup (attr.ecommunity) : NULL; + lcomm = (attr.lcommunity) ? lcommunity_dup (attr.lcommunity) : NULL; for (mpinfo = bgp_info_mpath_first (new_best); mpinfo; mpinfo = bgp_info_mpath_next (mpinfo)) @@ -723,28 +717,27 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best, community = community_dup (mpinfo->attr->community); } - ae = mpinfo->attr->extra; - if (ae && ae->ecommunity) + if (mpinfo->attr->ecommunity) { if (ecomm) { - ecommerge = ecommunity_merge (ecomm, ae->ecommunity); + ecommerge = ecommunity_merge (ecomm, mpinfo->attr->ecommunity); ecomm = ecommunity_uniq_sort (ecommerge); ecommunity_free (&ecommerge); } else - ecomm = ecommunity_dup (ae->ecommunity); + ecomm = ecommunity_dup (mpinfo->attr->ecommunity); } - if (ae && ae->lcommunity) + if (mpinfo->attr->lcommunity) { if (lcomm) { - lcommerge = lcommunity_merge (lcomm, ae->lcommunity); + lcommerge = lcommunity_merge (lcomm, mpinfo->attr->lcommunity); lcomm = lcommunity_uniq_sort (lcommerge); lcommunity_free (&lcommerge); } else - lcomm = lcommunity_dup (ae->lcommunity); + lcomm = lcommunity_dup (mpinfo->attr->lcommunity); } } @@ -757,21 +750,18 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best, } if (ecomm) { - ae = bgp_attr_extra_get (&attr); - ae->ecommunity = ecomm; + attr.ecommunity = ecomm; attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); } /* Zap multipath attr nexthop so we set nexthop to self */ attr.nexthop.s_addr = 0; - if (attr.extra) - memset (&attr.extra->mp_nexthop_global, 0, sizeof (struct in6_addr)); + memset (&attr.mp_nexthop_global, 0, sizeof (struct in6_addr)); /* TODO: should we set ATOMIC_AGGREGATE and AGGREGATOR? */ } new_attr = bgp_attr_intern (&attr); - bgp_attr_extra_free (&attr); if (new_attr != bgp_info_mpath_attr (new_best)) { diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 341bb0abb5..3feb42246d 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -532,8 +532,8 @@ make_prefix (int afi, struct bgp_info *ri, struct prefix *p) break; case AFI_IP6: /* We don't register link local NH */ - if (ri->attr->extra->mp_nexthop_len != BGP_ATTR_NHLEN_IPV6_GLOBAL - || IN6_IS_ADDR_LINKLOCAL (&ri->attr->extra->mp_nexthop_global)) + if (ri->attr->mp_nexthop_len != BGP_ATTR_NHLEN_IPV6_GLOBAL + || IN6_IS_ADDR_LINKLOCAL (&ri->attr->mp_nexthop_global)) return -1; p->family = AF_INET6; @@ -545,7 +545,7 @@ make_prefix (int afi, struct bgp_info *ri, struct prefix *p) } else { - p->u.prefix6 = ri->attr->extra->mp_nexthop_global; + p->u.prefix6 = ri->attr->mp_nexthop_global; p->prefixlen = IPV6_MAX_BITLEN; } break; diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 0c31d6e9f3..2b48b34e13 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1364,7 +1364,6 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) u_char *end; struct stream *s; struct attr attr; - struct attr_extra extra; bgp_size_t attribute_len; bgp_size_t update_len; bgp_size_t withdraw_len; @@ -1389,11 +1388,9 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) /* Set initial values. */ memset (&attr, 0, sizeof (struct attr)); - memset (&extra, 0, sizeof (struct attr_extra)); - extra.label_index = BGP_INVALID_LABEL_INDEX; - extra.label = MPLS_INVALID_LABEL; + attr.label_index = BGP_INVALID_LABEL_INDEX; + attr.label = MPLS_INVALID_LABEL; memset (&nlris, 0, sizeof (nlris)); - attr.extra = &extra; memset (peer->rcvd_attr_str, 0, BUFSIZ); peer->rcvd_attr_printed = 0; diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index cd21c25c77..fabea1f113 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -330,7 +330,7 @@ bgp_pcount_adjust (struct bgp_node *rn, struct bgp_info *ri) static int bgp_label_index_differs (struct bgp_info *ri1, struct bgp_info *ri2) { - return (!(ri1->attr->extra->label_index == ri2->attr->extra->label_index)); + return (!(ri1->attr->label_index == ri2->attr->label_index)); } /* Set/unset bgp_info flags, adjusting any other state as needed. @@ -392,7 +392,6 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, char *pfx_buf, afi_t afi, safi_t safi) { struct attr *newattr, *existattr; - struct attr_extra *newattre, *existattre; bgp_peer_sort_t new_sort; bgp_peer_sort_t exist_sort; u_int32_t new_pref; @@ -443,8 +442,6 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, newattr = new->attr; existattr = exist->attr; - newattre = newattr->extra; - existattre = existattr->extra; /* For EVPN routes, we cannot just go by local vs remote, we have to * look at the MAC mobility sequence number, if present. @@ -457,7 +454,7 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, * consistency in this scenario we are going to prefer the path with the * sticky flag. */ - if (newattre->sticky != existattre->sticky) + if (newattr->sticky != existattr->sticky) { if (!debug) { @@ -466,14 +463,14 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, bgp_info_path_with_addpath_rx_str (exist, exist_buf); } - if (newattre->sticky && !existattre->sticky) + if (newattr->sticky && !existattr->sticky) { zlog_warn("%s: %s wins over %s due to sticky MAC flag", pfx_buf, new_buf, exist_buf); return 1; } - if (!newattre->sticky && existattre->sticky) + if (!newattr->sticky && existattr->sticky) { zlog_warn("%s: %s loses to %s due to sticky MAC flag", pfx_buf, new_buf, exist_buf); @@ -504,10 +501,8 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, /* 1. Weight check. */ new_weight = exist_weight = 0; - if (newattre) - new_weight = newattre->weight; - if (existattre) - exist_weight = existattre->weight; + new_weight = newattr->weight; + exist_weight = existattr->weight; if (new_weight > exist_weight) { @@ -877,11 +872,11 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, * used for the comparision, it will decide which path is better. */ if (newattr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) - new_id.s_addr = newattre->originator_id.s_addr; + new_id.s_addr = newattr->originator_id.s_addr; else new_id.s_addr = new->peer->remote_id.s_addr; if (existattr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) - exist_id.s_addr = existattre->originator_id.s_addr; + exist_id.s_addr = existattr->originator_id.s_addr; else exist_id.s_addr = exist->peer->remote_id.s_addr; @@ -1105,14 +1100,14 @@ bgp_cluster_filter (struct peer *peer, struct attr *attr) { struct in_addr cluster_id; - if (attr->extra && attr->extra->cluster) + if (attr->cluster) { if (peer->bgp->config & BGP_CONFIG_CLUSTER_ID) cluster_id = peer->bgp->cluster_id; else cluster_id = peer->bgp->router_id; - if (cluster_loop_check (attr->extra->cluster, cluster_id)) + if (cluster_loop_check (attr->cluster, cluster_id)) return 1; } return 0; @@ -1131,7 +1126,7 @@ bgp_input_modifier (struct peer *peer, struct prefix *p, struct attr *attr, /* Apply default weight value. */ if (peer->weight[afi][safi]) - (bgp_attr_extra_get (attr))->weight = peer->weight[afi][safi]; + attr->weight = peer->weight[afi][safi]; if (rmap_name) { @@ -1188,7 +1183,7 @@ bgp_output_modifier (struct peer *peer, struct prefix *p, struct attr *attr, /* Apply default weight value. */ if (peer->weight[afi][safi]) - (bgp_attr_extra_get (attr))->weight = peer->weight[afi][safi]; + attr->weight = peer->weight[afi][safi]; if (rmap_name) { @@ -1287,7 +1282,7 @@ subgroup_announce_reset_nhop (u_char family, struct attr *attr) if (family == AF_INET) attr->nexthop.s_addr = 0; if (family == AF_INET6) - memset (&attr->extra->mp_nexthop_global, 0, IPV6_MAX_BYTELEN); + memset (&attr->mp_nexthop_global, 0, IPV6_MAX_BYTELEN); } int @@ -1416,7 +1411,7 @@ subgroup_announce_check (struct bgp_node *rn, struct bgp_info *ri, peer's id. */ if (onlypeer && riattr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID) && - (IPV4_ADDR_SAME (&onlypeer->remote_id, &riattr->extra->originator_id))) + (IPV4_ADDR_SAME (&onlypeer->remote_id, &riattr->originator_id))) { if (bgp_debug_update(NULL, p, subgrp->update_group, 0)) zlog_debug ("%s [Update:SEND] %s originator-id is same as " @@ -1523,8 +1518,7 @@ subgroup_announce_check (struct bgp_node *rn, struct bgp_info *ri, set the originator id */ if (reflect && (!(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)))) { - attr->extra = bgp_attr_extra_get(attr); - IPV4_ADDR_COPY(&(attr->extra->originator_id), &(from->remote_id)); + IPV4_ADDR_COPY(&(attr->originator_id), &(from->remote_id)); SET_FLAG(attr->flag, BGP_ATTR_ORIGINATOR_ID); } @@ -1555,7 +1549,7 @@ subgroup_announce_check (struct bgp_node *rn, struct bgp_info *ri, (safi != SAFI_ENCAP && safi != SAFI_MPLS_VPN &&\ (p->family == AF_INET6 || peer_cap_enhe(peer, afi, safi))) || \ ((safi == SAFI_ENCAP || safi == SAFI_MPLS_VPN) &&\ - attr->extra->mp_nexthop_len >= IPV6_MAX_BYTELEN)) + attr->mp_nexthop_len >= IPV6_MAX_BYTELEN)) /* IPv6/MP starts with 1 nexthop. The link-local address is passed only if * the peer (group) is configured to receive link-local nexthop unchanged @@ -1565,14 +1559,14 @@ subgroup_announce_check (struct bgp_node *rn, struct bgp_info *ri, */ if (NEXTHOP_IS_V6) { - attr->extra->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL; + attr->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL; if ((CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED) && - IN6_IS_ADDR_LINKLOCAL (&attr->extra->mp_nexthop_local)) || + IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_local)) || (!reflect && peer->shared_network && (from == bgp->peer_self || peer->sort == BGP_PEER_EBGP))) { - attr->extra->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL; + attr->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL; } /* Clear off link-local nexthop in source, whenever it is not needed to @@ -1580,7 +1574,7 @@ subgroup_announce_check (struct bgp_node *rn, struct bgp_info *ri, */ if (!(CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED))) - memset (&attr->extra->mp_nexthop_local, 0, IPV6_MAX_BYTELEN); + memset (&attr->mp_nexthop_local, 0, IPV6_MAX_BYTELEN); } bgp_peer_remove_private_as(bgp, afi, safi, peer, attr); @@ -1592,9 +1586,6 @@ subgroup_announce_check (struct bgp_node *rn, struct bgp_info *ri, { struct bgp_info info; struct attr dummy_attr; - struct attr_extra dummy_extra; - - dummy_attr.extra = &dummy_extra; info.peer = peer; info.attr = attr; @@ -1679,7 +1670,7 @@ subgroup_announce_check (struct bgp_node *rn, struct bgp_info *ri, */ if (p->family == AF_INET6 || peer_cap_enhe(peer, afi, safi)) { - if (IN6_IS_ADDR_LINKLOCAL (&attr->extra->mp_nexthop_global)) + if (IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_global)) subgroup_announce_reset_nhop (AF_INET6, attr); } } @@ -1899,7 +1890,6 @@ subgroup_process_announce_selected (struct update_subgroup *subgrp, struct prefix *p; struct peer *onlypeer; struct attr attr; - struct attr_extra extra; afi_t afi; safi_t safi; @@ -1914,9 +1904,8 @@ subgroup_process_announce_selected (struct update_subgroup *subgrp, PEER_STATUS_ORF_WAIT_REFRESH)) return 0; - memset(&extra, 0, sizeof(struct attr_extra)); + memset(&attr, 0, sizeof(struct attr)); /* It's initialized in bgp_announce_check() */ - attr.extra = &extra; /* Announcement to the subgroup. If the route is filtered withdraw it. */ if (selected) @@ -2047,7 +2036,7 @@ bgp_process_main (struct work_queue *wq, void *data) { if (new_select->sub_type == BGP_ROUTE_STATIC && new_select->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_PREFIX_SID) && - new_select->attr->extra->label_index != BGP_INVALID_LABEL_INDEX) + new_select->attr->label_index != BGP_INVALID_LABEL_INDEX) { if (CHECK_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL)) bgp_unregister_for_label (rn); @@ -2459,27 +2448,24 @@ info_make (int type, int sub_type, u_short instance, struct peer *peer, static void overlay_index_update(struct attr *attr, struct eth_segment_id *eth_s_id, union gw_addr *gw_ip) { - struct attr_extra *extra; - if(!attr) return; - extra = bgp_attr_extra_get(attr); if(eth_s_id == NULL) { - memset(&(extra->evpn_overlay.eth_s_id),0, sizeof(struct eth_segment_id)); + memset(&(attr->evpn_overlay.eth_s_id),0, sizeof(struct eth_segment_id)); } else { - memcpy(&(extra->evpn_overlay.eth_s_id), eth_s_id, sizeof(struct eth_segment_id)); + memcpy(&(attr->evpn_overlay.eth_s_id), eth_s_id, sizeof(struct eth_segment_id)); } if(gw_ip == NULL) { - memset(&(extra->evpn_overlay.gw_ip), 0, sizeof(union gw_addr)); + memset(&(attr->evpn_overlay.gw_ip), 0, sizeof(union gw_addr)); } else { - memcpy(&(extra->evpn_overlay.gw_ip),gw_ip, sizeof(union gw_addr)); + memcpy(&(attr->evpn_overlay.gw_ip),gw_ip, sizeof(union gw_addr)); } } @@ -2492,7 +2478,7 @@ overlay_index_equal(afi_t afi, struct bgp_info *info, struct eth_segment_id *eth if(afi != AFI_L2VPN) return true; - if (!info->attr || !info->attr->extra) + if (!info->attr) { memset(&temp, 0, 16); info_eth_s_id = (struct eth_segment_id *)&temp; @@ -2502,8 +2488,8 @@ overlay_index_equal(afi_t afi, struct bgp_info *info, struct eth_segment_id *eth } else { - info_eth_s_id = &(info->attr->extra->evpn_overlay.eth_s_id); - info_gw_ip = &(info->attr->extra->evpn_overlay.gw_ip); + info_eth_s_id = &(info->attr->evpn_overlay.eth_s_id); + info_gw_ip = &(info->attr->evpn_overlay.gw_ip); } if(gw_ip == NULL) info_gw_ip_remote = (union gw_addr *)&temp; @@ -2522,7 +2508,6 @@ overlay_index_equal(afi_t afi, struct bgp_info *info, struct eth_segment_id *eth static int bgp_update_martian_nexthop (struct bgp *bgp, afi_t afi, safi_t safi, struct attr *attr) { - struct attr_extra *attre = attr->extra; int ret = 0; /* Only validated for unicast and multicast currently. */ @@ -2544,23 +2529,23 @@ bgp_update_martian_nexthop (struct bgp *bgp, afi_t afi, safi_t safi, struct attr * there is code in bgp_attr.c to ignore the link-local (2nd) nexthop if * it is not an IPv6 link-local address. */ - if (attre && attre->mp_nexthop_len) + if (attr->mp_nexthop_len) { - switch (attre->mp_nexthop_len) + switch (attr->mp_nexthop_len) { case BGP_ATTR_NHLEN_IPV4: case BGP_ATTR_NHLEN_VPNV4: - ret = (attre->mp_nexthop_global_in.s_addr == 0 || - IPV4_CLASS_DE (ntohl (attre->mp_nexthop_global_in.s_addr)) || - bgp_nexthop_self (bgp, attre->mp_nexthop_global_in)); + ret = (attr->mp_nexthop_global_in.s_addr == 0 || + IPV4_CLASS_DE (ntohl (attr->mp_nexthop_global_in.s_addr)) || + bgp_nexthop_self (bgp, attr->mp_nexthop_global_in)); break; case BGP_ATTR_NHLEN_IPV6_GLOBAL: case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL: case BGP_ATTR_NHLEN_VPNV6_GLOBAL: - ret = (IN6_IS_ADDR_UNSPECIFIED(&attre->mp_nexthop_global) || - IN6_IS_ADDR_LOOPBACK(&attre->mp_nexthop_global) || - IN6_IS_ADDR_MULTICAST(&attre->mp_nexthop_global)); + ret = (IN6_IS_ADDR_UNSPECIFIED(&attr->mp_nexthop_global) || + IN6_IS_ADDR_LOOPBACK(&attr->mp_nexthop_global) || + IN6_IS_ADDR_MULTICAST(&attr->mp_nexthop_global)); break; default: @@ -2583,7 +2568,6 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, struct bgp_node *rn; struct bgp *bgp; struct attr new_attr; - struct attr_extra new_extra; struct attr *attr_new; struct bgp_info *ri; struct bgp_info *new; @@ -2599,9 +2583,8 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, int same_attr=0; memset (&new_attr, 0, sizeof(struct attr)); - memset (&new_extra, 0, sizeof(struct attr_extra)); - new_extra.label_index = BGP_INVALID_LABEL_INDEX; - new_extra.label = MPLS_INVALID_LABEL; + new_attr.label_index = BGP_INVALID_LABEL_INDEX; + new_attr.label = MPLS_INVALID_LABEL; bgp = peer->bgp; rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd); @@ -2656,7 +2639,7 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, /* Route reflector originator ID check. */ if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID) - && IPV4_ADDR_SAME (&bgp->router_id, &attr->extra->originator_id)) + && IPV4_ADDR_SAME (&bgp->router_id, &attr->originator_id)) { reason = "originator is us;"; goto filtered; @@ -2676,7 +2659,6 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, goto filtered; } - new_attr.extra = &new_extra; bgp_attr_dup (&new_attr, attr); /* Apply incoming route-map. @@ -2850,14 +2832,14 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, { int cmp; - cmp = ecommunity_cmp (ri->attr->extra->ecommunity, - attr_new->extra->ecommunity); + cmp = ecommunity_cmp (ri->attr->ecommunity, + attr_new->ecommunity); if (!cmp) { if (bgp_debug_update(peer, p, NULL, 1)) zlog_debug ("Change in EXT-COMM, existing %s new %s", - ecommunity_str (ri->attr->extra->ecommunity), - ecommunity_str (attr_new->extra->ecommunity)); + ecommunity_str (ri->attr->ecommunity), + ecommunity_str (attr_new->ecommunity)); bgp_evpn_unimport_route (bgp, afi, safi, p, ri); } } @@ -4000,7 +3982,7 @@ bgp_static_update (struct bgp *bgp, struct prefix *p, /* Store label index, if required. */ if (bgp_static->label_index != BGP_INVALID_LABEL_INDEX) { - (bgp_attr_extra_get (&attr))->label_index = bgp_static->label_index; + attr.label_index = bgp_static->label_index; attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_PREFIX_SID); } @@ -4024,7 +4006,6 @@ bgp_static_update (struct bgp *bgp, struct prefix *p, /* Unintern original. */ aspath_unintern (&attr.aspath); - bgp_attr_extra_free (&attr); bgp_static_withdraw (bgp, p, afi, safi); return; } @@ -4047,7 +4028,6 @@ bgp_static_update (struct bgp *bgp, struct prefix *p, bgp_unlock_node (rn); bgp_attr_unintern (&attr_new); aspath_unintern (&attr.aspath); - bgp_attr_extra_free (&attr); return; } else @@ -4122,7 +4102,6 @@ bgp_static_update (struct bgp *bgp, struct prefix *p, bgp_process (bgp, rn, afi, safi); bgp_unlock_node (rn); aspath_unintern (&attr.aspath); - bgp_attr_extra_free (&attr); return; } } @@ -4174,7 +4153,6 @@ bgp_static_update (struct bgp *bgp, struct prefix *p, /* Unintern original. */ aspath_unintern (&attr.aspath); - bgp_attr_extra_free (&attr); } void @@ -4277,8 +4255,8 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p, { if (afi == AFI_IP) { - bgp_attr_extra_get (&attr)->mp_nexthop_global_in = bgp_static->igpnexthop; - bgp_attr_extra_get (&attr)->mp_nexthop_len = IPV4_MAX_BYTELEN; + attr.mp_nexthop_global_in = bgp_static->igpnexthop; + attr.mp_nexthop_len = IPV4_MAX_BYTELEN; } } if(afi == AFI_L2VPN) @@ -4323,7 +4301,6 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p, /* Unintern original. */ aspath_unintern (&attr.aspath); - bgp_attr_extra_free (&attr); bgp_static_withdraw_safi (bgp, p, afi, safi, &bgp_static->prd); return; } @@ -4351,7 +4328,6 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p, bgp_unlock_node (rn); bgp_attr_unintern (&attr_new); aspath_unintern (&attr.aspath); - bgp_attr_extra_free (&attr); return; } else @@ -4382,7 +4358,6 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p, #endif bgp_unlock_node (rn); aspath_unintern (&attr.aspath); - bgp_attr_extra_free (&attr); return; } } @@ -4417,7 +4392,6 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p, /* Unintern original. */ aspath_unintern (&attr.aspath); - bgp_attr_extra_free (&attr); } /* Configure static BGP network. When user don't run zebra, static @@ -6156,14 +6130,13 @@ bgp_redistribute_add (struct bgp *bgp, struct prefix *p, const struct in_addr *n if (nexthop6) { - struct attr_extra *extra = bgp_attr_extra_get(&attr); - extra->mp_nexthop_global = *nexthop6; - extra->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL; + attr.mp_nexthop_global = *nexthop6; + attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL; } attr.med = metric; attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); - attr.extra->tag = tag; + attr.tag = tag; afi = family2afi (p->family); @@ -6171,10 +6144,8 @@ bgp_redistribute_add (struct bgp *bgp, struct prefix *p, const struct in_addr *n if (red) { struct attr attr_new; - struct attr_extra extra_new; /* Copy attribute for modification. */ - attr_new.extra = &extra_new; bgp_attr_dup (&attr_new, &attr); if (red->redist_metric_flag) @@ -6199,7 +6170,6 @@ bgp_redistribute_add (struct bgp *bgp, struct prefix *p, const struct in_addr *n /* Unintern original. */ aspath_unintern (&attr.aspath); - bgp_attr_extra_free (&attr); bgp_redistribute_delete (bgp, p, type, instance); return; } @@ -6224,7 +6194,6 @@ bgp_redistribute_add (struct bgp *bgp, struct prefix *p, const struct in_addr *n { bgp_attr_unintern (&new_attr); aspath_unintern (&attr.aspath); - bgp_attr_extra_free (&attr); bgp_unlock_node (bn); return; } @@ -6247,7 +6216,6 @@ bgp_redistribute_add (struct bgp *bgp, struct prefix *p, const struct in_addr *n bgp_process (bgp, bn, afi, SAFI_UNICAST); bgp_unlock_node (bn); aspath_unintern (&attr.aspath); - bgp_attr_extra_free (&attr); return; } } @@ -6264,7 +6232,6 @@ bgp_redistribute_add (struct bgp *bgp, struct prefix *p, const struct in_addr *n /* Unintern original. */ aspath_unintern (&attr.aspath); - bgp_attr_extra_free (&attr); } void @@ -6479,7 +6446,7 @@ route_vty_out (struct vty *vty, struct prefix *p, /* Print attribute */ attr = binfo->attr; - if (attr) + if (attr) { /* * For ENCAP and EVPN routes, nexthop address family is not @@ -6487,32 +6454,25 @@ route_vty_out (struct vty *vty, struct prefix *p, * Both SAFI_MPLS_VPN and SAFI_ENCAP use the MP nexthop field * EVPN routes are also exchanged with a MP nexthop. Currently, this * is only IPv4, the value will be present in either attr->nexthop or - * attr->extra->mp_nexthop_global_in + * attr->mp_nexthop_global_in */ if ((safi == SAFI_ENCAP) || (safi == SAFI_MPLS_VPN)) { - if (attr->extra) - { - char buf[BUFSIZ]; - int af = NEXTHOP_FAMILY(attr->extra->mp_nexthop_len); + char buf[BUFSIZ]; + int af = NEXTHOP_FAMILY(attr->mp_nexthop_len); - switch (af) - { - case AF_INET: - vty_out (vty, "%s", inet_ntop(af, - &attr->extra->mp_nexthop_global_in, buf, BUFSIZ)); - break; - case AF_INET6: - vty_out (vty, "%s", inet_ntop(af, - &attr->extra->mp_nexthop_global, buf, BUFSIZ)); - break; - default: - vty_out(vty, "?"); - break; - } + switch (af) + { + case AF_INET: + vty_out (vty, "%s", inet_ntop(af, &attr->mp_nexthop_global_in, buf, BUFSIZ)); + break; + case AF_INET6: + vty_out (vty, "%s", inet_ntop(af, &attr->mp_nexthop_global, buf, BUFSIZ)); + break; + default: + vty_out(vty, "?"); + break; } - else - vty_out(vty, "?"); } else if (safi == SAFI_EVPN) { @@ -6535,7 +6495,7 @@ route_vty_out (struct vty *vty, struct prefix *p, json_nexthop_global = json_object_new_object(); if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN)) - json_object_string_add(json_nexthop_global, "ip", inet_ntoa (attr->extra->mp_nexthop_global_in)); + json_object_string_add(json_nexthop_global, "ip", inet_ntoa (attr->mp_nexthop_global_in)); else json_object_string_add(json_nexthop_global, "ip", inet_ntoa (attr->nexthop)); @@ -6546,7 +6506,7 @@ route_vty_out (struct vty *vty, struct prefix *p, { if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN)) vty_out (vty, "%-16s", - inet_ntoa (attr->extra->mp_nexthop_global_in)); + inet_ntoa (attr->mp_nexthop_global_in)); else vty_out (vty, "%-16s", inet_ntoa (attr->nexthop)); } @@ -6563,25 +6523,25 @@ route_vty_out (struct vty *vty, struct prefix *p, json_nexthop_global = json_object_new_object(); json_object_string_add(json_nexthop_global, "ip", inet_ntop (AF_INET6, - &attr->extra->mp_nexthop_global, + &attr->mp_nexthop_global, buf, BUFSIZ)); json_object_string_add(json_nexthop_global, "afi", "ipv6"); json_object_string_add(json_nexthop_global, "scope", "global"); /* We display both LL & GL if both have been received */ - if ((attr->extra->mp_nexthop_len == 32) || (binfo->peer->conf_if)) + if ((attr->mp_nexthop_len == 32) || (binfo->peer->conf_if)) { json_nexthop_ll = json_object_new_object(); json_object_string_add(json_nexthop_ll, "ip", inet_ntop (AF_INET6, - &attr->extra->mp_nexthop_local, + &attr->mp_nexthop_local, buf, BUFSIZ)); json_object_string_add(json_nexthop_ll, "afi", "ipv6"); json_object_string_add(json_nexthop_ll, "scope", "link-local"); - if ((IPV6_ADDR_CMP (&attr->extra->mp_nexthop_global, - &attr->extra->mp_nexthop_local) != 0) && - !attr->extra->mp_nexthop_prefer_global) + if ((IPV6_ADDR_CMP (&attr->mp_nexthop_global, + &attr->mp_nexthop_local) != 0) && + !attr->mp_nexthop_prefer_global) json_object_boolean_true_add(json_nexthop_ll, "used"); else json_object_boolean_true_add(json_nexthop_global, "used"); @@ -6592,8 +6552,8 @@ route_vty_out (struct vty *vty, struct prefix *p, else { /* Display LL if LL/Global both in table unless prefer-global is set */ - if (((attr->extra->mp_nexthop_len == 32) && - !attr->extra->mp_nexthop_prefer_global) || + if (((attr->mp_nexthop_len == 32) && + !attr->mp_nexthop_prefer_global) || (binfo->peer->conf_if)) { if (binfo->peer->conf_if) @@ -6611,7 +6571,7 @@ route_vty_out (struct vty *vty, struct prefix *p, { len = vty_out (vty, "%s", inet_ntop (AF_INET6, - &attr->extra->mp_nexthop_local, + &attr->mp_nexthop_local, buf, BUFSIZ)); len = 16 - len; @@ -6625,7 +6585,7 @@ route_vty_out (struct vty *vty, struct prefix *p, { len = vty_out (vty, "%s", inet_ntop (AF_INET6, - &attr->extra->mp_nexthop_global, + &attr->mp_nexthop_global, buf, BUFSIZ)); len = 16 - len; @@ -6658,14 +6618,9 @@ route_vty_out (struct vty *vty, struct prefix *p, vty_out (vty, " "); if (json_paths) - { - if (attr->extra) - json_object_int_add(json_path, "weight", attr->extra->weight); - else - json_object_int_add(json_path, "weight", 0); - } + json_object_int_add(json_path, "weight", attr->weight); else - vty_out (vty, "%7u ", (attr->extra ? attr->extra->weight : 0)); + vty_out (vty, "%7u ", attr->weight); if (json_paths) { char buf[BUFSIZ]; @@ -6762,7 +6717,7 @@ route_vty_out_tmp (struct vty *vty, struct prefix *p, struct attr *attr, safi_t !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) { if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN) - json_object_string_add(json_net, "nextHop", inet_ntoa (attr->extra->mp_nexthop_global_in)); + json_object_string_add(json_net, "nextHop", inet_ntoa (attr->mp_nexthop_global_in)); else json_object_string_add(json_net, "nextHop", inet_ntoa (attr->nexthop)); } @@ -6770,7 +6725,7 @@ route_vty_out_tmp (struct vty *vty, struct prefix *p, struct attr *attr, safi_t { char buf[BUFSIZ]; - json_object_string_add(json_net, "netHopGloabal", inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global, + json_object_string_add(json_net, "netHopGloabal", inet_ntop (AF_INET6, &attr->mp_nexthop_global, buf, BUFSIZ)); } @@ -6780,10 +6735,7 @@ route_vty_out_tmp (struct vty *vty, struct prefix *p, struct attr *attr, safi_t if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)) json_object_int_add(json_net, "localPref", attr->local_pref); - if (attr->extra) - json_object_int_add(json_net, "weight", attr->extra->weight); - else - json_object_int_add(json_net, "weight", 0); + json_object_int_add(json_net, "weight", attr->weight); /* Print aspath */ if (attr->aspath) @@ -6802,7 +6754,7 @@ route_vty_out_tmp (struct vty *vty, struct prefix *p, struct attr *attr, safi_t { if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN) vty_out (vty, "%-16s", - inet_ntoa (attr->extra->mp_nexthop_global_in)); + inet_ntoa (attr->mp_nexthop_global_in)); else vty_out (vty, "%-16s", inet_ntoa (attr->nexthop)); } @@ -6811,10 +6763,8 @@ route_vty_out_tmp (struct vty *vty, struct prefix *p, struct attr *attr, safi_t int len; char buf[BUFSIZ]; - assert (attr->extra); - len = vty_out (vty, "%s", - inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global, + inet_ntop (AF_INET6, &attr->mp_nexthop_global, buf, BUFSIZ)); len = 16 - len; if (len < 1) @@ -6832,7 +6782,7 @@ route_vty_out_tmp (struct vty *vty, struct prefix *p, struct attr *attr, safi_t else vty_out (vty, " "); - vty_out (vty, "%7u ", (attr->extra ? attr->extra->weight : 0)); + vty_out (vty, "%7u ", attr->weight); /* Print aspath */ if (attr->aspath) @@ -6891,9 +6841,9 @@ route_vty_out_tag (struct vty *vty, struct prefix *p, if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN) { if (json) - json_object_string_add(json_out, "mpNexthopGlobalIn", inet_ntoa (attr->extra->mp_nexthop_global_in)); + json_object_string_add(json_out, "mpNexthopGlobalIn", inet_ntoa (attr->mp_nexthop_global_in)); else - vty_out (vty, "%-16s", inet_ntoa (attr->extra->mp_nexthop_global_in)); + vty_out (vty, "%-16s", inet_ntoa (attr->mp_nexthop_global_in)); } else { @@ -6907,36 +6857,35 @@ route_vty_out_tag (struct vty *vty, struct prefix *p, || (safi == SAFI_EVPN && p->family == AF_ETHERNET && BGP_ATTR_NEXTHOP_AFI_IP6(attr)) || (BGP_ATTR_NEXTHOP_AFI_IP6(attr))) { - assert (attr->extra); char buf_a[BUFSIZ]; char buf_b[BUFSIZ]; char buf_c[BUFSIZ]; - if (attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL) + if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL) { if (json) json_object_string_add(json_out, "mpNexthopGlobalIn", - inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global, buf_a, BUFSIZ)); + inet_ntop (AF_INET6, &attr->mp_nexthop_global, buf_a, BUFSIZ)); else vty_out (vty, "%s", - inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global, + inet_ntop (AF_INET6, &attr->mp_nexthop_global, buf_a, BUFSIZ)); } - else if (attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) + else if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { if (json) { - inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global, + inet_ntop (AF_INET6, &attr->mp_nexthop_global, buf_a, BUFSIZ); - inet_ntop (AF_INET6, &attr->extra->mp_nexthop_local, + inet_ntop (AF_INET6, &attr->mp_nexthop_local, buf_b, BUFSIZ); sprintf(buf_c, "%s(%s)", buf_a, buf_b); json_object_string_add(json_out, "mpNexthopGlobalLocal", buf_c); } else vty_out (vty, "%s(%s)", - inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global, + inet_ntop (AF_INET6, &attr->mp_nexthop_global, buf_a, BUFSIZ), - inet_ntop (AF_INET6, &attr->extra->mp_nexthop_local, + inet_ntop (AF_INET6, &attr->mp_nexthop_local, buf_b, BUFSIZ)); } @@ -6987,60 +6936,52 @@ route_vty_out_overlay (struct vty *vty, struct prefix *p, attr = binfo->attr; if (attr) { - if (attr->extra) - { - char buf1[BUFSIZ]; - int af = NEXTHOP_FAMILY(attr->extra->mp_nexthop_len); + char buf1[BUFSIZ]; + int af = NEXTHOP_FAMILY(attr->mp_nexthop_len); - switch (af) { - case AF_INET: - vty_out (vty, "%-16s", inet_ntop(af, - &attr->extra->mp_nexthop_global_in, buf, BUFSIZ)); - break; - case AF_INET6: - vty_out (vty, "%s(%s)", - inet_ntop (af, - &attr->extra->mp_nexthop_global, buf, BUFSIZ), - inet_ntop (af, - &attr->extra->mp_nexthop_local, buf1, BUFSIZ)); - break; - default: - vty_out(vty, "?"); - } - } else { + switch (af) { + case AF_INET: + vty_out (vty, "%-16s", inet_ntop(af, + &attr->mp_nexthop_global_in, buf, BUFSIZ)); + break; + case AF_INET6: + vty_out (vty, "%s(%s)", + inet_ntop (af, + &attr->mp_nexthop_global, buf, BUFSIZ), + inet_ntop (af, + &attr->mp_nexthop_local, buf1, BUFSIZ)); + break; + default: vty_out(vty, "?"); } } - if(attr->extra) + struct eth_segment_id *id = &(attr->evpn_overlay.eth_s_id); + char *str = esi2str(id); + vty_out (vty, "%s", str); + XFREE (MTYPE_TMP, str); + if (IS_EVPN_PREFIX_IPADDR_V4((struct prefix_evpn *)p)) { - struct eth_segment_id *id = &(attr->extra->evpn_overlay.eth_s_id); - char *str = esi2str(id); - vty_out (vty, "%s", str); - XFREE (MTYPE_TMP, str); - if (IS_EVPN_PREFIX_IPADDR_V4((struct prefix_evpn *)p)) - { - vty_out (vty, "/%s", inet_ntoa (attr->extra->evpn_overlay.gw_ip.ipv4)); - } - else if (IS_EVPN_PREFIX_IPADDR_V6((struct prefix_evpn *)p)) - { - vty_out (vty, "/%s", - inet_ntop (AF_INET6, &(attr->extra->evpn_overlay.gw_ip.ipv6), - buf, BUFSIZ)); - } - if(attr->extra->ecommunity) + vty_out (vty, "/%s", inet_ntoa (attr->evpn_overlay.gw_ip.ipv4)); + } + else if (IS_EVPN_PREFIX_IPADDR_V6((struct prefix_evpn *)p)) + { + vty_out (vty, "/%s", + inet_ntop (AF_INET6, &(attr->evpn_overlay.gw_ip.ipv6), + buf, BUFSIZ)); + } + if(attr->ecommunity) + { + char *mac = NULL; + struct ecommunity_val *routermac = ecommunity_lookup (attr->ecommunity, + ECOMMUNITY_ENCODE_EVPN, + ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC); + if(routermac) + mac = ecom_mac2str((char *)routermac->val); + if(mac) { - char *mac = NULL; - struct ecommunity_val *routermac = ecommunity_lookup (attr->extra->ecommunity, - ECOMMUNITY_ENCODE_EVPN, - ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC); - if(routermac) - mac = ecom_mac2str((char *)routermac->val); - if(mac) - { - vty_out (vty, "/%s",(char *)mac); - XFREE(MTYPE_TMP, mac); - } + vty_out (vty, "/%s",(char *)mac); + XFREE(MTYPE_TMP, mac); } } vty_out (vty, VTYNL); @@ -7372,14 +7313,14 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, { if (json_paths) { - json_object_int_add(json_path, "aggregatorAs", attr->extra->aggregator_as); - json_object_string_add(json_path, "aggregatorId", inet_ntoa (attr->extra->aggregator_addr)); + json_object_int_add(json_path, "aggregatorAs", attr->aggregator_as); + json_object_string_add(json_path, "aggregatorId", inet_ntoa (attr->aggregator_addr)); } else { vty_out (vty, ", (aggregated by %u %s)", - attr->extra->aggregator_as, - inet_ntoa (attr->extra->aggregator_addr)); + attr->aggregator_as, + inet_ntoa (attr->aggregator_addr)); } } @@ -7429,9 +7370,9 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN) { if (json_paths) - json_object_string_add(json_nexthop_global, "ip", inet_ntoa (attr->extra->mp_nexthop_global_in)); + json_object_string_add(json_nexthop_global, "ip", inet_ntoa (attr->mp_nexthop_global_in)); else - vty_out (vty, " %s", inet_ntoa (attr->extra->mp_nexthop_global_in)); + vty_out (vty, " %s", inet_ntoa (attr->mp_nexthop_global_in)); } else { @@ -7446,11 +7387,10 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, } else { - assert (attr->extra); if (json_paths) { json_object_string_add(json_nexthop_global, "ip", - inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global, + inet_ntop (AF_INET6, &attr->mp_nexthop_global, buf, INET6_ADDRSTRLEN)); json_object_string_add(json_nexthop_global, "afi", "ipv6"); json_object_string_add(json_nexthop_global, "scope", "global"); @@ -7458,7 +7398,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, else { vty_out (vty, " %s", - inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global, + inet_ntop (AF_INET6, &attr->mp_nexthop_global, buf, INET6_ADDRSTRLEN)); } } @@ -7559,7 +7499,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, } if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) - vty_out (vty, " (%s)", inet_ntoa (attr->extra->originator_id)); + vty_out (vty, " (%s)", inet_ntoa (attr->originator_id)); else vty_out (vty, " (%s)", inet_ntop (AF_INET, &binfo->peer->remote_id, buf1, BUFSIZ)); } @@ -7569,20 +7509,20 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, vty_out (vty, VTYNL); /* display the link-local nexthop */ - if (attr->extra && attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) + if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { if (json_paths) { json_nexthop_ll = json_object_new_object(); json_object_string_add(json_nexthop_ll, "ip", - inet_ntop (AF_INET6, &attr->extra->mp_nexthop_local, + inet_ntop (AF_INET6, &attr->mp_nexthop_local, buf, INET6_ADDRSTRLEN)); json_object_string_add(json_nexthop_ll, "afi", "ipv6"); json_object_string_add(json_nexthop_ll, "scope", "link-local"); json_object_boolean_true_add(json_nexthop_ll, "accessible"); - if (!attr->extra->mp_nexthop_prefer_global) + if (!attr->mp_nexthop_prefer_global) json_object_boolean_true_add(json_nexthop_ll, "used"); else json_object_boolean_true_add(json_nexthop_global, "used"); @@ -7590,9 +7530,9 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, else { vty_outln (vty, " (%s) %s", - inet_ntop (AF_INET6, &attr->extra->mp_nexthop_local, + inet_ntop (AF_INET6, &attr->mp_nexthop_local, buf, INET6_ADDRSTRLEN), - attr->extra->mp_nexthop_prefer_global ? "(prefer-global)" : "(used)"); + attr->mp_nexthop_prefer_global ? "(prefer-global)" : "(used)"); } } /* If we do not have a link-local nexthop then we must flag the global as "used" */ @@ -7631,20 +7571,20 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, vty_out (vty, ", localpref %u", bgp->default_local_pref); } - if (attr->extra && attr->extra->weight != 0) + if (attr->weight != 0) { if (json_paths) - json_object_int_add(json_path, "weight", attr->extra->weight); + json_object_int_add(json_path, "weight", attr->weight); else - vty_out (vty, ", weight %u", attr->extra->weight); + vty_out (vty, ", weight %u", attr->weight); } - if (attr->extra && attr->extra->tag != 0) + if (attr->tag != 0) { if (json_paths) - json_object_int_add(json_path, "tag", attr->extra->tag); + json_object_int_add(json_path, "tag", attr->tag); else - vty_out (vty, ", tag %"ROUTE_TAG_PRI, attr->extra->tag); + vty_out (vty, ", tag %"ROUTE_TAG_PRI, attr->tag); } if (! CHECK_FLAG (binfo->flags, BGP_INFO_VALID)) @@ -7807,33 +7747,32 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, if (json_paths) { json_ext_community = json_object_new_object(); - json_object_string_add(json_ext_community, "string", attr->extra->ecommunity->str); + json_object_string_add(json_ext_community, "string", attr->ecommunity->str); json_object_object_add(json_path, "extendedCommunity", json_ext_community); } else { vty_outln (vty, " Extended Community: %s", - attr->extra->ecommunity->str); + attr->ecommunity->str); } } /* Line 6 display Large community */ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)) vty_outln (vty, " Large Community: %s", - attr->extra->lcommunity->str); + attr->lcommunity->str); /* Line 7 display Originator, Cluster-id */ if ((attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) || (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST))) { - assert (attr->extra); if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) { if (json_paths) - json_object_string_add(json_path, "originatorId", inet_ntoa (attr->extra->originator_id)); + json_object_string_add(json_path, "originatorId", inet_ntoa (attr->originator_id)); else vty_out (vty, " Originator: %s", - inet_ntoa (attr->extra->originator_id)); + inet_ntoa (attr->originator_id)); } if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) @@ -7845,16 +7784,16 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, json_cluster_list = json_object_new_object(); json_cluster_list_list = json_object_new_array(); - for (i = 0; i < attr->extra->cluster->length / 4; i++) + for (i = 0; i < attr->cluster->length / 4; i++) { - json_string = json_object_new_string(inet_ntoa (attr->extra->cluster->list[i])); + json_string = json_object_new_string(inet_ntoa (attr->cluster->list[i])); json_object_array_add(json_cluster_list_list, json_string); } /* struct cluster_list does not have "str" variable like * aspath and community do. Add this someday if someone * asks for it. - json_object_string_add(json_cluster_list, "string", attr->extra->cluster->str); + json_object_string_add(json_cluster_list, "string", attr->cluster->str); */ json_object_object_add(json_cluster_list, "list", json_cluster_list_list); json_object_object_add(json_path, "clusterList", json_cluster_list); @@ -7863,10 +7802,10 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, { vty_out (vty, ", Cluster list: "); - for (i = 0; i < attr->extra->cluster->length / 4; i++) + for (i = 0; i < attr->cluster->length / 4; i++) { vty_out (vty, "%s ", - inet_ntoa (attr->extra->cluster->list[i])); + inet_ntoa (attr->cluster->list[i])); } } } @@ -7893,13 +7832,13 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, } /* Label Index */ - if (attr->extra->label_index != BGP_INVALID_LABEL_INDEX) + if (attr->label_index != BGP_INVALID_LABEL_INDEX) { if (json_paths) - json_object_int_add(json_path, "labelIndex", attr->extra->label_index); + json_object_int_add(json_path, "labelIndex", attr->label_index); else vty_outln (vty, " Label Index: %d", - attr->extra->label_index); + attr->label_index); } /* Line 8 display Addpath IDs */ @@ -8105,10 +8044,8 @@ bgp_show_table (struct vty *vty, struct bgp *bgp, struct bgp_table *table, struct route_map *rmap = output_arg; struct bgp_info binfo; struct attr dummy_attr; - struct attr_extra dummy_extra; int ret; - dummy_attr.extra = &dummy_extra; bgp_attr_dup (&dummy_attr, ri->attr); binfo.peer = ri->peer; @@ -8186,21 +8123,20 @@ bgp_show_table (struct vty *vty, struct bgp *bgp, struct bgp_table *table, { struct lcommunity *lcom = output_arg; - if (! ri->attr->extra || ! ri->attr->extra->lcommunity || - ! lcommunity_match (ri->attr->extra->lcommunity, lcom)) + if (! ri->attr->lcommunity || + ! lcommunity_match (ri->attr->lcommunity, lcom)) continue; } if (type == bgp_show_type_lcommunity_list) { struct community_list *list = output_arg; - if (! ri->attr->extra || - ! lcommunity_list_match (ri->attr->extra->lcommunity, list)) + if (! lcommunity_list_match (ri->attr->lcommunity, list)) continue; } if (type == bgp_show_type_lcommunity_all) { - if (! ri->attr->extra || ! ri->attr->extra->lcommunity) + if (! ri->attr->lcommunity) continue; } if (type == bgp_show_type_dampend_paths @@ -9831,7 +9767,6 @@ show_adj_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, struct bgp *bgp; int header2 = 1; struct attr attr; - struct attr_extra extra; int ret; struct update_subgroup *subgrp; json_object *json_scode = NULL; @@ -9904,7 +9839,6 @@ show_adj_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, header1 = 0; } - attr.extra = &extra; for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) { if (in) diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index cb918718fe..4b82717569 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -232,8 +232,8 @@ struct bgp_static #define BGP_ATTR_NEXTHOP_AFI_IP6(attr) \ (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)) && \ - (attr)->extra && ((attr)->extra->mp_nexthop_len == 16 || \ - (attr)->extra->mp_nexthop_len == 32)) + ((attr)->mp_nexthop_len == 16 || \ + (attr)->mp_nexthop_len == 32)) #define BGP_INFO_COUNTABLE(BI) \ (! CHECK_FLAG ((BI)->flags, BGP_INFO_HISTORY) \ && ! CHECK_FLAG ((BI)->flags, BGP_INFO_REMOVED)) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index b0a3cc677d..7ce144f729 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -868,8 +868,7 @@ route_match_lcommunity (void *rule, struct prefix *prefix, if (! list) return RMAP_NOMATCH; - if (bgp_info->attr->extra && - lcommunity_list_match (bgp_info->attr->extra->lcommunity, list)) + if (lcommunity_list_match (bgp_info->attr->lcommunity, list)) return RMAP_MATCH; } @@ -933,15 +932,12 @@ route_match_ecommunity (void *rule, struct prefix *prefix, { bgp_info = object; - if (!bgp_info->attr->extra) - return RMAP_NOMATCH; - list = community_list_lookup (bgp_clist, (char *) rule, EXTCOMMUNITY_LIST_MASTER); if (! list) return RMAP_NOMATCH; - if (ecommunity_list_match (bgp_info->attr->extra->ecommunity, list)) + if (ecommunity_list_match (bgp_info->attr->ecommunity, list)) return RMAP_MATCH; } return RMAP_NOMATCH; @@ -1149,10 +1145,7 @@ route_match_tag (void *rule, struct prefix *prefix, tag = rule; bgp_info = object; - if (!bgp_info->attr->extra) - return RMAP_NOMATCH; - - return ((bgp_info->attr->extra->tag == *tag)? RMAP_MATCH : RMAP_NOMATCH); + return ((bgp_info->attr->tag == *tag)? RMAP_MATCH : RMAP_NOMATCH); } return RMAP_NOMATCH; @@ -1332,7 +1325,6 @@ route_set_weight (void *rule, struct prefix *prefix, route_map_object_t type, { struct rmap_value *rv; struct bgp_info *bgp_info; - u_int32_t weight; if (type == RMAP_BGP) { @@ -1341,11 +1333,7 @@ route_set_weight (void *rule, struct prefix *prefix, route_map_object_t type, bgp_info = object; /* Set weight value. */ - weight = route_value_adjust(rv, 0, bgp_info->peer); - if (weight) - (bgp_attr_extra_get (bgp_info->attr))->weight = weight; - else if (bgp_info->attr->extra) - bgp_info->attr->extra->weight = 0; + bgp_info->attr->weight = route_value_adjust(rv, 0, bgp_info->peer); } return RMAP_OKAY; @@ -1644,14 +1632,13 @@ route_set_lcommunity (void *rule, struct prefix *prefix, rcs = rule; binfo = object; attr = binfo->attr; - old = (attr->extra) ? attr->extra->lcommunity : NULL; + old = attr->lcommunity; /* "none" case. */ if (rcs->none) { attr->flag &= ~(ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES)); - if (attr->extra) - attr->extra->lcommunity = NULL; + attr->lcommunity = NULL; /* See the longer comment down below. */ if (old && old->refcnt == 0) @@ -1676,7 +1663,7 @@ route_set_lcommunity (void *rule, struct prefix *prefix, new = lcommunity_dup (rcs->lcom); /* will be intern()'d or attr_flush()'d by bgp_update_main() */ - (bgp_attr_extra_get (attr))->lcommunity = new; + attr->lcommunity = new; attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES); } @@ -1766,7 +1753,7 @@ route_set_lcommunity_delete (void *rule, struct prefix *prefix, binfo = object; list = community_list_lookup (bgp_clist, rule, LARGE_COMMUNITY_LIST_MASTER); - old = ((binfo->attr->extra) ? binfo->attr->extra->lcommunity : NULL); + old = binfo->attr->lcommunity; if (list && old) { @@ -1783,13 +1770,13 @@ route_set_lcommunity_delete (void *rule, struct prefix *prefix, if (new->size == 0) { - binfo->attr->extra->lcommunity = NULL; + binfo->attr->lcommunity = NULL; binfo->attr->flag &= ~ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES); lcommunity_free (&new); } else { - binfo->attr->extra->lcommunity = new; + binfo->attr->lcommunity = new; binfo->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES); } } @@ -1946,7 +1933,7 @@ route_set_ecommunity (void *rule, struct prefix *prefix, return RMAP_OKAY; /* We assume additive for Extended Community. */ - old_ecom = (bgp_attr_extra_get (bgp_info->attr))->ecommunity; + old_ecom = bgp_info->attr->ecommunity; if (old_ecom) { @@ -1961,7 +1948,7 @@ route_set_ecommunity (void *rule, struct prefix *prefix, new_ecom = ecommunity_dup (ecom); /* will be intern()'d or attr_flush()'d by bgp_update_main() */ - bgp_info->attr->extra->ecommunity = new_ecom; + bgp_info->attr->ecommunity = new_ecom; bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); } @@ -2129,16 +2116,14 @@ route_set_aggregator_as (void *rule, struct prefix *prefix, { struct bgp_info *bgp_info; struct aggregator *aggregator; - struct attr_extra *ae; if (type == RMAP_BGP) { bgp_info = object; aggregator = rule; - ae = bgp_attr_extra_get (bgp_info->attr); - ae->aggregator_as = aggregator->as; - ae->aggregator_addr = aggregator->address; + bgp_info->attr->aggregator_as = aggregator->as; + bgp_info->attr->aggregator_addr = aggregator->address; bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR); } @@ -2187,16 +2172,14 @@ route_set_tag (void *rule, struct prefix *prefix, { route_tag_t *tag; struct bgp_info *bgp_info; - struct attr_extra *ae; if (type == RMAP_BGP) { tag = rule; bgp_info = object; - ae = bgp_attr_extra_get (bgp_info->attr); /* Set tag value */ - ae->tag=*tag; + bgp_info->attr->tag=*tag; } @@ -2231,7 +2214,7 @@ route_set_label_index (void *rule, struct prefix *prefix, label_index = rv->value; if (label_index) { - (bgp_attr_extra_get (bgp_info->attr))->label_index = label_index; + bgp_info->attr->label_index = label_index; bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_PREFIX_SID); } } @@ -2302,14 +2285,11 @@ route_match_ipv6_next_hop (void *rule, struct prefix *prefix, { bgp_info = object; - if (!bgp_info->attr->extra) - return RMAP_NOMATCH; - - if (IPV6_ADDR_SAME (&bgp_info->attr->extra->mp_nexthop_global, addr)) + if (IPV6_ADDR_SAME (&bgp_info->attr->mp_nexthop_global, addr)) return RMAP_MATCH; - if (bgp_info->attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL && - IPV6_ADDR_SAME (&bgp_info->attr->extra->mp_nexthop_local, rule)) + if (bgp_info->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL && + IPV6_ADDR_SAME (&bgp_info->attr->mp_nexthop_local, rule)) return RMAP_MATCH; return RMAP_NOMATCH; @@ -2407,11 +2387,11 @@ route_set_ipv6_nexthop_global (void *rule, struct prefix *prefix, bgp_info = object; /* Set next hop value. */ - (bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_global = *address; + bgp_info->attr->mp_nexthop_global = *address; /* Set nexthop length. */ - if (bgp_info->attr->extra->mp_nexthop_len == 0) - bgp_info->attr->extra->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL; + if (bgp_info->attr->mp_nexthop_len == 0) + bgp_info->attr->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL; SET_FLAG(bgp_info->attr->rmap_change_flags, BATTR_RMAP_IPV6_GLOBAL_NHOP_CHANGED); @@ -2477,13 +2457,13 @@ route_set_ipv6_nexthop_prefer_global (void *rule, struct prefix *prefix, && sockunion_family (peer->su_remote) == AF_INET6) { /* Set next hop preference to global */ - bgp_info->attr->extra->mp_nexthop_prefer_global = TRUE; + bgp_info->attr->mp_nexthop_prefer_global = TRUE; SET_FLAG(bgp_info->attr->rmap_change_flags, BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED); } else { - bgp_info->attr->extra->mp_nexthop_prefer_global = FALSE; + bgp_info->attr->mp_nexthop_prefer_global = FALSE; SET_FLAG(bgp_info->attr->rmap_change_flags, BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED); } @@ -2535,11 +2515,11 @@ route_set_ipv6_nexthop_local (void *rule, struct prefix *prefix, bgp_info = object; /* Set next hop value. */ - (bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_local = *address; + bgp_info->attr->mp_nexthop_local = *address; /* Set nexthop length. */ - if (bgp_info->attr->extra->mp_nexthop_len != BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) - bgp_info->attr->extra->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL; + if (bgp_info->attr->mp_nexthop_len != BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) + bgp_info->attr->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL; SET_FLAG(bgp_info->attr->rmap_change_flags, BATTR_RMAP_IPV6_LL_NHOP_CHANGED); @@ -2611,15 +2591,15 @@ route_set_ipv6_nexthop_peer (void *rule, struct prefix *prefix, /* Set next hop value and length in attribute. */ if (IN6_IS_ADDR_LINKLOCAL(&peer_address)) { - (bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_local = peer_address; - if (bgp_info->attr->extra->mp_nexthop_len != 32) - bgp_info->attr->extra->mp_nexthop_len = 32; + bgp_info->attr->mp_nexthop_local = peer_address; + if (bgp_info->attr->mp_nexthop_len != 32) + bgp_info->attr->mp_nexthop_len = 32; } else { - (bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_global = peer_address; - if (bgp_info->attr->extra->mp_nexthop_len == 0) - bgp_info->attr->extra->mp_nexthop_len = 16; + bgp_info->attr->mp_nexthop_global = peer_address; + if (bgp_info->attr->mp_nexthop_len == 0) + bgp_info->attr->mp_nexthop_len = 16; } } @@ -2633,9 +2613,9 @@ route_set_ipv6_nexthop_peer (void *rule, struct prefix *prefix, SET_FLAG(bgp_info->attr->rmap_change_flags, BATTR_RMAP_NEXTHOP_PEER_ADDRESS); /* clear next hop value. */ - memset (&((bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_global), + memset (&(bgp_info->attr->mp_nexthop_global), 0, sizeof (struct in6_addr)); - memset (&((bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_local), + memset (&(bgp_info->attr->mp_nexthop_local), 0, sizeof (struct in6_addr)); } } @@ -2688,8 +2668,8 @@ route_set_vpnv4_nexthop (void *rule, struct prefix *prefix, bgp_info = object; /* Set next hop value. */ - (bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_global_in = *address; - (bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_len = 4; + bgp_info->attr->mp_nexthop_global_in = *address; + bgp_info->attr->mp_nexthop_len = 4; } return RMAP_OKAY; @@ -2730,8 +2710,8 @@ route_set_vpnv6_nexthop (void *rule, struct prefix *prefix, bgp_info = object; /* Set next hop value. */ - memcpy (&(bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_global, address, sizeof(struct in6_addr)); - (bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_len = BGP_ATTR_NHLEN_VPNV6_GLOBAL; + memcpy (&bgp_info->attr->mp_nexthop_global, address, sizeof(struct in6_addr)); + bgp_info->attr->mp_nexthop_len = BGP_ATTR_NHLEN_VPNV6_GLOBAL; } return RMAP_OKAY; @@ -2794,7 +2774,7 @@ route_set_originator_id (void *rule, struct prefix *prefix, route_map_object_t t bgp_info = object; bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID); - (bgp_attr_extra_get (bgp_info->attr))->originator_id = *address; + bgp_info->attr->originator_id = *address; } return RMAP_OKAY; diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c index db69400a67..c1a6ad589d 100644 --- a/bgpd/bgp_snmp.c +++ b/bgpd/bgp_snmp.c @@ -802,16 +802,10 @@ bgp4PathAttrTable (struct variable *v, oid name[], size_t *length, return SNMP_INTEGER (1); break; case BGP4PATHATTRAGGREGATORAS: /* 10 */ - if (binfo->attr->extra) - return SNMP_INTEGER (binfo->attr->extra->aggregator_as); - else - return SNMP_INTEGER (0); + return SNMP_INTEGER (binfo->attr->aggregator_as); break; case BGP4PATHATTRAGGREGATORADDR: /* 11 */ - if (binfo->attr->extra) - return SNMP_IPADDRESS (binfo->attr->extra->aggregator_addr); - else - return SNMP_INTEGER (0); + return SNMP_IPADDRESS (binfo->attr->aggregator_addr); break; case BGP4PATHATTRCALCLOCALPREF: /* 12 */ return SNMP_INTEGER (-1); diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index c4cb8ae1b3..f81568976f 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -587,7 +587,6 @@ subgroup_announce_table (struct update_subgroup *subgrp, struct bgp_node *rn; struct bgp_info *ri; struct attr attr; - struct attr_extra extra; struct peer *peer; afi_t afi; safi_t safi; @@ -610,9 +609,6 @@ subgroup_announce_table (struct update_subgroup *subgrp, && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE)) subgroup_default_originate (subgrp, 0); - /* It's initialized in bgp_announce_check() */ - attr.extra = &extra; - for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) for (ri = rn->info; ri; ri = ri->next) @@ -716,18 +712,16 @@ subgroup_default_originate (struct update_subgroup *subgrp, int withdraw) str2prefix ("0.0.0.0/0", &p); else if (afi == AFI_IP6) { - struct attr_extra *ae = attr.extra; - str2prefix ("::/0", &p); /* IPv6 global nexthop must be included. */ - ae->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL; + attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL; /* If the peer is on shared nextwork and we have link-local nexthop set it. */ if (peer->shared_network && !IN6_IS_ADDR_UNSPECIFIED (&peer->nexthop.v6_local)) - ae->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL; + attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL; } if (peer->default_rmap[afi][safi].name) @@ -739,11 +733,9 @@ subgroup_default_originate (struct update_subgroup *subgrp, int withdraw) for (ri = rn->info; ri; ri = ri->next) { struct attr dummy_attr; - struct attr_extra dummy_extra; struct bgp_info info; /* Provide dummy so the route-map can't modify the attributes */ - dummy_attr.extra = &dummy_extra; bgp_attr_dup (&dummy_attr, ri->attr); info.peer = ri->peer; info.attr = &dummy_attr; @@ -794,7 +786,6 @@ subgroup_default_originate (struct update_subgroup *subgrp, int withdraw) } } - bgp_attr_extra_free (&attr); aspath_unintern (&aspath); } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index b877d982c8..b58a3266a0 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -6724,11 +6724,6 @@ DEFUN (show_bgp_memory, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof(struct attr)), VTYNL); - if ((count = mtype_stats_alloc (MTYPE_ATTR_EXTRA))) - vty_out (vty, "%ld BGP extra attributes, using %s of memory%s", count, - mtype_memstr (memstrbuf, sizeof (memstrbuf), - count * sizeof(struct attr_extra)), - VTYNL); if ((count = attr_unknown_count())) vty_out (vty, "%ld unknown attributes%s", count, VTYNL); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 91c155b3fd..3a215dc476 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -73,14 +73,12 @@ struct stream *bgp_label_buf = NULL; 2. use an array to avoid number of mallocs. Number of supported next-hops are finite, use of arrays should be ok. */ struct attr attr_cp[MULTIPATH_NUM]; -struct attr_extra attr_extra_cp[MULTIPATH_NUM]; unsigned int attr_index = 0; /* Once per address-family initialization of the attribute array */ #define BGP_INFO_ATTR_BUF_INIT()\ do {\ memset(attr_cp, 0, MULTIPATH_NUM * sizeof(struct attr));\ - memset(attr_extra_cp, 0, MULTIPATH_NUM * sizeof(struct attr_extra));\ attr_index = 0;\ } while (0) @@ -88,7 +86,6 @@ do {\ do { \ *info_dst = *info_src; \ assert(attr_index != multipath_num);\ - attr_cp[attr_index].extra = &attr_extra_cp[attr_index]; \ bgp_attr_dup (&attr_cp[attr_index], info_src->attr); \ bgp_attr_deep_dup (&attr_cp[attr_index], info_src->attr); \ info_dst->attr = &attr_cp[attr_index]; \ @@ -1162,23 +1159,23 @@ bgp_info_to_ipv6_nexthop (struct bgp_info *info) struct in6_addr *nexthop = NULL; /* Only global address nexthop exists. */ - if (info->attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL) - nexthop = &info->attr->extra->mp_nexthop_global; + if (info->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL) + nexthop = &info->attr->mp_nexthop_global; /* If both global and link-local address present. */ - if (info->attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) + if (info->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { /* Check if route-map is set to prefer global over link-local */ - if (info->attr->extra->mp_nexthop_prefer_global) - nexthop = &info->attr->extra->mp_nexthop_global; + if (info->attr->mp_nexthop_prefer_global) + nexthop = &info->attr->mp_nexthop_global; else { /* Workaround for Cisco's nexthop bug. */ - if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->extra->mp_nexthop_global) + if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->mp_nexthop_global) && info->peer->su_remote->sa.sa_family == AF_INET6) nexthop = &info->peer->su_remote->sin6.sin6_addr; else - nexthop = &info->attr->extra->mp_nexthop_local; + nexthop = &info->attr->mp_nexthop_local; } } @@ -1248,10 +1245,7 @@ bgp_zebra_announce (struct bgp_node *rn, struct prefix *p, struct bgp_info *info flags = 0; peer = info->peer; - if ((info->attr->extra) && (info->attr->extra->tag != 0)) - tag = info->attr->extra->tag; - else - tag = 0; + tag = info->attr->tag; /* When we create an aggregate route we must also install a Null0 route in * the RIB */ @@ -1305,7 +1299,7 @@ bgp_zebra_announce (struct bgp_node *rn, struct prefix *p, struct bgp_info *info { /* Metric is currently based on the best-path only */ metric = info_cp->attr->med; - tag = info_cp->attr->extra->tag; + tag = info_cp->attr->tag; } nexthop = &info_cp->attr->nexthop; } @@ -1420,8 +1414,6 @@ bgp_zebra_announce (struct bgp_node *rn, struct prefix *p, struct bgp_info *info ifindex = 0; nexthop = NULL; - assert (info->attr->extra); - if (bgp->table_map[afi][safi].name) BGP_INFO_ATTR_BUF_INIT(); @@ -1441,7 +1433,7 @@ bgp_zebra_announce (struct bgp_node *rn, struct prefix *p, struct bgp_info *info if (mpinfo == info) { metric = info_cp->attr->med; - tag = info_cp->attr->extra->tag; + tag = info_cp->attr->tag; } nexthop = bgp_info_to_ipv6_nexthop(info_cp); } @@ -1454,7 +1446,7 @@ bgp_zebra_announce (struct bgp_node *rn, struct prefix *p, struct bgp_info *info continue; if ((mpinfo == info) && - mpinfo->attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) + mpinfo->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) if (mpinfo->peer->nexthop.ifp) ifindex = mpinfo->peer->nexthop.ifp->ifindex; @@ -1674,10 +1666,10 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi) api.metric = info->attr->med; api.tag = 0; - if ((info->attr->extra) && (info->attr->extra->tag != 0)) + if (info->attr->tag != 0) { SET_FLAG(api.message, ZAPI_MESSAGE_TAG); - api.tag = info->attr->extra->tag; + api.tag = info->attr->tag; } if (bgp_debug_zebra(p)) @@ -1696,8 +1688,6 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi) if (p->family == AF_INET6) { struct zapi_ipv6 api; - - assert (info->attr->extra); api.vrf_id = peer->bgp->vrf_id; api.flags = flags; @@ -1714,10 +1704,10 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi) api.metric = info->attr->med; api.tag = 0; - if ((info->attr->extra) && (info->attr->extra->tag != 0)) + if (info->attr->tag != 0) { SET_FLAG(api.message, ZAPI_MESSAGE_TAG); - api.tag = info->attr->extra->tag; + api.tag = info->attr->tag; } if (bgp_debug_zebra(p)) @@ -1903,9 +1893,7 @@ bgp_redistribute_metric_set (struct bgp *bgp, struct bgp_redist *red, afi_t afi, { struct attr *old_attr; struct attr new_attr; - struct attr_extra new_extra; - new_attr.extra = &new_extra; bgp_attr_dup (&new_attr, ri->attr); new_attr.med = red->redist_metric; old_attr = ri->attr; diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c index ffd4e3e323..5a9544247c 100644 --- a/bgpd/rfapi/rfapi.c +++ b/bgpd/rfapi/rfapi.c @@ -715,7 +715,6 @@ add_vnc_route ( /* Cripes, the memory management of attributes is byzantine */ bgp_attr_default_set (&attr, BGP_ORIGIN_INCOMPLETE); - assert (attr.extra); /* * At this point: @@ -772,7 +771,6 @@ add_vnc_route ( /* Encap SAFI not used with MPLS */ vnc_zlog_debug_verbose ("%s: mpls tunnel type, encap safi omitted", __func__); aspath_unintern (&attr.aspath); /* Unintern original. */ - bgp_attr_extra_free (&attr); return; } } @@ -790,7 +788,7 @@ add_vnc_route ( } /* override default weight assigned by bgp_attr_default_set() */ - attr.extra->weight = rfd->peer ? rfd->peer->weight[afi][safi] : 0; + attr.weight = rfd->peer ? rfd->peer->weight[afi][safi] : 0; /* * NB: ticket 81: do not reset attr.aspath here because it would @@ -808,7 +806,7 @@ add_vnc_route ( if (type == ZEBRA_ROUTE_BGP_DIRECT || type == ZEBRA_ROUTE_BGP_DIRECT_EXT) { attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID); - attr.extra->originator_id = bgp->router_id; + attr.originator_id = bgp->router_id; } @@ -825,7 +823,7 @@ add_vnc_route ( encaptlv->length = 4; lt = htonl (*lifetime); memcpy (encaptlv->value, <, 4); - attr.extra->vnc_subtlvs = encaptlv; + attr.vnc_subtlvs = encaptlv; vnc_zlog_debug_verbose ("%s: set Encap Attr Prefix Lifetime to %d", __func__, *lifetime); } @@ -845,13 +843,13 @@ add_vnc_route ( */ encaptlv = encap_tlv_dup ((struct bgp_attr_encap_subtlv *) rfp_options); - if (attr.extra->vnc_subtlvs) + if (attr.vnc_subtlvs) { - attr.extra->vnc_subtlvs->next = encaptlv; + attr.vnc_subtlvs->next = encaptlv; } else { - attr.extra->vnc_subtlvs = encaptlv; + attr.vnc_subtlvs = encaptlv; } } @@ -859,7 +857,7 @@ add_vnc_route ( { struct bgp_tea_options *hop; /* XXX max of one tlv present so far from above code */ - struct bgp_attr_encap_subtlv *tail = attr.extra->vnc_subtlvs; + struct bgp_attr_encap_subtlv *tail = attr.vnc_subtlvs; for (hop = rfp_options; hop; hop = hop->next) { @@ -887,7 +885,7 @@ add_vnc_route ( } else { - attr.extra->vnc_subtlvs = encaptlv; + attr.vnc_subtlvs = encaptlv; } tail = encaptlv; } @@ -903,8 +901,8 @@ add_vnc_route ( */ - attr.extra->ecommunity = ecommunity_new (); - assert (attr.extra->ecommunity); + attr.ecommunity = ecommunity_new (); + assert (attr.ecommunity); if (TunnelType != BGP_ENCAP_TYPE_MPLS && TunnelType != BGP_ENCAP_TYPE_RESERVED) @@ -921,7 +919,7 @@ add_vnc_route ( beec.val[1] = ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP; beec.val[6] = ((TunnelType) >> 8) & 0xff; beec.val[7] = (TunnelType) & 0xff; - ecommunity_add_val (attr.extra->ecommunity, &beec); + ecommunity_add_val (attr.ecommunity, &beec); } /* @@ -929,21 +927,21 @@ add_vnc_route ( */ if (rt_export_list) { - attr.extra->ecommunity = - ecommunity_merge (attr.extra->ecommunity, rt_export_list); + attr.ecommunity = + ecommunity_merge (attr.ecommunity, rt_export_list); } - if (attr.extra->ecommunity->size) + if (attr.ecommunity->size) { attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); } else { - ecommunity_free (&attr.extra->ecommunity); - attr.extra->ecommunity = NULL; + ecommunity_free (&attr.ecommunity); + attr.ecommunity = NULL; } - vnc_zlog_debug_verbose ("%s: attr.extra->ecommunity=%p", __func__, - attr.extra->ecommunity); + vnc_zlog_debug_verbose ("%s: attr.ecommunity=%p", __func__, + attr.ecommunity); /* @@ -965,13 +963,13 @@ add_vnc_route ( */ attr.nexthop.s_addr = nexthop->addr.v4.s_addr; - attr.extra->mp_nexthop_global_in = nexthop->addr.v4; - attr.extra->mp_nexthop_len = 4; + attr.mp_nexthop_global_in = nexthop->addr.v4; + attr.mp_nexthop_len = 4; break; case AF_INET6: - attr.extra->mp_nexthop_global = nexthop->addr.v6; - attr.extra->mp_nexthop_len = 16; + attr.mp_nexthop_global = nexthop->addr.v6; + attr.mp_nexthop_len = 16; break; default: @@ -1016,7 +1014,6 @@ add_vnc_route ( new_attr = bgp_attr_intern (&attr); aspath_unintern (&attr.aspath); /* Unintern original. */ - bgp_attr_extra_free (&attr); /* * At this point: diff --git a/bgpd/rfapi/rfapi_encap_tlv.c b/bgpd/rfapi/rfapi_encap_tlv.c index 04f8b249f7..24bfb41bfa 100644 --- a/bgpd/rfapi/rfapi_encap_tlv.c +++ b/bgpd/rfapi/rfapi_encap_tlv.c @@ -162,28 +162,24 @@ rfapi_tunneltype_option_to_tlv ( struct rfapi_un_option * rfapi_encap_tlv_to_un_option (struct attr *attr) { - struct attr_extra *attre = attr->extra; struct rfapi_un_option *uo = NULL; struct rfapi_tunneltype_option *tto; int rc; struct bgp_attr_encap_subtlv *stlv; - if (!attre) - return NULL; - /* no tunnel encap attr stored */ - if (!attre->encap_tunneltype) + if (!attr->encap_tunneltype) return NULL; - stlv = attre->encap_subtlvs; + stlv = attr->encap_subtlvs; uo = XCALLOC (MTYPE_RFAPI_UN_OPTION, sizeof (struct rfapi_un_option)); assert (uo); uo->type = RFAPI_UN_OPTION_TYPE_TUNNELTYPE; - uo->v.tunnel.type = attre->encap_tunneltype; + uo->v.tunnel.type = attr->encap_tunneltype; tto = &uo->v.tunnel; - switch (attre->encap_tunneltype) + switch (attr->encap_tunneltype) { case BGP_ENCAP_TYPE_L2TPV3_OVER_IP: rc = tlv_to_bgp_encap_type_l2tpv3overip (stlv, &tto->bgpinfo.l2tpv3_ip); @@ -249,7 +245,7 @@ rfapi_encap_tlv_to_un_option (struct attr *attr) default: vnc_zlog_debug_verbose ("%s: unknown tunnel type %d", - __func__, attre->encap_tunneltype); + __func__, attr->encap_tunneltype); rc = -1; break; } diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c index ec52b5742b..7b0ca0cbb9 100644 --- a/bgpd/rfapi/rfapi_import.c +++ b/bgpd/rfapi/rfapi_import.c @@ -1,4 +1,4 @@ -/* + /* * * Copyright 2009-2016, LabN Consulting, L.L.C. * @@ -308,12 +308,12 @@ rfapi_deferred_close_workfunc (struct work_queue *q, void *data) int rfapiGetL2o (struct attr *attr, struct rfapi_l2address_option *l2o) { - if (attr && attr->extra) + if (attr) { struct bgp_attr_encap_subtlv *pEncap; - for (pEncap = attr->extra->vnc_subtlvs; pEncap; pEncap = pEncap->next) + for (pEncap = attr->vnc_subtlvs; pEncap; pEncap = pEncap->next) { if (pEncap->type == BGP_VNC_SUBTLV_TYPE_RFPOPTION) @@ -358,10 +358,10 @@ rfapiGetVncLifetime (struct attr *attr, uint32_t * lifetime) *lifetime = RFAPI_INFINITE_LIFETIME; /* default to infinite */ - if (attr && attr->extra) + if (attr) { - for (pEncap = attr->extra->vnc_subtlvs; pEncap; pEncap = pEncap->next) + for (pEncap = attr->vnc_subtlvs; pEncap; pEncap = pEncap->next) { if (pEncap->type == BGP_VNC_SUBTLV_TYPE_LIFETIME) @@ -387,9 +387,9 @@ rfapiGetTunnelType (struct attr *attr, bgp_encap_types *type) { *type = BGP_ENCAP_TYPE_MPLS; /* default to MPLS */ - if (attr && attr->extra && attr->extra->ecommunity) + if (attr && attr->ecommunity) { - struct ecommunity *ecom = attr->extra->ecommunity; + struct ecommunity *ecom = attr->ecommunity; int i; for (i = 0; i < (ecom->size * ECOMMUNITY_SIZE); i += ECOMMUNITY_SIZE) @@ -431,9 +431,9 @@ rfapiGetVncTunnelUnAddr (struct attr *attr, struct prefix *p) return ENOENT; } - if (attr && attr->extra) + if (attr) { - for (pEncap = attr->extra->encap_subtlvs; pEncap; pEncap = pEncap->next) + for (pEncap = attr->encap_subtlvs; pEncap; pEncap = pEncap->next) { if (pEncap->type == BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT) @@ -1184,7 +1184,7 @@ rfapiVpnBiNhEqualsPt (struct bgp_info *bi, struct rfapi_ip_addr *hpt) if (!hpt || !bi) return 0; - family = BGP_MP_NEXTHOP_FAMILY (bi->attr->extra->mp_nexthop_len); + family = BGP_MP_NEXTHOP_FAMILY (bi->attr->mp_nexthop_len); if (hpt->addr_family != family) return 0; @@ -1192,12 +1192,12 @@ rfapiVpnBiNhEqualsPt (struct bgp_info *bi, struct rfapi_ip_addr *hpt) switch (family) { case AF_INET: - if (bi->attr->extra->mp_nexthop_global_in.s_addr != hpt->addr.v4.s_addr) + if (bi->attr->mp_nexthop_global_in.s_addr != hpt->addr.v4.s_addr) return 0; break; case AF_INET6: - if (IPV6_ADDR_CMP (&bi->attr->extra->mp_nexthop_global, &hpt->addr.v6)) + if (IPV6_ADDR_CMP (&bi->attr->mp_nexthop_global, &hpt->addr.v6)) return 0; break; @@ -1225,31 +1225,27 @@ rfapiVpnBiSamePtUn (struct bgp_info *bi1, struct bgp_info *bi2) if (!bi1->attr || !bi2->attr) return 0; - if (!bi1->attr->extra || !bi2->attr->extra) - return 0; - /* * VN address comparisons */ - if (BGP_MP_NEXTHOP_FAMILY (bi1->attr->extra->mp_nexthop_len) != - BGP_MP_NEXTHOP_FAMILY (bi2->attr->extra->mp_nexthop_len)) + if (BGP_MP_NEXTHOP_FAMILY (bi1->attr->mp_nexthop_len) != + BGP_MP_NEXTHOP_FAMILY (bi2->attr->mp_nexthop_len)) { return 0; } - switch (BGP_MP_NEXTHOP_FAMILY (bi1->attr->extra->mp_nexthop_len)) + switch (BGP_MP_NEXTHOP_FAMILY (bi1->attr->mp_nexthop_len)) { - case AF_INET: - if (bi1->attr->extra->mp_nexthop_global_in.s_addr != - bi2->attr->extra->mp_nexthop_global_in.s_addr) + if (bi1->attr->mp_nexthop_global_in.s_addr != + bi2->attr->mp_nexthop_global_in.s_addr) return 0; break; case AF_INET6: - if (IPV6_ADDR_CMP (&bi1->attr->extra->mp_nexthop_global, - &bi2->attr->extra->mp_nexthop_global)) + if (IPV6_ADDR_CMP (&bi1->attr->mp_nexthop_global, + &bi2->attr->mp_nexthop_global)) return 0; break; @@ -1419,11 +1415,11 @@ rfapiRouteInfo2NextHopEntry ( memcpy (&vo->v.l2addr.macaddr, &rn->p.u.prefix_eth.octet, ETHER_ADDR_LEN); /* only low 3 bytes of this are significant */ - if (bi->attr && bi->attr->extra) + if (bi->attr) { - (void) rfapiEcommunityGetLNI (bi->attr->extra->ecommunity, + (void) rfapiEcommunityGetLNI (bi->attr->ecommunity, &vo->v.l2addr.logical_net_id); - (void) rfapiEcommunityGetEthernetTag (bi->attr->extra->ecommunity, + (void) rfapiEcommunityGetEthernetTag (bi->attr->ecommunity, &vo->v.l2addr.tag_id); } @@ -1451,132 +1447,129 @@ rfapiRouteInfo2NextHopEntry ( bgp_encap_types tun_type; new->prefix.cost = rfapiRfpCost (bi->attr); - if (bi->attr->extra) + struct bgp_attr_encap_subtlv *pEncap; + + switch (BGP_MP_NEXTHOP_FAMILY (bi->attr->mp_nexthop_len)) { + case AF_INET: + new->vn_address.addr_family = AF_INET; + new->vn_address.addr.v4 = bi->attr->mp_nexthop_global_in; + break; - struct bgp_attr_encap_subtlv *pEncap; + case AF_INET6: + new->vn_address.addr_family = AF_INET6; + new->vn_address.addr.v6 = bi->attr->mp_nexthop_global; + break; - switch (BGP_MP_NEXTHOP_FAMILY (bi->attr->extra->mp_nexthop_len)) + default: + zlog_warn ("%s: invalid vpn nexthop length: %d", + __func__, bi->attr->mp_nexthop_len); + rfapi_free_next_hop_list (new); + return NULL; + } + + for (pEncap = bi->attr->vnc_subtlvs; pEncap; + pEncap = pEncap->next) + { + switch (pEncap->type) { - case AF_INET: - new->vn_address.addr_family = AF_INET; - new->vn_address.addr.v4 = bi->attr->extra->mp_nexthop_global_in; - break; - - case AF_INET6: - new->vn_address.addr_family = AF_INET6; - new->vn_address.addr.v6 = bi->attr->extra->mp_nexthop_global; + case BGP_VNC_SUBTLV_TYPE_LIFETIME: + /* use configured lifetime, not attr lifetime */ break; default: - zlog_warn ("%s: invalid vpn nexthop length: %d", - __func__, bi->attr->extra->mp_nexthop_len); - rfapi_free_next_hop_list (new); - return NULL; + zlog_warn ("%s: unknown VNC option type %d", + __func__, pEncap->type); + + + break; } + } - for (pEncap = bi->attr->extra->vnc_subtlvs; pEncap; - pEncap = pEncap->next) + rfapiGetTunnelType (bi->attr, &tun_type); + if (tun_type == BGP_ENCAP_TYPE_MPLS) + { + struct prefix p; + /* MPLS carries UN address in next hop */ + rfapiNexthop2Prefix (bi->attr, &p); + if (p.family != 0) { - switch (pEncap->type) - { - case BGP_VNC_SUBTLV_TYPE_LIFETIME: - /* use configured lifetime, not attr lifetime */ - break; - - default: - zlog_warn ("%s: unknown VNC option type %d", - __func__, pEncap->type); - - - break; - } + rfapiQprefix2Raddr(&p, &new->un_address); + have_vnc_tunnel_un = 1; } + } - rfapiGetTunnelType (bi->attr, &tun_type); - if (tun_type == BGP_ENCAP_TYPE_MPLS) + for (pEncap = bi->attr->encap_subtlvs; pEncap; + pEncap = pEncap->next) + { + switch (pEncap->type) { - struct prefix p; - /* MPLS carries UN address in next hop */ - rfapiNexthop2Prefix (bi->attr, &p); - if (p.family != 0) + case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: + /* + * Overrides ENCAP UN address, if any + */ + switch (pEncap->length) { - rfapiQprefix2Raddr(&p, &new->un_address); + + case 8: + new->un_address.addr_family = AF_INET; + memcpy (&new->un_address.addr.v4, pEncap->value, 4); have_vnc_tunnel_un = 1; - } - } + break; - for (pEncap = bi->attr->extra->encap_subtlvs; pEncap; - pEncap = pEncap->next) - { - switch (pEncap->type) - { - case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: - /* - * Overrides ENCAP UN address, if any - */ - switch (pEncap->length) - { - - case 8: - new->un_address.addr_family = AF_INET; - memcpy (&new->un_address.addr.v4, pEncap->value, 4); - have_vnc_tunnel_un = 1; - break; - - case 20: - new->un_address.addr_family = AF_INET6; - memcpy (&new->un_address.addr.v6, pEncap->value, 16); - have_vnc_tunnel_un = 1; - break; - - default: - zlog_warn - ("%s: invalid tunnel subtlv UN addr length (%d) for bi %p", - __func__, pEncap->length, bi); - } + case 20: + new->un_address.addr_family = AF_INET6; + memcpy (&new->un_address.addr.v6, pEncap->value, 16); + have_vnc_tunnel_un = 1; break; default: - zlog_warn ("%s: unknown Encap Attribute option type %d", - __func__, pEncap->type); - - - break; + zlog_warn + ("%s: invalid tunnel subtlv UN addr length (%d) for bi %p", + __func__, pEncap->length, bi); } - } + break; - new->un_options = rfapi_encap_tlv_to_un_option (bi->attr); + default: + zlog_warn ("%s: unknown Encap Attribute option type %d", + __func__, pEncap->type); + + + break; + } + } + + new->un_options = rfapi_encap_tlv_to_un_option (bi->attr); #if DEBUG_ENCAP_MONITOR - vnc_zlog_debug_verbose ("%s: line %d: have_vnc_tunnel_un=%d", - __func__, __LINE__, have_vnc_tunnel_un); + vnc_zlog_debug_verbose ("%s: line %d: have_vnc_tunnel_un=%d", + __func__, __LINE__, have_vnc_tunnel_un); #endif - if (!have_vnc_tunnel_un && bi && bi->extra) + if (!have_vnc_tunnel_un && bi && bi->extra) + { + /* + * use cached UN address from ENCAP route + */ + new->un_address.addr_family = bi->extra->vnc.import.un_family; + switch (new->un_address.addr_family) { - /* - * use cached UN address from ENCAP route - */ - new->un_address.addr_family = bi->extra->vnc.import.un_family; - switch (new->un_address.addr_family) - { - case AF_INET: - new->un_address.addr.v4 = bi->extra->vnc.import.un.addr4; - break; - case AF_INET6: - new->un_address.addr.v6 = bi->extra->vnc.import.un.addr6; - break; - default: - zlog_warn ("%s: invalid UN addr family (%d) for bi %p", - __func__, new->un_address.addr_family, bi); - rfapi_free_next_hop_list (new); - return NULL; - break; - } + case AF_INET: + new->un_address.addr.v4 = bi->extra->vnc.import.un.addr4; + break; + case AF_INET6: + new->un_address.addr.v6 = bi->extra->vnc.import.un.addr6; + break; + default: + zlog_warn ("%s: invalid UN addr family (%d) for bi %p", + __func__, new->un_address.addr_family, bi); + rfapi_free_next_hop_list (new); + return NULL; + break; } } } + new->lifetime = lifetime; return new; } @@ -2702,19 +2695,18 @@ rfapiNexthop2Prefix (struct attr *attr, struct prefix *p) { assert (p); assert (attr); - assert (attr->extra); memset (p, 0, sizeof (struct prefix)); - switch (p->family = BGP_MP_NEXTHOP_FAMILY (attr->extra->mp_nexthop_len)) + switch (p->family = BGP_MP_NEXTHOP_FAMILY (attr->mp_nexthop_len)) { case AF_INET: - p->u.prefix4 = attr->extra->mp_nexthop_global_in; + p->u.prefix4 = attr->mp_nexthop_global_in; p->prefixlen = 32; break; case AF_INET6: - p->u.prefix6 = attr->extra->mp_nexthop_global; + p->u.prefix6 = attr->mp_nexthop_global; p->prefixlen = 128; break; @@ -2779,9 +2771,7 @@ rfapiAttrNexthopAddrDifferent (struct prefix *p1, struct prefix *p2) static void rfapiCopyUnEncap2VPN (struct bgp_info *encap_bi, struct bgp_info *vpn_bi) { - struct attr_extra *attre; - - if (!encap_bi->attr || !encap_bi->attr->extra) + if (!encap_bi->attr) { zlog_warn ("%s: no encap bi attr/extra, can't copy UN address", __func__); @@ -2795,9 +2785,7 @@ rfapiCopyUnEncap2VPN (struct bgp_info *encap_bi, struct bgp_info *vpn_bi) return; } - attre = encap_bi->attr->extra; - - switch (BGP_MP_NEXTHOP_FAMILY (attre->mp_nexthop_len)) + switch (BGP_MP_NEXTHOP_FAMILY (encap_bi->attr->mp_nexthop_len)) { case AF_INET: @@ -2811,17 +2799,17 @@ rfapiCopyUnEncap2VPN (struct bgp_info *encap_bi, struct bgp_info *vpn_bi) } vpn_bi->extra->vnc.import.un_family = AF_INET; - vpn_bi->extra->vnc.import.un.addr4 = attre->mp_nexthop_global_in; + vpn_bi->extra->vnc.import.un.addr4 = encap_bi->attr->mp_nexthop_global_in; break; case AF_INET6: vpn_bi->extra->vnc.import.un_family = AF_INET6; - vpn_bi->extra->vnc.import.un.addr6 = attre->mp_nexthop_global; + vpn_bi->extra->vnc.import.un.addr6 = encap_bi->attr->mp_nexthop_global; break; default: zlog_warn ("%s: invalid encap nexthop length: %d", - __func__, attre->mp_nexthop_len); + __func__, encap_bi->attr->mp_nexthop_len); vpn_bi->extra->vnc.import.un_family = 0; break; } @@ -3102,21 +3090,21 @@ rfapiExpireEncapNow ( static int rfapiGetNexthop (struct attr *attr, struct prefix *prefix) { - switch (BGP_MP_NEXTHOP_FAMILY (attr->extra->mp_nexthop_len)) + switch (BGP_MP_NEXTHOP_FAMILY (attr->mp_nexthop_len)) { case AF_INET: prefix->family = AF_INET; prefix->prefixlen = 32; - prefix->u.prefix4 = attr->extra->mp_nexthop_global_in; + prefix->u.prefix4 = attr->mp_nexthop_global_in; break; case AF_INET6: prefix->family = AF_INET6; prefix->prefixlen = 128; - prefix->u.prefix6 = attr->extra->mp_nexthop_global; + prefix->u.prefix6 = attr->mp_nexthop_global; break; default: - vnc_zlog_debug_verbose ("%s: unknown attr->extra->mp_nexthop_len %d", __func__, - attr->extra->mp_nexthop_len); + vnc_zlog_debug_verbose ("%s: unknown attr->mp_nexthop_len %d", __func__, + attr->mp_nexthop_len); return EINVAL; } return 0; @@ -3187,7 +3175,7 @@ rfapiBgpInfoFilteredImportEncap ( * On a withdraw, peer and RD are sufficient to determine if * we should act. */ - if (!attr || !attr->extra || !attr->extra->ecommunity) + if (!attr || !attr->ecommunity) { vnc_zlog_debug_verbose ("%s: attr, extra, or ecommunity missing, not importing", @@ -3195,7 +3183,7 @@ rfapiBgpInfoFilteredImportEncap ( return; } #if RFAPI_REQUIRE_ENCAP_BEEC - if (!rfapiEcommunitiesMatchBeec (attr->extra->ecommunity)) + if (!rfapiEcommunitiesMatchBeec (attr->ecommunity)) { vnc_zlog_debug_verbose ("%s: it=%p: no match for BGP Encapsulation ecommunity", __func__, import_table); @@ -3203,7 +3191,7 @@ rfapiBgpInfoFilteredImportEncap ( } #endif if (!rfapiEcommunitiesIntersect (import_table->rt_import_list, - attr->extra->ecommunity)) + attr->ecommunity)) { vnc_zlog_debug_verbose ("%s: it=%p: no ecommunity intersection", @@ -3669,7 +3657,7 @@ rfapiBgpInfoFilteredImportVPN ( */ if (action == FIF_ACTION_UPDATE) { - if (!attr || !attr->extra || !attr->extra->ecommunity) + if (!attr || !attr->ecommunity) { vnc_zlog_debug_verbose ("%s: attr, extra, or ecommunity missing, not importing", @@ -3678,7 +3666,7 @@ rfapiBgpInfoFilteredImportVPN ( } if ((import_table != bgp->rfapi->it_ce) && !rfapiEcommunitiesIntersect (import_table->rt_import_list, - attr->extra->ecommunity)) + attr->ecommunity)) { vnc_zlog_debug_verbose ("%s: it=%p: no ecommunity intersection", @@ -4162,12 +4150,12 @@ rfapiProcessUpdate ( * Find rt containing LNI (Logical Network ID), which * _should_ always be present when mac address is present */ - rc = rfapiEcommunityGetLNI (attr->extra->ecommunity, &lni); + rc = rfapiEcommunityGetLNI (attr->ecommunity, &lni); vnc_zlog_debug_verbose - ("%s: rfapiEcommunityGetLNI returned %d, lni=%d, attr=%p, attr->extra=%p", - __func__, rc, lni, attr, attr->extra); - if (attr && attr->extra && !rc) + ("%s: rfapiEcommunityGetLNI returned %d, lni=%d, attr=%p", + __func__, rc, lni, attr); + if (attr && !rc) { it = rfapiMacImportTableGet (bgp, lni); diff --git a/bgpd/rfapi/rfapi_rib.c b/bgpd/rfapi/rfapi_rib.c index 5c3976a0c1..563c862381 100644 --- a/bgpd/rfapi/rfapi_rib.c +++ b/bgpd/rfapi/rfapi_rib.c @@ -664,7 +664,7 @@ rfapiRibBi2Ri( ri->lifetime = lifetime; /* This loop based on rfapiRouteInfo2NextHopEntry() */ - for (pEncap = bi->attr->extra->vnc_subtlvs; pEncap; pEncap = pEncap->next) + for (pEncap = bi->attr->vnc_subtlvs; pEncap; pEncap = pEncap->next) { struct bgp_tea_options *hop; @@ -723,11 +723,11 @@ rfapiRibBi2Ri( memcpy (&vo->v.l2addr.macaddr, bi->extra->vnc.import.rd.val+2, ETHER_ADDR_LEN); - if (bi->attr && bi->attr->extra) + if (bi->attr) { - (void) rfapiEcommunityGetLNI (bi->attr->extra->ecommunity, + (void) rfapiEcommunityGetLNI (bi->attr->ecommunity, &vo->v.l2addr.logical_net_id); - (void) rfapiEcommunityGetEthernetTag (bi->attr->extra->ecommunity, + (void) rfapiEcommunityGetEthernetTag (bi->attr->ecommunity, &vo->v.l2addr.tag_id); } diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c index d12958a600..81e307d86f 100644 --- a/bgpd/rfapi/rfapi_vty.c +++ b/bgpd/rfapi/rfapi_vty.c @@ -469,9 +469,9 @@ rfapi_vty_out_vncinfo ( } } - if (bi->attr && bi->attr->extra && bi->attr->extra->ecommunity) + if (bi->attr && bi->attr->ecommunity) { - s = ecommunity_ecom2str (bi->attr->extra->ecommunity, + s = ecommunity_ecom2str (bi->attr->ecommunity, ECOMMUNITY_FORMAT_ROUTE_MAP, 0); vty_out (vty, " EC{%s}", s); XFREE (MTYPE_ECOMMUNITY_STR, s); @@ -499,7 +499,6 @@ rfapiPrintAttrPtrs (void *stream, struct attr *attr) void *out; const char *vty_newline; - struct attr_extra *ae; char buf[BUFSIZ]; if (rfapiStream2Vty (stream, &fp, &vty, &out, &vty_newline) == 0) @@ -518,15 +517,12 @@ rfapiPrintAttrPtrs (void *stream, struct attr *attr) fp (out, " community=%p, refcnt=%d%s", attr->community, (attr->community ? attr->community->refcnt : 0), HVTYNL); - if ((ae = attr->extra)) - { - fp (out, " ecommunity=%p, refcnt=%d%s", ae->ecommunity, - (ae->ecommunity ? ae->ecommunity->refcnt : 0), HVTYNL); - fp (out, " cluster=%p, refcnt=%d%s", ae->cluster, - (ae->cluster ? ae->cluster->refcnt : 0), HVTYNL); - fp (out, " transit=%p, refcnt=%d%s", ae->transit, - (ae->transit ? ae->transit->refcnt : 0), HVTYNL); - } + fp (out, " ecommunity=%p, refcnt=%d%s", attr->ecommunity, + (attr->ecommunity ? attr->ecommunity->refcnt : 0), HVTYNL); + fp (out, " cluster=%p, refcnt=%d%s", attr->cluster, + (attr->cluster ? attr->cluster->refcnt : 0), HVTYNL); + fp (out, " transit=%p, refcnt=%d%s", attr->transit, + (attr->transit ? attr->transit->refcnt : 0), HVTYNL); } /* @@ -593,26 +589,26 @@ rfapiPrintBi (void *stream, struct bgp_info *bi) * RFP option sizes (they are opaque values) * extended communities (RTs) */ - if (bi->attr && bi->attr->extra) + if (bi->attr) { uint32_t lifetime; int printed_1st_gol = 0; struct bgp_attr_encap_subtlv *pEncap; struct prefix pfx_un; - int af = BGP_MP_NEXTHOP_FAMILY (bi->attr->extra->mp_nexthop_len); + int af = BGP_MP_NEXTHOP_FAMILY (bi->attr->mp_nexthop_len); /* Nexthop */ if (af == AF_INET) { r = snprintf (p, REMAIN, "%s", inet_ntop (AF_INET, - &bi->attr->extra->mp_nexthop_global_in, + &bi->attr->mp_nexthop_global_in, buf, BUFSIZ)); INCP; } else if (af == AF_INET6) { r = snprintf (p, REMAIN, "%s", inet_ntop (AF_INET6, - &bi->attr->extra->mp_nexthop_global, + &bi->attr->mp_nexthop_global, buf, BUFSIZ)); INCP; } @@ -650,7 +646,7 @@ rfapiPrintBi (void *stream, struct bgp_info *bi) } /* RFP option lengths */ - for (pEncap = bi->attr->extra->vnc_subtlvs; pEncap; + for (pEncap = bi->attr->vnc_subtlvs; pEncap; pEncap = pEncap->next) { @@ -673,9 +669,9 @@ rfapiPrintBi (void *stream, struct bgp_info *bi) } /* RT list */ - if (bi->attr->extra->ecommunity) + if (bi->attr->ecommunity) { - s = ecommunity_ecom2str (bi->attr->extra->ecommunity, + s = ecommunity_ecom2str (bi->attr->ecommunity, ECOMMUNITY_FORMAT_ROUTE_MAP, 0); r = snprintf (p, REMAIN, " %s", s); INCP; @@ -704,9 +700,9 @@ rfapiPrintBi (void *stream, struct bgp_info *bi) if (bi->attr) { - if (bi->attr->extra) + if (bi->attr->weight) { - r = snprintf (p, REMAIN, " W=%d", bi->attr->extra->weight); + r = snprintf (p, REMAIN, " W=%d", bi->attr->weight); INCP; } diff --git a/bgpd/rfapi/vnc_export_bgp.c b/bgpd/rfapi/vnc_export_bgp.c index bca95e47c0..342dc6a193 100644 --- a/bgpd/rfapi/vnc_export_bgp.c +++ b/bgpd/rfapi/vnc_export_bgp.c @@ -74,7 +74,6 @@ encap_attr_export_ce ( */ memset (new, 0, sizeof (struct attr)); bgp_attr_dup (new, orig); - bgp_attr_extra_get (new); /* * Set nexthop @@ -83,17 +82,13 @@ encap_attr_export_ce ( { case AF_INET: new->nexthop = use_nexthop->u.prefix4; - new->extra->mp_nexthop_len = 4; /* bytes */ + new->mp_nexthop_len = 4; /* bytes */ new->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); break; case AF_INET6: - if (!new->extra) - { - new->extra = XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra)); - } - new->extra->mp_nexthop_global = use_nexthop->u.prefix6; - new->extra->mp_nexthop_len = 16; /* bytes */ + new->mp_nexthop_global = use_nexthop->u.prefix6; + new->mp_nexthop_len = 16; /* bytes */ break; default: @@ -133,7 +128,6 @@ encap_attr_export_ce ( * * Caller should, after using the attr, call: * - bgp_attr_flush() to free non-interned parts - * - call bgp_attr_extra_free() to free extra */ } @@ -144,8 +138,8 @@ getce (struct bgp *bgp, struct attr *attr, struct prefix *pfx_ce) int i; uint16_t localadmin = bgp->rfapi_cfg->resolve_nve_roo_local_admin; - for (ecp = attr->extra->ecommunity->val, i = 0; - i < attr->extra->ecommunity->size; ++i, ecp += ECOMMUNITY_SIZE) + for (ecp = attr->ecommunity->val, i = 0; + i < attr->ecommunity->size; ++i, ecp += ECOMMUNITY_SIZE) { if (VNC_DEBUG(EXPORT_BGP_GETCE)) @@ -309,14 +303,12 @@ vnc_direct_bgp_add_route_ce ( if (ret == RMAP_DENYMATCH) { bgp_attr_flush (&hattr); - bgp_attr_extra_free (&hattr); return; } } iattr = bgp_attr_intern (&hattr); bgp_attr_flush (&hattr); - bgp_attr_extra_free (&hattr); /* * Rule: disallow route-map alteration of next-hop, because it @@ -563,14 +555,14 @@ vnc_route_origin_ecom (struct route_node *rn) struct ecommunity_val roec; - switch (BGP_MP_NEXTHOP_FAMILY (bi->attr->extra->mp_nexthop_len)) + switch (BGP_MP_NEXTHOP_FAMILY (bi->attr->mp_nexthop_len)) { case AF_INET: memset (&roec, 0, sizeof (roec)); roec.val[0] = 0x01; roec.val[1] = 0x03; memcpy (roec.val + 2, - &bi->attr->extra->mp_nexthop_global_in.s_addr, 4); + &bi->attr->mp_nexthop_global_in.s_addr, 4); roec.val[6] = 0; roec.val[7] = 0; ecommunity_add_val (new, &roec); @@ -642,16 +634,16 @@ encap_attr_export ( { use_nexthop = &orig_nexthop; orig_nexthop.family = - BGP_MP_NEXTHOP_FAMILY (orig->extra->mp_nexthop_len); + BGP_MP_NEXTHOP_FAMILY (orig->mp_nexthop_len); if (orig_nexthop.family == AF_INET) { orig_nexthop.prefixlen = 32; - orig_nexthop.u.prefix4 = orig->extra->mp_nexthop_global_in; + orig_nexthop.u.prefix4 = orig->mp_nexthop_global_in; } else if (orig_nexthop.family == AF_INET6) { orig_nexthop.prefixlen = 128; - orig_nexthop.u.prefix6 = orig->extra->mp_nexthop_global; + orig_nexthop.u.prefix6 = orig->mp_nexthop_global; } else { @@ -673,17 +665,13 @@ encap_attr_export ( { case AF_INET: new->nexthop = use_nexthop->u.prefix4; - new->extra->mp_nexthop_len = 4; /* bytes */ + new->mp_nexthop_len = 4; /* bytes */ new->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); break; case AF_INET6: - if (!new->extra) - { - new->extra = XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra)); - } - new->extra->mp_nexthop_global = use_nexthop->u.prefix6; - new->extra->mp_nexthop_len = 16; /* bytes */ + new->mp_nexthop_global = use_nexthop->u.prefix6; + new->mp_nexthop_len = 16; /* bytes */ break; default: @@ -691,7 +679,6 @@ encap_attr_export ( break; } - bgp_attr_extra_get (new); if (rn) { ecom_ro = vnc_route_origin_ecom (rn); @@ -701,17 +688,14 @@ encap_attr_export ( /* TBD test/assert for IPv6 */ ecom_ro = vnc_route_origin_ecom_single (&use_nexthop->u.prefix4); } - if (new->extra->ecommunity) + if (new->ecommunity) { if (ecom_ro) - { - new->extra->ecommunity = - ecommunity_merge (ecom_ro, new->extra->ecommunity); - } + new->ecommunity = ecommunity_merge (ecom_ro, new->ecommunity); } else { - new->extra->ecommunity = ecom_ro; + new->ecommunity = ecom_ro; } if (ecom_ro) { @@ -750,7 +734,6 @@ encap_attr_export ( * * Caller should, after using the attr, call: * - bgp_attr_flush() to free non-interned parts - * - call bgp_attr_extra_free() to free extra */ return 0; @@ -887,7 +870,6 @@ vnc_direct_bgp_add_prefix ( if (ret == RMAP_DENYMATCH) { bgp_attr_flush (&hattr); - bgp_attr_extra_free (&hattr); vnc_zlog_debug_verbose ("%s: route map says DENY, so not calling bgp_update", __func__); @@ -903,7 +885,6 @@ vnc_direct_bgp_add_prefix ( iattr = bgp_attr_intern (&hattr); bgp_attr_flush (&hattr); - bgp_attr_extra_free (&hattr); bgp_update (irfd->peer, &rn->p, /* prefix */ 0, /* addpath_id */ @@ -917,7 +898,6 @@ vnc_direct_bgp_add_prefix ( } aspath_unintern (&attr.aspath); - bgp_attr_extra_free (&attr); } /* @@ -1134,7 +1114,6 @@ vnc_direct_bgp_add_nve (struct bgp *bgp, struct rfapi_descriptor *rfd) if (ret == RMAP_DENYMATCH) { bgp_attr_flush (&hattr); - bgp_attr_extra_free (&hattr); continue; } @@ -1142,7 +1121,6 @@ vnc_direct_bgp_add_nve (struct bgp *bgp, struct rfapi_descriptor *rfd) iattr = bgp_attr_intern (&hattr); bgp_attr_flush (&hattr); - bgp_attr_extra_free (&hattr); bgp_update (irfd->peer, &rn->p, /* prefix */ 0, /* addpath_id */ @@ -1157,7 +1135,6 @@ vnc_direct_bgp_add_nve (struct bgp *bgp, struct rfapi_descriptor *rfd) } aspath_unintern (&attr.aspath); - bgp_attr_extra_free (&attr); } } } @@ -1361,7 +1338,6 @@ vnc_direct_bgp_add_group_afi ( if (ret == RMAP_DENYMATCH) { bgp_attr_flush (&hattr); - bgp_attr_extra_free (&hattr); continue; } @@ -1369,7 +1345,6 @@ vnc_direct_bgp_add_group_afi ( iattr = bgp_attr_intern (&hattr); bgp_attr_flush (&hattr); - bgp_attr_extra_free (&hattr); bgp_update (irfd->peer, &rn->p, /* prefix */ 0, /* addpath_id */ @@ -1384,7 +1359,6 @@ vnc_direct_bgp_add_group_afi ( } aspath_unintern (&attr.aspath); - bgp_attr_extra_free (&attr); } @@ -1744,14 +1718,12 @@ vnc_direct_bgp_rh_add_route ( if (ret == RMAP_DENYMATCH) { bgp_attr_flush (&hattr); - bgp_attr_extra_free (&hattr); return; } } iattr = bgp_attr_intern (&hattr); bgp_attr_flush (&hattr); - bgp_attr_extra_free (&hattr); /* * record route information that we will need to expire @@ -1983,7 +1955,6 @@ vnc_direct_bgp_rh_vpn_enable (struct bgp *bgp, afi_t afi) if (ret == RMAP_DENYMATCH) { bgp_attr_flush (&hattr); - bgp_attr_extra_free (&hattr); vnc_zlog_debug_verbose ("%s: route map says DENY", __func__); continue; } @@ -1991,7 +1962,6 @@ vnc_direct_bgp_rh_vpn_enable (struct bgp *bgp, afi_t afi) iattr = bgp_attr_intern (&hattr); bgp_attr_flush (&hattr); - bgp_attr_extra_free (&hattr); /* * record route information that we will need to expire diff --git a/bgpd/rfapi/vnc_import_bgp.c b/bgpd/rfapi/vnc_import_bgp.c index 47203cd238..1daf02a6bf 100644 --- a/bgpd/rfapi/vnc_import_bgp.c +++ b/bgpd/rfapi/vnc_import_bgp.c @@ -393,7 +393,6 @@ process_unicast_route ( if (ret == RMAP_DENYMATCH) { bgp_attr_flush (&hattr); - bgp_attr_extra_free (&hattr); vnc_zlog_debug_verbose ("%s: route map \"%s\" says DENY, returning", __func__, rmap->name); return -1; @@ -406,8 +405,8 @@ process_unicast_route ( */ rfapiUnicastNexthop2Prefix (afi, &hattr, unicast_nexthop); - if (hattr.extra && hattr.extra->ecommunity) - *ecom = ecommunity_dup (hattr.extra->ecommunity); + if (hattr.ecommunity) + *ecom = ecommunity_dup (hattr.ecommunity); else *ecom = ecommunity_new (); @@ -415,7 +414,6 @@ process_unicast_route ( * Done with hattr, clean up */ bgp_attr_flush (&hattr); - bgp_attr_extra_free (&hattr); /* * Add EC that carries original NH of iBGP route (2 bytes = magic @@ -510,18 +508,18 @@ vnc_import_bgp_add_route_mode_resolve_nve_one_bi ( plifetime = &lifetime; } - if (bi->attr && bi->attr->extra) + if (bi->attr) { - encaptlvs = bi->attr->extra->vnc_subtlvs; - if (bi->attr->extra->encap_tunneltype != BGP_ENCAP_TYPE_RESERVED && - bi->attr->extra->encap_tunneltype != BGP_ENCAP_TYPE_MPLS) + encaptlvs = bi->attr->vnc_subtlvs; + if (bi->attr->encap_tunneltype != BGP_ENCAP_TYPE_RESERVED && + bi->attr->encap_tunneltype != BGP_ENCAP_TYPE_MPLS) { if (opt != NULL) opt->next = &optary[cur_opt]; opt = &optary[cur_opt++]; memset (opt, 0, sizeof (struct rfapi_un_option)); opt->type = RFAPI_UN_OPTION_TYPE_TUNNELTYPE; - opt->v.tunnel.type = bi->attr->extra->encap_tunneltype; + opt->v.tunnel.type = bi->attr->encap_tunneltype; /* TBD parse bi->attr->extra->encap_subtlvs */ } } @@ -532,8 +530,8 @@ vnc_import_bgp_add_route_mode_resolve_nve_one_bi ( struct ecommunity *new_ecom = ecommunity_dup (ecom); - if (bi->attr && bi->attr->extra && bi->attr->extra->ecommunity) - ecommunity_merge (new_ecom, bi->attr->extra->ecommunity); + if (bi->attr && bi->attr->ecommunity) + ecommunity_merge (new_ecom, bi->attr->ecommunity); if (bi->extra) label = decode_label (&bi->extra->label); @@ -891,7 +889,6 @@ vnc_import_bgp_add_route_mode_plain (struct bgp *bgp, if (ret == RMAP_DENYMATCH) { bgp_attr_flush (&hattr); - bgp_attr_extra_free (&hattr); vnc_zlog_debug_verbose ("%s: route map \"%s\" says DENY, returning", __func__, rmap->name); return; @@ -900,7 +897,6 @@ vnc_import_bgp_add_route_mode_plain (struct bgp *bgp, iattr = bgp_attr_intern (&hattr); bgp_attr_flush (&hattr); - bgp_attr_extra_free (&hattr); /* Now iattr is an allocated interned attr */ @@ -925,8 +921,8 @@ vnc_import_bgp_add_route_mode_plain (struct bgp *bgp, memset (&prd, 0, sizeof (prd)); rfapi_set_autord_from_vn (&prd, &vnaddr); - if (iattr && iattr->extra && iattr->extra->ecommunity) - ecom = ecommunity_dup (iattr->extra->ecommunity); + if (iattr && iattr->ecommunity) + ecom = ecommunity_dup (iattr->ecommunity); } @@ -1103,7 +1099,6 @@ vnc_import_bgp_add_route_mode_nvegroup (struct bgp *bgp, if (ret == RMAP_DENYMATCH) { bgp_attr_flush (&hattr); - bgp_attr_extra_free (&hattr); vnc_zlog_debug_verbose ("%s: route map \"%s\" says DENY, returning", __func__, rmap->name); return; @@ -1112,7 +1107,6 @@ vnc_import_bgp_add_route_mode_nvegroup (struct bgp *bgp, iattr = bgp_attr_intern (&hattr); bgp_attr_flush (&hattr); - bgp_attr_extra_free (&hattr); /* Now iattr is an allocated interned attr */ @@ -1139,8 +1133,8 @@ vnc_import_bgp_add_route_mode_nvegroup (struct bgp *bgp, else ecom = ecommunity_new (); - if (iattr && iattr->extra && iattr->extra->ecommunity) - ecom = ecommunity_merge (ecom, iattr->extra->ecommunity); + if (iattr && iattr->ecommunity) + ecom = ecommunity_merge (ecom, iattr->ecommunity); } local_pref = calc_local_pref (iattr, peer); @@ -1942,7 +1936,6 @@ vnc_import_bgp_exterior_add_route_it ( ZEBRA_ROUTE_BGP_DIRECT_EXT, BGP_ROUTE_REDISTRIBUTE, &label); - bgp_attr_extra_free (&new_attr); } if (have_usable_route) @@ -2273,7 +2266,6 @@ vnc_import_bgp_exterior_add_route_interior ( ZEBRA_ROUTE_BGP_DIRECT_EXT, BGP_ROUTE_REDISTRIBUTE, &label); - bgp_attr_extra_free (&new_attr); } vnc_zlog_debug_verbose ("%s: finished constructing exteriors based on existing monitors", @@ -2412,7 +2404,6 @@ vnc_import_bgp_exterior_add_route_interior ( ZEBRA_ROUTE_BGP_DIRECT_EXT, BGP_ROUTE_REDISTRIBUTE, &label); - bgp_attr_extra_free (&new_attr); } } @@ -2536,7 +2527,6 @@ vnc_import_bgp_exterior_add_route_interior ( ZEBRA_ROUTE_BGP_DIRECT_EXT, BGP_ROUTE_REDISTRIBUTE, &label); - bgp_attr_extra_free (&new_attr); } } if (list_adopted) @@ -2740,7 +2730,6 @@ vnc_import_bgp_exterior_del_route_interior ( ZEBRA_ROUTE_BGP_DIRECT_EXT, BGP_ROUTE_REDISTRIBUTE, &label); - bgp_attr_extra_free (&new_attr); } } From 8c19712819711a8fa09770b500963250e55cf9c9 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 14 Jul 2017 08:08:52 -0400 Subject: [PATCH 30/31] bgpd: Disable new EVPN CLI Signed-off-by: Donald Sharp --- bgpd/bgp_evpn_vty.c | 9 ++++++++- bgpd/bgp_route.c | 4 ++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index c533151ba7..5ad2fa0ddb 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -55,6 +55,7 @@ struct evpn_config_write struct vty *vty; }; +#if defined (HAVE_CUMULUS) static void display_import_rt (struct vty *vty, struct irt_node *irt) { @@ -339,6 +340,7 @@ show_vni_entry (struct hash_backet *backet, struct vty *vty) } vty_out (vty, "%s", VTY_NEWLINE); } +#endif /* HAVE_CUMULUS */ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd, @@ -1020,6 +1022,7 @@ DEFUN(no_evpnrt5_network, argv[idx_ethtag]->arg); } +#if defined(HAVE_CUMULUS) static void evpn_rt_delete_auto (struct bgp *bgp, struct bgpevpn *vpn, struct list *rtl) { @@ -1742,6 +1745,7 @@ evpn_unset_advertise_all_vni (struct bgp *bgp) bgp_zebra_advertise_all_vni (bgp, bgp->advertise_all_vni); bgp_evpn_cleanup_on_disable (bgp); } +#endif /* HAVE_CUMULUS */ static void write_vni_config (struct vty *vty, struct bgpevpn *vpn, int *write) @@ -1794,6 +1798,7 @@ write_vni_config_for_entry (struct hash_backet *backet, write_vni_config (cfg->vty, vpn, &cfg->write); } +#if defined (HAVE_CUMULUS) DEFUN (bgp_evpn_advertise_all_vni, bgp_evpn_advertise_all_vni_cmd, "advertise-all-vni", @@ -2597,7 +2602,7 @@ DEFUN (no_bgp_evpn_vni_rt_without_val, evpn_unconfigure_export_rt (bgp, vpn, NULL); return CMD_SUCCESS; } - +#endif /* * Output EVPN configuration information. */ @@ -2640,6 +2645,7 @@ void bgp_ethernetvpn_init(void) install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_overlay_cmd); install_element(BGP_EVPN_NODE, &no_evpnrt5_network_cmd); install_element(BGP_EVPN_NODE, &evpnrt5_network_cmd); +#if defined(HAVE_CUMULUS) install_element (BGP_EVPN_NODE, &bgp_evpn_advertise_all_vni_cmd); install_element (BGP_EVPN_NODE, &no_bgp_evpn_advertise_all_vni_cmd); @@ -2665,4 +2671,5 @@ void bgp_ethernetvpn_init(void) install_element (BGP_EVPN_VNI_NODE, &bgp_evpn_vni_rt_cmd); install_element (BGP_EVPN_VNI_NODE, &no_bgp_evpn_vni_rt_cmd); install_element (BGP_EVPN_VNI_NODE, &no_bgp_evpn_vni_rt_without_val_cmd); +#endif } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index fabea1f113..3db7dc7637 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -7209,7 +7209,9 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, { char buf[INET6_ADDRSTRLEN]; char buf1[BUFSIZ]; +#if defined(HAVE_CUMULUS) char buf2[EVPN_ROUTE_STRLEN]; +#endif struct attr *attr; int sockunion_vty_out (struct vty *, union sockunion *); time_t tbuf; @@ -8293,7 +8295,9 @@ route_vty_out_detail_header (struct vty *vty, struct bgp *bgp, struct listnode *node, *nnode; char buf1[INET6_ADDRSTRLEN]; char buf2[INET6_ADDRSTRLEN]; +#if defined(HAVE_CUMULUS) char buf3[EVPN_ROUTE_STRLEN]; +#endif int count = 0; int best = 0; int suppress = 0; From 2850f0ea580764393ae1253ef87a57d772dafafd Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 14 Jul 2017 08:52:45 -0400 Subject: [PATCH 31/31] bgpd, zebra: Cleanup warnings from new code 1) Clean up VTY_NEWLINE -> \n 2) Remove usages of VTY_GET_INTEGER Signed-off-by: Donald Sharp --- bgpd/bgp_evpn_vty.c | 213 +++++++++++++++++++++----------------------- bgpd/bgp_route.c | 17 ++-- zebra/debug.c | 2 +- zebra/interface.c | 22 ++--- zebra/zebra_vty.c | 24 ++--- zebra/zebra_vxlan.c | 133 ++++++++++++++------------- 6 files changed, 201 insertions(+), 210 deletions(-) diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index fc4944a6d1..b5a58f0147 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -123,12 +123,11 @@ display_import_rt (struct vty *vty, struct irt_node *irt) return; } - vty_out (vty, "%s", VTY_NEWLINE); - vty_out (vty, "List of VNIs importing routes with this route-target:%s", - VTY_NEWLINE); + vty_out (vty, "\n"); + vty_out (vty, "List of VNIs importing routes with this route-target:\n"); for (ALL_LIST_ELEMENTS (irt->vnis, node, nnode, tmp_vpn)) - vty_out (vty, " %u%s", tmp_vpn->vni, VTY_NEWLINE); + vty_out (vty, " %u\n", tmp_vpn->vni); } static void @@ -170,25 +169,22 @@ bgp_evpn_show_route_rd_header (struct vty *vty, struct bgp_node *rd_rn) break; } - vty_out (vty, "%s", VTY_NEWLINE); + vty_out (vty, "\n"); } static void bgp_evpn_show_route_header (struct vty *vty, struct bgp *bgp) { - char ri_header[] = " Network Next Hop Metric LocPrf Weight Path%s"; + char ri_header[] = " Network Next Hop Metric LocPrf Weight Path\n"; - vty_out (vty, "BGP table version is 0, local router ID is %s%s", - inet_ntoa (bgp->router_id), VTY_NEWLINE); + vty_out (vty, "BGP table version is 0, local router ID is %s\n", + inet_ntoa (bgp->router_id)); vty_out (vty, "Status codes: s suppressed, d damped, h history, " - "* valid, > best, i - internal%s", VTY_NEWLINE); - vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s", - VTY_NEWLINE); - vty_out (vty, "EVPN type-2 prefix: [2]:[ESI]:[EthTag]:[MAClen]:[MAC]:[IPlen]:[IP]%s", - VTY_NEWLINE); - vty_out (vty, "EVPN type-3 prefix: [3]:[EthTag]:[IPlen]:[OrigIP]%s%s", - VTY_NEWLINE, VTY_NEWLINE); - vty_out (vty, ri_header, VTY_NEWLINE); + "* valid, > best, i - internal\n"); + vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete\n"); + vty_out (vty, "EVPN type-2 prefix: [2]:[ESI]:[EthTag]:[MAClen]:[MAC]:[IPlen]:[IP]\n"); + vty_out (vty, "EVPN type-3 prefix: [3]:[EthTag]:[IPlen]:[OrigIP]\n\n"); + vty_out (vty, "%s", ri_header); } static void @@ -202,27 +198,26 @@ display_vni (struct vty *vty, struct bgpevpn *vpn) vty_out (vty, "VNI: %d", vpn->vni); if (is_vni_live (vpn)) vty_out (vty, " (known to the kernel)"); - vty_out (vty, "%s", VTY_NEWLINE); + vty_out (vty, "\n"); - vty_out (vty, " RD: %s%s", - prefix_rd2str (&vpn->prd, buf1, RD_ADDRSTRLEN), - VTY_NEWLINE); - vty_out (vty, " Originator IP: %s%s", - inet_ntoa(vpn->originator_ip), VTY_NEWLINE); + vty_out (vty, " RD: %s\n", + prefix_rd2str (&vpn->prd, buf1, RD_ADDRSTRLEN)); + vty_out (vty, " Originator IP: %s\n", + inet_ntoa(vpn->originator_ip)); - vty_out (vty, " Import Route Target:%s", VTY_NEWLINE); + vty_out (vty, " Import Route Target:\n"); for (ALL_LIST_ELEMENTS (vpn->import_rtl, node, nnode, ecom)) { ecom_str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0); - vty_out (vty, " %s%s", ecom_str, VTY_NEWLINE); + vty_out (vty, " %s\n", ecom_str); XFREE (MTYPE_ECOMMUNITY_STR, ecom_str); } - vty_out (vty, " Export Route Target:%s", VTY_NEWLINE); + vty_out (vty, " Export Route Target:\n"); for (ALL_LIST_ELEMENTS (vpn->export_rtl, node, nnode, ecom)) { ecom_str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0); - vty_out (vty, " %s%s", ecom_str, VTY_NEWLINE); + vty_out (vty, " %s\n", ecom_str); XFREE (MTYPE_ECOMMUNITY_STR, ecom_str); } } @@ -273,12 +268,12 @@ show_vni_routes (struct bgp *bgp, struct bgpevpn *vpn, int type, } if (prefix_cnt == 0) - vty_out (vty, "No EVPN prefixes %sexist for this VNI%s", - type ? "(of requested type) " : "", VTY_NEWLINE); + vty_out (vty, "No EVPN prefixes %sexist for this VNI\n", + type ? "(of requested type) " : ""); else - vty_out (vty, "%sDisplayed %u prefixes (%u paths)%s%s", - VTY_NEWLINE, prefix_cnt, path_cnt, - type ? " (of requested type)" : "", VTY_NEWLINE); + vty_out (vty, "\nDisplayed %u prefixes (%u paths)%s\n", + prefix_cnt, path_cnt, + type ? " (of requested type)" : ""); } static void @@ -288,7 +283,7 @@ show_vni_routes_hash (struct hash_backet *backet, void *arg) struct vni_walk_ctx *wctx = arg; struct vty *vty = wctx->vty; - vty_out (vty, "%sVNI: %d%s%s", VTY_NEWLINE, vpn->vni, VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, "\nVNI: %d\n\n", vpn->vni); show_vni_routes (wctx->bgp, vpn, 0, wctx->vty, wctx->vtep_ip); } @@ -338,7 +333,7 @@ show_vni_entry (struct hash_backet *backet, struct vty *vty) XFREE (MTYPE_ECOMMUNITY_STR, ecom_str); break; } - vty_out (vty, "%s", VTY_NEWLINE); + vty_out (vty, "\n"); } #endif /* HAVE_CUMULUS */ @@ -1385,7 +1380,7 @@ evpn_show_route_vni_multicast (struct vty *vty, struct bgp *bgp, vpn = bgp_evpn_lookup_vni (bgp, vni); if (!vpn) { - vty_out (vty, "VNI not found%s", VTY_NEWLINE); + vty_out (vty, "VNI not found\n"); return; } @@ -1394,7 +1389,7 @@ evpn_show_route_vni_multicast (struct vty *vty, struct bgp *bgp, rn = bgp_node_lookup (vpn->route_table, (struct prefix *)&p); if (!rn || !rn->info) { - vty_out (vty, "%% Network not in table%s", VTY_NEWLINE); + vty_out (vty, "%% Network not in table\n"); return; } @@ -1408,8 +1403,8 @@ evpn_show_route_vni_multicast (struct vty *vty, struct bgp *bgp, path_cnt++; } - vty_out (vty, "%sDisplayed %u paths for requested prefix%s", - VTY_NEWLINE, path_cnt, VTY_NEWLINE); + vty_out (vty, "\nDisplayed %u paths for requested prefix\n", + path_cnt); } /* @@ -1436,7 +1431,7 @@ evpn_show_route_vni_macip (struct vty *vty, struct bgp *bgp, vpn = bgp_evpn_lookup_vni (bgp, vni); if (!vpn) { - vty_out (vty, "VNI not found%s", VTY_NEWLINE); + vty_out (vty, "VNI not found\n"); return; } @@ -1445,7 +1440,7 @@ evpn_show_route_vni_macip (struct vty *vty, struct bgp *bgp, rn = bgp_node_lookup (vpn->route_table, (struct prefix *)&p); if (!rn || !rn->info) { - vty_out (vty, "%% Network not in table%s", VTY_NEWLINE); + vty_out (vty, "%% Network not in table\n"); return; } @@ -1459,8 +1454,8 @@ evpn_show_route_vni_macip (struct vty *vty, struct bgp *bgp, path_cnt++; } - vty_out (vty, "%sDisplayed %u paths for requested prefix%s", - VTY_NEWLINE, path_cnt, VTY_NEWLINE); + vty_out (vty, "\nDisplayed %u paths for requested prefix\n", + path_cnt); } /* @@ -1478,7 +1473,7 @@ evpn_show_routes_vni (struct vty *vty, struct bgp *bgp, vpn = bgp_evpn_lookup_vni (bgp, vni); if (!vpn) { - vty_out (vty, "VNI not found%s", VTY_NEWLINE); + vty_out (vty, "VNI not found\n"); return; } @@ -1512,7 +1507,7 @@ evpn_show_route_rd_macip (struct vty *vty, struct bgp *bgp, (struct prefix *)&p, prd); if (!rn || !rn->info) { - vty_out (vty, "%% Network not in table%s", VTY_NEWLINE); + vty_out (vty, "%% Network not in table\n"); return; } @@ -1526,8 +1521,8 @@ evpn_show_route_rd_macip (struct vty *vty, struct bgp *bgp, path_cnt++; } - vty_out (vty, "%sDisplayed %u paths for requested prefix%s", - VTY_NEWLINE, path_cnt, VTY_NEWLINE); + vty_out (vty, "\nDisplayed %u paths for requested prefix\n", + path_cnt); } /* @@ -1573,9 +1568,9 @@ evpn_show_route_rd (struct vty *vty, struct bgp *bgp, if (rd_header) { vty_out (vty, "EVPN type-2 prefix: [2]:[ESI]:[EthTag]:[MAClen]:" - "[MAC]%s", VTY_NEWLINE); + "[MAC]\n"); vty_out (vty, "EVPN type-3 prefix: [3]:[EthTag]:[IPlen]:" - "[OrigIP]%s%s", VTY_NEWLINE, VTY_NEWLINE); + "[OrigIP]\n\n"); rd_header = 0; } @@ -1594,12 +1589,12 @@ evpn_show_route_rd (struct vty *vty, struct bgp *bgp, } if (prefix_cnt == 0) - vty_out (vty, "No prefixes exist with this RD%s%s", - type ? " (of requested type)" : "", VTY_NEWLINE); + vty_out (vty, "No prefixes exist with this RD%s\n", + type ? " (of requested type)" : ""); else - vty_out (vty, "%sDisplayed %u prefixes (%u paths) with this RD%s%s", - VTY_NEWLINE, prefix_cnt, path_cnt, - type ? " (of requested type)" : "", VTY_NEWLINE); + vty_out (vty, "\nDisplayed %u prefixes (%u paths) with this RD%s\n", + prefix_cnt, path_cnt, + type ? " (of requested type)" : ""); } /* @@ -1675,12 +1670,12 @@ evpn_show_all_routes (struct vty *vty, struct bgp *bgp, int type) } if (prefix_cnt == 0) - vty_out (vty, "No EVPN prefixes %sexist%s", - type ? "(of requested type) " : "", VTY_NEWLINE); + vty_out (vty, "No EVPN prefixes %sexist\n", + type ? "(of requested type) " : ""); else - vty_out (vty, "%sDisplayed %u prefixes (%u paths)%s%s", - VTY_NEWLINE, prefix_cnt, path_cnt, - type ? " (of requested type)" : "", VTY_NEWLINE); + vty_out (vty, "\nDisplayed %u prefixes (%u paths)%s\n", + prefix_cnt, path_cnt, + type ? " (of requested type)" : ""); } /* @@ -1694,7 +1689,7 @@ evpn_show_vni (struct vty *vty, struct bgp *bgp, vni_t vni) vpn = bgp_evpn_lookup_vni (bgp, vni); if (!vpn) { - vty_out (vty, "VNI not found%s", VTY_NEWLINE); + vty_out (vty, "VNI not found\n"); return; } @@ -1712,11 +1707,10 @@ evpn_show_all_vnis (struct vty *vty, struct bgp *bgp) num_vnis = hashcount(bgp->vnihash); if (!num_vnis) return; - vty_out(vty, "Number of VNIs: %u%s", - num_vnis, VTY_NEWLINE); - vty_out(vty, "Flags: * - Kernel %s", VTY_NEWLINE); - vty_out(vty, " %-10s %-15s %-21s %-25s %-25s%s", - "VNI", "Orig IP", "RD", "Import RT", "Export RT", VTY_NEWLINE); + vty_out(vty, "Number of VNIs: %u\n", num_vnis); + vty_out(vty, "Flags: * - Kernel \n"); + vty_out(vty, " %-10s %-15s %-21s %-25s %-25s\n", + "VNI", "Orig IP", "RD", "Import RT", "Export RT"); hash_iterate (bgp->vnihash, (void (*) (struct hash_backet *, void *)) show_vni_entry, vty); @@ -1758,18 +1752,17 @@ write_vni_config (struct vty *vty, struct bgpevpn *vpn, int *write) if (is_vni_configured (vpn)) { bgp_config_write_family_header (vty, afi, safi, write); - vty_out (vty, " vni %d%s", vpn->vni, VTY_NEWLINE); + vty_out (vty, " vni %d\n", vpn->vni); if (is_rd_configured (vpn)) - vty_out (vty, " rd %s%s", - prefix_rd2str (&vpn->prd, buf1, RD_ADDRSTRLEN), - VTY_NEWLINE); + vty_out (vty, " rd %s\n", + prefix_rd2str (&vpn->prd, buf1, RD_ADDRSTRLEN)); if (is_import_rt_configured (vpn)) { for (ALL_LIST_ELEMENTS (vpn->import_rtl, node, nnode, ecom)) { ecom_str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0); - vty_out (vty, " route-target import %s%s", ecom_str, VTY_NEWLINE); + vty_out (vty, " route-target import %s\n", ecom_str); XFREE (MTYPE_ECOMMUNITY_STR, ecom_str); } } @@ -1779,12 +1772,12 @@ write_vni_config (struct vty *vty, struct bgpevpn *vpn, int *write) for (ALL_LIST_ELEMENTS (vpn->export_rtl, node, nnode, ecom)) { ecom_str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0); - vty_out (vty, " route-target export %s%s", ecom_str, VTY_NEWLINE); + vty_out (vty, " route-target export %s\n", ecom_str); XFREE (MTYPE_ECOMMUNITY_STR, ecom_str); } } - vty_out (vty, " exit-vni%s", VTY_NEWLINE); + vty_out (vty, " exit-vni\n"); } } @@ -1838,8 +1831,8 @@ DEFUN (show_bgp_evpn_vni, if (!bgp) return CMD_WARNING; - vty_out (vty, "Advertise All VNI flag: %s%s", - bgp->advertise_all_vni? "Enabled" : "Disabled", VTY_NEWLINE); + vty_out (vty, "Advertise All VNI flag: %s\n", + bgp->advertise_all_vni? "Enabled" : "Disabled"); evpn_show_all_vnis (vty, bgp); return CMD_SUCCESS; @@ -1861,7 +1854,7 @@ DEFUN (show_bgp_evpn_vni_num, if (!bgp) return CMD_WARNING; - VTY_GET_INTEGER_RANGE ("VNI", vni, argv[4]->arg, 1, VNI_MAX); + vni = strtoul(argv[4]->arg, NULL, 10); evpn_show_vni (vty, bgp, vni); return CMD_SUCCESS; @@ -1939,7 +1932,7 @@ DEFUN (show_bgp_evpn_route_rd, ret = str2prefix_rd (argv[5]->arg, &prd); if (! ret) { - vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + vty_out (vty, "%% Malformed Route Distinguisher\n"); return CMD_WARNING; } @@ -1984,12 +1977,12 @@ DEFUN (show_bgp_evpn_route_rd_macip, ret = str2prefix_rd (argv[5]->arg, &prd); if (! ret) { - vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + vty_out (vty, "%% Malformed Route Distinguisher\n"); return CMD_WARNING; } if (!prefix_str2mac (argv[7]->arg, &mac)) { - vty_out (vty, "%% Malformed MAC address%s", VTY_NEWLINE); + vty_out (vty, "%% Malformed MAC address\n"); return CMD_WARNING; } memset (&ip, 0, sizeof (ip)); @@ -1997,7 +1990,7 @@ DEFUN (show_bgp_evpn_route_rd_macip, { if (str2ipaddr (argv[9]->arg, &ip) != 0) { - vty_out (vty, "%% Malformed IP address%s", VTY_NEWLINE); + vty_out (vty, "%% Malformed IP address\n"); return CMD_WARNING; } } @@ -2032,7 +2025,7 @@ DEFUN (show_bgp_evpn_route_vni, vtep_ip.s_addr = 0; - VTY_GET_INTEGER_RANGE ("VNI", vni, argv[5]->arg, 1, VNI_MAX); + vni = strtoul(argv[5]->arg, NULL, 10); if (argc == 8 && argv[6]->arg) { @@ -2049,7 +2042,7 @@ DEFUN (show_bgp_evpn_route_vni, { if (!inet_aton (argv[7]->arg, &vtep_ip)) { - vty_out (vty, "%% Malformed VTEP IP address%s", VTY_NEWLINE); + vty_out (vty, "%% Malformed VTEP IP address\n"); return CMD_WARNING; } } @@ -2084,10 +2077,10 @@ DEFUN (show_bgp_evpn_route_vni_macip, if (!bgp) return CMD_WARNING; - VTY_GET_INTEGER_RANGE ("VNI", vni, argv[5]->arg, 1, VNI_MAX); + vni = strtoul(argv[5]->arg, NULL, 10); if (!prefix_str2mac (argv[7]->arg, &mac)) { - vty_out (vty, "%% Malformed MAC address%s", VTY_NEWLINE); + vty_out (vty, "%% Malformed MAC address\n"); return CMD_WARNING; } memset (&ip, 0, sizeof (ip)); @@ -2095,7 +2088,7 @@ DEFUN (show_bgp_evpn_route_vni_macip, { if (str2ipaddr (argv[9]->arg, &ip) != 0) { - vty_out (vty, "%% Malformed IP address%s", VTY_NEWLINE); + vty_out (vty, "%% Malformed IP address\n"); return CMD_WARNING; } } @@ -2125,11 +2118,11 @@ DEFUN (show_bgp_evpn_route_vni_multicast, if (!bgp) return CMD_WARNING; - VTY_GET_INTEGER_RANGE ("VNI", vni, argv[5]->arg, 1, VNI_MAX); + vni = strtoul(argv[5]->arg, NULL, 10); ret = inet_aton (argv[7]->arg, &orig_ip); if (!ret) { - vty_out (vty, "%% Malformed Originating Router IP address%s", VTY_NEWLINE); + vty_out (vty, "%% Malformed Originating Router IP address\n"); return CMD_WARNING; } @@ -2161,7 +2154,7 @@ DEFUN (show_bgp_evpn_route_vni_all, { if (!inet_aton (argv[7]->arg, &vtep_ip)) { - vty_out (vty, "%% Malformed VTEP IP address%s", VTY_NEWLINE); + vty_out (vty, "%% Malformed VTEP IP address\n"); return CMD_WARNING; } } @@ -2201,13 +2194,13 @@ DEFUN_NOSH (bgp_evpn_vni, if (!bgp) return CMD_WARNING; - VTY_GET_INTEGER_RANGE ("VNI", vni, argv[1]->arg, 1, VNI_MAX); + vni = strtoul(argv[1]->arg, NULL, 10); /* Create VNI, or mark as configured. */ vpn = evpn_create_update_vni (bgp, vni); if (!vpn) { - vty_out (vty, "%% Failed to create VNI %s", VTY_NEWLINE); + vty_out (vty, "%% Failed to create VNI \n"); return CMD_WARNING; } @@ -2229,18 +2222,18 @@ DEFUN (no_bgp_evpn_vni, if (!bgp) return CMD_WARNING; - VTY_GET_INTEGER_RANGE ("VNI", vni, argv[2]->arg, 1, VNI_MAX); + vni = strtoul(argv[2]->arg, NULL, 10); /* Check if we should disallow. */ vpn = bgp_evpn_lookup_vni (bgp, vni); if (!vpn) { - vty_out (vty, "%% Specified VNI does not exist%s", VTY_NEWLINE); + vty_out (vty, "%% Specified VNI does not exist\n"); return CMD_WARNING; } if (!is_vni_configured (vpn)) { - vty_out (vty, "%% Specified VNI is not configured%s", VTY_NEWLINE); + vty_out (vty, "%% Specified VNI is not configured\n"); return CMD_WARNING; } @@ -2275,7 +2268,7 @@ DEFUN (bgp_evpn_vni_rd, ret = str2prefix_rd (argv[1]->arg, &prd); if (! ret) { - vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + vty_out (vty, "%% Malformed Route Distinguisher\n"); return CMD_WARNING; } @@ -2306,20 +2299,20 @@ DEFUN (no_bgp_evpn_vni_rd, ret = str2prefix_rd (argv[2]->arg, &prd); if (! ret) { - vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + vty_out (vty, "%% Malformed Route Distinguisher\n"); return CMD_WARNING; } /* Check if we should disallow. */ if (!is_rd_configured (vpn)) { - vty_out (vty, "%% RD is not configured for this VNI%s", VTY_NEWLINE); + vty_out (vty, "%% RD is not configured for this VNI\n"); return CMD_WARNING; } if (!bgp_evpn_rd_matches_existing(vpn, &prd)) { - vty_out (vty, "%% RD specified does not match configuration for this VNI%s", VTY_NEWLINE); + vty_out (vty, "%% RD specified does not match configuration for this VNI\n"); return CMD_WARNING; } @@ -2342,7 +2335,7 @@ DEFUN (no_bgp_evpn_vni_rd_without_val, /* Check if we should disallow. */ if (!is_rd_configured (vpn)) { - vty_out (vty, "%% RD is not configured for this VNI%s", VTY_NEWLINE); + vty_out (vty, "%% RD is not configured for this VNI\n"); return CMD_WARNING; } @@ -2396,7 +2389,7 @@ DEFUN (bgp_evpn_vni_rt, rt_type = RT_TYPE_BOTH; else { - vty_out (vty, "%% Invalid Route Target type%s", VTY_NEWLINE); + vty_out (vty, "%% Invalid Route Target type\n"); return CMD_WARNING; } @@ -2408,7 +2401,7 @@ DEFUN (bgp_evpn_vni_rt, ecommunity_str(ecomadd); if (!ecomadd) { - vty_out (vty, "%% Malformed Route Target list%s", VTY_NEWLINE); + vty_out (vty, "%% Malformed Route Target list\n"); return CMD_WARNING; } @@ -2425,7 +2418,7 @@ DEFUN (bgp_evpn_vni_rt, ecommunity_str(ecomadd); if (!ecomadd) { - vty_out (vty, "%% Malformed Route Target list%s", VTY_NEWLINE); + vty_out (vty, "%% Malformed Route Target list\n"); return CMD_WARNING; } @@ -2463,7 +2456,7 @@ DEFUN (no_bgp_evpn_vni_rt, rt_type = RT_TYPE_BOTH; else { - vty_out (vty, "%% Invalid Route Target type%s", VTY_NEWLINE); + vty_out (vty, "%% Invalid Route Target type\n"); return CMD_WARNING; } @@ -2473,7 +2466,7 @@ DEFUN (no_bgp_evpn_vni_rt, { if (!is_import_rt_configured (vpn)) { - vty_out (vty, "%% Import RT is not configured for this VNI%s", VTY_NEWLINE); + vty_out (vty, "%% Import RT is not configured for this VNI\n"); return CMD_WARNING; } } @@ -2481,7 +2474,7 @@ DEFUN (no_bgp_evpn_vni_rt, { if (!is_export_rt_configured (vpn)) { - vty_out (vty, "%% Export RT is not configured for this VNI%s", VTY_NEWLINE); + vty_out (vty, "%% Export RT is not configured for this VNI\n"); return CMD_WARNING; } } @@ -2489,7 +2482,7 @@ DEFUN (no_bgp_evpn_vni_rt, { if (!is_import_rt_configured (vpn) && !is_export_rt_configured (vpn)) { - vty_out (vty, "%% Import/Export RT is not configured for this VNI%s", VTY_NEWLINE); + vty_out (vty, "%% Import/Export RT is not configured for this VNI\n"); return CMD_WARNING; } } @@ -2498,7 +2491,7 @@ DEFUN (no_bgp_evpn_vni_rt, ecommunity_str(ecomdel); if (!ecomdel) { - vty_out (vty, "%% Malformed Route Target list%s", VTY_NEWLINE); + vty_out (vty, "%% Malformed Route Target list\n"); return CMD_WARNING; } @@ -2506,7 +2499,7 @@ DEFUN (no_bgp_evpn_vni_rt, { if (!bgp_evpn_rt_matches_existing (vpn->import_rtl, ecomdel)) { - vty_out (vty, "%% RT specified does not match configuration for this VNI%s", VTY_NEWLINE); + vty_out (vty, "%% RT specified does not match configuration for this VNI\n"); return CMD_WARNING; } evpn_unconfigure_import_rt (bgp, vpn, ecomdel); @@ -2515,7 +2508,7 @@ DEFUN (no_bgp_evpn_vni_rt, { if (!bgp_evpn_rt_matches_existing (vpn->export_rtl, ecomdel)) { - vty_out (vty, "%% RT specified does not match configuration for this VNI%s", VTY_NEWLINE); + vty_out (vty, "%% RT specified does not match configuration for this VNI\n"); return CMD_WARNING; } evpn_unconfigure_export_rt (bgp, vpn, ecomdel); @@ -2538,7 +2531,7 @@ DEFUN (no_bgp_evpn_vni_rt, if (! found_ecomdel) { - vty_out (vty, "%% RT specified does not match configuration for this VNI%s", VTY_NEWLINE); + vty_out (vty, "%% RT specified does not match configuration for this VNI\n"); return CMD_WARNING; } } @@ -2571,7 +2564,7 @@ DEFUN (no_bgp_evpn_vni_rt_without_val, } else { - vty_out (vty, "%% Invalid Route Target type%s", VTY_NEWLINE); + vty_out (vty, "%% Invalid Route Target type\n"); return CMD_WARNING; } @@ -2580,7 +2573,7 @@ DEFUN (no_bgp_evpn_vni_rt_without_val, { if (!is_import_rt_configured (vpn)) { - vty_out (vty, "%% Import RT is not configured for this VNI%s", VTY_NEWLINE); + vty_out (vty, "%% Import RT is not configured for this VNI\n"); return CMD_WARNING; } } @@ -2588,7 +2581,7 @@ DEFUN (no_bgp_evpn_vni_rt_without_val, { if (!is_export_rt_configured (vpn)) { - vty_out (vty, "%% Export RT is not configured for this VNI%s", VTY_NEWLINE); + vty_out (vty, "%% Export RT is not configured for this VNI\n"); return CMD_WARNING; } } @@ -2623,7 +2616,7 @@ bgp_config_write_evpn_info (struct vty *vty, struct bgp *bgp, afi_t afi, if (bgp->advertise_all_vni) { bgp_config_write_family_header (vty, afi, safi, write); - vty_out (vty, " advertise-all-vni%s", VTY_NEWLINE); + vty_out (vty, " advertise-all-vni\n"); } } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 00708c4871..88b63107e9 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -7254,7 +7254,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, bgp_evpn_label2str (&binfo->extra->label, tag_buf, sizeof (tag_buf)); vty_out (vty, " VNI %s", tag_buf); } - vty_out (vty, "%s", VTY_NEWLINE); + vty_out (vty, "\n"); if (binfo->extra && binfo->extra->parent) { struct bgp_info *parent_ri; @@ -7265,10 +7265,10 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, if (rn && rn->prn) { prn = rn->prn; - vty_out (vty, " Imported from %s:%s%s", + vty_out (vty, " Imported from %s:%s\n", prefix_rd2str ((struct prefix_rd *)&prn->p, buf1, RD_ADDRSTRLEN), - buf2, VTY_NEWLINE); + buf2); } } } @@ -7761,7 +7761,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, /* Line 6 display Large community */ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)) - vty_outln (vty, " Large Community: %s\n", + vty_out (vty, " Large Community: %s\n", attr->lcommunity->str); /* Line 7 display Originator, Cluster-id */ @@ -8329,19 +8329,18 @@ route_vty_out_detail_header (struct vty *vty, struct bgp *bgp, { #if defined (HAVE_CUMULUS) if (safi == SAFI_EVPN) - vty_out (vty, "BGP routing table entry for %s%s%s%s", + vty_out (vty, "BGP routing table entry for %s%s%s\n", prd ? prefix_rd2str (prd, buf1, RD_ADDRSTRLEN) : "", prd ? ":" : "", bgp_evpn_route2str ((struct prefix_evpn *)p, - buf3, sizeof (buf3)), - VTY_NEWLINE); + buf3, sizeof (buf3))); else - vty_out (vty, "BGP routing table entry for %s%s%s/%d%s", + vty_out (vty, "BGP routing table entry for %s%s%s/%d\n", ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP) ? prefix_rd2str (prd, buf1, RD_ADDRSTRLEN) : ""), safi == SAFI_MPLS_VPN ? ":" : "", inet_ntop (p->family, &p->u.prefix, buf2, INET6_ADDRSTRLEN), - p->prefixlen, VTY_NEWLINE); + p->prefixlen); #else if (p->family == AF_ETHERNET) prefix2str (p, buf2, INET6_ADDRSTRLEN); diff --git a/zebra/debug.c b/zebra/debug.c index 763bf359ba..1c3cf9a3da 100644 --- a/zebra/debug.c +++ b/zebra/debug.c @@ -439,7 +439,7 @@ config_write_debug (struct vty *vty) } if (IS_ZEBRA_DEBUG_VXLAN) { - vty_out (vty, "debug zebra vxlan%s", VTY_NEWLINE); + vty_out (vty, "debug zebra vxlan\n"); write++; } return write; diff --git a/zebra/interface.c b/zebra/interface.c index fb856165b3..9618e9bb17 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -1209,23 +1209,23 @@ 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); + vty_out(vty, " Interface Type %s\n", + zebra_ziftype_2str (zebra_if->zif_type)); 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); + vty_out(vty, " Bridge VLAN-aware: %s\n", + bridge_info->vlan_aware ? "yes" : "no"); } 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); + vty_out(vty, " VLAN Id %u\n", + vlan_info->vid); } else if (IS_ZEBRA_IF_VXLAN (ifp)) { @@ -1237,7 +1237,7 @@ if_dump_vty (struct vty *vty, struct interface *ifp) 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); + vty_out(vty, "\n"); } if (IS_ZEBRA_IF_BRIDGE_SLAVE (ifp)) @@ -1246,13 +1246,13 @@ if_dump_vty (struct vty *vty, struct interface *ifp) 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); + vty_out(vty, " Master (bridge) ifindex %u\n", + br_slave->bridge_ifindex); } if (zebra_if->link_ifindex != IFINDEX_INTERNAL) - vty_out(vty, " Link ifindex %u%s", - zebra_if->link_ifindex, VTY_NEWLINE); + vty_out(vty, " Link ifindex %u\n", + zebra_if->link_ifindex); if (HAS_LINK_PARAMS(ifp)) { diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 52d404aeed..b1da38a7b6 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -3074,7 +3074,7 @@ DEFUN (show_evpn_vni_vni, struct zebra_vrf *zvrf; vni_t vni; - VTY_GET_INTEGER_RANGE ("VNI", vni, argv[3]->arg, 1, VNI_MAX); + vni = strtoul(argv[3]->arg, NULL, 10); zvrf = vrf_info_lookup(VRF_DEFAULT); zebra_vxlan_print_vni(vty, zvrf, vni); return CMD_SUCCESS; @@ -3092,7 +3092,7 @@ DEFUN (show_evpn_mac_vni, struct zebra_vrf *zvrf; vni_t vni; - VTY_GET_INTEGER_RANGE ("VNI", vni, argv[4]->arg, 1, VNI_MAX); + vni = strtoul(argv[4]->arg, NULL, 10); zvrf = vrf_info_lookup(VRF_DEFAULT); zebra_vxlan_print_macs_vni(vty, zvrf, vni); return CMD_SUCCESS; @@ -3130,7 +3130,7 @@ DEFUN (show_evpn_mac_vni_all_vtep, if (!inet_aton (argv[6]->arg, &vtep_ip)) { - vty_out (vty, "%% Malformed VTEP IP address%s", VTY_NEWLINE); + vty_out (vty, "%% Malformed VTEP IP address\n"); return CMD_WARNING; } zvrf = vrf_info_lookup(VRF_DEFAULT); @@ -3155,10 +3155,10 @@ DEFUN (show_evpn_mac_vni_mac, vni_t vni; struct ethaddr mac; - VTY_GET_INTEGER_RANGE ("VNI", vni, argv[4]->arg, 1, VNI_MAX); + vni = strtoul(argv[4]->arg, NULL, 10); if (!prefix_str2mac (argv[6]->arg, &mac)) { - vty_out (vty, "%% Malformed MAC address%s", VTY_NEWLINE); + vty_out (vty, "%% Malformed MAC address"); return CMD_WARNING; } zvrf = vrf_info_lookup(VRF_DEFAULT); @@ -3181,10 +3181,10 @@ DEFUN (show_evpn_mac_vni_vtep, vni_t vni; struct in_addr vtep_ip; - VTY_GET_INTEGER_RANGE ("VNI", vni, argv[4]->arg, 1, VNI_MAX); + vni = strtoul(argv[4]->arg, NULL, 10); if (!inet_aton (argv[6]->arg, &vtep_ip)) { - vty_out (vty, "%% Malformed VTEP IP address%s", VTY_NEWLINE); + vty_out (vty, "%% Malformed VTEP IP address\n"); return CMD_WARNING; } @@ -3205,7 +3205,7 @@ DEFUN (show_evpn_neigh_vni, struct zebra_vrf *zvrf; vni_t vni; - VTY_GET_INTEGER_RANGE ("VNI", vni, argv[4]->arg, 1, VNI_MAX); + vni = strtoul(argv[4]->arg, NULL, 10); zvrf = vrf_info_lookup(VRF_DEFAULT); zebra_vxlan_print_neigh_vni(vty, zvrf, vni); return CMD_SUCCESS; @@ -3242,10 +3242,10 @@ DEFUN (show_evpn_neigh_vni_neigh, vni_t vni; struct ipaddr ip; - VTY_GET_INTEGER_RANGE ("VNI", vni, argv[4]->arg, 1, VNI_MAX); + vni = strtoul(argv[4]->arg, NULL, 10); if (str2ipaddr (argv[6]->arg, &ip) != 0) { - vty_out (vty, "%% Malformed Neighbor address%s", VTY_NEWLINE); + vty_out (vty, "%% Malformed Neighbor address\n"); return CMD_WARNING; } zvrf = vrf_info_lookup(VRF_DEFAULT); @@ -3268,10 +3268,10 @@ DEFUN (show_evpn_neigh_vni_vtep, vni_t vni; struct in_addr vtep_ip; - VTY_GET_INTEGER_RANGE ("VNI", vni, argv[4]->arg, 1, VNI_MAX); + vni = strtoul(argv[4]->arg, NULL, 10); if (!inet_aton (argv[6]->arg, &vtep_ip)) { - vty_out (vty, "%% Malformed VTEP IP address%s", VTY_NEWLINE); + vty_out (vty, "%% Malformed VTEP IP address\n"); return CMD_WARNING; } diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 5eca8dc5d9..7df31cb93d 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -220,12 +220,12 @@ zvni_print_neigh (zebra_neigh_t *n, void *ctxt) ipaddr2str (&n->ip, buf2, sizeof(buf2)), vty = (struct vty *) ctxt; - vty_out(vty, "IP: %s%s", - ipaddr2str (&n->ip, buf2, sizeof(buf2)), VTY_NEWLINE); + vty_out(vty, "IP: %s\n", + ipaddr2str (&n->ip, buf2, sizeof(buf2))); vty_out(vty, " MAC: %s", prefix_mac2str (&n->emac, buf1, sizeof (buf1))); if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) vty_out(vty, " Remote VTEP: %s", inet_ntoa (n->r_vtep_ip)); - vty_out(vty, "%s", VTY_NEWLINE); + vty_out(vty, "\n"); } /* @@ -250,8 +250,8 @@ zvni_print_neigh_hash (struct hash_backet *backet, void *ctxt) if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL) && !(wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP)) { - vty_out(vty, "%*s %-6s %-17s %s", - -wctx->addr_width, buf2, "local", buf1, VTY_NEWLINE); + vty_out(vty, "%*s %-6s %-17s\n", + -wctx->addr_width, buf2, "local", buf1); wctx->count++; } else @@ -261,20 +261,20 @@ zvni_print_neigh_hash (struct hash_backet *backet, void *ctxt) if (IPV4_ADDR_SAME(&n->r_vtep_ip, &wctx->r_vtep_ip)) { if (wctx->count == 0) - vty_out(vty, "%*s %-6s %-17s %-21s%s", + vty_out(vty, "%*s %-6s %-17s %-21s\n", -wctx->addr_width, "Neighbor", "Type", "MAC", - "Remote VTEP", VTY_NEWLINE); - vty_out(vty, "%*s %-6s %-17s %-21s%s", + "Remote VTEP"); + vty_out(vty, "%*s %-6s %-17s %-21s\n", -wctx->addr_width, buf2, "remote", buf1, - inet_ntoa (n->r_vtep_ip), VTY_NEWLINE); + inet_ntoa (n->r_vtep_ip)); wctx->count++; } } else { - vty_out(vty, "%*s %-6s %-17s %-21s%s", + vty_out(vty, "%*s %-6s %-17s %-21s\n", -wctx->addr_width, buf2, "remote", buf1, - inet_ntoa (n->r_vtep_ip), VTY_NEWLINE); + inet_ntoa (n->r_vtep_ip)); wctx->count++; } } @@ -297,8 +297,8 @@ zvni_print_neigh_hash_all_vni (struct hash_backet *backet, void *ctxt) return; num_neigh = hashcount(zvni->neigh_table); - vty_out(vty, "%sVNI %u #ARP (IPv4 and IPv6, local and remote) %u%s%s", - VTY_NEWLINE, zvni->vni, num_neigh, VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "\nVNI %u #ARP (IPv4 and IPv6, local and remote) %u\n\n", + zvni->vni, num_neigh); if (!num_neigh) return; @@ -312,9 +312,9 @@ zvni_print_neigh_hash_all_vni (struct hash_backet *backet, void *ctxt) wctx.addr_width = 15; hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx); - vty_out(vty, "%*s %-6s %-17s %-21s%s", + vty_out(vty, "%*s %-6s %-17s %-21s\n", -wctx.addr_width, "IP", "Type", "MAC", - "Remote VTEP", VTY_NEWLINE); + "Remote VTEP"); hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx); } @@ -328,8 +328,8 @@ zvni_print_mac (zebra_mac_t *mac, void *ctxt) char buf1[20]; vty = (struct vty *) ctxt; - vty_out(vty, "MAC: %s%s", - prefix_mac2str (&mac->macaddr, buf1, sizeof (buf1)), VTY_NEWLINE); + vty_out(vty, "MAC: %s", + prefix_mac2str (&mac->macaddr, buf1, sizeof (buf1))); if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { struct zebra_ns *zns; @@ -351,7 +351,7 @@ zvni_print_mac (zebra_mac_t *mac, void *ctxt) inet_ntoa (mac->fwd_info.r_vtep_ip)); } vty_out(vty, " ARP ref: %u", mac->neigh_refcnt); - vty_out(vty, "%s", VTY_NEWLINE); + vty_out(vty, "\n"); } /* @@ -389,7 +389,7 @@ zvni_print_mac_hash (struct hash_backet *backet, void *ctxt) buf1, "local", ifp->name); if (vid) vty_out(vty, " %-5u", vid); - vty_out(vty, "%s", VTY_NEWLINE); + vty_out(vty, "\n"); wctx->count++; } else @@ -401,24 +401,23 @@ zvni_print_mac_hash (struct hash_backet *backet, void *ctxt) { if (wctx->count == 0) { - vty_out(vty, "%sVNI %u%s%s", - VTY_NEWLINE, wctx->zvni->vni,VTY_NEWLINE, VTY_NEWLINE); - vty_out(vty, "%-17s %-6s %-21s %-5s%s", + vty_out(vty, "\nVNI %u", + wctx->zvni->vni); + vty_out(vty, "%-17s %-6s %-21s %-5s", "MAC", "Type", "Intf/Remote VTEP", - "VLAN", VTY_NEWLINE); + "VLAN"); } - vty_out(vty, "%-17s %-6s %-21s%s", + vty_out(vty, "%-17s %-6s %-21s", buf1, "remote", - inet_ntoa (mac->fwd_info.r_vtep_ip), - VTY_NEWLINE); + inet_ntoa (mac->fwd_info.r_vtep_ip)); wctx->count++; } } else { - vty_out(vty, "%-17s %-6s %-21s%s", + vty_out(vty, "%-17s %-6s %-21s", buf1, "remote", - inet_ntoa (mac->fwd_info.r_vtep_ip), VTY_NEWLINE); + inet_ntoa (mac->fwd_info.r_vtep_ip)); wctx->count++; } } @@ -451,10 +450,10 @@ zvni_print_mac_hash_all_vni (struct hash_backet *backet, void *ctxt) return; if (!CHECK_FLAG(wctx->flags, SHOW_REMOTE_MAC_FROM_VTEP)) { - vty_out(vty, "%sVNI %u #MACs (local and remote) %u%s%s", - VTY_NEWLINE, zvni->vni, num_macs, VTY_NEWLINE, VTY_NEWLINE); - vty_out(vty, "%-17s %-6s %-21s %-5s%s", - "MAC", "Type", "Intf/Remote VTEP", "VLAN", VTY_NEWLINE); + vty_out(vty, "\nVNI %u #MACs (local and remote) %u\n\n", + zvni->vni, num_macs); + vty_out(vty, "%-17s %-6s %-21s %-5s\n", + "MAC", "Type", "Intf/Remote VTEP", "VLAN"); } hash_iterate(zvni->mac_table, zvni_print_mac_hash, wctx); @@ -473,33 +472,33 @@ zvni_print (zebra_vni_t *zvni, void *ctxt) vty = (struct vty *) ctxt; - vty_out(vty, "VNI: %u%s", zvni->vni, VTY_NEWLINE); + vty_out(vty, "VNI: %u\n", zvni->vni); if (!zvni->vxlan_if) { // unexpected - vty_out(vty, " VxLAN interface: unknown%s", VTY_NEWLINE); + vty_out(vty, " VxLAN interface: unknown\n"); return; } - vty_out(vty, " VxLAN interface: %s ifIndex: %u VTEP IP: %s%s", + vty_out(vty, " VxLAN interface: %s ifIndex: %u VTEP IP: %s\n", zvni->vxlan_if->name, zvni->vxlan_if->ifindex, - inet_ntoa(zvni->local_vtep_ip), VTY_NEWLINE); + inet_ntoa(zvni->local_vtep_ip)); if (!zvni->vteps) { - vty_out(vty, " No remote VTEPs known for this VNI%s", VTY_NEWLINE); + vty_out(vty, " No remote VTEPs known for this VNI\n"); } else { - vty_out(vty, " Remote VTEPs for this VNI:%s", VTY_NEWLINE); + vty_out(vty, " Remote VTEPs for this VNI:\n"); for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) - vty_out(vty, " %s%s", - inet_ntoa (zvtep->vtep_ip), VTY_NEWLINE); + vty_out(vty, " %s\n", + inet_ntoa (zvtep->vtep_ip)); } num_macs = hashcount(zvni->mac_table); - vty_out(vty, " Number of MACs (local and remote) known for this VNI: %u%s", - num_macs, VTY_NEWLINE); + vty_out(vty, " Number of MACs (local and remote) known for this VNI: %u\n", + num_macs); num_neigh = hashcount(zvni->neigh_table); vty_out(vty, " Number of ARPs (IPv4 and IPv6, local and remote) " - "known for this VNI: %u%s", num_neigh, VTY_NEWLINE); + "known for this VNI: %u", num_neigh); } /* @@ -529,11 +528,11 @@ zvni_print_hash (struct hash_backet *backet, void *ctxt) num_macs = hashcount(zvni->mac_table); num_neigh = hashcount(zvni->neigh_table); - vty_out(vty, "%-10u %-21s %-15s %-8u %-8u %-15u%s", + vty_out(vty, "%-10u %-21s %-15s %-8u %-8u %-15u\n", zvni->vni, zvni->vxlan_if ? zvni->vxlan_if->name : "unknown", inet_ntoa(zvni->local_vtep_ip), - num_macs, num_neigh, num_vteps, VTY_NEWLINE); + num_macs, num_neigh, num_vteps); } /* @@ -1779,7 +1778,7 @@ zebra_vxlan_print_neigh_vni (struct vty *vty, struct zebra_vrf *zvrf, vni_t vni) zvni = zvni_lookup (zvrf, vni); if (!zvni) { - vty_out (vty, "%% VNI %u does not exist%s", vni, VTY_NEWLINE); + vty_out (vty, "%% VNI %u does not exist\n", vni); return; } num_neigh = hashcount(zvni->neigh_table); @@ -1796,11 +1795,11 @@ zebra_vxlan_print_neigh_vni (struct vty *vty, struct zebra_vrf *zvrf, vni_t vni) wctx.addr_width = 15; hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx); - vty_out(vty, "Number of ARPs (local and remote) known for this VNI: %u%s", - num_neigh, VTY_NEWLINE); - vty_out(vty, "%*s %-6s %-17s %-21s%s", + vty_out(vty, "Number of ARPs (local and remote) known for this VNI: %u\n", + num_neigh); + vty_out(vty, "%*s %-6s %-17s %-21s\n", -wctx.addr_width, "IP", "Type", "MAC", - "Remote VTEP", VTY_NEWLINE); + "Remote VTEP"); hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx); } @@ -1831,14 +1830,14 @@ zebra_vxlan_print_specific_neigh_vni (struct vty *vty, struct zebra_vrf *zvrf, zvni = zvni_lookup (zvrf, vni); if (!zvni) { - vty_out (vty, "%% VNI %u does not exist%s", vni, VTY_NEWLINE); + vty_out (vty, "%% VNI %u does not exist", vni); return; } n = zvni_neigh_lookup (zvni, ip); if (!n) { - vty_out (vty, "%% Requested neighbor does not exist in VNI %u%s", - vni, VTY_NEWLINE); + vty_out (vty, "%% Requested neighbor does not exist in VNI %u\n", + vni); return; } @@ -1862,7 +1861,7 @@ zebra_vxlan_print_neigh_vni_vtep (struct vty *vty, struct zebra_vrf *zvrf, zvni = zvni_lookup (zvrf, vni); if (!zvni) { - vty_out (vty, "%% VNI %u does not exist%s", vni, VTY_NEWLINE); + vty_out (vty, "%% VNI %u does not exist\n", vni); return; } num_neigh = hashcount(zvni->neigh_table); @@ -1893,7 +1892,7 @@ zebra_vxlan_print_macs_vni (struct vty *vty, struct zebra_vrf *zvrf, vni_t vni) zvni = zvni_lookup (zvrf, vni); if (!zvni) { - vty_out (vty, "%% VNI %u does not exist%s", vni, VTY_NEWLINE); + vty_out (vty, "%% VNI %u does not exist\n", vni); return; } num_macs = hashcount(zvni->mac_table); @@ -1904,10 +1903,10 @@ zebra_vxlan_print_macs_vni (struct vty *vty, struct zebra_vrf *zvrf, vni_t vni) wctx.zvni = zvni; wctx.vty = vty; - vty_out(vty, "Number of MACs (local and remote) known for this VNI: %u%s", - num_macs, VTY_NEWLINE); - vty_out(vty, "%-17s %-6s %-21s %-5s%s", - "MAC", "Type", "Intf/Remote VTEP", "VLAN", VTY_NEWLINE); + vty_out(vty, "Number of MACs (local and remote) known for this VNI: %u\n", + num_macs); + vty_out(vty, "%-17s %-6s %-21s %-5s\n", + "MAC", "Type", "Intf/Remote VTEP", "VLAN"); hash_iterate(zvni->mac_table, zvni_print_mac_hash, &wctx); } @@ -1960,14 +1959,14 @@ zebra_vxlan_print_specific_mac_vni (struct vty *vty, struct zebra_vrf *zvrf, zvni = zvni_lookup (zvrf, vni); if (!zvni) { - vty_out (vty, "%% VNI %u does not exist%s", vni, VTY_NEWLINE); + vty_out (vty, "%% VNI %u does not exist\n", vni); return; } mac = zvni_mac_lookup (zvni, macaddr); if (!mac) { - vty_out (vty, "%% Requested MAC does not exist in VNI %u%s", - vni, VTY_NEWLINE); + vty_out (vty, "%% Requested MAC does not exist in VNI %u\n", + vni); return; } @@ -1990,7 +1989,7 @@ zebra_vxlan_print_macs_vni_vtep (struct vty *vty, struct zebra_vrf *zvrf, zvni = zvni_lookup (zvrf, vni); if (!zvni) { - vty_out (vty, "%% VNI %u does not exist%s", vni, VTY_NEWLINE); + vty_out (vty, "%% VNI %u does not exist\n", vni); return; } num_macs = hashcount(zvni->mac_table); @@ -2018,7 +2017,7 @@ zebra_vxlan_print_vni (struct vty *vty, struct zebra_vrf *zvrf, vni_t vni) zvni = zvni_lookup (zvrf, vni); if (!zvni) { - vty_out (vty, "%% VNI %u does not exist%s", vni, VTY_NEWLINE); + vty_out (vty, "%% VNI %u does not exist\n", vni); return; } zvni_print (zvni, (void *)vty); @@ -2037,10 +2036,10 @@ zebra_vxlan_print_vnis (struct vty *vty, struct zebra_vrf *zvrf) num_vnis = hashcount(zvrf->vni_table); if (!num_vnis) return; - vty_out(vty, "Number of VNIs: %u%s", num_vnis, VTY_NEWLINE); - vty_out(vty, "%-10s %-21s %-15s %-8s %-8s %-15s%s", + vty_out(vty, "Number of VNIs: %u\n", num_vnis); + vty_out(vty, "%-10s %-21s %-15s %-8s %-8s %-15s\n", "VNI", "VxLAN IF", "VTEP IP", "# MACs", "# ARPs", - "# Remote VTEPs", VTY_NEWLINE); + "# Remote VTEPs"); hash_iterate(zvrf->vni_table, zvni_print_hash, vty); }