From 12c29b43e40c4860164dbe09ce15a08675ef88d4 Mon Sep 17 00:00:00 2001 From: Kiran Kumar Kella <45939429+kirankella@users.noreply.github.com> Date: Thu, 19 Sep 2019 08:08:31 +0530 Subject: [PATCH] Cannot ping to link-local ipv6 interface address of the switch. (#774) * Cannot ping to link-local ipv6 interface address of the switch. Fixes: 1. Packets destined to the switch's routing interface link-local ipv6 address are not coming to CPU. Hence the ping fails. Since all interfaces have the same link-local ipv6 address, all we need is a single ip2me /128 route corresponding to this address added in the hardware. We don't need fe80 ip2me route added to hardware for every interface. Hence the address overlap issue won't arise for the link-local interface address. 2. Fixed another issue as part of this PR. Where the link-local ipv6 neighbors are not learned via netlink by neighsync. As a result, we could not add an ipv6 route via link-local nexthop. Allow neighsync to learn the link-local neighbors too. Signed-off-by: kiran.kella@broadcom.com * Incremental change to the code changes. * Incremental change to the code changes. * Incorporated review comments. * Incorporated review comments. * Add fe80::/10 route to CPU to forward all locally destined link-local ipv6 packets to CPU. * Retain fe80.../128 ip2me route in the hardware along with fe80::/10 subnet route. Signed-off-by: Kiran Kella --- neighsyncd/neighsync.cpp | 4 +- orchagent/routeorch.cpp | 85 ++++++++++++++++++++++++++++++++++++++++ orchagent/routeorch.h | 6 +++ 3 files changed, 92 insertions(+), 3 deletions(-) diff --git a/neighsyncd/neighsync.cpp b/neighsyncd/neighsync.cpp index c1f83c3aac4a..a4967c050249 100644 --- a/neighsyncd/neighsync.cpp +++ b/neighsyncd/neighsync.cpp @@ -61,9 +61,7 @@ void NeighSync::onMsg(int nlmsg_type, struct nl_object *obj) key+= ":"; nl_addr2str(rtnl_neigh_get_dst(neigh), ipStr, MAX_ADDR_SIZE); - /* Ignore IPv6 link-local addresses as neighbors */ - if (family == IPV6_NAME && IN6_IS_ADDR_LINKLOCAL(nl_addr_get_binary_addr(rtnl_neigh_get_dst(neigh)))) - return; + /* Ignore IPv6 multicast link-local addresses as neighbors */ if (family == IPV6_NAME && IN6_IS_ADDR_MC_LINKLOCAL(nl_addr_get_binary_addr(rtnl_neigh_get_dst(neigh)))) return; diff --git a/orchagent/routeorch.cpp b/orchagent/routeorch.cpp index a75b321158ae..bff955b60dae 100644 --- a/orchagent/routeorch.cpp +++ b/orchagent/routeorch.cpp @@ -104,6 +104,91 @@ RouteOrch::RouteOrch(DBConnector *db, string tableName, NeighOrch *neighOrch) : m_syncdRoutes[v6_default_ip_prefix] = IpAddresses(); SWSS_LOG_NOTICE("Create IPv6 default route with packet action drop"); + + /* All the interfaces have the same MAC address and hence the same + * auto-generated link-local ipv6 address with eui64 interface-id. + * Hence add a single /128 route entry for the link-local interface + * address pointing to the CPU port. + */ + IpPrefix linklocal_prefix = getLinkLocalEui64Addr(); + + addLinkLocalRouteToMe(gVirtualRouterId, linklocal_prefix); + + /* Add fe80::/10 subnet route to forward all link-local packets + * destined to us, to CPU */ + IpPrefix default_link_local_prefix("fe80::/10"); + + addLinkLocalRouteToMe(gVirtualRouterId, default_link_local_prefix); + + /* TODO: Add the link-local fe80::/10 route to cpu in every VRF created from + * vrforch::addOperation. */ +} + +std::string RouteOrch::getLinkLocalEui64Addr(void) +{ + SWSS_LOG_ENTER(); + + string ip_prefix; + const uint8_t *gmac = gMacAddress.getMac(); + + uint8_t eui64_interface_id[EUI64_INTF_ID_LEN]; + char ipv6_ll_addr[INET6_ADDRSTRLEN] = {0}; + + /* Link-local IPv6 address autogenerated by kernel with eui64 interface-id + * derived from the MAC address of the host interface. + */ + eui64_interface_id[0] = gmac[0] ^ 0x02; + eui64_interface_id[1] = gmac[1]; + eui64_interface_id[2] = gmac[2]; + eui64_interface_id[3] = 0xff; + eui64_interface_id[4] = 0xfe; + eui64_interface_id[5] = gmac[3]; + eui64_interface_id[6] = gmac[4]; + eui64_interface_id[7] = gmac[5]; + + snprintf(ipv6_ll_addr, INET6_ADDRSTRLEN, "fe80::%02x%02x:%02x%02x:%02x%02x:%02x%02x", + eui64_interface_id[0], eui64_interface_id[1], eui64_interface_id[2], + eui64_interface_id[3], eui64_interface_id[4], eui64_interface_id[5], + eui64_interface_id[6], eui64_interface_id[7]); + + ip_prefix = string(ipv6_ll_addr); + + return ip_prefix; +} + +void RouteOrch::addLinkLocalRouteToMe(sai_object_id_t vrf_id, IpPrefix linklocal_prefix) +{ + sai_route_entry_t unicast_route_entry; + unicast_route_entry.switch_id = gSwitchId; + unicast_route_entry.vr_id = vrf_id; + copy(unicast_route_entry.destination, linklocal_prefix); + subnet(unicast_route_entry.destination, unicast_route_entry.destination); + + sai_attribute_t attr; + vector attrs; + + attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; + attr.value.s32 = SAI_PACKET_ACTION_FORWARD; + attrs.push_back(attr); + + Port cpu_port; + gPortsOrch->getCpuPort(cpu_port); + + attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + attr.value.oid = cpu_port.m_port_id; + attrs.push_back(attr); + + sai_status_t status = sai_route_api->create_route_entry(&unicast_route_entry, (uint32_t)attrs.size(), attrs.data()); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create link local ipv6 route %s to cpu, rv:%d", + linklocal_prefix.getIp().to_string().c_str(), status); + throw runtime_error("Failed to create link local ipv6 route to cpu."); + } + + gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_IPV6_ROUTE); + + SWSS_LOG_NOTICE("Created link local ipv6 route %s to cpu", linklocal_prefix.to_string().c_str()); } bool RouteOrch::hasNextHopGroup(const IpAddresses& ipAddresses) const diff --git a/orchagent/routeorch.h b/orchagent/routeorch.h index b4d87b695863..310e93cd87ce 100644 --- a/orchagent/routeorch.h +++ b/orchagent/routeorch.h @@ -15,6 +15,9 @@ /* Maximum next hop group number */ #define NHGRP_MAX_SIZE 128 +/* Length of the Interface Id value in EUI64 format */ +#define EUI64_INTF_ID_LEN 8 + typedef std::map NextHopGroupMembers; struct NextHopGroupEntry @@ -84,6 +87,9 @@ class RouteOrch : public Orch, public Subject bool addRoute(IpPrefix, IpAddresses); bool removeRoute(IpPrefix); + std::string getLinkLocalEui64Addr(void); + void addLinkLocalRouteToMe(sai_object_id_t vrf_id, IpPrefix linklocal_prefix); + void doTask(Consumer& consumer); };