libnl  3.2.24-rc1
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-private/route/link/api.h>
65 
66 /** @cond SKIP */
67 struct inet_data
68 {
69  uint8_t i_confset[IPV4_DEVCONF_MAX];
70  uint32_t i_conf[IPV4_DEVCONF_MAX];
71 };
72 /** @endcond */
73 
74 static void *inet_alloc(struct rtnl_link *link)
75 {
76  return calloc(1, sizeof(struct inet_data));
77 }
78 
79 static void *inet_clone(struct rtnl_link *link, void *data)
80 {
81  struct inet_data *id;
82 
83  if ((id = inet_alloc(link)))
84  memcpy(id, data, sizeof(*id));
85 
86  return id;
87 }
88 
89 static void inet_free(struct rtnl_link *link, void *data)
90 {
91  free(data);
92 }
93 
94 static struct nla_policy inet_policy[IFLA_INET6_MAX+1] = {
95  [IFLA_INET_CONF] = { .minlen = IPV4_DEVCONF_MAX * 4 },
96 };
97 
98 static int inet_parse_af(struct rtnl_link *link, struct nlattr *attr, void *data)
99 {
100  struct inet_data *id = data;
101  struct nlattr *tb[IFLA_INET_MAX+1];
102  int err;
103 
104  err = nla_parse_nested(tb, IFLA_INET_MAX, attr, inet_policy);
105  if (err < 0)
106  return err;
107 
108  if (tb[IFLA_INET_CONF])
109  nla_memcpy(&id->i_conf, tb[IFLA_INET_CONF], sizeof(id->i_conf));
110 
111  return 0;
112 }
113 
114 static int inet_fill_af(struct rtnl_link *link, struct nl_msg *msg, void *data)
115 {
116  struct inet_data *id = data;
117  struct nlattr *nla;
118  int i;
119 
120  if (!(nla = nla_nest_start(msg, IFLA_INET_CONF)))
121  return -NLE_MSGSIZE;
122 
123  for (i = 0; i < IPV4_DEVCONF_MAX; i++)
124  if (id->i_confset[i])
125  NLA_PUT_U32(msg, i+1, id->i_conf[i]);
126 
127  nla_nest_end(msg, nla);
128 
129  return 0;
130 
131 nla_put_failure:
132  return -NLE_MSGSIZE;
133 }
134 
135 static const struct trans_tbl inet_devconf[] = {
136  __ADD(IPV4_DEVCONF_FORWARDING, forwarding)
137  __ADD(IPV4_DEVCONF_MC_FORWARDING, mc_forwarding)
138  __ADD(IPV4_DEVCONF_PROXY_ARP, proxy_arp)
139  __ADD(IPV4_DEVCONF_ACCEPT_REDIRECTS, accept_redirects)
140  __ADD(IPV4_DEVCONF_SECURE_REDIRECTS, secure_redirects)
141  __ADD(IPV4_DEVCONF_SEND_REDIRECTS, send_redirects)
142  __ADD(IPV4_DEVCONF_SHARED_MEDIA, shared_media)
143  __ADD(IPV4_DEVCONF_RP_FILTER, rp_filter)
144  __ADD(IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE, accept_source_route)
145  __ADD(IPV4_DEVCONF_BOOTP_RELAY, bootp_relay)
146  __ADD(IPV4_DEVCONF_LOG_MARTIANS, log_martians)
147  __ADD(IPV4_DEVCONF_TAG, tag)
148  __ADD(IPV4_DEVCONF_ARPFILTER, arpfilter)
149  __ADD(IPV4_DEVCONF_MEDIUM_ID, medium_id)
150  __ADD(IPV4_DEVCONF_NOXFRM, noxfrm)
151  __ADD(IPV4_DEVCONF_NOPOLICY, nopolicy)
152  __ADD(IPV4_DEVCONF_FORCE_IGMP_VERSION, force_igmp_version)
153  __ADD(IPV4_DEVCONF_ARP_ANNOUNCE, arp_announce)
154  __ADD(IPV4_DEVCONF_ARP_IGNORE, arp_ignore)
155  __ADD(IPV4_DEVCONF_PROMOTE_SECONDARIES, promote_secondaries)
156  __ADD(IPV4_DEVCONF_ARP_ACCEPT, arp_accept)
157  __ADD(IPV4_DEVCONF_ARP_NOTIFY, arp_notify)
158  __ADD(IPV4_DEVCONF_ACCEPT_LOCAL, accept_local)
159  __ADD(IPV4_DEVCONF_SRC_VMARK, src_vmark)
160  __ADD(IPV4_DEVCONF_PROXY_ARP_PVLAN, proxy_arp_pvlan)
161 };
162 
163 const char *rtnl_link_inet_devconf2str(int type, char *buf, size_t len)
164 {
165  return __type2str(type, buf, len, inet_devconf,
166  ARRAY_SIZE(inet_devconf));
167 }
168 
169 int rtnl_link_inet_str2devconf(const char *name)
170 {
171  return __str2type(name, inet_devconf, ARRAY_SIZE(inet_devconf));
172 }
173 
174 static void inet_dump_details(struct rtnl_link *link,
175  struct nl_dump_params *p, void *data)
176 {
177  struct inet_data *id = data;
178  char buf[64];
179  int i, n = 0;
180 
181  nl_dump_line(p, " ipv4 devconf:\n");
182  nl_dump_line(p, " ");
183 
184  for (i = 0; i < IPV4_DEVCONF_MAX; i++) {
185  nl_dump_line(p, "%-19s %3u",
186  rtnl_link_inet_devconf2str(i+1, buf, sizeof(buf)),
187  id->i_conf[i]);
188 
189  if (++n == 3) {
190  nl_dump(p, "\n");
191  nl_dump_line(p, " ");
192  n = 0;
193  } else
194  nl_dump(p, " ");
195  }
196 
197  if (n != 0)
198  nl_dump(p, "\n");
199 }
200 
201 static struct rtnl_link_af_ops inet_ops = {
202  .ao_family = AF_INET,
203  .ao_alloc = &inet_alloc,
204  .ao_clone = &inet_clone,
205  .ao_free = &inet_free,
206  .ao_parse_af = &inet_parse_af,
207  .ao_fill_af = &inet_fill_af,
208  .ao_dump[NL_DUMP_DETAILS] = &inet_dump_details,
209 };
210 
211 /**
212  * Get value of a ipv4 link configuration setting
213  * @arg link Link object
214  * @arg cfgid Configuration identifier
215  * @arg res Result pointer
216  *
217  * Stores the value of the specified configuration setting in the provided
218  * result pointer.
219  *
220  * @return 0 on success or a negative error code.
221  * @return -NLE_RANGE cfgid is out of range, 1..IPV4_DEVCONF_MAX
222  * @return -NLE_NOATTR configuration setting not available
223  */
224 int rtnl_link_inet_get_conf(struct rtnl_link *link, const unsigned int cfgid,
225  uint32_t *res)
226 {
227  struct inet_data *id;
228 
229  if (cfgid == 0 || cfgid > IPV4_DEVCONF_MAX)
230  return -NLE_RANGE;
231 
232  if (!(id = rtnl_link_af_alloc(link, &inet_ops)))
233  return -NLE_NOATTR;
234 
235  *res = id->i_conf[cfgid - 1];
236 
237  return 0;
238 }
239 
240 /**
241  * Change value of a ipv4 link configuration setting
242  * @arg link Link object
243  * @arg cfgid Configuration identifier
244  * @arg value New value
245  *
246  * Changes the value in the per link ipv4 configuration array.
247  *
248  * @return 0 on success or a negative error code.
249  * @return -NLE_RANGE cfgid is out of range, 1..IPV4_DEVCONF_MAX
250  * @return -NLE_NOMEM memory allocation failed
251  */
252 int rtnl_link_inet_set_conf(struct rtnl_link *link, const unsigned int cfgid,
253  uint32_t value)
254 {
255  struct inet_data *id;
256 
257  if (!(id = rtnl_link_af_alloc(link, &inet_ops)))
258  return -NLE_NOMEM;
259 
260  if (cfgid == 0 || cfgid > IPV4_DEVCONF_MAX)
261  return -NLE_RANGE;
262 
263  id->i_confset[cfgid - 1] = 1;
264  id->i_conf[cfgid - 1] = value;
265 
266  return 0;
267 }
268 
269 
270 static void __init inet_init(void)
271 {
272  rtnl_link_af_register(&inet_ops);
273 }
274 
275 static void __exit inet_exit(void)
276 {
277  rtnl_link_af_unregister(&inet_ops);
278 }
279 
280 /** @} */