2007-09-15 01:28:01 +02:00
|
|
|
/*
|
|
|
|
* lib/route/link.c Links (Interfaces)
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
2012-10-09 18:15:50 +02:00
|
|
|
* Copyright (c) 2003-2012 Thomas Graf <tgraf@suug.ch>
|
2007-09-15 01:28:01 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @ingroup rtnl
|
|
|
|
* @defgroup link Links (Interfaces)
|
2011-07-28 16:23:57 +02:00
|
|
|
*
|
|
|
|
* @details
|
|
|
|
* @route_doc{route_link, Link Documentation}
|
2007-09-15 01:28:01 +02:00
|
|
|
* @{
|
|
|
|
*/
|
|
|
|
|
2013-01-24 13:51:24 +01:00
|
|
|
#include <netlink-private/netlink.h>
|
2007-09-15 01:28:01 +02:00
|
|
|
#include <netlink/netlink.h>
|
|
|
|
#include <netlink/attr.h>
|
|
|
|
#include <netlink/utils.h>
|
|
|
|
#include <netlink/object.h>
|
2012-11-09 14:41:34 -08:00
|
|
|
#include <netlink/hashtable.h>
|
2013-08-01 13:57:08 +02:00
|
|
|
#include <netlink/data.h>
|
2007-09-15 01:28:01 +02:00
|
|
|
#include <netlink/route/rtnl.h>
|
|
|
|
#include <netlink/route/link.h>
|
2013-01-24 13:51:24 +01:00
|
|
|
#include <netlink-private/route/link/api.h>
|
2007-09-15 01:28:01 +02:00
|
|
|
|
|
|
|
/** @cond SKIP */
|
2012-10-09 18:15:50 +02:00
|
|
|
#define LINK_ATTR_MTU (1 << 0)
|
|
|
|
#define LINK_ATTR_LINK (1 << 1)
|
|
|
|
#define LINK_ATTR_TXQLEN (1 << 2)
|
|
|
|
#define LINK_ATTR_WEIGHT (1 << 3)
|
|
|
|
#define LINK_ATTR_MASTER (1 << 4)
|
|
|
|
#define LINK_ATTR_QDISC (1 << 5)
|
|
|
|
#define LINK_ATTR_MAP (1 << 6)
|
|
|
|
#define LINK_ATTR_ADDR (1 << 7)
|
|
|
|
#define LINK_ATTR_BRD (1 << 8)
|
|
|
|
#define LINK_ATTR_FLAGS (1 << 9)
|
|
|
|
#define LINK_ATTR_IFNAME (1 << 10)
|
|
|
|
#define LINK_ATTR_IFINDEX (1 << 11)
|
|
|
|
#define LINK_ATTR_FAMILY (1 << 12)
|
|
|
|
#define LINK_ATTR_ARPTYPE (1 << 13)
|
|
|
|
#define LINK_ATTR_STATS (1 << 14)
|
|
|
|
#define LINK_ATTR_CHANGE (1 << 15)
|
|
|
|
#define LINK_ATTR_OPERSTATE (1 << 16)
|
|
|
|
#define LINK_ATTR_LINKMODE (1 << 17)
|
|
|
|
#define LINK_ATTR_LINKINFO (1 << 18)
|
|
|
|
#define LINK_ATTR_IFALIAS (1 << 19)
|
|
|
|
#define LINK_ATTR_NUM_VF (1 << 20)
|
|
|
|
#define LINK_ATTR_PROMISCUITY (1 << 21)
|
2012-10-09 19:57:22 +02:00
|
|
|
#define LINK_ATTR_NUM_TX_QUEUES (1 << 22)
|
|
|
|
#define LINK_ATTR_NUM_RX_QUEUES (1 << 23)
|
2012-10-09 21:55:31 +02:00
|
|
|
#define LINK_ATTR_GROUP (1 << 24)
|
2013-01-07 18:36:12 -02:00
|
|
|
#define LINK_ATTR_CARRIER (1 << 25)
|
2013-01-17 16:29:04 -08:00
|
|
|
#define LINK_ATTR_PROTINFO (1 << 26)
|
|
|
|
#define LINK_ATTR_AF_SPEC (1 << 27)
|
2013-08-01 13:57:08 +02:00
|
|
|
#define LINK_ATTR_PHYS_PORT_ID (1 << 28)
|
2013-11-01 16:58:49 -07:00
|
|
|
#define LINK_ATTR_NS_FD (1 << 29)
|
|
|
|
#define LINK_ATTR_NS_PID (1 << 30)
|
2007-09-15 01:28:01 +02:00
|
|
|
|
|
|
|
static struct nl_cache_ops rtnl_link_ops;
|
|
|
|
static struct nl_object_ops link_obj_ops;
|
|
|
|
/** @endcond */
|
|
|
|
|
2010-11-13 01:38:13 +01:00
|
|
|
static struct rtnl_link_af_ops *af_lookup_and_alloc(struct rtnl_link *link,
|
|
|
|
int family)
|
|
|
|
{
|
|
|
|
struct rtnl_link_af_ops *af_ops;
|
2010-11-16 12:41:43 +01:00
|
|
|
void *data;
|
2010-11-13 01:38:13 +01:00
|
|
|
|
|
|
|
af_ops = rtnl_link_af_ops_lookup(family);
|
|
|
|
if (!af_ops)
|
|
|
|
return NULL;
|
|
|
|
|
2013-02-05 13:03:02 +01:00
|
|
|
if (!(data = rtnl_link_af_alloc(link, af_ops))) {
|
|
|
|
rtnl_link_af_ops_put(af_ops);
|
2010-11-16 12:41:43 +01:00
|
|
|
return NULL;
|
2013-02-05 13:03:02 +01:00
|
|
|
}
|
2010-11-13 01:38:13 +01:00
|
|
|
|
|
|
|
return af_ops;
|
|
|
|
}
|
|
|
|
|
2010-11-11 15:50:49 +01:00
|
|
|
static int af_free(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
|
|
|
|
void *data, void *arg)
|
|
|
|
{
|
|
|
|
if (ops->ao_free)
|
|
|
|
ops->ao_free(link, data);
|
|
|
|
|
|
|
|
rtnl_link_af_ops_put(ops);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int af_clone(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
|
|
|
|
void *data, void *arg)
|
|
|
|
{
|
|
|
|
struct rtnl_link *dst = arg;
|
|
|
|
|
|
|
|
if (ops->ao_clone &&
|
2011-04-21 14:46:06 +02:00
|
|
|
!(dst->l_af_data[ops->ao_family] = ops->ao_clone(dst, data)))
|
2010-11-11 15:50:49 +01:00
|
|
|
return -NLE_NOMEM;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-11-16 12:41:43 +01:00
|
|
|
static int af_fill(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
|
|
|
|
void *data, void *arg)
|
|
|
|
{
|
|
|
|
struct nl_msg *msg = arg;
|
|
|
|
struct nlattr *af_attr;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (!ops->ao_fill_af)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!(af_attr = nla_nest_start(msg, ops->ao_family)))
|
|
|
|
return -NLE_MSGSIZE;
|
|
|
|
|
|
|
|
if ((err = ops->ao_fill_af(link, arg, data)) < 0)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
nla_nest_end(msg, af_attr);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-11-11 15:50:49 +01:00
|
|
|
static int af_dump_line(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
|
|
|
|
void *data, void *arg)
|
|
|
|
{
|
|
|
|
struct nl_dump_params *p = arg;
|
|
|
|
|
|
|
|
if (ops->ao_dump[NL_DUMP_LINE])
|
|
|
|
ops->ao_dump[NL_DUMP_LINE](link, p, data);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int af_dump_details(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
|
|
|
|
void *data, void *arg)
|
|
|
|
{
|
|
|
|
struct nl_dump_params *p = arg;
|
|
|
|
|
|
|
|
if (ops->ao_dump[NL_DUMP_DETAILS])
|
|
|
|
ops->ao_dump[NL_DUMP_DETAILS](link, p, data);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int af_dump_stats(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
|
|
|
|
void *data, void *arg)
|
|
|
|
{
|
|
|
|
struct nl_dump_params *p = arg;
|
|
|
|
|
|
|
|
if (ops->ao_dump[NL_DUMP_STATS])
|
|
|
|
ops->ao_dump[NL_DUMP_STATS](link, p, data);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int do_foreach_af(struct rtnl_link *link,
|
|
|
|
int (*cb)(struct rtnl_link *,
|
|
|
|
struct rtnl_link_af_ops *, void *, void *),
|
|
|
|
void *arg)
|
|
|
|
{
|
|
|
|
int i, err;
|
|
|
|
|
|
|
|
for (i = 0; i < AF_MAX; i++) {
|
|
|
|
if (link->l_af_data[i]) {
|
|
|
|
struct rtnl_link_af_ops *ops;
|
|
|
|
|
|
|
|
if (!(ops = rtnl_link_af_ops_lookup(i)))
|
|
|
|
BUG();
|
|
|
|
|
2013-02-05 13:46:42 +01:00
|
|
|
err = cb(link, ops, link->l_af_data[i], arg);
|
|
|
|
|
|
|
|
rtnl_link_af_ops_put(ops);
|
|
|
|
|
|
|
|
if (err < 0)
|
2010-11-11 15:50:49 +01:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-01-08 15:00:46 +01:00
|
|
|
static void release_link_info(struct rtnl_link *link)
|
|
|
|
{
|
|
|
|
struct rtnl_link_info_ops *io = link->l_info_ops;
|
|
|
|
|
|
|
|
if (io != NULL) {
|
2011-04-15 15:30:46 +02:00
|
|
|
if (io->io_free)
|
|
|
|
io->io_free(link);
|
2014-03-31 13:21:06 +02:00
|
|
|
else {
|
|
|
|
/* Catch missing io_free() implementations */
|
|
|
|
BUG_ON(link->l_info);
|
|
|
|
}
|
2010-11-11 16:18:53 +01:00
|
|
|
rtnl_link_info_ops_put(io);
|
2008-01-08 15:00:46 +01:00
|
|
|
link->l_info_ops = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-15 01:28:01 +02:00
|
|
|
static void link_free_data(struct nl_object *c)
|
|
|
|
{
|
|
|
|
struct rtnl_link *link = nl_object_priv(c);
|
|
|
|
|
|
|
|
if (link) {
|
2008-01-08 15:00:46 +01:00
|
|
|
struct rtnl_link_info_ops *io;
|
|
|
|
|
|
|
|
if ((io = link->l_info_ops) != NULL)
|
|
|
|
release_link_info(link);
|
|
|
|
|
2013-02-05 13:46:42 +01:00
|
|
|
/* proto info af reference */
|
2013-02-05 13:18:25 +01:00
|
|
|
rtnl_link_af_ops_put(link->l_af_ops);
|
|
|
|
|
2007-09-15 01:28:01 +02:00
|
|
|
nl_addr_put(link->l_addr);
|
|
|
|
nl_addr_put(link->l_bcast);
|
2010-11-11 13:57:10 +01:00
|
|
|
|
|
|
|
free(link->l_ifalias);
|
2011-11-11 14:56:16 +01:00
|
|
|
free(link->l_info_kind);
|
2010-11-11 15:50:49 +01:00
|
|
|
|
|
|
|
do_foreach_af(link, af_free, NULL);
|
2013-08-01 13:57:08 +02:00
|
|
|
|
|
|
|
nl_data_free(link->l_phys_port_id);
|
2007-09-15 01:28:01 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int link_clone(struct nl_object *_dst, struct nl_object *_src)
|
|
|
|
{
|
|
|
|
struct rtnl_link *dst = nl_object_priv(_dst);
|
|
|
|
struct rtnl_link *src = nl_object_priv(_src);
|
2008-01-08 15:00:46 +01:00
|
|
|
int err;
|
2007-09-15 01:28:01 +02:00
|
|
|
|
|
|
|
if (src->l_addr)
|
|
|
|
if (!(dst->l_addr = nl_addr_clone(src->l_addr)))
|
2008-05-14 17:49:44 +02:00
|
|
|
return -NLE_NOMEM;
|
2007-09-15 01:28:01 +02:00
|
|
|
|
|
|
|
if (src->l_bcast)
|
|
|
|
if (!(dst->l_bcast = nl_addr_clone(src->l_bcast)))
|
2008-05-14 17:49:44 +02:00
|
|
|
return -NLE_NOMEM;
|
2007-09-15 01:28:01 +02:00
|
|
|
|
2010-11-11 13:57:10 +01:00
|
|
|
if (src->l_ifalias)
|
|
|
|
if (!(dst->l_ifalias = strdup(src->l_ifalias)))
|
|
|
|
return -NLE_NOMEM;
|
|
|
|
|
2011-11-11 14:56:16 +01:00
|
|
|
if (src->l_info_kind)
|
|
|
|
if (!(dst->l_info_kind = strdup(src->l_info_kind)))
|
|
|
|
return -NLE_NOMEM;
|
|
|
|
|
2008-01-08 15:00:46 +01:00
|
|
|
if (src->l_info_ops && src->l_info_ops->io_clone) {
|
|
|
|
err = src->l_info_ops->io_clone(dst, src);
|
|
|
|
if (err < 0)
|
2008-05-14 17:49:44 +02:00
|
|
|
return err;
|
2008-01-08 15:00:46 +01:00
|
|
|
}
|
|
|
|
|
2010-11-11 15:50:49 +01:00
|
|
|
if ((err = do_foreach_af(src, af_clone, dst)) < 0)
|
|
|
|
return err;
|
|
|
|
|
2013-08-01 13:57:08 +02:00
|
|
|
if (src->l_phys_port_id)
|
|
|
|
if (!(dst->l_phys_port_id = nl_data_clone(src->l_phys_port_id)))
|
|
|
|
return -NLE_NOMEM;
|
|
|
|
|
2007-09-15 01:28:01 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-01-02 11:00:31 +01:00
|
|
|
struct nla_policy rtln_link_policy[IFLA_MAX+1] = {
|
2012-10-09 18:15:50 +02:00
|
|
|
[IFLA_IFNAME] = { .type = NLA_STRING,
|
|
|
|
.maxlen = IFNAMSIZ },
|
|
|
|
[IFLA_MTU] = { .type = NLA_U32 },
|
|
|
|
[IFLA_TXQLEN] = { .type = NLA_U32 },
|
|
|
|
[IFLA_LINK] = { .type = NLA_U32 },
|
|
|
|
[IFLA_WEIGHT] = { .type = NLA_U32 },
|
|
|
|
[IFLA_MASTER] = { .type = NLA_U32 },
|
|
|
|
[IFLA_OPERSTATE] = { .type = NLA_U8 },
|
|
|
|
[IFLA_LINKMODE] = { .type = NLA_U8 },
|
|
|
|
[IFLA_LINKINFO] = { .type = NLA_NESTED },
|
|
|
|
[IFLA_QDISC] = { .type = NLA_STRING,
|
|
|
|
.maxlen = IFQDISCSIZ },
|
|
|
|
[IFLA_STATS] = { .minlen = sizeof(struct rtnl_link_stats) },
|
|
|
|
[IFLA_STATS64] = { .minlen = sizeof(struct rtnl_link_stats64)},
|
|
|
|
[IFLA_MAP] = { .minlen = sizeof(struct rtnl_link_ifmap) },
|
|
|
|
[IFLA_IFALIAS] = { .type = NLA_STRING, .maxlen = IFALIASZ },
|
|
|
|
[IFLA_NUM_VF] = { .type = NLA_U32 },
|
|
|
|
[IFLA_AF_SPEC] = { .type = NLA_NESTED },
|
|
|
|
[IFLA_PROMISCUITY] = { .type = NLA_U32 },
|
2012-10-09 19:57:22 +02:00
|
|
|
[IFLA_NUM_TX_QUEUES] = { .type = NLA_U32 },
|
|
|
|
[IFLA_NUM_RX_QUEUES] = { .type = NLA_U32 },
|
2012-10-09 21:55:31 +02:00
|
|
|
[IFLA_GROUP] = { .type = NLA_U32 },
|
2013-01-07 18:36:12 -02:00
|
|
|
[IFLA_CARRIER] = { .type = NLA_U8 },
|
2013-08-01 13:57:08 +02:00
|
|
|
[IFLA_PHYS_PORT_ID] = { .type = NLA_UNSPEC },
|
2013-11-01 16:58:49 -07:00
|
|
|
[IFLA_NET_NS_PID] = { .type = NLA_U32 },
|
|
|
|
[IFLA_NET_NS_FD] = { .type = NLA_U32 },
|
2007-09-15 01:28:01 +02:00
|
|
|
};
|
|
|
|
|
2008-01-08 15:00:46 +01:00
|
|
|
static struct nla_policy link_info_policy[IFLA_INFO_MAX+1] = {
|
|
|
|
[IFLA_INFO_KIND] = { .type = NLA_STRING },
|
|
|
|
[IFLA_INFO_DATA] = { .type = NLA_NESTED },
|
|
|
|
[IFLA_INFO_XSTATS] = { .type = NLA_NESTED },
|
|
|
|
};
|
|
|
|
|
2013-11-01 16:58:47 -07:00
|
|
|
int rtnl_link_info_parse(struct rtnl_link *link, struct nlattr **tb)
|
2007-09-15 01:28:01 +02:00
|
|
|
{
|
2013-11-01 16:58:47 -07:00
|
|
|
if (tb[IFLA_IFNAME] == NULL)
|
|
|
|
return -NLE_MISSING_ATTR;
|
2007-09-15 01:28:01 +02:00
|
|
|
|
|
|
|
nla_strlcpy(link->l_name, tb[IFLA_IFNAME], IFNAMSIZ);
|
|
|
|
|
|
|
|
|
|
|
|
if (tb[IFLA_STATS]) {
|
|
|
|
struct rtnl_link_stats *st = nla_data(tb[IFLA_STATS]);
|
2010-10-29 01:58:27 +02:00
|
|
|
|
2007-09-15 01:28:01 +02:00
|
|
|
link->l_stats[RTNL_LINK_RX_PACKETS] = st->rx_packets;
|
2010-10-29 01:58:27 +02:00
|
|
|
link->l_stats[RTNL_LINK_TX_PACKETS] = st->tx_packets;
|
2007-09-15 01:28:01 +02:00
|
|
|
link->l_stats[RTNL_LINK_RX_BYTES] = st->rx_bytes;
|
2010-10-29 01:58:27 +02:00
|
|
|
link->l_stats[RTNL_LINK_TX_BYTES] = st->tx_bytes;
|
2007-09-15 01:28:01 +02:00
|
|
|
link->l_stats[RTNL_LINK_RX_ERRORS] = st->rx_errors;
|
2010-10-29 01:58:27 +02:00
|
|
|
link->l_stats[RTNL_LINK_TX_ERRORS] = st->tx_errors;
|
2007-09-15 01:28:01 +02:00
|
|
|
link->l_stats[RTNL_LINK_RX_DROPPED] = st->rx_dropped;
|
2010-10-29 01:58:27 +02:00
|
|
|
link->l_stats[RTNL_LINK_TX_DROPPED] = st->tx_dropped;
|
|
|
|
link->l_stats[RTNL_LINK_MULTICAST] = st->multicast;
|
|
|
|
link->l_stats[RTNL_LINK_COLLISIONS] = st->collisions;
|
|
|
|
|
|
|
|
link->l_stats[RTNL_LINK_RX_LEN_ERR] = st->rx_length_errors;
|
|
|
|
link->l_stats[RTNL_LINK_RX_OVER_ERR] = st->rx_over_errors;
|
|
|
|
link->l_stats[RTNL_LINK_RX_CRC_ERR] = st->rx_crc_errors;
|
|
|
|
link->l_stats[RTNL_LINK_RX_FRAME_ERR] = st->rx_frame_errors;
|
2007-09-15 01:28:01 +02:00
|
|
|
link->l_stats[RTNL_LINK_RX_FIFO_ERR] = st->rx_fifo_errors;
|
2010-10-29 01:58:27 +02:00
|
|
|
link->l_stats[RTNL_LINK_RX_MISSED_ERR] = st->rx_missed_errors;
|
|
|
|
|
|
|
|
link->l_stats[RTNL_LINK_TX_ABORT_ERR] = st->tx_aborted_errors;
|
|
|
|
link->l_stats[RTNL_LINK_TX_CARRIER_ERR] = st->tx_carrier_errors;
|
|
|
|
link->l_stats[RTNL_LINK_TX_FIFO_ERR] = st->tx_fifo_errors;
|
|
|
|
link->l_stats[RTNL_LINK_TX_HBEAT_ERR] = st->tx_heartbeat_errors;
|
|
|
|
link->l_stats[RTNL_LINK_TX_WIN_ERR] = st->tx_window_errors;
|
|
|
|
|
|
|
|
link->l_stats[RTNL_LINK_RX_COMPRESSED] = st->rx_compressed;
|
|
|
|
link->l_stats[RTNL_LINK_TX_COMPRESSED] = st->tx_compressed;
|
|
|
|
|
|
|
|
link->ce_mask |= LINK_ATTR_STATS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tb[IFLA_STATS64]) {
|
2011-08-11 11:43:46 -07:00
|
|
|
/*
|
|
|
|
* This structure contains 64bit parameters, and per the
|
|
|
|
* documentation in lib/attr.c, must not be accessed
|
|
|
|
* directly (because of alignment to 4 instead of 8).
|
|
|
|
* Therefore, copy the data to the stack and access it from
|
|
|
|
* there, where it will be aligned to 8.
|
|
|
|
*/
|
|
|
|
struct rtnl_link_stats64 st;
|
|
|
|
|
|
|
|
nla_memcpy(&st, tb[IFLA_STATS64],
|
|
|
|
sizeof(struct rtnl_link_stats64));
|
2010-10-29 01:58:27 +02:00
|
|
|
|
2011-08-11 11:43:46 -07:00
|
|
|
link->l_stats[RTNL_LINK_RX_PACKETS] = st.rx_packets;
|
|
|
|
link->l_stats[RTNL_LINK_TX_PACKETS] = st.tx_packets;
|
|
|
|
link->l_stats[RTNL_LINK_RX_BYTES] = st.rx_bytes;
|
|
|
|
link->l_stats[RTNL_LINK_TX_BYTES] = st.tx_bytes;
|
|
|
|
link->l_stats[RTNL_LINK_RX_ERRORS] = st.rx_errors;
|
|
|
|
link->l_stats[RTNL_LINK_TX_ERRORS] = st.tx_errors;
|
|
|
|
link->l_stats[RTNL_LINK_RX_DROPPED] = st.rx_dropped;
|
|
|
|
link->l_stats[RTNL_LINK_TX_DROPPED] = st.tx_dropped;
|
|
|
|
link->l_stats[RTNL_LINK_MULTICAST] = st.multicast;
|
|
|
|
link->l_stats[RTNL_LINK_COLLISIONS] = st.collisions;
|
|
|
|
|
|
|
|
link->l_stats[RTNL_LINK_RX_LEN_ERR] = st.rx_length_errors;
|
|
|
|
link->l_stats[RTNL_LINK_RX_OVER_ERR] = st.rx_over_errors;
|
|
|
|
link->l_stats[RTNL_LINK_RX_CRC_ERR] = st.rx_crc_errors;
|
|
|
|
link->l_stats[RTNL_LINK_RX_FRAME_ERR] = st.rx_frame_errors;
|
|
|
|
link->l_stats[RTNL_LINK_RX_FIFO_ERR] = st.rx_fifo_errors;
|
|
|
|
link->l_stats[RTNL_LINK_RX_MISSED_ERR] = st.rx_missed_errors;
|
|
|
|
|
|
|
|
link->l_stats[RTNL_LINK_TX_ABORT_ERR] = st.tx_aborted_errors;
|
|
|
|
link->l_stats[RTNL_LINK_TX_CARRIER_ERR] = st.tx_carrier_errors;
|
|
|
|
link->l_stats[RTNL_LINK_TX_FIFO_ERR] = st.tx_fifo_errors;
|
|
|
|
link->l_stats[RTNL_LINK_TX_HBEAT_ERR] = st.tx_heartbeat_errors;
|
|
|
|
link->l_stats[RTNL_LINK_TX_WIN_ERR] = st.tx_window_errors;
|
|
|
|
|
|
|
|
link->l_stats[RTNL_LINK_RX_COMPRESSED] = st.rx_compressed;
|
|
|
|
link->l_stats[RTNL_LINK_TX_COMPRESSED] = st.tx_compressed;
|
2007-09-15 01:28:01 +02:00
|
|
|
|
|
|
|
link->ce_mask |= LINK_ATTR_STATS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tb[IFLA_TXQLEN]) {
|
|
|
|
link->l_txqlen = nla_get_u32(tb[IFLA_TXQLEN]);
|
|
|
|
link->ce_mask |= LINK_ATTR_TXQLEN;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tb[IFLA_MTU]) {
|
|
|
|
link->l_mtu = nla_get_u32(tb[IFLA_MTU]);
|
|
|
|
link->ce_mask |= LINK_ATTR_MTU;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tb[IFLA_ADDRESS]) {
|
2008-05-14 18:26:47 +02:00
|
|
|
link->l_addr = nl_addr_alloc_attr(tb[IFLA_ADDRESS], AF_UNSPEC);
|
2013-11-01 16:58:47 -07:00
|
|
|
if (link->l_addr == NULL)
|
|
|
|
return -NLE_NOMEM;
|
2007-09-15 01:28:01 +02:00
|
|
|
nl_addr_set_family(link->l_addr,
|
|
|
|
nl_addr_guess_family(link->l_addr));
|
|
|
|
link->ce_mask |= LINK_ATTR_ADDR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tb[IFLA_BROADCAST]) {
|
2008-05-14 18:26:47 +02:00
|
|
|
link->l_bcast = nl_addr_alloc_attr(tb[IFLA_BROADCAST],
|
|
|
|
AF_UNSPEC);
|
2013-11-01 16:58:47 -07:00
|
|
|
if (link->l_bcast == NULL)
|
|
|
|
return -NLE_NOMEM;
|
2007-09-15 01:28:01 +02:00
|
|
|
nl_addr_set_family(link->l_bcast,
|
|
|
|
nl_addr_guess_family(link->l_bcast));
|
|
|
|
link->ce_mask |= LINK_ATTR_BRD;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tb[IFLA_LINK]) {
|
|
|
|
link->l_link = nla_get_u32(tb[IFLA_LINK]);
|
|
|
|
link->ce_mask |= LINK_ATTR_LINK;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tb[IFLA_WEIGHT]) {
|
|
|
|
link->l_weight = nla_get_u32(tb[IFLA_WEIGHT]);
|
|
|
|
link->ce_mask |= LINK_ATTR_WEIGHT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tb[IFLA_QDISC]) {
|
|
|
|
nla_strlcpy(link->l_qdisc, tb[IFLA_QDISC], IFQDISCSIZ);
|
|
|
|
link->ce_mask |= LINK_ATTR_QDISC;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tb[IFLA_MAP]) {
|
2008-03-31 22:43:04 +02:00
|
|
|
nla_memcpy(&link->l_map, tb[IFLA_MAP],
|
|
|
|
sizeof(struct rtnl_link_ifmap));
|
2007-09-15 01:28:01 +02:00
|
|
|
link->ce_mask |= LINK_ATTR_MAP;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tb[IFLA_MASTER]) {
|
|
|
|
link->l_master = nla_get_u32(tb[IFLA_MASTER]);
|
|
|
|
link->ce_mask |= LINK_ATTR_MASTER;
|
|
|
|
}
|
|
|
|
|
2013-01-07 18:36:12 -02:00
|
|
|
if (tb[IFLA_CARRIER]) {
|
|
|
|
link->l_carrier = nla_get_u8(tb[IFLA_CARRIER]);
|
|
|
|
link->ce_mask |= LINK_ATTR_CARRIER;
|
|
|
|
}
|
|
|
|
|
2007-12-19 22:03:44 +01:00
|
|
|
if (tb[IFLA_OPERSTATE]) {
|
|
|
|
link->l_operstate = nla_get_u8(tb[IFLA_OPERSTATE]);
|
|
|
|
link->ce_mask |= LINK_ATTR_OPERSTATE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tb[IFLA_LINKMODE]) {
|
|
|
|
link->l_linkmode = nla_get_u8(tb[IFLA_LINKMODE]);
|
|
|
|
link->ce_mask |= LINK_ATTR_LINKMODE;
|
|
|
|
}
|
|
|
|
|
2010-11-11 13:57:10 +01:00
|
|
|
if (tb[IFLA_IFALIAS]) {
|
|
|
|
link->l_ifalias = nla_strdup(tb[IFLA_IFALIAS]);
|
2013-11-01 16:58:47 -07:00
|
|
|
if (link->l_ifalias == NULL)
|
|
|
|
return -NLE_NOMEM;
|
2010-11-11 13:57:10 +01:00
|
|
|
link->ce_mask |= LINK_ATTR_IFALIAS;
|
|
|
|
}
|
|
|
|
|
2013-12-03 20:16:09 -08:00
|
|
|
if (tb[IFLA_NET_NS_FD]) {
|
|
|
|
link->l_ns_fd = nla_get_u32(tb[IFLA_NET_NS_FD]);
|
|
|
|
link->ce_mask |= LINK_ATTR_NS_FD;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tb[IFLA_NET_NS_PID]) {
|
|
|
|
link->l_ns_pid = nla_get_u32(tb[IFLA_NET_NS_PID]);
|
|
|
|
link->ce_mask |= LINK_ATTR_NS_PID;
|
|
|
|
}
|
|
|
|
|
2013-11-01 16:58:47 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
|
|
|
|
struct nlmsghdr *n, struct nl_parser_param *pp)
|
|
|
|
{
|
|
|
|
struct rtnl_link *link;
|
|
|
|
struct ifinfomsg *ifi;
|
|
|
|
struct nlattr *tb[IFLA_MAX+1];
|
|
|
|
struct rtnl_link_af_ops *af_ops = NULL;
|
|
|
|
int err, family;
|
|
|
|
struct nla_policy real_link_policy[IFLA_MAX+1];
|
|
|
|
|
2014-01-02 11:00:31 +01:00
|
|
|
memcpy(&real_link_policy, rtln_link_policy, sizeof(rtln_link_policy));
|
2013-11-01 16:58:47 -07:00
|
|
|
|
|
|
|
link = rtnl_link_alloc();
|
|
|
|
if (link == NULL) {
|
|
|
|
err = -NLE_NOMEM;
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
|
|
|
link->ce_msgtype = n->nlmsg_type;
|
|
|
|
|
2015-05-13 14:46:08 +02:00
|
|
|
if (!nlmsg_valid_hdr(n, sizeof(*ifi))) {
|
|
|
|
err = -NLE_MSG_TOOSHORT;
|
|
|
|
goto errout;
|
|
|
|
}
|
2013-11-01 16:58:47 -07:00
|
|
|
|
|
|
|
ifi = nlmsg_data(n);
|
|
|
|
link->l_family = family = ifi->ifi_family;
|
|
|
|
link->l_arptype = ifi->ifi_type;
|
|
|
|
link->l_index = ifi->ifi_index;
|
|
|
|
link->l_flags = ifi->ifi_flags;
|
|
|
|
link->l_change = ifi->ifi_change;
|
|
|
|
link->ce_mask = (LINK_ATTR_IFNAME | LINK_ATTR_FAMILY |
|
|
|
|
LINK_ATTR_ARPTYPE| LINK_ATTR_IFINDEX |
|
|
|
|
LINK_ATTR_FLAGS | LINK_ATTR_CHANGE);
|
|
|
|
|
|
|
|
if ((af_ops = af_lookup_and_alloc(link, family))) {
|
|
|
|
if (af_ops->ao_protinfo_policy) {
|
|
|
|
memcpy(&real_link_policy[IFLA_PROTINFO],
|
|
|
|
af_ops->ao_protinfo_policy,
|
|
|
|
sizeof(struct nla_policy));
|
|
|
|
}
|
|
|
|
|
|
|
|
link->l_af_ops = af_ops;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = nlmsg_parse(n, sizeof(*ifi), tb, IFLA_MAX, real_link_policy);
|
|
|
|
if (err < 0)
|
2015-05-13 14:46:08 +02:00
|
|
|
goto errout;
|
2013-11-01 16:58:47 -07:00
|
|
|
|
|
|
|
err = rtnl_link_info_parse(link, tb);
|
|
|
|
if (err < 0)
|
2015-05-13 14:46:08 +02:00
|
|
|
goto errout;
|
2013-11-01 16:58:47 -07:00
|
|
|
|
2010-11-11 14:11:32 +01:00
|
|
|
if (tb[IFLA_NUM_VF]) {
|
|
|
|
link->l_num_vf = nla_get_u32(tb[IFLA_NUM_VF]);
|
|
|
|
link->ce_mask |= LINK_ATTR_NUM_VF;
|
|
|
|
}
|
|
|
|
|
2008-01-08 15:00:46 +01:00
|
|
|
if (tb[IFLA_LINKINFO]) {
|
|
|
|
struct nlattr *li[IFLA_INFO_MAX+1];
|
|
|
|
|
|
|
|
err = nla_parse_nested(li, IFLA_INFO_MAX, tb[IFLA_LINKINFO],
|
|
|
|
link_info_policy);
|
|
|
|
if (err < 0)
|
|
|
|
goto errout;
|
|
|
|
|
2011-04-19 09:57:35 +02:00
|
|
|
if (li[IFLA_INFO_KIND]) {
|
2008-01-08 15:00:46 +01:00
|
|
|
struct rtnl_link_info_ops *ops;
|
2014-04-01 18:03:29 -07:00
|
|
|
char *kind = nla_get_string(li[IFLA_INFO_KIND]);
|
2013-10-10 20:51:38 +00:00
|
|
|
int af;
|
2008-01-08 15:00:46 +01:00
|
|
|
|
2014-04-01 18:03:29 -07:00
|
|
|
err = rtnl_link_set_type(link, kind);
|
|
|
|
if (err < 0)
|
2011-11-11 14:56:16 +01:00
|
|
|
goto errout;
|
|
|
|
|
2013-10-10 20:51:38 +00:00
|
|
|
if ((af = nl_str2af(kind)) >= 0 &&
|
|
|
|
!af_ops && (af_ops = af_lookup_and_alloc(link, af))) {
|
|
|
|
|
|
|
|
if (af_ops->ao_protinfo_policy) {
|
|
|
|
tb[IFLA_PROTINFO] = (struct nlattr *)af_ops->ao_protinfo_policy;
|
|
|
|
}
|
|
|
|
link->l_family = family = af;
|
|
|
|
link->l_af_ops = af_ops;
|
|
|
|
}
|
|
|
|
|
2008-01-08 15:00:46 +01:00
|
|
|
ops = rtnl_link_info_ops_lookup(kind);
|
2011-04-19 09:57:35 +02:00
|
|
|
link->l_info_ops = ops;
|
2011-11-11 14:56:16 +01:00
|
|
|
|
|
|
|
if (ops) {
|
|
|
|
if (ops->io_parse &&
|
|
|
|
(li[IFLA_INFO_DATA] || li[IFLA_INFO_XSTATS])) {
|
|
|
|
err = ops->io_parse(link, li[IFLA_INFO_DATA],
|
|
|
|
li[IFLA_INFO_XSTATS]);
|
|
|
|
if (err < 0)
|
|
|
|
goto errout;
|
|
|
|
} else {
|
|
|
|
/* XXX: Warn about unparsed info? */
|
|
|
|
}
|
2008-01-08 15:00:46 +01:00
|
|
|
}
|
|
|
|
}
|
2013-01-17 16:29:04 -08:00
|
|
|
link->ce_mask |= LINK_ATTR_LINKINFO;
|
2008-01-08 15:00:46 +01:00
|
|
|
}
|
|
|
|
|
2010-11-11 15:50:49 +01:00
|
|
|
if (tb[IFLA_PROTINFO] && af_ops && af_ops->ao_parse_protinfo) {
|
|
|
|
err = af_ops->ao_parse_protinfo(link, tb[IFLA_PROTINFO],
|
|
|
|
link->l_af_data[link->l_family]);
|
|
|
|
if (err < 0)
|
|
|
|
goto errout;
|
2013-01-17 16:29:04 -08:00
|
|
|
link->ce_mask |= LINK_ATTR_PROTINFO;
|
2010-11-11 15:50:49 +01:00
|
|
|
}
|
|
|
|
|
2010-11-13 01:38:13 +01:00
|
|
|
if (tb[IFLA_AF_SPEC]) {
|
|
|
|
struct nlattr *af_attr;
|
|
|
|
int remaining;
|
|
|
|
|
|
|
|
nla_for_each_nested(af_attr, tb[IFLA_AF_SPEC], remaining) {
|
|
|
|
af_ops = af_lookup_and_alloc(link, nla_type(af_attr));
|
|
|
|
if (af_ops && af_ops->ao_parse_af) {
|
|
|
|
char *af_data = link->l_af_data[nla_type(af_attr)];
|
|
|
|
|
|
|
|
err = af_ops->ao_parse_af(link, af_attr, af_data);
|
|
|
|
if (err < 0)
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2013-01-17 16:29:04 -08:00
|
|
|
link->ce_mask |= LINK_ATTR_AF_SPEC;
|
2010-11-13 01:38:13 +01:00
|
|
|
}
|
|
|
|
|
2012-10-09 18:15:50 +02:00
|
|
|
if (tb[IFLA_PROMISCUITY]) {
|
|
|
|
link->l_promiscuity = nla_get_u32(tb[IFLA_PROMISCUITY]);
|
2012-10-09 19:34:23 +02:00
|
|
|
link->ce_mask |= LINK_ATTR_PROMISCUITY;
|
2012-10-09 18:15:50 +02:00
|
|
|
}
|
|
|
|
|
2012-10-09 19:57:22 +02:00
|
|
|
if (tb[IFLA_NUM_TX_QUEUES]) {
|
|
|
|
link->l_num_tx_queues = nla_get_u32(tb[IFLA_NUM_TX_QUEUES]);
|
|
|
|
link->ce_mask |= LINK_ATTR_NUM_TX_QUEUES;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tb[IFLA_NUM_RX_QUEUES]) {
|
|
|
|
link->l_num_rx_queues = nla_get_u32(tb[IFLA_NUM_RX_QUEUES]);
|
|
|
|
link->ce_mask |= LINK_ATTR_NUM_RX_QUEUES;
|
2012-10-09 21:55:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (tb[IFLA_GROUP]) {
|
|
|
|
link->l_group = nla_get_u32(tb[IFLA_GROUP]);
|
|
|
|
link->ce_mask |= LINK_ATTR_GROUP;
|
|
|
|
}
|
2012-10-09 19:57:22 +02:00
|
|
|
|
2013-08-01 13:57:08 +02:00
|
|
|
if (tb[IFLA_PHYS_PORT_ID]) {
|
|
|
|
link->l_phys_port_id = nl_data_alloc_attr(tb[IFLA_PHYS_PORT_ID]);
|
|
|
|
if (link->l_phys_port_id == NULL) {
|
|
|
|
err = -NLE_NOMEM;
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
link->ce_mask |= LINK_ATTR_PHYS_PORT_ID;
|
|
|
|
}
|
|
|
|
|
2007-09-15 01:28:01 +02:00
|
|
|
err = pp->pp_cb((struct nl_object *) link, pp);
|
|
|
|
errout:
|
2010-11-11 15:50:49 +01:00
|
|
|
rtnl_link_af_ops_put(af_ops);
|
2007-09-15 01:28:01 +02:00
|
|
|
rtnl_link_put(link);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2008-05-15 13:26:32 +02:00
|
|
|
static int link_request_update(struct nl_cache *cache, struct nl_sock *sk)
|
2007-09-15 01:28:01 +02:00
|
|
|
{
|
2010-11-11 22:26:11 +01:00
|
|
|
int family = cache->c_iarg1;
|
|
|
|
|
|
|
|
return nl_rtgen_request(sk, RTM_GETLINK, family, NLM_F_DUMP);
|
2007-09-15 01:28:01 +02:00
|
|
|
}
|
|
|
|
|
2008-05-23 23:45:14 +02:00
|
|
|
static void link_dump_line(struct nl_object *obj, struct nl_dump_params *p)
|
2007-09-15 01:28:01 +02:00
|
|
|
{
|
|
|
|
char buf[128];
|
2012-11-16 01:11:55 +01:00
|
|
|
struct nl_cache *cache = obj->ce_cache;
|
2007-09-15 01:28:01 +02:00
|
|
|
struct rtnl_link *link = (struct rtnl_link *) obj;
|
2013-11-09 10:04:35 +01:00
|
|
|
int fetched_cache = 0;
|
|
|
|
|
|
|
|
if (!cache) {
|
|
|
|
cache = nl_cache_mngt_require_safe("route/link");
|
|
|
|
fetched_cache = 1;
|
|
|
|
}
|
2007-09-15 01:28:01 +02:00
|
|
|
|
2008-05-23 23:45:14 +02:00
|
|
|
nl_dump_line(p, "%s %s ", link->l_name,
|
|
|
|
nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
|
2007-12-19 22:03:44 +01:00
|
|
|
|
|
|
|
if (link->l_addr && !nl_addr_iszero(link->l_addr))
|
2008-05-23 23:45:14 +02:00
|
|
|
nl_dump(p, "%s ", nl_addr2str(link->l_addr, buf, sizeof(buf)));
|
2007-09-15 01:28:01 +02:00
|
|
|
|
|
|
|
if (link->ce_mask & LINK_ATTR_MASTER) {
|
2013-11-09 10:04:35 +01:00
|
|
|
if (cache) {
|
|
|
|
struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
|
|
|
|
nl_dump(p, "master %s ", master ? master->l_name : "inv");
|
|
|
|
if (master)
|
|
|
|
rtnl_link_put(master);
|
|
|
|
} else
|
|
|
|
nl_dump(p, "master %d ", link->l_master);
|
2007-09-15 01:28:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
rtnl_link_flags2str(link->l_flags, buf, sizeof(buf));
|
|
|
|
if (buf[0])
|
2008-05-23 23:45:14 +02:00
|
|
|
nl_dump(p, "<%s> ", buf);
|
2008-01-08 15:00:46 +01:00
|
|
|
|
|
|
|
if (link->ce_mask & LINK_ATTR_LINK) {
|
2013-11-09 10:04:35 +01:00
|
|
|
if (cache) {
|
|
|
|
struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
|
|
|
|
nl_dump(p, "slave-of %s ", ll ? ll->l_name : "NONE");
|
|
|
|
if (ll)
|
|
|
|
rtnl_link_put(ll);
|
|
|
|
} else
|
|
|
|
nl_dump(p, "slave-of %d ", link->l_link);
|
2008-01-08 15:00:46 +01:00
|
|
|
}
|
|
|
|
|
2012-10-09 21:55:31 +02:00
|
|
|
if (link->ce_mask & LINK_ATTR_GROUP)
|
|
|
|
nl_dump(p, "group %u ", link->l_group);
|
|
|
|
|
2008-05-23 23:45:14 +02:00
|
|
|
if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_LINE])
|
|
|
|
link->l_info_ops->io_dump[NL_DUMP_LINE](link, p);
|
2007-09-15 01:28:01 +02:00
|
|
|
|
2010-11-11 15:50:49 +01:00
|
|
|
do_foreach_af(link, af_dump_line, p);
|
|
|
|
|
2008-05-23 23:45:14 +02:00
|
|
|
nl_dump(p, "\n");
|
2013-11-09 10:04:35 +01:00
|
|
|
|
|
|
|
if (fetched_cache)
|
|
|
|
nl_cache_put(cache);
|
2007-09-15 01:28:01 +02:00
|
|
|
}
|
|
|
|
|
2008-05-23 23:45:14 +02:00
|
|
|
static void link_dump_details(struct nl_object *obj, struct nl_dump_params *p)
|
2007-09-15 01:28:01 +02:00
|
|
|
{
|
|
|
|
struct rtnl_link *link = (struct rtnl_link *) obj;
|
|
|
|
char buf[64];
|
|
|
|
|
2008-05-23 23:45:14 +02:00
|
|
|
link_dump_line(obj, p);
|
2007-09-15 01:28:01 +02:00
|
|
|
|
2008-05-23 23:45:14 +02:00
|
|
|
nl_dump_line(p, " mtu %u ", link->l_mtu);
|
|
|
|
nl_dump(p, "txqlen %u weight %u ", link->l_txqlen, link->l_weight);
|
2007-09-15 01:28:01 +02:00
|
|
|
|
|
|
|
if (link->ce_mask & LINK_ATTR_QDISC)
|
2008-05-23 23:45:14 +02:00
|
|
|
nl_dump(p, "qdisc %s ", link->l_qdisc);
|
2007-09-15 01:28:01 +02:00
|
|
|
|
|
|
|
if (link->ce_mask & LINK_ATTR_MAP && link->l_map.lm_irq)
|
2008-05-23 23:45:14 +02:00
|
|
|
nl_dump(p, "irq %u ", link->l_map.lm_irq);
|
2007-09-15 01:28:01 +02:00
|
|
|
|
|
|
|
if (link->ce_mask & LINK_ATTR_IFINDEX)
|
2008-05-23 23:45:14 +02:00
|
|
|
nl_dump(p, "index %u ", link->l_index);
|
2007-09-15 01:28:01 +02:00
|
|
|
|
2012-10-09 19:58:54 +02:00
|
|
|
if (link->ce_mask & LINK_ATTR_PROMISCUITY && link->l_promiscuity > 0)
|
2012-10-09 18:15:50 +02:00
|
|
|
nl_dump(p, "promisc-mode (%u users) ", link->l_promiscuity);
|
2007-12-19 22:03:44 +01:00
|
|
|
|
2008-05-23 23:45:14 +02:00
|
|
|
nl_dump(p, "\n");
|
2010-11-11 13:57:10 +01:00
|
|
|
|
|
|
|
if (link->ce_mask & LINK_ATTR_IFALIAS)
|
|
|
|
nl_dump_line(p, " alias %s\n", link->l_ifalias);
|
|
|
|
|
2008-05-23 23:45:14 +02:00
|
|
|
nl_dump_line(p, " ");
|
2007-12-19 22:03:44 +01:00
|
|
|
|
2012-10-09 19:57:22 +02:00
|
|
|
if (link->ce_mask & LINK_ATTR_NUM_TX_QUEUES)
|
|
|
|
nl_dump(p, "txq %u ", link->l_num_tx_queues);
|
|
|
|
|
|
|
|
if (link->ce_mask & LINK_ATTR_NUM_RX_QUEUES)
|
|
|
|
nl_dump(p, "rxq %u ", link->l_num_rx_queues);
|
|
|
|
|
2007-09-15 01:28:01 +02:00
|
|
|
if (link->ce_mask & LINK_ATTR_BRD)
|
2008-05-23 23:45:14 +02:00
|
|
|
nl_dump(p, "brd %s ", nl_addr2str(link->l_bcast, buf,
|
2007-09-15 01:28:01 +02:00
|
|
|
sizeof(buf)));
|
|
|
|
|
2007-12-19 22:03:44 +01:00
|
|
|
if ((link->ce_mask & LINK_ATTR_OPERSTATE) &&
|
|
|
|
link->l_operstate != IF_OPER_UNKNOWN) {
|
|
|
|
rtnl_link_operstate2str(link->l_operstate, buf, sizeof(buf));
|
2008-05-23 23:45:14 +02:00
|
|
|
nl_dump(p, "state %s ", buf);
|
2007-12-19 22:03:44 +01:00
|
|
|
}
|
|
|
|
|
2010-11-11 14:11:32 +01:00
|
|
|
if (link->ce_mask & LINK_ATTR_NUM_VF)
|
|
|
|
nl_dump(p, "num-vf %u ", link->l_num_vf);
|
|
|
|
|
2013-01-07 18:36:12 -02:00
|
|
|
nl_dump(p, "mode %s ",
|
2007-12-19 22:03:44 +01:00
|
|
|
rtnl_link_mode2str(link->l_linkmode, buf, sizeof(buf)));
|
2007-09-15 01:28:01 +02:00
|
|
|
|
2013-01-07 18:36:12 -02:00
|
|
|
nl_dump(p, "carrier %s",
|
|
|
|
rtnl_link_carrier2str(link->l_carrier, buf, sizeof(buf)));
|
|
|
|
|
|
|
|
nl_dump(p, "\n");
|
|
|
|
|
2008-05-23 23:45:14 +02:00
|
|
|
if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_DETAILS])
|
|
|
|
link->l_info_ops->io_dump[NL_DUMP_DETAILS](link, p);
|
2010-11-11 15:50:49 +01:00
|
|
|
|
|
|
|
do_foreach_af(link, af_dump_details, p);
|
2007-09-15 01:28:01 +02:00
|
|
|
}
|
|
|
|
|
2008-05-23 23:45:14 +02:00
|
|
|
static void link_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
|
2007-09-15 01:28:01 +02:00
|
|
|
{
|
|
|
|
struct rtnl_link *link = (struct rtnl_link *) obj;
|
|
|
|
char *unit, fmt[64];
|
|
|
|
float res;
|
|
|
|
|
2008-05-23 23:45:14 +02:00
|
|
|
link_dump_details(obj, p);
|
2007-09-15 01:28:01 +02:00
|
|
|
|
2008-05-23 23:45:14 +02:00
|
|
|
nl_dump_line(p, " Stats: bytes packets errors "
|
|
|
|
" dropped fifo-err compressed\n");
|
2007-09-15 01:28:01 +02:00
|
|
|
|
|
|
|
res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_RX_BYTES], &unit);
|
|
|
|
|
2012-08-29 23:59:17 +06:00
|
|
|
strcpy(fmt, " RX %X.2f %s %10" PRIu64 " %10" PRIu64 " %10" PRIu64 " %10" PRIu64 " %10" PRIu64 "\n");
|
2007-09-15 01:28:01 +02:00
|
|
|
fmt[9] = *unit == 'B' ? '9' : '7';
|
|
|
|
|
2008-05-23 23:45:14 +02:00
|
|
|
nl_dump_line(p, fmt, res, unit,
|
2007-09-15 01:28:01 +02:00
|
|
|
link->l_stats[RTNL_LINK_RX_PACKETS],
|
|
|
|
link->l_stats[RTNL_LINK_RX_ERRORS],
|
|
|
|
link->l_stats[RTNL_LINK_RX_DROPPED],
|
|
|
|
link->l_stats[RTNL_LINK_RX_FIFO_ERR],
|
|
|
|
link->l_stats[RTNL_LINK_RX_COMPRESSED]);
|
|
|
|
|
|
|
|
res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_TX_BYTES], &unit);
|
|
|
|
|
2012-08-29 23:59:17 +06:00
|
|
|
strcpy(fmt, " TX %X.2f %s %10" PRIu64 " %10" PRIu64 " %10" PRIu64 " %10" PRIu64 " %10" PRIu64 "\n");
|
2007-09-15 01:28:01 +02:00
|
|
|
fmt[9] = *unit == 'B' ? '9' : '7';
|
|
|
|
|
2008-05-23 23:45:14 +02:00
|
|
|
nl_dump_line(p, fmt, res, unit,
|
2007-09-15 01:28:01 +02:00
|
|
|
link->l_stats[RTNL_LINK_TX_PACKETS],
|
|
|
|
link->l_stats[RTNL_LINK_TX_ERRORS],
|
|
|
|
link->l_stats[RTNL_LINK_TX_DROPPED],
|
|
|
|
link->l_stats[RTNL_LINK_TX_FIFO_ERR],
|
|
|
|
link->l_stats[RTNL_LINK_TX_COMPRESSED]);
|
|
|
|
|
2008-05-23 23:45:14 +02:00
|
|
|
nl_dump_line(p, " Errors: length over crc "
|
|
|
|
" frame missed multicast\n");
|
2007-09-15 01:28:01 +02:00
|
|
|
|
2008-05-23 23:45:14 +02:00
|
|
|
nl_dump_line(p, " RX %10" PRIu64 " %10" PRIu64 " %10"
|
2007-09-15 01:28:01 +02:00
|
|
|
PRIu64 " %10" PRIu64 " %10" PRIu64 " %10"
|
|
|
|
PRIu64 "\n",
|
|
|
|
link->l_stats[RTNL_LINK_RX_LEN_ERR],
|
|
|
|
link->l_stats[RTNL_LINK_RX_OVER_ERR],
|
|
|
|
link->l_stats[RTNL_LINK_RX_CRC_ERR],
|
|
|
|
link->l_stats[RTNL_LINK_RX_FRAME_ERR],
|
|
|
|
link->l_stats[RTNL_LINK_RX_MISSED_ERR],
|
|
|
|
link->l_stats[RTNL_LINK_MULTICAST]);
|
|
|
|
|
2008-05-23 23:45:14 +02:00
|
|
|
nl_dump_line(p, " aborted carrier heartbeat "
|
|
|
|
" window collision\n");
|
2007-09-15 01:28:01 +02:00
|
|
|
|
2008-05-23 23:45:14 +02:00
|
|
|
nl_dump_line(p, " TX %10" PRIu64 " %10" PRIu64 " %10"
|
|
|
|
PRIu64 " %10" PRIu64 " %10" PRIu64 "\n",
|
2007-09-15 01:28:01 +02:00
|
|
|
link->l_stats[RTNL_LINK_TX_ABORT_ERR],
|
|
|
|
link->l_stats[RTNL_LINK_TX_CARRIER_ERR],
|
|
|
|
link->l_stats[RTNL_LINK_TX_HBEAT_ERR],
|
|
|
|
link->l_stats[RTNL_LINK_TX_WIN_ERR],
|
2010-10-29 01:58:27 +02:00
|
|
|
link->l_stats[RTNL_LINK_COLLISIONS]);
|
2007-09-15 01:28:01 +02:00
|
|
|
|
2008-01-08 15:00:46 +01:00
|
|
|
if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_STATS])
|
2008-05-23 23:45:14 +02:00
|
|
|
link->l_info_ops->io_dump[NL_DUMP_STATS](link, p);
|
2010-11-11 15:50:49 +01:00
|
|
|
|
|
|
|
do_foreach_af(link, af_dump_stats, p);
|
2007-09-15 01:28:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
static int link_handle_event(struct nl_object *a, struct rtnl_link_event_cb *cb)
|
|
|
|
{
|
|
|
|
struct rtnl_link *l = (struct rtnl_link *) a;
|
|
|
|
struct nl_cache *c = dp_cache(a);
|
|
|
|
int nevents = 0;
|
|
|
|
|
|
|
|
if (l->l_change == ~0U) {
|
|
|
|
if (l->ce_msgtype == RTM_NEWLINK)
|
|
|
|
cb->le_register(l);
|
|
|
|
else
|
|
|
|
cb->le_unregister(l);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (l->l_change & IFF_SLAVE) {
|
|
|
|
if (l->l_flags & IFF_SLAVE) {
|
|
|
|
struct rtnl_link *m = rtnl_link_get(c, l->l_master);
|
|
|
|
cb->le_new_bonding(l, m);
|
|
|
|
if (m)
|
|
|
|
rtnl_link_put(m);
|
|
|
|
} else
|
|
|
|
cb->le_cancel_bonding(l);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
if (l->l_change & IFF_UP && l->l_change & IFF_RUNNING)
|
|
|
|
dp_dump_line(p, line++, "link %s changed state to %s.\n",
|
|
|
|
l->l_name, l->l_flags & IFF_UP ? "up" : "down");
|
|
|
|
|
|
|
|
if (l->l_change & IFF_PROMISC) {
|
|
|
|
dp_new_line(p, line++);
|
|
|
|
dp_dump(p, "link %s %s promiscuous mode.\n",
|
|
|
|
l->l_name, l->l_flags & IFF_PROMISC ? "entered" : "left");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (line == 0)
|
|
|
|
dp_dump_line(p, line++, "link %s sent unknown event.\n",
|
|
|
|
l->l_name);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return nevents;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2012-11-09 14:41:34 -08:00
|
|
|
|
|
|
|
static void link_keygen(struct nl_object *obj, uint32_t *hashkey,
|
|
|
|
uint32_t table_sz)
|
|
|
|
{
|
|
|
|
struct rtnl_link *link = (struct rtnl_link *) obj;
|
|
|
|
unsigned int lkey_sz;
|
|
|
|
struct link_hash_key {
|
|
|
|
uint32_t l_index;
|
2012-11-14 06:06:41 -08:00
|
|
|
uint32_t l_family;
|
2012-11-09 14:41:34 -08:00
|
|
|
} __attribute__((packed)) lkey;
|
|
|
|
|
|
|
|
lkey_sz = sizeof(lkey);
|
|
|
|
lkey.l_index = link->l_index;
|
2012-11-14 06:06:41 -08:00
|
|
|
lkey.l_family = link->l_family;
|
2012-11-09 14:41:34 -08:00
|
|
|
|
|
|
|
*hashkey = nl_hash(&lkey, lkey_sz, 0) % table_sz;
|
|
|
|
|
2012-11-14 06:06:41 -08:00
|
|
|
NL_DBG(5, "link %p key (dev %d fam %d) keysz %d, hash 0x%x\n",
|
|
|
|
link, lkey.l_index, lkey.l_family, lkey_sz, *hashkey);
|
2012-11-09 14:41:34 -08:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-09-15 01:28:01 +02:00
|
|
|
static int link_compare(struct nl_object *_a, struct nl_object *_b,
|
|
|
|
uint32_t attrs, int flags)
|
|
|
|
{
|
|
|
|
struct rtnl_link *a = (struct rtnl_link *) _a;
|
|
|
|
struct rtnl_link *b = (struct rtnl_link *) _b;
|
|
|
|
int diff = 0;
|
|
|
|
|
|
|
|
#define LINK_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, LINK_ATTR_##ATTR, a, b, EXPR)
|
|
|
|
|
|
|
|
diff |= LINK_DIFF(IFINDEX, a->l_index != b->l_index);
|
|
|
|
diff |= LINK_DIFF(MTU, a->l_mtu != b->l_mtu);
|
|
|
|
diff |= LINK_DIFF(LINK, a->l_link != b->l_link);
|
|
|
|
diff |= LINK_DIFF(TXQLEN, a->l_txqlen != b->l_txqlen);
|
|
|
|
diff |= LINK_DIFF(WEIGHT, a->l_weight != b->l_weight);
|
|
|
|
diff |= LINK_DIFF(MASTER, a->l_master != b->l_master);
|
|
|
|
diff |= LINK_DIFF(FAMILY, a->l_family != b->l_family);
|
2007-12-19 22:03:44 +01:00
|
|
|
diff |= LINK_DIFF(OPERSTATE, a->l_operstate != b->l_operstate);
|
|
|
|
diff |= LINK_DIFF(LINKMODE, a->l_linkmode != b->l_linkmode);
|
2007-09-15 01:28:01 +02:00
|
|
|
diff |= LINK_DIFF(QDISC, strcmp(a->l_qdisc, b->l_qdisc));
|
|
|
|
diff |= LINK_DIFF(IFNAME, strcmp(a->l_name, b->l_name));
|
|
|
|
diff |= LINK_DIFF(ADDR, nl_addr_cmp(a->l_addr, b->l_addr));
|
|
|
|
diff |= LINK_DIFF(BRD, nl_addr_cmp(a->l_bcast, b->l_bcast));
|
2010-11-11 13:57:10 +01:00
|
|
|
diff |= LINK_DIFF(IFALIAS, strcmp(a->l_ifalias, b->l_ifalias));
|
2010-11-11 14:11:32 +01:00
|
|
|
diff |= LINK_DIFF(NUM_VF, a->l_num_vf != b->l_num_vf);
|
2012-10-09 18:15:50 +02:00
|
|
|
diff |= LINK_DIFF(PROMISCUITY, a->l_promiscuity != b->l_promiscuity);
|
2012-10-09 19:57:22 +02:00
|
|
|
diff |= LINK_DIFF(NUM_TX_QUEUES,a->l_num_tx_queues != b->l_num_tx_queues);
|
|
|
|
diff |= LINK_DIFF(NUM_RX_QUEUES,a->l_num_rx_queues != b->l_num_rx_queues);
|
2012-10-09 21:55:31 +02:00
|
|
|
diff |= LINK_DIFF(GROUP, a->l_group != b->l_group);
|
2007-09-15 01:28:01 +02:00
|
|
|
|
2013-02-15 10:26:29 -08:00
|
|
|
if (flags & LOOSE_COMPARISON)
|
|
|
|
diff |= LINK_DIFF(FLAGS,
|
|
|
|
(a->l_flags ^ b->l_flags) & b->l_flag_mask);
|
|
|
|
else
|
|
|
|
diff |= LINK_DIFF(FLAGS, a->l_flags != b->l_flags);
|
|
|
|
|
2013-01-17 16:29:04 -08:00
|
|
|
/*
|
|
|
|
* Compare LINK_ATTR_PROTINFO af_data
|
|
|
|
*/
|
|
|
|
if (a->l_family == b->l_family) {
|
|
|
|
if (rtnl_link_af_data_compare(a, b, a->l_family) != 0)
|
|
|
|
goto protinfo_mismatch;
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
2007-09-15 01:28:01 +02:00
|
|
|
return diff;
|
2013-01-17 16:29:04 -08:00
|
|
|
|
|
|
|
protinfo_mismatch:
|
|
|
|
diff |= LINK_DIFF(PROTINFO, 1);
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
#undef LINK_DIFF
|
2007-09-15 01:28:01 +02:00
|
|
|
}
|
|
|
|
|
2010-11-17 16:09:08 +01:00
|
|
|
static const struct trans_tbl link_attrs[] = {
|
2014-07-26 15:06:59 +02:00
|
|
|
__ADD(LINK_ATTR_MTU, mtu),
|
|
|
|
__ADD(LINK_ATTR_LINK, link),
|
|
|
|
__ADD(LINK_ATTR_TXQLEN, txqlen),
|
|
|
|
__ADD(LINK_ATTR_WEIGHT, weight),
|
|
|
|
__ADD(LINK_ATTR_MASTER, master),
|
|
|
|
__ADD(LINK_ATTR_QDISC, qdisc),
|
|
|
|
__ADD(LINK_ATTR_MAP, map),
|
|
|
|
__ADD(LINK_ATTR_ADDR, address),
|
|
|
|
__ADD(LINK_ATTR_BRD, broadcast),
|
|
|
|
__ADD(LINK_ATTR_FLAGS, flags),
|
|
|
|
__ADD(LINK_ATTR_IFNAME, name),
|
|
|
|
__ADD(LINK_ATTR_IFINDEX, ifindex),
|
|
|
|
__ADD(LINK_ATTR_FAMILY, family),
|
|
|
|
__ADD(LINK_ATTR_ARPTYPE, arptype),
|
|
|
|
__ADD(LINK_ATTR_STATS, stats),
|
|
|
|
__ADD(LINK_ATTR_CHANGE, change),
|
|
|
|
__ADD(LINK_ATTR_OPERSTATE, operstate),
|
|
|
|
__ADD(LINK_ATTR_LINKMODE, linkmode),
|
|
|
|
__ADD(LINK_ATTR_IFALIAS, ifalias),
|
|
|
|
__ADD(LINK_ATTR_NUM_VF, num_vf),
|
|
|
|
__ADD(LINK_ATTR_PROMISCUITY, promiscuity),
|
|
|
|
__ADD(LINK_ATTR_NUM_TX_QUEUES, num_tx_queues),
|
|
|
|
__ADD(LINK_ATTR_NUM_RX_QUEUES, num_rx_queues),
|
|
|
|
__ADD(LINK_ATTR_GROUP, group),
|
|
|
|
__ADD(LINK_ATTR_CARRIER, carrier),
|
|
|
|
__ADD(LINK_ATTR_PHYS_PORT_ID, phys_port_id),
|
2007-09-15 01:28:01 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static char *link_attrs2str(int attrs, char *buf, size_t len)
|
|
|
|
{
|
|
|
|
return __flags2str(attrs, buf, len, link_attrs,
|
|
|
|
ARRAY_SIZE(link_attrs));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2011-07-28 16:23:57 +02:00
|
|
|
* @name Get / List
|
2007-09-15 01:28:01 +02:00
|
|
|
* @{
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Allocate link cache and fill in all configured links.
|
2008-05-15 13:26:32 +02:00
|
|
|
* @arg sk Netlink socket.
|
2010-11-11 22:26:11 +01:00
|
|
|
* @arg family Link address family or AF_UNSPEC
|
2008-05-14 17:49:44 +02:00
|
|
|
* @arg result Pointer to store resulting cache.
|
2007-09-15 01:28:01 +02:00
|
|
|
*
|
2014-03-20 10:45:45 -07:00
|
|
|
* Allocates and initializes a new link cache. If \c sk is valid, a netlink
|
|
|
|
* message is sent to the kernel requesting a full dump of all configured
|
|
|
|
* links. The returned messages are parsed and filled into the cache. If
|
|
|
|
* the operation succeeds, the resulting cache will contain a link object for
|
|
|
|
* each link configured in the kernel. If \c sk is NULL, returns 0 but the
|
|
|
|
* cache is still empty.
|
2011-07-28 16:23:57 +02:00
|
|
|
*
|
|
|
|
* If \c family is set to an address family other than \c AF_UNSPEC the
|
|
|
|
* contents of the cache can be limited to a specific address family.
|
|
|
|
* Currently the following address families are supported:
|
|
|
|
* - AF_BRIDGE
|
|
|
|
* - AF_INET6
|
|
|
|
*
|
|
|
|
* @route_doc{link_list, Get List of Links}
|
|
|
|
* @see rtnl_link_get()
|
|
|
|
* @see rtnl_link_get_by_name()
|
2008-05-14 17:49:44 +02:00
|
|
|
* @return 0 on success or a negative error code.
|
2007-09-15 01:28:01 +02:00
|
|
|
*/
|
2010-11-11 22:26:11 +01:00
|
|
|
int rtnl_link_alloc_cache(struct nl_sock *sk, int family, struct nl_cache **result)
|
2007-09-15 01:28:01 +02:00
|
|
|
{
|
2010-11-11 22:26:11 +01:00
|
|
|
struct nl_cache * cache;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
cache = nl_cache_alloc(&rtnl_link_ops);
|
|
|
|
if (!cache)
|
|
|
|
return -NLE_NOMEM;
|
|
|
|
|
|
|
|
cache->c_iarg1 = family;
|
|
|
|
|
|
|
|
if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
|
|
|
|
nl_cache_free(cache);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
*result = cache;
|
|
|
|
return 0;
|
2007-09-15 01:28:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2011-07-28 16:23:57 +02:00
|
|
|
* Lookup link in cache by interface index
|
|
|
|
* @arg cache Link cache
|
|
|
|
* @arg ifindex Interface index
|
|
|
|
*
|
|
|
|
* Searches through the provided cache looking for a link with matching
|
|
|
|
* interface index.
|
2007-09-15 01:28:01 +02:00
|
|
|
*
|
2011-07-28 16:23:57 +02:00
|
|
|
* @attention The reference counter of the returned link object will be
|
|
|
|
* incremented. Use rtnl_link_put() to release the reference.
|
2007-09-15 01:28:01 +02:00
|
|
|
*
|
2011-07-28 16:23:57 +02:00
|
|
|
* @route_doc{link_list, Get List of Links}
|
|
|
|
* @see rtnl_link_get_by_name()
|
|
|
|
* @return Link object or NULL if no match was found.
|
2007-09-15 01:28:01 +02:00
|
|
|
*/
|
|
|
|
struct rtnl_link *rtnl_link_get(struct nl_cache *cache, int ifindex)
|
|
|
|
{
|
|
|
|
struct rtnl_link *link;
|
|
|
|
|
|
|
|
if (cache->c_ops != &rtnl_link_ops)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
nl_list_for_each_entry(link, &cache->c_items, ce_list) {
|
2013-01-28 07:46:16 -08:00
|
|
|
if (link->l_index == ifindex) {
|
2007-09-15 01:28:01 +02:00
|
|
|
nl_object_get((struct nl_object *) link);
|
|
|
|
return link;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2011-07-28 16:23:57 +02:00
|
|
|
* Lookup link in cache by link name
|
|
|
|
* @arg cache Link cache
|
|
|
|
* @arg name Name of link
|
|
|
|
*
|
|
|
|
* Searches through the provided cache looking for a link with matching
|
|
|
|
* link name
|
2007-09-15 01:28:01 +02:00
|
|
|
*
|
2011-07-28 16:23:57 +02:00
|
|
|
* @attention The reference counter of the returned link object will be
|
|
|
|
* incremented. Use rtnl_link_put() to release the reference.
|
2007-09-15 01:28:01 +02:00
|
|
|
*
|
2011-07-28 16:23:57 +02:00
|
|
|
* @route_doc{link_list, Get List of Links}
|
|
|
|
* @see rtnl_link_get()
|
|
|
|
* @return Link object or NULL if no match was found.
|
2007-09-15 01:28:01 +02:00
|
|
|
*/
|
|
|
|
struct rtnl_link *rtnl_link_get_by_name(struct nl_cache *cache,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
struct rtnl_link *link;
|
|
|
|
|
|
|
|
if (cache->c_ops != &rtnl_link_ops)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
nl_list_for_each_entry(link, &cache->c_items, ce_list) {
|
2013-01-28 07:46:16 -08:00
|
|
|
if (!strcmp(name, link->l_name)) {
|
2007-09-15 01:28:01 +02:00
|
|
|
nl_object_get((struct nl_object *) link);
|
|
|
|
return link;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
/**
|
|
|
|
* Construct RTM_GETLINK netlink message
|
|
|
|
* @arg ifindex Interface index
|
|
|
|
* @arg name Name of link
|
|
|
|
* @arg result Pointer to store resulting netlink message
|
|
|
|
*
|
|
|
|
* The behaviour of this function is identical to rtnl_link_get_kernel()
|
|
|
|
* with the exception that it will not send the message but return it in
|
|
|
|
* the provided return pointer instead.
|
|
|
|
*
|
|
|
|
* @see rtnl_link_get_kernel()
|
|
|
|
*
|
|
|
|
* @return 0 on success or a negative error code.
|
|
|
|
*/
|
|
|
|
int rtnl_link_build_get_request(int ifindex, const char *name,
|
|
|
|
struct nl_msg **result)
|
|
|
|
{
|
|
|
|
struct ifinfomsg ifi;
|
|
|
|
struct nl_msg *msg;
|
|
|
|
|
|
|
|
if (ifindex <= 0 && !name) {
|
|
|
|
APPBUG("ifindex or name must be specified");
|
|
|
|
return -NLE_MISSING_ATTR;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&ifi, 0, sizeof(ifi));
|
|
|
|
|
|
|
|
if (!(msg = nlmsg_alloc_simple(RTM_GETLINK, 0)))
|
|
|
|
return -NLE_NOMEM;
|
|
|
|
|
|
|
|
if (ifindex > 0)
|
|
|
|
ifi.ifi_index = ifindex;
|
|
|
|
|
|
|
|
if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
if (name)
|
|
|
|
NLA_PUT_STRING(msg, IFLA_IFNAME, name);
|
|
|
|
|
|
|
|
*result = msg;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return -NLE_MSGSIZE;
|
|
|
|
}
|
2007-09-15 01:28:01 +02:00
|
|
|
|
|
|
|
/**
|
2011-07-28 16:23:57 +02:00
|
|
|
* Get a link object directly from kernel
|
|
|
|
* @arg sk Netlink socket
|
|
|
|
* @arg ifindex Interface index
|
|
|
|
* @arg name Name of link
|
|
|
|
* @arg result Pointer to store resulting link object
|
|
|
|
*
|
|
|
|
* This function builds a \c RTM_GETLINK netlink message to request
|
|
|
|
* a specific link directly from the kernel. The returned answer is
|
|
|
|
* parsed into a struct rtnl_link object and returned via the result
|
|
|
|
* pointer or -NLE_OBJ_NOTFOUND is returned if no matching link was
|
|
|
|
* found.
|
|
|
|
*
|
2014-11-26 18:17:16 +01:00
|
|
|
* Older kernels do not support lookup by name. In that case, libnl
|
|
|
|
* will fail with -NLE_OPNOTSUPP. Note that previous version of libnl
|
|
|
|
* failed in this case with -NLE_INVAL. You can check libnl behavior
|
|
|
|
* using NL_CAPABILITY_ROUTE_LINK_GET_KERNEL_FAIL_OPNOTSUPP capability.
|
|
|
|
*
|
2011-07-28 16:23:57 +02:00
|
|
|
* @route_doc{link_direct_lookup, Lookup Single Link (Direct Lookup)}
|
|
|
|
* @return 0 on success or a negative error code.
|
|
|
|
*/
|
|
|
|
int rtnl_link_get_kernel(struct nl_sock *sk, int ifindex, const char *name,
|
|
|
|
struct rtnl_link **result)
|
|
|
|
{
|
|
|
|
struct nl_msg *msg = NULL;
|
|
|
|
struct nl_object *obj;
|
|
|
|
int err;
|
2014-11-26 18:17:16 +01:00
|
|
|
int syserr;
|
2011-07-28 16:23:57 +02:00
|
|
|
|
|
|
|
if ((err = rtnl_link_build_get_request(ifindex, name, &msg)) < 0)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = nl_send_auto(sk, msg);
|
|
|
|
nlmsg_free(msg);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
2014-11-26 18:17:16 +01:00
|
|
|
if ((err = nl_pickup_keep_syserr(sk, link_msg_parser, &obj, &syserr)) < 0) {
|
|
|
|
if (syserr == -EINVAL &&
|
|
|
|
ifindex <= 0 &&
|
|
|
|
name && *name) {
|
|
|
|
/* Older kernels do not support lookup by ifname. This was added
|
|
|
|
* by commit kernel a3d1289126e7b14307074b76bf1677015ea5036f .
|
|
|
|
* Detect this error case and return NLE_OPNOTSUPP instead of
|
|
|
|
* NLE_INVAL. */
|
|
|
|
return -NLE_OPNOTSUPP;
|
|
|
|
}
|
2011-07-28 16:23:57 +02:00
|
|
|
return err;
|
2014-11-26 18:17:16 +01:00
|
|
|
}
|
2011-07-28 16:23:57 +02:00
|
|
|
|
|
|
|
/* We have used link_msg_parser(), object is definitely a link */
|
|
|
|
*result = (struct rtnl_link *) obj;
|
|
|
|
|
2011-09-14 11:43:10 +02:00
|
|
|
/* If an object has been returned, we also need to wait for the ACK */
|
|
|
|
if (err == 0 && obj)
|
2012-06-13 13:24:19 +02:00
|
|
|
wait_for_ack(sk);
|
2011-09-14 11:43:10 +02:00
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Translate interface index to corresponding link name
|
|
|
|
* @arg cache Link cache
|
|
|
|
* @arg ifindex Interface index
|
|
|
|
* @arg dst String to store name
|
|
|
|
* @arg len Length of destination string
|
|
|
|
*
|
|
|
|
* Translates the specified interface index to the corresponding
|
|
|
|
* link name and stores the name in the destination string.
|
|
|
|
*
|
|
|
|
* @route_doc{link_translate_ifindex, Translating interface index to link name}
|
|
|
|
* @see rtnl_link_name2i()
|
|
|
|
* @return Name of link or NULL if no match was found.
|
|
|
|
*/
|
|
|
|
char * rtnl_link_i2name(struct nl_cache *cache, int ifindex, char *dst,
|
|
|
|
size_t len)
|
|
|
|
{
|
|
|
|
struct rtnl_link *link = rtnl_link_get(cache, ifindex);
|
|
|
|
|
|
|
|
if (link) {
|
|
|
|
strncpy(dst, link->l_name, len - 1);
|
|
|
|
rtnl_link_put(link);
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Translate link name to corresponding interface index
|
|
|
|
* @arg cache Link cache
|
|
|
|
* @arg name Name of link
|
|
|
|
*
|
|
|
|
* @route_doc{link_translate_ifindex, Translating interface index to link name}
|
|
|
|
* @see rtnl_link_i2name()
|
|
|
|
* @return Interface index or 0 if no match was found.
|
2007-09-15 01:28:01 +02:00
|
|
|
*/
|
2011-07-28 16:23:57 +02:00
|
|
|
int rtnl_link_name2i(struct nl_cache *cache, const char *name)
|
|
|
|
{
|
|
|
|
int ifindex = 0;
|
|
|
|
struct rtnl_link *link;
|
|
|
|
|
|
|
|
link = rtnl_link_get_by_name(cache, name);
|
|
|
|
if (link) {
|
|
|
|
ifindex = link->l_index;
|
|
|
|
rtnl_link_put(link);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ifindex;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @} */
|
2007-09-15 01:28:01 +02:00
|
|
|
|
2013-11-01 16:58:46 -07:00
|
|
|
int rtnl_link_fill_info(struct nl_msg *msg, struct rtnl_link *link)
|
2007-09-15 01:28:01 +02:00
|
|
|
{
|
2011-04-13 16:42:34 +02:00
|
|
|
if (link->ce_mask & LINK_ATTR_ADDR)
|
|
|
|
NLA_PUT_ADDR(msg, IFLA_ADDRESS, link->l_addr);
|
2007-09-15 01:28:01 +02:00
|
|
|
|
2011-04-13 16:42:34 +02:00
|
|
|
if (link->ce_mask & LINK_ATTR_BRD)
|
|
|
|
NLA_PUT_ADDR(msg, IFLA_BROADCAST, link->l_bcast);
|
2007-09-15 01:28:01 +02:00
|
|
|
|
2011-04-13 16:42:34 +02:00
|
|
|
if (link->ce_mask & LINK_ATTR_MTU)
|
|
|
|
NLA_PUT_U32(msg, IFLA_MTU, link->l_mtu);
|
2007-09-15 01:28:01 +02:00
|
|
|
|
2011-04-13 16:42:34 +02:00
|
|
|
if (link->ce_mask & LINK_ATTR_TXQLEN)
|
|
|
|
NLA_PUT_U32(msg, IFLA_TXQLEN, link->l_txqlen);
|
2007-09-15 01:28:01 +02:00
|
|
|
|
2011-04-13 16:42:34 +02:00
|
|
|
if (link->ce_mask & LINK_ATTR_WEIGHT)
|
|
|
|
NLA_PUT_U32(msg, IFLA_WEIGHT, link->l_weight);
|
2007-09-15 01:28:01 +02:00
|
|
|
|
2011-04-13 16:42:34 +02:00
|
|
|
if (link->ce_mask & LINK_ATTR_IFNAME)
|
|
|
|
NLA_PUT_STRING(msg, IFLA_IFNAME, link->l_name);
|
2007-09-15 01:28:01 +02:00
|
|
|
|
2011-04-13 16:42:34 +02:00
|
|
|
if (link->ce_mask & LINK_ATTR_OPERSTATE)
|
|
|
|
NLA_PUT_U8(msg, IFLA_OPERSTATE, link->l_operstate);
|
2007-12-19 22:03:44 +01:00
|
|
|
|
2013-01-07 18:36:12 -02:00
|
|
|
if (link->ce_mask & LINK_ATTR_CARRIER)
|
|
|
|
NLA_PUT_U8(msg, IFLA_CARRIER, link->l_carrier);
|
|
|
|
|
2011-04-13 16:42:34 +02:00
|
|
|
if (link->ce_mask & LINK_ATTR_LINKMODE)
|
|
|
|
NLA_PUT_U8(msg, IFLA_LINKMODE, link->l_linkmode);
|
2007-12-19 22:03:44 +01:00
|
|
|
|
2011-04-13 16:42:34 +02:00
|
|
|
if (link->ce_mask & LINK_ATTR_IFALIAS)
|
|
|
|
NLA_PUT_STRING(msg, IFLA_IFALIAS, link->l_ifalias);
|
2010-11-11 13:57:10 +01:00
|
|
|
|
2011-07-21 12:27:52 +02:00
|
|
|
if (link->ce_mask & LINK_ATTR_LINK)
|
|
|
|
NLA_PUT_U32(msg, IFLA_LINK, link->l_link);
|
|
|
|
|
2011-11-07 14:35:13 +01:00
|
|
|
if (link->ce_mask & LINK_ATTR_MASTER)
|
|
|
|
NLA_PUT_U32(msg, IFLA_MASTER, link->l_master);
|
|
|
|
|
2012-10-09 21:24:35 +02:00
|
|
|
if (link->ce_mask & LINK_ATTR_NUM_TX_QUEUES)
|
|
|
|
NLA_PUT_U32(msg, IFLA_NUM_TX_QUEUES, link->l_num_tx_queues);
|
|
|
|
|
|
|
|
if (link->ce_mask & LINK_ATTR_NUM_RX_QUEUES)
|
|
|
|
NLA_PUT_U32(msg, IFLA_NUM_RX_QUEUES, link->l_num_rx_queues);
|
|
|
|
|
2013-12-03 20:16:09 -08:00
|
|
|
if (link->ce_mask & LINK_ATTR_NS_FD)
|
|
|
|
NLA_PUT_U32(msg, IFLA_NET_NS_FD, link->l_ns_fd);
|
|
|
|
|
|
|
|
if (link->ce_mask & LINK_ATTR_NS_PID)
|
|
|
|
NLA_PUT_U32(msg, IFLA_NET_NS_PID, link->l_ns_pid);
|
2012-10-09 21:55:31 +02:00
|
|
|
|
2013-11-01 16:58:46 -07:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
return -NLE_MSGSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int build_link_msg(int cmd, struct ifinfomsg *hdr,
|
|
|
|
struct rtnl_link *link, int flags, struct nl_msg **result)
|
|
|
|
{
|
|
|
|
struct nl_msg *msg;
|
|
|
|
struct nlattr *af_spec;
|
|
|
|
|
|
|
|
msg = nlmsg_alloc_simple(cmd, flags);
|
|
|
|
if (!msg)
|
|
|
|
return -NLE_NOMEM;
|
|
|
|
|
|
|
|
if (nlmsg_append(msg, hdr, sizeof(*hdr), NLMSG_ALIGNTO) < 0)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
if (rtnl_link_fill_info(msg, link))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
2013-12-03 20:16:09 -08:00
|
|
|
if (link->ce_mask & LINK_ATTR_GROUP)
|
|
|
|
NLA_PUT_U32(msg, IFLA_GROUP, link->l_group);
|
|
|
|
|
2011-11-11 14:56:16 +01:00
|
|
|
if (link->ce_mask & LINK_ATTR_LINKINFO) {
|
2008-01-08 15:00:46 +01:00
|
|
|
struct nlattr *info;
|
|
|
|
|
|
|
|
if (!(info = nla_nest_start(msg, IFLA_LINKINFO)))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
2011-11-11 14:56:16 +01:00
|
|
|
NLA_PUT_STRING(msg, IFLA_INFO_KIND, link->l_info_kind);
|
2008-01-08 15:00:46 +01:00
|
|
|
|
2011-11-11 14:56:16 +01:00
|
|
|
if (link->l_info_ops) {
|
|
|
|
if (link->l_info_ops->io_put_attrs &&
|
|
|
|
link->l_info_ops->io_put_attrs(msg, link) < 0)
|
|
|
|
goto nla_put_failure;
|
|
|
|
}
|
2008-01-08 15:00:46 +01:00
|
|
|
|
|
|
|
nla_nest_end(msg, info);
|
|
|
|
}
|
|
|
|
|
2010-11-16 13:54:15 +01:00
|
|
|
if (!(af_spec = nla_nest_start(msg, IFLA_AF_SPEC)))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
2011-04-13 16:42:34 +02:00
|
|
|
if (do_foreach_af(link, af_fill, msg) < 0)
|
2010-11-16 12:41:43 +01:00
|
|
|
goto nla_put_failure;
|
|
|
|
|
2010-11-16 13:54:15 +01:00
|
|
|
nla_nest_end(msg, af_spec);
|
|
|
|
|
2008-05-14 17:49:44 +02:00
|
|
|
*result = msg;
|
|
|
|
return 0;
|
2007-09-15 01:28:01 +02:00
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
nlmsg_free(msg);
|
2008-05-14 17:49:44 +02:00
|
|
|
return -NLE_MSGSIZE;
|
2007-09-15 01:28:01 +02:00
|
|
|
}
|
|
|
|
|
2011-04-15 15:30:46 +02:00
|
|
|
/**
|
2011-07-28 16:23:57 +02:00
|
|
|
* @name Add / Modify
|
|
|
|
* @{
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Build a netlink message requesting the addition of new virtual link
|
2011-04-15 15:30:46 +02:00
|
|
|
* @arg link new link to add
|
|
|
|
* @arg flags additional netlink message flags
|
|
|
|
* @arg result pointer to store resulting netlink message
|
|
|
|
*
|
|
|
|
* The behaviour of this function is identical to rtnl_link_add() with
|
|
|
|
* the exception that it will not send the message but return it in the
|
|
|
|
* provided return pointer instead.
|
|
|
|
*
|
|
|
|
* @see rtnl_link_add()
|
|
|
|
*
|
|
|
|
* @note This operation is not supported on all kernel versions.
|
|
|
|
*
|
|
|
|
* @return 0 on success or a negative error code.
|
|
|
|
*/
|
|
|
|
int rtnl_link_build_add_request(struct rtnl_link *link, int flags,
|
|
|
|
struct nl_msg **result)
|
|
|
|
{
|
|
|
|
struct ifinfomsg ifi = {
|
|
|
|
.ifi_family = link->l_family,
|
|
|
|
.ifi_index = link->l_index,
|
|
|
|
.ifi_flags = link->l_flags,
|
|
|
|
};
|
|
|
|
|
|
|
|
return build_link_msg(RTM_NEWLINK, &ifi, link, flags, result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add virtual link
|
|
|
|
* @arg sk netlink socket.
|
|
|
|
* @arg link new link to add
|
|
|
|
* @arg flags additional netlink message flags
|
|
|
|
*
|
|
|
|
* Builds a \c RTM_NEWLINK netlink message requesting the addition of
|
|
|
|
* a new virtual link.
|
|
|
|
*
|
|
|
|
* After sending, the function will wait for the ACK or an eventual
|
|
|
|
* error message to be received and will therefore block until the
|
|
|
|
* operation has been completed.
|
|
|
|
*
|
2011-07-28 16:23:57 +02:00
|
|
|
* @copydoc auto_ack_warning
|
2011-04-15 15:30:46 +02:00
|
|
|
*
|
|
|
|
* @return 0 on success or a negative error code.
|
|
|
|
*/
|
|
|
|
int rtnl_link_add(struct nl_sock *sk, struct rtnl_link *link, int flags)
|
|
|
|
{
|
|
|
|
struct nl_msg *msg;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = rtnl_link_build_add_request(link, flags, &msg);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
return nl_send_sync(sk, msg);
|
2011-04-15 15:30:46 +02:00
|
|
|
}
|
|
|
|
|
2007-09-15 01:28:01 +02:00
|
|
|
/**
|
2011-07-28 16:23:57 +02:00
|
|
|
* Build a netlink message requesting the modification of link
|
2011-04-13 16:42:34 +02:00
|
|
|
* @arg orig original link to change
|
|
|
|
* @arg changes link containing the changes to be made
|
|
|
|
* @arg flags additional netlink message flags
|
|
|
|
* @arg result pointer to store resulting netlink message
|
|
|
|
*
|
|
|
|
* The behaviour of this function is identical to rtnl_link_change() with
|
|
|
|
* the exception that it will not send the message but return it in the
|
|
|
|
* provided return pointer instead.
|
|
|
|
*
|
|
|
|
* @see rtnl_link_change()
|
|
|
|
*
|
|
|
|
* @note The resulting message will have message type set to RTM_NEWLINK
|
|
|
|
* which may not work with older kernels. You may have to modify it
|
|
|
|
* to RTM_SETLINK (does not allow changing link info attributes) to
|
|
|
|
* have the change request work with older kernels.
|
|
|
|
*
|
|
|
|
* @return 0 on success or a negative error code.
|
|
|
|
*/
|
|
|
|
int rtnl_link_build_change_request(struct rtnl_link *orig,
|
|
|
|
struct rtnl_link *changes, int flags,
|
|
|
|
struct nl_msg **result)
|
|
|
|
{
|
|
|
|
struct ifinfomsg ifi = {
|
|
|
|
.ifi_family = orig->l_family,
|
|
|
|
.ifi_index = orig->l_index,
|
|
|
|
};
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (changes->ce_mask & LINK_ATTR_FLAGS) {
|
|
|
|
ifi.ifi_flags = orig->l_flags & ~changes->l_flag_mask;
|
|
|
|
ifi.ifi_flags |= changes->l_flags;
|
2015-07-09 17:40:18 +12:00
|
|
|
ifi.ifi_change = changes->l_flag_mask;
|
2011-04-13 16:42:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (changes->l_family && changes->l_family != orig->l_family) {
|
|
|
|
APPBUG("link change: family is immutable");
|
|
|
|
return -NLE_IMMUTABLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Avoid unnecessary name change requests */
|
|
|
|
if (orig->ce_mask & LINK_ATTR_IFINDEX &&
|
|
|
|
orig->ce_mask & LINK_ATTR_IFNAME &&
|
|
|
|
changes->ce_mask & LINK_ATTR_IFNAME &&
|
|
|
|
!strcmp(orig->l_name, changes->l_name))
|
|
|
|
changes->ce_mask &= ~LINK_ATTR_IFNAME;
|
|
|
|
|
|
|
|
if ((err = build_link_msg(RTM_NEWLINK, &ifi, changes, flags, result)) < 0)
|
|
|
|
goto errout;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
errout:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Change link
|
|
|
|
* @arg sk netlink socket.
|
|
|
|
* @arg orig original link to be changed
|
|
|
|
* @arg changes link containing the changes to be made
|
2007-09-15 01:28:01 +02:00
|
|
|
* @arg flags additional netlink message flags
|
|
|
|
*
|
2011-04-13 16:42:34 +02:00
|
|
|
* Builds a \c RTM_NEWLINK netlink message requesting the change of
|
|
|
|
* a network link. If -EOPNOTSUPP is returned by the kernel, the
|
|
|
|
* message type will be changed to \c RTM_SETLINK and the message is
|
|
|
|
* resent to work around older kernel versions.
|
|
|
|
*
|
|
|
|
* The link to be changed is looked up based on the interface index
|
|
|
|
* supplied in the \p orig link. Optionaly the link name is used but
|
|
|
|
* only if no interface index is provided, otherwise providing an
|
|
|
|
* link name will result in the link name being changed.
|
|
|
|
*
|
|
|
|
* If no matching link exists, the function will return
|
|
|
|
* -NLE_OBJ_NOTFOUND.
|
2007-09-15 01:28:01 +02:00
|
|
|
*
|
2011-04-13 16:42:34 +02:00
|
|
|
* After sending, the function will wait for the ACK or an eventual
|
|
|
|
* error message to be received and will therefore block until the
|
|
|
|
* operation has been completed.
|
|
|
|
*
|
2011-07-28 16:23:57 +02:00
|
|
|
* @copydoc auto_ack_warning
|
2011-04-13 16:42:34 +02:00
|
|
|
*
|
|
|
|
* @note The link name can only be changed if the link has been put
|
|
|
|
* in opertional down state. (~IF_UP)
|
|
|
|
*
|
|
|
|
* @return 0 on success or a negative error code.
|
2007-09-15 01:28:01 +02:00
|
|
|
*/
|
2011-04-13 16:42:34 +02:00
|
|
|
int rtnl_link_change(struct nl_sock *sk, struct rtnl_link *orig,
|
|
|
|
struct rtnl_link *changes, int flags)
|
2007-09-15 01:28:01 +02:00
|
|
|
{
|
|
|
|
struct nl_msg *msg;
|
2008-05-14 17:49:44 +02:00
|
|
|
int err;
|
2007-09-15 01:28:01 +02:00
|
|
|
|
2011-04-13 16:42:34 +02:00
|
|
|
err = rtnl_link_build_change_request(orig, changes, flags, &msg);
|
|
|
|
if (err < 0)
|
2008-05-14 17:49:44 +02:00
|
|
|
return err;
|
2011-04-13 16:42:34 +02:00
|
|
|
|
|
|
|
retry:
|
2008-05-15 13:45:41 +02:00
|
|
|
err = nl_send_auto_complete(sk, msg);
|
|
|
|
if (err < 0)
|
2011-04-13 16:42:34 +02:00
|
|
|
goto errout;
|
|
|
|
|
|
|
|
err = wait_for_ack(sk);
|
|
|
|
if (err == -NLE_OPNOTSUPP && msg->nm_nlh->nlmsg_type == RTM_NEWLINK) {
|
|
|
|
msg->nm_nlh->nlmsg_type = RTM_SETLINK;
|
|
|
|
goto retry;
|
|
|
|
}
|
2007-09-15 01:28:01 +02:00
|
|
|
|
2011-04-13 16:42:34 +02:00
|
|
|
errout:
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return err;
|
2007-09-15 01:28:01 +02:00
|
|
|
}
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
/** @} */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @name Delete
|
|
|
|
* @{
|
|
|
|
*/
|
|
|
|
|
2011-04-10 11:02:47 +02:00
|
|
|
/**
|
|
|
|
* Build a netlink message requesting the deletion of a link
|
|
|
|
* @arg link Link to delete
|
|
|
|
* @arg result Pointer to store resulting netlink message
|
|
|
|
*
|
|
|
|
* The behaviour of this function is identical to rtnl_link_delete() with
|
|
|
|
* the exception that it will not send the message but return it in the
|
|
|
|
* provided return pointer instead.
|
|
|
|
*
|
|
|
|
* @see rtnl_link_delete()
|
|
|
|
*
|
|
|
|
* @return 0 on success or a negative error code.
|
|
|
|
*/
|
|
|
|
int rtnl_link_build_delete_request(const struct rtnl_link *link,
|
|
|
|
struct nl_msg **result)
|
|
|
|
{
|
|
|
|
struct nl_msg *msg;
|
|
|
|
struct ifinfomsg ifi = {
|
|
|
|
.ifi_index = link->l_index,
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!(link->ce_mask & (LINK_ATTR_IFINDEX | LINK_ATTR_IFNAME))) {
|
|
|
|
APPBUG("ifindex or name must be specified");
|
|
|
|
return -NLE_MISSING_ATTR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(msg = nlmsg_alloc_simple(RTM_DELLINK, 0)))
|
|
|
|
return -NLE_NOMEM;
|
|
|
|
|
|
|
|
if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
if (link->ce_mask & LINK_ATTR_IFNAME)
|
|
|
|
NLA_PUT_STRING(msg, IFLA_IFNAME, link->l_name);
|
|
|
|
|
|
|
|
*result = msg;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return -NLE_MSGSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Delete link
|
|
|
|
* @arg sk Netlink socket
|
|
|
|
* @arg link Link to delete
|
|
|
|
*
|
|
|
|
* Builds a \c RTM_DELLINK netlink message requesting the deletion of
|
|
|
|
* a network link which has been previously added to the kernel and
|
|
|
|
* sends the message to the kernel.
|
|
|
|
*
|
|
|
|
* If no matching link exists, the function will return
|
|
|
|
* -NLE_OBJ_NOTFOUND.
|
|
|
|
*
|
|
|
|
* After sending, the function will wait for the ACK or an eventual
|
|
|
|
* error message to be received and will therefore block until the
|
|
|
|
* operation has been completed.
|
|
|
|
*
|
2011-07-28 16:23:57 +02:00
|
|
|
* @copydoc auto_ack_warning
|
2011-04-10 11:02:47 +02:00
|
|
|
*
|
|
|
|
* @note Only virtual links such as dummy interface or vlan interfaces
|
|
|
|
* can be deleted. It is not possible to delete physical interfaces
|
|
|
|
* such as ethernet interfaces or the loopback device.
|
|
|
|
*
|
|
|
|
* @return 0 on success or a negative error code.
|
|
|
|
*/
|
|
|
|
int rtnl_link_delete(struct nl_sock *sk, const struct rtnl_link *link)
|
|
|
|
{
|
|
|
|
struct nl_msg *msg;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if ((err = rtnl_link_build_delete_request(link, &msg)) < 0)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
return nl_send_sync(sk, msg);
|
|
|
|
}
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
/** @} */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @name Link Object
|
|
|
|
* @{
|
|
|
|
*/
|
2011-04-11 12:34:01 +02:00
|
|
|
|
|
|
|
/**
|
2011-07-28 16:23:57 +02:00
|
|
|
* Allocate link object
|
2011-04-11 12:34:01 +02:00
|
|
|
*
|
2011-07-28 16:23:57 +02:00
|
|
|
* @see rtnl_link_put()
|
|
|
|
* @return New link object or NULL if allocation failed
|
2011-04-11 12:34:01 +02:00
|
|
|
*/
|
2011-07-28 16:23:57 +02:00
|
|
|
struct rtnl_link *rtnl_link_alloc(void)
|
2011-04-11 12:34:01 +02:00
|
|
|
{
|
2011-07-28 16:23:57 +02:00
|
|
|
return (struct rtnl_link *) nl_object_alloc(&link_obj_ops);
|
2011-04-11 12:34:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2011-07-28 16:23:57 +02:00
|
|
|
* Return a link object reference
|
2012-05-10 12:03:59 +02:00
|
|
|
* @arg link Link object
|
2011-04-11 12:34:01 +02:00
|
|
|
*/
|
2011-07-28 16:23:57 +02:00
|
|
|
void rtnl_link_put(struct rtnl_link *link)
|
2011-04-11 12:34:01 +02:00
|
|
|
{
|
2011-07-28 16:23:57 +02:00
|
|
|
nl_object_put((struct nl_object *) link);
|
2011-04-11 12:34:01 +02:00
|
|
|
}
|
|
|
|
|
2007-09-15 01:28:01 +02:00
|
|
|
/**
|
2011-07-28 16:23:57 +02:00
|
|
|
* Set name of link object
|
|
|
|
* @arg link Link object
|
|
|
|
* @arg name New name
|
|
|
|
*
|
|
|
|
* @note To change the name of a link in the kernel, set the interface
|
|
|
|
* index to the link you wish to change, modify the link name using
|
|
|
|
* this function and pass the link object to rtnl_link_change() or
|
|
|
|
* rtnl_link_add().
|
|
|
|
*
|
|
|
|
* @route_doc{link_attr_name, Link Name}
|
|
|
|
* @see rtnl_link_get_name()
|
|
|
|
* @see rtnl_link_set_ifindex()
|
2007-09-15 01:28:01 +02:00
|
|
|
*/
|
2011-07-28 16:23:57 +02:00
|
|
|
void rtnl_link_set_name(struct rtnl_link *link, const char *name)
|
|
|
|
{
|
|
|
|
strncpy(link->l_name, name, sizeof(link->l_name) - 1);
|
|
|
|
link->ce_mask |= LINK_ATTR_IFNAME;
|
|
|
|
}
|
2007-09-15 01:28:01 +02:00
|
|
|
|
|
|
|
/**
|
2011-07-28 16:23:57 +02:00
|
|
|
* Return name of link object
|
|
|
|
* @arg link Link object
|
2007-09-15 01:28:01 +02:00
|
|
|
*
|
2011-07-28 16:23:57 +02:00
|
|
|
* @route_doc{link_attr_name, Link Name}
|
|
|
|
* @see rtnl_link_set_name()
|
|
|
|
* @return Link name or NULL if name is not specified
|
2007-09-15 01:28:01 +02:00
|
|
|
*/
|
2011-07-28 16:23:57 +02:00
|
|
|
char *rtnl_link_get_name(struct rtnl_link *link)
|
2007-09-15 01:28:01 +02:00
|
|
|
{
|
2011-07-28 16:23:57 +02:00
|
|
|
return link->ce_mask & LINK_ATTR_IFNAME ? link->l_name : NULL;
|
2007-09-15 01:28:01 +02:00
|
|
|
}
|
|
|
|
|
2012-10-09 21:55:31 +02:00
|
|
|
/**
|
|
|
|
* Set the group identifier of a link object
|
|
|
|
* @arg link Link object
|
|
|
|
* @arg group Group identifier
|
|
|
|
*/
|
|
|
|
void rtnl_link_set_group(struct rtnl_link *link, uint32_t group)
|
|
|
|
{
|
|
|
|
link->l_group = group;
|
|
|
|
link->ce_mask |= LINK_ATTR_GROUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the group identifier of link object
|
|
|
|
* @arg link Link object
|
|
|
|
*
|
|
|
|
* @return Group identifier or 0 if not set.
|
|
|
|
*/
|
|
|
|
uint32_t rtnl_link_get_group(struct rtnl_link *link)
|
|
|
|
{
|
|
|
|
return link->l_group;
|
|
|
|
}
|
|
|
|
|
2007-09-15 01:28:01 +02:00
|
|
|
static inline void __assign_addr(struct rtnl_link *link, struct nl_addr **pos,
|
|
|
|
struct nl_addr *new, int flag)
|
|
|
|
{
|
|
|
|
if (*pos)
|
|
|
|
nl_addr_put(*pos);
|
|
|
|
|
|
|
|
nl_addr_get(new);
|
|
|
|
*pos = new;
|
|
|
|
|
|
|
|
link->ce_mask |= flag;
|
|
|
|
}
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
/**
|
|
|
|
* Set link layer address of link object
|
|
|
|
* @arg link Link object
|
|
|
|
* @arg addr New link layer address
|
|
|
|
*
|
|
|
|
* The function increments the reference counter of the address object
|
|
|
|
* and overwrites any existing link layer address previously assigned.
|
|
|
|
*
|
|
|
|
* @route_doc{link_attr_address, Link layer address}
|
|
|
|
* @see rtnl_link_get_addr()
|
|
|
|
*/
|
2007-09-15 01:28:01 +02:00
|
|
|
void rtnl_link_set_addr(struct rtnl_link *link, struct nl_addr *addr)
|
|
|
|
{
|
|
|
|
__assign_addr(link, &link->l_addr, addr, LINK_ATTR_ADDR);
|
|
|
|
}
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
/**
|
|
|
|
* Return link layer address of link object
|
|
|
|
* @arg link Link object
|
|
|
|
*
|
|
|
|
* @copydoc pointer_lifetime_warning
|
|
|
|
* @route_doc{link_attr_address, Link Layer Address}
|
|
|
|
* @see rtnl_link_set_addr()
|
|
|
|
* @return Link layer address or NULL if not set.
|
|
|
|
*/
|
2007-09-15 01:28:01 +02:00
|
|
|
struct nl_addr *rtnl_link_get_addr(struct rtnl_link *link)
|
|
|
|
{
|
2011-07-28 16:23:57 +02:00
|
|
|
return link->ce_mask & LINK_ATTR_ADDR ? link->l_addr : NULL;
|
2007-09-15 01:28:01 +02:00
|
|
|
}
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
/**
|
|
|
|
* Set link layer broadcast address of link object
|
|
|
|
* @arg link Link object
|
|
|
|
* @arg addr New broadcast address
|
|
|
|
*
|
|
|
|
* The function increments the reference counter of the address object
|
|
|
|
* and overwrites any existing link layer broadcast address previously
|
|
|
|
* assigned.
|
|
|
|
*
|
|
|
|
* @route_doc{link_attr_broadcast, Link Layer Broadcast Address}
|
|
|
|
* @see rtnl_link_get_broadcast()
|
|
|
|
*/
|
|
|
|
void rtnl_link_set_broadcast(struct rtnl_link *link, struct nl_addr *addr)
|
2007-09-15 01:28:01 +02:00
|
|
|
{
|
2011-07-28 16:23:57 +02:00
|
|
|
__assign_addr(link, &link->l_bcast, addr, LINK_ATTR_BRD);
|
2007-09-15 01:28:01 +02:00
|
|
|
}
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
/**
|
|
|
|
* Return link layer broadcast address of link object
|
|
|
|
* @arg link Link object
|
|
|
|
*
|
|
|
|
* @copydoc pointer_lifetime_warning
|
|
|
|
* @route_doc{link_attr_address, Link Layer Address}
|
|
|
|
* @see rtnl_link_set_broadcast()
|
|
|
|
* @return Link layer address or NULL if not set.
|
|
|
|
*/
|
2007-09-15 01:28:01 +02:00
|
|
|
struct nl_addr *rtnl_link_get_broadcast(struct rtnl_link *link)
|
|
|
|
{
|
2011-07-28 16:23:57 +02:00
|
|
|
return link->ce_mask & LINK_ATTR_BRD ? link->l_bcast : NULL;
|
2007-09-15 01:28:01 +02:00
|
|
|
}
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
/**
|
|
|
|
* Set flags of link object
|
|
|
|
* @arg link Link object
|
|
|
|
* @arg flags Flags
|
|
|
|
*
|
|
|
|
* @see rtnl_link_get_flags()
|
|
|
|
* @see rtnl_link_unset_flags()
|
|
|
|
*/
|
2007-09-15 01:28:01 +02:00
|
|
|
void rtnl_link_set_flags(struct rtnl_link *link, unsigned int flags)
|
|
|
|
{
|
|
|
|
link->l_flag_mask |= flags;
|
|
|
|
link->l_flags |= flags;
|
|
|
|
link->ce_mask |= LINK_ATTR_FLAGS;
|
|
|
|
}
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
/**
|
|
|
|
* Unset flags of link object
|
|
|
|
* @arg link Link object
|
|
|
|
* @arg flags Flags
|
|
|
|
*
|
|
|
|
* @see rtnl_link_set_flags()
|
|
|
|
* @see rtnl_link_get_flags()
|
|
|
|
*/
|
2007-09-15 01:28:01 +02:00
|
|
|
void rtnl_link_unset_flags(struct rtnl_link *link, unsigned int flags)
|
|
|
|
{
|
|
|
|
link->l_flag_mask |= flags;
|
|
|
|
link->l_flags &= ~flags;
|
|
|
|
link->ce_mask |= LINK_ATTR_FLAGS;
|
|
|
|
}
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
/**
|
|
|
|
* Return flags of link object
|
|
|
|
* @arg link Link object
|
|
|
|
*
|
|
|
|
* @route_doc{link_attr_flags, Link Flags}
|
|
|
|
* @see rtnl_link_set_flags()
|
|
|
|
* @see rtnl_link_unset_flags()
|
|
|
|
* @return Link flags or 0 if none have been set.
|
|
|
|
*/
|
2007-09-15 01:28:01 +02:00
|
|
|
unsigned int rtnl_link_get_flags(struct rtnl_link *link)
|
|
|
|
{
|
|
|
|
return link->l_flags;
|
|
|
|
}
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
/**
|
|
|
|
* Set address family of link object
|
|
|
|
*
|
|
|
|
* @see rtnl_link_get_family()
|
|
|
|
*/
|
2007-09-15 01:28:01 +02:00
|
|
|
void rtnl_link_set_family(struct rtnl_link *link, int family)
|
|
|
|
{
|
|
|
|
link->l_family = family;
|
|
|
|
link->ce_mask |= LINK_ATTR_FAMILY;
|
2013-02-05 13:52:22 +01:00
|
|
|
|
2013-08-21 14:40:34 +02:00
|
|
|
if (link->l_af_ops) {
|
2013-02-05 13:52:22 +01:00
|
|
|
af_free(link, link->l_af_ops,
|
|
|
|
link->l_af_data[link->l_af_ops->ao_family], NULL);
|
2013-08-21 14:40:34 +02:00
|
|
|
link->l_af_data[link->l_af_ops->ao_family] = NULL;
|
|
|
|
}
|
2013-02-05 13:52:22 +01:00
|
|
|
|
|
|
|
link->l_af_ops = af_lookup_and_alloc(link, family);
|
2007-09-15 01:28:01 +02:00
|
|
|
}
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
/**
|
|
|
|
* Return address family of link object
|
|
|
|
* @arg link Link object
|
|
|
|
*
|
|
|
|
* @see rtnl_link_set_family()
|
|
|
|
* @return Address family or \c AF_UNSPEC if not specified.
|
|
|
|
*/
|
2007-09-15 01:28:01 +02:00
|
|
|
int rtnl_link_get_family(struct rtnl_link *link)
|
|
|
|
{
|
2011-07-28 16:23:57 +02:00
|
|
|
return link->ce_mask & LINK_ATTR_FAMILY ? link->l_family : AF_UNSPEC;
|
2007-09-15 01:28:01 +02:00
|
|
|
}
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
/**
|
|
|
|
* Set hardware type of link object
|
|
|
|
* @arg link Link object
|
|
|
|
* @arg arptype New hardware type \c (ARPHRD_*)
|
|
|
|
*
|
|
|
|
* @route_doc{link_attr_arptype, Hardware Type}
|
|
|
|
* @copydoc read_only_attribute
|
|
|
|
* @see rtnl_link_get_arptype()
|
|
|
|
*/
|
2007-09-15 01:28:01 +02:00
|
|
|
void rtnl_link_set_arptype(struct rtnl_link *link, unsigned int arptype)
|
|
|
|
{
|
|
|
|
link->l_arptype = arptype;
|
2011-07-28 16:23:57 +02:00
|
|
|
link->ce_mask |= LINK_ATTR_ARPTYPE;
|
2007-09-15 01:28:01 +02:00
|
|
|
}
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
/**
|
|
|
|
* Get hardware type of link object
|
|
|
|
* @arg link Link object
|
|
|
|
*
|
|
|
|
* @route_doc{link_attr_arptype, Hardware Type}
|
|
|
|
* @see rtnl_link_set_arptype()
|
|
|
|
* @return Hardware type \c (ARPHRD_ETHER *) or \c ARPHRD_VOID
|
|
|
|
*/
|
2007-09-15 01:28:01 +02:00
|
|
|
unsigned int rtnl_link_get_arptype(struct rtnl_link *link)
|
|
|
|
{
|
2011-07-28 16:23:57 +02:00
|
|
|
if (link->ce_mask & LINK_ATTR_ARPTYPE)
|
|
|
|
return link->l_arptype;
|
|
|
|
else
|
|
|
|
return ARPHRD_VOID;
|
2007-09-15 01:28:01 +02:00
|
|
|
}
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
/**
|
|
|
|
* Set interface index of link object
|
|
|
|
* @arg link Link object
|
|
|
|
* @arg ifindex Interface index
|
|
|
|
*
|
|
|
|
* @route_doc{link_attr_ifindex, Interface Index}
|
|
|
|
* @see rtnl_link_get_ifindex()
|
|
|
|
*/
|
2007-09-15 01:28:01 +02:00
|
|
|
void rtnl_link_set_ifindex(struct rtnl_link *link, int ifindex)
|
|
|
|
{
|
|
|
|
link->l_index = ifindex;
|
|
|
|
link->ce_mask |= LINK_ATTR_IFINDEX;
|
|
|
|
}
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Return interface index of link object
|
|
|
|
* @arg link Link object
|
|
|
|
*
|
|
|
|
* @route_doc{link_attr_ifindex, Interface Index}
|
|
|
|
* @see rtnl_link_set_ifindex()
|
|
|
|
* @return Interface index or 0 if not set.
|
|
|
|
*/
|
2007-09-15 01:28:01 +02:00
|
|
|
int rtnl_link_get_ifindex(struct rtnl_link *link)
|
|
|
|
{
|
2008-05-14 18:34:39 +02:00
|
|
|
return link->l_index;
|
2007-09-15 01:28:01 +02:00
|
|
|
}
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
/**
|
|
|
|
* Set Maximum Transmission Unit of link object
|
|
|
|
* @arg link Link object
|
|
|
|
* @arg mtu New MTU value in number of bytes
|
|
|
|
*
|
|
|
|
* @route_doc{link_attr_mtu, Maximum Transmission Unit}
|
|
|
|
* @see rtnl_link_get_mtu()
|
|
|
|
*/
|
2007-09-15 01:28:01 +02:00
|
|
|
void rtnl_link_set_mtu(struct rtnl_link *link, unsigned int mtu)
|
|
|
|
{
|
|
|
|
link->l_mtu = mtu;
|
|
|
|
link->ce_mask |= LINK_ATTR_MTU;
|
|
|
|
}
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
/**
|
|
|
|
* Return maximum transmission unit of link object
|
|
|
|
* @arg link Link object
|
|
|
|
*
|
|
|
|
* @route_doc{link_attr_mtu, Maximum Transmission Unit}
|
|
|
|
* @see rtnl_link_set_mtu()
|
|
|
|
* @return MTU in bytes or 0 if not set
|
|
|
|
*/
|
2007-09-15 01:28:01 +02:00
|
|
|
unsigned int rtnl_link_get_mtu(struct rtnl_link *link)
|
|
|
|
{
|
2011-07-28 16:23:57 +02:00
|
|
|
return link->l_mtu;
|
2007-09-15 01:28:01 +02:00
|
|
|
}
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
/**
|
|
|
|
* Set transmission queue length
|
|
|
|
* @arg link Link object
|
|
|
|
* @arg txqlen New queue length
|
|
|
|
*
|
|
|
|
* The unit is dependant on the link type. The most common units is number
|
|
|
|
* of packets.
|
|
|
|
*
|
|
|
|
* @route_doc{link_attr_txqlen, Transmission Queue Length}
|
|
|
|
*/
|
2007-09-15 01:28:01 +02:00
|
|
|
void rtnl_link_set_txqlen(struct rtnl_link *link, unsigned int txqlen)
|
|
|
|
{
|
|
|
|
link->l_txqlen = txqlen;
|
|
|
|
link->ce_mask |= LINK_ATTR_TXQLEN;
|
|
|
|
}
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
/**
|
|
|
|
* Return transmission queue length
|
|
|
|
* @arg link Link object
|
|
|
|
*
|
|
|
|
* The unit is dependant on the link type. The most common units is number
|
|
|
|
* of packets.
|
|
|
|
*
|
|
|
|
* @route_doc{link_attr_txqlen, Transmission Queue Length}
|
|
|
|
* @return queue length or 0 if not specified.
|
|
|
|
*/
|
2007-09-15 01:28:01 +02:00
|
|
|
unsigned int rtnl_link_get_txqlen(struct rtnl_link *link)
|
|
|
|
{
|
2011-07-28 16:23:57 +02:00
|
|
|
return link->ce_mask & LINK_ATTR_TXQLEN ? link->l_txqlen : 0;
|
2007-09-15 01:28:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void rtnl_link_set_link(struct rtnl_link *link, int ifindex)
|
|
|
|
{
|
|
|
|
link->l_link = ifindex;
|
|
|
|
link->ce_mask |= LINK_ATTR_LINK;
|
|
|
|
}
|
|
|
|
|
|
|
|
int rtnl_link_get_link(struct rtnl_link *link)
|
|
|
|
{
|
2008-05-14 18:34:39 +02:00
|
|
|
return link->l_link;
|
2007-09-15 01:28:01 +02:00
|
|
|
}
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
/**
|
|
|
|
* Set master link of link object
|
|
|
|
* @arg link Link object
|
|
|
|
* @arg ifindex Interface index of master link
|
|
|
|
*
|
|
|
|
* @see rtnl_link_get_master()
|
|
|
|
*/
|
2007-09-15 01:28:01 +02:00
|
|
|
void rtnl_link_set_master(struct rtnl_link *link, int ifindex)
|
|
|
|
{
|
|
|
|
link->l_master = ifindex;
|
|
|
|
link->ce_mask |= LINK_ATTR_MASTER;
|
|
|
|
}
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
/**
|
|
|
|
* Return master link of link object
|
|
|
|
* @arg link Link object
|
|
|
|
*
|
|
|
|
* @see rtnl_link_set_master()
|
|
|
|
* @return Interface index of master link or 0 if not specified
|
|
|
|
*/
|
2007-09-15 01:28:01 +02:00
|
|
|
int rtnl_link_get_master(struct rtnl_link *link)
|
|
|
|
{
|
2008-05-14 18:34:39 +02:00
|
|
|
return link->l_master;
|
2007-09-15 01:28:01 +02:00
|
|
|
}
|
|
|
|
|
2013-01-07 18:36:12 -02:00
|
|
|
/**
|
|
|
|
* Set carrier of link object
|
|
|
|
* @arg link Link object
|
|
|
|
* @arg status New carrier status
|
|
|
|
*
|
|
|
|
* @see rtnl_link_get_carrier()
|
|
|
|
*/
|
|
|
|
void rtnl_link_set_carrier(struct rtnl_link *link, uint8_t status)
|
|
|
|
{
|
|
|
|
link->l_carrier = status;
|
|
|
|
link->ce_mask |= LINK_ATTR_CARRIER;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return carrier status of link object
|
|
|
|
* @arg link Link object
|
|
|
|
*
|
|
|
|
* @see rtnl_link_set_master()
|
|
|
|
* @return Carrier state.
|
|
|
|
*/
|
|
|
|
uint8_t rtnl_link_get_carrier(struct rtnl_link *link)
|
|
|
|
{
|
|
|
|
return link->l_carrier;
|
|
|
|
}
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
/**
|
|
|
|
* Set operational status of link object
|
|
|
|
* @arg link Link object
|
|
|
|
* @arg status New opertional status
|
|
|
|
*
|
|
|
|
* @route_doc{link_attr_operstate, Operational Status}}
|
|
|
|
* @see rtnl_link_get_operstate()
|
|
|
|
*/
|
|
|
|
void rtnl_link_set_operstate(struct rtnl_link *link, uint8_t status)
|
2007-12-19 22:03:44 +01:00
|
|
|
{
|
2011-07-28 16:23:57 +02:00
|
|
|
link->l_operstate = status;
|
2007-12-19 22:03:44 +01:00
|
|
|
link->ce_mask |= LINK_ATTR_OPERSTATE;
|
|
|
|
}
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
/**
|
|
|
|
* Return operational status of link object
|
|
|
|
* @arg link Link object
|
|
|
|
*
|
|
|
|
* @route_doc{link_attr_operstate, Operational Status}
|
|
|
|
* @see rtnl_link_set_operstate()
|
|
|
|
* @return Opertional state or \c IF_OPER_UNKNOWN
|
|
|
|
*/
|
2007-12-19 22:03:44 +01:00
|
|
|
uint8_t rtnl_link_get_operstate(struct rtnl_link *link)
|
|
|
|
{
|
2011-07-28 16:23:57 +02:00
|
|
|
return link->l_operstate;
|
2007-12-19 22:03:44 +01:00
|
|
|
}
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
/**
|
|
|
|
* Set link mode of link object
|
|
|
|
* @arg link Link object
|
|
|
|
* @arg mode New link mode
|
|
|
|
*
|
|
|
|
* @route_doc{link_attr_mode, Mode}
|
|
|
|
* @see rtnl_link_get_linkmode()
|
|
|
|
*/
|
|
|
|
void rtnl_link_set_linkmode(struct rtnl_link *link, uint8_t mode)
|
2007-12-19 22:03:44 +01:00
|
|
|
{
|
2011-07-28 16:23:57 +02:00
|
|
|
link->l_linkmode = mode;
|
2007-12-19 22:03:44 +01:00
|
|
|
link->ce_mask |= LINK_ATTR_LINKMODE;
|
|
|
|
}
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
/**
|
|
|
|
* Return link mode of link object
|
|
|
|
* @arg link Link object
|
|
|
|
*
|
|
|
|
* @route_doc{link_attr_mode, Mode}
|
|
|
|
* @see rtnl_link_get_linkmode()
|
|
|
|
* @return Link mode or \c IF_LINK_MODE_DEFAULT
|
|
|
|
*/
|
2007-12-19 22:03:44 +01:00
|
|
|
uint8_t rtnl_link_get_linkmode(struct rtnl_link *link)
|
|
|
|
{
|
2011-07-28 16:23:57 +02:00
|
|
|
return link->l_linkmode;
|
2007-12-19 22:03:44 +01:00
|
|
|
}
|
|
|
|
|
2010-11-11 13:57:10 +01:00
|
|
|
/**
|
2011-07-28 16:23:57 +02:00
|
|
|
* Return alias name of link object (SNMP IfAlias)
|
2010-11-11 13:57:10 +01:00
|
|
|
* @arg link Link object
|
|
|
|
*
|
2011-07-28 16:23:57 +02:00
|
|
|
* @route_doc{link_attr_alias, Alias}
|
|
|
|
* @see rtnl_link_set_ifalias()
|
2010-11-11 13:57:10 +01:00
|
|
|
* @return Alias name or NULL if not set.
|
|
|
|
*/
|
|
|
|
const char *rtnl_link_get_ifalias(struct rtnl_link *link)
|
|
|
|
{
|
|
|
|
return link->l_ifalias;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2011-07-28 16:23:57 +02:00
|
|
|
* Set alias name of link object (SNMP IfAlias)
|
2010-11-11 13:57:10 +01:00
|
|
|
* @arg link Link object
|
|
|
|
* @arg alias Alias name or NULL to unset
|
|
|
|
*
|
|
|
|
* Sets the alias name of the link to the specified name. The alias
|
|
|
|
* name can be unset by specyfing NULL as the alias. The name will
|
|
|
|
* be strdup()ed, so no need to provide a persistent character string.
|
2011-07-28 16:23:57 +02:00
|
|
|
*
|
|
|
|
* @route_doc{link_attr_alias, Alias}
|
|
|
|
* @see rtnl_link_get_ifalias()
|
2010-11-11 13:57:10 +01:00
|
|
|
*/
|
|
|
|
void rtnl_link_set_ifalias(struct rtnl_link *link, const char *alias)
|
|
|
|
{
|
|
|
|
free(link->l_ifalias);
|
|
|
|
|
|
|
|
if (alias) {
|
|
|
|
link->l_ifalias = strdup(alias);
|
|
|
|
link->ce_mask |= LINK_ATTR_IFALIAS;
|
2014-06-10 17:50:09 +02:00
|
|
|
} else {
|
|
|
|
link->l_ifalias = NULL;
|
|
|
|
link->ce_mask &= ~LINK_ATTR_IFALIAS;
|
2010-11-11 13:57:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-11 14:11:32 +01:00
|
|
|
/**
|
2011-07-28 16:23:57 +02:00
|
|
|
* Set queueing discipline name of link object
|
|
|
|
* @arg link Link object
|
|
|
|
* @arg name Name of queueing discipline
|
|
|
|
*
|
|
|
|
* @copydoc read_only_attribute
|
|
|
|
*
|
|
|
|
* For more information on how to modify the qdisc of a link, see section
|
|
|
|
* @ref_route{route_tc, Traffic Control}.
|
|
|
|
*
|
|
|
|
* @route_doc{link_attr_qdisc, Queueing Discipline Name}
|
|
|
|
* @see rtnl_link_get_qdisc()
|
|
|
|
*/
|
|
|
|
void rtnl_link_set_qdisc(struct rtnl_link *link, const char *name)
|
|
|
|
{
|
|
|
|
strncpy(link->l_qdisc, name, sizeof(link->l_qdisc) - 1);
|
|
|
|
link->ce_mask |= LINK_ATTR_QDISC;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return name of queueing discipline of link object
|
|
|
|
* @arg link Link object
|
|
|
|
*
|
|
|
|
* @route_doc{link_attr_qdisc, Queueing Discipline Name}
|
|
|
|
* @see rtnl_link_set_qdisc()
|
|
|
|
* @return Name of qdisc or NULL if not specified.
|
|
|
|
*/
|
|
|
|
char *rtnl_link_get_qdisc(struct rtnl_link *link)
|
|
|
|
{
|
|
|
|
return link->ce_mask & LINK_ATTR_QDISC ? link->l_qdisc : NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return number of PCI virtual functions of link object
|
2010-11-11 14:11:32 +01:00
|
|
|
* @arg link Link object
|
|
|
|
* @arg num_vf Pointer to store number of VFs
|
|
|
|
*
|
2011-07-28 16:23:57 +02:00
|
|
|
* @return 0 on success or -NLE_OPNOTSUPP if not available
|
2010-11-11 14:11:32 +01:00
|
|
|
*/
|
|
|
|
int rtnl_link_get_num_vf(struct rtnl_link *link, uint32_t *num_vf)
|
|
|
|
{
|
|
|
|
if (link->ce_mask & LINK_ATTR_NUM_VF) {
|
|
|
|
*num_vf = link->l_num_vf;
|
|
|
|
return 0;
|
|
|
|
} else
|
|
|
|
return -NLE_OPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
/**
|
|
|
|
* Return value of link statistics counter
|
|
|
|
* @arg link Link object
|
|
|
|
* @arg id Identifier of statistical counter
|
|
|
|
*
|
|
|
|
* @return Value of counter or 0 if not specified.
|
|
|
|
*/
|
|
|
|
uint64_t rtnl_link_get_stat(struct rtnl_link *link, rtnl_link_stat_id_t id)
|
2007-09-15 01:28:01 +02:00
|
|
|
{
|
2011-07-28 16:23:57 +02:00
|
|
|
if (id > RTNL_LINK_STATS_MAX)
|
2007-09-15 01:28:01 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
return link->l_stats[id];
|
|
|
|
}
|
|
|
|
|
2010-11-11 22:26:11 +01:00
|
|
|
/**
|
2011-07-28 16:23:57 +02:00
|
|
|
* Set value of link statistics counter
|
2010-11-11 22:26:11 +01:00
|
|
|
* @arg link Link object
|
2011-07-28 16:23:57 +02:00
|
|
|
* @arg id Identifier of statistical counter
|
2010-11-11 22:26:11 +01:00
|
|
|
* @arg value New value
|
|
|
|
*
|
2011-07-28 16:23:57 +02:00
|
|
|
* \note Changing the value of a statistical counter will not change the
|
|
|
|
* value in the kernel.
|
|
|
|
*
|
2010-11-11 22:26:11 +01:00
|
|
|
* @return 0 on success or a negative error code
|
|
|
|
*/
|
2011-07-28 16:23:57 +02:00
|
|
|
int rtnl_link_set_stat(struct rtnl_link *link, rtnl_link_stat_id_t id,
|
2010-11-11 22:26:11 +01:00
|
|
|
const uint64_t value)
|
|
|
|
{
|
|
|
|
if (id > RTNL_LINK_STATS_MAX)
|
|
|
|
return -NLE_INVAL;
|
|
|
|
|
|
|
|
link->l_stats[id] = value;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-01-08 15:00:46 +01:00
|
|
|
/**
|
2011-07-28 16:23:57 +02:00
|
|
|
* Set type of link object
|
|
|
|
* @arg link Link object
|
|
|
|
* @arg type Name of link type
|
2008-01-08 15:00:46 +01:00
|
|
|
*
|
2011-07-28 16:23:57 +02:00
|
|
|
* Looks up the link type module and prepares the link to store type
|
2011-07-21 16:45:01 +02:00
|
|
|
* specific attributes. If a type has been assigned already it will
|
|
|
|
* be released with all link type specific attributes lost.
|
2008-01-08 15:00:46 +01:00
|
|
|
*
|
2011-07-28 16:23:57 +02:00
|
|
|
* @route_doc{link_modules, Link Modules}
|
2008-01-08 15:00:46 +01:00
|
|
|
* @return 0 on success or a negative errror code.
|
|
|
|
*/
|
2011-07-21 16:45:01 +02:00
|
|
|
int rtnl_link_set_type(struct rtnl_link *link, const char *type)
|
2008-01-08 15:00:46 +01:00
|
|
|
{
|
|
|
|
struct rtnl_link_info_ops *io;
|
|
|
|
int err;
|
2011-11-11 14:56:16 +01:00
|
|
|
char *kind;
|
2008-01-08 15:00:46 +01:00
|
|
|
|
2011-11-11 14:56:16 +01:00
|
|
|
free(link->l_info_kind);
|
|
|
|
link->ce_mask &= ~LINK_ATTR_LINKINFO;
|
2008-01-08 15:00:46 +01:00
|
|
|
if (link->l_info_ops)
|
|
|
|
release_link_info(link);
|
|
|
|
|
2011-11-11 14:56:16 +01:00
|
|
|
if (!type)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
kind = strdup(type);
|
|
|
|
if (!kind)
|
|
|
|
return -NLE_NOMEM;
|
|
|
|
|
|
|
|
io = rtnl_link_info_ops_lookup(type);
|
|
|
|
if (io) {
|
|
|
|
if (io->io_alloc && (err = io->io_alloc(link)) < 0)
|
|
|
|
goto errout;
|
2008-01-08 15:00:46 +01:00
|
|
|
|
2011-11-11 14:56:16 +01:00
|
|
|
link->l_info_ops = io;
|
|
|
|
}
|
|
|
|
|
|
|
|
link->l_info_kind = kind;
|
2011-04-15 15:30:46 +02:00
|
|
|
link->ce_mask |= LINK_ATTR_LINKINFO;
|
2008-01-08 15:00:46 +01:00
|
|
|
|
|
|
|
return 0;
|
2011-11-11 14:56:16 +01:00
|
|
|
|
|
|
|
errout:
|
|
|
|
free(kind);
|
|
|
|
return err;
|
2008-01-08 15:00:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2011-07-28 16:23:57 +02:00
|
|
|
* Return type of link
|
|
|
|
* @arg link Link object
|
2008-01-08 15:00:46 +01:00
|
|
|
*
|
2011-07-28 16:23:57 +02:00
|
|
|
* @route_doc{link_modules, Link Modules}
|
|
|
|
* @return Name of link type or NULL if not specified.
|
2008-01-08 15:00:46 +01:00
|
|
|
*/
|
2011-07-21 16:45:01 +02:00
|
|
|
char *rtnl_link_get_type(struct rtnl_link *link)
|
2008-01-08 15:00:46 +01:00
|
|
|
{
|
2011-11-11 14:56:16 +01:00
|
|
|
return link->l_info_kind;
|
2011-07-28 16:23:57 +02:00
|
|
|
}
|
|
|
|
|
2012-10-09 18:15:50 +02:00
|
|
|
/**
|
|
|
|
* Set link promiscuity count
|
|
|
|
* @arg link Link object
|
|
|
|
* @arg count New promiscuity count
|
|
|
|
*
|
|
|
|
* @copydoc read_only_attribute
|
|
|
|
*
|
|
|
|
* @see rtnl_link_get_promiscuity()
|
|
|
|
*/
|
|
|
|
void rtnl_link_set_promiscuity(struct rtnl_link *link, uint32_t count)
|
|
|
|
{
|
|
|
|
link->l_promiscuity = count;
|
2012-10-09 19:34:23 +02:00
|
|
|
link->ce_mask |= LINK_ATTR_PROMISCUITY;
|
2012-10-09 18:15:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return link promiscuity count
|
|
|
|
* @arg link Link object
|
|
|
|
*
|
|
|
|
* @see rtnl_link_set_promiscuity()
|
|
|
|
* @return Link promiscuity count or 0
|
|
|
|
*/
|
|
|
|
uint32_t rtnl_link_get_promiscuity(struct rtnl_link *link)
|
|
|
|
{
|
|
|
|
return link->l_promiscuity;
|
|
|
|
}
|
|
|
|
|
2012-10-09 19:57:22 +02:00
|
|
|
/**
|
|
|
|
* Set number of TX queues
|
|
|
|
* @arg link Link object
|
|
|
|
* @arg nqueues Number of queues
|
|
|
|
*
|
|
|
|
* Sets the number of TX queues of the link object. The value is considered
|
|
|
|
* by the kernel when creating network devices that can be created via
|
|
|
|
* netlink. The value will be passed on to alloc_netdev_mqs()
|
|
|
|
*
|
|
|
|
* Therefore use of rtnl_link_set_num_tx_queues() only makes sense in
|
|
|
|
* combination with rtnl_link_add() or if the link object is used as a filter.
|
|
|
|
*
|
|
|
|
* @see rtnl_link_get_num_tx_queues()
|
|
|
|
*/
|
|
|
|
void rtnl_link_set_num_tx_queues(struct rtnl_link *link, uint32_t nqueues)
|
|
|
|
{
|
|
|
|
link->l_num_tx_queues = nqueues;
|
|
|
|
link->ce_mask |= LINK_ATTR_NUM_TX_QUEUES;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return number of TX queues
|
|
|
|
* @arg link Link object
|
|
|
|
*
|
|
|
|
* @return Number of TX queues or 0
|
|
|
|
*/
|
|
|
|
uint32_t rtnl_link_get_num_tx_queues(struct rtnl_link *link)
|
|
|
|
{
|
|
|
|
return link->l_num_tx_queues;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set number of RX queues
|
|
|
|
* @arg link Link object
|
|
|
|
* @arg nqueues Number of queues
|
|
|
|
*
|
|
|
|
* Sets the number of RX queues of the link object. The value is considered
|
|
|
|
* by the kernel when creating network devices that can be created via
|
|
|
|
* netlink. The value will be passed on to alloc_netdev_mqs()
|
|
|
|
*
|
|
|
|
* Therefore use of rtnl_link_set_num_rx_queues() only makes sense in
|
|
|
|
* combination with rtnl_link_add() or if the link object is used as a filter.
|
|
|
|
*
|
|
|
|
* @see rtnl_link_get_num_rx_queues()
|
|
|
|
*/
|
|
|
|
void rtnl_link_set_num_rx_queues(struct rtnl_link *link, uint32_t nqueues)
|
|
|
|
{
|
|
|
|
link->l_num_rx_queues = nqueues;
|
|
|
|
link->ce_mask |= LINK_ATTR_NUM_RX_QUEUES;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return number of RX queues
|
|
|
|
* @arg link Link object
|
|
|
|
*
|
|
|
|
* @return Number of RX queues or 0
|
|
|
|
*/
|
|
|
|
uint32_t rtnl_link_get_num_rx_queues(struct rtnl_link *link)
|
|
|
|
{
|
|
|
|
return link->l_num_rx_queues;
|
|
|
|
}
|
2012-10-09 18:15:50 +02:00
|
|
|
|
2013-08-01 13:57:08 +02:00
|
|
|
/**
|
|
|
|
* Return physical port id of link object
|
|
|
|
* @arg link Link object
|
|
|
|
*
|
|
|
|
* @return Physical port id or NULL if not set.
|
|
|
|
*/
|
|
|
|
struct nl_data *rtnl_link_get_phys_port_id(struct rtnl_link *link)
|
|
|
|
{
|
|
|
|
return link->l_phys_port_id;
|
|
|
|
}
|
|
|
|
|
2013-11-01 16:58:49 -07:00
|
|
|
void rtnl_link_set_ns_fd(struct rtnl_link *link, int fd)
|
|
|
|
{
|
|
|
|
link->l_ns_fd = fd;
|
|
|
|
link->ce_mask |= LINK_ATTR_NS_FD;
|
|
|
|
}
|
|
|
|
|
|
|
|
int rtnl_link_get_ns_fd(struct rtnl_link *link)
|
|
|
|
{
|
|
|
|
return link->l_ns_fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
void rtnl_link_set_ns_pid(struct rtnl_link *link, pid_t pid)
|
|
|
|
{
|
|
|
|
link->l_ns_pid = pid;
|
|
|
|
link->ce_mask |= LINK_ATTR_NS_PID;
|
|
|
|
}
|
|
|
|
|
|
|
|
pid_t rtnl_link_get_ns_pid(struct rtnl_link *link)
|
|
|
|
{
|
|
|
|
return link->l_ns_pid;
|
|
|
|
}
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
/** @} */
|
|
|
|
|
2011-11-07 12:32:35 +01:00
|
|
|
/**
|
|
|
|
* @name Master/Slave
|
|
|
|
* @{
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Enslave slave link to master link
|
|
|
|
* @arg sock netlink socket
|
|
|
|
* @arg master ifindex of master link
|
|
|
|
* @arg slave ifindex of slave link
|
|
|
|
*
|
|
|
|
* This function is identical to rtnl_link_enslave() except that
|
|
|
|
* it takes interface indices instead of rtnl_link objects.
|
|
|
|
*
|
|
|
|
* @see rtnl_link_enslave()
|
|
|
|
*
|
|
|
|
* @return 0 on success or a negative error code.
|
|
|
|
*/
|
|
|
|
int rtnl_link_enslave_ifindex(struct nl_sock *sock, int master, int slave)
|
|
|
|
{
|
|
|
|
struct rtnl_link *link;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (!(link = rtnl_link_alloc()))
|
|
|
|
return -NLE_NOMEM;
|
|
|
|
|
|
|
|
rtnl_link_set_ifindex(link, slave);
|
|
|
|
rtnl_link_set_master(link, master);
|
|
|
|
|
|
|
|
if ((err = rtnl_link_change(sock, link, link, 0)) < 0)
|
|
|
|
goto errout;
|
|
|
|
|
|
|
|
rtnl_link_put(link);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Due to the kernel not signaling whether this opertion is
|
|
|
|
* supported or not, we will retrieve the attribute to see if the
|
|
|
|
* request was successful. If the master assigned remains unchanged
|
|
|
|
* we will return NLE_OPNOTSUPP to allow performing backwards
|
|
|
|
* compatibility of some sort.
|
|
|
|
*/
|
|
|
|
if ((err = rtnl_link_get_kernel(sock, slave, NULL, &link)) < 0)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
if (rtnl_link_get_master(link) != master)
|
|
|
|
err = -NLE_OPNOTSUPP;
|
|
|
|
|
|
|
|
errout:
|
|
|
|
rtnl_link_put(link);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Enslave slave link to master link
|
|
|
|
* @arg sock netlink socket
|
|
|
|
* @arg master master link
|
|
|
|
* @arg slave slave link
|
|
|
|
*
|
|
|
|
* Constructs a RTM_NEWLINK or RTM_SETLINK message adding the slave to
|
|
|
|
* the master and sends the request via the specified netlink socket.
|
|
|
|
*
|
|
|
|
* @note The feature of enslaving/releasing via netlink has only been added
|
|
|
|
* recently to the kernel (Feb 2011). Also, the kernel does not signal
|
|
|
|
* if the operation is not supported. Therefore this function will
|
|
|
|
* verify if the master assignment has changed and will return
|
|
|
|
* -NLE_OPNOTSUPP if it did not.
|
|
|
|
*
|
|
|
|
* @see rtnl_link_enslave_ifindex()
|
|
|
|
* @see rtnl_link_release()
|
|
|
|
*
|
|
|
|
* @return 0 on success or a negative error code.
|
|
|
|
*/
|
|
|
|
int rtnl_link_enslave(struct nl_sock *sock, struct rtnl_link *master,
|
|
|
|
struct rtnl_link *slave)
|
|
|
|
{
|
|
|
|
return rtnl_link_enslave_ifindex(sock, rtnl_link_get_ifindex(master),
|
|
|
|
rtnl_link_get_ifindex(slave));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Release slave link from its master
|
|
|
|
* @arg sock netlink socket
|
|
|
|
* @arg slave slave link
|
|
|
|
*
|
|
|
|
* This function is identical to rtnl_link_release() except that
|
|
|
|
* it takes an interface index instead of a rtnl_link object.
|
|
|
|
*
|
|
|
|
* @see rtnl_link_release()
|
|
|
|
*
|
|
|
|
* @return 0 on success or a negative error code.
|
|
|
|
*/
|
|
|
|
int rtnl_link_release_ifindex(struct nl_sock *sock, int slave)
|
|
|
|
{
|
|
|
|
return rtnl_link_enslave_ifindex(sock, 0, slave);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Release slave link from its master
|
|
|
|
* @arg sock netlink socket
|
|
|
|
* @arg slave slave link
|
|
|
|
*
|
|
|
|
* Constructs a RTM_NEWLINK or RTM_SETLINK message releasing the slave from
|
|
|
|
* its master and sends the request via the specified netlink socket.
|
|
|
|
*
|
|
|
|
* @note The feature of enslaving/releasing via netlink has only been added
|
|
|
|
* recently to the kernel (Feb 2011). Also, the kernel does not signal
|
|
|
|
* if the operation is not supported. Therefore this function will
|
|
|
|
* verify if the master assignment has changed and will return
|
|
|
|
* -NLE_OPNOTSUPP if it did not.
|
|
|
|
*
|
|
|
|
* @see rtnl_link_release_ifindex()
|
|
|
|
* @see rtnl_link_enslave()
|
|
|
|
*
|
|
|
|
* @return 0 on success or a negative error code.
|
|
|
|
*/
|
|
|
|
int rtnl_link_release(struct nl_sock *sock, struct rtnl_link *slave)
|
|
|
|
{
|
|
|
|
return rtnl_link_release_ifindex(sock, rtnl_link_get_ifindex(slave));
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @} */
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
/**
|
|
|
|
* @name Utilities
|
|
|
|
* @{
|
|
|
|
*/
|
|
|
|
|
|
|
|
static const struct trans_tbl link_flags[] = {
|
2014-07-26 15:06:59 +02:00
|
|
|
__ADD(IFF_LOOPBACK, loopback),
|
|
|
|
__ADD(IFF_BROADCAST, broadcast),
|
|
|
|
__ADD(IFF_POINTOPOINT, pointopoint),
|
|
|
|
__ADD(IFF_MULTICAST, multicast),
|
|
|
|
__ADD(IFF_NOARP, noarp),
|
|
|
|
__ADD(IFF_ALLMULTI, allmulti),
|
|
|
|
__ADD(IFF_PROMISC, promisc),
|
|
|
|
__ADD(IFF_MASTER, master),
|
|
|
|
__ADD(IFF_SLAVE, slave),
|
|
|
|
__ADD(IFF_DEBUG, debug),
|
|
|
|
__ADD(IFF_DYNAMIC, dynamic),
|
|
|
|
__ADD(IFF_AUTOMEDIA, automedia),
|
|
|
|
__ADD(IFF_PORTSEL, portsel),
|
|
|
|
__ADD(IFF_NOTRAILERS, notrailers),
|
|
|
|
__ADD(IFF_UP, up),
|
|
|
|
__ADD(IFF_RUNNING, running),
|
|
|
|
__ADD(IFF_LOWER_UP, lowerup),
|
|
|
|
__ADD(IFF_DORMANT, dormant),
|
|
|
|
__ADD(IFF_ECHO, echo),
|
2011-07-28 16:23:57 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
char *rtnl_link_flags2str(int flags, char *buf, size_t len)
|
|
|
|
{
|
|
|
|
return __flags2str(flags, buf, len, link_flags,
|
|
|
|
ARRAY_SIZE(link_flags));
|
|
|
|
}
|
|
|
|
|
|
|
|
int rtnl_link_str2flags(const char *name)
|
|
|
|
{
|
|
|
|
return __str2flags(name, link_flags, ARRAY_SIZE(link_flags));
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct trans_tbl link_stats[] = {
|
2014-07-26 15:06:59 +02:00
|
|
|
__ADD(RTNL_LINK_RX_PACKETS, rx_packets),
|
|
|
|
__ADD(RTNL_LINK_TX_PACKETS, tx_packets),
|
|
|
|
__ADD(RTNL_LINK_RX_BYTES, rx_bytes),
|
|
|
|
__ADD(RTNL_LINK_TX_BYTES, tx_bytes),
|
|
|
|
__ADD(RTNL_LINK_RX_ERRORS, rx_errors),
|
|
|
|
__ADD(RTNL_LINK_TX_ERRORS, tx_errors),
|
|
|
|
__ADD(RTNL_LINK_RX_DROPPED, rx_dropped),
|
|
|
|
__ADD(RTNL_LINK_TX_DROPPED, tx_dropped),
|
|
|
|
__ADD(RTNL_LINK_RX_COMPRESSED, rx_compressed),
|
|
|
|
__ADD(RTNL_LINK_TX_COMPRESSED, tx_compressed),
|
|
|
|
__ADD(RTNL_LINK_RX_FIFO_ERR, rx_fifo_err),
|
|
|
|
__ADD(RTNL_LINK_TX_FIFO_ERR, tx_fifo_err),
|
|
|
|
__ADD(RTNL_LINK_RX_LEN_ERR, rx_len_err),
|
|
|
|
__ADD(RTNL_LINK_RX_OVER_ERR, rx_over_err),
|
|
|
|
__ADD(RTNL_LINK_RX_CRC_ERR, rx_crc_err),
|
|
|
|
__ADD(RTNL_LINK_RX_FRAME_ERR, rx_frame_err),
|
|
|
|
__ADD(RTNL_LINK_RX_MISSED_ERR, rx_missed_err),
|
|
|
|
__ADD(RTNL_LINK_TX_ABORT_ERR, tx_abort_err),
|
|
|
|
__ADD(RTNL_LINK_TX_CARRIER_ERR, tx_carrier_err),
|
|
|
|
__ADD(RTNL_LINK_TX_HBEAT_ERR, tx_hbeat_err),
|
|
|
|
__ADD(RTNL_LINK_TX_WIN_ERR, tx_win_err),
|
|
|
|
__ADD(RTNL_LINK_COLLISIONS, collisions),
|
|
|
|
__ADD(RTNL_LINK_MULTICAST, multicast),
|
|
|
|
__ADD(RTNL_LINK_IP6_INPKTS, Ip6InReceives),
|
|
|
|
__ADD(RTNL_LINK_IP6_INHDRERRORS, Ip6InHdrErrors),
|
|
|
|
__ADD(RTNL_LINK_IP6_INTOOBIGERRORS, Ip6InTooBigErrors),
|
|
|
|
__ADD(RTNL_LINK_IP6_INNOROUTES, Ip6InNoRoutes),
|
|
|
|
__ADD(RTNL_LINK_IP6_INADDRERRORS, Ip6InAddrErrors),
|
|
|
|
__ADD(RTNL_LINK_IP6_INUNKNOWNPROTOS, Ip6InUnknownProtos),
|
|
|
|
__ADD(RTNL_LINK_IP6_INTRUNCATEDPKTS, Ip6InTruncatedPkts),
|
|
|
|
__ADD(RTNL_LINK_IP6_INDISCARDS, Ip6InDiscards),
|
|
|
|
__ADD(RTNL_LINK_IP6_INDELIVERS, Ip6InDelivers),
|
|
|
|
__ADD(RTNL_LINK_IP6_OUTFORWDATAGRAMS, Ip6OutForwDatagrams),
|
|
|
|
__ADD(RTNL_LINK_IP6_OUTPKTS, Ip6OutRequests),
|
|
|
|
__ADD(RTNL_LINK_IP6_OUTDISCARDS, Ip6OutDiscards),
|
|
|
|
__ADD(RTNL_LINK_IP6_OUTNOROUTES, Ip6OutNoRoutes),
|
|
|
|
__ADD(RTNL_LINK_IP6_REASMTIMEOUT, Ip6ReasmTimeout),
|
|
|
|
__ADD(RTNL_LINK_IP6_REASMREQDS, Ip6ReasmReqds),
|
|
|
|
__ADD(RTNL_LINK_IP6_REASMOKS, Ip6ReasmOKs),
|
|
|
|
__ADD(RTNL_LINK_IP6_REASMFAILS, Ip6ReasmFails),
|
|
|
|
__ADD(RTNL_LINK_IP6_FRAGOKS, Ip6FragOKs),
|
|
|
|
__ADD(RTNL_LINK_IP6_FRAGFAILS, Ip6FragFails),
|
|
|
|
__ADD(RTNL_LINK_IP6_FRAGCREATES, Ip6FragCreates),
|
|
|
|
__ADD(RTNL_LINK_IP6_INMCASTPKTS, Ip6InMcastPkts),
|
|
|
|
__ADD(RTNL_LINK_IP6_OUTMCASTPKTS, Ip6OutMcastPkts),
|
|
|
|
__ADD(RTNL_LINK_IP6_INBCASTPKTS, Ip6InBcastPkts),
|
|
|
|
__ADD(RTNL_LINK_IP6_OUTBCASTPKTS, Ip6OutBcastPkts),
|
|
|
|
__ADD(RTNL_LINK_IP6_INOCTETS, Ip6InOctets),
|
|
|
|
__ADD(RTNL_LINK_IP6_OUTOCTETS, Ip6OutOctets),
|
|
|
|
__ADD(RTNL_LINK_IP6_INMCASTOCTETS, Ip6InMcastOctets),
|
|
|
|
__ADD(RTNL_LINK_IP6_OUTMCASTOCTETS, Ip6OutMcastOctets),
|
|
|
|
__ADD(RTNL_LINK_IP6_INBCASTOCTETS, Ip6InBcastOctets),
|
|
|
|
__ADD(RTNL_LINK_IP6_OUTBCASTOCTETS, Ip6OutBcastOctets),
|
|
|
|
__ADD(RTNL_LINK_ICMP6_INMSGS, ICMP6_InMsgs),
|
|
|
|
__ADD(RTNL_LINK_ICMP6_INERRORS, ICMP6_InErrors),
|
|
|
|
__ADD(RTNL_LINK_ICMP6_OUTMSGS, ICMP6_OutMsgs),
|
|
|
|
__ADD(RTNL_LINK_ICMP6_OUTERRORS, ICMP6_OutErrors),
|
|
|
|
__ADD(RTNL_LINK_ICMP6_CSUMERRORS, ICMP6_InCsumErrors),
|
|
|
|
__ADD(RTNL_LINK_IP6_CSUMERRORS, Ip6_InCsumErrors),
|
|
|
|
__ADD(RTNL_LINK_IP6_NOECTPKTS, Ip6_InNoECTPkts),
|
|
|
|
__ADD(RTNL_LINK_IP6_ECT1PKTS, Ip6_InECT1Pkts),
|
|
|
|
__ADD(RTNL_LINK_IP6_ECT0PKTS, Ip6_InECT0Pkts),
|
|
|
|
__ADD(RTNL_LINK_IP6_CEPKTS, Ip6_InCEPkts),
|
2011-07-28 16:23:57 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
char *rtnl_link_stat2str(int st, char *buf, size_t len)
|
|
|
|
{
|
|
|
|
return __type2str(st, buf, len, link_stats, ARRAY_SIZE(link_stats));
|
|
|
|
}
|
|
|
|
|
|
|
|
int rtnl_link_str2stat(const char *name)
|
|
|
|
{
|
|
|
|
return __str2type(name, link_stats, ARRAY_SIZE(link_stats));
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct trans_tbl link_operstates[] = {
|
2014-07-26 15:06:59 +02:00
|
|
|
__ADD(IF_OPER_UNKNOWN, unknown),
|
|
|
|
__ADD(IF_OPER_NOTPRESENT, notpresent),
|
|
|
|
__ADD(IF_OPER_DOWN, down),
|
|
|
|
__ADD(IF_OPER_LOWERLAYERDOWN, lowerlayerdown),
|
|
|
|
__ADD(IF_OPER_TESTING, testing),
|
|
|
|
__ADD(IF_OPER_DORMANT, dormant),
|
|
|
|
__ADD(IF_OPER_UP, up),
|
2011-07-28 16:23:57 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
char *rtnl_link_operstate2str(uint8_t st, char *buf, size_t len)
|
|
|
|
{
|
|
|
|
return __type2str(st, buf, len, link_operstates,
|
|
|
|
ARRAY_SIZE(link_operstates));
|
|
|
|
}
|
|
|
|
|
|
|
|
int rtnl_link_str2operstate(const char *name)
|
|
|
|
{
|
|
|
|
return __str2type(name, link_operstates,
|
|
|
|
ARRAY_SIZE(link_operstates));
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct trans_tbl link_modes[] = {
|
2014-07-26 15:06:59 +02:00
|
|
|
__ADD(IF_LINK_MODE_DEFAULT, default),
|
|
|
|
__ADD(IF_LINK_MODE_DORMANT, dormant),
|
2011-07-28 16:23:57 +02:00
|
|
|
};
|
|
|
|
|
2013-01-07 18:36:12 -02:00
|
|
|
static const struct trans_tbl carrier_states[] = {
|
2014-07-26 15:06:59 +02:00
|
|
|
__ADD(IF_CARRIER_DOWN, down),
|
|
|
|
__ADD(IF_CARRIER_UP, up),
|
2013-01-07 18:36:12 -02:00
|
|
|
};
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
char *rtnl_link_mode2str(uint8_t st, char *buf, size_t len)
|
|
|
|
{
|
|
|
|
return __type2str(st, buf, len, link_modes, ARRAY_SIZE(link_modes));
|
|
|
|
}
|
|
|
|
|
|
|
|
int rtnl_link_str2mode(const char *name)
|
|
|
|
{
|
|
|
|
return __str2type(name, link_modes, ARRAY_SIZE(link_modes));
|
2008-01-08 15:00:46 +01:00
|
|
|
}
|
|
|
|
|
2013-01-07 18:36:12 -02:00
|
|
|
char *rtnl_link_carrier2str(uint8_t st, char *buf, size_t len)
|
|
|
|
{
|
|
|
|
return __type2str(st, buf, len, carrier_states,
|
|
|
|
ARRAY_SIZE(carrier_states));
|
|
|
|
}
|
|
|
|
|
|
|
|
int rtnl_link_str2carrier(const char *name)
|
|
|
|
{
|
|
|
|
return __str2type(name, carrier_states, ARRAY_SIZE(carrier_states));
|
|
|
|
}
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
/** @} */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @name Deprecated Functions
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @deprecated Use of this function is deprecated, use rtnl_link_set_type()
|
|
|
|
*/
|
2011-07-21 16:45:01 +02:00
|
|
|
int rtnl_link_set_info_type(struct rtnl_link *link, const char *type)
|
|
|
|
{
|
|
|
|
return rtnl_link_set_type(link, type);
|
|
|
|
}
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
/**
|
|
|
|
* @deprecated Use of this function is deprecated, use rtnl_link_get_type()
|
|
|
|
*/
|
2011-07-21 16:45:01 +02:00
|
|
|
char *rtnl_link_get_info_type(struct rtnl_link *link)
|
|
|
|
{
|
|
|
|
return rtnl_link_get_type(link);
|
|
|
|
}
|
|
|
|
|
2011-07-28 16:23:57 +02:00
|
|
|
/**
|
|
|
|
* @deprecated The weight attribute is unused and obsoleted in all recent kernels
|
|
|
|
*/
|
|
|
|
void rtnl_link_set_weight(struct rtnl_link *link, unsigned int weight)
|
|
|
|
{
|
|
|
|
link->l_weight = weight;
|
|
|
|
link->ce_mask |= LINK_ATTR_WEIGHT;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @deprecated The weight attribute is unused and obsoleted in all recent kernels
|
|
|
|
*/
|
|
|
|
unsigned int rtnl_link_get_weight(struct rtnl_link *link)
|
|
|
|
{
|
|
|
|
return link->l_weight;
|
|
|
|
}
|
|
|
|
|
2007-09-15 01:28:01 +02:00
|
|
|
/** @} */
|
|
|
|
|
|
|
|
static struct nl_object_ops link_obj_ops = {
|
|
|
|
.oo_name = "route/link",
|
|
|
|
.oo_size = sizeof(struct rtnl_link),
|
|
|
|
.oo_free_data = link_free_data,
|
|
|
|
.oo_clone = link_clone,
|
2008-05-23 23:45:14 +02:00
|
|
|
.oo_dump = {
|
|
|
|
[NL_DUMP_LINE] = link_dump_line,
|
|
|
|
[NL_DUMP_DETAILS] = link_dump_details,
|
|
|
|
[NL_DUMP_STATS] = link_dump_stats,
|
|
|
|
},
|
2007-09-15 01:28:01 +02:00
|
|
|
.oo_compare = link_compare,
|
2012-11-09 14:41:34 -08:00
|
|
|
.oo_keygen = link_keygen,
|
2007-09-15 01:28:01 +02:00
|
|
|
.oo_attrs2str = link_attrs2str,
|
2012-11-14 06:06:41 -08:00
|
|
|
.oo_id_attrs = LINK_ATTR_IFINDEX | LINK_ATTR_FAMILY,
|
2007-09-15 01:28:01 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct nl_af_group link_groups[] = {
|
|
|
|
{ AF_UNSPEC, RTNLGRP_LINK },
|
2012-11-14 06:06:41 -08:00
|
|
|
{ AF_BRIDGE, RTNLGRP_LINK },
|
2007-09-15 01:28:01 +02:00
|
|
|
{ END_OF_GROUP_LIST },
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct nl_cache_ops rtnl_link_ops = {
|
|
|
|
.co_name = "route/link",
|
|
|
|
.co_hdrsize = sizeof(struct ifinfomsg),
|
|
|
|
.co_msgtypes = {
|
|
|
|
{ RTM_NEWLINK, NL_ACT_NEW, "new" },
|
|
|
|
{ RTM_DELLINK, NL_ACT_DEL, "del" },
|
|
|
|
{ RTM_GETLINK, NL_ACT_GET, "get" },
|
2010-11-16 13:54:54 +01:00
|
|
|
{ RTM_SETLINK, NL_ACT_CHANGE, "set" },
|
2007-09-15 01:28:01 +02:00
|
|
|
END_OF_MSGTYPES_LIST,
|
|
|
|
},
|
|
|
|
.co_protocol = NETLINK_ROUTE,
|
|
|
|
.co_groups = link_groups,
|
|
|
|
.co_request_update = link_request_update,
|
|
|
|
.co_msg_parser = link_msg_parser,
|
|
|
|
.co_obj_ops = &link_obj_ops,
|
|
|
|
};
|
|
|
|
|
|
|
|
static void __init link_init(void)
|
|
|
|
{
|
|
|
|
nl_cache_mngt_register(&rtnl_link_ops);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __exit link_exit(void)
|
|
|
|
{
|
|
|
|
nl_cache_mngt_unregister(&rtnl_link_ops);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @} */
|