mirror of
https://github.com/microsoft/WSL.git
synced 2025-07-04 07:43:21 +00:00
3057 lines
76 KiB
C
3057 lines
76 KiB
C
![]() |
/*++
|
||
|
|
||
|
Copyright (c) Microsoft. All rights reserved.
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
vnet.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This file is a test of virtual network devices.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "lxtcommon.h"
|
||
|
#include "unittests.h"
|
||
|
#include <fcntl.h>
|
||
|
#include <unistd.h>
|
||
|
#include <sys/ioctl.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <sys/wait.h>
|
||
|
#include <sys/socket.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <stddef.h>
|
||
|
#include <bits/local_lim.h>
|
||
|
#include <net/if.h>
|
||
|
#include <net/if_arp.h>
|
||
|
#include <arpa/inet.h>
|
||
|
#include <netinet/in.h>
|
||
|
#include <netinet/ip.h>
|
||
|
#include <netinet/udp.h>
|
||
|
#include <netinet/tcp.h>
|
||
|
#include <linux/icmp.h>
|
||
|
#include <netinet/icmp6.h>
|
||
|
#include <net/if.h>
|
||
|
#include <linux/net_namespace.h>
|
||
|
#include <linux/netlink.h>
|
||
|
#include <linux/rtnetlink.h>
|
||
|
#include <linux/sockios.h>
|
||
|
#include <linux/veth.h>
|
||
|
|
||
|
//
|
||
|
// Globals.
|
||
|
//
|
||
|
|
||
|
#define LXT_NAME "VirtualNetwork"
|
||
|
#define LXT_REQUEST_SEQUENCE 0x4567
|
||
|
#define LXT_IP_ADDRESS1 "172.12.13.113"
|
||
|
#define LXT_IP_ADDRESS2 "172.12.13.114"
|
||
|
|
||
|
//
|
||
|
// Functions.
|
||
|
//
|
||
|
|
||
|
int BindSocketForNetlink(int Socket);
|
||
|
|
||
|
int CreateVirtualBridgeViaIoctl(const char* Name);
|
||
|
|
||
|
int CreateVirtualBridgeViaNetlink(const char* Name);
|
||
|
|
||
|
void CreateVirtualDeviceInfo(const char* Type, const char* Name, const char* DeviceData, int DeviceDataSize, char* Buffer, int* BufferSize);
|
||
|
|
||
|
int CreateVirtualDeviceViaNetlink(int Flags, const char* DeviceData, int DeviceDataSize, struct nlmsghdr** Response);
|
||
|
|
||
|
int CreateVirtualEthernetPairViaNetlink(const char* Name, const char* PeerName);
|
||
|
|
||
|
int DeleteVirtualDeviceViaNetlink(const char* Name);
|
||
|
|
||
|
int DeleteVirtualBridgeViaIoctl(const char* Name);
|
||
|
|
||
|
int GetNetworkInterfaceIndex(const char* Name);
|
||
|
|
||
|
int SetIpAddress(const char* InterfaceName, const struct in_addr* AddressIpv4, char PrefixLength);
|
||
|
|
||
|
int SetRoute(const char* InterfaceName, const struct in_addr* AddressIpv4, int PrefixLength);
|
||
|
|
||
|
int SetVirtualDeviceAttributeViaNetlink(const char* Name, int AttributeType, int AttributeValue, int* Response);
|
||
|
|
||
|
int SetVirtualDeviceFlagViaNetlink(const char* Name, int Flag, bool IsFlagEnabled, int* Response);
|
||
|
|
||
|
int VerifyRouteLinkDoesNotExist(
|
||
|
const char* InterfaceName,
|
||
|
/* optional */ int* SocketToUse);
|
||
|
|
||
|
int VerifyRouteLinkExists(
|
||
|
const char* InterfaceName,
|
||
|
/* optional */ int* SocketToUse);
|
||
|
|
||
|
//
|
||
|
// Test cases.
|
||
|
//
|
||
|
|
||
|
LXT_VARIATION_HANDLER EmptyDeviceErrorFromNetlink;
|
||
|
LXT_VARIATION_HANDLER PhysicalDeviceNamespace1;
|
||
|
LXT_VARIATION_HANDLER SanityPermissionsCheck;
|
||
|
LXT_VARIATION_HANDLER VirtualBridgeAutoName;
|
||
|
LXT_VARIATION_HANDLER VirtualBridgeFromIoctl1;
|
||
|
LXT_VARIATION_HANDLER VirtualBridgeNamespace1;
|
||
|
LXT_VARIATION_HANDLER VirtualBridgeFromNetlink1;
|
||
|
LXT_VARIATION_HANDLER VirtualEthernetPairFromNetlink1;
|
||
|
LXT_VARIATION_HANDLER VirtualEthernetPairFromNetlink2;
|
||
|
LXT_VARIATION_HANDLER VirtualEthernetPairNamespace1;
|
||
|
LXT_VARIATION_HANDLER VirtualEthernetPairNamespace2;
|
||
|
LXT_VARIATION_HANDLER VirtualEthernetPairNamespace3;
|
||
|
LXT_VARIATION_HANDLER VirtualEthernetPairNamespace4;
|
||
|
LXT_VARIATION_HANDLER VirtualEthernetPairNamespace5;
|
||
|
LXT_VARIATION_HANDLER VirtualEthernetPairConfigure;
|
||
|
LXT_VARIATION_HANDLER VirtualEthernetPairData;
|
||
|
LXT_VARIATION_HANDLER VirtualEthernetPairNamespaceData;
|
||
|
|
||
|
//
|
||
|
// Global constants
|
||
|
//
|
||
|
|
||
|
static const LXT_VARIATION g_LxtVariations[] = {
|
||
|
{"Permissions Check", SanityPermissionsCheck},
|
||
|
{"No Device Error Check", EmptyDeviceErrorFromNetlink},
|
||
|
{"Virtual Bridge IOCTL", VirtualBridgeFromIoctl1},
|
||
|
{"Virtual Bridge Netlink", VirtualBridgeFromNetlink1},
|
||
|
{"Virtual Bridge auto name generation", VirtualBridgeAutoName},
|
||
|
{"Virtual Ethernet Pair", VirtualEthernetPairFromNetlink1},
|
||
|
{"Virtual Ethernet Pair (part 2)", VirtualEthernetPairFromNetlink2},
|
||
|
{"Virtual Bridge basic namespace check", VirtualBridgeNamespace1},
|
||
|
{"Virtual Ethernet Pair basic namespace check", VirtualEthernetPairNamespace1},
|
||
|
{"Virtual Ethernet Pair namespace check (part 2)", VirtualEthernetPairNamespace2},
|
||
|
{"Virtual Ethernet Pair namespace check (part 3)", VirtualEthernetPairNamespace3},
|
||
|
{"Virtual Ethernet Pair namespace link verification", VirtualEthernetPairNamespace4},
|
||
|
{"Virtual Ethernet Pair namespace socket check", VirtualEthernetPairNamespace5},
|
||
|
{"Virtual Ethernet Pair simple configuration", VirtualEthernetPairConfigure},
|
||
|
|
||
|
//
|
||
|
// Requires firewall manipulation to allow packet traversal
|
||
|
//
|
||
|
|
||
|
//{"Virtual Ethernet Pair data check", VirtualEthernetPairData},
|
||
|
//{"Virtual Ethernet Pair namespace data check", VirtualEthernetPairNamespaceData},
|
||
|
|
||
|
//
|
||
|
// Moving physical adpaters between namespaces is not currently supported
|
||
|
//
|
||
|
|
||
|
//{"Physical device basic namespace check", PhysicalDeviceNamespace1},
|
||
|
};
|
||
|
|
||
|
int VnetTestEntry(int Argc, char* Argv[])
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine main entry point for the virtual network device test.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Argc - Supplies the number of command line arguments.
|
||
|
|
||
|
Argv - Supplies the command line arguments.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
LXT_ARGS Args;
|
||
|
int OriginalNetworkNamespaceFd;
|
||
|
int Result;
|
||
|
|
||
|
OriginalNetworkNamespaceFd = -1;
|
||
|
LxtCheckResult(LxtInitialize(Argc, Argv, &Args, LXT_NAME));
|
||
|
|
||
|
//
|
||
|
// Since new devices are going to be created/destroyed, move to a new
|
||
|
// network namespace to try to prevent polluting the root namespace in case
|
||
|
// of errors.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(OriginalNetworkNamespaceFd = open("/proc/self/ns/net", 0));
|
||
|
LxtCheckErrno(unshare(CLONE_NEWNET));
|
||
|
|
||
|
//
|
||
|
// Run tests.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(LxtRunVariations(&Args, g_LxtVariations, LXT_COUNT_OF(g_LxtVariations)));
|
||
|
|
||
|
ErrorExit:
|
||
|
|
||
|
//
|
||
|
// Try to restore to original network namespace.
|
||
|
//
|
||
|
|
||
|
if (OriginalNetworkNamespaceFd > 0)
|
||
|
{
|
||
|
setns(OriginalNetworkNamespaceFd, CLONE_NEWNET);
|
||
|
close(OriginalNetworkNamespaceFd);
|
||
|
}
|
||
|
|
||
|
LxtUninitialize();
|
||
|
return !LXT_SUCCESS(Result);
|
||
|
}
|
||
|
|
||
|
int BindSocketForNetlink(int Socket)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine is a helper function to bind a socket for NETLINK use.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Socket - Supplies the socket to bind.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
struct sockaddr_nl BindAddress;
|
||
|
int Result;
|
||
|
|
||
|
memset(&BindAddress, 0, sizeof(BindAddress));
|
||
|
BindAddress.nl_family = AF_NETLINK;
|
||
|
LxtCheckErrno(bind(Socket, (struct sockaddr*)&BindAddress, sizeof(BindAddress)));
|
||
|
|
||
|
Result = 0;
|
||
|
|
||
|
ErrorExit:
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int CreateVirtualBridgeViaIoctl(const char* Name)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine creates a virtual bridge device via the SIOCBRADDBR ioctl.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Name - Supplies the name to assign the new bridge.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
int Result;
|
||
|
int Sock;
|
||
|
|
||
|
Sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||
|
if (Sock < 0)
|
||
|
{
|
||
|
Result = -1;
|
||
|
goto ErrorExit;
|
||
|
}
|
||
|
|
||
|
Result = ioctl(Sock, SIOCBRADDBR, Name);
|
||
|
|
||
|
ErrorExit:
|
||
|
if (Sock > 0)
|
||
|
{
|
||
|
close(Sock);
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
void CreateVirtualDeviceInfo(const char* Type, const char* Name, const char* DeviceData, int DeviceDataSize, char* Buffer, int* BufferSize)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine generates the ifinfomsg and attributes representing a virtual
|
||
|
device.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Type - Supplies the optional name of the virtual device type.
|
||
|
|
||
|
Name - Supplies the name to assign the new device.
|
||
|
|
||
|
DeviceData - Supplies an optional buffer of device-type specific data.
|
||
|
|
||
|
DeviceDataSize - Supplies the size in bytes of DeviceData.
|
||
|
|
||
|
Buffer - Supplies the buffer to store the message. If this is null
|
||
|
BufferSize will return the number of bytes required.
|
||
|
|
||
|
BufferSize - Supplies a pointer to the size of the buffer.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
struct rtattr* Attribute;
|
||
|
int BufferOffset;
|
||
|
struct rtattr* LinkAttribute;
|
||
|
int LinkAttributeMessageOffset;
|
||
|
int LocalBufferSize;
|
||
|
int MessageSize;
|
||
|
int StringLength;
|
||
|
|
||
|
BufferOffset = 0;
|
||
|
if (Buffer == NULL)
|
||
|
{
|
||
|
LocalBufferSize = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LocalBufferSize = *BufferSize;
|
||
|
}
|
||
|
|
||
|
MessageSize = RTA_ALIGN(sizeof(struct ifinfomsg));
|
||
|
if (LocalBufferSize >= MessageSize)
|
||
|
{
|
||
|
memset(&Buffer[BufferOffset], 0, (MessageSize - BufferOffset));
|
||
|
BufferOffset = MessageSize;
|
||
|
}
|
||
|
|
||
|
StringLength = strlen(Name);
|
||
|
MessageSize += RTA_SPACE(StringLength + 1);
|
||
|
if (LocalBufferSize >= MessageSize)
|
||
|
{
|
||
|
Attribute = (struct rtattr*)&Buffer[BufferOffset];
|
||
|
Attribute->rta_len = RTA_LENGTH(StringLength + 1);
|
||
|
Attribute->rta_type = IFLA_IFNAME;
|
||
|
memcpy(RTA_DATA(Attribute), Name, StringLength + 1);
|
||
|
BufferOffset = MessageSize;
|
||
|
}
|
||
|
|
||
|
if ((Type != NULL) || ((DeviceData != NULL) && (DeviceDataSize > 0)))
|
||
|
{
|
||
|
MessageSize += RTA_SPACE(0);
|
||
|
if (LocalBufferSize >= MessageSize)
|
||
|
{
|
||
|
LinkAttribute = (struct rtattr*)&Buffer[BufferOffset];
|
||
|
LinkAttribute->rta_type = IFLA_LINKINFO;
|
||
|
|
||
|
//
|
||
|
// The length of the link attribute contains other nested
|
||
|
// attributes, so remember it here and set it later.
|
||
|
//
|
||
|
|
||
|
LinkAttributeMessageOffset = BufferOffset;
|
||
|
BufferOffset = MessageSize;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LinkAttribute = NULL;
|
||
|
}
|
||
|
|
||
|
StringLength = strlen(Type);
|
||
|
MessageSize += RTA_SPACE(StringLength);
|
||
|
if (LocalBufferSize >= MessageSize)
|
||
|
{
|
||
|
Attribute = (struct rtattr*)&Buffer[BufferOffset];
|
||
|
Attribute->rta_len = RTA_LENGTH(StringLength);
|
||
|
Attribute->rta_type = IFLA_INFO_KIND;
|
||
|
memcpy(RTA_DATA(Attribute), Type, StringLength);
|
||
|
BufferOffset = MessageSize;
|
||
|
}
|
||
|
|
||
|
if ((DeviceData != NULL) && (DeviceDataSize > 0))
|
||
|
{
|
||
|
MessageSize += RTA_SPACE(DeviceDataSize);
|
||
|
if (LocalBufferSize >= MessageSize)
|
||
|
{
|
||
|
Attribute = (struct rtattr*)&Buffer[BufferOffset];
|
||
|
Attribute->rta_len = RTA_LENGTH(DeviceDataSize);
|
||
|
Attribute->rta_type = IFLA_INFO_DATA;
|
||
|
memcpy(RTA_DATA(Attribute), DeviceData, DeviceDataSize);
|
||
|
BufferOffset = MessageSize;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (LinkAttribute != NULL)
|
||
|
{
|
||
|
LinkAttribute->rta_len = MessageSize - LinkAttributeMessageOffset;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*BufferSize = MessageSize;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
int CreateVirtualBridgeViaNetlink(const char* Name)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine creates a new virtual bridge using the netlink RTM_NEWLINK
|
||
|
message. On success the caller should free the Response buffer.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Name - Supplies the name to give the new virtual bridge.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
char* DeviceData;
|
||
|
int DeviceDataSize;
|
||
|
struct nlmsgerr* ErrorMessage;
|
||
|
struct nlmsghdr* Response;
|
||
|
int Result;
|
||
|
|
||
|
Response = NULL;
|
||
|
|
||
|
//
|
||
|
// Determine the size of the device data part of the message.
|
||
|
//
|
||
|
|
||
|
CreateVirtualDeviceInfo("bridge", Name, NULL, 0, NULL, &DeviceDataSize);
|
||
|
|
||
|
//
|
||
|
// Allocate a buffer to hold the device data.
|
||
|
//
|
||
|
|
||
|
DeviceData = LxtAlloc(DeviceDataSize);
|
||
|
if (DeviceData == NULL)
|
||
|
{
|
||
|
Result = -1;
|
||
|
goto ErrorExit;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Fill in the device data buffer.
|
||
|
//
|
||
|
|
||
|
CreateVirtualDeviceInfo("bridge", Name, NULL, 0, DeviceData, &DeviceDataSize);
|
||
|
|
||
|
//
|
||
|
// Attempt to create the device.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(CreateVirtualDeviceViaNetlink((NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK | NLM_F_REQUEST), DeviceData, DeviceDataSize, &Response));
|
||
|
|
||
|
//
|
||
|
// Verify success.
|
||
|
//
|
||
|
|
||
|
ErrorMessage = NLMSG_DATA(Response);
|
||
|
LxtCheckEqual(ErrorMessage->error, 0, "%d");
|
||
|
Result = 0;
|
||
|
|
||
|
ErrorExit:
|
||
|
if (Response != NULL)
|
||
|
{
|
||
|
LxtFree(Response);
|
||
|
}
|
||
|
|
||
|
if (DeviceData != NULL)
|
||
|
{
|
||
|
LxtFree(DeviceData);
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int CreateVirtualDeviceViaNetlink(int Flags, const char* DeviceData, int DeviceDataSize, struct nlmsghdr** Response)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine creates a new virtual device using the netlink RTM_NEWLINK
|
||
|
message. On success the caller should free the Response buffer.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Flags - Supplies the message flags.
|
||
|
|
||
|
DeviceData - Supplies the optional device data.
|
||
|
|
||
|
DeviceDataSize - Supplies the size in bytes of the device data.
|
||
|
|
||
|
Response - Supplies a pointer to be filled in with newly allocated memory
|
||
|
holding the response. It is the caller's responsibility to free this
|
||
|
memory.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
socklen_t AddressLength;
|
||
|
struct nlmsgerr* ErrorMessage;
|
||
|
struct nlmsghdr* NextResponseMessage;
|
||
|
struct nlmsghdr* RequestMessage;
|
||
|
int RequestMessageSize;
|
||
|
struct nlmsghdr* ResponseMessage;
|
||
|
int ResponseMessageSize;
|
||
|
int ReceiveResult;
|
||
|
int Result;
|
||
|
int Socket;
|
||
|
|
||
|
//
|
||
|
// Allocate space for the request and the response.
|
||
|
//
|
||
|
|
||
|
RequestMessageSize = NLMSG_SPACE(DeviceDataSize);
|
||
|
RequestMessage = LxtAlloc(RequestMessageSize);
|
||
|
if (RequestMessage == NULL)
|
||
|
{
|
||
|
Result = ENOMEM;
|
||
|
goto ErrorExit;
|
||
|
}
|
||
|
|
||
|
ResponseMessageSize = RequestMessageSize + sizeof(*ErrorMessage);
|
||
|
ResponseMessage = LxtAlloc(ResponseMessageSize);
|
||
|
if (RequestMessage == NULL)
|
||
|
{
|
||
|
Result = ENOMEM;
|
||
|
goto ErrorExit;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Create and bind socket.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(Socket = socket(AF_NETLINK, SOCK_RAW, 0));
|
||
|
LxtCheckErrno(BindSocketForNetlink(Socket));
|
||
|
|
||
|
//
|
||
|
// Create a RTM_NEWLINK request.
|
||
|
//
|
||
|
|
||
|
memset(RequestMessage, 0, sizeof(*RequestMessage));
|
||
|
RequestMessage->nlmsg_len = RequestMessageSize;
|
||
|
RequestMessage->nlmsg_type = RTM_NEWLINK;
|
||
|
RequestMessage->nlmsg_seq = LXT_REQUEST_SEQUENCE;
|
||
|
RequestMessage->nlmsg_flags = Flags;
|
||
|
memcpy(NLMSG_DATA(RequestMessage), DeviceData, DeviceDataSize);
|
||
|
LxtCheckErrno(sendto(Socket, RequestMessage, RequestMessageSize, 0, NULL, 0));
|
||
|
|
||
|
//
|
||
|
// Get the response.
|
||
|
//
|
||
|
|
||
|
memset(ResponseMessage, 0, ResponseMessageSize);
|
||
|
LxtCheckErrno(ReceiveResult = recvfrom(Socket, ResponseMessage, ResponseMessageSize, 0, NULL, 0));
|
||
|
|
||
|
LxtCheckTrue(NLMSG_OK(ResponseMessage, ReceiveResult));
|
||
|
LxtCheckEqual(ResponseMessage->nlmsg_type, NLMSG_ERROR, "%d");
|
||
|
LxtCheckGreater((ResponseMessage->nlmsg_len + 1), NLMSG_PAYLOAD(ResponseMessage, 0), "%d");
|
||
|
|
||
|
ErrorMessage = NLMSG_DATA(ResponseMessage);
|
||
|
if (ErrorMessage->error < 0)
|
||
|
{
|
||
|
|
||
|
//
|
||
|
// On error, the entire message should be returned.
|
||
|
//
|
||
|
|
||
|
LxtCheckEqual(ResponseMessage->nlmsg_len, ResponseMessageSize, "%d");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
//
|
||
|
// On success, just the header of the original message is expected to
|
||
|
// be returned, which is already included in the error message size.
|
||
|
//
|
||
|
|
||
|
LxtCheckEqual(ResponseMessage->nlmsg_len, NLMSG_SPACE(sizeof(*ErrorMessage)), "%d");
|
||
|
}
|
||
|
|
||
|
LxtCheckEqual(ResponseMessage->nlmsg_flags, 0, "%d");
|
||
|
LxtCheckEqual(ResponseMessage->nlmsg_seq, LXT_REQUEST_SEQUENCE, "%d");
|
||
|
LxtCheckEqual(ResponseMessage->nlmsg_pid, getpid(), "%d");
|
||
|
NextResponseMessage = NLMSG_NEXT(ResponseMessage, ReceiveResult);
|
||
|
LxtCheckTrue(NLMSG_OK(NextResponseMessage, ReceiveResult) == FALSE);
|
||
|
Result = 0;
|
||
|
|
||
|
ErrorExit:
|
||
|
if (Socket > 0)
|
||
|
{
|
||
|
close(Socket);
|
||
|
}
|
||
|
|
||
|
if (RequestMessage != NULL)
|
||
|
{
|
||
|
LxtFree(RequestMessage);
|
||
|
}
|
||
|
|
||
|
if (Result != 0)
|
||
|
{
|
||
|
if (ResponseMessage != NULL)
|
||
|
{
|
||
|
LxtFree(ResponseMessage);
|
||
|
}
|
||
|
|
||
|
errno = Result;
|
||
|
return -1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*Response = ResponseMessage;
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int DeleteVirtualBridgeViaIoctl(const char* Name)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine deletes a virtual bridge device via the SIOCBRDELBR ioctl.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Name - Supplies the name to assign the new bridge.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
int Result;
|
||
|
int Sock;
|
||
|
|
||
|
Sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||
|
if (Sock < 0)
|
||
|
{
|
||
|
Result = -1;
|
||
|
goto ErrorExit;
|
||
|
}
|
||
|
|
||
|
Result = ioctl(Sock, SIOCBRDELBR, Name);
|
||
|
|
||
|
ErrorExit:
|
||
|
if (Sock > 0)
|
||
|
{
|
||
|
close(Sock);
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int DeleteVirtualDeviceViaNetlink(const char* Name)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine removes a virtual device using the netlink RTM_DELLLINK
|
||
|
message.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Name - Supplies the name of the device to delete.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
socklen_t AddressLength;
|
||
|
int InterfaceIndex;
|
||
|
struct nlmsghdr* NextResponseMessage;
|
||
|
int ReceiveResult;
|
||
|
struct
|
||
|
{
|
||
|
struct nlmsghdr Header;
|
||
|
struct ifinfomsg Message __attribute__((aligned(NLMSG_ALIGNTO)));
|
||
|
} RequestMessage;
|
||
|
struct
|
||
|
{
|
||
|
struct nlmsghdr Header;
|
||
|
struct nlmsgerr Error __attribute__((aligned(NLMSG_ALIGNTO)));
|
||
|
} ResponseMessage;
|
||
|
int Result;
|
||
|
int Socket;
|
||
|
|
||
|
LxtCheckErrno(InterfaceIndex = GetNetworkInterfaceIndex(Name));
|
||
|
|
||
|
//
|
||
|
// Create and bind NETLINK socket.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(Socket = socket(AF_NETLINK, SOCK_RAW, 0));
|
||
|
LxtCheckErrno(BindSocketForNetlink(Socket));
|
||
|
|
||
|
//
|
||
|
// Create a RTM_DELLINK request.
|
||
|
//
|
||
|
|
||
|
memset(&RequestMessage, 0, sizeof(RequestMessage));
|
||
|
RequestMessage.Header.nlmsg_len = sizeof(RequestMessage);
|
||
|
RequestMessage.Header.nlmsg_type = RTM_DELLINK;
|
||
|
RequestMessage.Header.nlmsg_seq = LXT_REQUEST_SEQUENCE;
|
||
|
RequestMessage.Header.nlmsg_flags = NLM_F_ACK | NLM_F_REQUEST;
|
||
|
RequestMessage.Message.ifi_index = InterfaceIndex;
|
||
|
LxtCheckErrno(sendto(Socket, &RequestMessage, sizeof(RequestMessage), 0, NULL, 0));
|
||
|
|
||
|
//
|
||
|
// Get the response.
|
||
|
//
|
||
|
|
||
|
memset(&ResponseMessage, 0, sizeof(ResponseMessage));
|
||
|
LxtCheckErrno(ReceiveResult = recvfrom(Socket, &ResponseMessage, sizeof(ResponseMessage), 0, NULL, 0));
|
||
|
|
||
|
LxtCheckTrue(NLMSG_OK(&ResponseMessage.Header, ReceiveResult));
|
||
|
LxtCheckEqual(ResponseMessage.Header.nlmsg_type, NLMSG_ERROR, "%d");
|
||
|
LxtCheckEqual(ResponseMessage.Header.nlmsg_len, sizeof(ResponseMessage), "%d");
|
||
|
|
||
|
LxtCheckEqual(ResponseMessage.Header.nlmsg_flags, 0, "%d");
|
||
|
LxtCheckEqual(ResponseMessage.Header.nlmsg_seq, LXT_REQUEST_SEQUENCE, "%d");
|
||
|
LxtCheckEqual(ResponseMessage.Header.nlmsg_pid, getpid(), "%d");
|
||
|
LxtCheckEqual(ResponseMessage.Error.error, 0, "%d");
|
||
|
NextResponseMessage = NLMSG_NEXT(&ResponseMessage.Header, ReceiveResult);
|
||
|
LxtCheckTrue(NLMSG_OK(NextResponseMessage, ReceiveResult) == FALSE);
|
||
|
Result = 0;
|
||
|
|
||
|
ErrorExit:
|
||
|
if (Socket > 0)
|
||
|
{
|
||
|
close(Socket);
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int CreateVirtualEthernetPairViaNetlink(const char* Name, const char* PeerName)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine creates a new virtual bridge using the netlink RTM_NEWLINK
|
||
|
message. On success the caller should free the Response buffer.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Name - Supplies the name to give the new virtual ethernet.
|
||
|
|
||
|
PeerName - Supplies the name to give the other end of the new virtual
|
||
|
ethernet pair.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
struct rtattr* Attribute;
|
||
|
char* DeviceData;
|
||
|
int DeviceDataSize;
|
||
|
struct nlmsgerr* ErrorMessage;
|
||
|
char* PeerDeviceData;
|
||
|
int PeerDeviceDataSize;
|
||
|
struct nlmsghdr* Response;
|
||
|
int Result;
|
||
|
|
||
|
Response = NULL;
|
||
|
|
||
|
//
|
||
|
// Determine the size of the peer device data part of the message.
|
||
|
//
|
||
|
|
||
|
CreateVirtualDeviceInfo(NULL, PeerName, NULL, 0, NULL, &PeerDeviceDataSize);
|
||
|
|
||
|
//
|
||
|
// Allocate a buffer to hold the peer device data.
|
||
|
//
|
||
|
|
||
|
PeerDeviceData = LxtAlloc(RTA_SPACE(PeerDeviceDataSize));
|
||
|
if (PeerDeviceData == NULL)
|
||
|
{
|
||
|
Result = -1;
|
||
|
goto ErrorExit;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Fill in the peer device data buffer.
|
||
|
//
|
||
|
|
||
|
Attribute = (struct rtattr*)PeerDeviceData;
|
||
|
Attribute->rta_len = RTA_LENGTH(PeerDeviceDataSize);
|
||
|
Attribute->rta_type = VETH_INFO_PEER;
|
||
|
CreateVirtualDeviceInfo(NULL, PeerName, NULL, 0, RTA_DATA(Attribute), &PeerDeviceDataSize);
|
||
|
|
||
|
//
|
||
|
// Determine the size of the device data part of the message.
|
||
|
//
|
||
|
|
||
|
CreateVirtualDeviceInfo("veth", Name, PeerDeviceData, Attribute->rta_len, NULL, &DeviceDataSize);
|
||
|
|
||
|
//
|
||
|
// Allocate a buffer to hold the peer device data.
|
||
|
//
|
||
|
|
||
|
DeviceData = LxtAlloc(DeviceDataSize);
|
||
|
if (DeviceData == NULL)
|
||
|
{
|
||
|
Result = -1;
|
||
|
goto ErrorExit;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Fill in the peer device data buffer.
|
||
|
//
|
||
|
|
||
|
CreateVirtualDeviceInfo("veth", Name, PeerDeviceData, Attribute->rta_len, DeviceData, &DeviceDataSize);
|
||
|
|
||
|
//
|
||
|
// Attempt to create the device.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(CreateVirtualDeviceViaNetlink((NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK | NLM_F_REQUEST), DeviceData, DeviceDataSize, &Response));
|
||
|
|
||
|
//
|
||
|
// Verify success.
|
||
|
//
|
||
|
|
||
|
ErrorMessage = NLMSG_DATA(Response);
|
||
|
LxtCheckEqual(ErrorMessage->error, 0, "%d");
|
||
|
Result = 0;
|
||
|
|
||
|
ErrorExit:
|
||
|
if (Response != NULL)
|
||
|
{
|
||
|
LxtFree(Response);
|
||
|
}
|
||
|
|
||
|
if (DeviceData != NULL)
|
||
|
{
|
||
|
LxtFree(DeviceData);
|
||
|
}
|
||
|
|
||
|
if (PeerDeviceData != NULL)
|
||
|
{
|
||
|
LxtFree(PeerDeviceData);
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int GetNetworkInterfaceIndex(const char* Name)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine returns the network interface index of a device.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Name - Supplies the name of the device
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns the index on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
struct ifreq InterfaceRequest;
|
||
|
int Result;
|
||
|
int Socket;
|
||
|
|
||
|
Socket = socket(AF_UNIX, SOCK_DGRAM, 0);
|
||
|
if (Socket < 0)
|
||
|
{
|
||
|
Result = -1;
|
||
|
goto ErrorExit;
|
||
|
}
|
||
|
|
||
|
memset(&InterfaceRequest, 0, sizeof(InterfaceRequest));
|
||
|
strcpy(InterfaceRequest.ifr_name, Name);
|
||
|
Result = ioctl(Socket, SIOCGIFINDEX, &InterfaceRequest);
|
||
|
LxtClose(Socket);
|
||
|
if (Result < 0)
|
||
|
{
|
||
|
goto ErrorExit;
|
||
|
}
|
||
|
|
||
|
Result = InterfaceRequest.ifr_ifindex;
|
||
|
|
||
|
ErrorExit:
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int EmptyDeviceErrorFromNetlink(PLXT_ARGS Args)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine sends a create message with no device described. This pattern
|
||
|
is used by tools like 'ip' to determine if the system supports virtual
|
||
|
network device creation.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Args - Supplies the command line arguments.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
struct ifinfomsg DeviceData;
|
||
|
struct nlmsgerr* ErrorMessage;
|
||
|
struct nlmsghdr* Response;
|
||
|
int Result;
|
||
|
|
||
|
Response = NULL;
|
||
|
memset(&DeviceData, 0, sizeof(DeviceData));
|
||
|
LxtCheckResult(CreateVirtualDeviceViaNetlink((NLM_F_REQUEST | NLM_F_ACK), (const char*)&DeviceData, sizeof(DeviceData), &Response));
|
||
|
|
||
|
ErrorMessage = NLMSG_DATA(Response);
|
||
|
LxtCheckEqual(ErrorMessage->error, -ENODEV, "%d");
|
||
|
Result = 0;
|
||
|
|
||
|
ErrorExit:
|
||
|
if (Response != NULL)
|
||
|
{
|
||
|
LxtFree(Response);
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int PhysicalDeviceNamespace1(PLXT_ARGS Args)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine does basic network namespace sanity testing with a physical
|
||
|
device (assumes existence of eth0):
|
||
|
1) creates a new namespace
|
||
|
2) attempt to move eth0 to new namespace
|
||
|
3) close new namespace
|
||
|
4) verify device was returned to the root namespace
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Args - Supplies the command line arguments.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
int NewNetworkNamespaceFd;
|
||
|
int OriginalNetworkNamespaceFd;
|
||
|
int RootNetworkNamespaceFd;
|
||
|
int Response;
|
||
|
int Result;
|
||
|
|
||
|
NewNetworkNamespaceFd = 0;
|
||
|
OriginalNetworkNamespaceFd = 0;
|
||
|
|
||
|
//
|
||
|
// Open file descriptor of default network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(OriginalNetworkNamespaceFd = open("/proc/self/ns/net", 0));
|
||
|
|
||
|
//
|
||
|
// Open file descriptor of the root network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(RootNetworkNamespaceFd = open("/proc/1/ns/net", 0));
|
||
|
|
||
|
//
|
||
|
// Switch to a new network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(unshare(CLONE_NEWNET));
|
||
|
|
||
|
//
|
||
|
// Open file descriptor of the new network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(NewNetworkNamespaceFd = open("/proc/self/ns/net", 0));
|
||
|
|
||
|
//
|
||
|
// Switch to root network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(setns(RootNetworkNamespaceFd, CLONE_NEWNET));
|
||
|
|
||
|
//
|
||
|
// Try to move eth0 to the new network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(SetVirtualDeviceAttributeViaNetlink("eth0", IFLA_NET_NS_FD, NewNetworkNamespaceFd, &Response));
|
||
|
|
||
|
LxtCheckEqual(Response, 0, "%d");
|
||
|
|
||
|
//
|
||
|
// Verify that the device is gone.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrnoFailure(GetNetworkInterfaceIndex("eth0"), ENODEV);
|
||
|
|
||
|
//
|
||
|
// Close the new network namespace. This should restore any physical
|
||
|
// devices to the root network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckClose(NewNetworkNamespaceFd);
|
||
|
|
||
|
//
|
||
|
// Pause for a bit to allow background processing to occur.
|
||
|
//
|
||
|
|
||
|
sleep(1);
|
||
|
|
||
|
//
|
||
|
// Verify that the device is back.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(GetNetworkInterfaceIndex("eth0"));
|
||
|
|
||
|
//
|
||
|
// Restore back to default network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(setns(OriginalNetworkNamespaceFd, CLONE_NEWNET));
|
||
|
|
||
|
ErrorExit:
|
||
|
if (NewNetworkNamespaceFd > 0)
|
||
|
{
|
||
|
close(NewNetworkNamespaceFd);
|
||
|
}
|
||
|
|
||
|
if (RootNetworkNamespaceFd > 0)
|
||
|
{
|
||
|
close(RootNetworkNamespaceFd);
|
||
|
}
|
||
|
|
||
|
if (OriginalNetworkNamespaceFd > 0)
|
||
|
{
|
||
|
close(OriginalNetworkNamespaceFd);
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int SanityPermissionsCheck(PLXT_ARGS Args)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine does a simple operation to check that the current user has
|
||
|
appropriate permissions. This should be run as the first test to give a
|
||
|
quick error to the user that typically the entire test needs to be run
|
||
|
with sudo.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Args - Supplies the command line arguments.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
struct ifinfomsg DeviceData;
|
||
|
struct nlmsgerr* ErrorMessage;
|
||
|
struct nlmsghdr* Response;
|
||
|
int Result;
|
||
|
|
||
|
Response = NULL;
|
||
|
memset(&DeviceData, 0, sizeof(DeviceData));
|
||
|
LxtCheckResult(CreateVirtualDeviceViaNetlink((NLM_F_REQUEST | NLM_F_ACK), (const char*)&DeviceData, sizeof(DeviceData), &Response));
|
||
|
|
||
|
ErrorMessage = NLMSG_DATA(Response);
|
||
|
if (ErrorMessage->error == -1)
|
||
|
{
|
||
|
LxtLogError("Make sure test is run with sudo!");
|
||
|
Result = -1;
|
||
|
goto ErrorExit;
|
||
|
}
|
||
|
|
||
|
Result = 0;
|
||
|
|
||
|
ErrorExit:
|
||
|
if (Response != NULL)
|
||
|
{
|
||
|
LxtFree(Response);
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int SetIpAddress(const char* InterfaceName, const struct in_addr* AddressIpv4, char PrefixLength)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine adds an IP address to a network interface.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
InterfaceName - Supplies the interface name.
|
||
|
|
||
|
AddressIpv4 - Supplies the IP address.
|
||
|
|
||
|
PrefixLength - Supplies the prefix length of the address.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
socklen_t AddressLength;
|
||
|
struct nlmsgerr* ErrorMessage;
|
||
|
int InterfaceIndex;
|
||
|
int ReceiveResult;
|
||
|
struct
|
||
|
{
|
||
|
struct nlmsghdr Header;
|
||
|
struct ifaddrmsg Message __attribute__((aligned(NLMSG_ALIGNTO)));
|
||
|
struct
|
||
|
{
|
||
|
struct rtattr RtHeader __attribute__((aligned(RTA_ALIGNTO)));
|
||
|
struct in_addr AddressIpv4 __attribute__((aligned(RTA_ALIGNTO)));
|
||
|
} AddressAttribute;
|
||
|
struct
|
||
|
{
|
||
|
struct rtattr RtHeader __attribute__((aligned(RTA_ALIGNTO)));
|
||
|
struct in_addr AddressIpv4 __attribute__((aligned(RTA_ALIGNTO)));
|
||
|
} LocalAddressAttribute;
|
||
|
} RequestMessage;
|
||
|
struct
|
||
|
{
|
||
|
struct nlmsghdr Header;
|
||
|
struct nlmsgerr Error __attribute__((aligned(NLMSG_ALIGNTO)));
|
||
|
} ResponseMessage;
|
||
|
int Result;
|
||
|
int Socket;
|
||
|
|
||
|
LxtCheckErrno(InterfaceIndex = GetNetworkInterfaceIndex(InterfaceName));
|
||
|
|
||
|
//
|
||
|
// Create and bind NETLINK socket.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(Socket = socket(AF_NETLINK, SOCK_RAW, 0));
|
||
|
LxtCheckErrno(BindSocketForNetlink(Socket));
|
||
|
|
||
|
//
|
||
|
// Create a RTM_NEWLINK request.
|
||
|
//
|
||
|
|
||
|
memset(&RequestMessage, 0, sizeof(RequestMessage));
|
||
|
RequestMessage.Header.nlmsg_len = sizeof(RequestMessage);
|
||
|
RequestMessage.Header.nlmsg_type = RTM_NEWADDR;
|
||
|
RequestMessage.Header.nlmsg_seq = LXT_REQUEST_SEQUENCE;
|
||
|
RequestMessage.Header.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK | NLM_F_REQUEST;
|
||
|
|
||
|
RequestMessage.Message.ifa_family = AF_INET;
|
||
|
RequestMessage.Message.ifa_prefixlen = PrefixLength;
|
||
|
RequestMessage.Message.ifa_index = InterfaceIndex;
|
||
|
RequestMessage.AddressAttribute.RtHeader.rta_len = RTA_LENGTH(sizeof(*AddressIpv4));
|
||
|
|
||
|
RequestMessage.AddressAttribute.RtHeader.rta_type = IFA_ADDRESS;
|
||
|
memcpy(&RequestMessage.AddressAttribute.AddressIpv4, AddressIpv4, sizeof(*AddressIpv4));
|
||
|
|
||
|
RequestMessage.LocalAddressAttribute.RtHeader.rta_len = RTA_LENGTH(sizeof(*AddressIpv4));
|
||
|
|
||
|
RequestMessage.LocalAddressAttribute.RtHeader.rta_type = IFA_LOCAL;
|
||
|
memcpy(&RequestMessage.LocalAddressAttribute.AddressIpv4, AddressIpv4, sizeof(*AddressIpv4));
|
||
|
|
||
|
LxtCheckErrno(sendto(Socket, &RequestMessage, sizeof(RequestMessage), 0, NULL, 0));
|
||
|
|
||
|
//
|
||
|
// Get the response.
|
||
|
//
|
||
|
|
||
|
memset(&ResponseMessage, 0, sizeof(ResponseMessage));
|
||
|
LxtCheckErrno(ReceiveResult = recvfrom(Socket, &ResponseMessage, sizeof(ResponseMessage), 0, NULL, 0));
|
||
|
|
||
|
LxtCheckEqual(ReceiveResult, sizeof(ResponseMessage), "%d");
|
||
|
if (ResponseMessage.Header.nlmsg_len != ReceiveResult)
|
||
|
{
|
||
|
LxtCheckGreater(ResponseMessage.Header.nlmsg_len, ReceiveResult, "%d");
|
||
|
}
|
||
|
|
||
|
LxtCheckEqual(ResponseMessage.Header.nlmsg_type, NLMSG_ERROR, "%d");
|
||
|
LxtCheckEqual(ResponseMessage.Header.nlmsg_flags, 0, "%d");
|
||
|
LxtCheckEqual(ResponseMessage.Header.nlmsg_seq, LXT_REQUEST_SEQUENCE, "%d");
|
||
|
LxtCheckEqual(ResponseMessage.Header.nlmsg_pid, getpid(), "%d");
|
||
|
LxtCheckEqual(ResponseMessage.Error.error, 0, "%d");
|
||
|
Result = 0;
|
||
|
|
||
|
ErrorExit:
|
||
|
if (Socket > 0)
|
||
|
{
|
||
|
close(Socket);
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int SetRoute(const char* InterfaceName, const struct in_addr* AddressIpv4, int PrefixLength)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine adds a route to a network interface.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
InterfaceName - Supplies the interface name.
|
||
|
|
||
|
AddressIpv4 - Supplies the IP address.
|
||
|
|
||
|
PrefixLength - Supplies the prefix length of AddressIpv4.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
socklen_t AddressLength;
|
||
|
struct nlmsgerr* ErrorMessage;
|
||
|
int InterfaceIndex;
|
||
|
int ReceiveResult;
|
||
|
struct
|
||
|
{
|
||
|
struct nlmsghdr Header;
|
||
|
struct rtmsg Message __attribute__((aligned(NLMSG_ALIGNTO)));
|
||
|
struct
|
||
|
{
|
||
|
struct rtattr RtHeader __attribute__((aligned(RTA_ALIGNTO)));
|
||
|
struct in_addr AddressIpv4 __attribute__((aligned(RTA_ALIGNTO)));
|
||
|
} DestAttribute;
|
||
|
struct
|
||
|
{
|
||
|
struct rtattr RtHeader __attribute__((aligned(RTA_ALIGNTO)));
|
||
|
int InterfaceIndex __attribute__((aligned(RTA_ALIGNTO)));
|
||
|
} IndexAttribute;
|
||
|
} RequestMessage;
|
||
|
struct
|
||
|
{
|
||
|
struct nlmsghdr Header;
|
||
|
struct nlmsgerr Error __attribute__((aligned(NLMSG_ALIGNTO)));
|
||
|
} ResponseMessage;
|
||
|
int Result;
|
||
|
int Socket;
|
||
|
|
||
|
LxtCheckErrno(InterfaceIndex = GetNetworkInterfaceIndex(InterfaceName));
|
||
|
|
||
|
//
|
||
|
// Create and bind NETLINK socket.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(Socket = socket(AF_NETLINK, SOCK_RAW, 0));
|
||
|
LxtCheckErrno(BindSocketForNetlink(Socket));
|
||
|
|
||
|
//
|
||
|
// Create a RTM_NEWROUTE request.
|
||
|
//
|
||
|
|
||
|
memset(&RequestMessage, 0, sizeof(RequestMessage));
|
||
|
RequestMessage.Header.nlmsg_len = sizeof(RequestMessage);
|
||
|
RequestMessage.Header.nlmsg_type = RTM_NEWROUTE;
|
||
|
RequestMessage.Header.nlmsg_seq = LXT_REQUEST_SEQUENCE;
|
||
|
RequestMessage.Header.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK | NLM_F_REQUEST;
|
||
|
|
||
|
RequestMessage.Message.rtm_family = AF_INET;
|
||
|
RequestMessage.Message.rtm_dst_len = PrefixLength;
|
||
|
RequestMessage.Message.rtm_table = RT_TABLE_MAIN;
|
||
|
RequestMessage.Message.rtm_protocol = RTPROT_BOOT;
|
||
|
RequestMessage.Message.rtm_scope = RT_SCOPE_LINK;
|
||
|
RequestMessage.Message.rtm_type = RTA_DST;
|
||
|
|
||
|
RequestMessage.DestAttribute.RtHeader.rta_len = RTA_LENGTH(sizeof(*AddressIpv4));
|
||
|
|
||
|
RequestMessage.DestAttribute.RtHeader.rta_type = RTA_DST;
|
||
|
memcpy(&RequestMessage.DestAttribute.AddressIpv4, AddressIpv4, sizeof(*AddressIpv4));
|
||
|
|
||
|
RequestMessage.IndexAttribute.RtHeader.rta_len = RTA_LENGTH(sizeof(int));
|
||
|
|
||
|
RequestMessage.IndexAttribute.RtHeader.rta_type = RTA_OIF;
|
||
|
RequestMessage.IndexAttribute.InterfaceIndex = InterfaceIndex;
|
||
|
|
||
|
LxtCheckErrno(sendto(Socket, &RequestMessage, sizeof(RequestMessage), 0, NULL, 0));
|
||
|
|
||
|
//
|
||
|
// Get the response.
|
||
|
//
|
||
|
|
||
|
memset(&ResponseMessage, 0, sizeof(ResponseMessage));
|
||
|
LxtCheckErrno(ReceiveResult = recvfrom(Socket, &ResponseMessage, sizeof(ResponseMessage), 0, NULL, 0));
|
||
|
|
||
|
LxtCheckEqual(ReceiveResult, sizeof(ResponseMessage), "%d");
|
||
|
if (ResponseMessage.Header.nlmsg_len != ReceiveResult)
|
||
|
{
|
||
|
LxtCheckGreater(ResponseMessage.Header.nlmsg_len, ReceiveResult, "%d");
|
||
|
}
|
||
|
|
||
|
LxtCheckEqual(ResponseMessage.Header.nlmsg_type, NLMSG_ERROR, "%d");
|
||
|
LxtCheckEqual(ResponseMessage.Header.nlmsg_flags, 0, "%d");
|
||
|
LxtCheckEqual(ResponseMessage.Header.nlmsg_seq, LXT_REQUEST_SEQUENCE, "%d");
|
||
|
LxtCheckEqual(ResponseMessage.Header.nlmsg_pid, getpid(), "%d");
|
||
|
LxtCheckEqual(ResponseMessage.Error.error, 0, "%d");
|
||
|
Result = 0;
|
||
|
|
||
|
ErrorExit:
|
||
|
if (Socket > 0)
|
||
|
{
|
||
|
close(Socket);
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int SetVirtualDeviceAttributeViaNetlink(const char* Name, int AttributeType, int AttributeValue, int* Response)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine attempts to move a virtual device to the network namespace
|
||
|
referenced by the NamespaceFd.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Name - Supplies the name of the virtual device.
|
||
|
|
||
|
AttributeType - Supplies the attribute type.
|
||
|
|
||
|
AttributeValue - Supplies the attribute value.
|
||
|
|
||
|
NetworkNamespaceFd - Supplies the file descriptor of a network namespace.
|
||
|
|
||
|
Response - Supplies a pointer to receive the response errno.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
socklen_t AddressLength;
|
||
|
struct nlmsgerr* ErrorMessage;
|
||
|
int InterfaceIndex;
|
||
|
int ReceiveResult;
|
||
|
struct
|
||
|
{
|
||
|
struct nlmsghdr Header;
|
||
|
struct ifinfomsg Message __attribute__((aligned(NLMSG_ALIGNTO)));
|
||
|
struct
|
||
|
{
|
||
|
struct rtattr RtHeader __attribute__((aligned(RTA_ALIGNTO)));
|
||
|
int RtValue __attribute__((aligned(RTA_ALIGNTO)));
|
||
|
} Attribute;
|
||
|
} RequestMessage;
|
||
|
struct
|
||
|
{
|
||
|
struct nlmsghdr Header;
|
||
|
struct nlmsgerr Error __attribute__((aligned(NLMSG_ALIGNTO)));
|
||
|
} ResponseMessage;
|
||
|
int Result;
|
||
|
int Socket;
|
||
|
|
||
|
LxtCheckErrno(InterfaceIndex = GetNetworkInterfaceIndex(Name));
|
||
|
|
||
|
//
|
||
|
// Create and bind NETLINK socket.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(Socket = socket(AF_NETLINK, SOCK_RAW, 0));
|
||
|
LxtCheckErrno(BindSocketForNetlink(Socket));
|
||
|
|
||
|
//
|
||
|
// Create a RTM_NEWLINK update request.
|
||
|
//
|
||
|
|
||
|
memset(&RequestMessage, 0, sizeof(RequestMessage));
|
||
|
RequestMessage.Header.nlmsg_len = sizeof(RequestMessage);
|
||
|
RequestMessage.Header.nlmsg_type = RTM_NEWLINK;
|
||
|
RequestMessage.Header.nlmsg_seq = LXT_REQUEST_SEQUENCE;
|
||
|
RequestMessage.Header.nlmsg_flags = NLM_F_ACK | NLM_F_REQUEST;
|
||
|
RequestMessage.Message.ifi_index = InterfaceIndex;
|
||
|
RequestMessage.Attribute.RtHeader.rta_len = RTA_LENGTH(sizeof(int));
|
||
|
RequestMessage.Attribute.RtHeader.rta_type = AttributeType;
|
||
|
RequestMessage.Attribute.RtValue = AttributeValue;
|
||
|
LxtCheckErrno(sendto(Socket, &RequestMessage, sizeof(RequestMessage), 0, NULL, 0));
|
||
|
|
||
|
//
|
||
|
// Get the response.
|
||
|
//
|
||
|
|
||
|
memset(&ResponseMessage, 0, sizeof(ResponseMessage));
|
||
|
LxtCheckErrno(ReceiveResult = recvfrom(Socket, &ResponseMessage, sizeof(ResponseMessage), 0, NULL, 0));
|
||
|
|
||
|
LxtCheckEqual(ReceiveResult, sizeof(ResponseMessage), "%d");
|
||
|
if (ResponseMessage.Header.nlmsg_len != ReceiveResult)
|
||
|
{
|
||
|
LxtCheckGreater(ResponseMessage.Header.nlmsg_len, ReceiveResult, "%d");
|
||
|
}
|
||
|
|
||
|
LxtCheckEqual(ResponseMessage.Header.nlmsg_type, NLMSG_ERROR, "%d");
|
||
|
LxtCheckEqual(ResponseMessage.Header.nlmsg_flags, 0, "%d");
|
||
|
LxtCheckEqual(ResponseMessage.Header.nlmsg_seq, LXT_REQUEST_SEQUENCE, "%d");
|
||
|
LxtCheckEqual(ResponseMessage.Header.nlmsg_pid, getpid(), "%d");
|
||
|
*Response = ResponseMessage.Error.error;
|
||
|
Result = 0;
|
||
|
|
||
|
ErrorExit:
|
||
|
if (Socket > 0)
|
||
|
{
|
||
|
close(Socket);
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int SetVirtualDeviceFlagViaNetlink(const char* Name, int Flag, bool IsFlagEnabled, int* Response)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine toggles network interface flags (e.g. up/down).
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Name - Supplies the name of the virtual device.
|
||
|
|
||
|
Flag - Supplies the flag to toggle.
|
||
|
|
||
|
IsFlagEnabled - Supplies the state the flag should be set to.
|
||
|
|
||
|
Response - Supplies a pointer to receive the response errno.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
socklen_t AddressLength;
|
||
|
struct nlmsgerr* ErrorMessage;
|
||
|
int InterfaceIndex;
|
||
|
int ReceiveResult;
|
||
|
struct
|
||
|
{
|
||
|
struct nlmsghdr Header;
|
||
|
struct ifinfomsg Message __attribute__((aligned(NLMSG_ALIGNTO)));
|
||
|
} RequestMessage;
|
||
|
struct
|
||
|
{
|
||
|
struct nlmsghdr Header;
|
||
|
struct nlmsgerr Error __attribute__((aligned(NLMSG_ALIGNTO)));
|
||
|
} ResponseMessage;
|
||
|
int Result;
|
||
|
int Socket;
|
||
|
|
||
|
LxtCheckErrno(InterfaceIndex = GetNetworkInterfaceIndex(Name));
|
||
|
|
||
|
//
|
||
|
// Create and bind NETLINK socket.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(Socket = socket(AF_NETLINK, SOCK_RAW, 0));
|
||
|
LxtCheckErrno(BindSocketForNetlink(Socket));
|
||
|
|
||
|
//
|
||
|
// Create a RTM_NEWLINK update request.
|
||
|
//
|
||
|
|
||
|
memset(&RequestMessage, 0, sizeof(RequestMessage));
|
||
|
RequestMessage.Header.nlmsg_len = sizeof(RequestMessage);
|
||
|
RequestMessage.Header.nlmsg_type = RTM_NEWLINK;
|
||
|
RequestMessage.Header.nlmsg_seq = LXT_REQUEST_SEQUENCE;
|
||
|
RequestMessage.Header.nlmsg_flags = NLM_F_ACK | NLM_F_REQUEST;
|
||
|
RequestMessage.Message.ifi_index = InterfaceIndex;
|
||
|
RequestMessage.Message.ifi_change = Flag;
|
||
|
if (IsFlagEnabled)
|
||
|
{
|
||
|
RequestMessage.Message.ifi_flags = Flag;
|
||
|
}
|
||
|
|
||
|
LxtCheckErrno(sendto(Socket, &RequestMessage, sizeof(RequestMessage), 0, NULL, 0));
|
||
|
|
||
|
//
|
||
|
// Get the response.
|
||
|
//
|
||
|
|
||
|
memset(&ResponseMessage, 0, sizeof(ResponseMessage));
|
||
|
LxtCheckErrno(ReceiveResult = recvfrom(Socket, &ResponseMessage, sizeof(ResponseMessage), 0, NULL, 0));
|
||
|
|
||
|
LxtCheckEqual(ReceiveResult, sizeof(ResponseMessage), "%d");
|
||
|
if (ResponseMessage.Header.nlmsg_len != ReceiveResult)
|
||
|
{
|
||
|
LxtCheckGreater(ResponseMessage.Header.nlmsg_len, ReceiveResult, "%d");
|
||
|
}
|
||
|
|
||
|
LxtCheckEqual(ResponseMessage.Header.nlmsg_type, NLMSG_ERROR, "%d");
|
||
|
LxtCheckEqual(ResponseMessage.Header.nlmsg_flags, 0, "%d");
|
||
|
LxtCheckEqual(ResponseMessage.Header.nlmsg_seq, LXT_REQUEST_SEQUENCE, "%d");
|
||
|
LxtCheckEqual(ResponseMessage.Header.nlmsg_pid, getpid(), "%d");
|
||
|
*Response = ResponseMessage.Error.error;
|
||
|
Result = 0;
|
||
|
|
||
|
ErrorExit:
|
||
|
if (Socket > 0)
|
||
|
{
|
||
|
close(Socket);
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int VerifyRouteLinkDoesNotExist(
|
||
|
const char* InterfaceName,
|
||
|
/* optional */ int* SocketToUse)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine attempts to retrieve the link information for a network
|
||
|
interface, expecting that interface not to exist.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
InterfaceName - Supplies the name of the network interface.
|
||
|
|
||
|
SocketToUse - Supplies an optional socket bound to NETLINK to use for the
|
||
|
query.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
socklen_t AddressLength;
|
||
|
bool CloseSocket;
|
||
|
struct nlmsgerr* ErrorMessage;
|
||
|
struct nlmsghdr* Header;
|
||
|
int InterfaceIndex;
|
||
|
size_t InterfaceNameLength;
|
||
|
char ReceiveBuffer[5000];
|
||
|
int ReceiveResult;
|
||
|
int Result;
|
||
|
int Socket;
|
||
|
|
||
|
struct _RequestMessage
|
||
|
{
|
||
|
struct nlmsghdr Header;
|
||
|
struct ifinfomsg Message __attribute__((aligned(NLMSG_ALIGNTO)));
|
||
|
struct
|
||
|
{
|
||
|
struct rtattr RtHeader __attribute__((aligned(RTA_ALIGNTO)));
|
||
|
char InterfaceName[32] __attribute__((aligned(RTA_ALIGNTO)));
|
||
|
} Attribute;
|
||
|
} RequestMessage;
|
||
|
|
||
|
if (SocketToUse != NULL)
|
||
|
{
|
||
|
CloseSocket = false;
|
||
|
Socket = *SocketToUse;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
//
|
||
|
// Create and bind socket. Create a RTM_GETLINK request.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(Socket = socket(AF_NETLINK, SOCK_RAW, 0));
|
||
|
CloseSocket = true;
|
||
|
LxtCheckErrno(BindSocketForNetlink(Socket));
|
||
|
}
|
||
|
|
||
|
memset(&RequestMessage, 0, sizeof(RequestMessage));
|
||
|
RequestMessage.Header.nlmsg_type = RTM_GETLINK;
|
||
|
RequestMessage.Header.nlmsg_seq = LXT_REQUEST_SEQUENCE;
|
||
|
;
|
||
|
RequestMessage.Message.ifi_family = AF_NETLINK;
|
||
|
RequestMessage.Header.nlmsg_flags = NLM_F_REQUEST;
|
||
|
InterfaceNameLength = strlen(InterfaceName) + 1;
|
||
|
LxtCheckGreaterOrEqual(sizeof(RequestMessage.Attribute.InterfaceName), InterfaceNameLength, "%lu");
|
||
|
|
||
|
RequestMessage.Attribute.RtHeader.rta_len = RTA_LENGTH(InterfaceNameLength);
|
||
|
RequestMessage.Attribute.RtHeader.rta_type = IFLA_IFNAME;
|
||
|
memcpy(RequestMessage.Attribute.InterfaceName, InterfaceName, InterfaceNameLength);
|
||
|
|
||
|
RequestMessage.Header.nlmsg_len = offsetof(struct _RequestMessage, Attribute.InterfaceName) + InterfaceNameLength;
|
||
|
|
||
|
LxtCheckErrno(sendto(Socket, &RequestMessage, RequestMessage.Header.nlmsg_len, 0, NULL, 0));
|
||
|
|
||
|
LxtCheckErrno(ReceiveResult = recv(Socket, ReceiveBuffer, sizeof(ReceiveBuffer), 0));
|
||
|
|
||
|
Header = (struct nlmsghdr*)ReceiveBuffer;
|
||
|
LxtCheckTrue(NLMSG_OK(Header, ReceiveResult));
|
||
|
LxtCheckEqual(Header->nlmsg_type, NLMSG_ERROR, "%d");
|
||
|
LxtCheckGreater((Header->nlmsg_len + 1), NLMSG_PAYLOAD(Header, 0), "%d");
|
||
|
|
||
|
ErrorMessage = NLMSG_DATA(Header);
|
||
|
LxtCheckEqual(ErrorMessage->error, -ENODEV, "%d");
|
||
|
|
||
|
ErrorExit:
|
||
|
if (CloseSocket)
|
||
|
{
|
||
|
close(Socket);
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int VerifyRouteLinkExists(
|
||
|
const char* InterfaceName,
|
||
|
/* optional */ int* SocketToUse)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine retrieves the link information for a network interface.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
InterfaceName - Supplies the name of the network interface.
|
||
|
|
||
|
SocketToUse - Supplies an optional socket bound to NETLINK to use for the
|
||
|
query.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
socklen_t AddressLength;
|
||
|
bool CloseSocket;
|
||
|
struct nlmsghdr* Header;
|
||
|
struct ifinfomsg* InterfaceInfo;
|
||
|
int InterfaceIndex;
|
||
|
size_t InterfaceNameLength;
|
||
|
char ReceiveBuffer[5000];
|
||
|
int ReceiveResult;
|
||
|
int Result;
|
||
|
int Socket;
|
||
|
|
||
|
struct _RequestMessage
|
||
|
{
|
||
|
struct nlmsghdr Header;
|
||
|
struct ifinfomsg Message __attribute__((aligned(NLMSG_ALIGNTO)));
|
||
|
struct
|
||
|
{
|
||
|
struct rtattr RtHeader __attribute__((aligned(RTA_ALIGNTO)));
|
||
|
char InterfaceName[32] __attribute__((aligned(RTA_ALIGNTO)));
|
||
|
} Attribute;
|
||
|
} RequestMessage;
|
||
|
|
||
|
if (SocketToUse != NULL)
|
||
|
{
|
||
|
CloseSocket = false;
|
||
|
Socket = *SocketToUse;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
//
|
||
|
// Create and bind socket. Create a RTM_GETLINK request.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(Socket = socket(AF_NETLINK, SOCK_RAW, 0));
|
||
|
CloseSocket = true;
|
||
|
LxtCheckErrno(BindSocketForNetlink(Socket));
|
||
|
}
|
||
|
|
||
|
memset(&RequestMessage, 0, sizeof(RequestMessage));
|
||
|
RequestMessage.Header.nlmsg_type = RTM_GETLINK;
|
||
|
RequestMessage.Header.nlmsg_seq = LXT_REQUEST_SEQUENCE;
|
||
|
;
|
||
|
RequestMessage.Message.ifi_family = AF_NETLINK;
|
||
|
RequestMessage.Header.nlmsg_flags = NLM_F_REQUEST;
|
||
|
InterfaceNameLength = strlen(InterfaceName) + 1;
|
||
|
LxtCheckGreaterOrEqual(sizeof(RequestMessage.Attribute.InterfaceName), InterfaceNameLength, "%lu");
|
||
|
|
||
|
RequestMessage.Attribute.RtHeader.rta_len = RTA_LENGTH(InterfaceNameLength);
|
||
|
RequestMessage.Attribute.RtHeader.rta_type = IFLA_IFNAME;
|
||
|
memcpy(RequestMessage.Attribute.InterfaceName, InterfaceName, InterfaceNameLength);
|
||
|
|
||
|
RequestMessage.Header.nlmsg_len = offsetof(struct _RequestMessage, Attribute.InterfaceName) + InterfaceNameLength;
|
||
|
|
||
|
LxtCheckErrno(sendto(Socket, &RequestMessage, RequestMessage.Header.nlmsg_len, 0, NULL, 0));
|
||
|
|
||
|
LxtCheckErrno(ReceiveResult = recv(Socket, ReceiveBuffer, sizeof(ReceiveBuffer), 0));
|
||
|
|
||
|
Header = (struct nlmsghdr*)ReceiveBuffer;
|
||
|
LxtCheckTrue(NLMSG_OK(Header, ReceiveResult));
|
||
|
LxtCheckEqual(Header->nlmsg_type, RTM_NEWLINK, "%d");
|
||
|
LxtCheckGreaterOrEqual((Header->nlmsg_len + 1), NLMSG_PAYLOAD(Header, sizeof(*InterfaceInfo)), "%d");
|
||
|
|
||
|
InterfaceInfo = NLMSG_DATA(Header);
|
||
|
if (SocketToUse == NULL)
|
||
|
{
|
||
|
LxtCheckErrno(InterfaceIndex = GetNetworkInterfaceIndex(InterfaceName));
|
||
|
LxtCheckEqual(InterfaceIndex, InterfaceInfo->ifi_index, "%d");
|
||
|
}
|
||
|
|
||
|
ErrorExit:
|
||
|
if (CloseSocket)
|
||
|
{
|
||
|
close(Socket);
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int VirtualBridgeAutoName(PLXT_ARGS Args)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine creates and deletes new bridges, allowing the system to
|
||
|
assign them default "bridgexx" names.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Args - Supplies the command line arguments.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
bool DeleteDeviceOne;
|
||
|
bool DeleteDeviceTwo;
|
||
|
int Result;
|
||
|
|
||
|
DeleteDeviceOne = false;
|
||
|
DeleteDeviceTwo = false;
|
||
|
|
||
|
LxtCheckResult(CreateVirtualBridgeViaNetlink(""));
|
||
|
DeleteDeviceOne = true;
|
||
|
LxtCheckErrno(GetNetworkInterfaceIndex("bridge0"));
|
||
|
LxtCheckResult(CreateVirtualBridgeViaNetlink(""));
|
||
|
DeleteDeviceTwo = true;
|
||
|
LxtCheckErrno(GetNetworkInterfaceIndex("bridge1"));
|
||
|
|
||
|
ErrorExit:
|
||
|
if (DeleteDeviceTwo)
|
||
|
{
|
||
|
(void)DeleteVirtualDeviceViaNetlink("bridge1");
|
||
|
}
|
||
|
|
||
|
if (DeleteDeviceOne)
|
||
|
{
|
||
|
(void)DeleteVirtualDeviceViaNetlink("bridge0");
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int VirtualBridgeFromIoctl1(PLXT_ARGS Args)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine creates and deletes a new bridge using UNIX socket ioctls.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Args - Supplies the command line arguments.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
int Result;
|
||
|
|
||
|
LxtCheckResult(CreateVirtualBridgeViaIoctl("testbridge"));
|
||
|
LxtCheckErrno(GetNetworkInterfaceIndex("testbridge"));
|
||
|
LxtCheckResult(DeleteVirtualBridgeViaIoctl("testbridge"));
|
||
|
LxtCheckErrnoFailure(GetNetworkInterfaceIndex("testbridge"), ENODEV);
|
||
|
|
||
|
ErrorExit:
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int VirtualBridgeFromNetlink1(PLXT_ARGS Args)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine creates and deletes a new bridge using netlink messages.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Args - Supplies the command line arguments.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
bool DeleteDevice;
|
||
|
int Result;
|
||
|
|
||
|
DeleteDevice = false;
|
||
|
|
||
|
LxtCheckResult(CreateVirtualBridgeViaNetlink("testbridge"));
|
||
|
DeleteDevice = true;
|
||
|
LxtCheckErrno(GetNetworkInterfaceIndex("testbridge"));
|
||
|
LxtCheckResult(DeleteVirtualDeviceViaNetlink("testbridge"));
|
||
|
DeleteDevice = false;
|
||
|
LxtCheckErrnoFailure(GetNetworkInterfaceIndex("testbridge"), ENODEV);
|
||
|
|
||
|
ErrorExit:
|
||
|
if (DeleteDevice)
|
||
|
{
|
||
|
(void)DeleteVirtualDeviceViaNetlink("testbridge");
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int VirtualBridgeNamespace1(PLXT_ARGS Args)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine does basic network namespace sanity testing with a bridge:
|
||
|
1) creates a new virtual bridge device
|
||
|
1) creates a new namespace
|
||
|
3) try to move the bridge into the other namespace - should fail.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Args - Supplies the command line arguments.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
bool DeleteDevice;
|
||
|
int NewNetworkNamespaceFd;
|
||
|
int OriginalNetworkNamespaceFd;
|
||
|
int Response;
|
||
|
int Result;
|
||
|
|
||
|
DeleteDevice = false;
|
||
|
NewNetworkNamespaceFd = 0;
|
||
|
OriginalNetworkNamespaceFd = 0;
|
||
|
|
||
|
//
|
||
|
// Open file descriptor of default network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(OriginalNetworkNamespaceFd = open("/proc/self/ns/net", 0));
|
||
|
|
||
|
//
|
||
|
// Create a new virtual bridge.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(CreateVirtualBridgeViaNetlink("testbridge"));
|
||
|
DeleteDevice = true;
|
||
|
|
||
|
//
|
||
|
// Switch to a new network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(unshare(CLONE_NEWNET));
|
||
|
|
||
|
//
|
||
|
// Open file descriptor of the new network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(NewNetworkNamespaceFd = open("/proc/self/ns/net", 0));
|
||
|
|
||
|
//
|
||
|
// Switch back to original network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(setns(OriginalNetworkNamespaceFd, CLONE_NEWNET));
|
||
|
|
||
|
//
|
||
|
// Try to move the bridge into the new namespace. This should fail as
|
||
|
// bridges are not allowed to move between namespaces.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(SetVirtualDeviceAttributeViaNetlink("testbridge", IFLA_NET_NS_FD, NewNetworkNamespaceFd, &Response));
|
||
|
|
||
|
LxtCheckEqual(Response, -EINVAL, "%d");
|
||
|
|
||
|
//
|
||
|
// Delete the device.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(DeleteVirtualDeviceViaNetlink("testbridge"));
|
||
|
DeleteDevice = false;
|
||
|
|
||
|
ErrorExit:
|
||
|
if (NewNetworkNamespaceFd > 0)
|
||
|
{
|
||
|
close(NewNetworkNamespaceFd);
|
||
|
}
|
||
|
|
||
|
if (OriginalNetworkNamespaceFd > 0)
|
||
|
{
|
||
|
close(OriginalNetworkNamespaceFd);
|
||
|
}
|
||
|
|
||
|
if (DeleteDevice)
|
||
|
{
|
||
|
(void)DeleteVirtualDeviceViaNetlink("testbridge");
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int VirtualEthernetPairFromNetlink1(PLXT_ARGS Args)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine creates and deletes a new virtual ethernet pair using netlink
|
||
|
messages. The delete is performed on the primary device.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Args - Supplies the command line arguments.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
bool DeleteDevice;
|
||
|
int Result;
|
||
|
|
||
|
DeleteDevice = false;
|
||
|
|
||
|
LxtCheckResult(CreateVirtualEthernetPairViaNetlink("veth_tst0", "veth_tst1"));
|
||
|
LxtCheckErrno(GetNetworkInterfaceIndex("veth_tst0"));
|
||
|
LxtCheckErrno(GetNetworkInterfaceIndex("veth_tst1"));
|
||
|
LxtCheckResult(DeleteVirtualDeviceViaNetlink("veth_tst0"));
|
||
|
LxtCheckErrnoFailure(GetNetworkInterfaceIndex("veth_tst0"), ENODEV);
|
||
|
LxtCheckErrnoFailure(GetNetworkInterfaceIndex("veth_tst1"), ENODEV);
|
||
|
|
||
|
ErrorExit:
|
||
|
if (DeleteDevice)
|
||
|
{
|
||
|
(void)DeleteVirtualDeviceViaNetlink("veth_tst0");
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int VirtualEthernetPairFromNetlink2(PLXT_ARGS Args)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine creates and deletes a new virtual ethernet pair using netlink
|
||
|
messages. The delete is performed on the peer device.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Args - Supplies the command line arguments.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
bool DeleteDevice;
|
||
|
int Result;
|
||
|
|
||
|
DeleteDevice = false;
|
||
|
|
||
|
LxtCheckResult(CreateVirtualEthernetPairViaNetlink("veth_tst0", "veth_tst1"));
|
||
|
DeleteDevice = true;
|
||
|
LxtCheckErrno(GetNetworkInterfaceIndex("veth_tst0"));
|
||
|
LxtCheckErrno(GetNetworkInterfaceIndex("veth_tst1"));
|
||
|
LxtCheckResult(DeleteVirtualDeviceViaNetlink("veth_tst1"));
|
||
|
DeleteDevice = false;
|
||
|
LxtCheckErrnoFailure(GetNetworkInterfaceIndex("veth_tst0"), ENODEV);
|
||
|
LxtCheckErrnoFailure(GetNetworkInterfaceIndex("veth_tst1"), ENODEV);
|
||
|
|
||
|
ErrorExit:
|
||
|
if (DeleteDevice)
|
||
|
{
|
||
|
(void)DeleteVirtualDeviceViaNetlink("veth_tst1");
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int VirtualEthernetPairNamespace1(PLXT_ARGS Args)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine does basic network namespace sanity testing with a virtual
|
||
|
ethernet pair:
|
||
|
1) creates a new virtual ethernet pair
|
||
|
2) creates a new namespace
|
||
|
3) try to move one end of the pair into the other namespace
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Args - Supplies the command line arguments.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
bool DeleteDevice;
|
||
|
int NewNetworkNamespaceFd;
|
||
|
int OriginalNetworkNamespaceFd;
|
||
|
int Response;
|
||
|
int Result;
|
||
|
|
||
|
DeleteDevice = false;
|
||
|
NewNetworkNamespaceFd = 0;
|
||
|
OriginalNetworkNamespaceFd = 0;
|
||
|
|
||
|
//
|
||
|
// Open file descriptor of default network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(OriginalNetworkNamespaceFd = open("/proc/self/ns/net", 0));
|
||
|
|
||
|
//
|
||
|
// Create a new virtual ethernet pair.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(CreateVirtualEthernetPairViaNetlink("veth0", "veth1"));
|
||
|
DeleteDevice = true;
|
||
|
|
||
|
//
|
||
|
// Switch to a new network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(unshare(CLONE_NEWNET));
|
||
|
|
||
|
//
|
||
|
// Open file descriptor of the new network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(NewNetworkNamespaceFd = open("/proc/self/ns/net", 0));
|
||
|
|
||
|
//
|
||
|
// Switch back to original network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(setns(OriginalNetworkNamespaceFd, CLONE_NEWNET));
|
||
|
|
||
|
//
|
||
|
// Try to move one half of the pair into the new namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(SetVirtualDeviceAttributeViaNetlink("veth1", IFLA_NET_NS_FD, NewNetworkNamespaceFd, &Response));
|
||
|
|
||
|
LxtCheckEqual(Response, 0, "%d");
|
||
|
|
||
|
//
|
||
|
// Delete the device.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(DeleteVirtualDeviceViaNetlink("veth0"));
|
||
|
DeleteDevice = false;
|
||
|
|
||
|
ErrorExit:
|
||
|
if (NewNetworkNamespaceFd > 0)
|
||
|
{
|
||
|
close(NewNetworkNamespaceFd);
|
||
|
}
|
||
|
|
||
|
if (OriginalNetworkNamespaceFd > 0)
|
||
|
{
|
||
|
(void)setns(OriginalNetworkNamespaceFd, CLONE_NEWNET);
|
||
|
close(OriginalNetworkNamespaceFd);
|
||
|
}
|
||
|
|
||
|
if (DeleteDevice)
|
||
|
{
|
||
|
(void)DeleteVirtualDeviceViaNetlink("veth0");
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int VirtualEthernetPairNamespace2(PLXT_ARGS Args)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine does basic network namespace sanity testing with a virtual
|
||
|
ethernet pair:
|
||
|
1) create a virtual ethernet pair.
|
||
|
2) create a new namespace
|
||
|
3) move one end of the pair into the new namespace.
|
||
|
4) create another virtual ethernet pair using the same name as that of
|
||
|
the moved end.
|
||
|
5) try to move the same-named end again.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Args - Supplies the command line arguments.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
bool DeleteFirstDevice;
|
||
|
bool DeleteSecondDevice;
|
||
|
int NewNetworkNamespaceFd;
|
||
|
int OriginalNetworkNamespaceFd;
|
||
|
int Response;
|
||
|
int Result;
|
||
|
|
||
|
DeleteFirstDevice = false;
|
||
|
DeleteSecondDevice = false;
|
||
|
NewNetworkNamespaceFd = 0;
|
||
|
OriginalNetworkNamespaceFd = 0;
|
||
|
|
||
|
//
|
||
|
// Open file descriptor of default network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(OriginalNetworkNamespaceFd = open("/proc/self/ns/net", 0));
|
||
|
|
||
|
//
|
||
|
// Create a new virtual ethernet pair.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(CreateVirtualEthernetPairViaNetlink("veth0", "veth1"));
|
||
|
DeleteFirstDevice = true;
|
||
|
|
||
|
//
|
||
|
// Switch to a new network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(unshare(CLONE_NEWNET));
|
||
|
|
||
|
//
|
||
|
// Open file descriptor of the new network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(NewNetworkNamespaceFd = open("/proc/self/ns/net", 0));
|
||
|
|
||
|
//
|
||
|
// Switch back to original network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(setns(OriginalNetworkNamespaceFd, CLONE_NEWNET));
|
||
|
|
||
|
//
|
||
|
// Try to move one half of the pair into the new namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(SetVirtualDeviceAttributeViaNetlink("veth1", IFLA_NET_NS_FD, NewNetworkNamespaceFd, &Response));
|
||
|
|
||
|
LxtCheckEqual(Response, 0, "%d");
|
||
|
|
||
|
//
|
||
|
// Create a new virtual ethernet pair, re-using the moved name.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(CreateVirtualEthernetPairViaNetlink("veth2", "veth1"));
|
||
|
DeleteSecondDevice = true;
|
||
|
|
||
|
//
|
||
|
// Try to move it again, expecting failure.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(setns(OriginalNetworkNamespaceFd, CLONE_NEWNET));
|
||
|
LxtCheckResult(SetVirtualDeviceAttributeViaNetlink("veth1", IFLA_NET_NS_FD, NewNetworkNamespaceFd, &Response));
|
||
|
|
||
|
LxtCheckEqual(Response, -EEXIST, "%d");
|
||
|
|
||
|
//
|
||
|
// Cleanup.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(DeleteVirtualDeviceViaNetlink("veth0"));
|
||
|
DeleteFirstDevice = false;
|
||
|
LxtCheckResult(DeleteVirtualDeviceViaNetlink("veth2"));
|
||
|
DeleteSecondDevice = false;
|
||
|
|
||
|
ErrorExit:
|
||
|
if (NewNetworkNamespaceFd > 0)
|
||
|
{
|
||
|
close(NewNetworkNamespaceFd);
|
||
|
}
|
||
|
|
||
|
if (OriginalNetworkNamespaceFd > 0)
|
||
|
{
|
||
|
(void)setns(OriginalNetworkNamespaceFd, CLONE_NEWNET);
|
||
|
close(OriginalNetworkNamespaceFd);
|
||
|
}
|
||
|
|
||
|
if (DeleteFirstDevice)
|
||
|
{
|
||
|
(void)DeleteVirtualDeviceViaNetlink("veth0");
|
||
|
}
|
||
|
|
||
|
if (DeleteSecondDevice)
|
||
|
{
|
||
|
(void)DeleteVirtualDeviceViaNetlink("veth2");
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int VirtualEthernetPairNamespace3(PLXT_ARGS Args)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine does basic network namespace sanity testing with a virtual
|
||
|
ethernet pair:
|
||
|
1) creates a new virtual ethernet pair
|
||
|
2) creates a new namespace
|
||
|
3) move one end of the pair into the other namespace
|
||
|
4) close the new namespace
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Args - Supplies the command line arguments.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
bool DeleteDevice;
|
||
|
int NewNetworkNamespaceFd;
|
||
|
int OriginalNetworkNamespaceFd;
|
||
|
int Response;
|
||
|
int Result;
|
||
|
|
||
|
DeleteDevice = false;
|
||
|
NewNetworkNamespaceFd = 0;
|
||
|
OriginalNetworkNamespaceFd = 0;
|
||
|
|
||
|
//
|
||
|
// Open file descriptor of default network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(OriginalNetworkNamespaceFd = open("/proc/self/ns/net", 0));
|
||
|
|
||
|
//
|
||
|
// Create a new virtual ethernet pair.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(CreateVirtualEthernetPairViaNetlink("veth0", "veth1"));
|
||
|
DeleteDevice = true;
|
||
|
|
||
|
//
|
||
|
// Switch to a new network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(unshare(CLONE_NEWNET));
|
||
|
|
||
|
//
|
||
|
// Open file descriptor of the new network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(NewNetworkNamespaceFd = open("/proc/self/ns/net", 0));
|
||
|
|
||
|
//
|
||
|
// Switch back to original network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(setns(OriginalNetworkNamespaceFd, CLONE_NEWNET));
|
||
|
|
||
|
//
|
||
|
// Try to move one half of the pair into the new namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(SetVirtualDeviceAttributeViaNetlink("veth1", IFLA_NET_NS_FD, NewNetworkNamespaceFd, &Response));
|
||
|
|
||
|
LxtCheckEqual(Response, 0, "%d");
|
||
|
|
||
|
//
|
||
|
// Close the new namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckClose(NewNetworkNamespaceFd);
|
||
|
|
||
|
//
|
||
|
// Both endpoints should have been deleted when the namespace was closed.
|
||
|
// Delay a bit to let the state settle.
|
||
|
//
|
||
|
|
||
|
sleep(1);
|
||
|
LxtCheckErrnoFailure(GetNetworkInterfaceIndex("veth0"), ENODEV);
|
||
|
DeleteDevice = false;
|
||
|
|
||
|
ErrorExit:
|
||
|
if (NewNetworkNamespaceFd > 0)
|
||
|
{
|
||
|
close(NewNetworkNamespaceFd);
|
||
|
}
|
||
|
|
||
|
if (OriginalNetworkNamespaceFd > 0)
|
||
|
{
|
||
|
(void)setns(OriginalNetworkNamespaceFd, CLONE_NEWNET);
|
||
|
close(OriginalNetworkNamespaceFd);
|
||
|
}
|
||
|
|
||
|
if (DeleteDevice)
|
||
|
{
|
||
|
(void)DeleteVirtualDeviceViaNetlink("veth0");
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int VirtualEthernetPairNamespace4(PLXT_ARGS Args)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine does simple validation on network interface link information
|
||
|
when creating virtual ethernet adapters and moving them between namespaces.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Args - Supplies the command line arguments.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
bool DeleteDevice;
|
||
|
int NewNetworkNamespaceFd;
|
||
|
int OriginalNetworkNamespaceFd;
|
||
|
int Response;
|
||
|
int Result;
|
||
|
|
||
|
DeleteDevice = false;
|
||
|
NewNetworkNamespaceFd = 0;
|
||
|
OriginalNetworkNamespaceFd = 0;
|
||
|
|
||
|
//
|
||
|
// Open file descriptor of default network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(OriginalNetworkNamespaceFd = open("/proc/self/ns/net", 0));
|
||
|
|
||
|
//
|
||
|
// Create a new virtual ethernet pair.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(CreateVirtualEthernetPairViaNetlink("veth0", "veth1"));
|
||
|
DeleteDevice = true;
|
||
|
|
||
|
//
|
||
|
// Switch to a new network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(unshare(CLONE_NEWNET));
|
||
|
|
||
|
//
|
||
|
// Open file descriptor of the new network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(NewNetworkNamespaceFd = open("/proc/self/ns/net", 0));
|
||
|
|
||
|
//
|
||
|
// Switch back to original network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(setns(OriginalNetworkNamespaceFd, CLONE_NEWNET));
|
||
|
|
||
|
//
|
||
|
// Check the route link entries.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(VerifyRouteLinkExists("veth0", NULL));
|
||
|
LxtCheckResult(VerifyRouteLinkExists("veth1", NULL));
|
||
|
|
||
|
//
|
||
|
// Try to move one half of the pair into the new namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(SetVirtualDeviceAttributeViaNetlink("veth1", IFLA_NET_NS_FD, NewNetworkNamespaceFd, &Response));
|
||
|
|
||
|
LxtCheckEqual(Response, 0, "%d");
|
||
|
|
||
|
//
|
||
|
// Check the route link entries.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(setns(NewNetworkNamespaceFd, CLONE_NEWNET));
|
||
|
LxtCheckResult(VerifyRouteLinkExists("veth1", NULL));
|
||
|
LxtCheckErrno(setns(OriginalNetworkNamespaceFd, CLONE_NEWNET));
|
||
|
LxtCheckResult(VerifyRouteLinkExists("veth0", NULL));
|
||
|
|
||
|
//
|
||
|
// Close the new namespace, and wait a second for state to settle.
|
||
|
//
|
||
|
|
||
|
LxtCheckClose(NewNetworkNamespaceFd);
|
||
|
sleep(1);
|
||
|
|
||
|
//
|
||
|
// The namespace deletion should have removed the devices.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(VerifyRouteLinkDoesNotExist("veth0", NULL));
|
||
|
DeleteDevice = false;
|
||
|
LxtCheckResult(VerifyRouteLinkDoesNotExist("veth1", NULL));
|
||
|
|
||
|
ErrorExit:
|
||
|
if (NewNetworkNamespaceFd > 0)
|
||
|
{
|
||
|
close(NewNetworkNamespaceFd);
|
||
|
}
|
||
|
|
||
|
if (OriginalNetworkNamespaceFd > 0)
|
||
|
{
|
||
|
(void)setns(OriginalNetworkNamespaceFd, CLONE_NEWNET);
|
||
|
close(OriginalNetworkNamespaceFd);
|
||
|
}
|
||
|
|
||
|
if (DeleteDevice)
|
||
|
{
|
||
|
(void)DeleteVirtualDeviceViaNetlink("veth0");
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int VirtualEthernetPairNamespace5(PLXT_ARGS Args)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine does simple validation of socket creation being tied to the
|
||
|
network namespace.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Args - Supplies the command line arguments.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
bool DeleteDevice;
|
||
|
int NewNetworkNamespaceFd;
|
||
|
int OriginalNetworkNamespaceFd;
|
||
|
int Response;
|
||
|
int Result;
|
||
|
int SocketNewNs;
|
||
|
|
||
|
DeleteDevice = false;
|
||
|
NewNetworkNamespaceFd = 0;
|
||
|
OriginalNetworkNamespaceFd = 0;
|
||
|
|
||
|
//
|
||
|
// Open file descriptor of default network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(OriginalNetworkNamespaceFd = open("/proc/self/ns/net", 0));
|
||
|
|
||
|
//
|
||
|
// Create a new virtual ethernet pair.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(CreateVirtualEthernetPairViaNetlink("veth0", "veth1"));
|
||
|
DeleteDevice = true;
|
||
|
|
||
|
//
|
||
|
// Switch to a new network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(unshare(CLONE_NEWNET));
|
||
|
|
||
|
//
|
||
|
// Create a socket while in the new network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(SocketNewNs = socket(AF_NETLINK, SOCK_RAW, 0));
|
||
|
|
||
|
//
|
||
|
// Open file descriptor of the new network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(NewNetworkNamespaceFd = open("/proc/self/ns/net", 0));
|
||
|
|
||
|
//
|
||
|
// Switch back to original network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(setns(OriginalNetworkNamespaceFd, CLONE_NEWNET));
|
||
|
|
||
|
//
|
||
|
// Bind the socket created in the new network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(BindSocketForNetlink(SocketNewNs));
|
||
|
|
||
|
//
|
||
|
// Check the route link entries.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(VerifyRouteLinkExists("veth0", NULL));
|
||
|
LxtCheckResult(VerifyRouteLinkExists("veth1", NULL));
|
||
|
|
||
|
//
|
||
|
// Check the non-existence of the entries with the other socket.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(VerifyRouteLinkDoesNotExist("veth0", &SocketNewNs));
|
||
|
LxtCheckResult(VerifyRouteLinkDoesNotExist("veth1", &SocketNewNs));
|
||
|
|
||
|
//
|
||
|
// Try to move one half of the pair into the new namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(SetVirtualDeviceAttributeViaNetlink("veth1", IFLA_NET_NS_FD, NewNetworkNamespaceFd, &Response));
|
||
|
|
||
|
LxtCheckEqual(Response, 0, "%d");
|
||
|
|
||
|
//
|
||
|
// Check the route link entries.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(VerifyRouteLinkExists("veth0", NULL));
|
||
|
LxtCheckResult(VerifyRouteLinkDoesNotExist("veth0", &SocketNewNs));
|
||
|
LxtCheckResult(VerifyRouteLinkDoesNotExist("veth1", NULL));
|
||
|
LxtCheckResult(VerifyRouteLinkExists("veth1", &SocketNewNs));
|
||
|
|
||
|
//
|
||
|
// Close the new namespace and the related socket, and wait a second for
|
||
|
// state to settle.
|
||
|
//
|
||
|
|
||
|
LxtCheckClose(SocketNewNs);
|
||
|
SocketNewNs = 0;
|
||
|
LxtCheckClose(NewNetworkNamespaceFd);
|
||
|
sleep(1);
|
||
|
|
||
|
//
|
||
|
// The namespace deletion should have removed the devices.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(VerifyRouteLinkDoesNotExist("veth0", NULL));
|
||
|
DeleteDevice = false;
|
||
|
LxtCheckResult(VerifyRouteLinkDoesNotExist("veth1", NULL));
|
||
|
|
||
|
ErrorExit:
|
||
|
if (SocketNewNs > 0)
|
||
|
{
|
||
|
close(SocketNewNs);
|
||
|
}
|
||
|
|
||
|
if (NewNetworkNamespaceFd > 0)
|
||
|
{
|
||
|
close(NewNetworkNamespaceFd);
|
||
|
}
|
||
|
|
||
|
if (OriginalNetworkNamespaceFd > 0)
|
||
|
{
|
||
|
(void)setns(OriginalNetworkNamespaceFd, CLONE_NEWNET);
|
||
|
close(OriginalNetworkNamespaceFd);
|
||
|
}
|
||
|
|
||
|
if (DeleteDevice)
|
||
|
{
|
||
|
(void)DeleteVirtualDeviceViaNetlink("veth0");
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int VirtualEthernetPairConfigure(PLXT_ARGS Args)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine creates a virtual ethernet pair and attempts to bring them up
|
||
|
and assign them static IP addresses.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Args - Supplies the command line arguments.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
bool DeleteDevice;
|
||
|
struct in_addr AddressIpv4;
|
||
|
int Response;
|
||
|
int Result;
|
||
|
|
||
|
DeleteDevice = false;
|
||
|
|
||
|
//
|
||
|
// Create a new virtual ethernet pair.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(CreateVirtualEthernetPairViaNetlink("veth0", "veth1"));
|
||
|
DeleteDevice = true;
|
||
|
|
||
|
//
|
||
|
// Bring the interfaces up and assign static IP addresses.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(SetVirtualDeviceFlagViaNetlink("veth0", IFF_UP, true, &Response));
|
||
|
|
||
|
LxtCheckEqual(Response, 0, "%d");
|
||
|
inet_aton(LXT_IP_ADDRESS1, &AddressIpv4);
|
||
|
LxtCheckResult(SetIpAddress("veth0", &AddressIpv4, 32));
|
||
|
|
||
|
LxtCheckResult(SetVirtualDeviceFlagViaNetlink("veth1", IFF_UP, true, &Response));
|
||
|
|
||
|
LxtCheckEqual(Response, 0, "%d");
|
||
|
inet_aton(LXT_IP_ADDRESS2, &AddressIpv4);
|
||
|
LxtCheckResult(SetIpAddress("veth1", &AddressIpv4, 32));
|
||
|
|
||
|
//
|
||
|
// Try to delete the device.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(DeleteVirtualDeviceViaNetlink("veth0"));
|
||
|
DeleteDevice = false;
|
||
|
|
||
|
ErrorExit:
|
||
|
if (DeleteDevice)
|
||
|
{
|
||
|
(void)DeleteVirtualDeviceViaNetlink("veth0");
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int VirtualEthernetPairData(PLXT_ARGS Args)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Args - Supplies the command line arguments.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
struct sockaddr_in AddressIpv4 = {};
|
||
|
socklen_t AddressLength;
|
||
|
ssize_t BytesReceived;
|
||
|
ssize_t BytesSent;
|
||
|
bool DeleteDevice;
|
||
|
struct sockaddr_in FromAddressIpv4;
|
||
|
;
|
||
|
char RecvBuffer[10] = {0};
|
||
|
int Response;
|
||
|
int Result;
|
||
|
char SendBuffer[10] = {"123456789"};
|
||
|
int Socket;
|
||
|
int Socket2;
|
||
|
|
||
|
DeleteDevice = false;
|
||
|
Socket = -1;
|
||
|
Socket2 = -1;
|
||
|
|
||
|
//
|
||
|
// Make sure the loopback adapter is up.
|
||
|
//
|
||
|
|
||
|
(void)SetVirtualDeviceFlagViaNetlink("lo", IFF_UP, true, &Response);
|
||
|
|
||
|
//
|
||
|
// Create a new virtual ethernet pair.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(CreateVirtualEthernetPairViaNetlink("veth0", "veth1"));
|
||
|
DeleteDevice = true;
|
||
|
|
||
|
//
|
||
|
// Bring the interfaces up and assign static IP addresses.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(SetVirtualDeviceFlagViaNetlink("veth0", IFF_UP, true, &Response));
|
||
|
|
||
|
LxtCheckEqual(Response, 0, "%d");
|
||
|
AddressIpv4.sin_family = AF_INET;
|
||
|
inet_aton(LXT_IP_ADDRESS1, &AddressIpv4.sin_addr);
|
||
|
LxtCheckResult(SetIpAddress("veth0", &AddressIpv4.sin_addr, 32));
|
||
|
LxtCheckErrno((Socket = socket(AF_INET, SOCK_DGRAM, 0)));
|
||
|
LxtCheckErrno(bind(Socket, (struct sockaddr*)&AddressIpv4, sizeof(AddressIpv4)));
|
||
|
|
||
|
LxtCheckResult(SetVirtualDeviceFlagViaNetlink("veth1", IFF_UP, true, &Response));
|
||
|
|
||
|
LxtCheckEqual(Response, 0, "%d");
|
||
|
LxtCheckResult(SetRoute("veth1", &AddressIpv4.sin_addr, 32));
|
||
|
inet_aton(LXT_IP_ADDRESS2, &AddressIpv4.sin_addr);
|
||
|
LxtCheckResult(SetIpAddress("veth1", &AddressIpv4.sin_addr, 32));
|
||
|
LxtCheckErrno((Socket2 = socket(AF_INET, SOCK_DGRAM, 0)));
|
||
|
LxtCheckErrno(bind(Socket2, (struct sockaddr*)&AddressIpv4, sizeof(AddressIpv4)));
|
||
|
|
||
|
//
|
||
|
// Send a packet between the devices.
|
||
|
//
|
||
|
|
||
|
AddressLength = sizeof(AddressIpv4);
|
||
|
LxtCheckErrno(getsockname(Socket2, (struct sockaddr*)&AddressIpv4, &AddressLength));
|
||
|
|
||
|
LxtCheckEqual(AddressLength, sizeof(AddressIpv4), "%lu");
|
||
|
LxtCheckResult(SetRoute("veth0", &AddressIpv4.sin_addr, 32));
|
||
|
LxtLogInfo("AddressIpv4.sin_family = %d", AddressIpv4.sin_family);
|
||
|
LxtLogInfo("AddressIpv4.sin_port = %d", AddressIpv4.sin_port);
|
||
|
LxtLogInfo("AddressIpv4.sin_addr = %08x", AddressIpv4.sin_addr.s_addr);
|
||
|
LxtCheckErrno((BytesSent = sendto(Socket, SendBuffer, sizeof(SendBuffer), 0, (struct sockaddr*)&AddressIpv4, sizeof(AddressIpv4))));
|
||
|
|
||
|
LxtCheckEqual(BytesSent, sizeof(SendBuffer), "%lu");
|
||
|
AddressLength = sizeof(FromAddressIpv4);
|
||
|
LxtCheckErrno((BytesReceived = recvfrom(Socket2, RecvBuffer, sizeof(RecvBuffer), 0, (struct sockaddr*)&FromAddressIpv4, &AddressLength)));
|
||
|
|
||
|
LxtCheckEqual(BytesReceived, sizeof(SendBuffer), "%lu");
|
||
|
LxtCheckMemoryEqual(RecvBuffer, SendBuffer, BytesReceived);
|
||
|
LxtCheckEqual(AddressLength, sizeof(FromAddressIpv4), "%lu");
|
||
|
|
||
|
//
|
||
|
// Try to delete the device.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(DeleteVirtualDeviceViaNetlink("veth0"));
|
||
|
DeleteDevice = false;
|
||
|
|
||
|
ErrorExit:
|
||
|
if (Socket > 0)
|
||
|
{
|
||
|
close(Socket);
|
||
|
}
|
||
|
|
||
|
if (Socket2 > 0)
|
||
|
{
|
||
|
close(Socket2);
|
||
|
}
|
||
|
|
||
|
if (DeleteDevice)
|
||
|
{
|
||
|
(void)DeleteVirtualDeviceViaNetlink("veth0");
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int VirtualEthernetPairNamespaceData(PLXT_ARGS Args)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Args - Supplies the command line arguments.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
struct sockaddr_in AddressIpv4 = {};
|
||
|
socklen_t AddressLength;
|
||
|
ssize_t BytesReceived;
|
||
|
ssize_t BytesSent;
|
||
|
bool DeleteDevice;
|
||
|
struct sockaddr_in FromAddressIpv4;
|
||
|
;
|
||
|
int NewNetworkNamespaceFd;
|
||
|
int OriginalNetworkNamespaceFd;
|
||
|
char RecvBuffer[10] = {0};
|
||
|
int Response;
|
||
|
int Result;
|
||
|
char SendBuffer[10] = {"123456789"};
|
||
|
int Socket;
|
||
|
int Socket2;
|
||
|
|
||
|
DeleteDevice = false;
|
||
|
NewNetworkNamespaceFd = 0;
|
||
|
OriginalNetworkNamespaceFd = 0;
|
||
|
Socket = -1;
|
||
|
Socket2 = -1;
|
||
|
|
||
|
//
|
||
|
// Open file descriptor of default network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(OriginalNetworkNamespaceFd = open("/proc/self/ns/net", 0));
|
||
|
|
||
|
//
|
||
|
// Switch to a new network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(unshare(CLONE_NEWNET));
|
||
|
|
||
|
//
|
||
|
// Open file descriptor of the new network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(NewNetworkNamespaceFd = open("/proc/self/ns/net", 0));
|
||
|
|
||
|
//
|
||
|
// Switch back to original network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(setns(OriginalNetworkNamespaceFd, CLONE_NEWNET));
|
||
|
|
||
|
//
|
||
|
// Create a new virtual ethernet pair.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(CreateVirtualEthernetPairViaNetlink("veth0", "veth1"));
|
||
|
DeleteDevice = true;
|
||
|
|
||
|
//
|
||
|
// Try to move one half of the pair into the new namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(SetVirtualDeviceAttributeViaNetlink("veth1", IFLA_NET_NS_FD, NewNetworkNamespaceFd, &Response));
|
||
|
|
||
|
LxtCheckEqual(Response, 0, "%d");
|
||
|
|
||
|
//
|
||
|
// Bring the interfaces up and assign static IP addresses.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(SetVirtualDeviceFlagViaNetlink("veth0", IFF_UP, true, &Response));
|
||
|
|
||
|
LxtCheckEqual(Response, 0, "%d");
|
||
|
AddressIpv4.sin_family = AF_INET;
|
||
|
inet_aton(LXT_IP_ADDRESS1, &AddressIpv4.sin_addr);
|
||
|
LxtCheckResult(SetIpAddress("veth0", &AddressIpv4.sin_addr, 32));
|
||
|
LxtCheckErrno((Socket = socket(AF_INET, SOCK_DGRAM, 0)));
|
||
|
LxtCheckErrno(bind(Socket, (struct sockaddr*)&AddressIpv4, sizeof(AddressIpv4)));
|
||
|
|
||
|
//
|
||
|
// Switch to the new network namespace to configure the other endpoint.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(setns(NewNetworkNamespaceFd, CLONE_NEWNET));
|
||
|
LxtCheckResult(SetVirtualDeviceFlagViaNetlink("veth1", IFF_UP, true, &Response));
|
||
|
|
||
|
LxtCheckEqual(Response, 0, "%d");
|
||
|
LxtCheckResult(SetRoute("veth1", &AddressIpv4.sin_addr, 32));
|
||
|
inet_aton(LXT_IP_ADDRESS2, &AddressIpv4.sin_addr);
|
||
|
LxtCheckResult(SetIpAddress("veth1", &AddressIpv4.sin_addr, 32));
|
||
|
|
||
|
//
|
||
|
// Open UDP sockets to try to send and receive on the IP addresses assigned
|
||
|
// above.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno((Socket2 = socket(AF_INET, SOCK_DGRAM, 0)));
|
||
|
LxtCheckErrno(bind(Socket2, (struct sockaddr*)&AddressIpv4, sizeof(AddressIpv4)));
|
||
|
|
||
|
AddressLength = sizeof(AddressIpv4);
|
||
|
LxtCheckErrno(getsockname(Socket2, (struct sockaddr*)&AddressIpv4, &AddressLength));
|
||
|
|
||
|
LxtCheckEqual(AddressLength, sizeof(AddressIpv4), "%lu");
|
||
|
|
||
|
//
|
||
|
// Switch back to original network namespace.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(setns(OriginalNetworkNamespaceFd, CLONE_NEWNET));
|
||
|
|
||
|
//
|
||
|
// Send a packet between the devices.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(SetRoute("veth0", &AddressIpv4.sin_addr, 32));
|
||
|
LxtLogInfo("AddressIpv4.sin_family = %d", AddressIpv4.sin_family);
|
||
|
LxtLogInfo("AddressIpv4.sin_port = %d", AddressIpv4.sin_port);
|
||
|
LxtLogInfo("AddressIpv4.sin_addr = %08x", AddressIpv4.sin_addr.s_addr);
|
||
|
LxtCheckErrno((BytesSent = sendto(Socket, SendBuffer, sizeof(SendBuffer), 0, (struct sockaddr*)&AddressIpv4, sizeof(AddressIpv4))));
|
||
|
|
||
|
LxtCheckEqual(BytesSent, sizeof(SendBuffer), "%lu");
|
||
|
AddressLength = sizeof(FromAddressIpv4);
|
||
|
LxtCheckErrno((BytesReceived = recvfrom(Socket2, RecvBuffer, sizeof(RecvBuffer), 0, (struct sockaddr*)&FromAddressIpv4, &AddressLength)));
|
||
|
|
||
|
LxtCheckEqual(BytesReceived, sizeof(SendBuffer), "%lu");
|
||
|
LxtCheckMemoryEqual(RecvBuffer, SendBuffer, BytesReceived);
|
||
|
LxtCheckEqual(AddressLength, sizeof(FromAddressIpv4), "%lu");
|
||
|
|
||
|
//
|
||
|
// Try to delete the device.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(DeleteVirtualDeviceViaNetlink("veth0"));
|
||
|
DeleteDevice = false;
|
||
|
|
||
|
ErrorExit:
|
||
|
if (NewNetworkNamespaceFd > 0)
|
||
|
{
|
||
|
close(NewNetworkNamespaceFd);
|
||
|
}
|
||
|
|
||
|
if (OriginalNetworkNamespaceFd > 0)
|
||
|
{
|
||
|
(void)setns(OriginalNetworkNamespaceFd, CLONE_NEWNET);
|
||
|
close(OriginalNetworkNamespaceFd);
|
||
|
}
|
||
|
|
||
|
if (Socket > 0)
|
||
|
{
|
||
|
close(Socket);
|
||
|
}
|
||
|
|
||
|
if (Socket2 > 0)
|
||
|
{
|
||
|
close(Socket2);
|
||
|
}
|
||
|
|
||
|
if (DeleteDevice)
|
||
|
{
|
||
|
(void)DeleteVirtualDeviceViaNetlink("veth0");
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|