diff mbox series

[net-next,v2,15/16] netdevsim: move netdev creation/destruction to dev probe

Message ID 20190420102922.6001-16-jiri@resnulli.us
State Changes Requested
Delegated to: David Miller
Headers show
Series netdevsim: impement proper device model | expand

Commit Message

Jiri Pirko April 20, 2019, 10:29 a.m. UTC
From: Jiri Pirko <jiri@mellanox.com>

Remove the existing way to create netdevsim over rtnetlink and move the
netdev creation/destruction to dev probe, so for every probed port,
a netdevsim-netdev instance is created.

Adjust selftests to work with new interface.

Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
v1->v2:
- rebased
- used new del_port attr to allow original multi test
rfc->v1:
- adjusted all selftests
---
 drivers/net/netdevsim/bpf.c                 |  13 +-
 drivers/net/netdevsim/bus.c                 |  25 +--
 drivers/net/netdevsim/dev.c                 |  13 +-
 drivers/net/netdevsim/ipsec.c               |   3 +-
 drivers/net/netdevsim/netdev.c              | 138 +++++---------
 drivers/net/netdevsim/netdevsim.h           |  11 +-
 tools/testing/selftests/bpf/test_offload.py | 195 ++++++++++++--------
 tools/testing/selftests/net/rtnetlink.sh    |   6 +-
 8 files changed, 207 insertions(+), 197 deletions(-)

Comments

Jakub Kicinski April 22, 2019, 7:31 p.m. UTC | #1
On Sat, 20 Apr 2019 12:29:21 +0200, Jiri Pirko wrote:
> diff --git a/tools/testing/selftests/bpf/test_offload.py b/tools/testing/selftests/bpf/test_offload.py
> index 5f2e4f9e70e4..a0566dcf064a 100755
> --- a/tools/testing/selftests/bpf/test_offload.py
> +++ b/tools/testing/selftests/bpf/test_offload.py
> @@ -1,6 +1,7 @@
>  #!/usr/bin/python3
>  
>  # Copyright (C) 2017 Netronome Systems, Inc.
> +# Copyright (c) 2019 Mellanox Technologies. All rights reserved

What's your guiding principle with adding those copyright lines
everywhere?

>  # This software is licensed under the GNU General License Version 2,
>  # June 1991 as shown in the file COPYING in the top-level directory of this
> @@ -24,6 +25,7 @@ import struct
>  import subprocess
>  import time
>  import traceback
> +import errno

aphabetic order.

>  
>  logfile = None
>  log_level = 1
> @@ -323,42 +325,85 @@ class DebugfsDir:
>  
>          return dfs
>  
> -class NetdevSim:
> +class NetdevSimDev:
>      """
> -    Class for netdevsim netdevice and its attributes.
> +    Class for netdevsim bus device and its attributes.
>      """
>  
> -    def __init__(self, link=None):
> -        self.link = link
> +    def __init__(self, port_count=1):
> +        addr = 0
> +        while True:
> +            try:
> +                with open("/sys/bus/netdevsim/new_device","w") as f:

space after ,

> +                    f.write("%u %u" % (addr, port_count))
> +            except OSError as e:
> +                if e.errno == errno.ENOSPC:
> +                    addr += 1
> +                    continue
> +                raise e
> +            break
>  
> -        self.dev = self._netdevsim_create()
>          devs.append(self)
> +        self.addr = addr
> +        self.dfs_dir = "/sys/kernel/debug/netdevsim/netdevsim%u/" % addr
>  
> -        self.ns = ""
> +        self.nsims = []
> +        for port_index in range(port_count):
> +            self.nsims.append(NetdevSim(self, port_index))
>  
> -        self.dfs_dir = '/sys/kernel/debug/netdevsim/netdevsim0/ports/0/'
> -        self.dev_dir = self.dfs_dir + '/dev/'
> -        self.dfs_refresh()
> +    def dfs_num_bound_progs(self):
> +        path = os.path.join(self.dfs_dir, "bpf_bound_progs")
> +        _, progs = cmd('ls %s' % (path))
> +        return len(progs.split())
>  
> -    def __getitem__(self, key):
> -        return self.dev[key]
> +    def dfs_get_bound_progs(self, expected):
> +        progs = DebugfsDir(os.path.join(self.dfs_dir, "bpf_bound_progs"))
> +        if expected is not None:
> +            if len(progs) != expected:
> +                fail(True, "%d BPF programs bound, expected %d" %
> +                     (len(progs), expected))
> +        return progs
>  
> -    def _netdevsim_create(self):
> -        link = "" if self.link is None else "link " + self.link.dev['ifname']
> -        _, old  = ip("link show")
> -        ip("link add sim%d {link} type netdevsim".format(link=link))
> -        _, new  = ip("link show")
> +    def remove(self):
> +        with open("/sys/bus/netdevsim/del_device","w") as f:

and here, etc.

> +            f.write("%u" % self.addr)
> +        devs.remove(self)
>  
> -        for dev in new:
> -            f = filter(lambda x: x["ifname"] == dev["ifname"], old)
> -            if len(list(f)) == 0:
> -                return dev
> +    def remove_nsim(self, nsim):
> +        self.nsims.remove(nsim)
> +        with open("/sys/bus/netdevsim/devices/netdevsim%u/del_port" % self.addr ,"w") as f:
> +            f.write("%u" % nsim.port_index)
>  
> -        raise Exception("failed to create netdevsim device")
> +class NetdevSim:
> +    """
> +    Class for netdevsim netdevice and its attributes.
> +    """
> +
> +    def __init__(self, nsimdev, port_index):
> +        self.nsimdev = nsimdev
> +        self.port_index = port_index
> +        self.ns = ""
> +        self.dfs_dir = "%s/ports/%u/" % (nsimdev.dfs_dir, port_index)
> +        self.dfs_refresh()
> +
> +        ifname = "eni%unp%u" % (nsimdev.addr, port_index + 1)
> +        timeout = 0.5
> +        timeout_start = time.time()
> +
> +        while True:
> +            try:
> +                _, [self.dev] = ip("link show dev %s" % ifname)
> +            except Exception as e:
> +                if time.time() < timeout_start + timeout:
> +                    continue
> +                raise e
> +            break

udevadm settle?  The reliance on latest systemd is a real bad idea,
could you fall back to netdevsimX names if eni$SOME$CUFT is not found?

> +    def __getitem__(self, key):
> +        return self.dev[key]
>  
>      def remove(self):
> -        devs.remove(self)
> -        ip("link del dev %s" % (self.dev["ifname"]), ns=self.ns)
> +        self.nsimdev.remove_nsim(self)
>  
>      def dfs_refresh(self):
>          self.dfs = DebugfsDir(self.dfs_dir)
Jiri Pirko April 23, 2019, 7:20 a.m. UTC | #2
Mon, Apr 22, 2019 at 09:31:33PM CEST, jakub.kicinski@netronome.com wrote:
>On Sat, 20 Apr 2019 12:29:21 +0200, Jiri Pirko wrote:
>> diff --git a/tools/testing/selftests/bpf/test_offload.py b/tools/testing/selftests/bpf/test_offload.py
>> index 5f2e4f9e70e4..a0566dcf064a 100755
>> --- a/tools/testing/selftests/bpf/test_offload.py
>> +++ b/tools/testing/selftests/bpf/test_offload.py
>> @@ -1,6 +1,7 @@
>>  #!/usr/bin/python3
>>  
>>  # Copyright (C) 2017 Netronome Systems, Inc.
>> +# Copyright (c) 2019 Mellanox Technologies. All rights reserved
>
>What's your guiding principle with adding those copyright lines
>everywhere?

Semi-random :) I can remove it if you want.


>
>>  # This software is licensed under the GNU General License Version 2,
>>  # June 1991 as shown in the file COPYING in the top-level directory of this
>> @@ -24,6 +25,7 @@ import struct
>>  import subprocess
>>  import time
>>  import traceback
>> +import errno
>
>aphabetic order.

Ok.


>
>>  
>>  logfile = None
>>  log_level = 1
>> @@ -323,42 +325,85 @@ class DebugfsDir:
>>  
>>          return dfs
>>  
>> -class NetdevSim:
>> +class NetdevSimDev:
>>      """
>> -    Class for netdevsim netdevice and its attributes.
>> +    Class for netdevsim bus device and its attributes.
>>      """
>>  
>> -    def __init__(self, link=None):
>> -        self.link = link
>> +    def __init__(self, port_count=1):
>> +        addr = 0
>> +        while True:
>> +            try:
>> +                with open("/sys/bus/netdevsim/new_device","w") as f:
>
>space after ,

Ok.


>
>> +                    f.write("%u %u" % (addr, port_count))
>> +            except OSError as e:
>> +                if e.errno == errno.ENOSPC:
>> +                    addr += 1
>> +                    continue
>> +                raise e
>> +            break
>>  
>> -        self.dev = self._netdevsim_create()
>>          devs.append(self)
>> +        self.addr = addr
>> +        self.dfs_dir = "/sys/kernel/debug/netdevsim/netdevsim%u/" % addr
>>  
>> -        self.ns = ""
>> +        self.nsims = []
>> +        for port_index in range(port_count):
>> +            self.nsims.append(NetdevSim(self, port_index))
>>  
>> -        self.dfs_dir = '/sys/kernel/debug/netdevsim/netdevsim0/ports/0/'
>> -        self.dev_dir = self.dfs_dir + '/dev/'
>> -        self.dfs_refresh()
>> +    def dfs_num_bound_progs(self):
>> +        path = os.path.join(self.dfs_dir, "bpf_bound_progs")
>> +        _, progs = cmd('ls %s' % (path))
>> +        return len(progs.split())
>>  
>> -    def __getitem__(self, key):
>> -        return self.dev[key]
>> +    def dfs_get_bound_progs(self, expected):
>> +        progs = DebugfsDir(os.path.join(self.dfs_dir, "bpf_bound_progs"))
>> +        if expected is not None:
>> +            if len(progs) != expected:
>> +                fail(True, "%d BPF programs bound, expected %d" %
>> +                     (len(progs), expected))
>> +        return progs
>>  
>> -    def _netdevsim_create(self):
>> -        link = "" if self.link is None else "link " + self.link.dev['ifname']
>> -        _, old  = ip("link show")
>> -        ip("link add sim%d {link} type netdevsim".format(link=link))
>> -        _, new  = ip("link show")
>> +    def remove(self):
>> +        with open("/sys/bus/netdevsim/del_device","w") as f:
>
>and here, etc.

ok


>
>> +            f.write("%u" % self.addr)
>> +        devs.remove(self)
>>  
>> -        for dev in new:
>> -            f = filter(lambda x: x["ifname"] == dev["ifname"], old)
>> -            if len(list(f)) == 0:
>> -                return dev
>> +    def remove_nsim(self, nsim):
>> +        self.nsims.remove(nsim)
>> +        with open("/sys/bus/netdevsim/devices/netdevsim%u/del_port" % self.addr ,"w") as f:
>> +            f.write("%u" % nsim.port_index)
>>  
>> -        raise Exception("failed to create netdevsim device")
>> +class NetdevSim:
>> +    """
>> +    Class for netdevsim netdevice and its attributes.
>> +    """
>> +
>> +    def __init__(self, nsimdev, port_index):
>> +        self.nsimdev = nsimdev
>> +        self.port_index = port_index
>> +        self.ns = ""
>> +        self.dfs_dir = "%s/ports/%u/" % (nsimdev.dfs_dir, port_index)
>> +        self.dfs_refresh()
>> +
>> +        ifname = "eni%unp%u" % (nsimdev.addr, port_index + 1)
>> +        timeout = 0.5
>> +        timeout_start = time.time()
>> +
>> +        while True:
>> +            try:
>> +                _, [self.dev] = ip("link show dev %s" % ifname)
>> +            except Exception as e:
>> +                if time.time() < timeout_start + timeout:
>> +                    continue
>> +                raise e
>> +            break
>
>udevadm settle?  The reliance on latest systemd is a real bad idea,

Not sure that "udevadm settle" would help here. The diver bus probe handle
may be executed from a workqueue, so here, there might be the udev event
queue empty yet still the netdev is not present.


>could you fall back to netdevsimX names if eni$SOME$CUFT is not found?

That would not help. If you have udev which does not support this, you
are going to endup with "eth0, eth1, .."


>
>> +    def __getitem__(self, key):
>> +        return self.dev[key]
>>  
>>      def remove(self):
>> -        devs.remove(self)
>> -        ip("link del dev %s" % (self.dev["ifname"]), ns=self.ns)
>> +        self.nsimdev.remove_nsim(self)
>>  
>>      def dfs_refresh(self):
>>          self.dfs = DebugfsDir(self.dfs_dir)
Jakub Kicinski April 23, 2019, 5:05 p.m. UTC | #3
On Tue, 23 Apr 2019 09:20:14 +0200, Jiri Pirko wrote:
> Mon, Apr 22, 2019 at 09:31:33PM CEST, jakub.kicinski@netronome.com wrote:
> >On Sat, 20 Apr 2019 12:29:21 +0200, Jiri Pirko wrote:  
> >> diff --git a/tools/testing/selftests/bpf/test_offload.py b/tools/testing/selftests/bpf/test_offload.py
> >> index 5f2e4f9e70e4..a0566dcf064a 100755
> >> --- a/tools/testing/selftests/bpf/test_offload.py
> >> +++ b/tools/testing/selftests/bpf/test_offload.py
> >> @@ -1,6 +1,7 @@
> >>  #!/usr/bin/python3
> >>  
> >>  # Copyright (C) 2017 Netronome Systems, Inc.
> >> +# Copyright (c) 2019 Mellanox Technologies. All rights reserved  
> >
> >What's your guiding principle with adding those copyright lines
> >everywhere?  
> 
> Semi-random :) I can remove it if you want.

Technically I have no opinion, personally I find it petty and
unnecessary in the git era..  Probably not worth your time now 
to go and remove :)

> >> +class NetdevSim:
> >> +    """
> >> +    Class for netdevsim netdevice and its attributes.
> >> +    """
> >> +
> >> +    def __init__(self, nsimdev, port_index):
> >> +        self.nsimdev = nsimdev
> >> +        self.port_index = port_index
> >> +        self.ns = ""
> >> +        self.dfs_dir = "%s/ports/%u/" % (nsimdev.dfs_dir, port_index)
> >> +        self.dfs_refresh()
> >> +
> >> +        ifname = "eni%unp%u" % (nsimdev.addr, port_index + 1)
> >> +        timeout = 0.5
> >> +        timeout_start = time.time()
> >> +
> >> +        while True:
> >> +            try:
> >> +                _, [self.dev] = ip("link show dev %s" % ifname)
> >> +            except Exception as e:
> >> +                if time.time() < timeout_start + timeout:
> >> +                    continue
> >> +                raise e
> >> +            break  
> >
> >udevadm settle?  The reliance on latest systemd is a real bad idea,  
> 
> Not sure that "udevadm settle" would help here. The diver bus probe handle
> may be executed from a workqueue, so here, there might be the udev event
> queue empty yet still the netdev is not present.

Mm.. true.  I must say I had a ton of issues with this in Netronome
test systems, those "wait for renames" loop always broke no matter
what..  OS upgrade, adding debug stuff into the kernel..  I get
flashbacks.  I've seen udev easily take 20s to rename on a heavy kernel.
Since we replaced the loops with udevadm settle - it's been a bliss.  
YMMV but in my experience regardless of workqueues and all udev is way
more reliable.

> >could you fall back to netdevsimX names if eni$SOME$CUFT is not found?  
> 
> That would not help. If you have udev which does not support this, you
> are going to endup with "eth0, eth1, .."

That is not great :(  The kbuild bot runs BPF offload tests, they run
with some CentOS user space.  If we don't want to name the device in
the kernel, perhaps it'd be possible to scan sysfs?  The ifc names
should be under $device/net/, right?
Jiri Pirko April 23, 2019, 7:14 p.m. UTC | #4
Tue, Apr 23, 2019 at 07:05:28PM CEST, jakub.kicinski@netronome.com wrote:
>On Tue, 23 Apr 2019 09:20:14 +0200, Jiri Pirko wrote:
>> Mon, Apr 22, 2019 at 09:31:33PM CEST, jakub.kicinski@netronome.com wrote:
>> >On Sat, 20 Apr 2019 12:29:21 +0200, Jiri Pirko wrote:  
>> >> diff --git a/tools/testing/selftests/bpf/test_offload.py b/tools/testing/selftests/bpf/test_offload.py
>> >> index 5f2e4f9e70e4..a0566dcf064a 100755
>> >> --- a/tools/testing/selftests/bpf/test_offload.py
>> >> +++ b/tools/testing/selftests/bpf/test_offload.py
>> >> @@ -1,6 +1,7 @@
>> >>  #!/usr/bin/python3
>> >>  
>> >>  # Copyright (C) 2017 Netronome Systems, Inc.
>> >> +# Copyright (c) 2019 Mellanox Technologies. All rights reserved  
>> >
>> >What's your guiding principle with adding those copyright lines
>> >everywhere?  
>> 
>> Semi-random :) I can remove it if you want.
>
>Technically I have no opinion, personally I find it petty and
>unnecessary in the git era..  Probably not worth your time now 
>to go and remove :)
>
>> >> +class NetdevSim:
>> >> +    """
>> >> +    Class for netdevsim netdevice and its attributes.
>> >> +    """
>> >> +
>> >> +    def __init__(self, nsimdev, port_index):
>> >> +        self.nsimdev = nsimdev
>> >> +        self.port_index = port_index
>> >> +        self.ns = ""
>> >> +        self.dfs_dir = "%s/ports/%u/" % (nsimdev.dfs_dir, port_index)
>> >> +        self.dfs_refresh()
>> >> +
>> >> +        ifname = "eni%unp%u" % (nsimdev.addr, port_index + 1)
>> >> +        timeout = 0.5
>> >> +        timeout_start = time.time()
>> >> +
>> >> +        while True:
>> >> +            try:
>> >> +                _, [self.dev] = ip("link show dev %s" % ifname)
>> >> +            except Exception as e:
>> >> +                if time.time() < timeout_start + timeout:
>> >> +                    continue
>> >> +                raise e
>> >> +            break  
>> >
>> >udevadm settle?  The reliance on latest systemd is a real bad idea,  
>> 
>> Not sure that "udevadm settle" would help here. The diver bus probe handle
>> may be executed from a workqueue, so here, there might be the udev event
>> queue empty yet still the netdev is not present.
>
>Mm.. true.  I must say I had a ton of issues with this in Netronome
>test systems, those "wait for renames" loop always broke no matter
>what..  OS upgrade, adding debug stuff into the kernel..  I get
>flashbacks.  I've seen udev easily take 20s to rename on a heavy kernel.
>Since we replaced the loops with udevadm settle - it's been a bliss.  
>YMMV but in my experience regardless of workqueues and all udev is way
>more reliable.

Sure, But I don't see how udevadm settle would help here. Hmm but
perhaps I can poll sysfs until the device appears there and then I can
udevadm settle.


