add veth link support
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com> Signed-off-by: Thomas Graf <tgraf@suug.ch>
This commit is contained in:
parent
1f3511c1d1
commit
4263106728
8 changed files with 371 additions and 2 deletions
|
@ -312,6 +312,14 @@ struct ifla_vxlan_port_range {
|
|||
__be16 high;
|
||||
};
|
||||
|
||||
enum {
|
||||
VETH_INFO_UNSPEC,
|
||||
VETH_INFO_PEER,
|
||||
|
||||
__VETH_INFO_MAX
|
||||
#define VETH_INFO_MAX (__VETH_INFO_MAX - 1)
|
||||
};
|
||||
|
||||
/* SR-IOV virtual function management section */
|
||||
|
||||
enum {
|
||||
|
|
|
@ -97,6 +97,8 @@ typedef enum {
|
|||
|
||||
#define RTNL_LINK_STATS_MAX (__RTNL_LINK_STATS_MAX - 1)
|
||||
|
||||
extern struct nla_policy link_policy[];
|
||||
|
||||
extern struct rtnl_link *rtnl_link_alloc(void);
|
||||
extern void rtnl_link_put(struct rtnl_link *);
|
||||
|
||||
|
|
35
include/netlink/route/link/veth.h
Normal file
35
include/netlink/route/link/veth.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* netlink/route/link/veth.h VETH interface
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* Copyright (c) 2013 Cong Wang <xiyou.wangcong@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef NETLINK_LINK_VETH_H_
|
||||
#define NETLINK_LINK_VETH_H_
|
||||
|
||||
#include <netlink/netlink.h>
|
||||
#include <netlink/route/link.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern struct rtnl_link *rtnl_link_veth_alloc(void);
|
||||
extern void rtnl_link_veth_release(struct rtnl_link *);
|
||||
|
||||
extern int rtnl_link_is_veth(struct rtnl_link *);
|
||||
|
||||
extern struct rtnl_link *rtnl_link_veth_get_peer(struct rtnl_link *);
|
||||
extern int rtnl_link_veth_add(struct nl_sock *sock, const char *name,
|
||||
const char *peer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -76,7 +76,7 @@ libnl_route_3_la_SOURCES = \
|
|||
route/link/api.c route/link/vlan.c route/link/dummy.c \
|
||||
route/link/bridge.c route/link/inet6.c route/link/inet.c \
|
||||
route/link/bonding.c route/link/can.c route/link/macvlan.c \
|
||||
route/link/vxlan.c \
|
||||
route/link/vxlan.c route/link/veth.c \
|
||||
\
|
||||
route/qdisc/blackhole.c route/qdisc/cbq.c route/qdisc/dsmark.c \
|
||||
route/qdisc/fifo.c route/qdisc/htb.c route/qdisc/netem.c \
|
||||
|
|
|
@ -260,7 +260,7 @@ static int link_clone(struct nl_object *_dst, struct nl_object *_src)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct nla_policy link_policy[IFLA_MAX+1] = {
|
||||
struct nla_policy link_policy[IFLA_MAX+1] = {
|
||||
[IFLA_IFNAME] = { .type = NLA_STRING,
|
||||
.maxlen = IFNAMSIZ },
|
||||
[IFLA_MTU] = { .type = NLA_U32 },
|
||||
|
|
281
lib/route/link/veth.c
Normal file
281
lib/route/link/veth.c
Normal file
|
@ -0,0 +1,281 @@
|
|||
/*
|
||||
* lib/route/link/veth.c Virtual Ethernet
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* Copyright (c) 2013 Cong Wang <xiyou.wangcong@gmail.com>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup link
|
||||
* @defgroup veth VETH
|
||||
* Virtual Ethernet
|
||||
*
|
||||
* @details
|
||||
* \b Link Type Name: "veth"
|
||||
*
|
||||
* @route_doc{link_veth, VETH Documentation}
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <netlink-private/netlink.h>
|
||||
#include <netlink/netlink.h>
|
||||
#include <netlink/attr.h>
|
||||
#include <netlink/utils.h>
|
||||
#include <netlink/object.h>
|
||||
#include <netlink/route/rtnl.h>
|
||||
#include <netlink-private/route/link/api.h>
|
||||
#include <netlink/route/link/veth.h>
|
||||
|
||||
#include <linux/if_link.h>
|
||||
|
||||
static struct nla_policy veth_policy[VETH_INFO_MAX+1] = {
|
||||
[VETH_INFO_PEER] = { .minlen = sizeof(struct ifinfomsg) },
|
||||
};
|
||||
|
||||
static int veth_parse(struct rtnl_link *link, struct nlattr *data,
|
||||
struct nlattr *xstats)
|
||||
{
|
||||
struct nlattr *tb[VETH_INFO_MAX+1];
|
||||
struct nlattr *peer_tb[IFLA_MAX + 1];
|
||||
struct rtnl_link *peer = link->l_info;
|
||||
int err;
|
||||
|
||||
NL_DBG(3, "Parsing veth link info");
|
||||
|
||||
if ((err = nla_parse_nested(tb, VETH_INFO_MAX, data, veth_policy)) < 0)
|
||||
goto errout;
|
||||
|
||||
if (tb[VETH_INFO_PEER]) {
|
||||
struct nlattr *nla_peer;
|
||||
struct ifinfomsg *ifi;
|
||||
|
||||
nla_peer = tb[VETH_INFO_PEER];
|
||||
ifi = nla_data(nla_peer);
|
||||
|
||||
peer->l_family = ifi->ifi_family;
|
||||
peer->l_arptype = ifi->ifi_type;
|
||||
peer->l_index = ifi->ifi_index;
|
||||
peer->l_flags = ifi->ifi_flags;
|
||||
peer->l_change = ifi->ifi_change;
|
||||
err = nla_parse(peer_tb, IFLA_MAX,
|
||||
nla_data(nla_peer) + sizeof(struct ifinfomsg),
|
||||
nla_len(nla_peer) - sizeof(struct ifinfomsg),
|
||||
link_policy);
|
||||
if (err < 0)
|
||||
goto errout;
|
||||
|
||||
err = rtnl_link_info_parse(peer, peer_tb);
|
||||
if (err < 0)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
|
||||
errout:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void veth_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
|
||||
{
|
||||
}
|
||||
|
||||
static void veth_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
|
||||
{
|
||||
struct rtnl_link *peer = link->l_info;
|
||||
char *name;
|
||||
name = rtnl_link_get_name(peer);
|
||||
nl_dump(p, " peer ");
|
||||
if (name)
|
||||
nl_dump_line(p, "%s\n", name);
|
||||
else
|
||||
nl_dump_line(p, "%u\n", peer->l_index);
|
||||
}
|
||||
|
||||
static int veth_clone(struct rtnl_link *dst, struct rtnl_link *src)
|
||||
{
|
||||
struct rtnl_link *dst_peer , *src_peer = src->l_info;
|
||||
int err;
|
||||
|
||||
dst_peer = dst->l_info = rtnl_link_alloc();
|
||||
if (!dst_peer || !src_peer)
|
||||
return -NLE_NOMEM;
|
||||
if ((err = rtnl_link_set_type(dst, "veth")) < 0) {
|
||||
rtnl_link_put(dst_peer);
|
||||
return err;
|
||||
}
|
||||
|
||||
memcpy(dst_peer, src_peer, sizeof(struct rtnl_link));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int veth_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
|
||||
{
|
||||
struct rtnl_link *peer = link->l_info;
|
||||
struct ifinfomsg ifi;
|
||||
struct nlattr *data, *info_peer;
|
||||
|
||||
memset(&ifi, 0, sizeof ifi);
|
||||
ifi.ifi_family = peer->l_family;
|
||||
ifi.ifi_type = peer->l_arptype;
|
||||
ifi.ifi_index = peer->l_index;
|
||||
ifi.ifi_flags = peer->l_flags;
|
||||
ifi.ifi_change = peer->l_change;
|
||||
|
||||
if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
|
||||
return -NLE_MSGSIZE;
|
||||
if (!(info_peer = nla_nest_start(msg, VETH_INFO_PEER)))
|
||||
return -NLE_MSGSIZE;
|
||||
if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
|
||||
return -NLE_MSGSIZE;
|
||||
rtnl_link_fill_info(msg, peer);
|
||||
nla_nest_end(msg, info_peer);
|
||||
nla_nest_end(msg, data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct rtnl_link_info_ops veth_info_ops = {
|
||||
.io_name = "veth",
|
||||
.io_parse = veth_parse,
|
||||
.io_dump = {
|
||||
[NL_DUMP_LINE] = veth_dump_line,
|
||||
[NL_DUMP_DETAILS] = veth_dump_details,
|
||||
},
|
||||
.io_clone = veth_clone,
|
||||
.io_put_attrs = veth_put_attrs,
|
||||
};
|
||||
|
||||
/** @cond SKIP */
|
||||
|
||||
#define IS_VETH_LINK_ASSERT(link) \
|
||||
if ((link)->l_info_ops != &veth_info_ops) { \
|
||||
APPBUG("Link is not a veth link. set type \"veth\" first."); \
|
||||
return NULL; \
|
||||
}
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
* @name VETH Object
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Allocate link object of type veth
|
||||
*
|
||||
* @return Allocated link object or NULL.
|
||||
*/
|
||||
struct rtnl_link *rtnl_link_veth_alloc(void)
|
||||
{
|
||||
struct rtnl_link *link, *peer;
|
||||
int err;
|
||||
|
||||
if (!(link = rtnl_link_alloc()))
|
||||
return NULL;
|
||||
if (!(peer = rtnl_link_alloc())) {
|
||||
rtnl_link_put(link);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((err = rtnl_link_set_type(link, "veth")) < 0) {
|
||||
rtnl_link_put(peer);
|
||||
rtnl_link_put(link);
|
||||
return NULL;
|
||||
}
|
||||
if ((err = rtnl_link_set_type(peer, "veth")) < 0) {
|
||||
rtnl_link_put(peer);
|
||||
rtnl_link_put(link);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
link->l_info = peer;
|
||||
peer->l_info = link;
|
||||
return link;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the peer link of a veth link
|
||||
*
|
||||
* @return the peer link object.
|
||||
*/
|
||||
struct rtnl_link *rtnl_link_veth_get_peer(struct rtnl_link *link)
|
||||
{
|
||||
IS_VETH_LINK_ASSERT(link);
|
||||
return link->l_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release a veth link and its peer
|
||||
*
|
||||
*/
|
||||
void rtnl_link_veth_release(struct rtnl_link *link)
|
||||
{
|
||||
struct rtnl_link *peer = rtnl_link_veth_get_peer(link);
|
||||
rtnl_link_put(peer);
|
||||
rtnl_link_put(link);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if link is a veth link
|
||||
* @arg link Link object
|
||||
*
|
||||
* @return True if link is a veth link, otherwise false is returned.
|
||||
*/
|
||||
int rtnl_link_is_veth(struct rtnl_link *link)
|
||||
{
|
||||
return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "veth");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new kernel veth device
|
||||
* @arg sock netlink socket
|
||||
* @arg name name of the veth device or NULL
|
||||
* @arg peer_name name of its peer or NULL
|
||||
*
|
||||
* Creates a new veth device pair in the kernel. If no name is
|
||||
* provided, the kernel will automatically pick a name of the
|
||||
* form "veth%d" (e.g. veth0, veth1, etc.)
|
||||
*
|
||||
* @return 0 on success or a negative error code
|
||||
*/
|
||||
int rtnl_link_veth_add(struct nl_sock *sock, const char *name,
|
||||
const char *peer_name)
|
||||
{
|
||||
struct rtnl_link *link, *peer;
|
||||
int err = -NLE_NOMEM;
|
||||
|
||||
if (!(link = rtnl_link_veth_alloc()))
|
||||
return -NLE_NOMEM;
|
||||
peer = rtnl_link_veth_get_peer(link);
|
||||
|
||||
if (name && peer_name) {
|
||||
rtnl_link_set_name(link, name);
|
||||
rtnl_link_set_name(peer, peer_name);
|
||||
}
|
||||
|
||||
err = rtnl_link_add(sock, link, NLM_F_CREATE);
|
||||
|
||||
rtnl_link_put(peer);
|
||||
rtnl_link_put(link);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
static void __init veth_init(void)
|
||||
{
|
||||
rtnl_link_register_info(&veth_info_ops);
|
||||
}
|
||||
|
||||
static void __exit veth_exit(void)
|
||||
{
|
||||
rtnl_link_unregister_info(&veth_info_ops);
|
||||
}
|
||||
|
||||
/** @} */
|
|
@ -22,6 +22,7 @@ check_PROGRAMS = \
|
|||
test-create-bond \
|
||||
test-create-vlan \
|
||||
test-create-vxlan \
|
||||
test-create-veth \
|
||||
test-create-bridge \
|
||||
test-delete-link \
|
||||
test-socket-creation \
|
||||
|
@ -43,6 +44,7 @@ test_cache_mngr_SOURCES = test-cache-mngr.c
|
|||
test_create_bond_SOURCES = test-create-bond.c
|
||||
test_create_vlan_SOURCES = test-create-vlan.c
|
||||
test_create_vxlan_SOURCES = test-create-vxlan.c
|
||||
test_create_veth_SOURCES = test-create-veth.c
|
||||
test_create_bridge_SOURCES = test-create-bridge.c
|
||||
test_delete_link_SOURCES = test-delete-link.c
|
||||
test_genl_SOURCES = test-genl.c
|
||||
|
|
41
tests/test-create-veth.c
Normal file
41
tests/test-create-veth.c
Normal file
|
@ -0,0 +1,41 @@
|
|||
#include <netlink/netlink.h>
|
||||
#include <netlink/route/link.h>
|
||||
#include <netlink/route/link/veth.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct rtnl_link *link;
|
||||
struct nl_sock *sk;
|
||||
int err;
|
||||
struct rtnl_link *peer;
|
||||
|
||||
sk = nl_socket_alloc();
|
||||
if ((err = nl_connect(sk, NETLINK_ROUTE)) < 0) {
|
||||
nl_perror(err, "Unable to connect socket");
|
||||
return err;
|
||||
}
|
||||
|
||||
#if 0
|
||||
rtnl_link_veth_add(sk, "veth2", "veth3");
|
||||
#else
|
||||
link = rtnl_link_veth_alloc();
|
||||
if (!link) {
|
||||
nl_perror(err, "Unable to alloc link");
|
||||
return err;
|
||||
}
|
||||
|
||||
rtnl_link_set_name(link, "veth8");
|
||||
peer = rtnl_link_veth_get_peer(link);
|
||||
rtnl_link_set_name(peer, "veth9");
|
||||
|
||||
if ((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0) {
|
||||
nl_perror(err, "Unable to add link");
|
||||
return err;
|
||||
}
|
||||
printf("peer is %s\n", rtnl_link_get_name(peer));
|
||||
rtnl_link_put(link);
|
||||
#endif
|
||||
nl_close(sk);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Reference in a new issue