@@ -232,9 +232,154 @@ del_device_store(const struct bus_type *bus, const char *buf, size_t count)
232
232
}
233
233
static BUS_ATTR_WO (del_device );
234
234
235
+ static ssize_t link_device_store (const struct bus_type * bus , const char * buf , size_t count )
236
+ {
237
+ struct netdevsim * nsim_a , * nsim_b , * peer ;
238
+ struct net_device * dev_a , * dev_b ;
239
+ unsigned int ifidx_a , ifidx_b ;
240
+ int netnsfd_a , netnsfd_b , err ;
241
+ struct net * ns_a , * ns_b ;
242
+
243
+ err = sscanf (buf , "%d:%u %d:%u" , & netnsfd_a , & ifidx_a , & netnsfd_b ,
244
+ & ifidx_b );
245
+ if (err != 4 ) {
246
+ pr_err ("Format for linking two devices is \"netnsfd_a:ifidx_a netnsfd_b:ifidx_b\" (int uint int uint).\n" );
247
+ return - EINVAL ;
248
+ }
249
+
250
+ ns_a = get_net_ns_by_fd (netnsfd_a );
251
+ if (IS_ERR (ns_a )) {
252
+ pr_err ("Could not find netns with fd: %d\n" , netnsfd_a );
253
+ return - EINVAL ;
254
+ }
255
+
256
+ ns_b = get_net_ns_by_fd (netnsfd_b );
257
+ if (IS_ERR (ns_b )) {
258
+ pr_err ("Could not find netns with fd: %d\n" , netnsfd_b );
259
+ put_net (ns_a );
260
+ return - EINVAL ;
261
+ }
262
+
263
+ err = - EINVAL ;
264
+ rtnl_lock ();
265
+ dev_a = __dev_get_by_index (ns_a , ifidx_a );
266
+ if (!dev_a ) {
267
+ pr_err ("Could not find device with ifindex %u in netnsfd %d\n" ,
268
+ ifidx_a , netnsfd_a );
269
+ goto out_err ;
270
+ }
271
+
272
+ if (!netdev_is_nsim (dev_a )) {
273
+ pr_err ("Device with ifindex %u in netnsfd %d is not a netdevsim\n" ,
274
+ ifidx_a , netnsfd_a );
275
+ goto out_err ;
276
+ }
277
+
278
+ dev_b = __dev_get_by_index (ns_b , ifidx_b );
279
+ if (!dev_b ) {
280
+ pr_err ("Could not find device with ifindex %u in netnsfd %d\n" ,
281
+ ifidx_b , netnsfd_b );
282
+ goto out_err ;
283
+ }
284
+
285
+ if (!netdev_is_nsim (dev_b )) {
286
+ pr_err ("Device with ifindex %u in netnsfd %d is not a netdevsim\n" ,
287
+ ifidx_b , netnsfd_b );
288
+ goto out_err ;
289
+ }
290
+
291
+ if (dev_a == dev_b ) {
292
+ pr_err ("Cannot link a netdevsim to itself\n" );
293
+ goto out_err ;
294
+ }
295
+
296
+ err = - EBUSY ;
297
+ nsim_a = netdev_priv (dev_a );
298
+ peer = rtnl_dereference (nsim_a -> peer );
299
+ if (peer ) {
300
+ pr_err ("Netdevsim %d:%u is already linked\n" , netnsfd_a ,
301
+ ifidx_a );
302
+ goto out_err ;
303
+ }
304
+
305
+ nsim_b = netdev_priv (dev_b );
306
+ peer = rtnl_dereference (nsim_b -> peer );
307
+ if (peer ) {
308
+ pr_err ("Netdevsim %d:%u is already linked\n" , netnsfd_b ,
309
+ ifidx_b );
310
+ goto out_err ;
311
+ }
312
+
313
+ err = 0 ;
314
+ rcu_assign_pointer (nsim_a -> peer , nsim_b );
315
+ rcu_assign_pointer (nsim_b -> peer , nsim_a );
316
+
317
+ out_err :
318
+ put_net (ns_b );
319
+ put_net (ns_a );
320
+ rtnl_unlock ();
321
+
322
+ return !err ? count : err ;
323
+ }
324
+ static BUS_ATTR_WO (link_device );
325
+
326
+ static ssize_t unlink_device_store (const struct bus_type * bus , const char * buf , size_t count )
327
+ {
328
+ struct netdevsim * nsim , * peer ;
329
+ struct net_device * dev ;
330
+ unsigned int ifidx ;
331
+ int netnsfd , err ;
332
+ struct net * ns ;
333
+
334
+ err = sscanf (buf , "%u:%u" , & netnsfd , & ifidx );
335
+ if (err != 2 ) {
336
+ pr_err ("Format for unlinking a device is \"netnsfd:ifidx\" (int uint).\n" );
337
+ return - EINVAL ;
338
+ }
339
+
340
+ ns = get_net_ns_by_fd (netnsfd );
341
+ if (IS_ERR (ns )) {
342
+ pr_err ("Could not find netns with fd: %d\n" , netnsfd );
343
+ return - EINVAL ;
344
+ }
345
+
346
+ err = - EINVAL ;
347
+ rtnl_lock ();
348
+ dev = __dev_get_by_index (ns , ifidx );
349
+ if (!dev ) {
350
+ pr_err ("Could not find device with ifindex %u in netnsfd %d\n" ,
351
+ ifidx , netnsfd );
352
+ goto out_put_netns ;
353
+ }
354
+
355
+ if (!netdev_is_nsim (dev )) {
356
+ pr_err ("Device with ifindex %u in netnsfd %d is not a netdevsim\n" ,
357
+ ifidx , netnsfd );
358
+ goto out_put_netns ;
359
+ }
360
+
361
+ nsim = netdev_priv (dev );
362
+ peer = rtnl_dereference (nsim -> peer );
363
+ if (!peer )
364
+ goto out_put_netns ;
365
+
366
+ err = 0 ;
367
+ RCU_INIT_POINTER (nsim -> peer , NULL );
368
+ RCU_INIT_POINTER (peer -> peer , NULL );
369
+
370
+ out_put_netns :
371
+ put_net (ns );
372
+ rtnl_unlock ();
373
+
374
+ return !err ? count : err ;
375
+ }
376
+ static BUS_ATTR_WO (unlink_device );
377
+
235
378
static struct attribute * nsim_bus_attrs [] = {
236
379
& bus_attr_new_device .attr ,
237
380
& bus_attr_del_device .attr ,
381
+ & bus_attr_link_device .attr ,
382
+ & bus_attr_unlink_device .attr ,
238
383
NULL
239
384
};
240
385
ATTRIBUTE_GROUPS (nsim_bus );
0 commit comments