libnl  3.4.0
inet.c
1 /*
2  * lib/route/link/inet.c AF_INET link operations
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation version 2.1
7  * of the License.
8  *
9  * Copyright (c) 2010 Thomas Graf <tgraf@suug.ch>
10  */
11 
12 /**
13  * @ingroup link_API
14  * @defgroup link_inet IPv4 Link Module
15  * @brief Implementation of IPv4 specific link attributes
16  *
17  *
18  *
19  * @par Example: Reading the value of IPV4_DEVCONF_FORWARDING
20  * @code
21  * struct nl_cache *cache;
22  * struct rtnl_link *link;
23  * uint32_t value;
24  *
25  * // Allocate a link cache
26  * rtnl_link_alloc_cache(sock, AF_UNSPEC, &cache);
27  *
28  * // Search for the link we wish to see the value from
29  * link = rtnl_link_get_by_name(cache, "eth0");
30  *
31  * // Read the value of the setting IPV4_DEVCONF_FORWARDING
32  * if (rtnl_link_inet_get_conf(link, IPV4_DEVCONF_FORWARDING, &value) < 0)
33  * // Error: Unable to read config setting
34  *
35  * printf("forwarding is %s\n", value ? "enabled" : "disabled");
36  * @endcode
37  *
38  * @par Example: Changing the value of IPV4_DEVCONF_FOWARDING
39  * @code
40  * //
41  * // ... Continueing from the previous example ...
42  * //
43  *
44  * struct rtnl_link *new;
45  *
46  * // Allocate a new link to store the changes we wish to make.
47  * new = rtnl_link_alloc();
48  *
49  * // Set IPV4_DEVCONF_FORWARDING to '1'
50  * rtnl_link_inet_set_conf(new, IPV4_DEVCONF_FORWARDING, 1);
51  *
52  * // Send the change request to the kernel.
53  * rtnl_link_change(sock, link, new, 0);
54  * @endcode
55  *
56  * @{
57  */
58 
59 
60 #include <netlink-private/netlink.h>
61 #include <netlink/netlink.h>
62 #include <netlink/attr.h>
63 #include <netlink/route/rtnl.h>
64 #include <netlink/route/link/inet.h>
65 #include <netlink-private/route/link/api.h>
66 
67 /** @cond SKIP */
68 struct inet_data
69 {
70  uint8_t i_confset[IPV4_DEVCONF_MAX];
71  uint32_t i_conf[IPV4_DEVCONF_MAX];
72 };
73 /** @endcond */
74 
75 static void *inet_alloc(struct rtnl_link *link)
76 {
77  return calloc(1, sizeof(struct inet_data));
78 }
79 
80 static void *inet_clone(struct rtnl_link *link, void *data)
81 {
82  struct inet_data *id;
83 
84  if ((id = inet_alloc(link)))
85  memcpy(id, data, sizeof(*id));
86 
87  return id;
88 }
89 
90 static void inet_free(struct rtnl_link *link, void *data)
91 {
92  free(data);
93 }
94 
95 static struct nla_policy inet_policy[IFLA_INET_MAX+1] = {
96  [IFLA_INET_CONF] = { .minlen = 4 },
97 };
98 
99 static int inet_parse_af(struct rtnl_link *link, struct nlattr *attr, void *data)
100 {
101  struct inet_data *id = data;
102  struct nlattr *tb[IFLA_INET_MAX+1];
103  int err;
104 
105  err = nla_parse_nested(tb, IFLA_INET_MAX, attr, inet_policy);
106  if (err < 0)
107  return err;
108  if (tb[IFLA_INET_CONF] && nla_len(tb[IFLA_INET_CONF]) % 4)
109  return -EINVAL;
110 
111  if (tb[IFLA_INET_CONF]) {
112  int i;
113  int len = min_t(int, IPV4_DEVCONF_MAX, nla_len(tb[IFLA_INET_CONF]) / 4);
114 
115  for (i = 0; i < len; i++)
116  id->i_confset[i] = 1;
117  nla_memcpy(&id->i_conf, tb[IFLA_INET_CONF], sizeof(id->i_conf));
118  }
119 
120  return 0;
121 }
122 
123 static int inet_fill_af(struct rtnl_link *link, struct nl_msg *msg, void *data)
124 {
125  struct inet_data *id = data;
126  struct nlattr *nla;
127  int i;
128 
129  if (!(nla = nla_nest_start(msg, IFLA_INET_CONF)))
130  return -NLE_MSGSIZE;
131 
132  for (i = 0; i < IPV4_DEVCONF_MAX; i++)
133  if (id->i_confset[i])
134  NLA_PUT_U32(msg, i+1, id->i_conf[i]);
135 
136  nla_nest_end(msg, nla);
137 
138  return 0;
139 
140 nla_put_failure:
141  return -NLE_MSGSIZE;
142 }
143 
144 static const struct trans_tbl inet_devconf[] = {
145  __ADD(IPV4_DEVCONF_FORWARDING, forwarding),
146  __ADD(IPV4_DEVCONF_MC_FORWARDING, mc_forwarding),
147  __ADD(IPV4_DEVCONF_PROXY_ARP, proxy_arp),
148  __ADD(IPV4_DEVCONF_ACCEPT_REDIRECTS, accept_redirects),
149  __ADD(IPV4_DEVCONF_SECURE_REDIRECTS, secure_redirects),
150  __ADD(IPV4_DEVCONF_SEND_REDIRECTS, send_redirects),
151  __ADD(IPV4_DEVCONF_SHARED_MEDIA, shared_media),
152  __ADD(IPV4_DEVCONF_RP_FILTER, rp_filter),
153  __ADD(IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE, accept_source_route),
154  __ADD(IPV4_DEVCONF_BOOTP_RELAY, bootp_relay),
155  __ADD(IPV4_DEVCONF_LOG_MARTIANS, log_martians),
156  __ADD(IPV4_DEVCONF_TAG, tag),
157  __ADD(IPV4_DEVCONF_ARPFILTER, arpfilter),
158  __ADD(IPV4_DEVCONF_MEDIUM_ID, medium_id),
159  __ADD(IPV4_DEVCONF_NOXFRM, noxfrm),
160  __ADD(IPV4_DEVCONF_NOPOLICY, nopolicy),
161  __ADD(IPV4_DEVCONF_FORCE_IGMP_VERSION, force_igmp_version),
162  __ADD(IPV4_DEVCONF_ARP_ANNOUNCE, arp_announce),
163  __ADD(IPV4_DEVCONF_ARP_IGNORE, arp_ignore),
164  __ADD(IPV4_DEVCONF_PROMOTE_SECONDARIES, promote_secondaries),
165  __ADD(IPV4_DEVCONF_ARP_ACCEPT, arp_accept),
166  __ADD(IPV4_DEVCONF_ARP_NOTIFY, arp_notify),
167  __ADD(IPV4_DEVCONF_ACCEPT_LOCAL, accept_local),
168  __ADD(IPV4_DEVCONF_SRC_VMARK, src_vmark),
169  __ADD(IPV4_DEVCONF_PROXY_ARP_PVLAN, proxy_arp_pvlan),
170  __ADD(IPV4_DEVCONF_ROUTE_LOCALNET, route_localnet),
171  __ADD(IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL, igmpv2_unsolicited_report_interval),
172  __ADD(IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL, igmpv3_unsolicited_report_interval),
173 };
174 
175 const char *rtnl_link_inet_devconf2str(int type, char *buf, size_t len)
176 {
177  return __type2str(type, buf, len, inet_devconf,
178  ARRAY_SIZE(inet_devconf));
179 }
180 
181 int rtnl_link_inet_str2devconf(const char *name)
182 {
183  return __str2type(name, inet_devconf, ARRAY_SIZE(inet_devconf));
184 }
185 
186 static void inet_dump_details(struct rtnl_link *link,
187  struct nl_dump_params *p, void *data)
188 {
189  struct inet_data *id = data;
190  char buf[64];
191  int i, n = 0;
192 
193  nl_dump_line(p, " ipv4 devconf:\n");
194  nl_dump_line(p, " ");
195 
196  for (i = 0; i < IPV4_DEVCONF_MAX; i++) {
197  nl_dump_line(p, "%-19s %3u",
198  rtnl_link_inet_devconf2str(i+1, buf, sizeof(buf)),
199  id->i_confset[i] ? id->i_conf[i] : 0);
200 
201  if (++n == 3) {
202  nl_dump(p, "\n");
203  nl_dump_line(p, " ");
204  n = 0;
205  } else
206  nl_dump(p, " ");
207  }
208 
209  if (n != 0)
210  nl_dump(p, "\n");
211 }
212 
213 static struct rtnl_link_af_ops inet_ops = {
214  .ao_family = AF_INET,
215  .ao_alloc = &inet_alloc,
216  .ao_clone = &inet_clone,
217  .ao_free = &inet_free,
218  .ao_parse_af = &inet_parse_af,
219  .ao_fill_af = &inet_fill_af,
220  .ao_dump[NL_DUMP_DETAILS] = &inet_dump_details,
221 };
222 
223 /**
224  * Get value of a ipv4 link configuration setting
225  * @arg link Link object
226  * @arg cfgid Configuration identifier
227  * @arg res Result pointer
228  *
229  * Stores the value of the specified configuration setting in the provided
230  * result pointer.
231  *
232  * @return 0 on success or a negative error code.
233  * @return -NLE_RANGE cfgid is out of range, 1..IPV4_DEVCONF_MAX
234  * @return -NLE_NOATTR configuration setting not available
235  * @return -NLE_INVAL cfgid not set. If the link was received via netlink,
236  * it means that the cfgid is not supported.
237  */
238 int rtnl_link_inet_get_conf(struct rtnl_link *link, const unsigned int cfgid,
239  uint32_t *res)
240 {
241  struct inet_data *id;
242 
243  if (cfgid == 0 || cfgid > IPV4_DEVCONF_MAX)
244  return -NLE_RANGE;
245 
246  if (!(id = rtnl_link_af_data(link, &inet_ops)))
247  return -NLE_NOATTR;
248 
249  if (!id->i_confset[cfgid - 1])
250  return -NLE_INVAL;
251  *res = id->i_conf[cfgid - 1];
252 
253  return 0;
254 }
255 
256 /**
257  * Change value of a ipv4 link configuration setting
258  * @arg link Link object
259  * @arg cfgid Configuration identifier
260  * @arg value New value
261  *
262  * Changes the value in the per link ipv4 configuration array.
263  *
264  * @return 0 on success or a negative error code.
265  * @return -NLE_RANGE cfgid is out of range, 1..IPV4_DEVCONF_MAX
266  * @return -NLE_NOMEM memory allocation failed
267  */
268 int rtnl_link_inet_set_conf(struct rtnl_link *link, const unsigned int cfgid,
269  uint32_t value)
270 {
271  struct inet_data *id;
272 
273  if (!(id = rtnl_link_af_alloc(link, &inet_ops)))
274  return -NLE_NOMEM;
275 
276  if (cfgid == 0 || cfgid > IPV4_DEVCONF_MAX)
277  return -NLE_RANGE;
278 
279  id->i_confset[cfgid - 1] = 1;
280  id->i_conf[cfgid - 1] = value;
281 
282  return 0;
283 }
284 
285 
286 static void __init inet_init(void)
287 {
288  rtnl_link_af_register(&inet_ops);
289 }
290 
291 static void __exit inet_exit(void)
292 {
293  rtnl_link_af_unregister(&inet_ops);
294 }
295 
296 /** @} */
Attribute validation policy.
Definition: attr.h:69
Dump all attributes but no statistics.
Definition: types.h:23
int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
Finalize nesting of attributes.
Definition: attr.c:924
int nla_memcpy(void *dest, const struct nlattr *src, int count)
Copy attribute payload to another memory area.
Definition: attr.c:353
int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, struct nla_policy *policy)
Create attribute index based on nested attribute.
Definition: attr.c:999
#define NLA_PUT_U32(msg, attrtype, value)
Add 32 bit integer attribute to netlink message.
Definition: attr.h:235
int nla_len(const struct nlattr *nla)
Return length of the payload .
Definition: attr.c:131
uint16_t minlen
Minimal length of payload required.
Definition: attr.h:74
Dumping parameters.
Definition: types.h:33
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
Definition: utils.c:961
struct nlattr * nla_nest_start(struct nl_msg *msg, int attrtype)
Start a new level of nested attributes.
Definition: attr.c:902