-
Notifications
You must be signed in to change notification settings - Fork 7
C Test Network API
Note
|
See also Test Writing Guidelines, C Test Case Tutorial, C Test API, Shell Test API. |
LTP library includes helper functions for configuring sockets and setting up network devices.
#include "tst_safe_net.h"
Most common standard syscalls and libc functions for configuring sockets have a
"safe" variant in LTP library which will call tst_brk()
if the underlying
system function fails. See
C Test API. The
safe function names are in uppercase with the SAFE_
prefix (e.g. the safe
variant of socket()
is called SAFE_SOCKET()
). For most safe functions, the
parameters and return type are identical to the standard system function:
-
SAFE_SOCKET()
-
SAFE_SOCKETPAIR()
-
SAFE_GETSOCKOPT()
-
SAFE_SETSOCKOPT()
-
SAFE_BIND()
-
SAFE_LISTEN()
-
SAFE_ACCEPT()
-
SAFE_CONNECT()
-
SAFE_GETSOCKNAME()
-
SAFE_GETHOSTNAME()
-
SAFE_GETADDRINFO()
A few safe functions have extra parameters for quick return value validation.
The ellipsis (…
) represents the standard parameters of the underlying system
function:
-
SAFE_SEND(char strict, …)
-
SAFE_SENDTO(char strict, …)
-
If
strict
is non-zero, the return value must be equal to the data length argument. Otherwise the test will fail and exit.
-
-
SAFE_SENDMSG(size_t msg_len, …)
-
SAFE_RECV(size_t msg_len, …)
-
SAFE_RECVMSG(size_t msg_len, …)
-
If
msg_len
is non-zero, the return value must be equal to themsg_len
argument. Otherwise the test will fail and exit.
-
There are also some custom functions for simpler configuration and queries:
-
int SAFE_SETSOCKOPT_INT(int sockfd, int level, int optname, int value)
– Simple setsockopt() variant for passing integers by value. -
int TST_GETSOCKPORT(int sockfd)
– Get port number (in host byte order) of a bound socket. -
unsigned short TST_GET_UNUSED_PORT(int family, int type)
– Get a random port number (in network byte order) which is currently closed for the given socket family and type. Note that another application may open the port while the test is still running. The test user is responsible for setting up test environment without such interference.
#include "tst_net.h"
LTP library also provides helper functions for quick initialization of socket address structures:
-
void tst_get_in_addr(const char *ip_str, struct in_addr *ip)
– Convert human-readable IPv4 address stringip_str
to binary representation in network byte order. The converted value will be stored in the second argument. -
void tst_get_in6_addr(const char *ip_str, struct in6_addr *ip6)
– Convert human-readable IPv6 address stringip_str
to binary representation in network byte order. The converted value will be stored in the second argument. -
socklen_t tst_get_connect_address(int sock, struct sockaddr_storage *addr)
– Find the address which can be used to send data to bound socketsock
from another socket. The address will be stored in the second argument. This function automatically converts wildcard bind address to localhost. Returns size of the address in bytes. -
void tst_init_sockaddr_inet(struct sockaddr_in *sa, const char *ip_str, uint16_t port)
– Initialize socket address structuresa
using human-readable IPv4 addressip_str
and port numberport
in host byte order. -
void tst_init_sockaddr_inet_bin(struct sockaddr_in *sa, uint32_t ip_val, uint16_t port)
– Initialize socket address structuresa
using binary IPv4 addressip_val
and port numberport
, both in host byte order. -
void tst_init_sockaddr_inet6(struct sockaddr_in6 *sa, const char *ip_str, uint16_t port)
– Initialize socket address structuresa
using human-readable IPv6 addressip_str
and port numberport
in host byte order. -
void tst_init_sockaddr_inet6_bin(struct sockaddr_in6 *sa, const struct in6_addr *ip_val, uint16_t port)
– Initialize socket address structuresa
using binary IPv6 addressip_val
and port numberport
, both in host byte order.
#include <sys/socket.h>
#include <netinet/in.h>
#include "tst_test.h"
#include "tst_safe_net.h"
#include "tst_net.h"
static int sockfd = -1;
static void setup(void)
{
struct sockaddr_in addr;
tst_init_sockaddr_inet_bin(&addr, INADDR_ANY, 0);
sockfd = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0);
SAFE_SETSOCKOPT_INT(sockfd, SOL_SOCKET, SO_SNDBUF, 4096);
SAFE_BIND(sockfd, (struct sockaddr *)&addr, sizeof(addr));
SAFE_LISTEN(sockfd, 8);
}
#include "tst_netdevice.h"
When opening a localhost socket isn’t enough and the test needs special device or routing configuration, the netdevice library can create the required network setup without calling external programs. Internally, the netdevice functions use a rtnetlink socket to communicate with the kernel.
All of these functions will call tst_brk()
on failure, unless stated
otherwise. Error values described below are returned only during test cleanup
stage.
-
int NETDEV_INDEX_BY_NAME(const char *ifname)
– Returns the device index for the given device name, or -1 on error. -
int NETDEV_SET_STATE(const char *ifname, int up)
– Enable or disable a network deviceifname
. Returns 0 on success, -1 on error. -
int CREATE_VETH_PAIR(const char *ifname1, const char *ifname2)
– Creates a connected pair of virtual network devices with given device names. Returns 1 on success, 0 on error. Add"CONFIG_VETH"
totest.needs_kconfigs
if your test calls this function. -
int NETDEV_ADD_DEVICE(const char *ifname, const char *devtype)
- Creates a new network device namedifname
of specified device type. Returns 1 on success, 0 on error. -
int NETDEV_REMOVE_DEVICE(const char *ifname)
– Removes network deviceifname
. Returns 1 on success, 0 on error.
-
int NETDEV_ADD_ADDRESS(const char *ifname, unsigned int family, const void *address, unsigned int prefix, size_t addrlen, unsigned int flags)
– Adds new address to network deviceifname
. This is a low-level function which allows setting any type of address. You must specify the protocolfamily
, address length in bytes (addrlen
) and network prefix length (prefix
). Theaddress
itself must be in binary representation in network byte order. You can also pass rtnetlink flags from theIFA_F_*
group. Returns 1 on success, 0 on error. -
int NETDEV_ADD_ADDRESS_INET(const char *ifname, in_addr_t address, unsigned int prefix, unsigned int flags)
– Adds new IPv4 address to network deviceifname
. Parameters have the same meaning as inNETDEV_ADD_ADDRESS()
. Returns 1 on success, 0 on error. -
int NETDEV_REMOVE_ADDRESS(const char *ifname, unsigned int family, const void *address, size_t addrlen)
– Removes the specified address from network deviceifname
. Parameters have the same meaning as inNETDEV_ADD_ADDRESS()
. Returns 1 on success, 0 on error. -
int NETDEV_REMOVE_ADDRESS_INET(const char *ifname, in_addr_t address)
– Removes specified IPv4address
(in network byte order) from network deviceifname
. Returns 1 on success, 0 on error.
Warning
|
Moving a network device to another namespace will erase previous configuration. Move the device to the correct namespace first, then configure it. |
-
int NETDEV_CHANGE_NS_FD(const char *ifname, int nsfd)
– Moves network deviceifname
to network namespace designated by open file descriptornsfd
. Returns 1 on success, 0 on error. -
int NETDEV_CHANGE_NS_PID(const char *ifname, pid_t nspid)
– Moves network deviceifname
to the network namespace currently used by processnspid
. Returns 1 on success, 0 on error.
-
int NETDEV_ADD_ROUTE(const char *ifname, unsigned int family, const void *srcaddr, unsigned int srcprefix, size_t srclen, const void *dstaddr, unsigned int dstprefix, size_t dstlen, const void *gateway, size_t gatewaylen)
– Adds new route to the main routing table. This is a low-level function which allows creating routes for any protocol. You must specify the protocolfamily
and either network device nameifname
orgateway
address. Both packet source addresssrcaddr
and destination addressdstaddr
are optional. You must also specify the corresponding length and prefix argument for any address which is notNULL
. All addresses must be in binary representation in network byte order. Returns 1 on success, 0 on error. -
int NETDEV_ADD_ROUTE_INET(const char *ifname, in_addr_t srcaddr, unsigned int srcprefix, in_addr_t dstaddr, unsigned int dstprefix, in_addr_t gateway)
– Adds new IPv4 route to the main routing table. Parameters have the same meaning as inNETDEV_ADD_ROUTE()
. If you do not want to set explicitgateway
address, set it to 0. If the routing rule should ignore the source or destination address, set the corresponding prefix argument to 0. Returns 1 on success, 0 on error. -
int NETDEV_REMOVE_ROUTE(const char *ifname, unsigned int family, const void *srcaddr, unsigned int srcprefix, size_t srclen, const void *dstaddr, unsigned int dstprefix, size_t dstlen, const void *gateway, size_t gatewaylen)
– Removes a route from the main routing table. Parameters have the same meaning as inNETDEV_ADD_ROUTE()
. Returns 1 on success, 0 on error. -
int NETDEV_REMOVE_ROUTE_INET(const char *ifname, in_addr_t srcaddr, unsigned int srcprefix, in_addr_t dstaddr, unsigned int dstprefix, in_addr_t gateway)
– Removes IPv4 route from the main routing table. Parameters have the same meaning as inNETDEV_ADD_ROUTE_INET()
. Returns 1 on success, 0 on error.
#include <arpa/inet.h>
#include <linux/if_addr.h>
#include "tst_test.h"
#include "tst_netdevice.h"
...
static void setup(void)
{
CREATE_VETH_PAIR("ltp_veth1", "ltp_veth2");
NETDEV_ADD_ADDRESS_INET("ltp_veth2", htonl(DSTADDR), NETMASK,
IFA_F_NOPREFIXROUTE);
NETDEV_SET_STATE("ltp_veth2", 1);
NETDEV_ADD_ROUTE_INET("ltp_veth2", 0, 0, htonl(SRCNET), NETMASK, 0);
NETDEV_ADD_ADDRESS_INET("ltp_veth1", htonl(SRCADDR), NETMASK,
IFA_F_NOPREFIXROUTE);
NETDEV_SET_STATE("ltp_veth1", 1);
NETDEV_ADD_ROUTE_INET("ltp_veth1", 0, 0, htonl(DSTNET), NETMASK, 0);
...
}
#include "tst_rtnetlink.h"
The rtnetlink library provides helper functions for constructing and sending arbitrary messages and parsing kernel responses.
All of the functions below will call tst_brk()
on failure, unless stated
otherwise. Error values described below are returned only during test cleanup
stage.
struct tst_rtnl_context;
struct tst_rtnl_attr_list {
unsigned short type;
const void *data;
ssize_t len;
const struct tst_rtnl_attr_list *sublist;
};
struct tst_rtnl_message {
struct nlmsghdr *header;
struct nlmsgerr *err;
void *payload;
size_t payload_size;
};
struct tst_rtnl_context
is an opaque rtnetlink socket with buffer for
constructing and sending arbitrary messages using the functions described
below. Create a new context using RTNL_CREATE_CONTEXT()
, then free it using
RTNL_DESTROY_CONTEXT()
when you’re done with it.
struct tst_rtnl_attr_list
is a helper structure for defining complex
rtnetlink message attribute payloads, including nested attribute lists. Every
list and sublist defined using this structure is terminated by item with
negative len
.
-
type
is the attribute type that will be stored instruct rtattr.rta_type
. -
data
contains arbitrary attribute payload. -
len
contains length of thedata
attribute in bytes. Ifdata
isNULL
, setlen
to 0. The last item in a list or sublist must have negative length. -
sublist
contains a nested attribute list which will be appended afterdata
as part of the attribute payload.struct rtattr.rta_len
will be calculated automatically with proper alignment, do not add the sublist size to thelen
field. If you do not want to add nested attributes, setsublist
toNULL
.
struct tst_rtnl_message
is a structure holding partially parsed rtnetlink
messages received from the kernel. RTNL_RECV()
returns an array of these
structures with the last item having NULL
in the header
field. Call
RTNL_FREE_MESSAGE()
to free a message list returned by RTNL_RECV()
.
-
header
is the netlink header structure of the message.NULL
in the header field terminates a list of messages. -
err
points to the payload ofNLMSG_ERROR
messages. It is set toNULL
for all other message types. -
payload
is a pointer to message data. -
payload_size
is the length ofpayload
data in bytes.
-
struct tst_rtnl_context *RTNL_CREATE_CONTEXT(void)
– Creates a new rtnetlink communication context for use with the functions described below. ReturnsNULL
on error. -
void RTNL_FREE_MESSAGE(struct tst_rtnl_message *msg)
– Frees an array of messages returned byRTNL_RECV()
. -
void RTNL_DESTROY_CONTEXT(struct tst_rtnl_context *ctx)
– Closes a communication context created byRTNL_CREATE_CONTEXT()
. -
int RTNL_SEND(struct tst_rtnl_context *ctx)
– Sends all messages waiting inctx
buffer to the kernel. If there are multiple messages to send, a newNLMSG_DONE
message will be added automatically. Returns the number of bytes sent on success. Return 0 or negative value on error. -
int RTNL_SEND_VALIDATE(struct tst_rtnl_context *ctx)
– Sends all messages just likeRTNL_SEND()
, then receives the response from the kernel and validates results of requests sent with theNLM_F_ACK
flag. This function callstst_brk()
as usual if communication fails but it will return error status without terminating the test if one of the received messages contains error code. SeeRTNL_CHECK_ACKS()
below for explanation of the return value. -
int RTNL_WAIT(struct tst_rtnl_context *ctx)
– Waits until data becomes available to read from the rtnetlink socket (timeout: 1 second). Returns 1 if there is data to read, 0 on timeout or -1 on error. -
struct tst_rtnl_message *RTNL_RECV(struct tst_rtnl_context *ctx)
– Receives rtnetlink messages from the kernel. The messages are received in non-blocking mode so callingRTNL_WAIT()
first is recommended. Returns an array of partially parsed messages terminated by an item withNULL
in theheader
field. On error or when there are no messages to receive, returnsNULL
. CallRTNL_FREE_MESSAGE()
to free the returned data. -
int RTNL_CHECK_ACKS(struct tst_rtnl_context *ctx, struct tst_rtnl_message *response)
– Validate results of requests sent with theNLM_F_ACK
flag. Do not callRTNL_ADD_MESSAGE()
betweenRTNL_SEND()
andRTNL_CHECK_ACKS()
because it will reset the state ofctx
and prevent result validation. Returns 1 if all messages sent with theNLM_F_ACK
flag have a corresponding message inresponse
and the error code is 0. If any of the expected response messages is missing, this function will calltst_brk()
(or return 0 during test cleanup phase). If any of the response messages has non-zero error code, this function will return 0 and store the first non-zero error code in global variabletst_rtnl_errno
(sign-flipped just like regular libcerrno
).
-
int RTNL_ADD_MESSAGE(struct tst_rtnl_context *ctx, const struct nlmsghdr *header, const void *payload, size_t payload_size)
– Adds new rtnetlink message toctx
buffer. You need to provide messageheader
and optionalpayload
.payload_size
is the size ofpayload
data in bytes. If you don’t want to add any payload data, setpayload
toNULL
andpayload_size
to 0. This function will automatically fill thenlmsg_len
,nlmsg_seq
andnlmsg_pid
fields of the new message header. You don’t need to set those. It’ll also automatically addNLM_F_MULTI
flag when needed. Returns 1 on success, 0 on error. Note that the first call ofRTNL_ADD_MESSAGE()
afterRTNL_SEND()
will reset the state ofctx
andRTNL_CHECK_ACKS()
will not work correctly until the nextRTNL_SEND()
. -
int RTNL_ADD_ATTR(struct tst_rtnl_context *ctx, unsigned short type, const void *data, unsigned short len)
– Adds new attribute to the last message inctx
buffer. SeeRTNL_ADD_MESSAGE()
. You need to provide attributetype
which will be stored instruct rtattr.rta_type
, optional payloaddata
and payload sizelen
in bytes. If you don’t want to add any payload, setdata
toNULL
andlen
to 0. Returns 1 on success, 0 on error. -
int RTNL_ADD_ATTR_STRING(struct tst_rtnl_context *ctx, unsigned short type, const char *data)
– Adds new string attribute to the last message inctx
buffer. Parameters and return value are the same as forRTNL_ADD_ATTR()
, except the payload length is calculated usingstrlen()
. -
int RTNL_ADD_ATTR_LIST(struct tst_rtnl_context *ctx, const struct tst_rtnl_attr_list *list)
– Adds a list of attributes to the last message inctx
buffer. See description ofstruct tst_rtnl_attr_list
andRTNL_ADD_MESSAGE()
above. Returns the number of added attributes on success (nested attributes are not counted), -1 on error.
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "tst_test.h"
#include "tst_rtnetlink.h"
#include "tst_netdevice.h"
...
void setup(void)
{
struct tst_rtnl_context *ctx;
int index, ret;
in_addr_t addr;
struct nlmsghdr header = {
.nlmsg_type = RTM_NEWADDR,
.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE |
NLM_F_EXCL
};
struct ifaddrmsg info = {
.ifa_family = AF_INET,
.ifa_prefixlen = 24
};
index = NETDEV_INDEX_BY_NAME("ltp_veth1");
info.ifa_index = index;
ctx = RTNL_CREATE_CONTEXT();
RTNL_ADD_MESSAGE(ctx, &header, &info, sizeof(info));
addr = inet_addr("192.168.123.45");
RTNL_ADD_ATTR(ctx, IFA_LOCAL, &addr, sizeof(addr));
ret = RTNL_SEND_VALIDATE(ctx);
RTNL_DESTROY_CONTEXT(ctx);
if (!ret) {
tst_brk(TBROK, "Failed to set ltp_veth1 address");
}
}