Skip to content

Commit

Permalink
Cannot ping to link-local ipv6 interface address of the switch. (#774)
Browse files Browse the repository at this point in the history
* 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: [email protected]

* 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 <[email protected]>
  • Loading branch information
kirankella authored and yxieca committed Sep 19, 2019
1 parent 4d8e08d commit 12c29b4
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 3 deletions.
4 changes: 1 addition & 3 deletions neighsyncd/neighsync.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
85 changes: 85 additions & 0 deletions orchagent/routeorch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<sai_attribute_t> 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
Expand Down
6 changes: 6 additions & 0 deletions orchagent/routeorch.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<IpAddress, sai_object_id_t> NextHopGroupMembers;

struct NextHopGroupEntry
Expand Down Expand Up @@ -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);
};

Expand Down

0 comments on commit 12c29b4

Please sign in to comment.