>
>> >could you fall back to netdevsimX names if eni$SOME$CUFT is not found?  
>> 
>> That would not help. If you have udev which does not support this, you
>> are going to endup with "eth0, eth1, .."
>
>That is not great :(  The kbuild bot runs BPF offload tests, they run
>with some CentOS user space.  If we don't want to name the device in
>the kernel, perhaps it'd be possible to scan sysfs?  The ifc names
>should be under $device/net/, right?

Yeah, hmm. I'll think about it and fix. Thanks!
diff mbox series

Patch

diff --git a/drivers/net/netdevsim/bpf.c b/drivers/net/netdevsim/bpf.c
index 89980b223adc..2b74425822ab 100644
--- a/drivers/net/netdevsim/bpf.c
+++ b/drivers/net/netdevsim/bpf.c
@@ -612,6 +612,7 @@  void nsim_bpf_dev_exit(struct nsim_dev *nsim_dev)
 
 int nsim_bpf_init(struct netdevsim *ns)
 {
+	struct dentry *ddir = ns->nsim_dev_port->ddir;
 	int err;
 
 	err = bpf_offload_dev_netdev_register(ns->nsim_dev->bpf_dev,
@@ -619,23 +620,23 @@  int nsim_bpf_init(struct netdevsim *ns)
 	if (err)
 		return err;
 
-	debugfs_create_u32("bpf_offloaded_id", 0400, ns->ddir,
+	debugfs_create_u32("bpf_offloaded_id", 0400, ddir,
 			   &ns->bpf_offloaded_id);
 
 	ns->bpf_tc_accept = true;
-	debugfs_create_bool("bpf_tc_accept", 0600, ns->ddir,
+	debugfs_create_bool("bpf_tc_accept", 0600, ddir,
 			    &ns->bpf_tc_accept);
-	debugfs_create_bool("bpf_tc_non_bound_accept", 0600, ns->ddir,
+	debugfs_create_bool("bpf_tc_non_bound_accept", 0600, ddir,
 			    &ns->bpf_tc_non_bound_accept);
 	ns->bpf_xdpdrv_accept = true;
-	debugfs_create_bool("bpf_xdpdrv_accept", 0600, ns->ddir,
+	debugfs_create_bool("bpf_xdpdrv_accept", 0600, ddir,
 			    &ns->bpf_xdpdrv_accept);
 	ns->bpf_xdpoffload_accept = true;
-	debugfs_create_bool("bpf_xdpoffload_accept", 0600, ns->ddir,
+	debugfs_create_bool("bpf_xdpoffload_accept", 0600, ddir,
 			    &ns->bpf_xdpoffload_accept);
 
 	ns->bpf_map_accept = true;
-	debugfs_create_bool("bpf_map_accept", 0600, ns->ddir,
+	debugfs_create_bool("bpf_map_accept", 0600, ddir,
 			    &ns->bpf_map_accept);
 
 	return 0;
diff --git a/drivers/net/netdevsim/bus.c b/drivers/net/netdevsim/bus.c
index af0208a68931..7a723aba513c 100644
--- a/drivers/net/netdevsim/bus.c
+++ b/drivers/net/netdevsim/bus.c
@@ -151,6 +151,9 @@  static struct device_type nsim_bus_dev_type = {
 	.release = nsim_bus_dev_release,
 };
 
+static struct nsim_bus_dev *nsim_bus_dev_new(unsigned int id,
+					     unsigned int port_count);
+
 static ssize_t new_device_store(struct bus_type *bus, const char *buf,
 				size_t count)
 {
@@ -186,6 +189,8 @@  static ssize_t new_device_store(struct bus_type *bus, const char *buf,
 }
 static BUS_ATTR_WO(new_device);
 
+static void nsim_bus_dev_del(struct nsim_bus_dev *nsim_bus_dev);
+
 static ssize_t del_device_store(struct bus_type *bus, const char *buf,
 				size_t count)
 {
@@ -259,7 +264,8 @@  static struct bus_type nsim_bus = {
 	.num_vf		= nsim_num_vf,
 };
 
-struct nsim_bus_dev *nsim_bus_dev_new(unsigned int id, unsigned int port_count)
+static struct nsim_bus_dev *nsim_bus_dev_new(unsigned int id,
+					     unsigned int port_count)
 {
 	struct nsim_bus_dev *nsim_bus_dev;
 	int err;
@@ -268,8 +274,7 @@  struct nsim_bus_dev *nsim_bus_dev_new(unsigned int id, unsigned int port_count)
 	if (!nsim_bus_dev)
 		return ERR_PTR(-ENOMEM);
 
-	err = ida_alloc_range(&nsim_bus_dev_ids,
-			      id == ~0 ? 0 : id, id, GFP_KERNEL);
+	err = ida_alloc_range(&nsim_bus_dev_ids, id, id, GFP_KERNEL);
 	if (err < 0)
 		goto err_nsim_bus_dev_free;
 	nsim_bus_dev->dev.id = err;
@@ -289,19 +294,7 @@  struct nsim_bus_dev *nsim_bus_dev_new(unsigned int id, unsigned int port_count)
 	return ERR_PTR(err);
 }
 
-struct nsim_bus_dev *nsim_bus_dev_new_with_ns(struct netdevsim *ns)
-{
-	struct nsim_bus_dev *nsim_bus_dev;
-
-	dev_hold(ns->netdev);
-	rtnl_unlock();
-	nsim_bus_dev = nsim_bus_dev_new(~0, 0);
-	rtnl_lock();
-	dev_put(ns->netdev);
-	return nsim_bus_dev;
-}
-
-void nsim_bus_dev_del(struct nsim_bus_dev *nsim_bus_dev)
+static void nsim_bus_dev_del(struct nsim_bus_dev *nsim_bus_dev)
 {
 	device_unregister(&nsim_bus_dev->dev);
 	ida_free(&nsim_bus_dev_ids, nsim_bus_dev->dev.id);
diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c
index c51142d5e140..3b155feb2761 100644
--- a/drivers/net/netdevsim/dev.c
+++ b/drivers/net/netdevsim/dev.c
@@ -278,7 +278,7 @@  static struct nsim_dev *nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev,
 	return ERR_PTR(err);
 }
 
-void nsim_dev_destroy(struct nsim_dev *nsim_dev)
+static void nsim_dev_destroy(struct nsim_dev *nsim_dev)
 {
 	struct devlink *devlink = priv_to_devlink(nsim_dev);
 
@@ -317,10 +317,19 @@  static int __nsim_dev_port_add(struct nsim_dev *nsim_dev,
 	if (err)
 		goto err_dl_port_unregister;
 
+	nsim_dev_port->ns = nsim_create(nsim_dev, nsim_dev_port);
+	if (IS_ERR(nsim_dev_port->ns)) {
+		err = PTR_ERR(nsim_dev_port->ns);
+		goto err_port_debugfs_exit;
+	}
+
+	devlink_port_type_eth_set(devlink_port, nsim_dev_port->ns->netdev);
 	list_add(&nsim_dev_port->list, &nsim_dev->port_list);
 
 	return 0;
 
+err_port_debugfs_exit:
+	nsim_dev_port_debugfs_exit(nsim_dev_port);
 err_dl_port_unregister:
 	devlink_port_unregister(devlink_port);
 err_port_free:
@@ -333,6 +342,8 @@  static void __nsim_dev_port_del(struct nsim_dev_port *nsim_dev_port)
 	struct devlink_port *devlink_port = &nsim_dev_port->devlink_port;
 
 	list_del(&nsim_dev_port->list);
+	devlink_port_type_clear(devlink_port);
+	nsim_destroy(nsim_dev_port->ns);
 	nsim_dev_port_debugfs_exit(nsim_dev_port);
 	devlink_port_unregister(devlink_port);
 	kfree(nsim_dev_port);
diff --git a/drivers/net/netdevsim/ipsec.c b/drivers/net/netdevsim/ipsec.c
index 76e11d889bb6..e27fc1a4516d 100644
--- a/drivers/net/netdevsim/ipsec.c
+++ b/drivers/net/netdevsim/ipsec.c
@@ -283,7 +283,8 @@  void nsim_ipsec_init(struct netdevsim *ns)
 	ns->netdev->features |= NSIM_ESP_FEATURES;
 	ns->netdev->hw_enc_features |= NSIM_ESP_FEATURES;
 
-	ns->ipsec.pfile = debugfs_create_file("ipsec", 0400, ns->ddir, ns,
+	ns->ipsec.pfile = debugfs_create_file("ipsec", 0400,
+					      ns->nsim_dev_port->ddir, ns,
 					      &ipsec_dbg_fops);
 }
 
diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c
index 99169fe521f2..38ebf846ed49 100644
--- a/drivers/net/netdevsim/netdev.c
+++ b/drivers/net/netdevsim/netdev.c
@@ -25,59 +25,6 @@ 
 
 #include "netdevsim.h"
 
-static int nsim_get_port_parent_id(struct net_device *dev,
-				   struct netdev_phys_item_id *ppid)
-{
-	struct netdevsim *ns = netdev_priv(dev);
-
-	memcpy(ppid, &ns->nsim_dev->switch_id, sizeof(*ppid));
-	return 0;
-}
-
-static int nsim_init(struct net_device *dev)
-{
-	struct netdevsim *ns = netdev_priv(dev);
-	char dev_link_name[32];
-	int err;
-
-	ns->ddir = debugfs_create_dir("0", ns->nsim_dev->ports_ddir);
-	if (IS_ERR_OR_NULL(ns->ddir))
-		return -ENOMEM;
-
-	sprintf(dev_link_name, "../../../" DRV_NAME "%u",
-		ns->nsim_dev->nsim_bus_dev->dev.id);
-	debugfs_create_symlink("dev", ns->ddir, dev_link_name);
-
-	err = nsim_bpf_init(ns);
-	if (err)
-		goto err_debugfs_destroy;
-
-	nsim_ipsec_init(ns);
-
-	return 0;
-
-err_debugfs_destroy:
-	debugfs_remove_recursive(ns->ddir);
-	return err;
-}
-
-static void nsim_uninit(struct net_device *dev)
-{
-	struct netdevsim *ns = netdev_priv(dev);
-
-	nsim_ipsec_teardown(ns);
-	debugfs_remove_recursive(ns->ddir);
-	nsim_bpf_uninit(ns);
-}
-
-static void nsim_free(struct net_device *dev)
-{
-	struct netdevsim *ns = netdev_priv(dev);
-
-	nsim_bus_dev_del(ns->nsim_bus_dev);
-	/* netdev and vf state will be freed out of device_release() */
-}
-
 static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct netdevsim *ns = netdev_priv(dev);
@@ -299,8 +246,6 @@  nsim_set_features(struct net_device *dev, netdev_features_t features)
 }
 
 static const struct net_device_ops nsim_netdev_ops = {
-	.ndo_init		= nsim_init,
-	.ndo_uninit		= nsim_uninit,
 	.ndo_start_xmit		= nsim_start_xmit,
 	.ndo_set_rx_mode	= nsim_set_rx_mode,
 	.ndo_set_mac_address	= eth_mac_addr,
@@ -318,7 +263,6 @@  static const struct net_device_ops nsim_netdev_ops = {
 	.ndo_setup_tc		= nsim_setup_tc,
 	.ndo_set_features	= nsim_set_features,
 	.ndo_bpf		= nsim_bpf,
-	.ndo_get_port_parent_id	= nsim_get_port_parent_id,
 };
 
 static void nsim_setup(struct net_device *dev)
@@ -326,10 +270,6 @@  static void nsim_setup(struct net_device *dev)
 	ether_setup(dev);
 	eth_hw_addr_random(dev);
 
-	dev->netdev_ops = &nsim_netdev_ops;
-	dev->needs_free_netdev = true;
-	dev->priv_destructor = nsim_free;
-
 	dev->tx_queue_len = 0;
 	dev->flags |= IFF_NOARP;
 	dev->flags &= ~IFF_MULTICAST;
@@ -344,50 +284,70 @@  static void nsim_setup(struct net_device *dev)
 	dev->max_mtu = ETH_MAX_MTU;
 }
 
-static int nsim_validate(struct nlattr *tb[], struct nlattr *data[],
-			 struct netlink_ext_ack *extack)
-{
-	if (tb[IFLA_ADDRESS]) {
-		if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
-			return -EINVAL;
-		if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
-			return -EADDRNOTAVAIL;
-	}
-	return 0;
-}
-
-static int nsim_newlink(struct net *src_net, struct net_device *dev,
-			struct nlattr *tb[], struct nlattr *data[],
-			struct netlink_ext_ack *extack)
+struct netdevsim *nsim_create(struct nsim_dev *nsim_dev,
+			      struct nsim_dev_port *nsim_dev_port)
 {
-	struct netdevsim *ns = netdev_priv(dev);
+	struct net_device *dev;
+	struct netdevsim *ns;
 	int err;
 
-	ns->netdev = dev;
-	ns->nsim_bus_dev = nsim_bus_dev_new_with_ns(ns);
-	if (IS_ERR(ns->nsim_bus_dev))
-		return PTR_ERR(ns->nsim_bus_dev);
+	dev = alloc_netdev(sizeof(*ns), "eth%d", NET_NAME_UNKNOWN, nsim_setup);
+	if (!dev)
+		return ERR_PTR(-ENOMEM);
 
+	ns = netdev_priv(dev);
+	ns->netdev = dev;
+	ns->nsim_dev = nsim_dev;
+	ns->nsim_dev_port = nsim_dev_port;
+	ns->nsim_bus_dev = nsim_dev->nsim_bus_dev;
 	SET_NETDEV_DEV(dev, &ns->nsim_bus_dev->dev);
+	dev->netdev_ops = &nsim_netdev_ops;
 
-	ns->nsim_dev = dev_get_drvdata(&ns->nsim_bus_dev->dev);
+	rtnl_lock();
+	err = nsim_bpf_init(ns);
+	if (err)
+		goto err_free_netdev;
+
+	nsim_ipsec_init(ns);
 
 	err = register_netdevice(dev);
 	if (err)
-		goto err_dev_del;
-	return 0;
+		goto err_ipsec_teardown;
+	rtnl_unlock();
 
-err_dev_del:
-	nsim_bus_dev_del(ns->nsim_bus_dev);
-	return err;
+	return ns;
+
+err_ipsec_teardown:
+	nsim_ipsec_teardown(ns);
+	nsim_bpf_uninit(ns);
+	rtnl_unlock();
+err_free_netdev:
+	free_netdev(dev);
+	return ERR_PTR(err);
+}
+
+void nsim_destroy(struct netdevsim *ns)
+{
+	struct net_device *dev = ns->netdev;
+
+	rtnl_lock();
+	unregister_netdevice(dev);
+	nsim_ipsec_teardown(ns);
+	nsim_bpf_uninit(ns);
+	rtnl_unlock();
+	free_netdev(dev);
+}
+
+static int nsim_validate(struct nlattr *tb[], struct nlattr *data[],
+			 struct netlink_ext_ack *extack)
+{
+	NL_SET_ERR_MSG_MOD(extack, "Please use: echo \"[ID] [PORT_COUNT]\" > /sys/bus/netdevsim/new_device");
+	return -EOPNOTSUPP;
 }
 
 static struct rtnl_link_ops nsim_link_ops __read_mostly = {
 	.kind		= DRV_NAME,
-	.priv_size	= sizeof(struct netdevsim),
-	.setup		= nsim_setup,
 	.validate	= nsim_validate,
-	.newlink	= nsim_newlink,
 };
 
 static int __init nsim_module_init(void)
diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h
index 6b60589cab91..c2b23e5e01ab 100644
--- a/drivers/net/netdevsim/netdevsim.h
+++ b/drivers/net/netdevsim/netdevsim.h
@@ -51,6 +51,7 @@  struct nsim_ipsec {
 struct netdevsim {
 	struct net_device *netdev;
 	struct nsim_dev *nsim_dev;
+	struct nsim_dev_port *nsim_dev_port;
 
 	u64 tx_packets;
 	u64 tx_bytes;
@@ -58,8 +59,6 @@  struct netdevsim {
 
 	struct nsim_bus_dev *nsim_bus_dev;
 
-	struct dentry *ddir;
-
 	struct bpf_prog	*bpf_offloaded;
 	u32 bpf_offloaded_id;
 
@@ -75,6 +74,10 @@  struct netdevsim {
 	struct nsim_ipsec ipsec;
 };
 
+struct netdevsim *nsim_create(struct nsim_dev *nsim_dev,
+			      struct nsim_dev_port *nsim_dev_port);
+void nsim_destroy(struct netdevsim *ns);
+
 #ifdef CONFIG_BPF_SYSCALL
 int nsim_bpf_dev_init(struct nsim_dev *nsim_dev);
 void nsim_bpf_dev_exit(struct nsim_dev *nsim_dev);
@@ -136,6 +139,7 @@  struct nsim_dev_port {
 	struct devlink_port devlink_port;
 	unsigned int port_index;
 	struct dentry *ddir;
+	struct netdevsim *ns;
 };
 
 struct nsim_dev {
@@ -212,8 +216,5 @@  struct nsim_bus_dev {
 	struct nsim_vf_config *vfconfigs;
 };
 
-struct nsim_bus_dev *nsim_bus_dev_new(unsigned int id, unsigned int port_count);
-struct nsim_bus_dev *nsim_bus_dev_new_with_ns(struct netdevsim *ns);
-void nsim_bus_dev_del(struct nsim_bus_dev *nsim_bus_dev);
 int nsim_bus_init(void);
 void nsim_bus_exit(void);
diff --git a/tools/testing/selftests/bpf/test_offload.py b/tools/testing/selftests/bpf/test_offload.py
index 5f2e4f9e70e4..a0566dcf064a 100755
--- a/tools/testing/selftests/bpf/test_offload.py
+++ b/tools/testing/selftests/bpf/test_offload.py
@@ -1,6 +1,7 @@ 
 #!/usr/bin/python3
 
 # Copyright (C) 2017 Netronome Systems, Inc.
+# Copyright (c) 2019 Mellanox Technologies. All rights reserved
 #
 # This software is licensed under the GNU General License Version 2,
 # June 1991 as shown in the file COPYING in the top-level directory of this
@@ -24,6 +25,7 @@  import struct
 import subprocess
 import time
 import traceback
+import errno
 
 logfile = None
 log_level = 1
@@ -323,42 +325,85 @@  class DebugfsDir:
 
         return dfs
 
-class NetdevSim:
+class NetdevSimDev:
     """
-    Class for netdevsim netdevice and its attributes.
+    Class for netdevsim bus device and its attributes.
     """
 
-    def __init__(self, link=None):
-        self.link = link
+    def __init__(self, port_count=1):
+        addr = 0
+        while True:
+            try:
+                with open("/sys/bus/netdevsim/new_device","w") as f:
+                    f.write("%u %u" % (addr, port_count))
+            except OSError as e:
+                if e.errno == errno.ENOSPC:
+                    addr += 1
+                    continue
+                raise e
+            break
 
-        self.dev = self._netdevsim_create()
         devs.append(self)
+        self.addr = addr
+        self.dfs_dir = "/sys/kernel/debug/netdevsim/netdevsim%u/" % addr
 
-        self.ns = ""
+        self.nsims = []
+        for port_index in range(port_count):
+            self.nsims.append(NetdevSim(self, port_index))
 
-        self.dfs_dir = '/sys/kernel/debug/netdevsim/netdevsim0/ports/0/'
-        self.dev_dir = self.dfs_dir + '/dev/'
-        self.dfs_refresh()
+    def dfs_num_bound_progs(self):
+        path = os.path.join(self.dfs_dir, "bpf_bound_progs")
+        _, progs = cmd('ls %s' % (path))
+        return len(progs.split())
 
-    def __getitem__(self, key):
-        return self.dev[key]
+    def dfs_get_bound_progs(self, expected):
+        progs = DebugfsDir(os.path.join(self.dfs_dir, "bpf_bound_progs"))
+        if expected is not None:
+            if len(progs) != expected:
+                fail(True, "%d BPF programs bound, expected %d" %
+                     (len(progs), expected))
+        return progs
 
-    def _netdevsim_create(self):
-        link = "" if self.link is None else "link " + self.link.dev['ifname']
-        _, old  = ip("link show")
-        ip("link add sim%d {link} type netdevsim".format(link=link))
-        _, new  = ip("link show")
+    def remove(self):
+        with open("/sys/bus/netdevsim/del_device","w") as f:
+            f.write("%u" % self.addr)
+        devs.remove(self)
 
-        for dev in new:
-            f = filter(lambda x: x["ifname"] == dev["ifname"], old)
-            if len(list(f)) == 0:
-                return dev
+    def remove_nsim(self, nsim):
+        self.nsims.remove(nsim)
+        with open("/sys/bus/netdevsim/devices/netdevsim%u/del_port" % self.addr ,"w") as f:
+            f.write("%u" % nsim.port_index)
 
-        raise Exception("failed to create netdevsim device")
+class NetdevSim:
+    """
+    Class for netdevsim netdevice and its attributes.
+    """
+
+    def __init__(self, nsimdev, port_index):
+        self.nsimdev = nsimdev
+        self.port_index = port_index
+        self.ns = ""
+        self.dfs_dir = "%s/ports/%u/" % (nsimdev.dfs_dir, port_index)
+        self.dfs_refresh()
+
+        ifname = "eni%unp%u" % (nsimdev.addr, port_index + 1)
+        timeout = 0.5
+        timeout_start = time.time()
+
+        while True:
+            try:
+                _, [self.dev] = ip("link show dev %s" % ifname)
+            except Exception as e:
+                if time.time() < timeout_start + timeout:
+                    continue
+                raise e
+            break
+
+    def __getitem__(self, key):
+        return self.dev[key]
 
     def remove(self):
-        devs.remove(self)
-        ip("link del dev %s" % (self.dev["ifname"]), ns=self.ns)
+        self.nsimdev.remove_nsim(self)
 
     def dfs_refresh(self):
         self.dfs = DebugfsDir(self.dfs_dir)
@@ -369,22 +414,9 @@  class NetdevSim:
         _, data = cmd('cat %s' % (path))
         return data.strip()
 
-    def dfs_num_bound_progs(self):
-        path = os.path.join(self.dev_dir, "bpf_bound_progs")
-        _, progs = cmd('ls %s' % (path))
-        return len(progs.split())
-
-    def dfs_get_bound_progs(self, expected):
-        progs = DebugfsDir(os.path.join(self.dev_dir, "bpf_bound_progs"))
-        if expected is not None:
-            if len(progs) != expected:
-                fail(True, "%d BPF programs bound, expected %d" %
-                     (len(progs), expected))
-        return progs
-
     def wait_for_flush(self, bound=0, total=0, n_retry=20):
         for i in range(n_retry):
-            nbound = self.dfs_num_bound_progs()
+            nbound = self.nsimdev.dfs_num_bound_progs()
             nprogs = len(bpftool_prog_list())
             if nbound == bound and nprogs == total:
                 return
@@ -614,7 +646,7 @@  def test_spurios_extack(sim, obj, skip_hw, needle):
                             include_stderr=True)
     check_no_extack(res, needle)
 
-def test_multi_prog(sim, obj, modename, modeid):
+def test_multi_prog(simdev, sim, obj, modename, modeid):
     start_test("Test multi-attachment XDP - %s + offload..." %
                (modename or "default", ))
     sim.set_xdp(obj, "offload")
@@ -670,11 +702,12 @@  def test_multi_prog(sim, obj, modename, modeid):
     check_multi_basic(two_xdps)
 
     start_test("Test multi-attachment XDP - device remove...")
-    sim.remove()
+    simdev.remove()
 
-    sim = NetdevSim()
+    simdev = NetdevSimDev()
+    sim, = simdev.nsims
     sim.set_ethtool_tc_offloads(True)
-    return sim
+    return [simdev, sim]
 
 # Parse command line
 parser = argparse.ArgumentParser()
@@ -731,12 +764,14 @@  try:
     bytecode = bpf_bytecode("1,6 0 0 4294967295,")
 
     start_test("Test destruction of generic XDP...")
-    sim = NetdevSim()
+    simdev = NetdevSimDev()
+    sim, = simdev.nsims
     sim.set_xdp(obj, "generic")
-    sim.remove()
+    simdev.remove()
     bpftool_prog_list_wait(expected=0)
 
-    sim = NetdevSim()
+    simdev = NetdevSimDev()
+    sim, = simdev.nsims
     sim.tc_add_ingress()
 
     start_test("Test TC non-offloaded...")
@@ -746,7 +781,7 @@  try:
     start_test("Test TC non-offloaded isn't getting bound...")
     ret, _ = sim.cls_bpf_add_filter(obj, fail=False)
     fail(ret != 0, "Software TC filter did not load")
-    sim.dfs_get_bound_progs(expected=0)
+    simdev.dfs_get_bound_progs(expected=0)
 
     sim.tc_flush_filters()
 
@@ -763,7 +798,7 @@  try:
     start_test("Test TC offload by default...")
     ret, _ = sim.cls_bpf_add_filter(obj, fail=False)
     fail(ret != 0, "Software TC filter did not load")
-    sim.dfs_get_bound_progs(expected=0)
+    simdev.dfs_get_bound_progs(expected=0)
     ingress = sim.tc_show_ingress(expected=1)
     fltr = ingress[0]
     fail(not fltr["in_hw"], "Filter not offloaded by default")
@@ -773,7 +808,7 @@  try:
     start_test("Test TC cBPF bytcode tries offload by default...")
     ret, _ = sim.cls_bpf_add_filter(bytecode, fail=False)
     fail(ret != 0, "Software TC filter did not load")
-    sim.dfs_get_bound_progs(expected=0)
+    simdev.dfs_get_bound_progs(expected=0)
     ingress = sim.tc_show_ingress(expected=1)
     fltr = ingress[0]
     fail(not fltr["in_hw"], "Bytecode not offloaded by default")
@@ -841,7 +876,7 @@  try:
     check_verifier_log(err, "[netdevsim] Hello from netdevsim!")
 
     start_test("Test TC offload basics...")
-    dfs = sim.dfs_get_bound_progs(expected=1)
+    dfs = simdev.dfs_get_bound_progs(expected=1)
     progs = bpftool_prog_list(expected=1)
     ingress = sim.tc_show_ingress(expected=1)
 
@@ -876,18 +911,20 @@  try:
 
     start_test("Test destroying device gets rid of TC filters...")
     sim.cls_bpf_add_filter(obj, skip_sw=True)
-    sim.remove()
+    simdev.remove()
     bpftool_prog_list_wait(expected=0)
 
-    sim = NetdevSim()
+    simdev = NetdevSimDev()
+    sim, = simdev.nsims
     sim.set_ethtool_tc_offloads(True)
 
     start_test("Test destroying device gets rid of XDP...")
     sim.set_xdp(obj, "offload")
-    sim.remove()
+    simdev.remove()
     bpftool_prog_list_wait(expected=0)
 
-    sim = NetdevSim()
+    simdev = NetdevSimDev()
+    sim, = simdev.nsims
     sim.set_ethtool_tc_offloads(True)
 
     start_test("Test XDP prog reporting...")
@@ -973,7 +1010,7 @@  try:
     check_verifier_log(err, "[netdevsim] Hello from netdevsim!")
 
     start_test("Test XDP offload is device bound...")
-    dfs = sim.dfs_get_bound_progs(expected=1)
+    dfs = simdev.dfs_get_bound_progs(expected=1)
     dprog = dfs[0]
 
     fail(prog["id"] != link_xdp["id"], "Program IDs don't match")
@@ -992,7 +1029,8 @@  try:
     bpftool_prog_list_wait(expected=0)
 
     start_test("Test attempt to use a program for a wrong device...")
-    sim2 = NetdevSim()
+    simdev2 = NetdevSimDev()
+    sim2, = simdev2.nsims
     sim2.set_xdp(obj, "offload")
     pin_file, pinned = pin_prog("/sys/fs/bpf/tmp")
 
@@ -1000,7 +1038,7 @@  try:
                               fail=False, include_stderr=True)
     fail(ret == 0, "Pinned program loaded for a different device accepted")
     check_extack_nsim(err, "program bound to different dev.", args)
-    sim2.remove()
+    simdev2.remove()
     ret, _, err = sim.set_xdp(pinned, "offload",
                               fail=False, include_stderr=True)
     fail(ret == 0, "Pinned program loaded for a removed device accepted")
@@ -1008,9 +1046,9 @@  try:
     rm(pin_file)
     bpftool_prog_list_wait(expected=0)
 
-    sim = test_multi_prog(sim, obj, "", 1)
-    sim = test_multi_prog(sim, obj, "drv", 1)
-    sim = test_multi_prog(sim, obj, "generic", 2)
+    simdev, sim = test_multi_prog(simdev, sim, obj, "", 1)
+    simdev, sim = test_multi_prog(simdev, sim, obj, "drv", 1)
+    simdev, sim = test_multi_prog(simdev, sim, obj, "generic", 2)
 
     start_test("Test mixing of TC and XDP...")
     sim.tc_add_ingress()
@@ -1063,9 +1101,9 @@  try:
                (sim['ifname'], obj)
     tc_proc = cmd(cmd_line, background=True, fail=False)
     # Wait for the verifier to start
-    while sim.dfs_num_bound_progs() <= 2:
+    while simdev.dfs_num_bound_progs() <= 2:
         pass
-    sim.remove()
+    simdev.remove()
     end = time.time()
     ret, _ = cmd_result(tc_proc, fail=False)
     time_diff = end - start
@@ -1080,7 +1118,8 @@  try:
     clean_up()
     bpftool_prog_list_wait(expected=0)
 
-    sim = NetdevSim()
+    simdev = NetdevSimDev()
+    sim, = simdev.nsims
     map_obj = bpf_obj("sample_map_ret0.o")
     start_test("Test loading program with maps...")
     sim.set_xdp(map_obj, "offload", JSON=False) # map fixup msg breaks JSON
@@ -1102,7 +1141,7 @@  try:
 
     prog_file, _ = pin_prog("/sys/fs/bpf/tmp_prog")
     map_file, _ = pin_map("/sys/fs/bpf/tmp_map", idx=1, expected=2)
-    sim.remove()
+    simdev.remove()
 
     start_test("Test bpftool bound info reporting (removed dev)...")
     check_dev_info_removed(prog_file=prog_file, map_file=map_file)
@@ -1111,7 +1150,8 @@  try:
     clean_up()
     bpftool_prog_list_wait(expected=0)
 
-    sim = NetdevSim()
+    simdev = NetdevSimDev()
+    sim, = simdev.nsims
 
     start_test("Test map update (no flags)...")
     sim.set_xdp(map_obj, "offload", JSON=False) # map fixup msg breaks JSON
@@ -1192,27 +1232,29 @@  try:
     start_test("Test map remove...")
     sim.unset_xdp("offload")
     bpftool_map_list_wait(expected=0)
-    sim.remove()
+    simdev.remove()
 
-    sim = NetdevSim()
+    simdev = NetdevSimDev()
+    sim, = simdev.nsims
     sim.set_xdp(map_obj, "offload", JSON=False) # map fixup msg breaks JSON
-    sim.remove()
+    simdev.remove()
     bpftool_map_list_wait(expected=0)
 
     start_test("Test map creation fail path...")
-    sim = NetdevSim()
+    simdev = NetdevSimDev()
+    sim, = simdev.nsims
     sim.dfs["bpf_map_accept"] = "N"
     ret, _ = sim.set_xdp(map_obj, "offload", JSON=False, fail=False)
     fail(ret == 0,
          "netdevsim didn't refuse to create a map with offload disabled")
 
-    sim.remove()
+    simdev.remove()
 
     start_test("Test multi-dev ASIC program reuse...")
-    simA = NetdevSim()
-    simB1 = NetdevSim()
-    simB2 = NetdevSim(link=simB1)
-    simB3 = NetdevSim(link=simB1)
+    simdevA = NetdevSimDev()
+    simA, = simdevA.nsims
+    simdevB = NetdevSimDev(3)
+    simB1, simB2, simB3 = simdevB.nsims
     sims = (simA, simB1, simB2, simB3)
     simB = (simB1, simB2, simB3)
 
@@ -1224,13 +1266,13 @@  try:
     progB = bpf_pinned("/sys/fs/bpf/nsimB")
 
     simA.set_xdp(progA, "offload", JSON=False)
-    for d in simB:
+    for d in simdevB.nsims:
         d.set_xdp(progB, "offload", JSON=False)
 
     start_test("Test multi-dev ASIC cross-dev replace...")
     ret, _ = simA.set_xdp(progB, "offload", force=True, JSON=False, fail=False)
     fail(ret == 0, "cross-ASIC program allowed")
-    for d in simB:
+    for d in simdevB.nsims:
         ret, _ = d.set_xdp(progA, "offload", force=True, JSON=False, fail=False)
         fail(ret == 0, "cross-ASIC program allowed")
 
@@ -1242,7 +1284,7 @@  try:
                                fail=False, include_stderr=True)
     fail(ret == 0, "cross-ASIC program allowed")
     check_extack_nsim(err, "program bound to different dev.", args)
-    for d in simB:
+    for d in simdevB.nsims:
         ret, _, err = d.set_xdp(progA, "offload", force=True, JSON=False,
                                 fail=False, include_stderr=True)
         fail(ret == 0, "cross-ASIC program allowed")
@@ -1279,7 +1321,7 @@  try:
     start_test("Test multi-dev ASIC cross-dev destruction...")
     bpftool_prog_list_wait(expected=2)
 
-    simA.remove()
+    simdevA.remove()
     bpftool_prog_list_wait(expected=1)
 
     ifnameB = bpftool("prog show %s" % (progB))[1]["dev"]["ifname"]
@@ -1297,6 +1339,7 @@  try:
     fail(ifnameB != simB3['ifname'], "program not bound to remaining device")
 
     simB3.remove()
+    simdevB.remove()
     bpftool_prog_list_wait(expected=0)
 
     start_test("Test multi-dev ASIC cross-dev destruction - orphaned...")
diff --git a/tools/testing/selftests/net/rtnetlink.sh b/tools/testing/selftests/net/rtnetlink.sh
index 311f82bcbe8d..3a7d55fb5f6e 100755
--- a/tools/testing/selftests/net/rtnetlink.sh
+++ b/tools/testing/selftests/net/rtnetlink.sh
@@ -696,7 +696,7 @@  kci_test_ipsec_offload()
 	algo="aead rfc4106(gcm(aes)) 0x3132333435363738393031323334353664636261 128"
 	srcip=192.168.123.3
 	dstip=192.168.123.4
-	dev=simx1
+	dev=eni0np1
 	sysfsd=/sys/kernel/debug/netdevsim/netdevsim0/ports/0/
 	sysfsf=$sysfsd/ipsec
 
@@ -708,7 +708,8 @@  kci_test_ipsec_offload()
 		return 1
 	fi
 
-	ip link add $dev type netdevsim
+	echo "0" > /sys/bus/netdevsim/new_device
+	while [ ! -d /sys/class/net/$dev ] ; do :; done
 	ip addr add $srcip dev $dev
 	ip link set $dev up
 	if [ ! -d $sysfsd ] ; then
@@ -781,7 +782,6 @@  EOF
 	fi
 
 	# clean up any leftovers
-	ip link del $dev
 	rmmod netdevsim
 
 	if [ $ret -ne 0 ]; then