daemon: adjustments to support global configurable mtu values for node interfaces and bridges
This commit is contained in:
parent
5ff4447528
commit
0b531d7fd8
9 changed files with 72 additions and 50 deletions
|
@ -142,6 +142,7 @@ class InterfaceData:
|
||||||
ip4_mask: int = None
|
ip4_mask: int = None
|
||||||
ip6: str = None
|
ip6: str = None
|
||||||
ip6_mask: int = None
|
ip6_mask: int = None
|
||||||
|
mtu: int = None
|
||||||
|
|
||||||
def get_ips(self) -> List[str]:
|
def get_ips(self) -> List[str]:
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -187,6 +187,7 @@ class DistributedController:
|
||||||
|
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
|
mtu = self.session.options.get_config_int("mtu")
|
||||||
for node_id in self.session.nodes:
|
for node_id in self.session.nodes:
|
||||||
node = self.session.nodes[node_id]
|
node = self.session.nodes[node_id]
|
||||||
if not isinstance(node, CoreNetwork):
|
if not isinstance(node, CoreNetwork):
|
||||||
|
@ -195,17 +196,17 @@ class DistributedController:
|
||||||
continue
|
continue
|
||||||
for name in self.servers:
|
for name in self.servers:
|
||||||
server = self.servers[name]
|
server = self.servers[name]
|
||||||
self.create_gre_tunnel(node, server)
|
self.create_gre_tunnel(node, server, mtu)
|
||||||
|
|
||||||
def create_gre_tunnel(
|
def create_gre_tunnel(
|
||||||
self, node: CoreNetwork, server: DistributedServer
|
self, node: CoreNetwork, server: DistributedServer, mtu: int
|
||||||
) -> Tuple[GreTap, GreTap]:
|
) -> Tuple[GreTap, GreTap]:
|
||||||
"""
|
"""
|
||||||
Create gre tunnel using a pair of gre taps between the local and remote server.
|
Create gre tunnel using a pair of gre taps between the local and remote server.
|
||||||
|
|
||||||
:param node: node to create gre tunnel for
|
:param node: node to create gre tunnel for
|
||||||
:param server: server to create
|
:param server: server to create tunnel for
|
||||||
tunnel for
|
:param mtu: mtu for gre taps
|
||||||
:return: local and remote gre taps created for tunnel
|
:return: local and remote gre taps created for tunnel
|
||||||
"""
|
"""
|
||||||
host = server.host
|
host = server.host
|
||||||
|
@ -215,14 +216,14 @@ class DistributedController:
|
||||||
return tunnel
|
return tunnel
|
||||||
# local to server
|
# local to server
|
||||||
logger.info("local tunnel node(%s) to remote(%s) key(%s)", node.name, host, key)
|
logger.info("local tunnel node(%s) to remote(%s) key(%s)", node.name, host, key)
|
||||||
local_tap = GreTap(session=self.session, remoteip=host, key=key)
|
local_tap = GreTap(session=self.session, remoteip=host, key=key, mtu=mtu)
|
||||||
local_tap.net_client.set_iface_master(node.brname, local_tap.localname)
|
local_tap.net_client.set_iface_master(node.brname, local_tap.localname)
|
||||||
# server to local
|
# server to local
|
||||||
logger.info(
|
logger.info(
|
||||||
"remote tunnel node(%s) to local(%s) key(%s)", node.name, self.address, key
|
"remote tunnel node(%s) to local(%s) key(%s)", node.name, self.address, key
|
||||||
)
|
)
|
||||||
remote_tap = GreTap(
|
remote_tap = GreTap(
|
||||||
session=self.session, remoteip=self.address, key=key, server=server
|
session=self.session, remoteip=self.address, key=key, server=server, mtu=mtu
|
||||||
)
|
)
|
||||||
remote_tap.net_client.set_iface_master(node.brname, remote_tap.localname)
|
remote_tap.net_client.set_iface_master(node.brname, remote_tap.localname)
|
||||||
# save tunnels for shutdown
|
# save tunnels for shutdown
|
||||||
|
|
|
@ -46,7 +46,7 @@ from core.location.geo import GeoLocation
|
||||||
from core.location.mobility import BasicRangeModel, MobilityManager
|
from core.location.mobility import BasicRangeModel, MobilityManager
|
||||||
from core.nodes.base import CoreNetworkBase, CoreNode, CoreNodeBase, NodeBase
|
from core.nodes.base import CoreNetworkBase, CoreNode, CoreNodeBase, NodeBase
|
||||||
from core.nodes.docker import DockerNode
|
from core.nodes.docker import DockerNode
|
||||||
from core.nodes.interface import CoreInterface
|
from core.nodes.interface import DEFAULT_MTU, CoreInterface
|
||||||
from core.nodes.lxd import LxcNode
|
from core.nodes.lxd import LxcNode
|
||||||
from core.nodes.network import (
|
from core.nodes.network import (
|
||||||
CtrlNet,
|
CtrlNet,
|
||||||
|
@ -253,7 +253,12 @@ class Session:
|
||||||
node2 = self.get_node(node2_id, NodeBase)
|
node2 = self.get_node(node2_id, NodeBase)
|
||||||
iface1 = None
|
iface1 = None
|
||||||
iface2 = None
|
iface2 = None
|
||||||
|
# set mtu
|
||||||
|
mtu = self.options.get_config_int("mtu") or DEFAULT_MTU
|
||||||
|
if iface1_data:
|
||||||
|
iface1_data.mtu = mtu
|
||||||
|
if iface2_data:
|
||||||
|
iface2_data.mtu = mtu
|
||||||
# wireless link
|
# wireless link
|
||||||
if link_type == LinkTypes.WIRELESS:
|
if link_type == LinkTypes.WIRELESS:
|
||||||
if isinstance(node1, CoreNodeBase) and isinstance(node2, CoreNodeBase):
|
if isinstance(node1, CoreNodeBase) and isinstance(node2, CoreNodeBase):
|
||||||
|
@ -567,12 +572,18 @@ class Session:
|
||||||
service_class = self.service_manager.get_service(name)
|
service_class = self.service_manager.get_service(name)
|
||||||
node.add_config_service(service_class)
|
node.add_config_service(service_class)
|
||||||
|
|
||||||
|
# set network mtu, if configured
|
||||||
|
mtu = self.options.get_config_int("mtu")
|
||||||
|
if isinstance(node, CoreNetworkBase) and mtu > 0:
|
||||||
|
node.mtu = mtu
|
||||||
|
|
||||||
# ensure default emane configuration
|
# ensure default emane configuration
|
||||||
if isinstance(node, EmaneNet) and options.emane:
|
if isinstance(node, EmaneNet) and options.emane:
|
||||||
model_class = self.emane.get_model(options.emane)
|
model_class = self.emane.get_model(options.emane)
|
||||||
node.model = model_class(self, node.id)
|
node.model = model_class(self, node.id)
|
||||||
if self.state == EventTypes.RUNTIME_STATE:
|
if self.state == EventTypes.RUNTIME_STATE:
|
||||||
self.emane.add_node(node)
|
self.emane.add_node(node)
|
||||||
|
|
||||||
# set default wlan config if needed
|
# set default wlan config if needed
|
||||||
if isinstance(node, WlanNode):
|
if isinstance(node, WlanNode):
|
||||||
self.mobility.set_model_config(_id, BasicRangeModel.name)
|
self.mobility.set_model_config(_id, BasicRangeModel.name)
|
||||||
|
|
|
@ -40,6 +40,7 @@ class SessionConfig(ConfigurableManager, ConfigurableOptions):
|
||||||
id="link_interval", default="1", label="EMANE Link Check Interval (sec)"
|
id="link_interval", default="1", label="EMANE Link Check Interval (sec)"
|
||||||
),
|
),
|
||||||
ConfigInt(id="link_timeout", default="4", label="EMANE Link Timeout (sec)"),
|
ConfigInt(id="link_timeout", default="4", label="EMANE Link Timeout (sec)"),
|
||||||
|
ConfigInt(id="mtu", default="0", label="MTU for All Devices"),
|
||||||
]
|
]
|
||||||
config_type: RegisterTlvs = RegisterTlvs.UTILITY
|
config_type: RegisterTlvs = RegisterTlvs.UTILITY
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ from core.emulator.enumerations import LinkTypes, MessageFlags, NodeTypes
|
||||||
from core.errors import CoreCommandError, CoreError
|
from core.errors import CoreCommandError, CoreError
|
||||||
from core.executables import MOUNT, TEST, VNODED
|
from core.executables import MOUNT, TEST, VNODED
|
||||||
from core.nodes.client import VnodeClient
|
from core.nodes.client import VnodeClient
|
||||||
from core.nodes.interface import CoreInterface, TunTap, Veth
|
from core.nodes.interface import DEFAULT_MTU, CoreInterface, TunTap, Veth
|
||||||
from core.nodes.netclient import LinuxNetClient, get_net_client
|
from core.nodes.netclient import LinuxNetClient, get_net_client
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -712,47 +712,37 @@ class CoreNode(CoreNodeBase):
|
||||||
with self.lock:
|
with self.lock:
|
||||||
return super().next_iface_id()
|
return super().next_iface_id()
|
||||||
|
|
||||||
def newveth(self, iface_id: int = None, ifname: str = None) -> int:
|
def newveth(
|
||||||
|
self, iface_id: int = None, ifname: str = None, mtu: int = DEFAULT_MTU
|
||||||
|
) -> int:
|
||||||
"""
|
"""
|
||||||
Create a new interface.
|
Create a new interface.
|
||||||
|
|
||||||
:param iface_id: id for the new interface
|
:param iface_id: id for the new interface
|
||||||
:param ifname: name for the new interface
|
:param ifname: name for the new interface
|
||||||
|
:param mtu: mtu for interface
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
with self.lock:
|
with self.lock:
|
||||||
if iface_id is None:
|
iface_id = iface_id if iface_id is not None else self.next_iface_id()
|
||||||
iface_id = self.next_iface_id()
|
ifname = ifname if ifname is not None else f"eth{iface_id}"
|
||||||
|
|
||||||
if ifname is None:
|
|
||||||
ifname = f"eth{iface_id}"
|
|
||||||
|
|
||||||
sessionid = self.session.short_session_id()
|
sessionid = self.session.short_session_id()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
suffix = f"{self.id:x}.{iface_id}.{sessionid}"
|
suffix = f"{self.id:x}.{iface_id}.{sessionid}"
|
||||||
except TypeError:
|
except TypeError:
|
||||||
suffix = f"{self.id}.{iface_id}.{sessionid}"
|
suffix = f"{self.id}.{iface_id}.{sessionid}"
|
||||||
|
|
||||||
localname = f"veth{suffix}"
|
localname = f"veth{suffix}"
|
||||||
if len(localname) >= 16:
|
if len(localname) >= 16:
|
||||||
raise ValueError(f"interface local name ({localname}) too long")
|
raise CoreError(f"interface local name ({localname}) too long")
|
||||||
|
name = f"{localname}p"
|
||||||
name = localname + "p"
|
|
||||||
if len(name) >= 16:
|
if len(name) >= 16:
|
||||||
raise ValueError(f"interface name ({name}) too long")
|
raise CoreError(f"interface name ({name}) too long")
|
||||||
|
veth = Veth(self.session, self, name, localname, mtu, self.server, self.up)
|
||||||
veth = Veth(
|
|
||||||
self.session, self, name, localname, start=self.up, server=self.server
|
|
||||||
)
|
|
||||||
|
|
||||||
if self.up:
|
if self.up:
|
||||||
self.net_client.device_ns(veth.name, str(self.pid))
|
self.net_client.device_ns(veth.name, str(self.pid))
|
||||||
self.node_net_client.device_name(veth.name, ifname)
|
self.node_net_client.device_name(veth.name, ifname)
|
||||||
self.node_net_client.checksums_off(ifname)
|
self.node_net_client.checksums_off(ifname)
|
||||||
|
|
||||||
veth.name = ifname
|
veth.name = ifname
|
||||||
|
|
||||||
if self.up:
|
if self.up:
|
||||||
flow_id = self.node_net_client.get_ifindex(veth.name)
|
flow_id = self.node_net_client.get_ifindex(veth.name)
|
||||||
veth.flow_id = int(flow_id)
|
veth.flow_id = int(flow_id)
|
||||||
|
@ -760,16 +750,14 @@ class CoreNode(CoreNodeBase):
|
||||||
mac = self.node_net_client.get_mac(veth.name)
|
mac = self.node_net_client.get_mac(veth.name)
|
||||||
logger.debug("interface mac: %s - %s", veth.name, mac)
|
logger.debug("interface mac: %s - %s", veth.name, mac)
|
||||||
veth.set_mac(mac)
|
veth.set_mac(mac)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# add network interface to the node. If unsuccessful, destroy the
|
# add network interface to the node. If unsuccessful, destroy the
|
||||||
# network interface and raise exception.
|
# network interface and raise exception.
|
||||||
self.add_iface(veth, iface_id)
|
self.add_iface(veth, iface_id)
|
||||||
except ValueError as e:
|
except CoreError as e:
|
||||||
veth.shutdown()
|
veth.shutdown()
|
||||||
del veth
|
del veth
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
return iface_id
|
return iface_id
|
||||||
|
|
||||||
def newtuntap(self, iface_id: int = None, ifname: str = None) -> int:
|
def newtuntap(self, iface_id: int = None, ifname: str = None) -> int:
|
||||||
|
@ -781,24 +769,18 @@ class CoreNode(CoreNodeBase):
|
||||||
:return: interface index
|
:return: interface index
|
||||||
"""
|
"""
|
||||||
with self.lock:
|
with self.lock:
|
||||||
if iface_id is None:
|
iface_id = iface_id if iface_id is not None else self.next_iface_id()
|
||||||
iface_id = self.next_iface_id()
|
ifname = ifname if ifname is not None else f"eth{iface_id}"
|
||||||
|
|
||||||
if ifname is None:
|
|
||||||
ifname = f"eth{iface_id}"
|
|
||||||
|
|
||||||
sessionid = self.session.short_session_id()
|
sessionid = self.session.short_session_id()
|
||||||
localname = f"tap{self.id}.{iface_id}.{sessionid}"
|
localname = f"tap{self.id}.{iface_id}.{sessionid}"
|
||||||
name = ifname
|
name = ifname
|
||||||
tuntap = TunTap(self.session, self, name, localname, start=self.up)
|
tuntap = TunTap(self.session, self, name, localname, start=self.up)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.add_iface(tuntap, iface_id)
|
self.add_iface(tuntap, iface_id)
|
||||||
except ValueError as e:
|
except CoreError as e:
|
||||||
tuntap.shutdown()
|
tuntap.shutdown()
|
||||||
del tuntap
|
del tuntap
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
return iface_id
|
return iface_id
|
||||||
|
|
||||||
def set_mac(self, iface_id: int, mac: str) -> None:
|
def set_mac(self, iface_id: int, mac: str) -> None:
|
||||||
|
@ -879,7 +861,7 @@ class CoreNode(CoreNodeBase):
|
||||||
raise CoreError(
|
raise CoreError(
|
||||||
f"node({self.name}) already has interface({iface_id})"
|
f"node({self.name}) already has interface({iface_id})"
|
||||||
)
|
)
|
||||||
iface_id = self.newveth(iface_id, iface_data.name)
|
iface_id = self.newveth(iface_id, iface_data.name, iface_data.mtu)
|
||||||
self.attachnet(iface_id, net)
|
self.attachnet(iface_id, net)
|
||||||
if iface_data.mac:
|
if iface_data.mac:
|
||||||
self.set_mac(iface_id, iface_data.mac)
|
self.set_mac(iface_id, iface_data.mac)
|
||||||
|
@ -1001,13 +983,14 @@ class CoreNetworkBase(NodeBase):
|
||||||
"""
|
"""
|
||||||
Create a CoreNetworkBase instance.
|
Create a CoreNetworkBase instance.
|
||||||
|
|
||||||
:param session: CORE session object
|
:param session: session object
|
||||||
:param _id: object id
|
:param _id: object id
|
||||||
:param name: object name
|
:param name: object name
|
||||||
:param server: remote server node
|
:param server: remote server node
|
||||||
will run on, default is None for localhost
|
will run on, default is None for localhost
|
||||||
"""
|
"""
|
||||||
super().__init__(session, _id, name, server)
|
super().__init__(session, _id, name, server)
|
||||||
|
self.mtu: int = DEFAULT_MTU
|
||||||
self.brname: Optional[str] = None
|
self.brname: Optional[str] = None
|
||||||
self.linked: Dict[CoreInterface, Dict[CoreInterface, bool]] = {}
|
self.linked: Dict[CoreInterface, Dict[CoreInterface, bool]] = {}
|
||||||
self.linked_lock: threading.Lock = threading.Lock()
|
self.linked_lock: threading.Lock = threading.Lock()
|
||||||
|
|
|
@ -378,6 +378,9 @@ class Veth(CoreInterface):
|
||||||
:raises CoreCommandError: when there is a command exception
|
:raises CoreCommandError: when there is a command exception
|
||||||
"""
|
"""
|
||||||
self.net_client.create_veth(self.localname, self.name)
|
self.net_client.create_veth(self.localname, self.name)
|
||||||
|
if self.mtu > 0:
|
||||||
|
self.net_client.set_mtu(self.name, self.mtu)
|
||||||
|
self.net_client.set_mtu(self.localname, self.mtu)
|
||||||
self.net_client.device_up(self.localname)
|
self.net_client.device_up(self.localname)
|
||||||
self.up = True
|
self.up = True
|
||||||
|
|
||||||
|
@ -455,12 +458,10 @@ class TunTap(CoreInterface):
|
||||||
"""
|
"""
|
||||||
if not self.up:
|
if not self.up:
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.node.node_net_client.device_flush(self.name)
|
self.node.node_net_client.device_flush(self.name)
|
||||||
except CoreCommandError:
|
except CoreCommandError:
|
||||||
logger.exception("error shutting down tunnel tap")
|
logger.exception("error shutting down tunnel tap")
|
||||||
|
|
||||||
self.up = False
|
self.up = False
|
||||||
|
|
||||||
def waitfor(
|
def waitfor(
|
||||||
|
@ -584,7 +585,7 @@ class GreTap(CoreInterface):
|
||||||
node: "CoreNode" = None,
|
node: "CoreNode" = None,
|
||||||
name: str = None,
|
name: str = None,
|
||||||
session: "Session" = None,
|
session: "Session" = None,
|
||||||
mtu: int = 1458,
|
mtu: int = DEFAULT_MTU,
|
||||||
remoteip: str = None,
|
remoteip: str = None,
|
||||||
_id: int = None,
|
_id: int = None,
|
||||||
localip: str = None,
|
localip: str = None,
|
||||||
|
@ -622,6 +623,8 @@ class GreTap(CoreInterface):
|
||||||
if remoteip is None:
|
if remoteip is None:
|
||||||
raise CoreError("missing remote IP required for GRE TAP device")
|
raise CoreError("missing remote IP required for GRE TAP device")
|
||||||
self.net_client.create_gretap(self.localname, remoteip, localip, ttl, key)
|
self.net_client.create_gretap(self.localname, remoteip, localip, ttl, key)
|
||||||
|
if self.mtu > 0:
|
||||||
|
self.net_client.set_mtu(self.localname, self.mtu)
|
||||||
self.net_client.device_up(self.localname)
|
self.net_client.device_up(self.localname)
|
||||||
self.up = True
|
self.up = True
|
||||||
|
|
||||||
|
|
|
@ -296,6 +296,16 @@ class LinuxNetClient:
|
||||||
"""
|
"""
|
||||||
self.run(f"{IP} link set {name} type bridge ageing_time {value}")
|
self.run(f"{IP} link set {name} type bridge ageing_time {value}")
|
||||||
|
|
||||||
|
def set_mtu(self, name: str, value: int) -> None:
|
||||||
|
"""
|
||||||
|
Sets the mtu value for a device.
|
||||||
|
|
||||||
|
:param name: name of device to set value for
|
||||||
|
:param value: mtu value to set
|
||||||
|
:return: nothing
|
||||||
|
"""
|
||||||
|
self.run(f"{IP} link set {name} mtu {value}")
|
||||||
|
|
||||||
|
|
||||||
class OvsNetClient(LinuxNetClient):
|
class OvsNetClient(LinuxNetClient):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -290,12 +290,14 @@ class CoreNetwork(CoreNetworkBase):
|
||||||
|
|
||||||
def startup(self) -> None:
|
def startup(self) -> None:
|
||||||
"""
|
"""
|
||||||
Linux bridge starup logic.
|
Linux bridge startup logic.
|
||||||
|
|
||||||
:return: nothing
|
:return: nothing
|
||||||
:raises CoreCommandError: when there is a command exception
|
:raises CoreCommandError: when there is a command exception
|
||||||
"""
|
"""
|
||||||
self.net_client.create_bridge(self.brname)
|
self.net_client.create_bridge(self.brname)
|
||||||
|
if self.mtu > 0:
|
||||||
|
self.net_client.set_mtu(self.brname, self.mtu)
|
||||||
self.has_nftables_chain = False
|
self.has_nftables_chain = False
|
||||||
self.up = True
|
self.up = True
|
||||||
nft_queue.start(self)
|
nft_queue.start(self)
|
||||||
|
@ -584,6 +586,7 @@ class GreTapBridge(CoreNetwork):
|
||||||
localip=localip,
|
localip=localip,
|
||||||
ttl=ttl,
|
ttl=ttl,
|
||||||
key=self.grekey,
|
key=self.grekey,
|
||||||
|
mtu=self.mtu,
|
||||||
)
|
)
|
||||||
|
|
||||||
def startup(self) -> None:
|
def startup(self) -> None:
|
||||||
|
@ -619,7 +622,7 @@ class GreTapBridge(CoreNetwork):
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
if self.gretap:
|
if self.gretap:
|
||||||
raise ValueError(f"gretap already exists for {self.name}")
|
raise CoreError(f"gretap already exists for {self.name}")
|
||||||
remoteip = ips[0].split("/")[0]
|
remoteip = ips[0].split("/")[0]
|
||||||
localip = None
|
localip = None
|
||||||
if len(ips) > 1:
|
if len(ips) > 1:
|
||||||
|
@ -630,6 +633,7 @@ class GreTapBridge(CoreNetwork):
|
||||||
localip=localip,
|
localip=localip,
|
||||||
ttl=self.ttl,
|
ttl=self.ttl,
|
||||||
key=self.grekey,
|
key=self.grekey,
|
||||||
|
mtu=self.mtu,
|
||||||
)
|
)
|
||||||
self.attach(self.gretap)
|
self.attach(self.gretap)
|
||||||
|
|
||||||
|
|
|
@ -176,12 +176,20 @@ class PhysicalNode(CoreNodeBase):
|
||||||
if self.up:
|
if self.up:
|
||||||
# this is reached when this node is linked to a network node
|
# this is reached when this node is linked to a network node
|
||||||
# tunnel to net not built yet, so build it now and adopt it
|
# tunnel to net not built yet, so build it now and adopt it
|
||||||
_, remote_tap = self.session.distributed.create_gre_tunnel(net, self.server)
|
_, remote_tap = self.session.distributed.create_gre_tunnel(
|
||||||
|
net, self.server, iface_data.mtu
|
||||||
|
)
|
||||||
self.adopt_iface(remote_tap, iface_id, iface_data.mac, ips)
|
self.adopt_iface(remote_tap, iface_id, iface_data.mac, ips)
|
||||||
return remote_tap
|
return remote_tap
|
||||||
else:
|
else:
|
||||||
# this is reached when configuring services (self.up=False)
|
# this is reached when configuring services (self.up=False)
|
||||||
iface = GreTap(node=self, name=name, session=self.session, start=False)
|
iface = GreTap(
|
||||||
|
node=self,
|
||||||
|
name=name,
|
||||||
|
session=self.session,
|
||||||
|
start=False,
|
||||||
|
mtu=iface_data.mtu,
|
||||||
|
)
|
||||||
self.adopt_iface(iface, iface_id, iface_data.mac, ips)
|
self.adopt_iface(iface, iface_id, iface_data.mac, ips)
|
||||||
return iface
|
return iface
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue