You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
297 lines
7.5 KiB
297 lines
7.5 KiB
/*
|
|
* lib/route/link/inet.c AF_INET link operations
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation version 2.1
|
|
* of the License.
|
|
*
|
|
* Copyright (c) 2010 Thomas Graf <tgraf@suug.ch>
|
|
*/
|
|
|
|
/**
|
|
* @ingroup link_API
|
|
* @defgroup link_inet IPv4 Link Module
|
|
* @brief Implementation of IPv4 specific link attributes
|
|
*
|
|
*
|
|
*
|
|
* @par Example: Reading the value of IPV4_DEVCONF_FORWARDING
|
|
* @code
|
|
* struct nl_cache *cache;
|
|
* struct rtnl_link *link;
|
|
* uint32_t value;
|
|
*
|
|
* // Allocate a link cache
|
|
* rtnl_link_alloc_cache(sock, AF_UNSPEC, &cache);
|
|
*
|
|
* // Search for the link we wish to see the value from
|
|
* link = rtnl_link_get_by_name(cache, "eth0");
|
|
*
|
|
* // Read the value of the setting IPV4_DEVCONF_FORWARDING
|
|
* if (rtnl_link_inet_get_conf(link, IPV4_DEVCONF_FORWARDING, &value) < 0)
|
|
* // Error: Unable to read config setting
|
|
*
|
|
* printf("forwarding is %s\n", value ? "enabled" : "disabled");
|
|
* @endcode
|
|
*
|
|
* @par Example: Changing the value of IPV4_DEVCONF_FOWARDING
|
|
* @code
|
|
* //
|
|
* // ... Continueing from the previous example ...
|
|
* //
|
|
*
|
|
* struct rtnl_link *new;
|
|
*
|
|
* // Allocate a new link to store the changes we wish to make.
|
|
* new = rtnl_link_alloc();
|
|
*
|
|
* // Set IPV4_DEVCONF_FORWARDING to '1'
|
|
* rtnl_link_inet_set_conf(new, IPV4_DEVCONF_FORWARDING, 1);
|
|
*
|
|
* // Send the change request to the kernel.
|
|
* rtnl_link_change(sock, link, new, 0);
|
|
* @endcode
|
|
*
|
|
* @{
|
|
*/
|
|
|
|
|
|
#include <netlink-private/netlink.h>
|
|
#include <netlink/netlink.h>
|
|
#include <netlink/attr.h>
|
|
#include <netlink/route/rtnl.h>
|
|
#include <netlink/route/link/inet.h>
|
|
#include <netlink-private/route/link/api.h>
|
|
|
|
/** @cond SKIP */
|
|
struct inet_data
|
|
{
|
|
uint8_t i_confset[IPV4_DEVCONF_MAX];
|
|
uint32_t i_conf[IPV4_DEVCONF_MAX];
|
|
};
|
|
/** @endcond */
|
|
|
|
static void *inet_alloc(struct rtnl_link *link)
|
|
{
|
|
return calloc(1, sizeof(struct inet_data));
|
|
}
|
|
|
|
static void *inet_clone(struct rtnl_link *link, void *data)
|
|
{
|
|
struct inet_data *id;
|
|
|
|
if ((id = inet_alloc(link)))
|
|
memcpy(id, data, sizeof(*id));
|
|
|
|
return id;
|
|
}
|
|
|
|
static void inet_free(struct rtnl_link *link, void *data)
|
|
{
|
|
free(data);
|
|
}
|
|
|
|
static struct nla_policy inet_policy[IFLA_INET_MAX+1] = {
|
|
[IFLA_INET_CONF] = { .minlen = 4 },
|
|
};
|
|
|
|
static int inet_parse_af(struct rtnl_link *link, struct nlattr *attr, void *data)
|
|
{
|
|
struct inet_data *id = data;
|
|
struct nlattr *tb[IFLA_INET_MAX+1];
|
|
int err;
|
|
|
|
err = nla_parse_nested(tb, IFLA_INET_MAX, attr, inet_policy);
|
|
if (err < 0)
|
|
return err;
|
|
if (tb[IFLA_INET_CONF] && nla_len(tb[IFLA_INET_CONF]) % 4)
|
|
return -EINVAL;
|
|
|
|
if (tb[IFLA_INET_CONF]) {
|
|
int i;
|
|
int len = min_t(int, IPV4_DEVCONF_MAX, nla_len(tb[IFLA_INET_CONF]) / 4);
|
|
|
|
for (i = 0; i < len; i++)
|
|
id->i_confset[i] = 1;
|
|
nla_memcpy(&id->i_conf, tb[IFLA_INET_CONF], sizeof(id->i_conf));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int inet_fill_af(struct rtnl_link *link, struct nl_msg *msg, void *data)
|
|
{
|
|
struct inet_data *id = data;
|
|
struct nlattr *nla;
|
|
int i;
|
|
|
|
if (!(nla = nla_nest_start(msg, IFLA_INET_CONF)))
|
|
return -NLE_MSGSIZE;
|
|
|
|
for (i = 0; i < IPV4_DEVCONF_MAX; i++)
|
|
if (id->i_confset[i])
|
|
NLA_PUT_U32(msg, i+1, id->i_conf[i]);
|
|
|
|
nla_nest_end(msg, nla);
|
|
|
|
return 0;
|
|
|
|
nla_put_failure:
|
|
return -NLE_MSGSIZE;
|
|
}
|
|
|
|
static const struct trans_tbl inet_devconf[] = {
|
|
__ADD(IPV4_DEVCONF_FORWARDING, forwarding),
|
|
__ADD(IPV4_DEVCONF_MC_FORWARDING, mc_forwarding),
|
|
__ADD(IPV4_DEVCONF_PROXY_ARP, proxy_arp),
|
|
__ADD(IPV4_DEVCONF_ACCEPT_REDIRECTS, accept_redirects),
|
|
__ADD(IPV4_DEVCONF_SECURE_REDIRECTS, secure_redirects),
|
|
__ADD(IPV4_DEVCONF_SEND_REDIRECTS, send_redirects),
|
|
__ADD(IPV4_DEVCONF_SHARED_MEDIA, shared_media),
|
|
__ADD(IPV4_DEVCONF_RP_FILTER, rp_filter),
|
|
__ADD(IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE, accept_source_route),
|
|
__ADD(IPV4_DEVCONF_BOOTP_RELAY, bootp_relay),
|
|
__ADD(IPV4_DEVCONF_LOG_MARTIANS, log_martians),
|
|
__ADD(IPV4_DEVCONF_TAG, tag),
|
|
__ADD(IPV4_DEVCONF_ARPFILTER, arpfilter),
|
|
__ADD(IPV4_DEVCONF_MEDIUM_ID, medium_id),
|
|
__ADD(IPV4_DEVCONF_NOXFRM, noxfrm),
|
|
__ADD(IPV4_DEVCONF_NOPOLICY, nopolicy),
|
|
__ADD(IPV4_DEVCONF_FORCE_IGMP_VERSION, force_igmp_version),
|
|
__ADD(IPV4_DEVCONF_ARP_ANNOUNCE, arp_announce),
|
|
__ADD(IPV4_DEVCONF_ARP_IGNORE, arp_ignore),
|
|
__ADD(IPV4_DEVCONF_PROMOTE_SECONDARIES, promote_secondaries),
|
|
__ADD(IPV4_DEVCONF_ARP_ACCEPT, arp_accept),
|
|
__ADD(IPV4_DEVCONF_ARP_NOTIFY, arp_notify),
|
|
__ADD(IPV4_DEVCONF_ACCEPT_LOCAL, accept_local),
|
|
__ADD(IPV4_DEVCONF_SRC_VMARK, src_vmark),
|
|
__ADD(IPV4_DEVCONF_PROXY_ARP_PVLAN, proxy_arp_pvlan),
|
|
__ADD(IPV4_DEVCONF_ROUTE_LOCALNET, route_localnet),
|
|
__ADD(IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL, igmpv2_unsolicited_report_interval),
|
|
__ADD(IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL, igmpv3_unsolicited_report_interval),
|
|
};
|
|
|
|
const char *rtnl_link_inet_devconf2str(int type, char *buf, size_t len)
|
|
{
|
|
return __type2str(type, buf, len, inet_devconf,
|
|
ARRAY_SIZE(inet_devconf));
|
|
}
|
|
|
|
int rtnl_link_inet_str2devconf(const char *name)
|
|
{
|
|
return __str2type(name, inet_devconf, ARRAY_SIZE(inet_devconf));
|
|
}
|
|
|
|
static void inet_dump_details(struct rtnl_link *link,
|
|
struct nl_dump_params *p, void *data)
|
|
{
|
|
struct inet_data *id = data;
|
|
char buf[64];
|
|
int i, n = 0;
|
|
|
|
nl_dump_line(p, " ipv4 devconf:\n");
|
|
nl_dump_line(p, " ");
|
|
|
|
for (i = 0; i < IPV4_DEVCONF_MAX; i++) {
|
|
nl_dump_line(p, "%-19s %3u",
|
|
rtnl_link_inet_devconf2str(i+1, buf, sizeof(buf)),
|
|
id->i_confset[i] ? id->i_conf[i] : 0);
|
|
|
|
if (++n == 3) {
|
|
nl_dump(p, "\n");
|
|
nl_dump_line(p, " ");
|
|
n = 0;
|
|
} else
|
|
nl_dump(p, " ");
|
|
}
|
|
|
|
if (n != 0)
|
|
nl_dump(p, "\n");
|
|
}
|
|
|
|
static struct rtnl_link_af_ops inet_ops = {
|
|
.ao_family = AF_INET,
|
|
.ao_alloc = &inet_alloc,
|
|
.ao_clone = &inet_clone,
|
|
.ao_free = &inet_free,
|
|
.ao_parse_af = &inet_parse_af,
|
|
.ao_fill_af = &inet_fill_af,
|
|
.ao_dump[NL_DUMP_DETAILS] = &inet_dump_details,
|
|
};
|
|
|
|
/**
|
|
* Get value of a ipv4 link configuration setting
|
|
* @arg link Link object
|
|
* @arg cfgid Configuration identifier
|
|
* @arg res Result pointer
|
|
*
|
|
* Stores the value of the specified configuration setting in the provided
|
|
* result pointer.
|
|
*
|
|
* @return 0 on success or a negative error code.
|
|
* @return -NLE_RANGE cfgid is out of range, 1..IPV4_DEVCONF_MAX
|
|
* @return -NLE_NOATTR configuration setting not available
|
|
* @return -NLE_INVAL cfgid not set. If the link was received via netlink,
|
|
* it means that the cfgid is not supported.
|
|
*/
|
|
int rtnl_link_inet_get_conf(struct rtnl_link *link, const unsigned int cfgid,
|
|
uint32_t *res)
|
|
{
|
|
struct inet_data *id;
|
|
|
|
if (cfgid == 0 || cfgid > IPV4_DEVCONF_MAX)
|
|
return -NLE_RANGE;
|
|
|
|
if (!(id = rtnl_link_af_data(link, &inet_ops)))
|
|
return -NLE_NOATTR;
|
|
|
|
if (!id->i_confset[cfgid - 1])
|
|
return -NLE_INVAL;
|
|
*res = id->i_conf[cfgid - 1];
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Change value of a ipv4 link configuration setting
|
|
* @arg link Link object
|
|
* @arg cfgid Configuration identifier
|
|
* @arg value New value
|
|
*
|
|
* Changes the value in the per link ipv4 configuration array.
|
|
*
|
|
* @return 0 on success or a negative error code.
|
|
* @return -NLE_RANGE cfgid is out of range, 1..IPV4_DEVCONF_MAX
|
|
* @return -NLE_NOMEM memory allocation failed
|
|
*/
|
|
int rtnl_link_inet_set_conf(struct rtnl_link *link, const unsigned int cfgid,
|
|
uint32_t value)
|
|
{
|
|
struct inet_data *id;
|
|
|
|
if (!(id = rtnl_link_af_alloc(link, &inet_ops)))
|
|
return -NLE_NOMEM;
|
|
|
|
if (cfgid == 0 || cfgid > IPV4_DEVCONF_MAX)
|
|
return -NLE_RANGE;
|
|
|
|
id->i_confset[cfgid - 1] = 1;
|
|
id->i_conf[cfgid - 1] = value;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void __init inet_init(void)
|
|
{
|
|
rtnl_link_af_register(&inet_ops);
|
|
}
|
|
|
|
static void __exit inet_exit(void)
|
|
{
|
|
rtnl_link_af_unregister(&inet_ops);
|
|
}
|
|
|
|
/** @} */
|