--- /dev/null
+/*\r
+ * Copyright (c) 2008 Microsoft Corporation. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ * $Id:$\r
+ */\r
+\r
+//\r
+// IBAT: InfiniBand Address Translation\r
+//\r
+// Description:\r
+// Maps remote IP addresses (IPv4 and IPv6) to the remote GID.\r
+//\r
+// The mapping requires two steps:\r
+// 1. Mapping the remote IP address to the remote Ethernet MAC address\r
+// 2. Retrieve the remote GID given the remote Ethernet MAC address\r
+// from IPoIB\r
+//\r
+// The first step is accomplished as follows on Windows Server 2008:\r
+// 1. Lookup the desired MAC from the OS using GetIpNetEntry2\r
+// 2. If the remote IP isn't found, resolve the remote IP address\r
+// using ResolveIpNetEntry2\r
+//\r
+// The first step is accomplished as follows on Windows Server 2003:\r
+// 1. Retrieve the whole IP->MAC mapping table from the OS using\r
+// GetIpNetTable.\r
+// 2. Walk the returned table looking for the destination IP to\r
+// find the destination Ethernet MAC address.\r
+// 3. If the remote IP isn't found, resolve the remote IP address using\r
+// SendARP.\r
+//\r
+// The second step is accomplished by asking IPoIB for the remote GID\r
+// given the remote MAC.\r
+\r
+#pragma warning( push, 3 )\r
+#include <windows.h>\r
+#include <stdlib.h>\r
+#include <winioctl.h>\r
+#pragma warning( pop )\r
+#include "iba/ibat.h"\r
+#include <iphlpapi.h>\r
+#include "iba/ib_at_ioctl.h"\r
+\r
+\r
+namespace IBAT\r
+{\r
+\r
+ const IN6_ADDR x_DefaultGid = {0xFE,0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0};\r
+\r
+class H\r
+{\r
+public:\r
+ H( HANDLE h = INVALID_HANDLE_VALUE ) : m_h( h ) {};\r
+ ~H(){ if( m_h != INVALID_HANDLE_VALUE ) CloseHandle( m_h ); }\r
+\r
+ H& operator =(HANDLE h){ CloseHandle( m_h ); m_h = h; }\r
+ operator HANDLE() const { return m_h; }\r
+\r
+private:\r
+ HANDLE m_h;\r
+};\r
+\r
+#if WINVER >= 0x600\r
+HRESULT\r
+Resolve(\r
+ __in const struct sockaddr* pSrcAddr,\r
+ __in const struct sockaddr* pDestAddr,\r
+ __out IN6_ADDR* pSrcGid,\r
+ __out IN6_ADDR* pDestGid,\r
+ __out USHORT* pPkey\r
+ )\r
+{\r
+ if( pSrcAddr->sa_family != pDestAddr->sa_family )\r
+ return E_INVALIDARG;\r
+\r
+ H hIbatDev = CreateFileW( IBAT_WIN32_NAME,\r
+ MAXIMUM_ALLOWED, 0, NULL,\r
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );\r
+ if( hIbatDev == INVALID_HANDLE_VALUE )\r
+ return HRESULT_FROM_WIN32( GetLastError() );\r
+\r
+ bool fLoopback;\r
+ IOCTL_IBAT_IP_TO_PORT_IN port_in;\r
+ port_in.Version = IBAT_IOCTL_VERSION;\r
+ if( pSrcAddr->sa_family == AF_INET )\r
+ {\r
+ port_in.Address.IpVersion = 4;\r
+ RtlCopyMemory(\r
+ &port_in.Address.Address[12],\r
+ &((struct sockaddr_in*)pSrcAddr)->sin_addr,\r
+ sizeof( ((struct sockaddr_in*)pSrcAddr)->sin_addr ) );\r
+\r
+ fLoopback = ((struct sockaddr_in*)pDestAddr)->sin_addr.s_addr ==\r
+ ((struct sockaddr_in*)pSrcAddr)->sin_addr.s_addr;\r
+ }\r
+ else\r
+ {\r
+ port_in.Address.IpVersion = 6;\r
+ RtlCopyMemory(\r
+ port_in.Address.Address,\r
+ &((struct sockaddr_in6*)pSrcAddr)->sin6_addr,\r
+ sizeof(port_in.Address.Address) );\r
+ fLoopback = IN6_ADDR_EQUAL(\r
+ &((struct sockaddr_in6*)pDestAddr)->sin6_addr,\r
+ &((struct sockaddr_in6*)pSrcAddr)->sin6_addr\r
+ ) == TRUE;\r
+ }\r
+\r
+ IBAT_PORT_RECORD port_out;\r
+ DWORD size;\r
+ BOOL fSuccess = DeviceIoControl( hIbatDev, IOCTL_IBAT_IP_TO_PORT,\r
+ &port_in, sizeof(port_in), &port_out, sizeof(port_out), &size, NULL );\r
+\r
+ if( !fSuccess )\r
+ return HRESULT_FROM_WIN32( GetLastError() );\r
+\r
+ // Check for loopback.\r
+ if( fLoopback )\r
+ {\r
+ *pSrcGid = x_DefaultGid;\r
+ RtlCopyMemory(\r
+ &pSrcGid->u.Byte[8],\r
+ &port_out.PortGuid,\r
+ sizeof(port_out.PortGuid) );\r
+ *pDestGid = *pSrcGid;\r
+ *pPkey = port_out.PKey;\r
+ return S_OK;\r
+ }\r
+\r
+ NET_LUID luid;\r
+ DWORD ret;\r
+ do\r
+ {\r
+ DWORD iIf;\r
+ ret = GetBestInterfaceEx( (struct sockaddr*)pSrcAddr, &iIf );\r
+ if( ret != NO_ERROR )\r
+ return HRESULT_FROM_WIN32( ret );\r
+\r
+ // Interface indexes are not constant, so get the LUID mapping for the\r
+ // returned interface for use in the rest of the function.\r
+ ret = ConvertInterfaceIndexToLuid( iIf, &luid );\r
+\r
+ } while( ret != NO_ERROR );\r
+\r
+ SOCKADDR_INET src;\r
+ MIB_IPNET_ROW2 net = {0};\r
+ net.InterfaceLuid = luid;\r
+ switch( pDestAddr->sa_family )\r
+ {\r
+ case AF_INET:\r
+ net.Address.si_family = src.si_family = AF_INET;\r
+ net.Address.Ipv4 = *(struct sockaddr_in*)pDestAddr;\r
+ src.Ipv4 = *(struct sockaddr_in*)pSrcAddr;\r
+ break;\r
+\r
+ case AF_INET6:\r
+ net.Address.si_family = src.si_family = AF_INET6;\r
+ net.Address.Ipv6 = *(struct sockaddr_in6*)pDestAddr;\r
+ src.Ipv6 = *(struct sockaddr_in6*)pSrcAddr;\r
+ break;\r
+\r
+ default:\r
+ return E_INVALIDARG;\r
+ }\r
+\r
+ bool fRetry = true;\r
+retry:\r
+ ret = GetIpNetEntry2( &net );\r
+ if( ret != NO_ERROR )\r
+ return HRESULT_FROM_WIN32( ret );\r
+\r
+ switch( net.State )\r
+ {\r
+ default:\r
+ case NlnsUnreachable:\r
+ ret = ResolveIpNetEntry2( &net, &src );\r
+ if( ret == ERROR_BAD_NET_NAME && fRetry )\r
+ {\r
+ fRetry = false;\r
+ goto retry;\r
+ }\r
+ else if( ret != NO_ERROR )\r
+ {\r
+ return HRESULT_FROM_WIN32( ret );\r
+ }\r
+ break;\r
+\r
+ case NlnsReachable:\r
+ case NlnsPermanent:\r
+ break;\r
+\r
+ case NlnsIncomplete:\r
+ return E_PENDING;\r
+ }\r
+\r
+ if( net.PhysicalAddressLength > 6 )\r
+ return E_UNEXPECTED;\r
+\r
+ IOCTL_IBAT_MAC_TO_GID_IN mac_in;\r
+ mac_in.Version = IBAT_IOCTL_VERSION;\r
+ mac_in.PortGuid = port_out.PortGuid;\r
+ RtlCopyMemory( mac_in.DestMac, net.PhysicalAddress, IBAT_MAC_LEN );\r
+\r
+ fSuccess = DeviceIoControl( hIbatDev, IOCTL_IBAT_MAC_TO_GID,\r
+ &mac_in, sizeof(mac_in), pDestGid, sizeof(*pDestGid), &size, NULL );\r
+ if( !fSuccess )\r
+ return HRESULT_FROM_WIN32( GetLastError() );\r
+\r
+ // Use the same subnet prefix as the destination.\r
+ *pSrcGid = *pDestGid;\r
+ RtlCopyMemory( &pSrcGid->u.Byte[8], &port_out.PortGuid, sizeof(port_out.PortGuid) );\r
+ *pPkey = port_out.PKey;\r
+ return S_OK;\r
+}\r
+#else // Back compatibility with Windows Server 2003\r
+\r
+\r
+static HRESULT\r
+GetDestMac(\r
+ __in struct sockaddr_in* pDestAddr,\r
+ __out BYTE* pDestMac\r
+ )\r
+{\r
+ DWORD ret;\r
+\r
+ MIB_IPNETTABLE* pTable = NULL;\r
+ ULONG len = 0;\r
+ do\r
+ {\r
+ ret = GetIpNetTable( pTable, &len, FALSE );\r
+ if( ret != ERROR_INSUFFICIENT_BUFFER )\r
+ break;\r
+\r
+ if( pTable != NULL )\r
+ {\r
+ HeapFree( GetProcessHeap(), 0, pTable );\r
+ }\r
+\r
+ pTable = (MIB_IPNETTABLE*)HeapAlloc( GetProcessHeap(), 0, len );\r
+ } while( ret == ERROR_INSUFFICIENT_BUFFER );\r
+\r
+ if( ret != NO_ERROR )\r
+ {\r
+ if( pTable != NULL )\r
+ {\r
+ HeapFree( GetProcessHeap(), 0, pTable );\r
+ }\r
+ return HRESULT_FROM_WIN32( ret );\r
+ }\r
+\r
+ ret = ERROR_NOT_SUPPORTED;\r
+ DWORD i;\r
+ for( i = 0; i < pTable->dwNumEntries; i++ )\r
+ {\r
+ if( pTable->table[i].dwType == MIB_IPNET_TYPE_OTHER ||\r
+ pTable->table[i].dwType == MIB_IPNET_TYPE_INVALID )\r
+ {\r
+ continue;\r
+ }\r
+\r
+ if( pTable->table[i].dwAddr !=\r
+ ((struct sockaddr_in*)pDestAddr)->sin_addr.s_addr )\r
+ {\r
+ continue;\r
+ }\r
+\r
+ if( pTable->table[i].dwPhysAddrLen != IBAT_MAC_LEN )\r
+ {\r
+ continue;\r
+ }\r
+\r
+ RtlCopyMemory( pDestMac, pTable->table[i].bPhysAddr, IBAT_MAC_LEN );\r
+ ret = S_OK;\r
+ break;\r
+ }\r
+ HeapFree( GetProcessHeap(), 0, pTable );\r
+\r
+ return HRESULT_FROM_WIN32( ret );\r
+}\r
+\r
+HRESULT\r
+Resolve(\r
+ __in const struct sockaddr* pSrcAddr,\r
+ __in const struct sockaddr* pDestAddr,\r
+ __out IN6_ADDR* pSrcGid,\r
+ __out IN6_ADDR* pDestGid,\r
+ __out USHORT* pPkey\r
+ )\r
+{\r
+ if( pDestAddr->sa_family != AF_INET )\r
+ return E_NOTIMPL;\r
+\r
+ H hIbatDev = CreateFileW( IBAT_WIN32_NAME,\r
+ MAXIMUM_ALLOWED, 0, NULL,\r
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );\r
+ if( hIbatDev == INVALID_HANDLE_VALUE )\r
+ return HRESULT_FROM_WIN32( GetLastError() );\r
+\r
+ IOCTL_IBAT_IP_TO_PORT_IN port_in;\r
+ port_in.Version = IBAT_IOCTL_VERSION;\r
+ port_in.Address.IpVersion = 4;\r
+ RtlCopyMemory(\r
+ &port_in.Address.Address[12],\r
+ &((struct sockaddr_in*)pSrcAddr)->sin_addr,\r
+ sizeof( ((struct sockaddr_in*)pSrcAddr)->sin_addr ) );\r
+\r
+ IBAT_PORT_RECORD port_out;\r
+ DWORD size;\r
+ BOOL fSuccess = DeviceIoControl( hIbatDev, IOCTL_IBAT_IP_TO_PORT,\r
+ &port_in, sizeof(port_in), &port_out, sizeof(port_out), &size, NULL );\r
+\r
+ if( !fSuccess )\r
+ return HRESULT_FROM_WIN32( GetLastError() );\r
+\r
+ // Check for loopback.\r
+ if( ((struct sockaddr_in*)pDestAddr)->sin_addr.s_addr ==\r
+ ((struct sockaddr_in*)pSrcAddr)->sin_addr.s_addr )\r
+ {\r
+ *pSrcGid = x_DefaultGid;\r
+ RtlCopyMemory(\r
+ &pSrcGid->u.Byte[8],\r
+ &port_out.PortGuid,\r
+ sizeof(port_out.PortGuid) );\r
+ *pDestGid = *pSrcGid;\r
+ *pPkey = port_out.PKey;\r
+ return S_OK;\r
+ }\r
+\r
+ IOCTL_IBAT_MAC_TO_GID_IN mac_in;\r
+ mac_in.Version = IBAT_IOCTL_VERSION;\r
+ mac_in.PortGuid = port_out.PortGuid;\r
+ HRESULT hr = GetDestMac( (struct sockaddr_in*)pDestAddr, mac_in.DestMac );\r
+ if( FAILED( hr ) )\r
+ {\r
+ ULONG len = sizeof(mac_in.DestMac);\r
+ DWORD ret = SendARP(\r
+ ((struct sockaddr_in*)pDestAddr)->sin_addr.s_addr,\r
+ ((struct sockaddr_in*)pSrcAddr)->sin_addr.s_addr,\r
+ (ULONG*)mac_in.DestMac,\r
+ &len\r
+ );\r
+ if( ret != NO_ERROR )\r
+ return HRESULT_FROM_WIN32( ret );\r
+ }\r
+\r
+ fSuccess = DeviceIoControl( hIbatDev, IOCTL_IBAT_MAC_TO_GID,\r
+ &mac_in, sizeof(mac_in), pDestGid, sizeof(*pDestGid), &size, NULL );\r
+ if( !fSuccess )\r
+ return HRESULT_FROM_WIN32( GetLastError() );\r
+\r
+ // Use the same subnet prefix as the destination.\r
+ *pSrcGid = *pDestGid;\r
+ RtlCopyMemory( &pSrcGid->u.Byte[8], &port_out.PortGuid, sizeof(port_out.PortGuid) );\r
+ *pPkey = port_out.PKey;\r
+ return S_OK;\r
+}\r
+\r
+#endif\r
+}\r
+\r
+extern "C"\r
+{\r
+\r
+HRESULT\r
+IbatResolve(\r
+ __in const struct sockaddr* pSrcAddr,\r
+ __in const struct sockaddr* pDestAddr,\r
+ __out IN6_ADDR* pSrcGid,\r
+ __out IN6_ADDR* pDestGid,\r
+ __out USHORT* pPkey\r
+ )\r
+{\r
+ return IBAT::Resolve( pSrcAddr, pDestAddr, pSrcGid, pDestGid, pPkey );\r
+}\r
+\r
+} /* extern "C" */\r
--- /dev/null
+/*\r
+ * Copyright (c) 2008 Microsoft Corporation. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ * $Id:$\r
+ */\r
+\r
+\r
+#include "iba/ibat.h"\r
+#include "stdlib.h"\r
+#include "stdio.h"\r
+\r
+\r
+inline LONGLONG GetElapsedTime()\r
+{\r
+ LARGE_INTEGER elapsed;\r
+ QueryPerformanceCounter(&elapsed);\r
+ return elapsed.QuadPart;\r
+}\r
+\r
+inline LONGLONG GetFrequency()\r
+{\r
+ LARGE_INTEGER Frequency;\r
+ QueryPerformanceFrequency(&Frequency);\r
+ return Frequency.QuadPart;\r
+}\r
+\r
+int PrintUsage( int argc, char *argv[] )\r
+{\r
+ UNREFERENCED_PARAMETER( argc );\r
+ printf( "%s <source IP> <destination IP>\n", argv[0] );\r
+\r
+ return __LINE__;\r
+}\r
+\r
+int __cdecl main(int argc, char *argv[])\r
+{\r
+ if( argc < 3 )\r
+ return PrintUsage( argc, argv );\r
+\r
+ struct sockaddr_in srcAddr = {0};\r
+ srcAddr.sin_family = AF_INET;\r
+ srcAddr.sin_addr.s_addr = inet_addr( argv[1] );\r
+\r
+ struct sockaddr_in destAddr = {0};\r
+ destAddr.sin_family = AF_INET;\r
+ destAddr.sin_addr.s_addr = inet_addr( argv[2] );\r
+\r
+ IN6_ADDR srcGid;\r
+ IN6_ADDR destGid;\r
+ USHORT pkey;\r
+\r
+ HRESULT hr = IBAT::Resolve(\r
+ (struct sockaddr*)&srcAddr,\r
+ (struct sockaddr*)&destAddr,\r
+ &srcGid,\r
+ &destGid,\r
+ &pkey\r
+ );\r
+ if( FAILED( hr ) )\r
+ {\r
+ printf( "Resolve returned %08x.\n", hr );\r
+ return hr;\r
+ }\r
+\r
+ printf(\r
+ "I B at:\n"\r
+ "partition %x\n"\r
+ "source GID %x:%x:%x:%x:%x:%x:%x:%x\n"\r
+ "destination GID %x:%x:%x:%x:%x:%x:%x:%x\n",\r
+ pkey,\r
+ srcGid.u.Word[0], srcGid.u.Word[1], srcGid.u.Word[2], srcGid.u.Word[3],\r
+ srcGid.u.Word[4], srcGid.u.Word[5], srcGid.u.Word[6], srcGid.u.Word[7],\r
+ destGid.u.Word[0], destGid.u.Word[1], destGid.u.Word[2], destGid.u.Word[3],\r
+ destGid.u.Word[4], destGid.u.Word[5], destGid.u.Word[6], destGid.u.Word[7]\r
+ );\r
+\r
+ LONGLONG StartTime = GetElapsedTime();\r
+ for( int i = 0; i < 2000; i++ )\r
+ {\r
+ HRESULT hr = IBAT::Resolve(\r
+ (struct sockaddr*)&srcAddr,\r
+ (struct sockaddr*)&destAddr,\r
+ &srcGid,\r
+ &destGid,\r
+ &pkey\r
+ );\r
+ if( FAILED( hr ) )\r
+ {\r
+ printf( "Resolve returned %08x.\n", hr );\r
+ return hr;\r
+ }\r
+ }\r
+ LONGLONG RunTime = GetElapsedTime() - StartTime;\r
+ double Rate = 2000.0 / ((double)RunTime / (double)GetFrequency());\r
+ printf( "%7.2f lookups per second\n", Rate );\r
+\r
+ return 0;\r
+}\r