Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
  1/*
  2 * Copyright (c) 2018 Cumulus Networks. All rights reserved.
  3 * Copyright (c) 2018 David Ahern <dsa@cumulusnetworks.com>
  4 *
  5 * This software is licensed under the GNU General License Version 2,
  6 * June 1991 as shown in the file COPYING in the top-level directory of this
  7 * source tree.
  8 *
  9 * THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS"
 10 * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 11 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 12 * FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
 13 * OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
 14 * THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
 15 */
 16
 17#include <linux/device.h>
 18#include <net/devlink.h>
 19#include <net/netns/generic.h>
 20
 21#include "netdevsim.h"
 22
 23static unsigned int nsim_devlink_id;
 24
 25/* place holder until devlink and namespaces is sorted out */
 26static struct net *nsim_devlink_net(struct devlink *devlink)
 27{
 28	return &init_net;
 29}
 30
 31/* IPv4
 32 */
 33static u64 nsim_ipv4_fib_resource_occ_get(void *priv)
 34{
 35	struct net *net = priv;
 36
 37	return nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB, false);
 38}
 39
 40static u64 nsim_ipv4_fib_rules_res_occ_get(void *priv)
 41{
 42	struct net *net = priv;
 43
 44	return nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB_RULES, false);
 45}
 46
 47/* IPv6
 48 */
 49static u64 nsim_ipv6_fib_resource_occ_get(void *priv)
 50{
 51	struct net *net = priv;
 52
 53	return nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB, false);
 54}
 55
 56static u64 nsim_ipv6_fib_rules_res_occ_get(void *priv)
 57{
 58	struct net *net = priv;
 59
 60	return nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB_RULES, false);
 61}
 62
 63static int devlink_resources_register(struct devlink *devlink)
 64{
 65	struct devlink_resource_size_params params = {
 66		.size_max = (u64)-1,
 67		.size_granularity = 1,
 68		.unit = DEVLINK_RESOURCE_UNIT_ENTRY
 69	};
 70	struct net *net = nsim_devlink_net(devlink);
 71	int err;
 72	u64 n;
 73
 74	/* Resources for IPv4 */
 75	err = devlink_resource_register(devlink, "IPv4", (u64)-1,
 76					NSIM_RESOURCE_IPV4,
 77					DEVLINK_RESOURCE_ID_PARENT_TOP,
 78					&params);
 79	if (err) {
 80		pr_err("Failed to register IPv4 top resource\n");
 81		goto out;
 82	}
 83
 84	n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB, true);
 85	err = devlink_resource_register(devlink, "fib", n,
 86					NSIM_RESOURCE_IPV4_FIB,
 87					NSIM_RESOURCE_IPV4, &params);
 88	if (err) {
 89		pr_err("Failed to register IPv4 FIB resource\n");
 90		return err;
 91	}
 92
 93	n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB_RULES, true);
 94	err = devlink_resource_register(devlink, "fib-rules", n,
 95					NSIM_RESOURCE_IPV4_FIB_RULES,
 96					NSIM_RESOURCE_IPV4, &params);
 97	if (err) {
 98		pr_err("Failed to register IPv4 FIB rules resource\n");
 99		return err;
100	}
101
102	/* Resources for IPv6 */
103	err = devlink_resource_register(devlink, "IPv6", (u64)-1,
104					NSIM_RESOURCE_IPV6,
105					DEVLINK_RESOURCE_ID_PARENT_TOP,
106					&params);
107	if (err) {
108		pr_err("Failed to register IPv6 top resource\n");
109		goto out;
110	}
111
112	n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB, true);
113	err = devlink_resource_register(devlink, "fib", n,
114					NSIM_RESOURCE_IPV6_FIB,
115					NSIM_RESOURCE_IPV6, &params);
116	if (err) {
117		pr_err("Failed to register IPv6 FIB resource\n");
118		return err;
119	}
120
121	n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB_RULES, true);
122	err = devlink_resource_register(devlink, "fib-rules", n,
123					NSIM_RESOURCE_IPV6_FIB_RULES,
124					NSIM_RESOURCE_IPV6, &params);
125	if (err) {
126		pr_err("Failed to register IPv6 FIB rules resource\n");
127		return err;
128	}
129
130	devlink_resource_occ_get_register(devlink,
131					  NSIM_RESOURCE_IPV4_FIB,
132					  nsim_ipv4_fib_resource_occ_get,
133					  net);
134	devlink_resource_occ_get_register(devlink,
135					  NSIM_RESOURCE_IPV4_FIB_RULES,
136					  nsim_ipv4_fib_rules_res_occ_get,
137					  net);
138	devlink_resource_occ_get_register(devlink,
139					  NSIM_RESOURCE_IPV6_FIB,
140					  nsim_ipv6_fib_resource_occ_get,
141					  net);
142	devlink_resource_occ_get_register(devlink,
143					  NSIM_RESOURCE_IPV6_FIB_RULES,
144					  nsim_ipv6_fib_rules_res_occ_get,
145					  net);
146out:
147	return err;
148}
149
150static int nsim_devlink_reload(struct devlink *devlink)
151{
152	enum nsim_resource_id res_ids[] = {
153		NSIM_RESOURCE_IPV4_FIB, NSIM_RESOURCE_IPV4_FIB_RULES,
154		NSIM_RESOURCE_IPV6_FIB, NSIM_RESOURCE_IPV6_FIB_RULES
155	};
156	struct net *net = nsim_devlink_net(devlink);
157	int i;
158
159	for (i = 0; i < ARRAY_SIZE(res_ids); ++i) {
160		int err;
161		u64 val;
162
163		err = devlink_resource_size_get(devlink, res_ids[i], &val);
164		if (!err) {
165			err = nsim_fib_set_max(net, res_ids[i], val);
166			if (err)
167				return err;
168		}
169	}
170
171	return 0;
172}
173
174static void nsim_devlink_net_reset(struct net *net)
175{
176	enum nsim_resource_id res_ids[] = {
177		NSIM_RESOURCE_IPV4_FIB, NSIM_RESOURCE_IPV4_FIB_RULES,
178		NSIM_RESOURCE_IPV6_FIB, NSIM_RESOURCE_IPV6_FIB_RULES
179	};
180	int i;
181
182	for (i = 0; i < ARRAY_SIZE(res_ids); ++i) {
183		if (nsim_fib_set_max(net, res_ids[i], (u64)-1)) {
184			pr_err("Failed to reset limit for resource %u\n",
185			       res_ids[i]);
186		}
187	}
188}
189
190static const struct devlink_ops nsim_devlink_ops = {
191	.reload = nsim_devlink_reload,
192};
193
194/* once devlink / namespace issues are sorted out
195 * this needs to be net in which a devlink instance
196 * is to be created. e.g., dev_net(ns->netdev)
197 */
198static struct net *nsim_to_net(struct netdevsim *ns)
199{
200	return &init_net;
201}
202
203void nsim_devlink_teardown(struct netdevsim *ns)
204{
205	if (ns->devlink) {
206		struct net *net = nsim_to_net(ns);
207		bool *reg_devlink = net_generic(net, nsim_devlink_id);
208
209		devlink_unregister(ns->devlink);
210		devlink_free(ns->devlink);
211		ns->devlink = NULL;
212
213		nsim_devlink_net_reset(net);
214		*reg_devlink = true;
215	}
216}
217
218int nsim_devlink_setup(struct netdevsim *ns)
219{
220	struct net *net = nsim_to_net(ns);
221	bool *reg_devlink = net_generic(net, nsim_devlink_id);
222	struct devlink *devlink;
223	int err;
224
225	/* only one device per namespace controls devlink */
226	if (!*reg_devlink) {
227		ns->devlink = NULL;
228		return 0;
229	}
230
231	devlink = devlink_alloc(&nsim_devlink_ops, 0);
232	if (!devlink)
233		return -ENOMEM;
234
235	err = devlink_register(devlink, &ns->dev);
236	if (err)
237		goto err_devlink_free;
238
239	err = devlink_resources_register(devlink);
240	if (err)
241		goto err_dl_unregister;
242
243	ns->devlink = devlink;
244
245	*reg_devlink = false;
246
247	return 0;
248
249err_dl_unregister:
250	devlink_unregister(devlink);
251err_devlink_free:
252	devlink_free(devlink);
253
254	return err;
255}
256
257/* Initialize per network namespace state */
258static int __net_init nsim_devlink_netns_init(struct net *net)
259{
260	bool *reg_devlink = net_generic(net, nsim_devlink_id);
261
262	*reg_devlink = true;
263
264	return 0;
265}
266
267static struct pernet_operations nsim_devlink_net_ops = {
268	.init = nsim_devlink_netns_init,
269	.id   = &nsim_devlink_id,
270	.size = sizeof(bool),
271};
272
273void nsim_devlink_exit(void)
274{
275	unregister_pernet_subsys(&nsim_devlink_net_ops);
276	nsim_fib_exit();
277}
278
279int nsim_devlink_init(void)
280{
281	int err;
282
283	err = nsim_fib_init();
284	if (err)
285		goto err_out;
286
287	err = register_pernet_subsys(&nsim_devlink_net_ops);
288	if (err)
289		nsim_fib_exit();
290
291err_out:
292	return err;
293}