Merge pull request #250 from coreemu/refactor_pure

Merging directory layout changes and 2/3 support
This commit is contained in:
bharnden 2019-06-04 17:16:21 -07:00 committed by GitHub
commit 2dd1538184
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
112 changed files with 5424 additions and 5895 deletions

4
.gitignore vendored
View file

@ -18,8 +18,8 @@ debian
stamp-h1
# generated protobuf files
daemon/core/grpc/core_pb2.py
daemon/core/grpc/core_pb2_grpc.py
daemon/core/api/grpc/core_pb2.py
daemon/core/api/grpc/core_pb2_grpc.py
# python build directory
dist

View file

@ -110,6 +110,8 @@ if test "x$enable_daemon" = "xyes"; then
AC_CHECK_FUNCS([atexit dup2 gettimeofday memset socket strerror uname])
AM_PATH_PYTHON(2.7)
pythondir=`echo ${pythondir} | sed s,site-packages,dist-packages,`
AC_SUBST(pythondir,$pythondir)
AC_CHECK_PROG(brctl_path, brctl, $as_dir, no, $SEARCHPATH)
if test "x$brctl_path" = "xno" ; then

View file

@ -18,6 +18,8 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@ -527,7 +529,7 @@ public class CoreGrpcClient implements ICoreClient {
.build();
try {
CoreProto.GetNodeServiceFileResponse response = blockingStub.getNodeServiceFile(request);
return response.getData().toStringUtf8();
return response.getData();
} catch (StatusRuntimeException ex) {
throw new IOException(ex);
}
@ -600,7 +602,7 @@ public class CoreGrpcClient implements ICoreClient {
.setNodeId(node.getId())
.setService(serviceName)
.setFile(serviceFile.getName())
.setData(ByteString.copyFromUtf8(serviceFile.getData()))
.setData(serviceFile.getData())
.build();
try {
CoreProto.SetNodeServiceFileResponse response = blockingStub.setNodeServiceFile(request);
@ -696,7 +698,7 @@ public class CoreGrpcClient implements ICoreClient {
try {
CoreProto.SaveXmlResponse response = blockingStub.saveXml(request);
try (PrintWriter writer = new PrintWriter(file)) {
writer.print(response.getData().toStringUtf8());
writer.print(response.getData());
}
} catch (StatusRuntimeException ex) {
throw new IOException(ex);
@ -705,16 +707,18 @@ public class CoreGrpcClient implements ICoreClient {
@Override
public SessionOverview openSession(File file) throws IOException {
ByteString data = ByteString.readFrom(new FileInputStream(file));
CoreProto.OpenXmlRequest request = CoreProto.OpenXmlRequest.newBuilder()
.setData(data)
.build();
try {
byte[] encoded = Files.readAllBytes(file.toPath());
String data = new String(encoded, StandardCharsets.UTF_8);
CoreProto.OpenXmlRequest request = CoreProto.OpenXmlRequest.newBuilder()
.setData(data)
.build();
CoreProto.OpenXmlResponse response = blockingStub.openXml(request);
SessionOverview sessionOverview = new SessionOverview();
sessionOverview.setId(response.getSessionId());
return sessionOverview;
} catch (StatusRuntimeException ex) {
} catch (IOException | StatusRuntimeException ex) {
throw new IOException(ex);
}
}
@ -873,7 +877,7 @@ public class CoreGrpcClient implements ICoreClient {
public boolean createHook(Hook hook) throws IOException {
CoreProto.Hook hookProto = CoreProto.Hook.newBuilder()
.setStateValue(hook.getState())
.setData(ByteString.copyFromUtf8(hook.getData()))
.setData(hook.getData())
.setFile(hook.getFile())
.build();
CoreProto.AddHookRequest request = CoreProto.AddHookRequest.newBuilder()
@ -896,7 +900,7 @@ public class CoreGrpcClient implements ICoreClient {
for (CoreProto.Hook protoHook : response.getHooksList()) {
Hook hook = new Hook();
hook.setFile(protoHook.getFile());
hook.setData(protoHook.getData().toStringUtf8());
hook.setData(protoHook.getData());
hook.setState(protoHook.getStateValue());
hooks.add(hook);
}
@ -1193,7 +1197,7 @@ public class CoreGrpcClient implements ICoreClient {
// mobility script event
} else if (state.getValue() <= 9) {
Integer nodeId = event.getNodeId();
String[] values = event.getData().toStringUtf8().split("\\s+");
String[] values = event.getData().split("\\s+");
Integer start = Integer.parseInt(values[0].split("=")[1]);
Integer end = Integer.parseInt(values[1].split("=")[1]);
logger.info(String.format("node(%s) mobility event (%s) - start(%s) stop(%s)",

View file

@ -1,3 +0,0 @@
"""
Contains code specific to the legacy TCP API for interacting with the TCL based GUI.
"""

View file

@ -10,9 +10,9 @@ from contextlib import contextmanager
import grpc
from core.grpc import core_pb2
from core.grpc import core_pb2_grpc
from core.misc.ipaddress import Ipv4Prefix, Ipv6Prefix, MacAddress
from core.api.grpc import core_pb2
from core.api.grpc import core_pb2_grpc
from core.nodes.ipaddress import Ipv4Prefix, Ipv6Prefix, MacAddress
class InterfaceHelper(object):
@ -757,7 +757,7 @@ class CoreGrpcClient(object):
"""
request = core_pb2.SaveXmlRequest(session_id=session_id)
response = self.stub.SaveXml(request)
with open(file_path, "wb") as xml_file:
with open(file_path, "w") as xml_file:
xml_file.write(response.data)
def open_xml(self, file_path):
@ -768,7 +768,7 @@ class CoreGrpcClient(object):
:return: response with opened session id
:rtype: core_pb2.OpenXmlResponse
"""
with open(file_path, "rb") as xml_file:
with open(file_path, "r") as xml_file:
data = xml_file.read()
request = core_pb2.OpenXmlRequest(data=data)
return self.stub.OpenXml(request)

View file

@ -4,23 +4,24 @@ import os
import re
import tempfile
import time
from Queue import Queue, Empty
import grpc
from builtins import int
from concurrent import futures
from queue import Queue, Empty
from core.data import NodeData, LinkData, EventData, ConfigData, ExceptionData, FileData
from core.api.grpc import core_pb2
from core.api.grpc import core_pb2_grpc
from core.emulator.data import NodeData, LinkData, EventData, ConfigData, ExceptionData, FileData
from core.emulator.emudata import NodeOptions, InterfaceData, LinkOptions
from core.enumerations import NodeTypes, EventTypes, LinkTypes
from core.grpc import core_pb2
from core.grpc import core_pb2_grpc
from core.misc import nodeutils
from core.misc.ipaddress import MacAddress
from core.mobility import BasicRangeModel, Ns2ScriptedMobility
from core.service import ServiceManager
from core.emulator.enumerations import NodeTypes, EventTypes, LinkTypes
from core.location.mobility import BasicRangeModel, Ns2ScriptedMobility
from core.nodes import nodeutils
from core.nodes.ipaddress import MacAddress
from core.services.coreservices import ServiceManager
_ONE_DAY_IN_SECONDS = 60 * 60 * 24
_INTERFACE_REGEX = re.compile("\d+")
_INTERFACE_REGEX = re.compile(r"\d+")
def convert_value(value):
@ -71,7 +72,7 @@ def get_emane_model_id(node_id, interface_id):
def convert_link(session, link_data):
interface_one = None
if link_data.interface1_id is not None:
node = session.get_object(link_data.node1_id)
node = session.get_node(link_data.node1_id)
interface = node.netif(link_data.interface1_id)
interface_one = core_pb2.Interface(
id=link_data.interface1_id, name=interface.name, mac=convert_value(link_data.interface1_mac),
@ -80,7 +81,7 @@ def convert_link(session, link_data):
interface_two = None
if link_data.interface2_id is not None:
node = session.get_object(link_data.node2_id)
node = session.get_node(link_data.node2_id)
interface = node.netif(link_data.interface2_id)
interface_two = core_pb2.Interface(
id=link_data.interface2_id, name=interface.name, mac=convert_value(link_data.interface2_mac),
@ -162,7 +163,7 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
def get_node(self, session, node_id, context):
try:
return session.get_object(node_id)
return session.get_node(node_id)
except KeyError:
context.abort(grpc.StatusCode.NOT_FOUND, "node {} not found".format(node_id))
@ -252,9 +253,9 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
links = []
nodes = []
for node_id in session.objects:
node = session.objects[node_id]
if not isinstance(node.objid, int):
for _id in session.nodes:
node = session.nodes[_id]
if not isinstance(node.id, int):
continue
node_type = nodeutils.get_node_type(node.__class__).value
@ -271,7 +272,7 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
emane_model = node.model.name
node_proto = core_pb2.Node(
id=node.objid, name=node.name, emane=emane_model, model=model,
id=node.id, name=node.name, emane=emane_model, model=model,
type=node_type, position=position, services=services)
nodes.append(node_proto)
@ -437,14 +438,14 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
if last_check is not None:
interval = now - last_check
throughputs_event = core_pb2.ThroughputsEvent()
for key, current_rxtx in stats.iteritems():
for key in stats:
current_rxtx = stats[key]
previous_rxtx = last_stats.get(key)
if not previous_rxtx:
continue
rx_kbps = (current_rxtx["rx"] - previous_rxtx["rx"]) * 8.0 / interval
tx_kbps = (current_rxtx["tx"] - previous_rxtx["tx"]) * 8.0 / interval
throughput = rx_kbps + tx_kbps
print "%s - %s" % (key, throughput)
if key.startswith("veth"):
key = key.split(".")
node_id = int(_INTERFACE_REGEX.search(key[0]).group())
@ -494,7 +495,7 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
if emane_model:
session.emane.set_model_config(node_id, emane_model)
return core_pb2.AddNodeResponse(node_id=node.objid)
return core_pb2.AddNodeResponse(node_id=node.id)
def GetNode(self, request, context):
logging.debug("get node: %s", request)
@ -502,10 +503,11 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
node = self.get_node(session, request.node_id, context)
interfaces = []
for interface_id, interface in node._netif.iteritems():
for interface_id in node._netif:
interface = node._netif[interface_id]
net_id = None
if interface.net:
net_id = interface.net.objid
net_id = interface.net.id
interface_proto = core_pb2.Interface(
id=interface_id, netid=net_id, name=interface.name, mac=str(interface.hwaddr),
mtu=interface.mtu, flowid=interface.flow_id)
@ -519,7 +521,7 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
position = core_pb2.Position(x=node.position.x, y=node.position.y, z=node.position.z)
node_type = nodeutils.get_node_type(node.__class__).value
node = core_pb2.Node(
id=node.objid, name=node.name, type=node_type, emane=emane_model, model=node.type, position=position,
id=node.id, name=node.name, type=node_type, emane=emane_model, model=node.type, position=position,
services=services)
return core_pb2.GetNodeResponse(node=node, interfaces=interfaces)
@ -678,7 +680,8 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
logging.debug("get hooks: %s", request)
session = self.get_session(request.session_id, context)
hooks = []
for state, state_hooks in session._hooks.iteritems():
for state in session._hooks:
state_hooks = session._hooks[state]
for file_name, file_data in state_hooks:
hook = core_pb2.Hook(state=state, file=file_name, data=file_data)
hooks.append(hook)
@ -695,10 +698,11 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
logging.debug("get mobility configs: %s", request)
session = self.get_session(request.session_id, context)
response = core_pb2.GetMobilityConfigsResponse()
for node_id, model_config in session.mobility.node_configurations.iteritems():
for node_id in session.mobility.node_configurations:
model_config = session.mobility.node_configurations[node_id]
if node_id == -1:
continue
for model_name in model_config.iterkeys():
for model_name in model_config:
if model_name != Ns2ScriptedMobility.name:
continue
config = session.mobility.get_model_config(node_id, model_name)
@ -737,7 +741,8 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
def GetServices(self, request, context):
logging.debug("get services: %s", request)
services = []
for service in ServiceManager.services.itervalues():
for name in ServiceManager.services:
service = ServiceManager.services[name]
service_proto = core_pb2.Service(group=service.group, name=service.name)
services.append(service_proto)
return core_pb2.GetServicesResponse(services=services)
@ -896,11 +901,12 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
logging.debug("get emane model configs: %s", request)
session = self.get_session(request.session_id, context)
response = core_pb2.GetEmaneModelConfigsResponse()
for node_id, model_config in session.emane.node_configurations.iteritems():
for node_id in session.emane.node_configurations:
model_config = session.emane.node_configurations[node_id]
if node_id == -1:
continue
for model_name in model_config.iterkeys():
for model_name in model_config:
model = session.emane.models[model_name]
config = session.emane.get_model_config(node_id, model_name)
config_groups = get_config_groups(config, model)
@ -916,7 +922,7 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
_, temp_path = tempfile.mkstemp()
session.save_xml(temp_path)
with open(temp_path, "rb") as xml_file:
with open(temp_path, "r") as xml_file:
data = xml_file.read()
return core_pb2.SaveXmlResponse(data=data)
@ -927,7 +933,7 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
session.set_state(EventTypes.CONFIGURATION_STATE)
_, temp_path = tempfile.mkstemp()
with open(temp_path, "wb") as xml_file:
with open(temp_path, "w") as xml_file:
xml_file.write(request.data)
try:

View file

@ -10,27 +10,26 @@ import select
import socket
import threading
from core.api import coreapi
from core.coreobj import PyCoreNet
from core.coreobj import PyCoreNode
from core.enumerations import ConfigDataTypes
from core.enumerations import ConfigFlags
from core.enumerations import ConfigTlvs
from core.enumerations import EventTlvs
from core.enumerations import EventTypes
from core.enumerations import ExecuteTlvs
from core.enumerations import FileTlvs
from core.enumerations import LinkTlvs
from core.enumerations import MessageFlags
from core.enumerations import MessageTypes
from core.enumerations import NodeTlvs
from core.enumerations import NodeTypes
from core.enumerations import RegisterTlvs
from core.misc import nodeutils
from core.misc.ipaddress import IpAddress
from core.netns.vif import GreTap
from core.netns.vnet import GreTapBridge
from core.phys.pnodes import PhysicalNode
from core.api.tlv import coreapi
from core.nodes.base import CoreNodeBase, CoreNetworkBase
from core.emulator.enumerations import ConfigDataTypes
from core.emulator.enumerations import ConfigFlags
from core.emulator.enumerations import ConfigTlvs
from core.emulator.enumerations import EventTlvs
from core.emulator.enumerations import EventTypes
from core.emulator.enumerations import ExecuteTlvs
from core.emulator.enumerations import FileTlvs
from core.emulator.enumerations import LinkTlvs
from core.emulator.enumerations import MessageFlags
from core.emulator.enumerations import MessageTypes
from core.emulator.enumerations import NodeTlvs
from core.emulator.enumerations import NodeTypes
from core.emulator.enumerations import RegisterTlvs
from core.nodes import nodeutils
from core.nodes.ipaddress import IpAddress
from core.nodes.interface import GreTap
from core.nodes.network import GreTapBridge
from core.nodes.physical import PhysicalNode
class CoreDistributedServer(object):
@ -161,7 +160,8 @@ class CoreBroker(object):
logging.info("clearing state")
self.nodemap_lock.acquire()
self.nodemap.clear()
for server, count in self.nodecounts.iteritems():
for server in self.nodecounts:
count = self.nodecounts[server]
if count < 1:
self.delserver(server)
self.nodecounts.clear()
@ -201,7 +201,8 @@ class CoreBroker(object):
rlist = []
with self.servers_lock:
# build a socket list for select call
for server in self.servers.itervalues():
for name in self.servers:
server = self.servers[name]
if server.sock is not None:
rlist.append(server.sock)
r, _w, _x = select.select(rlist, [], [], 1.0)
@ -235,7 +236,7 @@ class CoreBroker(object):
return 0
if len(msghdr) != coreapi.CoreMessage.header_len:
logging.warn("warning: broker received not enough data len=%s", len(msghdr))
logging.warning("warning: broker received not enough data len=%s", len(msghdr))
return len(msghdr)
msgtype, msgflags, msglen = coreapi.CoreMessage.unpack_header(msghdr)
@ -350,7 +351,8 @@ class CoreBroker(object):
:rtype: CoreDistributedServer
"""
with self.servers_lock:
for server in self.servers.itervalues():
for name in self.servers:
server = self.servers[name]
if server.sock == sock:
return server
return None
@ -411,17 +413,16 @@ class CoreBroker(object):
remotenum = n2num
if key in self.tunnels.keys():
logging.warn("tunnel with key %s (%s-%s) already exists!", key, n1num, n2num)
logging.warning("tunnel with key %s (%s-%s) already exists!", key, n1num, n2num)
else:
objid = key & ((1 << 16) - 1)
_id = key & ((1 << 16) - 1)
logging.info("adding tunnel for %s-%s to %s with key %s", n1num, n2num, remoteip, key)
if localnum in self.physical_nodes:
# no bridge is needed on physical nodes; use the GreTap directly
gt = GreTap(node=None, name=None, session=self.session,
remoteip=remoteip, key=key)
else:
gt = self.session.add_object(cls=GreTapBridge, objid=objid,
policy="ACCEPT", remoteip=remoteip, key=key)
gt = self.session.create_node(cls=GreTapBridge, _id=_id, policy="ACCEPT", remoteip=remoteip, key=key)
gt.localnum = localnum
gt.remotenum = remotenum
self.tunnels[key] = gt
@ -444,24 +445,24 @@ class CoreBroker(object):
:rtype: list
"""
try:
net = self.session.get_object(node_id)
net = self.session.get_node(node_id)
logging.info("adding net tunnel for: id(%s) %s", node_id, net)
except KeyError:
raise KeyError("network node %s not found" % node_id)
# add other nets here that do not require tunnels
if nodeutils.is_node(net, NodeTypes.EMANE_NET):
logging.warn("emane network does not require a tunnel")
logging.warning("emane network does not require a tunnel")
return None
server_interface = getattr(net, "serverintf", None)
if nodeutils.is_node(net, NodeTypes.CONTROL_NET) and server_interface is not None:
logging.warn("control networks with server interfaces do not need a tunnel")
logging.warning("control networks with server interfaces do not need a tunnel")
return None
servers = self.getserversbynode(node_id)
if len(servers) < 2:
logging.warn("not enough servers to create a tunnel: %s", servers)
logging.warning("not enough servers to create a tunnel: %s", servers)
return None
hosts = []
@ -518,7 +519,7 @@ class CoreBroker(object):
except KeyError:
gt = None
if gt:
self.session.delete_object(gt.objid)
self.session.delete_node(gt.id)
del gt
def gettunnel(self, n1num, n2num):
@ -677,7 +678,7 @@ class CoreBroker(object):
"""
server = self.getserverbyname(servername)
if server is None:
logging.warn("ignoring unknown server: %s", servername)
logging.warning("ignoring unknown server: %s", servername)
return
if server.sock is None or server.host is None or server.port is None:
@ -691,7 +692,7 @@ class CoreBroker(object):
# send a Configuration message for the broker object and inform the
# server of its local name
tlvdata = ""
tlvdata = b""
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.OBJECT.value, "broker")
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.TYPE.value, ConfigFlags.UPDATE.value)
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.DATA_TYPES.value, (ConfigDataTypes.STRING.value,))
@ -721,7 +722,7 @@ class CoreBroker(object):
cmd = msg.get_tlv(ExecuteTlvs.COMMAND.value)
res = msg.get_tlv(ExecuteTlvs.RESULT.value)
tlvdata = ""
tlvdata = b""
tlvdata += coreapi.CoreExecuteTlv.pack(ExecuteTlvs.NODE.value, nodenum)
tlvdata += coreapi.CoreExecuteTlv.pack(ExecuteTlvs.NUMBER.value, execnum)
tlvdata += coreapi.CoreExecuteTlv.pack(ExecuteTlvs.COMMAND.value, cmd)
@ -753,12 +754,12 @@ class CoreBroker(object):
try:
nodecls = nodeutils.get_node_class(NodeTypes(nodetype))
except KeyError:
logging.warn("broker invalid node type %s", nodetype)
logging.warning("broker invalid node type %s", nodetype)
return handle_locally, servers
if nodecls is None:
logging.warn("broker unimplemented node type %s", nodetype)
logging.warning("broker unimplemented node type %s", nodetype)
return handle_locally, servers
if issubclass(nodecls, PyCoreNet) and nodetype != NodeTypes.WIRELESS_LAN.value:
if issubclass(nodecls, CoreNetworkBase) and nodetype != NodeTypes.WIRELESS_LAN.value:
# network node replicated on all servers; could be optimized
# don"t replicate WLANs, because ebtables rules won"t work
servers = self.getservers()
@ -769,7 +770,7 @@ class CoreBroker(object):
# do not record server name for networks since network
# nodes are replicated across all server
return handle_locally, servers
elif issubclass(nodecls, PyCoreNode):
elif issubclass(nodecls, CoreNodeBase):
name = message.get_tlv(NodeTlvs.NAME.value)
if name:
serverfiletxt = "%s %s %s" % (n, name, nodecls)
@ -1028,7 +1029,7 @@ class CoreBroker(object):
server.instantiation_complete = True
# broadcast out instantiate complete
tlvdata = ""
tlvdata = b""
tlvdata += coreapi.CoreEventTlv.pack(EventTlvs.TYPE.value, EventTypes.INSTANTIATION_COMPLETE.value)
message = coreapi.CoreEventMessage.pack(0, tlvdata)
for session_client in self.session_clients:
@ -1043,7 +1044,8 @@ class CoreBroker(object):
:rtype: bool
"""
with self.servers_lock:
for server in self.servers.itervalues():
for name in self.servers:
server = self.servers[name]
if not server.instantiation_complete:
return False
return True
@ -1089,12 +1091,12 @@ class CoreBroker(object):
control_nets = value.split()
if len(control_nets) < 2:
logging.warn("multiple controlnet prefixes do not exist")
logging.warning("multiple controlnet prefixes do not exist")
return
servers = self.session.broker.getservernames()
if len(servers) < 2:
logging.warn("not distributed")
logging.warning("not distributed")
return
servers.remove("localhost")

View file

@ -7,25 +7,26 @@ CORE API messaging is leveraged for communication with the GUI.
import socket
import struct
from past.builtins import basestring
from enum import Enum
from core.enumerations import ConfigTlvs
from core.enumerations import EventTlvs
from core.enumerations import EventTypes
from core.enumerations import ExceptionTlvs
from core.enumerations import ExecuteTlvs
from core.enumerations import FileTlvs
from core.enumerations import InterfaceTlvs
from core.enumerations import LinkTlvs
from core.enumerations import MessageFlags
from core.enumerations import MessageTypes
from core.enumerations import NodeTlvs
from core.enumerations import RegisterTlvs
from core.enumerations import SessionTlvs
from core.misc import structutils
from core.misc.ipaddress import IpAddress
from core.misc.ipaddress import MacAddress
from core.api.tlv import structutils
from core.emulator.enumerations import ConfigTlvs
from core.emulator.enumerations import EventTlvs
from core.emulator.enumerations import EventTypes
from core.emulator.enumerations import ExceptionTlvs
from core.emulator.enumerations import ExecuteTlvs
from core.emulator.enumerations import FileTlvs
from core.emulator.enumerations import InterfaceTlvs
from core.emulator.enumerations import LinkTlvs
from core.emulator.enumerations import MessageFlags
from core.emulator.enumerations import MessageTypes
from core.emulator.enumerations import NodeTlvs
from core.emulator.enumerations import RegisterTlvs
from core.emulator.enumerations import SessionTlvs
from core.nodes.ipaddress import IpAddress
from core.nodes.ipaddress import MacAddress
class CoreTlvData(object):
@ -157,7 +158,7 @@ class CoreTlvDataUint64(CoreTlvData):
Helper class for packing uint64 data.
"""
data_format = "!2xQ"
data_type = long
data_type = int
pad_len = 2
@ -176,8 +177,9 @@ class CoreTlvDataString(CoreTlvData):
:return: length of data packed and the packed data
:rtype: tuple
"""
if not isinstance(value, str):
raise ValueError("value not a string: %s" % value)
if not isinstance(value, basestring):
raise ValueError("value not a string: %s" % type(value))
value = value.encode("utf-8")
if len(value) < 256:
header_len = CoreTlv.header_len
@ -185,7 +187,7 @@ class CoreTlvDataString(CoreTlvData):
header_len = CoreTlv.long_header_len
pad_len = -(header_len + len(value)) % 4
return len(value), value + "\0" * pad_len
return len(value), value + b"\0" * pad_len
@classmethod
def unpack(cls, data):
@ -195,7 +197,7 @@ class CoreTlvDataString(CoreTlvData):
:param str data: unpack string data
:return: unpacked string data
"""
return data.rstrip("\0")
return data.rstrip(b"\0").decode("utf-8")
class CoreTlvDataUint16List(CoreTlvData):
@ -217,12 +219,12 @@ class CoreTlvDataUint16List(CoreTlvData):
if not isinstance(values, tuple):
raise ValueError("value not a tuple: %s" % values)
data = ""
data = b""
for value in values:
data += struct.pack(cls.data_format, value)
pad_len = -(CoreTlv.header_len + len(data)) % 4
return len(data), data + "\0" * pad_len
return len(data), data + b"\0" * pad_len
@classmethod
def unpack(cls, data):
@ -266,7 +268,7 @@ class CoreTlvDataIpv4Addr(CoreTlvDataObj):
return obj.addr
@staticmethod
def new_obj(obj):
def new_obj(value):
"""
Retrieve Ipv4 address from a string representation.
@ -274,7 +276,7 @@ class CoreTlvDataIpv4Addr(CoreTlvDataObj):
:return: Ipv4 address
:rtype: core.misc.ipaddress.IpAddress
"""
return IpAddress(af=socket.AF_INET, address=obj)
return IpAddress(af=socket.AF_INET, address=value)
class CoreTlvDataIPv6Addr(CoreTlvDataObj):
@ -324,7 +326,7 @@ class CoreTlvDataMacAddr(CoreTlvDataObj):
:return:
"""
# extend to 64 bits
return "\0\0" + obj.addr
return b"\0\0" + obj.addr
@staticmethod
def new_obj(value):
@ -397,12 +399,10 @@ class CoreTlv(object):
:return: header and packed data
"""
tlv_len, tlv_data = cls.tlv_data_class_map[tlv_type].pack(value)
if tlv_len < 256:
hdr = struct.pack(cls.header_format, tlv_type, tlv_len)
else:
hdr = struct.pack(cls.long_header_format, tlv_type, 0, tlv_len)
return hdr + tlv_data
@classmethod
@ -748,13 +748,11 @@ class CoreMessage(object):
:return: packed data
:rtype: str
"""
tlv_data = ""
keys = sorted(self.tlv_data.keys())
tlv_data = b""
for key in keys:
value = self.tlv_data[key]
tlv_data += self.tlv_class.pack(key, value)
return tlv_data
def repack(self):
@ -788,7 +786,7 @@ class CoreMessage(object):
:rtype: str
"""
message_flags = []
flag = 1L
flag = 1
while True:
if self.flags & flag:
@ -811,7 +809,8 @@ class CoreMessage(object):
"""
result = "%s <msgtype = %s, flags = %s>" % (self.__class__.__name__, self.type_str(), self.flag_str())
for key, value in self.tlv_data.iteritems():
for key in self.tlv_data:
value = self.tlv_data[key]
try:
tlv_type = self.tlv_class.tlv_type_map(key).name
except ValueError:

View file

@ -2,52 +2,51 @@
socket server request handlers leveraged by core servers.
"""
import Queue
import SocketServer
import logging
import os
from queue import Queue, Empty
import shlex
import shutil
import socketserver
import sys
import threading
import time
from builtins import range
from itertools import repeat
from core.api import coreapi
from core.api import dataconversion
from core.conf import ConfigShim
from core.data import ConfigData, ExceptionData
from core.data import EventData
from core.data import FileData
from core import utils
from core.api.tlv import coreapi, dataconversion, structutils
from core.config import ConfigShim
from core.emulator.data import ConfigData, ExceptionData
from core.emulator.data import EventData
from core.emulator.data import FileData
from core.emulator.emudata import InterfaceData
from core.emulator.emudata import LinkOptions
from core.emulator.emudata import NodeOptions
from core.enumerations import ConfigDataTypes
from core.enumerations import ConfigFlags
from core.enumerations import ConfigTlvs
from core.enumerations import EventTlvs
from core.enumerations import EventTypes
from core.enumerations import ExceptionTlvs
from core.enumerations import ExecuteTlvs
from core.enumerations import FileTlvs
from core.enumerations import LinkTlvs
from core.enumerations import LinkTypes
from core.enumerations import MessageFlags
from core.enumerations import MessageTypes
from core.enumerations import NodeTlvs
from core.enumerations import NodeTypes
from core.enumerations import RegisterTlvs
from core.enumerations import SessionTlvs
from core.misc import nodeutils
from core.misc import structutils
from core.misc import utils
from core.service import ServiceManager
from core.service import ServiceShim
from core.emulator.enumerations import ConfigDataTypes
from core.emulator.enumerations import ConfigFlags
from core.emulator.enumerations import ConfigTlvs
from core.emulator.enumerations import EventTlvs
from core.emulator.enumerations import EventTypes
from core.emulator.enumerations import ExceptionTlvs
from core.emulator.enumerations import ExecuteTlvs
from core.emulator.enumerations import FileTlvs
from core.emulator.enumerations import LinkTlvs
from core.emulator.enumerations import LinkTypes
from core.emulator.enumerations import MessageFlags
from core.emulator.enumerations import MessageTypes
from core.emulator.enumerations import NodeTlvs
from core.emulator.enumerations import NodeTypes
from core.emulator.enumerations import RegisterTlvs
from core.emulator.enumerations import SessionTlvs
from core.nodes import nodeutils
from core.services.coreservices import ServiceManager
from core.services.coreservices import ServiceShim
class CoreHandler(SocketServer.BaseRequestHandler):
class CoreHandler(socketserver.BaseRequestHandler):
"""
The SocketServer class uses the RequestHandler class for servicing requests.
The CoreHandler class uses the RequestHandler class for servicing requests.
"""
def __init__(self, request, client_address, server):
@ -70,7 +69,7 @@ class CoreHandler(SocketServer.BaseRequestHandler):
MessageTypes.EVENT.value: self.handle_event_message,
MessageTypes.SESSION.value: self.handle_session_message,
}
self.message_queue = Queue.Queue()
self.message_queue = Queue()
self.node_status_request = {}
self._shutdown_lock = threading.Lock()
self._sessions_lock = threading.Lock()
@ -81,7 +80,7 @@ class CoreHandler(SocketServer.BaseRequestHandler):
raise ValueError("invalid number of threads: %s" % num_threads)
logging.debug("launching core server handler threads: %s", num_threads)
for _ in xrange(num_threads):
for _ in range(num_threads):
thread = threading.Thread(target=self.handler_thread)
self.handler_threads.append(thread)
thread.start()
@ -93,7 +92,7 @@ class CoreHandler(SocketServer.BaseRequestHandler):
self.coreemu = server.coreemu
utils.close_onexec(request.fileno())
SocketServer.BaseRequestHandler.__init__(self, request, client_address, server)
socketserver.BaseRequestHandler.__init__(self, request, client_address, server)
def setup(self):
"""
@ -121,7 +120,7 @@ class CoreHandler(SocketServer.BaseRequestHandler):
time.sleep(1)
wait += 1
if wait == timeout:
logging.warn("queue failed to be empty, finishing request handler")
logging.warning("queue failed to be empty, finishing request handler")
break
logging.info("client disconnected: notifying threads")
@ -130,7 +129,7 @@ class CoreHandler(SocketServer.BaseRequestHandler):
logging.info("waiting for thread: %s", thread.getName())
thread.join(timeout)
if thread.isAlive():
logging.warn("joining %s failed: still alive after %s sec", thread.getName(), timeout)
logging.warning("joining %s failed: still alive after %s sec", thread.getName(), timeout)
logging.info("connection closed: %s", self.client_address)
if self.session:
@ -141,7 +140,7 @@ class CoreHandler(SocketServer.BaseRequestHandler):
logging.info("no session clients left and not active, initiating shutdown")
self.coreemu.delete_session(self.session.id)
return SocketServer.BaseRequestHandler.finish(self)
return socketserver.BaseRequestHandler.finish(self)
def session_message(self, flags=0):
"""
@ -159,7 +158,8 @@ class CoreHandler(SocketServer.BaseRequestHandler):
num_sessions = 0
with self._sessions_lock:
for _id, session in self.coreemu.sessions.iteritems():
for _id in self.coreemu.sessions:
session = self.coreemu.sessions[_id]
num_sessions += 1
id_list.append(str(_id))
@ -168,10 +168,10 @@ class CoreHandler(SocketServer.BaseRequestHandler):
name = ""
name_list.append(name)
file = session.file_name
if not file:
file = ""
file_list.append(file)
file_name = session.file_name
if not file_name:
file_name = ""
file_list.append(file_name)
node_count_list.append(str(session.get_node_count()))
@ -190,7 +190,7 @@ class CoreHandler(SocketServer.BaseRequestHandler):
thumbs = "|".join(thumb_list)
if num_sessions > 0:
tlv_data = ""
tlv_data = b""
if len(session_ids) > 0:
tlv_data += coreapi.CoreSessionTlv.pack(SessionTlvs.NUMBER.value, session_ids)
if len(names) > 0:
@ -224,7 +224,7 @@ class CoreHandler(SocketServer.BaseRequestHandler):
(EventTlvs.NAME, event_data.name),
(EventTlvs.DATA, event_data.data),
(EventTlvs.TIME, event_data.time),
(EventTlvs.TIME, event_data.session)
(EventTlvs.SESSION, event_data.session)
])
message = coreapi.CoreEventMessage.pack(0, tlv_data)
@ -373,17 +373,19 @@ class CoreHandler(SocketServer.BaseRequestHandler):
"""
logging.info("GUI has connected to session %d at %s", self.session.id, time.ctime())
tlv_data = ""
tlv_data = b""
tlv_data += coreapi.CoreRegisterTlv.pack(RegisterTlvs.EXECUTE_SERVER.value, "core-daemon")
tlv_data += coreapi.CoreRegisterTlv.pack(RegisterTlvs.EMULATION_SERVER.value, "core-daemon")
tlv_data += coreapi.CoreRegisterTlv.pack(self.session.broker.config_type, self.session.broker.name)
tlv_data += coreapi.CoreRegisterTlv.pack(self.session.location.config_type, self.session.location.name)
tlv_data += coreapi.CoreRegisterTlv.pack(self.session.mobility.config_type, self.session.mobility.name)
for model_class in self.session.mobility.models.itervalues():
for model_name in self.session.mobility.models:
model_class = self.session.mobility.models[model_name]
tlv_data += coreapi.CoreRegisterTlv.pack(model_class.config_type, model_class.name)
tlv_data += coreapi.CoreRegisterTlv.pack(self.session.services.config_type, self.session.services.name)
tlv_data += coreapi.CoreRegisterTlv.pack(self.session.emane.config_type, self.session.emane.name)
for model_class in self.session.emane.models.itervalues():
for model_name in self.session.emane.models:
model_class = self.session.emane.models[model_name]
tlv_data += coreapi.CoreRegisterTlv.pack(model_class.config_type, model_class.name)
tlv_data += coreapi.CoreRegisterTlv.pack(self.session.options.config_type, self.session.options.name)
tlv_data += coreapi.CoreRegisterTlv.pack(self.session.metadata.config_type, self.session.metadata.name)
@ -420,9 +422,9 @@ class CoreHandler(SocketServer.BaseRequestHandler):
message_type, message_flags, message_len = coreapi.CoreMessage.unpack_header(header)
if message_len == 0:
logging.warn("received message with no data")
logging.warning("received message with no data")
data = ""
data = b""
while len(data) < message_len:
data += self.request.recv(message_len - len(data))
if len(data) > message_len:
@ -464,7 +466,7 @@ class CoreHandler(SocketServer.BaseRequestHandler):
try:
message = self.message_queue.get(timeout=1)
self.handle_message(message)
except Queue.Empty:
except Empty:
pass
def handle_message(self, message):
@ -502,7 +504,7 @@ class CoreHandler(SocketServer.BaseRequestHandler):
:param message: message for replies
:return: nothing
"""
logging.debug("dispatching replies")
logging.debug("dispatching replies: %s", replies)
for reply in replies:
message_type, message_flags, message_length = coreapi.CoreMessage.unpack_header(reply)
try:
@ -627,7 +629,7 @@ class CoreHandler(SocketServer.BaseRequestHandler):
"""
replies = []
if message.flags & MessageFlags.ADD.value and message.flags & MessageFlags.DELETE.value:
logging.warn("ignoring invalid message: add and delete flag both set")
logging.warning("ignoring invalid message: add and delete flag both set")
return ()
node_type = None
@ -670,17 +672,17 @@ class CoreHandler(SocketServer.BaseRequestHandler):
node = self.session.add_node(node_type, node_id, node_options)
if node:
if message.flags & MessageFlags.STRING.value:
self.node_status_request[node.objid] = True
self.node_status_request[node.id] = True
if self.session.state == EventTypes.RUNTIME_STATE.value:
self.send_node_emulation_id(node.objid)
self.send_node_emulation_id(node.id)
elif message.flags & MessageFlags.DELETE.value:
with self._shutdown_lock:
result = self.session.delete_node(node_id)
# if we deleted a node broadcast out its removal
if result and message.flags & MessageFlags.STRING.value:
tlvdata = ""
tlvdata = b""
tlvdata += coreapi.CoreNodeTlv.pack(NodeTlvs.NUMBER.value, node_id)
flags = MessageFlags.DELETE.value | MessageFlags.LOCAL.value
replies.append(coreapi.CoreNodeMessage.pack(flags, tlvdata))
@ -774,10 +776,10 @@ class CoreHandler(SocketServer.BaseRequestHandler):
return ()
try:
node = self.session.get_object(node_num)
node = self.session.get_node(node_num)
# build common TLV items for reply
tlv_data = ""
tlv_data = b""
if node_num is not None:
tlv_data += coreapi.CoreExecuteTlv.pack(ExecuteTlvs.NODE.value, node_num)
tlv_data += coreapi.CoreExecuteTlv.pack(ExecuteTlvs.NUMBER.value, execute_num)
@ -905,7 +907,8 @@ class CoreHandler(SocketServer.BaseRequestHandler):
self.master = True
# find the session containing this client and set the session to master
for session in self.coreemu.sessions.itervalues():
for _id in self.coreemu.sessions:
session = self.coreemu.sessions[_id]
if self in session.broker.session_clients:
logging.debug("setting session to master: %s", session.id)
session.master = True
@ -996,7 +999,8 @@ class CoreHandler(SocketServer.BaseRequestHandler):
replies.append(config_response)
elif message_type != ConfigFlags.RESET and config_data.data_values:
values = ConfigShim.str_to_dict(config_data.data_values)
for key, value in values.iteritems():
for key in values:
value = values[key]
self.session.options.set_config(key, value)
return replies
@ -1005,7 +1009,7 @@ class CoreHandler(SocketServer.BaseRequestHandler):
self.session.location.reset()
else:
if not config_data.data_values:
logging.warn("location data missing")
logging.warning("location data missing")
else:
values = [float(x) for x in config_data.data_values.split("|")]
@ -1026,7 +1030,8 @@ class CoreHandler(SocketServer.BaseRequestHandler):
replies = []
if message_type == ConfigFlags.REQUEST:
node_id = config_data.node
data_values = "|".join(["%s=%s" % item for item in self.session.metadata.get_configs().iteritems()])
metadata_configs = self.session.metadata.get_configs()
data_values = "|".join(["%s=%s" % (x, metadata_configs[x]) for x in metadata_configs])
data_types = tuple(ConfigDataTypes.STRING.value for _ in self.session.metadata.get_configs())
config_response = ConfigData(
message_type=0,
@ -1039,7 +1044,8 @@ class CoreHandler(SocketServer.BaseRequestHandler):
replies.append(config_response)
elif message_type != ConfigFlags.RESET and config_data.data_values:
values = ConfigShim.str_to_dict(config_data.data_values)
for key, value in values.iteritems():
for key in values:
value = values[key]
self.session.metadata.set_config(key, value)
return replies
@ -1098,7 +1104,8 @@ class CoreHandler(SocketServer.BaseRequestHandler):
# sort groups by name and map services to groups
groups = set()
group_map = {}
for service_name in ServiceManager.services.itervalues():
for name in ServiceManager.services:
service_name = ServiceManager.services[name]
group = service_name.group
groups.add(group)
group_map.setdefault(group, []).append(service_name)
@ -1135,9 +1142,9 @@ class CoreHandler(SocketServer.BaseRequestHandler):
if not node_id:
return replies
node = self.session.get_object(node_id)
node = self.session.get_node(node_id)
if node is None:
logging.warn("request to configure service for unknown node %s", node_id)
logging.warning("request to configure service for unknown node %s", node_id)
return replies
services = ServiceShim.servicesfromopaque(opaque)
@ -1213,7 +1220,8 @@ class CoreHandler(SocketServer.BaseRequestHandler):
raise ValueError("custom service(%s) for node(%s) does not exist", service_name, node_id)
values = ConfigShim.str_to_dict(values)
for name, value in values.iteritems():
for name in values:
value = values[name]
ServiceShim.setvalue(service, name, value)
return replies
@ -1239,7 +1247,7 @@ class CoreHandler(SocketServer.BaseRequestHandler):
model_class = self.session.mobility.models.get(object_name)
if not model_class:
logging.warn("model class does not exist: %s", object_name)
logging.warning("model class does not exist: %s", object_name)
return []
config = self.session.mobility.get_model_config(node_id, object_name)
@ -1248,7 +1256,7 @@ class CoreHandler(SocketServer.BaseRequestHandler):
elif message_type != ConfigFlags.RESET:
# store the configuration values for later use, when the node
if not object_name:
logging.warn("no configuration object for node: %s", node_id)
logging.warning("no configuration object for node: %s", node_id)
return []
parsed_config = {}
@ -1309,7 +1317,7 @@ class CoreHandler(SocketServer.BaseRequestHandler):
model_class = self.session.emane.models.get(object_name)
if not model_class:
logging.warn("model class does not exist: %s", object_name)
logging.warning("model class does not exist: %s", object_name)
return []
config = self.session.emane.get_model_config(node_id, object_name)
@ -1318,7 +1326,7 @@ class CoreHandler(SocketServer.BaseRequestHandler):
elif message_type != ConfigFlags.RESET:
# store the configuration values for later use, when the node
if not object_name:
logging.warn("no configuration object for node: %s", node_id)
logging.warning("no configuration object for node: %s", node_id)
return []
parsed_config = {}
@ -1345,11 +1353,11 @@ class CoreHandler(SocketServer.BaseRequestHandler):
compressed_data = message.get_tlv(FileTlvs.COMPRESSED_DATA.value)
if compressed_data:
logging.warn("Compressed file data not implemented for File message.")
logging.warning("Compressed file data not implemented for File message.")
return ()
if source_name and data:
logging.warn("ignoring invalid File message: source and data TLVs are both present")
logging.warning("ignoring invalid File message: source and data TLVs are both present")
return ()
# some File Messages store custom files in services,
@ -1418,16 +1426,16 @@ class CoreHandler(SocketServer.BaseRequestHandler):
if event_type.value <= EventTypes.SHUTDOWN_STATE.value:
if node_id is not None:
try:
node = self.session.get_object(node_id)
node = self.session.get_node(node_id)
except KeyError:
raise KeyError("Event message for unknown node %d" % node_id)
# configure mobility models for WLAN added during runtime
if event_type == EventTypes.INSTANTIATION_STATE and nodeutils.is_node(node, NodeTypes.WIRELESS_LAN):
self.session.start_mobility(node_ids=(node.objid,))
self.session.start_mobility(node_ids=(node.id,))
return ()
logging.warn("dropping unhandled Event message with node number")
logging.warning("dropping unhandled Event message with node number")
return ()
self.session.set_state(event_type)
@ -1442,11 +1450,11 @@ class CoreHandler(SocketServer.BaseRequestHandler):
self.session.instantiate()
# after booting nodes attempt to send emulation id for nodes waiting on status
for obj in self.session.objects.itervalues():
self.send_node_emulation_id(obj.objid)
for _id in self.session.nodes:
self.send_node_emulation_id(_id)
elif event_type == EventTypes.RUNTIME_STATE:
if self.session.master:
logging.warn("Unexpected event message: RUNTIME state received at session master")
logging.warning("Unexpected event message: RUNTIME state received at session master")
else:
# master event queue is started in session.checkruntime()
self.session.start_events()
@ -1454,7 +1462,7 @@ class CoreHandler(SocketServer.BaseRequestHandler):
self.session.data_collect()
elif event_type == EventTypes.SHUTDOWN_STATE:
if self.session.master:
logging.warn("Unexpected event message: SHUTDOWN state received at session master")
logging.warning("Unexpected event message: SHUTDOWN state received at session master")
elif event_type in {EventTypes.START, EventTypes.STOP, EventTypes.RESTART, EventTypes.PAUSE,
EventTypes.RECONFIGURE}:
handled = False
@ -1469,7 +1477,7 @@ class CoreHandler(SocketServer.BaseRequestHandler):
self.session.mobility_event(event_data)
handled = True
if not handled:
logging.warn("Unhandled event message: event type %s ", event_type.name)
logging.warning("Unhandled event message: event type %s ", event_type.name)
elif event_type == EventTypes.FILE_OPEN:
filename = event_data.name
self.session.open_xml(filename, start=False)
@ -1484,14 +1492,14 @@ class CoreHandler(SocketServer.BaseRequestHandler):
name = event_data.name
data = event_data.data
if etime is None:
logging.warn("Event message scheduled event missing start time")
logging.warning("Event message scheduled event missing start time")
return ()
if message.flags & MessageFlags.ADD.value:
self.session.add_event(float(etime), node=node, name=name, data=data)
else:
raise NotImplementedError
else:
logging.warn("unhandled event message: event type %s", event_type)
logging.warning("unhandled event message: event type %s", event_type)
return ()
@ -1508,9 +1516,9 @@ class CoreHandler(SocketServer.BaseRequestHandler):
name = event_data.name
try:
node = self.session.get_object(node_id)
node = self.session.get_node(node_id)
except KeyError:
logging.warn("ignoring event for service '%s', unknown node '%s'", name, node_id)
logging.warning("ignoring event for service '%s', unknown node '%s'", name, node_id)
return
fail = ""
@ -1548,7 +1556,7 @@ class CoreHandler(SocketServer.BaseRequestHandler):
if num > 1:
unknown_data += ", "
num -= 1
logging.warn("Event requested for unknown service(s): %s", unknown_data)
logging.warning("Event requested for unknown service(s): %s", unknown_data)
unknown_data = "Unknown:" + unknown_data
event_data = EventData(
@ -1587,7 +1595,7 @@ class CoreHandler(SocketServer.BaseRequestHandler):
session = self.coreemu.sessions.get(session_id)
if session is None:
logging.warn("session %s not found", session_id)
logging.warning("session %s not found", session_id)
continue
logging.info("request to modify to session: %s", session.id)
@ -1647,7 +1655,7 @@ class CoreHandler(SocketServer.BaseRequestHandler):
logging.info("request to terminate session %s", session_id)
self.coreemu.delete_session(session_id)
else:
logging.warn("unhandled session flags for session %s", session_id)
logging.warning("unhandled session flags for session %s", session_id)
return ()
@ -1659,7 +1667,7 @@ class CoreHandler(SocketServer.BaseRequestHandler):
:return: nothing
"""
if node_id in self.node_status_request:
tlv_data = ""
tlv_data = b""
tlv_data += coreapi.CoreNodeTlv.pack(NodeTlvs.NUMBER.value, node_id)
tlv_data += coreapi.CoreNodeTlv.pack(NodeTlvs.EMULATION_ID.value, node_id)
reply = coreapi.CoreNodeMessage.pack(MessageFlags.ADD.value | MessageFlags.LOCAL.value, tlv_data)
@ -1679,13 +1687,14 @@ class CoreHandler(SocketServer.BaseRequestHandler):
nodes_data = []
links_data = []
with self.session._objects_lock:
for obj in self.session.objects.itervalues():
node_data = obj.data(message_type=MessageFlags.ADD.value)
with self.session._nodes_lock:
for node_id in self.session.nodes:
node = self.session.nodes[node_id]
node_data = node.data(message_type=MessageFlags.ADD.value)
if node_data:
nodes_data.append(node_data)
node_links = obj.all_link_data(flags=MessageFlags.ADD.value)
node_links = node.all_link_data(flags=MessageFlags.ADD.value)
for link_data in node_links:
links_data.append(link_data)
@ -1698,7 +1707,9 @@ class CoreHandler(SocketServer.BaseRequestHandler):
# send mobility model info
for node_id in self.session.mobility.nodes():
for model_name, config in self.session.mobility.get_all_configs(node_id).iteritems():
mobility_configs = self.session.mobility.get_all_configs(node_id)
for model_name in mobility_configs:
config = mobility_configs[model_name]
model_class = self.session.mobility.models[model_name]
logging.debug("mobility config: node(%s) class(%s) values(%s)", node_id, model_class, config)
config_data = ConfigShim.config_data(0, node_id, ConfigFlags.UPDATE.value, model_class, config)
@ -1706,7 +1717,9 @@ class CoreHandler(SocketServer.BaseRequestHandler):
# send emane model info
for node_id in self.session.emane.nodes():
for model_name, config in self.session.emane.get_all_configs(node_id).iteritems():
emane_configs = self.session.emane.get_all_configs(node_id)
for model_name in emane_configs:
config = emane_configs[model_name]
model_class = self.session.emane.models[model_name]
logging.debug("emane config: node(%s) class(%s) values(%s)", node_id, model_class, config)
config_data = ConfigShim.config_data(0, node_id, ConfigFlags.UPDATE.value, model_class, config)
@ -1717,7 +1730,7 @@ class CoreHandler(SocketServer.BaseRequestHandler):
for node_id, service in service_configs:
opaque = "service:%s" % service.name
data_types = tuple(repeat(ConfigDataTypes.STRING.value, len(ServiceShim.keys)))
node = self.session.get_object(node_id)
node = self.session.get_node(node_id)
values = ServiceShim.tovaluelist(node, service)
config_data = ConfigData(
message_type=0,
@ -1762,7 +1775,7 @@ class CoreHandler(SocketServer.BaseRequestHandler):
# send session metadata
metadata_configs = self.session.metadata.get_configs()
if metadata_configs:
data_values = "|".join(["%s=%s" % item for item in metadata_configs.iteritems()])
data_values = "|".join(["%s=%s" % (x, metadata_configs[x]) for x in metadata_configs])
data_types = tuple(ConfigDataTypes.STRING.value for _ in self.session.metadata.get_configs())
config_data = ConfigData(
message_type=0,

View file

@ -2,12 +2,12 @@
Defines core server for handling TCP connections.
"""
import SocketServer
import socketserver
from core.emulator.coreemu import CoreEmu
class CoreServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
class CoreServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
"""
TCP server class, manages sessions and spawns request handlers for
incoming connections.
@ -18,7 +18,7 @@ class CoreServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
def __init__(self, server_address, handler_class, config=None):
"""
Server class initialization takes configuration data and calls
the SocketServer constructor
the socketserver constructor.
:param tuple[str, int] server_address: server host and port to use
:param class handler_class: request handler
@ -27,4 +27,4 @@ class CoreServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
"""
self.coreemu = CoreEmu(config)
self.config = config
SocketServer.TCPServer.__init__(self, server_address, handler_class)
socketserver.TCPServer.__init__(self, server_address, handler_class)

View file

@ -2,10 +2,9 @@
Converts CORE data objects into legacy API messages.
"""
from core.api import coreapi
from core.enumerations import ConfigTlvs
from core.enumerations import NodeTlvs
from core.misc import structutils
from core.api.tlv import coreapi, structutils
from core.emulator.enumerations import ConfigTlvs
from core.emulator.enumerations import NodeTlvs
def convert_node(node_data):

View file

@ -3,6 +3,7 @@ Utilities for working with python struct data.
"""
import logging
from past.builtins import basestring
def pack_values(clazz, packers):
@ -15,7 +16,8 @@ def pack_values(clazz, packers):
"""
# iterate through tuples of values to pack
data = ""
logging.debug("packing: %s", packers)
data = b""
for packer in packers:
# check if a transformer was provided for valid values
transformer = None
@ -26,13 +28,9 @@ def pack_values(clazz, packers):
else:
raise RuntimeError("packer had more than 3 arguments")
# convert unicode to normal str for packing
if isinstance(value, unicode):
value = str(value)
# only pack actual values and avoid packing empty strings
# protobuf defaults to empty strings and does no imply a value to set
if value is None or (isinstance(value, str) and not value):
if value is None or (isinstance(value, basestring) and not value):
continue
# transform values as needed
@ -40,7 +38,7 @@ def pack_values(clazz, packers):
value = transformer(value)
# pack and add to existing data
logging.debug("packing: %s - %s", tlv_type, value)
logging.debug("packing: %s - %s type(%s)", tlv_type, value, type(value))
data += clazz.pack(tlv_type.value, value)
return data

View file

@ -5,7 +5,7 @@ Common support for configurable CORE objects.
import logging
from collections import OrderedDict
from core.data import ConfigData
from core.emulator.data import ConfigData
class ConfigShim(object):
@ -150,7 +150,7 @@ class ConfigurableManager(object):
:return: list of node ids
:rtype: list
"""
return [node_id for node_id in self.node_configurations.iterkeys() if node_id != self._default_node]
return [x for x in self.node_configurations if x != self._default_node]
def config_reset(self, node_id=None):
"""
@ -329,7 +329,8 @@ class ModelManager(ConfigurableManager):
model_config = self.get_model_config(node_id, model_name)
if not config:
config = {}
for key, value in config.iteritems():
for key in config:
value = config[key]
model_config[key] = value
# set as node model for startup
@ -369,9 +370,9 @@ class ModelManager(ConfigurableManager):
:param dict config: model configuration, None for default configuration
:return: nothing
"""
logging.info("setting mobility model(%s) for node(%s): %s", model_class.name, node.objid, config)
self.set_model_config(node.objid, model_class.name, config)
config = self.get_model_config(node.objid, model_class.name)
logging.info("setting mobility model(%s) for node(%s): %s", model_class.name, node.id, config)
self.set_model_config(node.id, model_class.name, config)
config = self.get_model_config(node.id, model_class.name)
node.setmodel(model_class, config)
def get_models(self, node):
@ -383,16 +384,17 @@ class ModelManager(ConfigurableManager):
:return: list of model and values tuples for the network node
:rtype: list
"""
all_configs = self.get_all_configs(node.objid)
all_configs = self.get_all_configs(node.id)
if not all_configs:
all_configs = {}
models = []
for model_name, config in all_configs.iteritems():
for model_name in all_configs:
config = all_configs[model_name]
if model_name == ModelManager._default_node:
continue
model_class = self.models[model_name]
models.append((model_class, config))
logging.debug("models for node(%s): %s", node.objid, models)
logging.debug("models for node(%s): %s", node.id, models)
return models

View file

@ -1,758 +0,0 @@
"""
Defines the basic objects for CORE emulation: the PyCoreObj base class, along with PyCoreNode,
PyCoreNet, and PyCoreNetIf.
"""
import os
import shutil
import socket
import threading
from socket import AF_INET
from socket import AF_INET6
from core.data import NodeData, LinkData
from core.enumerations import LinkTypes
from core.misc import ipaddress
class Position(object):
"""
Helper class for Cartesian coordinate position
"""
def __init__(self, x=None, y=None, z=None):
"""
Creates a Position instance.
:param x: x position
:param y: y position
:param z: z position
:return:
"""
self.x = x
self.y = y
self.z = z
def set(self, x=None, y=None, z=None):
"""
Returns True if the position has actually changed.
:param float x: x position
:param float y: y position
:param float z: z position
:return: True if position changed, False otherwise
:rtype: bool
"""
if self.x == x and self.y == y and self.z == z:
return False
self.x = x
self.y = y
self.z = z
return True
def get(self):
"""
Retrieve x,y,z position.
:return: x,y,z position tuple
:rtype: tuple
"""
return self.x, self.y, self.z
class PyCoreObj(object):
"""
Base class for CORE objects (nodes and networks)
"""
apitype = None
# TODO: appears start has no usage, verify and remove
def __init__(self, session, objid=None, name=None, start=True):
"""
Creates a PyCoreObj instance.
:param core.session.Session session: CORE session object
:param int objid: object id
:param str name: object name
:param bool start: start value
:return:
"""
self.session = session
if objid is None:
objid = session.get_object_id()
self.objid = objid
if name is None:
name = "o%s" % self.objid
self.name = name
self.type = None
self.server = None
self.services = None
# ifindex is key, PyCoreNetIf instance is value
self._netif = {}
self.ifindex = 0
self.canvas = None
self.icon = None
self.opaque = None
self.position = Position()
def startup(self):
"""
Each object implements its own startup method.
:return: nothing
"""
raise NotImplementedError
def shutdown(self):
"""
Each object implements its own shutdown method.
:return: nothing
"""
raise NotImplementedError
def setposition(self, x=None, y=None, z=None):
"""
Set the (x,y,z) position of the object.
:param float x: x position
:param float y: y position
:param float z: z position
:return: True if position changed, False otherwise
:rtype: bool
"""
return self.position.set(x=x, y=y, z=z)
def getposition(self):
"""
Return an (x,y,z) tuple representing this object's position.
:return: x,y,z position tuple
:rtype: tuple
"""
return self.position.get()
def ifname(self, ifindex):
"""
Retrieve interface name for index.
:param int ifindex: interface index
:return: interface name
:rtype: str
"""
return self._netif[ifindex].name
def netifs(self, sort=False):
"""
Retrieve network interfaces, sorted if desired.
:param bool sort: boolean used to determine if interfaces should be sorted
:return: network interfaces
:rtype: list
"""
if sort:
return map(lambda k: self._netif[k], sorted(self._netif.keys()))
else:
return self._netif.itervalues()
def numnetif(self):
"""
Return the attached interface count.
:return: number of network interfaces
:rtype: int
"""
return len(self._netif)
def getifindex(self, netif):
"""
Retrieve index for an interface.
:param PyCoreNetIf netif: interface to get index for
:return: interface index if found, -1 otherwise
:rtype: int
"""
for ifindex in self._netif:
if self._netif[ifindex] is netif:
return ifindex
return -1
def newifindex(self):
"""
Create a new interface index.
:return: interface index
:rtype: int
"""
while self.ifindex in self._netif:
self.ifindex += 1
ifindex = self.ifindex
self.ifindex += 1
return ifindex
def data(self, message_type, lat=None, lon=None, alt=None):
"""
Build a data object for this node.
:param message_type: purpose for the data object we are creating
:param str lat: latitude
:param str lon: longitude
:param str alt: altitude
:return: node data object
:rtype: core.data.NodeData
"""
if self.apitype is None:
return None
x, y, _ = self.getposition()
model = self.type
emulation_server = self.server
services = self.services
if services is not None:
services = "|".join([service.name for service in services])
node_data = NodeData(
message_type=message_type,
id=self.objid,
node_type=self.apitype,
name=self.name,
emulation_id=self.objid,
canvas=self.canvas,
icon=self.icon,
opaque=self.opaque,
x_position=x,
y_position=y,
latitude=lat,
longitude=lon,
altitude=alt,
model=model,
emulation_server=emulation_server,
services=services
)
return node_data
def all_link_data(self, flags):
"""
Build CORE Link data for this object. There is no default
method for PyCoreObjs as PyCoreNodes do not implement this but
PyCoreNets do.
:param flags: message flags
:return: list of link data
:rtype: core.data.LinkData
"""
return []
class PyCoreNode(PyCoreObj):
"""
Base class for CORE nodes.
"""
def __init__(self, session, objid=None, name=None, start=True):
"""
Create a PyCoreNode instance.
:param core.session.Session session: CORE session object
:param int objid: object id
:param str name: object name
:param bool start: boolean for starting
"""
super(PyCoreNode, self).__init__(session, objid, name, start=start)
self.services = []
self.nodedir = None
self.tmpnodedir = False
def addservice(self, service):
"""
Add a services to the service list.
:param core.service.CoreService service: service to add
:return: nothing
"""
if service is not None:
self.services.append(service)
def makenodedir(self):
"""
Create the node directory.
:return: nothing
"""
if self.nodedir is None:
self.nodedir = os.path.join(self.session.session_dir, self.name + ".conf")
os.makedirs(self.nodedir)
self.tmpnodedir = True
else:
self.tmpnodedir = False
def rmnodedir(self):
"""
Remove the node directory, unless preserve directory has been set.
:return: nothing
"""
preserve = self.session.options.get_config("preservedir") == "1"
if preserve:
return
if self.tmpnodedir:
shutil.rmtree(self.nodedir, ignore_errors=True)
def addnetif(self, netif, ifindex):
"""
Add network interface to node and set the network interface index if successful.
:param PyCoreNetIf netif: network interface to add
:param int ifindex: interface index
:return: nothing
"""
if ifindex in self._netif:
raise ValueError("ifindex %s already exists" % ifindex)
self._netif[ifindex] = netif
# TODO: this should have probably been set ahead, seems bad to me, check for failure and fix
netif.netindex = ifindex
def delnetif(self, ifindex):
"""
Delete a network interface
:param int ifindex: interface index to delete
:return: nothing
"""
if ifindex not in self._netif:
raise ValueError("ifindex %s does not exist" % ifindex)
netif = self._netif.pop(ifindex)
netif.shutdown()
del netif
# TODO: net parameter is not used, remove
def netif(self, ifindex, net=None):
"""
Retrieve network interface.
:param int ifindex: index of interface to retrieve
:param PyCoreNetIf net: network node
:return: network interface, or None if not found
:rtype: PyCoreNetIf
"""
if ifindex in self._netif:
return self._netif[ifindex]
else:
return None
def attachnet(self, ifindex, net):
"""
Attach a network.
:param int ifindex: interface of index to attach
:param PyCoreNetIf net: network to attach
:return:
"""
if ifindex not in self._netif:
raise ValueError("ifindex %s does not exist" % ifindex)
self._netif[ifindex].attachnet(net)
def detachnet(self, ifindex):
"""
Detach network interface.
:param int ifindex: interface index to detach
:return: nothing
"""
if ifindex not in self._netif:
raise ValueError("ifindex %s does not exist" % ifindex)
self._netif[ifindex].detachnet()
def setposition(self, x=None, y=None, z=None):
"""
Set position.
:param x: x position
:param y: y position
:param z: z position
:return: nothing
"""
changed = super(PyCoreNode, self).setposition(x, y, z)
if changed:
for netif in self.netifs(sort=True):
netif.setposition(x, y, z)
def commonnets(self, obj, want_ctrl=False):
"""
Given another node or net object, return common networks between
this node and that object. A list of tuples is returned, with each tuple
consisting of (network, interface1, interface2).
:param obj: object to get common network with
:param want_ctrl: flag set to determine if control network are wanted
:return: tuples of common networks
:rtype: list
"""
common = []
for netif1 in self.netifs():
if not want_ctrl and hasattr(netif1, "control"):
continue
for netif2 in obj.netifs():
if netif1.net == netif2.net:
common.append((netif1.net, netif1, netif2))
return common
def check_cmd(self, args):
"""
Runs shell command on node.
:param list[str]|str args: command to run
:return: combined stdout and stderr
:rtype: str
:raises CoreCommandError: when a non-zero exit status occurs
"""
raise NotImplementedError
def cmd(self, args, wait=True):
"""
Runs shell command on node, with option to not wait for a result.
:param list[str]|str args: command to run
:param bool wait: wait for command to exit, defaults to True
:return: exit status for command
:rtype: int
"""
raise NotImplementedError
def cmd_output(self, args):
"""
Runs shell command on node and get exit status and output.
:param list[str]|str args: command to run
:return: exit status and combined stdout and stderr
:rtype: tuple[int, str]
"""
raise NotImplementedError
def termcmdstring(self, sh):
"""
Create a terminal command string.
:param str sh: shell to execute command in
:return: str
"""
raise NotImplementedError
class PyCoreNet(PyCoreObj):
"""
Base class for networks
"""
linktype = LinkTypes.WIRED.value
def __init__(self, session, objid, name, start=True):
"""
Create a PyCoreNet instance.
:param core.session.Session session: CORE session object
:param int objid: object id
:param str name: object name
:param bool start: should object start
"""
super(PyCoreNet, self).__init__(session, objid, name, start=start)
self._linked = {}
self._linked_lock = threading.Lock()
def startup(self):
"""
Each object implements its own startup method.
:return: nothing
"""
raise NotImplementedError
def shutdown(self):
"""
Each object implements its own shutdown method.
:return: nothing
"""
raise NotImplementedError
def attach(self, netif):
"""
Attach network interface.
:param PyCoreNetIf netif: network interface to attach
:return: nothing
"""
i = self.newifindex()
self._netif[i] = netif
netif.netifi = i
with self._linked_lock:
self._linked[netif] = {}
def detach(self, netif):
"""
Detach network interface.
:param PyCoreNetIf netif: network interface to detach
:return: nothing
"""
del self._netif[netif.netifi]
netif.netifi = None
with self._linked_lock:
del self._linked[netif]
def all_link_data(self, flags):
"""
Build link data objects for this network. Each link object describes a link
between this network and a node.
"""
all_links = []
# build a link message from this network node to each node having a
# connected interface
for netif in self.netifs(sort=True):
if not hasattr(netif, "node"):
continue
otherobj = netif.node
uni = False
if otherobj is None:
# two layer-2 switches/hubs linked together via linknet()
if not hasattr(netif, "othernet"):
continue
otherobj = netif.othernet
if otherobj.objid == self.objid:
continue
netif.swapparams('_params_up')
upstream_params = netif.getparams()
netif.swapparams('_params_up')
if netif.getparams() != upstream_params:
uni = True
unidirectional = 0
if uni:
unidirectional = 1
interface2_ip4 = None
interface2_ip4_mask = None
interface2_ip6 = None
interface2_ip6_mask = None
for address in netif.addrlist:
ip, _sep, mask = address.partition("/")
mask = int(mask)
if ipaddress.is_ipv4_address(ip):
family = AF_INET
ipl = socket.inet_pton(family, ip)
interface2_ip4 = ipaddress.IpAddress(af=family, address=ipl)
interface2_ip4_mask = mask
else:
family = AF_INET6
ipl = socket.inet_pton(family, ip)
interface2_ip6 = ipaddress.IpAddress(af=family, address=ipl)
interface2_ip6_mask = mask
link_data = LinkData(
message_type=flags,
node1_id=self.objid,
node2_id=otherobj.objid,
link_type=self.linktype,
unidirectional=unidirectional,
interface2_id=otherobj.getifindex(netif),
interface2_mac=netif.hwaddr,
interface2_ip4=interface2_ip4,
interface2_ip4_mask=interface2_ip4_mask,
interface2_ip6=interface2_ip6,
interface2_ip6_mask=interface2_ip6_mask,
delay=netif.getparam("delay"),
bandwidth=netif.getparam("bw"),
dup=netif.getparam("duplicate"),
jitter=netif.getparam("jitter"),
per=netif.getparam("loss")
)
all_links.append(link_data)
if not uni:
continue
netif.swapparams('_params_up')
link_data = LinkData(
message_type=0,
node1_id=otherobj.objid,
node2_id=self.objid,
unidirectional=1,
delay=netif.getparam("delay"),
bandwidth=netif.getparam("bw"),
dup=netif.getparam("duplicate"),
jitter=netif.getparam("jitter"),
per=netif.getparam("loss")
)
netif.swapparams('_params_up')
all_links.append(link_data)
return all_links
class PyCoreNetIf(object):
"""
Base class for network interfaces.
"""
def __init__(self, node, name, mtu):
"""
Creates a PyCoreNetIf instance.
:param core.coreobj.PyCoreNode node: node for interface
:param str name: interface name
:param mtu: mtu value
"""
self.node = node
self.name = name
if not isinstance(mtu, (int, long)):
raise ValueError
self.mtu = mtu
self.net = None
self._params = {}
self.addrlist = []
self.hwaddr = None
# placeholder position hook
self.poshook = lambda a, b, c, d: None
# used with EMANE
self.transport_type = None
# interface index on the network
self.netindex = None
# index used to find flow data
self.flow_id = None
def startup(self):
"""
Startup method for the interface.
:return: nothing
"""
pass
def shutdown(self):
"""
Shutdown method for the interface.
:return: nothing
"""
pass
def attachnet(self, net):
"""
Attach network.
:param core.coreobj.PyCoreNet net: network to attach
:return: nothing
"""
if self.net:
self.detachnet()
self.net = None
net.attach(self)
self.net = net
def detachnet(self):
"""
Detach from a network.
:return: nothing
"""
if self.net is not None:
self.net.detach(self)
def addaddr(self, addr):
"""
Add address.
:param str addr: address to add
:return: nothing
"""
self.addrlist.append(addr)
def deladdr(self, addr):
"""
Delete address.
:param str addr: address to delete
:return: nothing
"""
self.addrlist.remove(addr)
def sethwaddr(self, addr):
"""
Set hardware address.
:param core.misc.ipaddress.MacAddress addr: hardware address to set to.
:return: nothing
"""
self.hwaddr = addr
def getparam(self, key):
"""
Retrieve a parameter from the, or None if the parameter does not exist.
:param key: parameter to get value for
:return: parameter value
"""
return self._params.get(key)
def getparams(self):
"""
Return (key, value) pairs for parameters.
"""
parameters = []
for k in sorted(self._params.keys()):
parameters.append((k, self._params[k]))
return parameters
def setparam(self, key, value):
"""
Set a parameter value, returns True if the parameter has changed.
:param key: parameter name to set
:param value: parameter value
:return: True if parameter changed, False otherwise
"""
# treat None and 0 as unchanged values
current_value = self._params.get(key)
if current_value == value or current_value <= 0 and value <= 0:
return False
self._params[key] = value
return True
def swapparams(self, name):
"""
Swap out parameters dict for name. If name does not exist,
intialize it. This is for supporting separate upstream/downstream
parameters when two layer-2 nodes are linked together.
:param str name: name of parameter to swap
:return: nothing
"""
tmp = self._params
if not hasattr(self, name):
setattr(self, name, {})
self._params = getattr(self, name)
setattr(self, name, tmp)
def setposition(self, x, y, z):
"""
Dispatch position hook handler.
:param x: x position
:param y: y position
:param z: z position
:return: nothing
"""
self.poshook(self, x, y, z)

View file

@ -1,10 +1,10 @@
"""
EMANE Bypass model for CORE
"""
from core.conf import ConfigGroup
from core.conf import Configuration
from core.config import ConfigGroup
from core.config import Configuration
from core.emane import emanemodel
from core.enumerations import ConfigDataTypes
from core.emulator.enumerations import ConfigDataTypes
class EmaneBypassModel(emanemodel.EmaneModel):

View file

@ -4,10 +4,10 @@ commeffect.py: EMANE CommEffect model for CORE
import logging
import os
from lxml import etree
from past.builtins import basestring
from core.conf import ConfigGroup
from core.config import ConfigGroup
from core.emane import emanemanifest
from core.emane import emanemodel
from core.xml import emanexml
@ -80,7 +80,7 @@ class EmaneCommEffectModel(emanemodel.EmaneModel):
transport_type = "virtual"
if interface and interface.transport_type == "raw":
transport_type = "raw"
transport_file = emanexml.transport_file_name(self.object_id, transport_type)
transport_file = emanexml.transport_file_name(self.id, transport_type)
etree.SubElement(nem_element, "transport", definition=transport_file)
# set shim configuration
@ -115,17 +115,17 @@ class EmaneCommEffectModel(emanemodel.EmaneModel):
"""
service = self.session.emane.service
if service is None:
logging.warn("%s: EMANE event service unavailable", self.name)
logging.warning("%s: EMANE event service unavailable", self.name)
return
if netif is None or netif2 is None:
logging.warn("%s: missing NEM information", self.name)
logging.warning("%s: missing NEM information", self.name)
return
# TODO: batch these into multiple events per transmission
# TODO: may want to split out seconds portion of delay and jitter
event = CommEffectEvent()
emane_node = self.session.get_object(self.object_id)
emane_node = self.session.get_node(self.id)
nemid = emane_node.getnemid(netif)
nemid2 = emane_node.getnemid(netif2)
mbw = bw

View file

@ -6,14 +6,13 @@ import logging
import os
import threading
from core import CoreCommandError
from core import CoreCommandError, utils
from core import constants
from core.api import coreapi
from core.api import dataconversion
from core.conf import ConfigGroup
from core.conf import ConfigShim
from core.conf import Configuration
from core.conf import ModelManager
from core.api.tlv import coreapi, dataconversion
from core.config import ConfigGroup
from core.config import ConfigShim
from core.config import Configuration
from core.config import ModelManager
from core.emane import emanemanifest
from core.emane.bypass import EmaneBypassModel
from core.emane.commeffect import EmaneCommEffectModel
@ -21,15 +20,14 @@ from core.emane.emanemodel import EmaneModel
from core.emane.ieee80211abg import EmaneIeee80211abgModel
from core.emane.rfpipe import EmaneRfPipeModel
from core.emane.tdma import EmaneTdmaModel
from core.enumerations import ConfigDataTypes
from core.enumerations import ConfigFlags
from core.enumerations import ConfigTlvs
from core.enumerations import MessageFlags
from core.enumerations import MessageTypes
from core.enumerations import NodeTypes
from core.enumerations import RegisterTlvs
from core.misc import nodeutils
from core.misc import utils
from core.emulator.enumerations import ConfigDataTypes
from core.emulator.enumerations import ConfigFlags
from core.emulator.enumerations import ConfigTlvs
from core.emulator.enumerations import MessageFlags
from core.emulator.enumerations import MessageTypes
from core.emulator.enumerations import NodeTypes
from core.emulator.enumerations import RegisterTlvs
from core.nodes import nodeutils
from core.xml import emanexml
try:
@ -109,14 +107,14 @@ class EmaneManager(ModelManager):
return self.get_configs(node_id=node_id, config_type=model_name)
else:
# don"t use default values when interface config is the same as net
# note here that using ifc.node.objid as key allows for only one type
# note here that using ifc.node.id as key allows for only one type
# of each model per node;
# TODO: use both node and interface as key
# Adamson change: first check for iface config keyed by "node:ifc.name"
# (so that nodes w/ multiple interfaces of same conftype can have
# different configs for each separate interface)
key = 1000 * interface.node.objid
key = 1000 * interface.node.id
if interface.netindex is not None:
key += interface.netindex
@ -125,7 +123,7 @@ class EmaneManager(ModelManager):
# otherwise retrieve the interfaces node configuration, avoid using defaults
if not config:
config = self.get_configs(node_id=interface.node.objid, config_type=model_name)
config = self.get_configs(node_id=interface.node.id, config_type=model_name)
# get non interface config, when none found
if not config:
@ -225,9 +223,9 @@ class EmaneManager(ModelManager):
:return: nothing
"""
with self._emane_node_lock:
if emane_node.objid in self._emane_nodes:
raise KeyError("non-unique EMANE object id %s for %s" % (emane_node.objid, emane_node))
self._emane_nodes[emane_node.objid] = emane_node
if emane_node.id in self._emane_nodes:
raise KeyError("non-unique EMANE object id %s for %s" % (emane_node.id, emane_node))
self._emane_nodes[emane_node.id] = emane_node
def getnodes(self):
"""
@ -251,10 +249,11 @@ class EmaneManager(ModelManager):
logging.debug("emane setup")
# TODO: drive this from the session object
with self.session._objects_lock:
for node in self.session.objects.itervalues():
with self.session._nodes_lock:
for node_id in self.session.nodes:
node = self.session.nodes[node_id]
if nodeutils.is_node(node, NodeTypes.EMANE):
logging.debug("adding emane node: id(%s) name(%s)", node.objid, node.name)
logging.debug("adding emane node: id(%s) name(%s)", node.id, node.name)
self.add_node(node)
if not self._emane_nodes:
@ -320,7 +319,8 @@ class EmaneManager(ModelManager):
self.startdaemons()
self.installnetifs()
for emane_node in self._emane_nodes.itervalues():
for node_id in self._emane_nodes:
emane_node = self._emane_nodes[node_id]
for netif in emane_node.netifs():
nems.append((netif.node.name, netif.name, emane_node.getnemid(netif)))
@ -345,7 +345,7 @@ class EmaneManager(ModelManager):
with self._emane_node_lock:
for key in sorted(self._emane_nodes.keys()):
emane_node = self._emane_nodes[key]
logging.debug("post startup for emane node: %s - %s", emane_node.objid, emane_node.name)
logging.debug("post startup for emane node: %s - %s", emane_node.id, emane_node.name)
emane_node.model.post_startup()
for netif in emane_node.netifs():
x, y, z = netif.node.position.get()
@ -497,7 +497,7 @@ class EmaneManager(ModelManager):
logging.info("Setting up default controlnet prefixes for distributed (%d configured)" % len(prefixes))
prefixes = ctrlnet.DEFAULT_PREFIX_LIST[0]
vals = 'controlnet="%s"' % prefixes
tlvdata = ""
tlvdata = b""
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.OBJECT.value, "session")
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.TYPE.value, 0)
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.VALUES.value, vals)
@ -517,7 +517,7 @@ class EmaneManager(ModelManager):
# skip nodes that already have a model set
if emane_node.model:
logging.debug("node(%s) already has model(%s)", emane_node.objid, emane_node.model.name)
logging.debug("node(%s) already has model(%s)", emane_node.id, emane_node.model.name)
continue
# set model configured for node, due to legacy messaging configuration before nodes exist
@ -554,7 +554,8 @@ class EmaneManager(ModelManager):
Return the number of NEMs emulated locally.
"""
count = 0
for emane_node in self._emane_nodes.itervalues():
for node_id in self._emane_nodes:
emane_node = self._emane_nodes[node_id]
count += len(emane_node.netifs())
return count
@ -644,7 +645,7 @@ class EmaneManager(ModelManager):
run_emane_on_host = True
continue
path = self.session.session_dir
n = node.objid
n = node.id
# control network not yet started here
self.session.add_remove_control_interface(node, 0, remove=False, conf_required=False)
@ -806,7 +807,7 @@ class EmaneManager(ModelManager):
for event in events:
txnemid, attrs = event
if "latitude" not in attrs or "longitude" not in attrs or "altitude" not in attrs:
logging.warn("dropped invalid location event")
logging.warning("dropped invalid location event")
continue
# yaw,pitch,roll,azimuth,elevation,velocity are unhandled
@ -828,7 +829,7 @@ class EmaneManager(ModelManager):
logging.info("location event for unknown NEM %s", nemid)
return False
n = netif.node.objid
n = netif.node.id
# convert from lat/long/alt to x,y,z coordinates
x, y, z = self.session.location.getxyz(lat, lon, alt)
x = int(x)
@ -845,7 +846,7 @@ class EmaneManager(ModelManager):
# generate a node message for this location update
try:
node = self.session.get_object(n)
node = self.session.get_node(n)
except KeyError:
logging.exception("location event NEM %s has no corresponding node %s" % (nemid, n))
return False
@ -906,8 +907,8 @@ class EmaneGlobalModel(EmaneModel):
ConfigGroup("NEM Parameters", emulator_len + 1, config_len)
]
def __init__(self, session, object_id=None):
super(EmaneGlobalModel, self).__init__(session, object_id)
def __init__(self, session, _id=None):
super(EmaneGlobalModel, self).__init__(session, _id)
def build_xml_files(self, config, interface=None):
raise NotImplementedError

View file

@ -1,7 +1,7 @@
import logging
from core.conf import Configuration
from core.enumerations import ConfigDataTypes
from core.config import Configuration
from core.emulator.enumerations import ConfigDataTypes
manifest = None
try:

View file

@ -4,11 +4,11 @@ Defines Emane Models used within CORE.
import logging
import os
from core.conf import ConfigGroup
from core.conf import Configuration
from core.config import ConfigGroup
from core.config import Configuration
from core.emane import emanemanifest
from core.enumerations import ConfigDataTypes
from core.mobility import WirelessModel
from core.emulator.enumerations import ConfigDataTypes
from core.location.mobility import WirelessModel
from core.xml import emanexml
@ -105,7 +105,7 @@ class EmaneModel(WirelessModel):
transport_type = "virtual"
if interface and interface.transport_type == "raw":
transport_type = "raw"
transport_name = emanexml.transport_file_name(self.object_id, transport_type)
transport_name = emanexml.transport_file_name(self.id, transport_type)
# create nem xml file
nem_file = os.path.join(self.session.session_dir, nem_name)
@ -138,7 +138,7 @@ class EmaneModel(WirelessModel):
:return:
"""
try:
wlan = self.session.get_object(self.object_id)
wlan = self.session.get_node(self.id)
wlan.setnempositions(moved_netifs)
except KeyError:
logging.exception("error during update")
@ -156,4 +156,4 @@ class EmaneModel(WirelessModel):
:param core.netns.vif.Veth netif2: interface two
:return: nothing
"""
logging.warn("emane model(%s) does not support link configuration", self.name)
logging.warning("emane model(%s) does not support link configuration", self.name)

View file

@ -6,10 +6,10 @@ share the same MAC+PHY model.
import logging
from core.coreobj import PyCoreNet
from core.enumerations import LinkTypes
from core.enumerations import NodeTypes
from core.enumerations import RegisterTlvs
from core.nodes.base import CoreNetworkBase
from core.emulator.enumerations import LinkTypes
from core.emulator.enumerations import NodeTypes
from core.emulator.enumerations import RegisterTlvs
try:
from emane.events import LocationEvent
@ -20,7 +20,7 @@ except ImportError:
logging.debug("compatible emane python bindings not installed")
class EmaneNet(PyCoreNet):
class EmaneNet(CoreNetworkBase):
"""
EMANE network base class.
"""
@ -37,8 +37,8 @@ class EmaneNode(EmaneNet):
Emane controller object that exists in a session.
"""
def __init__(self, session, objid=None, name=None, start=True):
super(EmaneNode, self).__init__(session, objid, name, start)
def __init__(self, session, _id=None, name=None, start=True):
super(EmaneNode, self).__init__(session, _id, name, start)
self.conf = ""
self.up = False
self.nemidmap = {}
@ -68,9 +68,9 @@ class EmaneNode(EmaneNet):
def updatemodel(self, config):
if not self.model:
raise ValueError("no model set to update for node(%s)", self.objid)
logging.info("node(%s) updating model(%s): %s", self.objid, self.model.name, config)
self.model.set_configs(config, node_id=self.objid)
raise ValueError("no model set to update for node(%s)", self.id)
logging.info("node(%s) updating model(%s): %s", self.id, self.model.name, config)
self.model.set_configs(config, node_id=self.id)
def setmodel(self, model, config):
"""
@ -80,10 +80,10 @@ class EmaneNode(EmaneNet):
if model.config_type == RegisterTlvs.WIRELESS.value:
# EmaneModel really uses values from ConfigurableManager
# when buildnemxml() is called, not during init()
self.model = model(session=self.session, object_id=self.objid)
self.model = model(session=self.session, _id=self.id)
self.model.update_config(config)
elif model.config_type == RegisterTlvs.MOBILITY.value:
self.mobility = model(session=self.session, object_id=self.objid)
self.mobility = model(session=self.session, _id=self.id)
self.mobility.update_config(config)
def setnemid(self, netif, nemid):
@ -116,7 +116,7 @@ class EmaneNode(EmaneNet):
"""
Retrieve list of linked interfaces sorted by node number.
"""
return sorted(self._netif.values(), key=lambda ifc: ifc.node.objid)
return sorted(self._netif.values(), key=lambda ifc: ifc.node.id)
def installnetifs(self):
"""
@ -130,7 +130,7 @@ class EmaneNode(EmaneNet):
logging.error(warntxt)
for netif in self.netifs():
external = self.session.emane.get_config("external", self.objid, self.model.name)
external = self.session.emane.get_config("external", self.id, self.model.name)
if external == "0":
netif.setaddrs()

View file

@ -5,11 +5,10 @@ tdma.py: EMANE TDMA model bindings for CORE
import logging
import os
from core import constants
from core.conf import Configuration
from core import constants, utils
from core.config import Configuration
from core.emane import emanemodel
from core.enumerations import ConfigDataTypes
from core.misc import utils
from core.emulator.enumerations import ConfigDataTypes
class EmaneTdmaModel(emanemodel.EmaneModel):
@ -49,7 +48,7 @@ class EmaneTdmaModel(emanemodel.EmaneModel):
:return: nothing
"""
# get configured schedule
config = self.session.emane.get_configs(node_id=self.object_id, config_type=self.name)
config = self.session.emane.get_configs(node_id=self.id, config_type=self.name)
if not config:
return
schedule = config[self.schedule_name]

View file

@ -5,19 +5,11 @@ import signal
import sys
import core.services
from core.coreobj import PyCoreNet
from core.coreobj import PyCoreNode
from core.data import NodeData
from core.emulator.emudata import LinkOptions
from core.emulator.emudata import NodeOptions
from core.enumerations import EventTypes
from core.enumerations import LinkTypes
from core.enumerations import NodeTypes
from core.misc import nodemaps
from core.misc import nodeutils
from core.service import ServiceManager
from core.session import Session
from core.xml.corexml import CoreXmlReader, CoreXmlWriter
from core.emulator.emudata import IdGen
from core.emulator.session import Session
from core.nodes import nodemaps
from core.nodes import nodeutils
from core.services.coreservices import ServiceManager
def signal_handler(signal_number, _):
@ -39,740 +31,6 @@ signal.signal(signal.SIGUSR1, signal_handler)
signal.signal(signal.SIGUSR2, signal_handler)
def create_interface(node, network, interface_data):
"""
Create an interface for a node on a network using provided interface data.
:param node: node to create interface for
:param network: network to associate interface with
:param core.emulator.emudata.InterfaceData interface_data: interface data
:return: created interface
"""
node.newnetif(
network,
addrlist=interface_data.get_addresses(),
hwaddr=interface_data.mac,
ifindex=interface_data.id,
ifname=interface_data.name
)
return node.netif(interface_data.id, network)
def link_config(network, interface, link_options, devname=None, interface_two=None):
"""
Convenience method for configuring a link,
:param network: network to configure link for
:param interface: interface to configure
:param core.emulator.emudata.LinkOptions link_options: data to configure link with
:param str devname: device name, default is None
:param interface_two: other interface associated, default is None
:return: nothing
"""
config = {
"netif": interface,
"bw": link_options.bandwidth,
"delay": link_options.delay,
"loss": link_options.per,
"duplicate": link_options.dup,
"jitter": link_options.jitter,
"netif2": interface_two
}
# hacky check here, because physical and emane nodes do not conform to the same linkconfig interface
if not nodeutils.is_node(network, [NodeTypes.EMANE, NodeTypes.PHYSICAL]):
config["devname"] = devname
network.linkconfig(**config)
def is_net_node(node):
"""
Convenience method for testing if a legacy core node is considered a network node.
:param object node: object to test against
:return: True if object is an instance of a network node, False otherwise
:rtype: bool
"""
return isinstance(node, PyCoreNet)
def is_core_node(node):
"""
Convenience method for testing if a legacy core node is considered a core node.
:param object node: object to test against
:return: True if object is an instance of a core node, False otherwise
:rtype: bool
"""
return isinstance(node, PyCoreNode)
class IdGen(object):
def __init__(self, _id=0):
self.id = _id
def next(self):
self.id += 1
return self.id
class EmuSession(Session):
def __init__(self, _id, config=None, mkdir=True):
super(EmuSession, self).__init__(_id, config, mkdir)
# object management
self.node_id_gen = IdGen()
# set default services
self.services.default_services = {
"mdr": ("zebra", "OSPFv3MDR", "IPForward"),
"PC": ("DefaultRoute",),
"prouter": ("zebra", "OSPFv2", "OSPFv3", "IPForward"),
"router": ("zebra", "OSPFv2", "OSPFv3", "IPForward"),
"host": ("DefaultRoute", "SSH"),
}
def _link_nodes(self, node_one_id, node_two_id):
"""
Convenience method for retrieving nodes within link data.
:param int node_one_id: node one id
:param int node_two_id: node two id
:return: nodes, network nodes if present, and tunnel if present
:rtype: tuple
"""
logging.debug("link message between node1(%s) and node2(%s)", node_one_id, node_two_id)
# values to fill
net_one = None
net_two = None
# retrieve node one
node_one = self.get_object(node_one_id)
node_two = self.get_object(node_two_id)
# both node ids are provided
tunnel = self.broker.gettunnel(node_one_id, node_two_id)
logging.debug("tunnel between nodes: %s", tunnel)
if nodeutils.is_node(tunnel, NodeTypes.TAP_BRIDGE):
net_one = tunnel
if tunnel.remotenum == node_one_id:
node_one = None
else:
node_two = None
# physical node connected via gre tap tunnel
elif tunnel:
if tunnel.remotenum == node_one_id:
node_one = None
else:
node_two = None
if is_net_node(node_one):
if not net_one:
net_one = node_one
else:
net_two = node_one
node_one = None
if is_net_node(node_two):
if not net_one:
net_one = node_two
else:
net_two = node_two
node_two = None
logging.debug("link node types n1(%s) n2(%s) net1(%s) net2(%s) tunnel(%s)",
node_one, node_two, net_one, net_two, tunnel)
return node_one, node_two, net_one, net_two, tunnel
# TODO: this doesn't appear to ever be used, EMANE or basic wireless range
def _link_wireless(self, objects, connect):
"""
Objects to deal with when connecting/disconnecting wireless links.
:param list objects: possible objects to deal with
:param bool connect: link interfaces if True, unlink otherwise
:return: nothing
"""
objects = [x for x in objects if x]
if len(objects) < 2:
raise ValueError("wireless link failure: %s", objects)
logging.debug("handling wireless linking objects(%s) connect(%s)", objects, connect)
common_networks = objects[0].commonnets(objects[1])
if not common_networks:
raise ValueError("no common network found for wireless link/unlink")
for common_network, interface_one, interface_two in common_networks:
if not nodeutils.is_node(common_network, [NodeTypes.WIRELESS_LAN, NodeTypes.EMANE]):
logging.info("skipping common network that is not wireless/emane: %s", common_network)
continue
logging.info("wireless linking connect(%s): %s - %s", connect, interface_one, interface_two)
if connect:
common_network.link(interface_one, interface_two)
else:
common_network.unlink(interface_one, interface_two)
def add_link(self, node_one_id, node_two_id, interface_one=None, interface_two=None, link_options=LinkOptions()):
"""
Add a link between nodes.
:param int node_one_id: node one id
:param int node_two_id: node two id
:param core.emulator.emudata.InterfaceData interface_one: node one interface data, defaults to none
:param core.emulator.emudata.InterfaceData interface_two: node two interface data, defaults to none
:param core.emulator.emudata.LinkOptions link_options: data for creating link, defaults to no options
:return:
"""
# get node objects identified by link data
node_one, node_two, net_one, net_two, tunnel = self._link_nodes(node_one_id, node_two_id)
if node_one:
node_one.lock.acquire()
if node_two:
node_two.lock.acquire()
try:
# wireless link
if link_options.type == LinkTypes.WIRELESS:
objects = [node_one, node_two, net_one, net_two]
self._link_wireless(objects, connect=True)
# wired link
else:
# 2 nodes being linked, ptp network
if all([node_one, node_two]) and not net_one:
logging.info("adding link for peer to peer nodes: %s - %s", node_one.name, node_two.name)
ptp_class = nodeutils.get_node_class(NodeTypes.PEER_TO_PEER)
start = self.state > EventTypes.DEFINITION_STATE.value
net_one = self.add_object(cls=ptp_class, start=start)
# node to network
if node_one and net_one:
logging.info("adding link from node to network: %s - %s", node_one.name, net_one.name)
interface = create_interface(node_one, net_one, interface_one)
link_config(net_one, interface, link_options)
# network to node
if node_two and net_one:
logging.info("adding link from network to node: %s - %s", node_two.name, net_one.name)
interface = create_interface(node_two, net_one, interface_two)
if not link_options.unidirectional:
link_config(net_one, interface, link_options)
# network to network
if net_one and net_two:
logging.info("adding link from network to network: %s - %s", net_one.name, net_two.name)
if nodeutils.is_node(net_two, NodeTypes.RJ45):
interface = net_two.linknet(net_one)
else:
interface = net_one.linknet(net_two)
link_config(net_one, interface, link_options)
if not link_options.unidirectional:
interface.swapparams("_params_up")
link_config(net_two, interface, link_options, devname=interface.name)
interface.swapparams("_params_up")
# a tunnel node was found for the nodes
addresses = []
if not node_one and all([net_one, interface_one]):
addresses.extend(interface_one.get_addresses())
if not node_two and all([net_two, interface_two]):
addresses.extend(interface_two.get_addresses())
# tunnel node logic
key = link_options.key
if key and nodeutils.is_node(net_one, NodeTypes.TUNNEL):
logging.info("setting tunnel key for: %s", net_one.name)
net_one.setkey(key)
if addresses:
net_one.addrconfig(addresses)
if key and nodeutils.is_node(net_two, NodeTypes.TUNNEL):
logging.info("setting tunnel key for: %s", net_two.name)
net_two.setkey(key)
if addresses:
net_two.addrconfig(addresses)
# physical node connected with tunnel
if not net_one and not net_two and (node_one or node_two):
if node_one and nodeutils.is_node(node_one, NodeTypes.PHYSICAL):
logging.info("adding link for physical node: %s", node_one.name)
addresses = interface_one.get_addresses()
node_one.adoptnetif(tunnel, interface_one.id, interface_one.mac, addresses)
link_config(node_one, tunnel, link_options)
elif node_two and nodeutils.is_node(node_two, NodeTypes.PHYSICAL):
logging.info("adding link for physical node: %s", node_two.name)
addresses = interface_two.get_addresses()
node_two.adoptnetif(tunnel, interface_two.id, interface_two.mac, addresses)
link_config(node_two, tunnel, link_options)
finally:
if node_one:
node_one.lock.release()
if node_two:
node_two.lock.release()
def delete_link(self, node_one_id, node_two_id, interface_one_id, interface_two_id, link_type=LinkTypes.WIRED):
"""
Delete a link between nodes.
:param int node_one_id: node one id
:param int node_two_id: node two id
:param int interface_one_id: interface id for node one
:param int interface_two_id: interface id for node two
:param core.enumerations.LinkTypes link_type: link type to delete
:return: nothing
"""
# get node objects identified by link data
node_one, node_two, net_one, net_two, _tunnel = self._link_nodes(node_one_id, node_two_id)
if node_one:
node_one.lock.acquire()
if node_two:
node_two.lock.acquire()
try:
# wireless link
if link_type == LinkTypes.WIRELESS:
objects = [node_one, node_two, net_one, net_two]
self._link_wireless(objects, connect=False)
# wired link
else:
if all([node_one, node_two]):
# TODO: fix this for the case where ifindex[1,2] are not specified
# a wired unlink event, delete the connecting bridge
interface_one = node_one.netif(interface_one_id)
interface_two = node_two.netif(interface_two_id)
# get interfaces from common network, if no network node
# otherwise get interfaces between a node and network
if not interface_one and not interface_two:
common_networks = node_one.commonnets(node_two)
for network, common_interface_one, common_interface_two in common_networks:
if (net_one and network == net_one) or not net_one:
interface_one = common_interface_one
interface_two = common_interface_two
break
if all([interface_one, interface_two]) and any([interface_one.net, interface_two.net]):
if interface_one.net != interface_two.net and all([interface_one.up, interface_two.up]):
raise ValueError("no common network found")
logging.info("deleting link node(%s):interface(%s) node(%s):interface(%s)",
node_one.name, interface_one.name, node_two.name, interface_two.name)
net_one = interface_one.net
interface_one.detachnet()
interface_two.detachnet()
if net_one.numnetif() == 0:
self.delete_object(net_one.objid)
node_one.delnetif(interface_one.netindex)
node_two.delnetif(interface_two.netindex)
finally:
if node_one:
node_one.lock.release()
if node_two:
node_two.lock.release()
def update_link(self, node_one_id, node_two_id, interface_one_id=None, interface_two_id=None,
link_options=LinkOptions()):
"""
Update link information between nodes.
:param int node_one_id: node one id
:param int node_two_id: node two id
:param int interface_one_id: interface id for node one
:param int interface_two_id: interface id for node two
:param core.emulator.emudata.LinkOptions link_options: data to update link with
:return: nothing
"""
# get node objects identified by link data
node_one, node_two, net_one, net_two, _tunnel = self._link_nodes(node_one_id, node_two_id)
if node_one:
node_one.lock.acquire()
if node_two:
node_two.lock.acquire()
try:
# wireless link
if link_options.type == LinkTypes.WIRELESS.value:
raise ValueError("cannot update wireless link")
else:
if not node_one and not node_two:
if net_one and net_two:
# modify link between nets
interface = net_one.getlinknetif(net_two)
upstream = False
if not interface:
upstream = True
interface = net_two.getlinknetif(net_one)
if not interface:
raise ValueError("modify unknown link between nets")
if upstream:
interface.swapparams("_params_up")
link_config(net_one, interface, link_options, devname=interface.name)
interface.swapparams("_params_up")
else:
link_config(net_one, interface, link_options)
if not link_options.unidirectional:
if upstream:
link_config(net_two, interface, link_options)
else:
interface.swapparams("_params_up")
link_config(net_two, interface, link_options, devname=interface.name)
interface.swapparams("_params_up")
else:
raise ValueError("modify link for unknown nodes")
elif not node_one:
# node1 = layer 2node, node2 = layer3 node
interface = node_two.netif(interface_two_id, net_one)
link_config(net_one, interface, link_options)
elif not node_two:
# node2 = layer 2node, node1 = layer3 node
interface = node_one.netif(interface_one_id, net_one)
link_config(net_one, interface, link_options)
else:
common_networks = node_one.commonnets(node_two)
if not common_networks:
raise ValueError("no common network found")
for net_one, interface_one, interface_two in common_networks:
if interface_one_id is not None and interface_one_id != node_one.getifindex(interface_one):
continue
link_config(net_one, interface_one, link_options, interface_two=interface_two)
if not link_options.unidirectional:
link_config(net_one, interface_two, link_options, interface_two=interface_one)
finally:
if node_one:
node_one.lock.release()
if node_two:
node_two.lock.release()
def add_node(self, _type=NodeTypes.DEFAULT, _id=None, node_options=NodeOptions()):
"""
Add a node to the session, based on the provided node data.
:param core.enumerations.NodeTypes _type: type of node to create
:param int _id: id for node, defaults to None for generated id
:param core.emulator.emudata.NodeOptions node_options: data to create node with
:return: created node
"""
# retrieve node class for given node type
try:
node_class = nodeutils.get_node_class(_type)
except KeyError:
logging.error("invalid node type to create: %s", _type)
return None
# set node start based on current session state, override and check when rj45
start = self.state > EventTypes.DEFINITION_STATE.value
enable_rj45 = self.options.get_config("enablerj45") == "1"
if _type == NodeTypes.RJ45 and not enable_rj45:
start = False
# determine node id
if not _id:
while True:
_id = self.node_id_gen.next()
if _id not in self.objects:
break
# generate name if not provided
name = node_options.name
if not name:
name = "%s%s" % (node_class.__name__, _id)
# create node
logging.info("creating node(%s) id(%s) name(%s) start(%s)", node_class.__name__, _id, name, start)
node = self.add_object(cls=node_class, objid=_id, name=name, start=start)
# set node attributes
node.icon = node_options.icon
node.canvas = node_options.canvas
node.opaque = node_options.opaque
# set node position and broadcast it
self.set_node_position(node, node_options)
# add services to default and physical nodes only
if _type in [NodeTypes.DEFAULT, NodeTypes.PHYSICAL]:
node.type = node_options.model
logging.debug("set node type: %s", node.type)
self.services.add_services(node, node.type, node_options.services)
# boot nodes if created after runtime, LcxNodes, Physical, and RJ45 are all PyCoreNodes
is_boot_node = isinstance(node, PyCoreNode) and not nodeutils.is_node(node, NodeTypes.RJ45)
if self.state == EventTypes.RUNTIME_STATE.value and is_boot_node:
self.write_objects()
self.add_remove_control_interface(node=node, remove=False)
self.services.boot_services(node)
return node
def update_node(self, node_id, node_options):
"""
Update node information.
:param int node_id: id of node to update
:param core.emulator.emudata.NodeOptions node_options: data to update node with
:return: True if node updated, False otherwise
:rtype: bool
"""
result = False
try:
# get node to update
node = self.get_object(node_id)
# set node position and broadcast it
self.set_node_position(node, node_options)
# update attributes
node.canvas = node_options.canvas
node.icon = node_options.icon
# set node as updated successfully
result = True
except KeyError:
logging.error("failure to update node that does not exist: %s", node_id)
return result
def delete_node(self, node_id):
"""
Delete a node from the session and check if session should shutdown, if no nodes are left.
:param int node_id: id of node to delete
:return: True if node deleted, False otherwise
:rtype: bool
"""
# delete node and check for session shutdown if a node was removed
result = self.custom_delete_object(node_id)
if result:
self.check_shutdown()
return result
def set_node_position(self, node, node_options):
"""
Set position for a node, use lat/lon/alt if needed.
:param node: node to set position for
:param core.emulator.emudata.NodeOptions node_options: data for node
:return: nothing
"""
# extract location values
x = node_options.x
y = node_options.y
lat = node_options.lat
lon = node_options.lon
alt = node_options.alt
# check if we need to generate position from lat/lon/alt
has_empty_position = all(i is None for i in [x, y])
has_lat_lon_alt = all(i is not None for i in [lat, lon, alt])
using_lat_lon_alt = has_empty_position and has_lat_lon_alt
if using_lat_lon_alt:
x, y, _ = self.location.getxyz(lat, lon, alt)
# set position and broadcast
if None not in [x, y]:
node.setposition(x, y, None)
# broadcast updated location when using lat/lon/alt
if using_lat_lon_alt:
self.broadcast_node_location(node)
def broadcast_node_location(self, node):
"""
Broadcast node location to all listeners.
:param core.netns.nodes.PyCoreObj node: node to broadcast location for
:return: nothing
"""
node_data = NodeData(
message_type=0,
id=node.objid,
x_position=node.position.x,
y_position=node.position.y
)
self.broadcast_node(node_data)
def start_mobility(self, node_ids=None):
"""
Start mobility for the provided node ids.
:param list[int] node_ids: nodes to start mobility for
:return: nothing
"""
self.mobility.startup(node_ids)
def shutdown(self):
"""
Shutdown session.
:return: nothing
"""
logging.info("session(%s) shutting down", self.id)
self.set_state(EventTypes.DATACOLLECT_STATE, send_event=True)
self.set_state(EventTypes.SHUTDOWN_STATE, send_event=True)
super(EmuSession, self).shutdown()
def custom_delete_object(self, object_id):
"""
Remove an emulation object.
:param int object_id: object id to remove
:return: True if object deleted, False otherwise
"""
result = False
with self._objects_lock:
if object_id in self.objects:
obj = self.objects.pop(object_id)
obj.shutdown()
result = True
return result
def is_active(self):
"""
Determine if this session is considered to be active. (Runtime or Data collect states)
:return: True if active, False otherwise
"""
result = self.state in {EventTypes.RUNTIME_STATE.value, EventTypes.DATACOLLECT_STATE.value}
logging.info("session(%s) checking if active: %s", self.id, result)
return result
def open_xml(self, file_name, start=False):
"""
Import a session from the EmulationScript XML format.
:param str file_name: xml file to load session from
:param bool start: instantiate session if true, false otherwise
:return: nothing
"""
# clear out existing session
self.clear()
# write out xml file
CoreXmlReader(self).read(file_name)
# start session if needed
if start:
self.name = os.path.basename(file_name)
self.file_name = file_name
self.instantiate()
def save_xml(self, file_name):
"""
Export a session to the EmulationScript XML format.
:param str file_name: file name to write session xml to
:return: nothing
"""
CoreXmlWriter(self).write(file_name)
def add_hook(self, state, file_name, source_name, data):
"""
Store a hook from a received file message.
:param int state: when to run hook
:param str file_name: file name for hook
:param str source_name: source name
:param data: hook data
:return: nothing
"""
# hack to conform with old logic until updated
state = ":%s" % state
self.set_hook(state, file_name, source_name, data)
def add_node_file(self, node_id, source_name, file_name, data):
"""
Add a file to a node.
:param int node_id: node to add file to
:param str source_name: source file name
:param str file_name: file name to add
:param str data: file data
:return: nothing
"""
node = self.get_object(node_id)
if source_name is not None:
node.addfile(source_name, file_name)
elif data is not None:
node.nodefile(file_name, data)
def clear(self):
"""
Clear all CORE session data. (objects, hooks, broker)
:return: nothing
"""
self.delete_objects()
self.del_hooks()
self.broker.reset()
self.emane.reset()
def start_events(self):
"""
Start event loop.
:return: nothing
"""
self.event_loop.run()
def mobility_event(self, event_data):
"""
Handle a mobility event.
:param core.data.EventData event_data: event data to handle
:return: nothing
"""
self.mobility.handleevent(event_data)
def create_wireless_node(self, _id=None, node_options=NodeOptions()):
"""
Create a wireless node for use within an wireless/EMANE networks.
:param int _id: int for node, defaults to None and will be generated
:param core.emulator.emudata.NodeOptions node_options: options for emane node, model will always be "mdr"
:return: new emane node
:rtype: core.netns.nodes.CoreNode
"""
node_options.model = "mdr"
return self.add_node(_type=NodeTypes.DEFAULT, _id=_id, node_options=node_options)
def create_emane_network(self, model, geo_reference, geo_scale=None, node_options=NodeOptions(), config=None):
"""
Convenience method for creating an emane network.
:param model: emane model to use for emane network
:param geo_reference: geo reference point to use for emane node locations
:param geo_scale: geo scale to use for emane node locations, defaults to 1.0
:param core.emulator.emudata.NodeOptions node_options: options for emane node being created
:param dict config: emane model configuration
:return: create emane network
"""
# required to be set for emane to function properly
self.location.setrefgeo(*geo_reference)
if geo_scale:
self.location.refscale = geo_scale
# create and return network
emane_network = self.add_node(_type=NodeTypes.EMANE, node_options=node_options)
self.emane.set_model(emane_network, model, config)
return emane_network
class CoreEmu(object):
"""
Provides logic for creating and configuring CORE sessions and the nodes within them.
@ -793,7 +51,7 @@ class CoreEmu(object):
self.config = config
# session management
self.session_id_gen = IdGen(_id=59999)
self.session_id_gen = IdGen(_id=0)
self.sessions = {}
# set default nodes
@ -838,33 +96,31 @@ class CoreEmu(object):
logging.info("shutting down all sessions")
sessions = self.sessions.copy()
self.sessions.clear()
for session in sessions.itervalues():
for _id in sessions:
session = sessions[_id]
session.shutdown()
def create_session(self, _id=None, master=True, _cls=EmuSession):
def create_session(self, _id=None, master=True):
"""
Create a new CORE session, set to master if running standalone.
:param int _id: session id for new session
:param bool master: sets session to master
:param class _cls: EmuSession class to use
:return: created session
:rtype: EmuSession
"""
session_id = _id
if not session_id:
if not _id:
while True:
session_id = self.session_id_gen.next()
if session_id not in self.sessions:
_id = self.session_id_gen.next()
if _id not in self.sessions:
break
session = _cls(session_id, config=self.config)
logging.info("created session: %s", session_id)
session = Session(_id, config=self.config)
logging.info("created session: %s", _id)
if master:
session.master = True
self.sessions[session_id] = session
self.sessions[_id] = session
return session
def delete_session(self, _id):

View file

@ -1,7 +1,77 @@
from core.enumerations import LinkTypes
from core.misc.ipaddress import Ipv4Prefix
from core.misc.ipaddress import Ipv6Prefix
from core.misc.ipaddress import MacAddress
from core.emulator.enumerations import LinkTypes
from core.emulator.enumerations import NodeTypes
from core.nodes import nodeutils
from core.nodes.base import CoreNetworkBase
from core.nodes.ipaddress import Ipv4Prefix
from core.nodes.ipaddress import Ipv6Prefix
from core.nodes.ipaddress import MacAddress
class IdGen(object):
def __init__(self, _id=0):
self.id = _id
def next(self):
self.id += 1
return self.id
def is_net_node(node):
"""
Convenience method for testing if a legacy core node is considered a network node.
:param object node: object to test against
:return: True if object is an instance of a network node, False otherwise
:rtype: bool
"""
return isinstance(node, CoreNetworkBase)
def create_interface(node, network, interface_data):
"""
Create an interface for a node on a network using provided interface data.
:param node: node to create interface for
:param network: network to associate interface with
:param core.emulator.emudata.InterfaceData interface_data: interface data
:return: created interface
"""
node.newnetif(
network,
addrlist=interface_data.get_addresses(),
hwaddr=interface_data.mac,
ifindex=interface_data.id,
ifname=interface_data.name
)
return node.netif(interface_data.id, network)
def link_config(network, interface, link_options, devname=None, interface_two=None):
"""
Convenience method for configuring a link,
:param network: network to configure link for
:param interface: interface to configure
:param core.emulator.emudata.LinkOptions link_options: data to configure link with
:param str devname: device name, default is None
:param interface_two: other interface associated, default is None
:return: nothing
"""
config = {
"netif": interface,
"bw": link_options.bandwidth,
"delay": link_options.delay,
"loss": link_options.per,
"duplicate": link_options.dup,
"jitter": link_options.jitter,
"netif2": interface_two
}
# hacky check here, because physical and emane nodes do not conform to the same linkconfig interface
if not nodeutils.is_node(network, [NodeTypes.EMANE, NodeTypes.PHYSICAL]):
config["devname"] = devname
network.linkconfig(**config)
class NodeOptions(object):
@ -9,7 +79,7 @@ class NodeOptions(object):
Options for creating and updating nodes within core.
"""
def __init__(self, name=None, model="router"):
def __init__(self, name=None, model="PC"):
"""
Create a NodeOptions object.
@ -117,7 +187,7 @@ class IpPrefixes(object):
"""
if not self.ip4:
raise ValueError("ip4 prefixes have not been set")
return str(self.ip4.addr(node.objid))
return str(self.ip4.addr(node.id))
def ip6_address(self, node):
"""
@ -129,7 +199,7 @@ class IpPrefixes(object):
"""
if not self.ip6:
raise ValueError("ip6 prefixes have not been set")
return str(self.ip6.addr(node.objid))
return str(self.ip6.addr(node.id))
def create_interface(self, node, name=None, mac=None):
"""
@ -149,14 +219,14 @@ class IpPrefixes(object):
ip4 = None
ip4_mask = None
if self.ip4:
ip4 = str(self.ip4.addr(node.objid))
ip4 = str(self.ip4.addr(node.id))
ip4_mask = self.ip4.prefixlen
# generate ip6 data
ip6 = None
ip6_mask = None
if self.ip6:
ip6 = str(self.ip6.addr(node.objid))
ip6 = str(self.ip6.addr(node.id))
ip6_mask = self.ip6.prefixlen
# random mac

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,62 @@
from core.config import ConfigurableManager
from core.config import ConfigurableOptions
from core.config import Configuration
from core.emulator.enumerations import ConfigDataTypes
from core.emulator.enumerations import RegisterTlvs
from core.plugins.sdt import Sdt
class SessionConfig(ConfigurableManager, ConfigurableOptions):
"""
Provides session configuration.
"""
name = "session"
options = [
Configuration(_id="controlnet", _type=ConfigDataTypes.STRING, label="Control Network"),
Configuration(_id="controlnet0", _type=ConfigDataTypes.STRING, label="Control Network 0"),
Configuration(_id="controlnet1", _type=ConfigDataTypes.STRING, label="Control Network 1"),
Configuration(_id="controlnet2", _type=ConfigDataTypes.STRING, label="Control Network 2"),
Configuration(_id="controlnet3", _type=ConfigDataTypes.STRING, label="Control Network 3"),
Configuration(_id="controlnet_updown_script", _type=ConfigDataTypes.STRING, label="Control Network Script"),
Configuration(_id="enablerj45", _type=ConfigDataTypes.BOOL, default="1", options=["On", "Off"],
label="Enable RJ45s"),
Configuration(_id="preservedir", _type=ConfigDataTypes.BOOL, default="0", options=["On", "Off"],
label="Preserve session dir"),
Configuration(_id="enablesdt", _type=ConfigDataTypes.BOOL, default="0", options=["On", "Off"],
label="Enable SDT3D output"),
Configuration(_id="sdturl", _type=ConfigDataTypes.STRING, default=Sdt.DEFAULT_SDT_URL, label="SDT3D URL")
]
config_type = RegisterTlvs.UTILITY.value
def __init__(self):
super(SessionConfig, self).__init__()
self.set_configs(self.default_values())
def get_config(self, _id, node_id=ConfigurableManager._default_node,
config_type=ConfigurableManager._default_type, default=None):
value = super(SessionConfig, self).get_config(_id, node_id, config_type, default)
if value == "":
value = default
return value
def get_config_bool(self, name, default=None):
value = self.get_config(name)
if value is None:
return default
return value.lower() == "true"
def get_config_int(self, name, default=None):
value = self.get_config(name, default=default)
if value is not None:
value = int(value)
return value
class SessionMetaData(ConfigurableManager):
"""
Metadata is simply stored in a configs[] dict. Key=value pairs are
passed in from configure messages destined to the "metadata" object.
The data is not otherwise interpreted or processed.
"""
name = "metadata"
config_type = RegisterTlvs.UTILITY.value

View file

@ -7,8 +7,8 @@ https://pypi.python.org/pypi/utm (version 0.3.0).
import logging
from core.enumerations import RegisterTlvs
from core.misc import utm
from core.emulator.enumerations import RegisterTlvs
from core.location import utm
class CoreLocation(object):

View file

@ -5,6 +5,7 @@ event.py: event loop implementation using a heap queue and threads.
import heapq
import threading
import time
from past.builtins import cmp
class Timer(threading.Thread):

View file

@ -8,23 +8,25 @@ import math
import os
import threading
import time
from builtins import int
from past.builtins import cmp
from core.conf import ConfigGroup
from core.conf import ConfigurableOptions
from core.conf import Configuration
from core.conf import ModelManager
from core.coreobj import PyCoreNode
from core.data import EventData
from core.data import LinkData
from core.enumerations import ConfigDataTypes
from core.enumerations import EventTypes
from core.enumerations import LinkTypes
from core.enumerations import MessageFlags
from core.enumerations import MessageTypes
from core.enumerations import NodeTlvs
from core.enumerations import RegisterTlvs
from core.misc import utils
from core.misc.ipaddress import IpAddress
from core import utils
from core.config import ConfigGroup
from core.config import ConfigurableOptions
from core.config import Configuration
from core.config import ModelManager
from core.emulator.data import EventData
from core.emulator.data import LinkData
from core.emulator.enumerations import ConfigDataTypes
from core.emulator.enumerations import EventTypes
from core.emulator.enumerations import LinkTypes
from core.emulator.enumerations import MessageFlags
from core.emulator.enumerations import MessageTypes
from core.emulator.enumerations import NodeTlvs
from core.emulator.enumerations import RegisterTlvs
from core.nodes.base import CoreNodeBase
from core.nodes.ipaddress import IpAddress
class MobilityManager(ModelManager):
@ -67,12 +69,12 @@ class MobilityManager(ModelManager):
logging.info("node mobility configurations: %s", self.get_all_configs(node_id))
try:
node = self.session.get_object(node_id)
node = self.session.get_node(node_id)
except KeyError:
logging.warn("skipping mobility configuration for unknown node: %s", node_id)
logging.warning("skipping mobility configuration for unknown node: %s", node_id)
continue
for model_name in self.models.iterkeys():
for model_name in self.models:
config = self.get_configs(node_id, model_name)
if not config:
continue
@ -98,7 +100,7 @@ class MobilityManager(ModelManager):
name = event_data.name
try:
node = self.session.get_object(node_id)
node = self.session.get_node(node_id)
except KeyError:
logging.exception("Ignoring event for model '%s', unknown node '%s'", name, node_id)
return
@ -109,7 +111,7 @@ class MobilityManager(ModelManager):
try:
cls = self.models[model]
except KeyError:
logging.warn("Ignoring event for unknown model '%s'", model)
logging.warning("Ignoring event for unknown model '%s'", model)
continue
if cls.config_type in [RegisterTlvs.WIRELESS.value, RegisterTlvs.MOBILITY.value]:
@ -118,11 +120,11 @@ class MobilityManager(ModelManager):
continue
if model is None:
logging.warn("Ignoring event, %s has no model", node.name)
logging.warning("Ignoring event, %s has no model", node.name)
continue
if cls.name != model.name:
logging.warn("Ignoring event for %s wrong model %s,%s", node.name, cls.name, model.name)
logging.warning("Ignoring event for %s wrong model %s,%s", node.name, cls.name, model.name)
continue
if event_type == EventTypes.STOP.value or event_type == EventTypes.RESTART.value:
@ -152,7 +154,7 @@ class MobilityManager(ModelManager):
data += " end=%d" % int(model.endtime)
event_data = EventData(
node=model.object_id,
node=model.id,
event_type=event_type,
name="mobility:%s" % model.name,
data=data,
@ -173,7 +175,7 @@ class MobilityManager(ModelManager):
"""
for node_id in self.nodes():
try:
node = self.session.get_object(node_id)
node = self.session.get_node(node_id)
except KeyError:
continue
if node.model:
@ -187,7 +189,7 @@ class MobilityManager(ModelManager):
:param core.coreobj.PyCoreNode node: node to add physical network to
:return: nothing
"""
node_id = node.objid
node_id = node.id
self.phys[node_id] = node
if netnum not in self.physnets:
self.physnets[netnum] = [node_id, ]
@ -213,7 +215,7 @@ class MobilityManager(ModelManager):
return
if nn[1] in self.session.broker.physical_nodes:
# record the fact that this PhysicalNode is linked to a net
dummy = PyCoreNode(session=self.session, objid=nn[1], name="n%d" % nn[1], start=False)
dummy = CoreNodeBase(session=self.session, _id=nn[1], name="n%d" % nn[1], start=False)
self.addphys(nn[0], dummy)
# TODO: remove need to handling old style messages
@ -243,13 +245,13 @@ class MobilityManager(ModelManager):
:param net: network to install
:return: nothing
"""
nodenums = self.physnets.get(net.objid, [])
for nodenum in nodenums:
node = self.phys[nodenum]
node_ids = self.physnets.get(net.id, [])
for node_id in node_ids:
node = self.phys[node_id]
# TODO: fix this bad logic, relating to depending on a break to get a valid server
for server in self.session.broker.getserversbynode(nodenum):
for server in self.session.broker.getserversbynode(node_id):
break
netif = self.session.broker.gettunnel(net.objid, IpAddress.to_int(server.host))
netif = self.session.broker.gettunnel(net.id, IpAddress.to_int(server.host))
node.addnetif(netif, 0)
netif.node = node
x, y, z = netif.node.position.get()
@ -265,15 +267,15 @@ class WirelessModel(ConfigurableOptions):
bitmap = None
position_callback = None
def __init__(self, session, object_id):
def __init__(self, session, _id):
"""
Create a WirelessModel instance.
:param core.session.Session session: core session we are tied to
:param int object_id: object id
:param int _id: object id
"""
self.session = session
self.object_id = object_id
self.id = _id
def all_link_data(self, flags):
"""
@ -329,17 +331,17 @@ class BasicRangeModel(WirelessModel):
ConfigGroup("Basic Range Parameters", 1, len(cls.configurations()))
]
def __init__(self, session, object_id):
def __init__(self, session, _id):
"""
Create a BasicRangeModel instance.
:param core.session.Session session: related core session
:param int object_id: object id
:param int _id: object id
:param dict config: values
"""
super(BasicRangeModel, self).__init__(session=session, object_id=object_id)
super(BasicRangeModel, self).__init__(session=session, _id=_id)
self.session = session
self.wlan = session.get_object(object_id)
self.wlan = session.get_node(_id)
self._netifs = {}
self._netifslock = threading.Lock()
@ -357,7 +359,7 @@ class BasicRangeModel(WirelessModel):
:return: nothing
"""
self.range = float(config["range"])
logging.info("basic range model configured for WLAN %d using range %d", self.wlan.objid, self.range)
logging.info("basic range model configured for WLAN %d using range %d", self.wlan.id, self.range)
self.bw = int(config["bandwidth"])
if self.bw == 0.0:
self.bw = None
@ -521,9 +523,9 @@ class BasicRangeModel(WirelessModel):
"""
return LinkData(
message_type=message_type,
node1_id=interface1.node.objid,
node2_id=interface2.node.objid,
network_id=self.wlan.objid,
node1_id=interface1.node.id,
node2_id=interface2.node.id,
network_id=self.wlan.id,
link_type=LinkTypes.WIRELESS.value
)
@ -605,15 +607,15 @@ class WayPointMobility(WirelessModel):
STATE_RUNNING = 1
STATE_PAUSED = 2
def __init__(self, session, object_id):
def __init__(self, session, _id):
"""
Create a WayPointMobility instance.
:param core.session.Session session: CORE session instance
:param int object_id: object id
:param int _id: object id
:return:
"""
super(WayPointMobility, self).__init__(session=session, object_id=object_id)
super(WayPointMobility, self).__init__(session=session, _id=_id)
self.state = self.STATE_STOPPED
self.queue = []
@ -622,7 +624,7 @@ class WayPointMobility(WirelessModel):
self.initial = {}
self.lasttime = None
self.endtime = None
self.wlan = session.get_object(object_id)
self.wlan = session.get_node(_id)
# these are really set in child class via confmatrix
self.loop = False
self.refresh_ms = 50
@ -700,20 +702,20 @@ class WayPointMobility(WirelessModel):
Calculate next node location and update its coordinates.
Returns True if the node's position has changed.
:param core.netns.nodes.CoreNode node: node to move
:param core.netns.vnode.CoreNode node: node to move
:param dt: move factor
:return: True if node was moved, False otherwise
:rtype: bool
"""
if node.objid not in self.points:
if node.id not in self.points:
return False
x1, y1, z1 = node.getposition()
x2, y2, z2 = self.points[node.objid].coords
speed = self.points[node.objid].speed
x2, y2, z2 = self.points[node.id].coords
speed = self.points[node.id].speed
# instantaneous move (prevents dx/dy == 0.0 below)
if speed == 0:
self.setnodeposition(node, x2, y2, z2)
del self.points[node.objid]
del self.points[node.id]
return True
# speed can be a velocity vector (ns3 mobility) or speed value
if isinstance(speed, (float, int)):
@ -739,7 +741,7 @@ class WayPointMobility(WirelessModel):
# the last node to reach the last waypoint determines this
# script's endtime
self.endtime = self.lasttime - self.timezero
del self.points[node.objid]
del self.points[node.id]
return False
if (x1 + dx) < 0.0:
dx = 0.0 - x1
@ -758,9 +760,9 @@ class WayPointMobility(WirelessModel):
moved_netifs = []
for netif in self.wlan.netifs():
node = netif.node
if node.objid not in self.initial:
if node.id not in self.initial:
continue
x, y, z = self.initial[node.objid].coords
x, y, z = self.initial[node.id].coords
self.setnodeposition(node, x, y, z)
moved.append(node)
moved_netifs.append(netif)
@ -830,7 +832,7 @@ class WayPointMobility(WirelessModel):
without invoking the interface poshook callback that may perform
range calculation.
:param core.netns.nodes.CoreNode node: node to set position for
:param core.netns.vnode.CoreNode node: node to set position for
:param x: x position
:param y: y position
:param z: z position
@ -923,15 +925,15 @@ class Ns2ScriptedMobility(WayPointMobility):
ConfigGroup("ns-2 Mobility Script Parameters", 1, len(cls.configurations()))
]
def __init__(self, session, object_id):
def __init__(self, session, _id):
"""
Creates a Ns2ScriptedMobility instance.
:param core.session.Session session: CORE session instance
:param int object_id: object id
:param int _id: object id
:param config: values
"""
super(Ns2ScriptedMobility, self).__init__(session=session, object_id=object_id)
super(Ns2ScriptedMobility, self).__init__(session=session, _id=_id)
self._netifs = {}
self._netifslock = threading.Lock()
@ -946,7 +948,7 @@ class Ns2ScriptedMobility(WayPointMobility):
def update_config(self, config):
self.file = config["file"]
logging.info("ns-2 scripted mobility configured for WLAN %d using file: %s", self.object_id, self.file)
logging.info("ns-2 scripted mobility configured for WLAN %d using file: %s", self.id, self.file)
self.refresh_ms = int(config["refresh_ms"])
self.loop = config["loop"].lower() == "on"
self.autostart = config["autostart"]

View file

@ -1,246 +0,0 @@
#!/usr/bin/env python
# this file is from http://pygps.org/
# Lat Long - UTM, UTM - Lat Long conversions
from math import pi, sin, cos, tan, sqrt
# LatLong- UTM conversion..h
# definitions for lat/long to UTM and UTM to lat/lng conversions
# include <string.h>
_deg2rad = pi / 180.0
_rad2deg = 180.0 / pi
_EquatorialRadius = 2
_eccentricitySquared = 3
_ellipsoid = [
# id, Ellipsoid name, Equatorial Radius, square of eccentricity
# first once is a placeholder only, To allow array indices to match id numbers
[-1, "Placeholder", 0, 0],
[1, "Airy", 6377563, 0.00667054],
[2, "Australian National", 6378160, 0.006694542],
[3, "Bessel 1841", 6377397, 0.006674372],
[4, "Bessel 1841 (Nambia] ", 6377484, 0.006674372],
[5, "Clarke 1866", 6378206, 0.006768658],
[6, "Clarke 1880", 6378249, 0.006803511],
[7, "Everest", 6377276, 0.006637847],
[8, "Fischer 1960 (Mercury] ", 6378166, 0.006693422],
[9, "Fischer 1968", 6378150, 0.006693422],
[10, "GRS 1967", 6378160, 0.006694605],
[11, "GRS 1980", 6378137, 0.00669438],
[12, "Helmert 1906", 6378200, 0.006693422],
[13, "Hough", 6378270, 0.00672267],
[14, "International", 6378388, 0.00672267],
[15, "Krassovsky", 6378245, 0.006693422],
[16, "Modified Airy", 6377340, 0.00667054],
[17, "Modified Everest", 6377304, 0.006637847],
[18, "Modified Fischer 1960", 6378155, 0.006693422],
[19, "South American 1969", 6378160, 0.006694542],
[20, "WGS 60", 6378165, 0.006693422],
[21, "WGS 66", 6378145, 0.006694542],
[22, "WGS-72", 6378135, 0.006694318],
[23, "WGS-84", 6378137, 0.00669438]
]
# Reference ellipsoids derived from Peter H. Dana's website-
# http://www.utexas.edu/depts/grg/gcraft/notes/datum/elist.html
# Department of Geography, University of Texas at Austin
# Internet: pdana@mail.utexas.edu
# 3/22/95
# Source
# Defense Mapping Agency. 1987b. DMA Technical Report: Supplement to Department of Defense World Geodetic System
# 1984 Technical Report. Part I and II. Washington, DC: Defense Mapping Agency
# def LLtoUTM(int ReferenceEllipsoid, const double Lat, const double Long,
# double &UTMNorthing, double &UTMEasting, char* UTMZone)
def LLtoUTM(ReferenceEllipsoid, Lat, Long, zone=None):
"""converts lat/long to UTM coords. Equations from USGS Bulletin 1532
East Longitudes are positive, West longitudes are negative.
North latitudes are positive, South latitudes are negative
Lat and Long are in decimal degrees
Written by Chuck Gantz- chuck.gantz@globalstar.com"""
a = _ellipsoid[ReferenceEllipsoid][_EquatorialRadius]
eccSquared = _ellipsoid[ReferenceEllipsoid][_eccentricitySquared]
k0 = 0.9996
# Make sure the longitude is between -180.00 .. 179.9
LongTemp = (Long + 180) - int((Long + 180) / 360) * 360 - 180 # -180.00 .. 179.9
LatRad = Lat * _deg2rad
LongRad = LongTemp * _deg2rad
if zone is None:
ZoneNumber = int((LongTemp + 180) / 6) + 1
else:
ZoneNumber = zone
if Lat >= 56.0 and Lat < 64.0 and LongTemp >= 3.0 and LongTemp < 12.0:
ZoneNumber = 32
# Special zones for Svalbard
if Lat >= 72.0 and Lat < 84.0:
if LongTemp >= 0.0 and LongTemp < 9.0:
ZoneNumber = 31
elif LongTemp >= 9.0 and LongTemp < 21.0:
ZoneNumber = 33
elif LongTemp >= 21.0 and LongTemp < 33.0:
ZoneNumber = 35
elif LongTemp >= 33.0 and LongTemp < 42.0:
ZoneNumber = 37
LongOrigin = (ZoneNumber - 1) * 6 - 180 + 3 # +3 puts origin in middle of zone
LongOriginRad = LongOrigin * _deg2rad
# compute the UTM Zone from the latitude and longitude
UTMZone = "%d%c" % (ZoneNumber, _UTMLetterDesignator(Lat))
eccPrimeSquared = (eccSquared) / (1 - eccSquared)
N = a / sqrt(1 - eccSquared * sin(LatRad) * sin(LatRad))
T = tan(LatRad) * tan(LatRad)
C = eccPrimeSquared * cos(LatRad) * cos(LatRad)
A = cos(LatRad) * (LongRad - LongOriginRad)
M = a * ((1
- eccSquared / 4
- 3 * eccSquared * eccSquared / 64
- 5 * eccSquared * eccSquared * eccSquared / 256) * LatRad
- (3 * eccSquared / 8
+ 3 * eccSquared * eccSquared / 32
+ 45 * eccSquared * eccSquared * eccSquared / 1024) * sin(2 * LatRad)
+ (15 * eccSquared * eccSquared / 256 + 45 * eccSquared * eccSquared * eccSquared / 1024) * sin(4 * LatRad)
- (35 * eccSquared * eccSquared * eccSquared / 3072) * sin(6 * LatRad))
UTMEasting = (k0 * N * (A + (1 - T + C) * A * A * A / 6
+ (5 - 18 * T + T * T + 72 * C - 58 * eccPrimeSquared) * A * A * A * A * A / 120)
+ 500000.0)
UTMNorthing = (k0 * (M + N * tan(LatRad) * (A * A / 2 + (5 - T + 9 * C + 4 * C * C) * A * A * A * A / 24
+ (61
- 58 * T
+ T * T
+ 600 * C
- 330 * eccPrimeSquared) * A * A * A * A * A * A / 720)))
if Lat < 0:
UTMNorthing = UTMNorthing + 10000000.0; # 10000000 meter offset for southern hemisphere
return (UTMZone, UTMEasting, UTMNorthing)
def _UTMLetterDesignator(Lat):
"""This routine determines the correct UTM letter designator for the given
latitude returns 'Z' if latitude is outside the UTM limits of 84N to 80S
Written by Chuck Gantz- chuck.gantz@globalstar.com"""
if 84 >= Lat >= 72:
return 'X'
elif 72 > Lat >= 64:
return 'W'
elif 64 > Lat >= 56:
return 'V'
elif 56 > Lat >= 48:
return 'U'
elif 48 > Lat >= 40:
return 'T'
elif 40 > Lat >= 32:
return 'S'
elif 32 > Lat >= 24:
return 'R'
elif 24 > Lat >= 16:
return 'Q'
elif 16 > Lat >= 8:
return 'P'
elif 8 > Lat >= 0:
return 'N'
elif 0 > Lat >= -8:
return 'M'
elif -8 > Lat >= -16:
return 'L'
elif -16 > Lat >= -24:
return 'K'
elif -24 > Lat >= -32:
return 'J'
elif -32 > Lat >= -40:
return 'H'
elif -40 > Lat >= -48:
return 'G'
elif -48 > Lat >= -56:
return 'F'
elif -56 > Lat >= -64:
return 'E'
elif -64 > Lat >= -72:
return 'D'
elif -72 > Lat >= -80:
return 'C'
else:
return 'Z' # if the Latitude is outside the UTM limits
# void UTMtoLL(int ReferenceEllipsoid, const double UTMNorthing, const double UTMEasting, const char* UTMZone,
# double& Lat, double& Long )
def UTMtoLL(ReferenceEllipsoid, northing, easting, zone):
"""converts UTM coords to lat/long. Equations from USGS Bulletin 1532
East Longitudes are positive, West longitudes are negative.
North latitudes are positive, South latitudes are negative
Lat and Long are in decimal degrees.
Written by Chuck Gantz- chuck.gantz@globalstar.com
Converted to Python by Russ Nelson <nelson@crynwr.com>"""
k0 = 0.9996
a = _ellipsoid[ReferenceEllipsoid][_EquatorialRadius]
eccSquared = _ellipsoid[ReferenceEllipsoid][_eccentricitySquared]
e1 = (1 - sqrt(1 - eccSquared)) / (1 + sqrt(1 - eccSquared))
# NorthernHemisphere; //1 for northern hemispher, 0 for southern
x = easting - 500000.0 # remove 500,000 meter offset for longitude
y = northing
ZoneLetter = zone[-1]
ZoneNumber = int(zone[:-1])
if ZoneLetter >= 'N':
NorthernHemisphere = 1 # point is in northern hemisphere
else:
NorthernHemisphere = 0 # point is in southern hemisphere
y -= 10000000.0 # remove 10,000,000 meter offset used for southern hemisphere
LongOrigin = (ZoneNumber - 1) * 6 - 180 + 3 # +3 puts origin in middle of zone
eccPrimeSquared = (eccSquared) / (1 - eccSquared)
M = y / k0
mu = M / (
a * (1 - eccSquared / 4 - 3 * eccSquared * eccSquared / 64 - 5 * eccSquared * eccSquared * eccSquared / 256))
phi1Rad = (mu + (3 * e1 / 2 - 27 * e1 * e1 * e1 / 32) * sin(2 * mu)
+ (21 * e1 * e1 / 16 - 55 * e1 * e1 * e1 * e1 / 32) * sin(4 * mu)
+ (151 * e1 * e1 * e1 / 96) * sin(6 * mu))
phi1 = phi1Rad * _rad2deg;
N1 = a / sqrt(1 - eccSquared * sin(phi1Rad) * sin(phi1Rad))
T1 = tan(phi1Rad) * tan(phi1Rad)
C1 = eccPrimeSquared * cos(phi1Rad) * cos(phi1Rad)
R1 = a * (1 - eccSquared) / pow(1 - eccSquared * sin(phi1Rad) * sin(phi1Rad), 1.5)
D = x / (N1 * k0)
Lat = phi1Rad - (N1 * tan(phi1Rad) / R1) * (
D * D / 2 - (5 + 3 * T1 + 10 * C1 - 4 * C1 * C1 - 9 * eccPrimeSquared) * D * D * D * D / 24
+ (61 + 90 * T1 + 298 * C1 + 45 * T1 * T1 - 252 * eccPrimeSquared - 3 * C1 * C1) * D * D * D * D * D * D / 720)
Lat = Lat * _rad2deg
Long = (D - (1 + 2 * T1 + C1) * D * D * D / 6 + (
5 - 2 * C1 + 28 * T1 - 3 * C1 * C1 + 8 * eccPrimeSquared + 24 * T1 * T1)
* D * D * D * D * D / 120) / cos(phi1Rad)
Long = LongOrigin + Long * _rad2deg
return (Lat, Long)
if __name__ == '__main__':
(z, e, n) = LLtoUTM(23, 45.00, -75.00)
print z, e, n
print UTMtoLL(23, n, e, z)

View file

@ -1,28 +0,0 @@
"""
Provides default node maps that can be used to run core with.
"""
from core.emane.nodes import EmaneNet
from core.emane.nodes import EmaneNode
from core.enumerations import NodeTypes
from core.netns import nodes
from core.netns.vnet import GreTapBridge
from core.phys import pnodes
# legacy core nodes, that leverage linux bridges
NODES = {
NodeTypes.DEFAULT: nodes.CoreNode,
NodeTypes.PHYSICAL: pnodes.PhysicalNode,
NodeTypes.TBD: None,
NodeTypes.SWITCH: nodes.SwitchNode,
NodeTypes.HUB: nodes.HubNode,
NodeTypes.WIRELESS_LAN: nodes.WlanNode,
NodeTypes.RJ45: nodes.RJ45Node,
NodeTypes.TUNNEL: nodes.TunnelNode,
NodeTypes.KTUNNEL: None,
NodeTypes.EMANE: EmaneNode,
NodeTypes.EMANE_NET: EmaneNet,
NodeTypes.TAP_BRIDGE: GreTapBridge,
NodeTypes.PEER_TO_PEER: nodes.PtpNet,
NodeTypes.CONTROL_NET: nodes.CtrlNet
}

View file

@ -1,172 +0,0 @@
"""
quagga.py: helper class for generating Quagga configuration.
"""
from string import Template
from core.misc import utils
def addrstr(x):
if x.find(".") >= 0:
return "ip address %s" % x
elif x.find(":") >= 0:
return "ipv6 address %s" % x
else:
raise ValueError("invalid address: %s" % x)
class NetIf(object):
"""
Represents a network interface.
"""
def __init__(self, name, addrlist=None):
"""
Create a NetIf instance.
:param str name: interface name
:param addrlist: address list for the interface
"""
self.name = name
if addrlist:
self.addrlist = addrlist
else:
self.addrlist = []
class Conf(object):
"""
Provides a configuration object.
"""
template = Template("")
def __init__(self, **kwargs):
"""
Create a Conf instance.
:param dict kwargs: configuration keyword arguments
"""
self.kwargs = kwargs
def __str__(self):
"""
Provides a string representation of a configuration object.
:return: string representation
:rtype: str
"""
tmp = self.template.substitute(**self.kwargs)
if tmp[-1] == "\n":
tmp = tmp[:-1]
return tmp
class QuaggaOSPF6Interface(Conf):
"""
Provides quagga ospf6 interface functionality.
"""
AF_IPV6_ID = 0
AF_IPV4_ID = 65
template = Template("""\
interface $interface
$addr
ipv6 ospf6 instance-id $instanceid
ipv6 ospf6 hello-interval 2
ipv6 ospf6 dead-interval 11
ipv6 ospf6 retransmit-interval 5
ipv6 ospf6 network $network
ipv6 ospf6 diffhellos
ipv6 ospf6 adjacencyconnectivity uniconnected
ipv6 ospf6 lsafullness mincostlsa
""")
# ip address $ipaddr/32
# ipv6 ospf6 simhelloLLtoULRecv :$simhelloport
# !$ipaddr:$simhelloport
def __init__(self, netif, instanceid=AF_IPV4_ID, network="manet-designated-router", **kwargs):
"""
Create a QuaggaOSPF6Interface instance.
:param netif: network interface
:param int instanceid: instance id
:param network: network
:param dict kwargs: keyword arguments
"""
self.netif = netif
addr = "\n ".join(map(addrstr, netif.addrlist))
self.instanceid = instanceid
self.network = network
Conf.__init__(self, interface=netif.name, addr=addr,
instanceid=instanceid, network=network, **kwargs)
def name(self):
"""
Retrieve network interface name.
:return: network interface name
:rtype: str
"""
return self.netif.name
class QuaggaOSPF6(Conf):
"""
Provides quagga ospf6 functionality.
"""
template = Template("""\
$interfaces
!
router ospf6
router-id $routerid
$ospfifs
$redistribute
""")
def __init__(self, ospf6ifs, area, routerid, redistribute="! no redistribute"):
"""
Create a QuaggaOSPF6 instance.
:param list ospf6ifs: ospf6 interfaces
:param area: area
:param routerid: router id
:param str redistribute: redistribute value
"""
ospf6ifs = utils.make_tuple(ospf6ifs)
interfaces = "\n!\n".join(map(str, ospf6ifs))
ospfifs = "\n ".join(map(lambda x: "interface %s area %s" % (x.name(), area), ospf6ifs))
Conf.__init__(self, interfaces=interfaces, routerid=routerid, ospfifs=ospfifs, redistribute=redistribute)
class QuaggaConf(Conf):
"""
Provides quagga configuration functionality.
"""
template = Template("""\
log file $logfile
$debugs
!
$routers
!
$forwarding
""")
def __init__(self, routers, logfile, debugs=()):
"""
Create a QuaggaConf instance.
:param list routers: routers
:param str logfile: log file name
:param debugs: debug options
"""
routers = "\n!\n".join(map(str, utils.make_tuple(routers)))
if debugs:
debugs = "\n".join(utils.make_tuple(debugs))
else:
debugs = "! no debugs"
forwarding = "ip forwarding\nipv6 forwarding"
Conf.__init__(self, logfile=logfile, debugs=debugs, routers=routers, forwarding=forwarding)

View file

@ -1,739 +0,0 @@
"""
Definition of LxcNode, CoreNode, and other node classes that inherit from the CoreNode,
implementing specific node types.
"""
import logging
import socket
import threading
from socket import AF_INET
from socket import AF_INET6
from core import CoreCommandError
from core import constants
from core.coreobj import PyCoreNetIf
from core.coreobj import PyCoreNode
from core.coreobj import PyCoreObj
from core.data import LinkData
from core.enumerations import LinkTypes
from core.enumerations import NodeTypes
from core.enumerations import RegisterTlvs
from core.misc import ipaddress
from core.misc import utils
from core.netns.vnet import GreTapBridge
from core.netns.vnet import LxBrNet
from core.netns.vnode import LxcNode
class CtrlNet(LxBrNet):
"""
Control network functionality.
"""
policy = "ACCEPT"
# base control interface index
CTRLIF_IDX_BASE = 99
DEFAULT_PREFIX_LIST = [
"172.16.0.0/24 172.16.1.0/24 172.16.2.0/24 172.16.3.0/24 172.16.4.0/24",
"172.17.0.0/24 172.17.1.0/24 172.17.2.0/24 172.17.3.0/24 172.17.4.0/24",
"172.18.0.0/24 172.18.1.0/24 172.18.2.0/24 172.18.3.0/24 172.18.4.0/24",
"172.19.0.0/24 172.19.1.0/24 172.19.2.0/24 172.19.3.0/24 172.19.4.0/24"
]
def __init__(self, session, objid="ctrlnet", name=None, prefix=None,
hostid=None, start=True, assign_address=True,
updown_script=None, serverintf=None):
"""
Creates a CtrlNet instance.
:param core.session.Session session: core session instance
:param int objid: node id
:param str name: node namee
:param prefix: control network ipv4 prefix
:param hostid: host id
:param bool start: start flag
:param str assign_address: assigned address
:param str updown_script: updown script
:param serverintf: server interface
:return:
"""
self.prefix = ipaddress.Ipv4Prefix(prefix)
self.hostid = hostid
self.assign_address = assign_address
self.updown_script = updown_script
self.serverintf = serverintf
LxBrNet.__init__(self, session, objid=objid, name=name, start=start)
def startup(self):
"""
Startup functionality for the control network.
:return: nothing
:raises CoreCommandError: when there is a command exception
"""
if self.detectoldbridge():
return
LxBrNet.startup(self)
if self.hostid:
addr = self.prefix.addr(self.hostid)
else:
addr = self.prefix.max_addr()
logging.info("added control network bridge: %s %s", self.brname, self.prefix)
if self.assign_address:
addrlist = ["%s/%s" % (addr, self.prefix.prefixlen)]
self.addrconfig(addrlist=addrlist)
logging.info("address %s", addr)
if self.updown_script:
logging.info("interface %s updown script (%s startup) called", self.brname, self.updown_script)
utils.check_cmd([self.updown_script, self.brname, "startup"])
if self.serverintf:
# sets the interface as a port of the bridge
utils.check_cmd([constants.BRCTL_BIN, "addif", self.brname, self.serverintf])
# bring interface up
utils.check_cmd([constants.IP_BIN, "link", "set", self.serverintf, "up"])
def detectoldbridge(self):
"""
Occassionally, control net bridges from previously closed sessions are not cleaned up.
Check if there are old control net bridges and delete them
:return: True if an old bridge was detected, False otherwise
:rtype: bool
"""
status, output = utils.cmd_output([constants.BRCTL_BIN, "show"])
if status != 0:
logging.error("Unable to retrieve list of installed bridges")
else:
lines = output.split("\n")
for line in lines[1:]:
cols = line.split("\t")
oldbr = cols[0]
flds = cols[0].split(".")
if len(flds) == 3:
if flds[0] == "b" and flds[1] == self.objid:
logging.error(
"error: An active control net bridge (%s) found. "
"An older session might still be running. "
"Stop all sessions and, if needed, delete %s to continue.", oldbr, oldbr
)
return True
return False
def shutdown(self):
"""
Control network shutdown.
:return: nothing
"""
if self.serverintf is not None:
try:
utils.check_cmd([constants.BRCTL_BIN, "delif", self.brname, self.serverintf])
except CoreCommandError:
logging.exception("error deleting server interface %s from bridge %s", self.serverintf, self.brname)
if self.updown_script is not None:
try:
logging.info("interface %s updown script (%s shutdown) called", self.brname, self.updown_script)
utils.check_cmd([self.updown_script, self.brname, "shutdown"])
except CoreCommandError:
logging.exception("error issuing shutdown script shutdown")
LxBrNet.shutdown(self)
def all_link_data(self, flags):
"""
Do not include CtrlNet in link messages describing this session.
:param flags: message flags
:return: list of link data
:rtype: list[core.data.LinkData]
"""
return []
class CoreNode(LxcNode):
"""
Basic core node class for nodes to extend.
"""
apitype = NodeTypes.DEFAULT.value
class PtpNet(LxBrNet):
"""
Peer to peer network node.
"""
policy = "ACCEPT"
def attach(self, netif):
"""
Attach a network interface, but limit attachment to two interfaces.
:param core.netns.vif.VEth netif: network interface
:return: nothing
"""
if len(self._netif) >= 2:
raise ValueError("Point-to-point links support at most 2 network interfaces")
LxBrNet.attach(self, netif)
def data(self, message_type, lat=None, lon=None, alt=None):
"""
Do not generate a Node Message for point-to-point links. They are
built using a link message instead.
:param message_type: purpose for the data object we are creating
:param float lat: latitude
:param float lon: longitude
:param float alt: altitude
:return: node data object
:rtype: core.data.NodeData
"""
return None
def all_link_data(self, flags):
"""
Build CORE API TLVs for a point-to-point link. One Link message
describes this network.
:param flags: message flags
:return: list of link data
:rtype: list[core.data.LinkData]
"""
all_links = []
if len(self._netif) != 2:
return all_links
if1, if2 = self._netif.values()
unidirectional = 0
if if1.getparams() != if2.getparams():
unidirectional = 1
interface1_ip4 = None
interface1_ip4_mask = None
interface1_ip6 = None
interface1_ip6_mask = None
for address in if1.addrlist:
ip, _sep, mask = address.partition("/")
mask = int(mask)
if ipaddress.is_ipv4_address(ip):
family = AF_INET
ipl = socket.inet_pton(family, ip)
interface1_ip4 = ipaddress.IpAddress(af=family, address=ipl)
interface1_ip4_mask = mask
else:
family = AF_INET6
ipl = socket.inet_pton(family, ip)
interface1_ip6 = ipaddress.IpAddress(af=family, address=ipl)
interface1_ip6_mask = mask
interface2_ip4 = None
interface2_ip4_mask = None
interface2_ip6 = None
interface2_ip6_mask = None
for address in if2.addrlist:
ip, _sep, mask = address.partition("/")
mask = int(mask)
if ipaddress.is_ipv4_address(ip):
family = AF_INET
ipl = socket.inet_pton(family, ip)
interface2_ip4 = ipaddress.IpAddress(af=family, address=ipl)
interface2_ip4_mask = mask
else:
family = AF_INET6
ipl = socket.inet_pton(family, ip)
interface2_ip6 = ipaddress.IpAddress(af=family, address=ipl)
interface2_ip6_mask = mask
link_data = LinkData(
message_type=flags,
node1_id=if1.node.objid,
node2_id=if2.node.objid,
link_type=self.linktype,
unidirectional=unidirectional,
delay=if1.getparam("delay"),
bandwidth=if1.getparam("bw"),
dup=if1.getparam("duplicate"),
jitter=if1.getparam("jitter"),
interface1_id=if1.node.getifindex(if1),
interface1_mac=if1.hwaddr,
interface1_ip4=interface1_ip4,
interface1_ip4_mask=interface1_ip4_mask,
interface1_ip6=interface1_ip6,
interface1_ip6_mask=interface1_ip6_mask,
interface2_id=if2.node.getifindex(if2),
interface2_mac=if2.hwaddr,
interface2_ip4=interface2_ip4,
interface2_ip4_mask=interface2_ip4_mask,
interface2_ip6=interface2_ip6,
interface2_ip6_mask=interface2_ip6_mask,
)
all_links.append(link_data)
# build a 2nd link message for the upstream link parameters
# (swap if1 and if2)
if unidirectional:
link_data = LinkData(
message_type=0,
node1_id=if2.node.objid,
node2_id=if1.node.objid,
delay=if1.getparam("delay"),
bandwidth=if1.getparam("bw"),
dup=if1.getparam("duplicate"),
jitter=if1.getparam("jitter"),
unidirectional=1,
interface1_id=if2.node.getifindex(if2),
interface2_id=if1.node.getifindex(if1)
)
all_links.append(link_data)
return all_links
class SwitchNode(LxBrNet):
"""
Provides switch functionality within a core node.
"""
apitype = NodeTypes.SWITCH.value
policy = "ACCEPT"
type = "lanswitch"
class HubNode(LxBrNet):
"""
Provides hub functionality within a core node, forwards packets to all bridge
ports by turning off MAC address learning.
"""
apitype = NodeTypes.HUB.value
policy = "ACCEPT"
type = "hub"
def __init__(self, session, objid=None, name=None, start=True):
"""
Creates a HubNode instance.
:param core.session.Session session: core session instance
:param int objid: node id
:param str name: node namee
:param bool start: start flag
:raises CoreCommandError: when there is a command exception
"""
LxBrNet.__init__(self, session, objid, name, start)
# TODO: move to startup method
if start:
utils.check_cmd([constants.BRCTL_BIN, "setageing", self.brname, "0"])
class WlanNode(LxBrNet):
"""
Provides wireless lan functionality within a core node.
"""
apitype = NodeTypes.WIRELESS_LAN.value
linktype = LinkTypes.WIRELESS.value
policy = "DROP"
type = "wlan"
def __init__(self, session, objid=None, name=None, start=True, policy=None):
"""
Create a WlanNode instance.
:param core.session.Session session: core session instance
:param int objid: node id
:param str name: node name
:param bool start: start flag
:param policy: wlan policy
"""
LxBrNet.__init__(self, session, objid, name, start, policy)
# wireless model such as basic range
self.model = None
# mobility model such as scripted
self.mobility = None
def attach(self, netif):
"""
Attach a network interface.
:param core.netns.vif.VEth netif: network interface
:return: nothing
"""
LxBrNet.attach(self, netif)
if self.model:
netif.poshook = self.model.position_callback
if netif.node is None:
return
x, y, z = netif.node.position.get()
# invokes any netif.poshook
netif.setposition(x, y, z)
def setmodel(self, model, config):
"""
Sets the mobility and wireless model.
:param core.mobility.WirelessModel.cls model: wireless model to set to
:param dict config: configuration for model being set
:return: nothing
"""
logging.info("adding model: %s", model.name)
if model.config_type == RegisterTlvs.WIRELESS.value:
self.model = model(session=self.session, object_id=self.objid)
self.model.update_config(config)
if self.model.position_callback:
for netif in self.netifs():
netif.poshook = self.model.position_callback
if netif.node is not None:
x, y, z = netif.node.position.get()
netif.poshook(netif, x, y, z)
self.model.setlinkparams()
elif model.config_type == RegisterTlvs.MOBILITY.value:
self.mobility = model(session=self.session, object_id=self.objid)
self.mobility.update_config(config)
def update_mobility(self, config):
if not self.mobility:
raise ValueError("no mobility set to update for node(%s)", self.objid)
self.mobility.set_configs(config, node_id=self.objid)
def updatemodel(self, config):
if not self.model:
raise ValueError("no model set to update for node(%s)", self.objid)
logging.info("node(%s) updating model(%s): %s", self.objid, self.model.name, config)
self.model.set_configs(config, node_id=self.objid)
if self.model.position_callback:
for netif in self.netifs():
netif.poshook = self.model.position_callback
if netif.node is not None:
x, y, z = netif.node.position.get()
netif.poshook(netif, x, y, z)
self.model.updateconfig()
def all_link_data(self, flags):
"""
Retrieve all link data.
:param flags: message flags
:return: list of link data
:rtype: list[core.data.LinkData]
"""
all_links = LxBrNet.all_link_data(self, flags)
if self.model:
all_links.extend(self.model.all_link_data(flags))
return all_links
class RJ45Node(PyCoreNode, PyCoreNetIf):
"""
RJ45Node is a physical interface on the host linked to the emulated
network.
"""
apitype = NodeTypes.RJ45.value
type = "rj45"
def __init__(self, session, objid=None, name=None, mtu=1500, start=True):
"""
Create an RJ45Node instance.
:param core.session.Session session: core session instance
:param int objid: node id
:param str name: node name
:param mtu: rj45 mtu
:param bool start: start flag
:return:
"""
PyCoreNode.__init__(self, session, objid, name, start=start)
PyCoreNetIf.__init__(self, node=self, name=name, mtu=mtu)
self.up = False
self.lock = threading.RLock()
self.ifindex = None
# the following are PyCoreNetIf attributes
self.transport_type = "raw"
self.localname = name
self.old_up = False
self.old_addrs = []
if start:
self.startup()
def startup(self):
"""
Set the interface in the up state.
:return: nothing
:raises CoreCommandError: when there is a command exception
"""
# interface will also be marked up during net.attach()
self.savestate()
utils.check_cmd([constants.IP_BIN, "link", "set", self.localname, "up"])
self.up = True
def shutdown(self):
"""
Bring the interface down. Remove any addresses and queuing
disciplines.
:return: nothing
"""
if not self.up:
return
try:
utils.check_cmd([constants.IP_BIN, "link", "set", self.localname, "down"])
utils.check_cmd([constants.IP_BIN, "addr", "flush", "dev", self.localname])
utils.check_cmd([constants.TC_BIN, "qdisc", "del", "dev", self.localname, "root"])
except CoreCommandError:
logging.exception("error shutting down")
self.up = False
self.restorestate()
# TODO: issue in that both classes inherited from provide the same method with different signatures
def attachnet(self, net):
"""
Attach a network.
:param core.coreobj.PyCoreNet net: network to attach
:return: nothing
"""
PyCoreNetIf.attachnet(self, net)
# TODO: issue in that both classes inherited from provide the same method with different signatures
def detachnet(self):
"""
Detach a network.
:return: nothing
"""
PyCoreNetIf.detachnet(self)
def newnetif(self, net=None, addrlist=None, hwaddr=None, ifindex=None, ifname=None):
"""
This is called when linking with another node. Since this node
represents an interface, we do not create another object here,
but attach ourselves to the given network.
:param core.coreobj.PyCoreNet net: new network instance
:param list[str] addrlist: address list
:param str hwaddr: hardware address
:param int ifindex: interface index
:param str ifname: interface name
:return: interface index
:rtype: int
:raises ValueError: when an interface has already been created, one max
"""
with self.lock:
if ifindex is None:
ifindex = 0
if self.net is not None:
raise ValueError("RJ45 nodes support at most 1 network interface")
self._netif[ifindex] = self
# PyCoreNetIf.node is self
self.node = self
self.ifindex = ifindex
if net is not None:
self.attachnet(net)
if addrlist:
for addr in utils.make_tuple(addrlist):
self.addaddr(addr)
return ifindex
def delnetif(self, ifindex):
"""
Delete a network interface.
:param int ifindex: interface index to delete
:return: nothing
"""
if ifindex is None:
ifindex = 0
self._netif.pop(ifindex)
if ifindex == self.ifindex:
self.shutdown()
else:
raise ValueError("ifindex %s does not exist" % ifindex)
def netif(self, ifindex, net=None):
"""
This object is considered the network interface, so we only
return self here. This keeps the RJ45Node compatible with
real nodes.
:param int ifindex: interface index to retrieve
:param net: network to retrieve
:return: a network interface
:rtype: core.coreobj.PyCoreNetIf
"""
if net is not None and net == self.net:
return self
if ifindex is None:
ifindex = 0
if ifindex == self.ifindex:
return self
return None
def getifindex(self, netif):
"""
Retrieve network interface index.
:param core.coreobj.PyCoreNetIf netif: network interface to retrieve index for
:return: interface index, None otherwise
:rtype: int
"""
if netif != self:
return None
return self.ifindex
def addaddr(self, addr):
"""
Add address to to network interface.
:param str addr: address to add
:return: nothing
:raises CoreCommandError: when there is a command exception
"""
if self.up:
utils.check_cmd([constants.IP_BIN, "addr", "add", str(addr), "dev", self.name])
PyCoreNetIf.addaddr(self, addr)
def deladdr(self, addr):
"""
Delete address from network interface.
:param str addr: address to delete
:return: nothing
:raises CoreCommandError: when there is a command exception
"""
if self.up:
utils.check_cmd([constants.IP_BIN, "addr", "del", str(addr), "dev", self.name])
PyCoreNetIf.deladdr(self, addr)
def savestate(self):
"""
Save the addresses and other interface state before using the
interface for emulation purposes. TODO: save/restore the PROMISC flag
:return: nothing
:raises CoreCommandError: when there is a command exception
"""
self.old_up = False
self.old_addrs = []
args = [constants.IP_BIN, "addr", "show", "dev", self.localname]
output = utils.check_cmd(args)
for line in output.split("\n"):
items = line.split()
if len(items) < 2:
continue
if items[1] == "%s:" % self.localname:
flags = items[2][1:-1].split(",")
if "UP" in flags:
self.old_up = True
elif items[0] == "inet":
self.old_addrs.append((items[1], items[3]))
elif items[0] == "inet6":
if items[1][:4] == "fe80":
continue
self.old_addrs.append((items[1], None))
def restorestate(self):
"""
Restore the addresses and other interface state after using it.
:return: nothing
:raises CoreCommandError: when there is a command exception
"""
for addr in self.old_addrs:
if addr[1] is None:
utils.check_cmd([constants.IP_BIN, "addr", "add", addr[0], "dev", self.localname])
else:
utils.check_cmd([constants.IP_BIN, "addr", "add", addr[0], "brd", addr[1], "dev", self.localname])
if self.old_up:
utils.check_cmd([constants.IP_BIN, "link", "set", self.localname, "up"])
def setposition(self, x=None, y=None, z=None):
"""
Uses setposition from both parent classes.
:param float x: x position
:param float y: y position
:param float z: z position
:return: True if position changed, False otherwise
:rtype: bool
"""
result = PyCoreObj.setposition(self, x, y, z)
PyCoreNetIf.setposition(self, x, y, z)
return result
def check_cmd(self, args):
"""
Runs shell command on node.
:param list[str]|str args: command to run
:return: exist status and combined stdout and stderr
:rtype: tuple[int, str]
:raises CoreCommandError: when a non-zero exit status occurs
"""
raise NotImplementedError
def cmd(self, args, wait=True):
"""
Runs shell command on node, with option to not wait for a result.
:param list[str]|str args: command to run
:param bool wait: wait for command to exit, defaults to True
:return: exit status for command
:rtype: int
"""
raise NotImplementedError
def cmd_output(self, args):
"""
Runs shell command on node and get exit status and output.
:param list[str]|str args: command to run
:return: exit status and combined stdout and stderr
:rtype: tuple[int, str]
"""
raise NotImplementedError
def termcmdstring(self, sh):
"""
Create a terminal command string.
:param str sh: shell to execute command in
:return: str
"""
raise NotImplementedError
class TunnelNode(GreTapBridge):
"""
Provides tunnel functionality in a core node.
"""
apitype = NodeTypes.TUNNEL.value
policy = "ACCEPT"
type = "tunnel"

View file

@ -1,609 +0,0 @@
"""
PyCoreNode and LxcNode classes that implement the network namespac virtual node.
"""
import errno
import logging
import os
import random
import shutil
import signal
import string
import threading
from core import CoreCommandError
from core import constants
from core.coreobj import PyCoreNetIf
from core.coreobj import PyCoreNode
from core.enumerations import NodeTypes
from core.misc import nodeutils
from core.misc import utils
from core.misc.ipaddress import MacAddress
from core.netns import vnodeclient
from core.netns.vif import TunTap
from core.netns.vif import VEth
_DEFAULT_MTU = 1500
utils.check_executables([constants.IP_BIN])
class SimpleLxcNode(PyCoreNode):
"""
Provides simple lxc functionality for core nodes.
:var nodedir: str
:var ctrlchnlname: str
:var client: core.netns.vnodeclient.VnodeClient
:var pid: int
:var up: bool
:var lock: threading.RLock
:var _mounts: list[tuple[str, str]]
"""
valid_address_types = {"inet", "inet6", "inet6link"}
def __init__(self, session, objid=None, name=None, nodedir=None, start=True):
"""
Create a SimpleLxcNode instance.
:param core.session.Session session: core session instance
:param int objid: object id
:param str name: object name
:param str nodedir: node directory
:param bool start: start flag
"""
PyCoreNode.__init__(self, session, objid, name, start=start)
self.nodedir = nodedir
self.ctrlchnlname = os.path.abspath(os.path.join(self.session.session_dir, self.name))
self.client = None
self.pid = None
self.up = False
self.lock = threading.RLock()
self._mounts = []
def alive(self):
"""
Check if the node is alive.
:return: True if node is alive, False otherwise
:rtype: bool
"""
try:
os.kill(self.pid, 0)
except OSError:
return False
return True
def startup(self):
"""
Start a new namespace node by invoking the vnoded process that
allocates a new namespace. Bring up the loopback device and set
the hostname.
:return: nothing
"""
if self.up:
raise ValueError("starting a node that is already up")
# create a new namespace for this node using vnoded
vnoded = [
constants.VNODED_BIN,
"-v",
"-c", self.ctrlchnlname,
"-l", self.ctrlchnlname + ".log",
"-p", self.ctrlchnlname + ".pid"
]
if self.nodedir:
vnoded += ["-C", self.nodedir]
env = self.session.get_environment(state=False)
env["NODE_NUMBER"] = str(self.objid)
env["NODE_NAME"] = str(self.name)
output = utils.check_cmd(vnoded, env=env)
self.pid = int(output)
# create vnode client
self.client = vnodeclient.VnodeClient(self.name, self.ctrlchnlname)
# bring up the loopback interface
logging.debug("bringing up loopback interface")
self.check_cmd([constants.IP_BIN, "link", "set", "lo", "up"])
# set hostname for node
logging.debug("setting hostname: %s", self.name)
self.check_cmd(["hostname", self.name])
# mark node as up
self.up = True
def shutdown(self):
"""
Shutdown logic for simple lxc nodes.
:return: nothing
"""
# nothing to do if node is not up
if not self.up:
return
# unmount all targets (NOTE: non-persistent mount namespaces are
# removed by the kernel when last referencing process is killed)
self._mounts = []
# shutdown all interfaces
for netif in self.netifs():
netif.shutdown()
# attempt to kill node process and wait for termination of children
try:
os.kill(self.pid, signal.SIGTERM)
os.waitpid(self.pid, 0)
except OSError as e:
if e.errno != 10:
logging.exception("error killing process")
# remove node directory if present
try:
os.unlink(self.ctrlchnlname)
except OSError as e:
# no such file or directory
if e.errno != errno.ENOENT:
logging.exception("error removing node directory")
# clear interface data, close client, and mark self and not up
self._netif.clear()
self.client.close()
self.up = False
def cmd(self, args, wait=True):
"""
Runs shell command on node, with option to not wait for a result.
:param list[str]|str args: command to run
:param bool wait: wait for command to exit, defaults to True
:return: exit status for command
:rtype: int
"""
return self.client.cmd(args, wait)
def cmd_output(self, args):
"""
Runs shell command on node and get exit status and output.
:param list[str]|str args: command to run
:return: exit status and combined stdout and stderr
:rtype: tuple[int, str]
"""
return self.client.cmd_output(args)
def check_cmd(self, args):
"""
Runs shell command on node.
:param list[str]|str args: command to run
:return: combined stdout and stderr
:rtype: str
:raises CoreCommandError: when a non-zero exit status occurs
"""
return self.client.check_cmd(args)
def termcmdstring(self, sh="/bin/sh"):
"""
Create a terminal command string.
:param str sh: shell to execute command in
:return: str
"""
return self.client.termcmdstring(sh)
def mount(self, source, target):
"""
Create and mount a directory.
:param str source: source directory to mount
:param str target: target directory to create
:return: nothing
:raises CoreCommandError: when a non-zero exit status occurs
"""
source = os.path.abspath(source)
logging.info("node(%s) mounting: %s at %s", self.name, source, target)
cmd = 'mkdir -p "%s" && %s -n --bind "%s" "%s"' % (target, constants.MOUNT_BIN, source, target)
status, output = self.client.shcmd_result(cmd)
if status:
raise CoreCommandError(status, cmd, output)
self._mounts.append((source, target))
def newifindex(self):
"""
Retrieve a new interface index.
:return: new interface index
:rtype: int
"""
with self.lock:
return super(SimpleLxcNode, self).newifindex()
def newveth(self, ifindex=None, ifname=None, net=None):
"""
Create a new interface.
:param int ifindex: index for the new interface
:param str ifname: name for the new interface
:param net: network to associate interface with
:return: nothing
"""
with self.lock:
if ifindex is None:
ifindex = self.newifindex()
if ifname is None:
ifname = "eth%d" % ifindex
sessionid = self.session.short_session_id()
try:
suffix = "%x.%s.%s" % (self.objid, ifindex, sessionid)
except TypeError:
suffix = "%s.%s.%s" % (self.objid, ifindex, sessionid)
localname = "veth" + suffix
if len(localname) >= 16:
raise ValueError("interface local name (%s) too long" % localname)
name = localname + "p"
if len(name) >= 16:
raise ValueError("interface name (%s) too long" % name)
veth = VEth(node=self, name=name, localname=localname, net=net, start=self.up)
if self.up:
utils.check_cmd([constants.IP_BIN, "link", "set", veth.name, "netns", str(self.pid)])
self.check_cmd([constants.IP_BIN, "link", "set", veth.name, "name", ifname])
veth.name = ifname
if self.up:
# TODO: potentially find better way to query interface ID
# retrieve interface information
output = self.check_cmd(["ip", "link", "show", veth.name])
logging.debug("interface command output: %s", output)
output = output.split("\n")
veth.flow_id = int(output[0].strip().split(":")[0]) + 1
logging.debug("interface flow index: %s - %s", veth.name, veth.flow_id)
veth.hwaddr = MacAddress.from_string(output[1].strip().split()[1])
logging.debug("interface mac: %s - %s", veth.name, veth.hwaddr)
try:
self.addnetif(veth, ifindex)
except ValueError as e:
veth.shutdown()
del veth
raise e
return ifindex
def newtuntap(self, ifindex=None, ifname=None, net=None):
"""
Create a new tunnel tap.
:param int ifindex: interface index
:param str ifname: interface name
:param net: network to associate with
:return: interface index
:rtype: int
"""
with self.lock:
if ifindex is None:
ifindex = self.newifindex()
if ifname is None:
ifname = "eth%d" % ifindex
sessionid = self.session.short_session_id()
localname = "tap%s.%s.%s" % (self.objid, ifindex, sessionid)
name = ifname
tuntap = TunTap(node=self, name=name, localname=localname, net=net, start=self.up)
try:
self.addnetif(tuntap, ifindex)
except ValueError as e:
tuntap.shutdown()
del tuntap
raise e
return ifindex
def sethwaddr(self, ifindex, addr):
"""
Set hardware addres for an interface.
:param int ifindex: index of interface to set hardware address for
:param core.misc.ipaddress.MacAddress addr: hardware address to set
:return: nothing
:raises CoreCommandError: when a non-zero exit status occurs
"""
self._netif[ifindex].sethwaddr(addr)
if self.up:
args = [constants.IP_BIN, "link", "set", "dev", self.ifname(ifindex), "address", str(addr)]
self.check_cmd(args)
def addaddr(self, ifindex, addr):
"""
Add interface address.
:param int ifindex: index of interface to add address to
:param str addr: address to add to interface
:return: nothing
"""
if self.up:
# check if addr is ipv6
if ":" in str(addr):
args = [constants.IP_BIN, "addr", "add", str(addr), "dev", self.ifname(ifindex)]
self.check_cmd(args)
else:
args = [constants.IP_BIN, "addr", "add", str(addr), "broadcast", "+", "dev", self.ifname(ifindex)]
self.check_cmd(args)
self._netif[ifindex].addaddr(addr)
def deladdr(self, ifindex, addr):
"""
Delete address from an interface.
:param int ifindex: index of interface to delete address from
:param str addr: address to delete from interface
:return: nothing
:raises CoreCommandError: when a non-zero exit status occurs
"""
try:
self._netif[ifindex].deladdr(addr)
except ValueError:
logging.exception("trying to delete unknown address: %s" % addr)
if self.up:
self.check_cmd([constants.IP_BIN, "addr", "del", str(addr), "dev", self.ifname(ifindex)])
def delalladdr(self, ifindex, address_types=None):
"""
Delete all addresses from an interface.
:param int ifindex: index of interface to delete address types from
:param tuple[str] address_types: address types to delete
:return: nothing
:raises CoreCommandError: when a non-zero exit status occurs
"""
if not address_types:
address_types = self.valid_address_types
interface_name = self.ifname(ifindex)
addresses = self.client.getaddr(interface_name, rescan=True)
for address_type in address_types:
if address_type not in self.valid_address_types:
raise ValueError("addr type must be in: %s" % " ".join(self.valid_address_types))
for address in addresses[address_type]:
self.deladdr(ifindex, address)
# update cached information
self.client.getaddr(interface_name, rescan=True)
def ifup(self, ifindex):
"""
Bring an interface up.
:param int ifindex: index of interface to bring up
:return: nothing
"""
if self.up:
self.check_cmd([constants.IP_BIN, "link", "set", self.ifname(ifindex), "up"])
def newnetif(self, net=None, addrlist=None, hwaddr=None, ifindex=None, ifname=None):
"""
Create a new network interface.
:param net: network to associate with
:param list addrlist: addresses to add on the interface
:param core.misc.ipaddress.MacAddress hwaddr: hardware address to set for interface
:param int ifindex: index of interface to create
:param str ifname: name for interface
:return: interface index
:rtype: int
"""
if not addrlist:
addrlist = []
with self.lock:
# TODO: see if you can move this to emane specific code
if nodeutils.is_node(net, NodeTypes.EMANE):
ifindex = self.newtuntap(ifindex=ifindex, ifname=ifname, net=net)
# TUN/TAP is not ready for addressing yet; the device may
# take some time to appear, and installing it into a
# namespace after it has been bound removes addressing;
# save addresses with the interface now
self.attachnet(ifindex, net)
netif = self.netif(ifindex)
netif.sethwaddr(hwaddr)
for address in utils.make_tuple(addrlist):
netif.addaddr(address)
return ifindex
else:
ifindex = self.newveth(ifindex=ifindex, ifname=ifname, net=net)
if net is not None:
self.attachnet(ifindex, net)
if hwaddr:
self.sethwaddr(ifindex, hwaddr)
for address in utils.make_tuple(addrlist):
self.addaddr(ifindex, address)
self.ifup(ifindex)
return ifindex
def connectnode(self, ifname, othernode, otherifname):
"""
Connect a node.
:param str ifname: name of interface to connect
:param core.netns.nodes.LxcNode othernode: node to connect to
:param str otherifname: interface name to connect to
:return: nothing
"""
tmplen = 8
tmp1 = "tmp." + "".join([random.choice(string.ascii_lowercase) for _ in xrange(tmplen)])
tmp2 = "tmp." + "".join([random.choice(string.ascii_lowercase) for _ in xrange(tmplen)])
utils.check_cmd([constants.IP_BIN, "link", "add", "name", tmp1, "type", "veth", "peer", "name", tmp2])
utils.check_cmd([constants.IP_BIN, "link", "set", tmp1, "netns", str(self.pid)])
self.check_cmd([constants.IP_BIN, "link", "set", tmp1, "name", ifname])
interface = PyCoreNetIf(node=self, name=ifname, mtu=_DEFAULT_MTU)
self.addnetif(interface, self.newifindex())
utils.check_cmd([constants.IP_BIN, "link", "set", tmp2, "netns", str(othernode.pid)])
othernode.check_cmd([constants.IP_BIN, "link", "set", tmp2, "name", otherifname])
other_interface = PyCoreNetIf(node=othernode, name=otherifname, mtu=_DEFAULT_MTU)
othernode.addnetif(other_interface, othernode.newifindex())
def addfile(self, srcname, filename):
"""
Add a file.
:param str srcname: source file name
:param str filename: file name to add
:return: nothing
:raises CoreCommandError: when a non-zero exit status occurs
"""
logging.info("adding file from %s to %s", srcname, filename)
directory = os.path.dirname(filename)
cmd = 'mkdir -p "%s" && mv "%s" "%s" && sync' % (directory, srcname, filename)
status, output = self.client.shcmd_result(cmd)
if status:
raise CoreCommandError(status, cmd, output)
class LxcNode(SimpleLxcNode):
"""
Provides lcx node functionality for core nodes.
"""
def __init__(self, session, objid=None, name=None, nodedir=None, bootsh="boot.sh", start=True):
"""
Create a LxcNode instance.
:param core.session.Session session: core session instance
:param int objid: object id
:param str name: object name
:param str nodedir: node directory
:param bootsh: boot shell
:param bool start: start flag
"""
super(LxcNode, self).__init__(session=session, objid=objid, name=name, nodedir=nodedir, start=start)
self.bootsh = bootsh
if start:
self.startup()
def startup(self):
"""
Startup logic for the node.
:return: nothing
"""
with self.lock:
self.makenodedir()
super(LxcNode, self).startup()
self.privatedir("/var/run")
self.privatedir("/var/log")
def shutdown(self):
"""
Shutdown logic for the node.
:return: nothing
"""
if not self.up:
return
with self.lock:
try:
super(LxcNode, self).shutdown()
except OSError:
logging.exception("error during shutdown")
finally:
self.rmnodedir()
def privatedir(self, path):
"""
Create a private directory.
:param str path: path to create
:return: nothing
"""
if path[0] != "/":
raise ValueError("path not fully qualified: %s" % path)
hostpath = os.path.join(self.nodedir, os.path.normpath(path).strip("/").replace("/", "."))
os.mkdir(hostpath)
self.mount(hostpath, path)
def hostfilename(self, filename):
"""
Return the name of a node"s file on the host filesystem.
:param str filename: host file name
:return: path to file
"""
dirname, basename = os.path.split(filename)
if not basename:
raise ValueError("no basename for filename: %s" % filename)
if dirname and dirname[0] == "/":
dirname = dirname[1:]
dirname = dirname.replace("/", ".")
dirname = os.path.join(self.nodedir, dirname)
return os.path.join(dirname, basename)
def opennodefile(self, filename, mode="w"):
"""
Open a node file, within it"s directory.
:param str filename: file name to open
:param str mode: mode to open file in
:return: open file
:rtype: file
"""
hostfilename = self.hostfilename(filename)
dirname, _basename = os.path.split(hostfilename)
if not os.path.isdir(dirname):
os.makedirs(dirname, mode=0755)
return open(hostfilename, mode)
def nodefile(self, filename, contents, mode=0644):
"""
Create a node file with a given mode.
:param str filename: name of file to create
:param contents: contents of file
:param int mode: mode for file
:return: nothing
"""
with self.opennodefile(filename, "w") as open_file:
open_file.write(contents)
os.chmod(open_file.name, mode)
logging.info("node(%s) added file: %s; mode: 0%o", self.name, open_file.name, mode)
def nodefilecopy(self, filename, srcfilename, mode=None):
"""
Copy a file to a node, following symlinks and preserving metadata.
Change file mode if specified.
:param str filename: file name to copy file to
:param str srcfilename: file to copy
:param int mode: mode to copy to
:return: nothing
"""
hostfilename = self.hostfilename(filename)
shutil.copy2(srcfilename, hostfilename)
if mode is not None:
os.chmod(hostfilename, mode)
logging.info("node(%s) copied file: %s; mode: %s", self.name, hostfilename, mode)

1159
daemon/core/nodes/base.py Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
"""
vnodeclient.py: implementation of the VnodeClient class for issuing commands
client.py: implementation of the VnodeClient class for issuing commands
over a control channel to the vnoded process running in a network namespace.
The control channel can be accessed via calls to the vcmd Python module or
by invoking the vcmd shell command.
@ -8,11 +8,10 @@ by invoking the vcmd shell command.
import logging
import os
import vcmd
from subprocess import Popen, PIPE
from core import CoreCommandError
from core import CoreCommandError, utils
from core import constants
from core.misc import utils
class VnodeClient(object):
@ -29,7 +28,6 @@ class VnodeClient(object):
"""
self.name = name
self.ctrlchnlname = ctrlchnlname
self.cmdchnl = vcmd.VCmd(self.ctrlchnlname)
self._addr = {}
def _verify_connection(self):
@ -49,7 +47,7 @@ class VnodeClient(object):
:return: True if connected, False otherwise
:rtype: bool
"""
return self.cmdchnl.connected()
return True
def close(self):
"""
@ -57,7 +55,10 @@ class VnodeClient(object):
:return: nothing
"""
self.cmdchnl.close()
pass
def _cmd_args(self):
return [constants.VCMD_BIN, "-c", self.ctrlchnlname, "--"]
def cmd(self, args, wait=True):
"""
@ -72,7 +73,9 @@ class VnodeClient(object):
args = utils.split_args(args)
# run command, return process when not waiting
p = self.cmdchnl.qcmd(args)
cmd = self._cmd_args() + args
logging.info("cmd wait(%s): %s", wait, cmd)
p = Popen(cmd, stdout=PIPE, stderr=PIPE)
if not wait:
return 0
@ -95,7 +98,7 @@ class VnodeClient(object):
stdout.close()
stderr.close()
status = p.wait()
return status, output.strip()
return status, output.decode("utf-8").strip()
def check_cmd(self, args):
"""
@ -121,7 +124,12 @@ class VnodeClient(object):
"""
self._verify_connection()
args = utils.split_args(args)
return self.cmdchnl.popen(args)
# if isinstance(args, list):
# args = " ".join(args)
cmd = self._cmd_args() + args
logging.info("popen: %s", cmd)
p = Popen(cmd, stdout=PIPE, stderr=PIPE, stdin=PIPE)
return p, p.stdin, p.stdout, p.stderr
def icmd(self, args):
"""
@ -151,14 +159,17 @@ class VnodeClient(object):
# run command, return process when not waiting
args = utils.split_args(args)
p = self.cmdchnl.redircmd(infd, outfd, errfd, args)
cmd = self._cmd_args() + args
logging.info("redircmd: %s", cmd)
p = Popen(cmd, stdin=infd, stdout=outfd, stderr=errfd)
if not wait:
return p
# wait for and return exit status
status = p.wait()
if status:
logging.warn("cmd exited with status %s: %s", status, args)
logging.warning("cmd exited with status %s: %s", status, args)
return status
def term(self, sh="/bin/sh"):
@ -236,16 +247,16 @@ class VnodeClient(object):
elif line[3] == "link":
interface["inet6link"].append(line[1])
else:
logging.warn("unknown scope: %s" % line[3])
logging.warning("unknown scope: %s" % line[3])
err = stderr.read()
stdout.close()
stderr.close()
status = p.wait()
if status:
logging.warn("nonzero exist status (%s) for cmd: %s", status, args)
logging.warning("nonzero exist status (%s) for cmd: %s", status, args)
if err:
logging.warn("error output: %s", err)
logging.warning("error output: %s", err)
self._addr[ifname] = interface
return interface
@ -264,11 +275,11 @@ class VnodeClient(object):
# ignore first line
stdout.readline()
# second line has count names
tmp = stdout.readline().strip().split("|")
tmp = stdout.readline().decode("utf-8").strip().split("|")
rxkeys = tmp[1].split()
txkeys = tmp[2].split()
for line in stdout:
line = line.strip().split()
line = line.decode("utf-8").strip().split()
devname, tmp = line[0].split(":")
if tmp:
line.insert(1, tmp)
@ -285,9 +296,9 @@ class VnodeClient(object):
stderr.close()
status = p.wait()
if status:
logging.warn("nonzero exist status (%s) for cmd: %s", status, args)
logging.warning("nonzero exist status (%s) for cmd: %s", status, args)
if err:
logging.warn("error output: %s", err)
logging.warning("error output: %s", err)
if ifname is not None:
return stats[ifname]
else:

View file

@ -4,18 +4,191 @@ virtual ethernet classes that implement the interfaces available under Linux.
import logging
import time
from builtins import int
from builtins import range
from core import CoreCommandError
from core import CoreCommandError, utils
from core import constants
from core.coreobj import PyCoreNetIf
from core.enumerations import NodeTypes
from core.misc import nodeutils
from core.misc import utils
from core.emulator.enumerations import NodeTypes
from core.nodes import nodeutils
utils.check_executables([constants.IP_BIN])
class VEth(PyCoreNetIf):
class CoreInterface(object):
"""
Base class for network interfaces.
"""
def __init__(self, node, name, mtu):
"""
Creates a PyCoreNetIf instance.
:param core.coreobj.PyCoreNode node: node for interface
:param str name: interface name
:param mtu: mtu value
"""
self.node = node
self.name = name
if not isinstance(mtu, int):
raise ValueError
self.mtu = mtu
self.net = None
self._params = {}
self.addrlist = []
self.hwaddr = None
# placeholder position hook
self.poshook = lambda a, b, c, d: None
# used with EMANE
self.transport_type = None
# interface index on the network
self.netindex = None
# index used to find flow data
self.flow_id = None
def startup(self):
"""
Startup method for the interface.
:return: nothing
"""
pass
def shutdown(self):
"""
Shutdown method for the interface.
:return: nothing
"""
pass
def attachnet(self, net):
"""
Attach network.
:param core.coreobj.PyCoreNet net: network to attach
:return: nothing
"""
if self.net:
self.detachnet()
self.net = None
net.attach(self)
self.net = net
def detachnet(self):
"""
Detach from a network.
:return: nothing
"""
if self.net is not None:
self.net.detach(self)
def addaddr(self, addr):
"""
Add address.
:param str addr: address to add
:return: nothing
"""
self.addrlist.append(addr)
def deladdr(self, addr):
"""
Delete address.
:param str addr: address to delete
:return: nothing
"""
self.addrlist.remove(addr)
def sethwaddr(self, addr):
"""
Set hardware address.
:param core.misc.ipaddress.MacAddress addr: hardware address to set to.
:return: nothing
"""
self.hwaddr = addr
def getparam(self, key):
"""
Retrieve a parameter from the, or None if the parameter does not exist.
:param key: parameter to get value for
:return: parameter value
"""
return self._params.get(key)
def getparams(self):
"""
Return (key, value) pairs for parameters.
"""
parameters = []
for k in sorted(self._params.keys()):
parameters.append((k, self._params[k]))
return parameters
def setparam(self, key, value):
"""
Set a parameter value, returns True if the parameter has changed.
:param key: parameter name to set
:param value: parameter value
:return: True if parameter changed, False otherwise
"""
# treat None and 0 as unchanged values
if value is None or value <= 0:
return False
current_value = self._params.get(key)
if current_value is not None and current_value == value:
return False
self._params[key] = value
return True
def swapparams(self, name):
"""
Swap out parameters dict for name. If name does not exist,
intialize it. This is for supporting separate upstream/downstream
parameters when two layer-2 nodes are linked together.
:param str name: name of parameter to swap
:return: nothing
"""
tmp = self._params
if not hasattr(self, name):
setattr(self, name, {})
self._params = getattr(self, name)
setattr(self, name, tmp)
def setposition(self, x, y, z):
"""
Dispatch position hook handler.
:param x: x position
:param y: y position
:param z: z position
:return: nothing
"""
self.poshook(self, x, y, z)
def __lt__(self, other):
"""
Used for comparisons of this object.
:param other: other interface
:return: true if less than, false otherwise
:rtype: bool
"""
return id(self) < id(other)
class Veth(CoreInterface):
"""
Provides virtual ethernet functionality for core nodes.
"""
@ -34,7 +207,7 @@ class VEth(PyCoreNetIf):
:raises CoreCommandError: when there is a command exception
"""
# note that net arg is ignored
PyCoreNetIf.__init__(self, node=node, name=name, mtu=mtu)
CoreInterface.__init__(self, node=node, name=name, mtu=mtu)
self.localname = localname
self.up = False
if start:
@ -76,7 +249,7 @@ class VEth(PyCoreNetIf):
self.up = False
class TunTap(PyCoreNetIf):
class TunTap(CoreInterface):
"""
TUN/TAP virtual device in TAP mode
"""
@ -93,7 +266,7 @@ class TunTap(PyCoreNetIf):
:param net: related network
:param bool start: start flag
"""
PyCoreNetIf.__init__(self, node=node, name=name, mtu=mtu)
CoreInterface.__init__(self, node=node, name=name, mtu=mtu)
self.localname = localname
self.up = False
self.transport_type = "virtual"
@ -142,7 +315,7 @@ class TunTap(PyCoreNetIf):
"""
delay = 0.01
result = False
for i in xrange(1, attempts + 1):
for i in range(1, attempts + 1):
r = func()
if r == 0:
result = True
@ -233,7 +406,7 @@ class TunTap(PyCoreNetIf):
self.node.check_cmd([constants.IP_BIN, "addr", "add", str(addr), "dev", self.name])
class GreTap(PyCoreNetIf):
class GreTap(CoreInterface):
"""
GRE TAP device for tunneling between emulation servers.
Uses the "gretap" tunnel device type from Linux which is a GRE device
@ -241,7 +414,7 @@ class GreTap(PyCoreNetIf):
"""
def __init__(self, node=None, name=None, session=None, mtu=1458,
remoteip=None, objid=None, localip=None, ttl=255,
remoteip=None, _id=None, localip=None, ttl=255,
key=None, start=True):
"""
Creates a GreTap instance.
@ -251,29 +424,29 @@ class GreTap(PyCoreNetIf):
:param core.session.Session session: core session instance
:param mtu: interface mtu
:param str remoteip: remote address
:param int objid: object id
:param int _id: object id
:param str localip: local address
:param ttl: ttl value
:param key: gre tap key
:param bool start: start flag
:raises CoreCommandError: when there is a command exception
"""
PyCoreNetIf.__init__(self, node=node, name=name, mtu=mtu)
CoreInterface.__init__(self, node=node, name=name, mtu=mtu)
self.session = session
if objid is None:
if _id is None:
# from PyCoreObj
objid = ((id(self) >> 16) ^ (id(self) & 0xffff)) & 0xffff
self.objid = objid
_id = ((id(self) >> 16) ^ (id(self) & 0xffff)) & 0xffff
self.id = _id
sessionid = self.session.short_session_id()
# interface name on the local host machine
self.localname = "gt.%s.%s" % (self.objid, sessionid)
self.localname = "gt.%s.%s" % (self.id, sessionid)
self.transport_type = "raw"
if not start:
self.up = False
return
if remoteip is None:
raise ValueError, "missing remote IP required for GRE TAP device"
raise ValueError("missing remote IP required for GRE TAP device")
args = [constants.IP_BIN, "link", "add", self.localname, "type", "gretap",
"remote", str(remoteip)]
if localip:

View file

@ -6,6 +6,8 @@ import logging
import random
import socket
import struct
from builtins import bytes
from builtins import range
from socket import AF_INET
from socket import AF_INET6
@ -30,7 +32,7 @@ class MacAddress(object):
:return: string representation
:rtype: str
"""
return ":".join("%02x" % ord(x) for x in self.addr)
return ":".join("%02x" % x for x in bytearray(self.addr))
def to_link_local(self):
"""
@ -43,12 +45,12 @@ class MacAddress(object):
if not self.addr:
return IpAddress.from_string("::")
tmp = struct.unpack("!Q", "\x00\x00" + self.addr)[0]
nic = long(tmp) & 0x000000FFFFFFL
oui = long(tmp) & 0xFFFFFF000000L
nic = long(tmp) & 0x000000FFFFFF
oui = long(tmp) & 0xFFFFFF000000
# toggle U/L bit
oui ^= 0x020000000000L
oui ^= 0x020000000000
# append EUI-48 octets
oui = (oui << 16) | 0xFFFE000000L
oui = (oui << 16) | 0xFFFE000000
return IpAddress(AF_INET6, struct.pack("!QQ", 0xfe80 << 48, oui | nic))
@classmethod
@ -60,7 +62,7 @@ class MacAddress(object):
:return: mac address class
:rtype: MacAddress
"""
addr = "".join(chr(int(x, 16)) for x in s.split(":"))
addr = b"".join(bytes([int(x, 16)]) for x in s.split(":"))
return cls(addr)
@classmethod
@ -153,14 +155,14 @@ class IpAddress(object):
logging.exception("error during addition")
return NotImplemented
tmp = [ord(x) for x in self.addr]
for i in xrange(len(tmp) - 1, -1, -1):
tmp = [x for x in bytearray(self.addr)]
for i in range(len(tmp) - 1, -1, -1):
x = tmp[i] + carry
tmp[i] = x & 0xff
carry = x >> 8
if carry == 0:
break
addr = "".join(chr(x) for x in tmp)
addr = bytes(tmp)
return self.__class__(self.af, addr)
def __sub__(self, other):
@ -231,12 +233,13 @@ class IpPrefix(object):
else:
self.prefixlen = self.addrlen
self.prefix = socket.inet_pton(self.af, tmp[0])
self.prefix = bytes(self.prefix)
if self.addrlen > self.prefixlen:
addrbits = self.addrlen - self.prefixlen
netmask = ((1L << self.prefixlen) - 1) << addrbits
prefix = ""
for i in xrange(-1, -(addrbits >> 3) - 2, -1):
prefix = chr(ord(self.prefix[i]) & (netmask & 0xff)) + prefix
netmask = ((1 << self.prefixlen) - 1) << addrbits
prefix = bytes(b"")
for i in range(-1, -(addrbits >> 3) - 2, -1):
prefix = bytes([self.prefix[i] & (netmask & 0xff)]) + prefix
netmask >>= 8
self.prefix = self.prefix[:i] + prefix
@ -317,11 +320,11 @@ class IpPrefix(object):
self.af == AF_INET and tmp == (1 << (self.addrlen - self.prefixlen)) - 1):
raise ValueError("invalid hostid for prefix %s: %s" % (self, hostid))
addr = ""
addr = bytes(b"")
prefix_endpoint = -1
for i in xrange(-1, -(self.addrlen >> 3) - 1, -1):
for i in range(-1, -(self.addrlen >> 3) - 1, -1):
prefix_endpoint = i
addr = chr(ord(self.prefix[i]) | (tmp & 0xff)) + addr
addr = bytes([self.prefix[i] | (tmp & 0xff)]) + addr
tmp >>= 8
if not tmp:
break
@ -375,7 +378,7 @@ class IpPrefix(object):
:rtype: str
"""
addrbits = self.addrlen - self.prefixlen
netmask = ((1L << self.prefixlen) - 1) << addrbits
netmask = ((1 << self.prefixlen) - 1) << addrbits
netmaskbytes = struct.pack("!L", netmask)
return IpAddress(af=AF_INET, address=netmaskbytes).__str__()

View file

@ -5,15 +5,19 @@ Linux Ethernet bridging and ebtables rules.
import logging
import os
import socket
import threading
import time
from socket import AF_INET, AF_INET6
from core import CoreCommandError
from core import CoreCommandError, utils
from core import constants
from core.coreobj import PyCoreNet
from core.misc import utils
from core.netns.vif import GreTap
from core.netns.vif import VEth
from core.nodes.base import CoreNetworkBase
from core.emulator.data import LinkData
from core.emulator.enumerations import NodeTypes, LinkTypes, RegisterTlvs
from core.nodes import ipaddress
from core.nodes.interface import GreTap
from core.nodes.interface import Veth
utils.check_executables([
constants.BRCTL_BIN,
@ -236,30 +240,30 @@ def ebtablescmds(call, cmds):
call(args)
class LxBrNet(PyCoreNet):
class CoreNetwork(CoreNetworkBase):
"""
Provides linux bridge network functionlity for core nodes.
Provides linux bridge network functionality for core nodes.
"""
policy = "DROP"
def __init__(self, session, objid=None, name=None, start=True, policy=None):
def __init__(self, session, _id=None, name=None, start=True, policy=None):
"""
Creates a LxBrNet instance.
:param core.session.Session session: core session instance
:param int objid: object id
:param int _id: object id
:param str name: object name
:param bool start: start flag
:param policy: network policy
"""
PyCoreNet.__init__(self, session, objid, name, start)
CoreNetworkBase.__init__(self, session, _id, name, start)
if name is None:
name = str(self.objid)
name = str(self.id)
if policy is not None:
self.policy = policy
self.name = name
sessionid = self.session.short_session_id()
self.brname = "b.%s.%s" % (str(self.objid), sessionid)
self.brname = "b.%s.%s" % (str(self.id), sessionid)
self.up = False
if start:
self.startup()
@ -333,7 +337,7 @@ class LxBrNet(PyCoreNet):
utils.check_cmd([constants.BRCTL_BIN, "addif", self.brname, netif.localname])
utils.check_cmd([constants.IP_BIN, "link", "set", netif.localname, "up"])
PyCoreNet.attach(self, netif)
CoreNetworkBase.attach(self, netif)
def detach(self, netif):
"""
@ -345,7 +349,7 @@ class LxBrNet(PyCoreNet):
if self.up:
utils.check_cmd([constants.BRCTL_BIN, "delif", self.brname, netif.localname])
PyCoreNet.detach(self, netif)
CoreNetworkBase.detach(self, netif)
def linked(self, netif1, netif2):
"""
@ -477,7 +481,12 @@ class LxBrNet(PyCoreNet):
netem += ["loss", "%s%%" % min(loss, 100)]
if duplicate is not None and duplicate > 0:
netem += ["duplicate", "%s%%" % min(duplicate, 100)]
if delay <= 0 and jitter <= 0 and loss <= 0 and duplicate <= 0:
delay_check = delay is None or delay <= 0
jitter_check = jitter is None or jitter <= 0
loss_check = loss is None or loss <= 0
duplicate_check = duplicate is None or duplicate <= 0
if all([delay_check, jitter_check, loss_check, duplicate_check]):
# possibly remove netem if it exists and parent queue wasn't removed
if not netif.getparam("has_netem"):
return
@ -503,24 +512,24 @@ class LxBrNet(PyCoreNet):
"""
sessionid = self.session.short_session_id()
try:
self_objid = "%x" % self.objid
_id = "%x" % self.id
except TypeError:
self_objid = "%s" % self.objid
_id = "%s" % self.id
try:
net_objid = "%x" % net.objid
net_id = "%x" % net.id
except TypeError:
net_objid = "%s" % net.objid
net_id = "%s" % net.id
localname = "veth%s.%s.%s" % (self_objid, net_objid, sessionid)
localname = "veth%s.%s.%s" % (_id, net_id, sessionid)
if len(localname) >= 16:
raise ValueError("interface local name %s too long" % localname)
name = "veth%s.%s.%s" % (net_objid, self_objid, sessionid)
name = "veth%s.%s.%s" % (net_id, _id, sessionid)
if len(name) >= 16:
raise ValueError("interface name %s too long" % name)
netif = VEth(node=None, name=name, localname=localname, mtu=1500, net=self, start=self.up)
netif = Veth(node=None, name=name, localname=localname, mtu=1500, net=self, start=self.up)
self.attach(netif)
if net.up:
# this is similar to net.attach() but uses netif.name instead
@ -564,20 +573,20 @@ class LxBrNet(PyCoreNet):
utils.check_cmd([constants.IP_BIN, "addr", "add", str(addr), "dev", self.brname])
class GreTapBridge(LxBrNet):
class GreTapBridge(CoreNetwork):
"""
A network consisting of a bridge with a gretap device for tunneling to
another system.
"""
def __init__(self, session, remoteip=None, objid=None, name=None,
def __init__(self, session, remoteip=None, _id=None, name=None,
policy="ACCEPT", localip=None, ttl=255, key=None, start=True):
"""
Create a GreTapBridge instance.
:param core.session.Session session: core session instance
:param str remoteip: remote address
:param int objid: object id
:param int _id: object id
:param str name: object name
:param policy: network policy
:param str localip: local address
@ -586,10 +595,10 @@ class GreTapBridge(LxBrNet):
:param bool start: start flag
:return:
"""
LxBrNet.__init__(self, session=session, objid=objid, name=name, policy=policy, start=False)
CoreNetwork.__init__(self, session=session, _id=_id, name=name, policy=policy, start=False)
self.grekey = key
if self.grekey is None:
self.grekey = self.session.id ^ self.objid
self.grekey = self.session.id ^ self.id
self.localnum = None
self.remotenum = None
self.remoteip = remoteip
@ -609,7 +618,7 @@ class GreTapBridge(LxBrNet):
:return: nothing
"""
LxBrNet.startup(self)
CoreNetwork.startup(self)
if self.gretap:
self.attach(self.gretap)
@ -623,7 +632,7 @@ class GreTapBridge(LxBrNet):
self.detach(self.gretap)
self.gretap.shutdown()
self.gretap = None
LxBrNet.shutdown(self)
CoreNetwork.shutdown(self)
def addrconfig(self, addrlist):
"""
@ -654,3 +663,412 @@ class GreTapBridge(LxBrNet):
:return: nothing
"""
self.grekey = key
class CtrlNet(CoreNetwork):
"""
Control network functionality.
"""
policy = "ACCEPT"
# base control interface index
CTRLIF_IDX_BASE = 99
DEFAULT_PREFIX_LIST = [
"172.16.0.0/24 172.16.1.0/24 172.16.2.0/24 172.16.3.0/24 172.16.4.0/24",
"172.17.0.0/24 172.17.1.0/24 172.17.2.0/24 172.17.3.0/24 172.17.4.0/24",
"172.18.0.0/24 172.18.1.0/24 172.18.2.0/24 172.18.3.0/24 172.18.4.0/24",
"172.19.0.0/24 172.19.1.0/24 172.19.2.0/24 172.19.3.0/24 172.19.4.0/24"
]
def __init__(self, session, _id="ctrlnet", name=None, prefix=None,
hostid=None, start=True, assign_address=True,
updown_script=None, serverintf=None):
"""
Creates a CtrlNet instance.
:param core.session.Session session: core session instance
:param int _id: node id
:param str name: node namee
:param prefix: control network ipv4 prefix
:param hostid: host id
:param bool start: start flag
:param str assign_address: assigned address
:param str updown_script: updown script
:param serverintf: server interface
:return:
"""
self.prefix = ipaddress.Ipv4Prefix(prefix)
self.hostid = hostid
self.assign_address = assign_address
self.updown_script = updown_script
self.serverintf = serverintf
CoreNetwork.__init__(self, session, _id=_id, name=name, start=start)
def startup(self):
"""
Startup functionality for the control network.
:return: nothing
:raises CoreCommandError: when there is a command exception
"""
if self.detectoldbridge():
return
CoreNetwork.startup(self)
if self.hostid:
addr = self.prefix.addr(self.hostid)
else:
addr = self.prefix.max_addr()
logging.info("added control network bridge: %s %s", self.brname, self.prefix)
if self.assign_address:
addrlist = ["%s/%s" % (addr, self.prefix.prefixlen)]
self.addrconfig(addrlist=addrlist)
logging.info("address %s", addr)
if self.updown_script:
logging.info("interface %s updown script (%s startup) called", self.brname, self.updown_script)
utils.check_cmd([self.updown_script, self.brname, "startup"])
if self.serverintf:
# sets the interface as a port of the bridge
utils.check_cmd([constants.BRCTL_BIN, "addif", self.brname, self.serverintf])
# bring interface up
utils.check_cmd([constants.IP_BIN, "link", "set", self.serverintf, "up"])
def detectoldbridge(self):
"""
Occassionally, control net bridges from previously closed sessions are not cleaned up.
Check if there are old control net bridges and delete them
:return: True if an old bridge was detected, False otherwise
:rtype: bool
"""
status, output = utils.cmd_output([constants.BRCTL_BIN, "show"])
if status != 0:
logging.error("Unable to retrieve list of installed bridges")
else:
lines = output.split("\n")
for line in lines[1:]:
cols = line.split("\t")
oldbr = cols[0]
flds = cols[0].split(".")
if len(flds) == 3:
if flds[0] == "b" and flds[1] == self.id:
logging.error(
"error: An active control net bridge (%s) found. "
"An older session might still be running. "
"Stop all sessions and, if needed, delete %s to continue.", oldbr, oldbr
)
return True
return False
def shutdown(self):
"""
Control network shutdown.
:return: nothing
"""
if self.serverintf is not None:
try:
utils.check_cmd([constants.BRCTL_BIN, "delif", self.brname, self.serverintf])
except CoreCommandError:
logging.exception("error deleting server interface %s from bridge %s", self.serverintf, self.brname)
if self.updown_script is not None:
try:
logging.info("interface %s updown script (%s shutdown) called", self.brname, self.updown_script)
utils.check_cmd([self.updown_script, self.brname, "shutdown"])
except CoreCommandError:
logging.exception("error issuing shutdown script shutdown")
CoreNetwork.shutdown(self)
def all_link_data(self, flags):
"""
Do not include CtrlNet in link messages describing this session.
:param flags: message flags
:return: list of link data
:rtype: list[core.data.LinkData]
"""
return []
class PtpNet(CoreNetwork):
"""
Peer to peer network node.
"""
policy = "ACCEPT"
def attach(self, netif):
"""
Attach a network interface, but limit attachment to two interfaces.
:param core.netns.vif.VEth netif: network interface
:return: nothing
"""
if len(self._netif) >= 2:
raise ValueError("Point-to-point links support at most 2 network interfaces")
CoreNetwork.attach(self, netif)
def data(self, message_type, lat=None, lon=None, alt=None):
"""
Do not generate a Node Message for point-to-point links. They are
built using a link message instead.
:param message_type: purpose for the data object we are creating
:param float lat: latitude
:param float lon: longitude
:param float alt: altitude
:return: node data object
:rtype: core.data.NodeData
"""
return None
def all_link_data(self, flags):
"""
Build CORE API TLVs for a point-to-point link. One Link message
describes this network.
:param flags: message flags
:return: list of link data
:rtype: list[core.data.LinkData]
"""
all_links = []
if len(self._netif) != 2:
return all_links
if1, if2 = self._netif.values()
unidirectional = 0
if if1.getparams() != if2.getparams():
unidirectional = 1
interface1_ip4 = None
interface1_ip4_mask = None
interface1_ip6 = None
interface1_ip6_mask = None
for address in if1.addrlist:
ip, _sep, mask = address.partition("/")
mask = int(mask)
if ipaddress.is_ipv4_address(ip):
family = AF_INET
ipl = socket.inet_pton(family, ip)
interface1_ip4 = ipaddress.IpAddress(af=family, address=ipl)
interface1_ip4_mask = mask
else:
family = AF_INET6
ipl = socket.inet_pton(family, ip)
interface1_ip6 = ipaddress.IpAddress(af=family, address=ipl)
interface1_ip6_mask = mask
interface2_ip4 = None
interface2_ip4_mask = None
interface2_ip6 = None
interface2_ip6_mask = None
for address in if2.addrlist:
ip, _sep, mask = address.partition("/")
mask = int(mask)
if ipaddress.is_ipv4_address(ip):
family = AF_INET
ipl = socket.inet_pton(family, ip)
interface2_ip4 = ipaddress.IpAddress(af=family, address=ipl)
interface2_ip4_mask = mask
else:
family = AF_INET6
ipl = socket.inet_pton(family, ip)
interface2_ip6 = ipaddress.IpAddress(af=family, address=ipl)
interface2_ip6_mask = mask
link_data = LinkData(
message_type=flags,
node1_id=if1.node.id,
node2_id=if2.node.id,
link_type=self.linktype,
unidirectional=unidirectional,
delay=if1.getparam("delay"),
bandwidth=if1.getparam("bw"),
dup=if1.getparam("duplicate"),
jitter=if1.getparam("jitter"),
interface1_id=if1.node.getifindex(if1),
interface1_mac=if1.hwaddr,
interface1_ip4=interface1_ip4,
interface1_ip4_mask=interface1_ip4_mask,
interface1_ip6=interface1_ip6,
interface1_ip6_mask=interface1_ip6_mask,
interface2_id=if2.node.getifindex(if2),
interface2_mac=if2.hwaddr,
interface2_ip4=interface2_ip4,
interface2_ip4_mask=interface2_ip4_mask,
interface2_ip6=interface2_ip6,
interface2_ip6_mask=interface2_ip6_mask,
)
all_links.append(link_data)
# build a 2nd link message for the upstream link parameters
# (swap if1 and if2)
if unidirectional:
link_data = LinkData(
message_type=0,
node1_id=if2.node.id,
node2_id=if1.node.id,
delay=if1.getparam("delay"),
bandwidth=if1.getparam("bw"),
dup=if1.getparam("duplicate"),
jitter=if1.getparam("jitter"),
unidirectional=1,
interface1_id=if2.node.getifindex(if2),
interface2_id=if1.node.getifindex(if1)
)
all_links.append(link_data)
return all_links
class SwitchNode(CoreNetwork):
"""
Provides switch functionality within a core node.
"""
apitype = NodeTypes.SWITCH.value
policy = "ACCEPT"
type = "lanswitch"
class HubNode(CoreNetwork):
"""
Provides hub functionality within a core node, forwards packets to all bridge
ports by turning off MAC address learning.
"""
apitype = NodeTypes.HUB.value
policy = "ACCEPT"
type = "hub"
def __init__(self, session, _id=None, name=None, start=True):
"""
Creates a HubNode instance.
:param core.session.Session session: core session instance
:param int _id: node id
:param str name: node namee
:param bool start: start flag
:raises CoreCommandError: when there is a command exception
"""
CoreNetwork.__init__(self, session, _id, name, start)
# TODO: move to startup method
if start:
utils.check_cmd([constants.BRCTL_BIN, "setageing", self.brname, "0"])
class WlanNode(CoreNetwork):
"""
Provides wireless lan functionality within a core node.
"""
apitype = NodeTypes.WIRELESS_LAN.value
linktype = LinkTypes.WIRELESS.value
policy = "DROP"
type = "wlan"
def __init__(self, session, _id=None, name=None, start=True, policy=None):
"""
Create a WlanNode instance.
:param core.session.Session session: core session instance
:param int _id: node id
:param str name: node name
:param bool start: start flag
:param policy: wlan policy
"""
CoreNetwork.__init__(self, session, _id, name, start, policy)
# wireless model such as basic range
self.model = None
# mobility model such as scripted
self.mobility = None
def attach(self, netif):
"""
Attach a network interface.
:param core.netns.vif.VEth netif: network interface
:return: nothing
"""
CoreNetwork.attach(self, netif)
if self.model:
netif.poshook = self.model.position_callback
if netif.node is None:
return
x, y, z = netif.node.position.get()
# invokes any netif.poshook
netif.setposition(x, y, z)
def setmodel(self, model, config):
"""
Sets the mobility and wireless model.
:param core.mobility.WirelessModel.cls model: wireless model to set to
:param dict config: configuration for model being set
:return: nothing
"""
logging.info("adding model: %s", model.name)
if model.config_type == RegisterTlvs.WIRELESS.value:
self.model = model(session=self.session, _id=self.id)
self.model.update_config(config)
if self.model.position_callback:
for netif in self.netifs():
netif.poshook = self.model.position_callback
if netif.node is not None:
x, y, z = netif.node.position.get()
netif.poshook(netif, x, y, z)
self.model.setlinkparams()
elif model.config_type == RegisterTlvs.MOBILITY.value:
self.mobility = model(session=self.session, _id=self.id)
self.mobility.update_config(config)
def update_mobility(self, config):
if not self.mobility:
raise ValueError("no mobility set to update for node(%s)", self.id)
self.mobility.set_configs(config, node_id=self.id)
def updatemodel(self, config):
if not self.model:
raise ValueError("no model set to update for node(%s)", self.id)
logging.info("node(%s) updating model(%s): %s", self.id, self.model.name, config)
self.model.set_configs(config, node_id=self.id)
if self.model.position_callback:
for netif in self.netifs():
netif.poshook = self.model.position_callback
if netif.node is not None:
x, y, z = netif.node.position.get()
netif.poshook(netif, x, y, z)
self.model.updateconfig()
def all_link_data(self, flags):
"""
Retrieve all link data.
:param flags: message flags
:return: list of link data
:rtype: list[core.data.LinkData]
"""
all_links = CoreNetwork.all_link_data(self, flags)
if self.model:
all_links.extend(self.model.all_link_data(flags))
return all_links
class TunnelNode(GreTapBridge):
"""
Provides tunnel functionality in a core node.
"""
apitype = NodeTypes.TUNNEL.value
policy = "ACCEPT"
type = "tunnel"

View file

@ -0,0 +1,29 @@
"""
Provides default node maps that can be used to run core with.
"""
import core.nodes.base
import core.nodes.network
import core.nodes.physical
from core.emane.nodes import EmaneNet
from core.emane.nodes import EmaneNode
from core.emulator.enumerations import NodeTypes
from core.nodes.network import GreTapBridge
from core.nodes import physical
# legacy core nodes, that leverage linux bridges
NODES = {
NodeTypes.DEFAULT: core.nodes.base.CoreNode,
NodeTypes.PHYSICAL: physical.PhysicalNode,
NodeTypes.TBD: None,
NodeTypes.SWITCH: core.nodes.network.SwitchNode,
NodeTypes.HUB: core.nodes.network.HubNode,
NodeTypes.WIRELESS_LAN: core.nodes.network.WlanNode,
NodeTypes.RJ45: core.nodes.physical.Rj45Node,
NodeTypes.TUNNEL: core.nodes.network.TunnelNode,
NodeTypes.KTUNNEL: None,
NodeTypes.EMANE: EmaneNode,
NodeTypes.EMANE_NET: EmaneNet,
NodeTypes.TAP_BRIDGE: GreTapBridge,
NodeTypes.PEER_TO_PEER: core.nodes.network.PtpNet,
NodeTypes.CONTROL_NET: core.nodes.network.CtrlNet
}

View file

@ -9,7 +9,8 @@ _NODE_MAP = None
def _log_map():
global _NODE_MAP
for key, value in _NODE_MAP.iteritems():
for key in _NODE_MAP:
value = _NODE_MAP[key]
name = None
if value:
name = value.__name__
@ -72,7 +73,7 @@ def get_node_type(node_class):
:rtype: core.enumerations.NodeTypes
"""
global _NODE_MAP
node_type_map = {v: k for k, v in _NODE_MAP.iteritems()}
node_type_map = {_NODE_MAP[x]: x for x in _NODE_MAP}
return node_type_map.get(node_class)

View file

@ -8,19 +8,18 @@ import threading
from socket import AF_INET
from socket import AF_INET6
from core import CoreCommandError
from core import CoreCommandError, utils
from core import constants
from core.coreobj import PyCoreNet
from core.data import LinkData
from core.enumerations import LinkTypes
from core.enumerations import NodeTypes
from core.enumerations import RegisterTlvs
from core.misc import ipaddress
from core.misc import utils
from core.netns.vif import GreTap
from core.netns.vif import VEth
from core.netns.vnet import EbtablesQueue
from core.netns.vnet import GreTapBridge
from core.nodes.base import CoreNetworkBase
from core.emulator.data import LinkData
from core.emulator.enumerations import LinkTypes
from core.emulator.enumerations import NodeTypes
from core.emulator.enumerations import RegisterTlvs
from core.nodes import ipaddress
from core.nodes.interface import GreTap
from core.nodes.interface import Veth
from core.nodes.network import EbtablesQueue
from core.nodes.network import GreTapBridge
# a global object because all WLANs share the same queue
# cannot have multiple threads invoking the ebtables commnd
@ -41,7 +40,7 @@ def ebtables_commands(call, commands):
call(command)
class OvsNet(PyCoreNet):
class OvsNet(CoreNetworkBase):
"""
Used to be LxBrNet.
@ -50,19 +49,19 @@ class OvsNet(PyCoreNet):
policy = "DROP"
def __init__(self, session, objid=None, name=None, start=True, policy=None):
def __init__(self, session, _id=None, name=None, start=True, policy=None):
"""
Creates an OvsNet instance.
:param core.session.Session session: session this object is a part of
:param objid:
:param _id:
:param name:
:param start:
:param policy:
:return:
"""
PyCoreNet.__init__(self, session, objid, name, start)
CoreNetworkBase.__init__(self, session, _id, name, start)
if policy:
self.policy = policy
@ -70,7 +69,7 @@ class OvsNet(PyCoreNet):
self.policy = self.__class__.policy
session_id = self.session.short_session_id()
self.bridge_name = "b.%s.%s" % (str(self.objid), session_id)
self.bridge_name = "b.%s.%s" % (str(self.id), session_id)
self.up = False
if start:
@ -129,13 +128,13 @@ class OvsNet(PyCoreNet):
utils.check_cmd([constants.OVS_BIN, "add-port", self.bridge_name, interface.localname])
utils.check_cmd([constants.IP_BIN, "link", "set", interface.localname, "up"])
PyCoreNet.attach(self, interface)
CoreNetworkBase.attach(self, interface)
def detach(self, interface):
if self.up:
utils.check_cmd([constants.OVS_BIN, "del-port", self.bridge_name, interface.localname])
PyCoreNet.detach(self, interface)
CoreNetworkBase.detach(self, interface)
def linked(self, interface_one, interface_two):
# check if the network interfaces are attached to this network
@ -279,25 +278,25 @@ class OvsNet(PyCoreNet):
session_id = self.session.short_session_id()
try:
self_objid = "%x" % self.objid
_id = "%x" % self.id
except TypeError:
self_objid = "%s" % self.objid
_id = "%s" % self.id
try:
net_objid = "%x" % network.objid
network_id = "%x" % network.id
except TypeError:
net_objid = "%s" % network.objid
network_id = "%s" % network.id
localname = "veth%s.%s.%s" % (self_objid, net_objid, session_id)
localname = "veth%s.%s.%s" % (_id, network_id, session_id)
if len(localname) >= 16:
raise ValueError("interface local name %s too long" % localname)
name = "veth%s.%s.%s" % (net_objid, self_objid, session_id)
name = "veth%s.%s.%s" % (network_id, _id, session_id)
if len(name) >= 16:
raise ValueError("interface name %s too long" % name)
interface = VEth(node=None, name=name, localname=localname, mtu=1500, net=self, start=self.up)
interface = Veth(node=None, name=name, localname=localname, mtu=1500, net=self, start=self.up)
self.attach(interface)
if network.up:
# this is similar to net.attach() but uses netif.name instead
@ -349,14 +348,14 @@ class OvsCtrlNet(OvsNet):
"172.19.0.0/24 172.19.1.0/24 172.19.2.0/24 172.19.3.0/24 172.19.4.0/24"
]
def __init__(self, session, objid="ctrlnet", name=None, prefix=None, hostid=None,
def __init__(self, session, _id="ctrlnet", name=None, prefix=None, hostid=None,
start=True, assign_address=True, updown_script=None, serverintf=None):
self.prefix = ipaddress.Ipv4Prefix(prefix)
self.hostid = hostid
self.assign_address = assign_address
self.updown_script = updown_script
self.serverintf = serverintf
OvsNet.__init__(self, session, objid=objid, name=name, start=start)
OvsNet.__init__(self, session, _id=_id, name=name, start=start)
def startup(self):
if self.detectoldbridge():
@ -394,7 +393,7 @@ class OvsCtrlNet(OvsNet):
if output:
for line in output.split("\n"):
bride_name = line.split(".")
if bride_name[0] == "b" and bride_name[1] == self.objid:
if bride_name[0] == "b" and bride_name[1] == self.id:
logging.error("older session may still be running with conflicting id for bridge: %s", line)
return True
@ -495,8 +494,8 @@ class OvsPtpNet(OvsNet):
# loss=netif.getparam("loss")
link_data = LinkData(
message_type=flags,
node1_id=if1.node.objid,
node2_id=if2.node.objid,
node1_id=if1.node.id,
node2_id=if2.node.id,
link_type=self.linktype,
unidirectional=unidirectional,
delay=if1.getparam("delay"),
@ -524,8 +523,8 @@ class OvsPtpNet(OvsNet):
if unidirectional:
link_data = LinkData(
message_type=0,
node1_id=if2.node.objid,
node2_id=if1.node.objid,
node1_id=if2.node.id,
node2_id=if1.node.id,
delay=if1.getparam("delay"),
bandwidth=if1.getparam("bw"),
dup=if1.getparam("duplicate"),
@ -550,12 +549,12 @@ class OvsHubNode(OvsNet):
policy = "ACCEPT"
type = "hub"
def __init__(self, session, objid=None, name=None, start=True):
def __init__(self, session, _id=None, name=None, start=True):
"""
the Hub node forwards packets to all bridge ports by turning off
the MAC address learning
"""
OvsNet.__init__(self, session, objid, name, start)
OvsNet.__init__(self, session, _id, name, start)
if start:
# TODO: verify that the below flow accomplishes what is desired for a "HUB"
@ -569,8 +568,8 @@ class OvsWlanNode(OvsNet):
policy = "DROP"
type = "wlan"
def __init__(self, session, objid=None, name=None, start=True, policy=None):
OvsNet.__init__(self, session, objid, name, start, policy)
def __init__(self, session, _id=None, name=None, start=True, policy=None):
OvsNet.__init__(self, session, _id, name, start, policy)
# wireless model such as basic range
self.model = None
@ -598,7 +597,7 @@ class OvsWlanNode(OvsNet):
logging.info("adding model %s", model.name)
if model.type == RegisterTlvs.WIRELESS.value:
self.model = model(session=self.session, object_id=self.objid, config=config)
self.model = model(session=self.session, _id=self.id, config=config)
if self.model.position_callback:
for interface in self.netifs():
interface.poshook = self.model.position_callback
@ -607,13 +606,13 @@ class OvsWlanNode(OvsNet):
interface.poshook(interface, x, y, z)
self.model.setlinkparams()
elif model.type == RegisterTlvs.MOBILITY.value:
self.mobility = model(session=self.session, object_id=self.objid, config=config)
self.mobility = model(session=self.session, _id=self.id, config=config)
def updatemodel(self, config):
if not self.model:
raise ValueError("no model set to update for node(%s)", self.objid)
logging.info("node(%s) updating model(%s): %s", self.objid, self.model.name, config)
self.model.set_configs(config, node_id=self.objid)
raise ValueError("no model set to update for node(%s)", self.id)
logging.info("node(%s) updating model(%s): %s", self.id, self.model.name, config)
self.model.set_configs(config, node_id=self.id)
if self.model.position_callback:
for netif in self.netifs():
netif.poshook = self.model.position_callback
@ -643,12 +642,12 @@ class OvsGreTapBridge(OvsNet):
another system.
"""
def __init__(self, session, remoteip=None, objid=None, name=None, policy="ACCEPT",
def __init__(self, session, remoteip=None, _id=None, name=None, policy="ACCEPT",
localip=None, ttl=255, key=None, start=True):
OvsNet.__init__(self, session=session, objid=objid, name=name, policy=policy, start=False)
OvsNet.__init__(self, session=session, _id=_id, name=name, policy=policy, start=False)
self.grekey = key
if self.grekey is None:
self.grekey = self.session.id ^ self.objid
self.grekey = self.session.id ^ self.id
self.localnum = None
self.remotenum = None

View file

@ -0,0 +1,544 @@
"""
PhysicalNode class for including real systems in the emulated network.
"""
import logging
import os
import subprocess
import threading
from core import CoreCommandError, utils
from core import constants
from core.nodes.base import CoreNodeBase
from core.nodes.interface import CoreInterface
from core.emulator.enumerations import NodeTypes
from core.nodes.network import GreTap
from core.nodes.network import CoreNetwork
class PhysicalNode(CoreNodeBase):
def __init__(self, session, _id=None, name=None, nodedir=None, start=True):
CoreNodeBase.__init__(self, session, _id, name, start=start)
self.nodedir = nodedir
self.up = start
self.lock = threading.RLock()
self._mounts = []
if start:
self.startup()
def startup(self):
with self.lock:
self.makenodedir()
def shutdown(self):
if not self.up:
return
with self.lock:
while self._mounts:
_source, target = self._mounts.pop(-1)
self.umount(target)
for netif in self.netifs():
netif.shutdown()
self.rmnodedir()
def termcmdstring(self, sh="/bin/sh"):
"""
Create a terminal command string.
:param str sh: shell to execute command in
:return: str
"""
return sh
def cmd(self, args, wait=True):
"""
Runs shell command on node, with option to not wait for a result.
:param list[str]|str args: command to run
:param bool wait: wait for command to exit, defaults to True
:return: exit status for command
:rtype: int
"""
os.chdir(self.nodedir)
status = utils.cmd(args, wait)
return status
def cmd_output(self, args):
"""
Runs shell command on node and get exit status and output.
:param list[str]|str args: command to run
:return: exit status and combined stdout and stderr
:rtype: tuple[int, str]
"""
os.chdir(self.nodedir)
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout, _ = p.communicate()
status = p.wait()
return status, stdout.strip()
def check_cmd(self, args):
"""
Runs shell command on node.
:param list[str]|str args: command to run
:return: combined stdout and stderr
:rtype: str
:raises CoreCommandError: when a non-zero exit status occurs
"""
status, output = self.cmd_output(args)
if status:
raise CoreCommandError(status, args, output)
return output.strip()
def shcmd(self, cmdstr, sh="/bin/sh"):
return self.cmd([sh, "-c", cmdstr])
def sethwaddr(self, ifindex, addr):
"""
same as SimpleLxcNode.sethwaddr()
"""
self._netif[ifindex].sethwaddr(addr)
ifname = self.ifname(ifindex)
if self.up:
self.check_cmd([constants.IP_BIN, "link", "set", "dev", ifname, "address", str(addr)])
def addaddr(self, ifindex, addr):
"""
same as SimpleLxcNode.addaddr()
"""
if self.up:
self.check_cmd([constants.IP_BIN, "addr", "add", str(addr), "dev", self.ifname(ifindex)])
self._netif[ifindex].addaddr(addr)
def deladdr(self, ifindex, addr):
"""
same as SimpleLxcNode.deladdr()
"""
try:
self._netif[ifindex].deladdr(addr)
except ValueError:
logging.exception("trying to delete unknown address: %s", addr)
if self.up:
self.check_cmd([constants.IP_BIN, "addr", "del", str(addr), "dev", self.ifname(ifindex)])
def adoptnetif(self, netif, ifindex, hwaddr, addrlist):
"""
The broker builds a GreTap tunnel device to this physical node.
When a link message is received linking this node to another part of
the emulation, no new interface is created; instead, adopt the
GreTap netif as the node interface.
"""
netif.name = "gt%d" % ifindex
netif.node = self
self.addnetif(netif, ifindex)
# use a more reasonable name, e.g. "gt0" instead of "gt.56286.150"
if self.up:
self.check_cmd([constants.IP_BIN, "link", "set", "dev", netif.localname, "down"])
self.check_cmd([constants.IP_BIN, "link", "set", netif.localname, "name", netif.name])
netif.localname = netif.name
if hwaddr:
self.sethwaddr(ifindex, hwaddr)
for addr in utils.make_tuple(addrlist):
self.addaddr(ifindex, addr)
if self.up:
self.check_cmd([constants.IP_BIN, "link", "set", "dev", netif.localname, "up"])
def linkconfig(self, netif, bw=None, delay=None, loss=None, duplicate=None, jitter=None, netif2=None):
"""
Apply tc queing disciplines using LxBrNet.linkconfig()
"""
# borrow the tc qdisc commands from LxBrNet.linkconfig()
linux_bridge = CoreNetwork(session=self.session, start=False)
linux_bridge.up = True
linux_bridge.linkconfig(netif, bw=bw, delay=delay, loss=loss, duplicate=duplicate, jitter=jitter, netif2=netif2)
del linux_bridge
def newifindex(self):
with self.lock:
while self.ifindex in self._netif:
self.ifindex += 1
ifindex = self.ifindex
self.ifindex += 1
return ifindex
def newnetif(self, net=None, addrlist=None, hwaddr=None, ifindex=None, ifname=None):
logging.info("creating interface")
if not addrlist:
addrlist = []
if self.up and net is None:
raise NotImplementedError
if ifindex is None:
ifindex = self.newifindex()
if self.up:
# 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
gt = self.session.broker.addnettunnel(net.id)
if gt is None or len(gt) != 1:
raise ValueError("error building tunnel from adding a new network interface: %s" % gt)
gt = gt[0]
net.detach(gt)
self.adoptnetif(gt, ifindex, hwaddr, addrlist)
return ifindex
# this is reached when configuring services (self.up=False)
if ifname is None:
ifname = "gt%d" % ifindex
netif = GreTap(node=self, name=ifname, session=self.session, start=False)
self.adoptnetif(netif, ifindex, hwaddr, addrlist)
return ifindex
def privatedir(self, path):
if path[0] != "/":
raise ValueError("path not fully qualified: %s" % path)
hostpath = os.path.join(self.nodedir, os.path.normpath(path).strip('/').replace('/', '.'))
os.mkdir(hostpath)
self.mount(hostpath, path)
def mount(self, source, target):
source = os.path.abspath(source)
logging.info("mounting %s at %s", source, target)
os.makedirs(target)
self.check_cmd([constants.MOUNT_BIN, "--bind", source, target])
self._mounts.append((source, target))
def umount(self, target):
logging.info("unmounting '%s'" % target)
try:
self.check_cmd([constants.UMOUNT_BIN, "-l", target])
except CoreCommandError:
logging.exception("unmounting failed for %s", target)
def opennodefile(self, filename, mode="w"):
dirname, basename = os.path.split(filename)
if not basename:
raise ValueError("no basename for filename: " + filename)
if dirname and dirname[0] == "/":
dirname = dirname[1:]
dirname = dirname.replace("/", ".")
dirname = os.path.join(self.nodedir, dirname)
if not os.path.isdir(dirname):
os.makedirs(dirname, mode=0o755)
hostfilename = os.path.join(dirname, basename)
return open(hostfilename, mode)
def nodefile(self, filename, contents, mode=0o644):
with self.opennodefile(filename, "w") as node_file:
node_file.write(contents)
os.chmod(node_file.name, mode)
logging.info("created nodefile: '%s'; mode: 0%o", node_file.name, mode)
class Rj45Node(CoreNodeBase, CoreInterface):
"""
RJ45Node is a physical interface on the host linked to the emulated
network.
"""
apitype = NodeTypes.RJ45.value
type = "rj45"
def __init__(self, session, _id=None, name=None, mtu=1500, start=True):
"""
Create an RJ45Node instance.
:param core.session.Session session: core session instance
:param int _id: node id
:param str name: node name
:param mtu: rj45 mtu
:param bool start: start flag
:return:
"""
CoreNodeBase.__init__(self, session, _id, name, start=start)
CoreInterface.__init__(self, node=self, name=name, mtu=mtu)
self.up = False
self.lock = threading.RLock()
self.ifindex = None
# the following are PyCoreNetIf attributes
self.transport_type = "raw"
self.localname = name
self.old_up = False
self.old_addrs = []
if start:
self.startup()
def startup(self):
"""
Set the interface in the up state.
:return: nothing
:raises CoreCommandError: when there is a command exception
"""
# interface will also be marked up during net.attach()
self.savestate()
utils.check_cmd([constants.IP_BIN, "link", "set", self.localname, "up"])
self.up = True
def shutdown(self):
"""
Bring the interface down. Remove any addresses and queuing
disciplines.
:return: nothing
"""
if not self.up:
return
try:
utils.check_cmd([constants.IP_BIN, "link", "set", self.localname, "down"])
utils.check_cmd([constants.IP_BIN, "addr", "flush", "dev", self.localname])
utils.check_cmd([constants.TC_BIN, "qdisc", "del", "dev", self.localname, "root"])
except CoreCommandError:
logging.exception("error shutting down")
self.up = False
self.restorestate()
# TODO: issue in that both classes inherited from provide the same method with different signatures
def attachnet(self, net):
"""
Attach a network.
:param core.coreobj.PyCoreNet net: network to attach
:return: nothing
"""
CoreInterface.attachnet(self, net)
# TODO: issue in that both classes inherited from provide the same method with different signatures
def detachnet(self):
"""
Detach a network.
:return: nothing
"""
CoreInterface.detachnet(self)
def newnetif(self, net=None, addrlist=None, hwaddr=None, ifindex=None, ifname=None):
"""
This is called when linking with another node. Since this node
represents an interface, we do not create another object here,
but attach ourselves to the given network.
:param core.coreobj.PyCoreNet net: new network instance
:param list[str] addrlist: address list
:param str hwaddr: hardware address
:param int ifindex: interface index
:param str ifname: interface name
:return: interface index
:rtype: int
:raises ValueError: when an interface has already been created, one max
"""
with self.lock:
if ifindex is None:
ifindex = 0
if self.net is not None:
raise ValueError("RJ45 nodes support at most 1 network interface")
self._netif[ifindex] = self
# PyCoreNetIf.node is self
self.node = self
self.ifindex = ifindex
if net is not None:
self.attachnet(net)
if addrlist:
for addr in utils.make_tuple(addrlist):
self.addaddr(addr)
return ifindex
def delnetif(self, ifindex):
"""
Delete a network interface.
:param int ifindex: interface index to delete
:return: nothing
"""
if ifindex is None:
ifindex = 0
self._netif.pop(ifindex)
if ifindex == self.ifindex:
self.shutdown()
else:
raise ValueError("ifindex %s does not exist" % ifindex)
def netif(self, ifindex, net=None):
"""
This object is considered the network interface, so we only
return self here. This keeps the RJ45Node compatible with
real nodes.
:param int ifindex: interface index to retrieve
:param net: network to retrieve
:return: a network interface
:rtype: core.coreobj.PyCoreNetIf
"""
if net is not None and net == self.net:
return self
if ifindex is None:
ifindex = 0
if ifindex == self.ifindex:
return self
return None
def getifindex(self, netif):
"""
Retrieve network interface index.
:param core.coreobj.PyCoreNetIf netif: network interface to retrieve index for
:return: interface index, None otherwise
:rtype: int
"""
if netif != self:
return None
return self.ifindex
def addaddr(self, addr):
"""
Add address to to network interface.
:param str addr: address to add
:return: nothing
:raises CoreCommandError: when there is a command exception
"""
if self.up:
utils.check_cmd([constants.IP_BIN, "addr", "add", str(addr), "dev", self.name])
CoreInterface.addaddr(self, addr)
def deladdr(self, addr):
"""
Delete address from network interface.
:param str addr: address to delete
:return: nothing
:raises CoreCommandError: when there is a command exception
"""
if self.up:
utils.check_cmd([constants.IP_BIN, "addr", "del", str(addr), "dev", self.name])
CoreInterface.deladdr(self, addr)
def savestate(self):
"""
Save the addresses and other interface state before using the
interface for emulation purposes. TODO: save/restore the PROMISC flag
:return: nothing
:raises CoreCommandError: when there is a command exception
"""
self.old_up = False
self.old_addrs = []
args = [constants.IP_BIN, "addr", "show", "dev", self.localname]
output = utils.check_cmd(args)
for line in output.split("\n"):
items = line.split()
if len(items) < 2:
continue
if items[1] == "%s:" % self.localname:
flags = items[2][1:-1].split(",")
if "UP" in flags:
self.old_up = True
elif items[0] == "inet":
self.old_addrs.append((items[1], items[3]))
elif items[0] == "inet6":
if items[1][:4] == "fe80":
continue
self.old_addrs.append((items[1], None))
def restorestate(self):
"""
Restore the addresses and other interface state after using it.
:return: nothing
:raises CoreCommandError: when there is a command exception
"""
for addr in self.old_addrs:
if addr[1] is None:
utils.check_cmd([constants.IP_BIN, "addr", "add", addr[0], "dev", self.localname])
else:
utils.check_cmd([constants.IP_BIN, "addr", "add", addr[0], "brd", addr[1], "dev", self.localname])
if self.old_up:
utils.check_cmd([constants.IP_BIN, "link", "set", self.localname, "up"])
def setposition(self, x=None, y=None, z=None):
"""
Uses setposition from both parent classes.
:param float x: x position
:param float y: y position
:param float z: z position
:return: True if position changed, False otherwise
:rtype: bool
"""
result = CoreNodeBase.setposition(self, x, y, z)
CoreInterface.setposition(self, x, y, z)
return result
def check_cmd(self, args):
"""
Runs shell command on node.
:param list[str]|str args: command to run
:return: exist status and combined stdout and stderr
:rtype: tuple[int, str]
:raises CoreCommandError: when a non-zero exit status occurs
"""
raise NotImplementedError
def cmd(self, args, wait=True):
"""
Runs shell command on node, with option to not wait for a result.
:param list[str]|str args: command to run
:param bool wait: wait for command to exit, defaults to True
:return: exit status for command
:rtype: int
"""
raise NotImplementedError
def cmd_output(self, args):
"""
Runs shell command on node and get exit status and output.
:param list[str]|str args: command to run
:return: exit status and combined stdout and stderr
:rtype: tuple[int, str]
"""
raise NotImplementedError
def termcmdstring(self, sh):
"""
Create a terminal command string.
:param str sh: shell to execute command in
:return: str
"""
raise NotImplementedError

View file

@ -1,245 +0,0 @@
"""
PhysicalNode class for including real systems in the emulated network.
"""
import logging
import os
import subprocess
import threading
from core import CoreCommandError
from core import constants
from core.coreobj import PyCoreNode
from core.misc import utils
from core.netns.vnet import GreTap
from core.netns.vnet import LxBrNet
class PhysicalNode(PyCoreNode):
def __init__(self, session, objid=None, name=None, nodedir=None, start=True):
PyCoreNode.__init__(self, session, objid, name, start=start)
self.nodedir = nodedir
self.up = start
self.lock = threading.RLock()
self._mounts = []
if start:
self.startup()
def startup(self):
with self.lock:
self.makenodedir()
def shutdown(self):
if not self.up:
return
with self.lock:
while self._mounts:
_source, target = self._mounts.pop(-1)
self.umount(target)
for netif in self.netifs():
netif.shutdown()
self.rmnodedir()
def termcmdstring(self, sh="/bin/sh"):
"""
Create a terminal command string.
:param str sh: shell to execute command in
:return: str
"""
return sh
def cmd(self, args, wait=True):
"""
Runs shell command on node, with option to not wait for a result.
:param list[str]|str args: command to run
:param bool wait: wait for command to exit, defaults to True
:return: exit status for command
:rtype: int
"""
os.chdir(self.nodedir)
status = utils.cmd(args, wait)
return status
def cmd_output(self, args):
"""
Runs shell command on node and get exit status and output.
:param list[str]|str args: command to run
:return: exit status and combined stdout and stderr
:rtype: tuple[int, str]
"""
os.chdir(self.nodedir)
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout, _ = p.communicate()
status = p.wait()
return status, stdout.strip()
def check_cmd(self, args):
"""
Runs shell command on node.
:param list[str]|str args: command to run
:return: combined stdout and stderr
:rtype: str
:raises CoreCommandError: when a non-zero exit status occurs
"""
status, output = self.cmd_output(args)
if status:
raise CoreCommandError(status, args, output)
return output.strip()
def shcmd(self, cmdstr, sh="/bin/sh"):
return self.cmd([sh, "-c", cmdstr])
def sethwaddr(self, ifindex, addr):
"""
same as SimpleLxcNode.sethwaddr()
"""
self._netif[ifindex].sethwaddr(addr)
ifname = self.ifname(ifindex)
if self.up:
self.check_cmd([constants.IP_BIN, "link", "set", "dev", ifname, "address", str(addr)])
def addaddr(self, ifindex, addr):
"""
same as SimpleLxcNode.addaddr()
"""
if self.up:
self.check_cmd([constants.IP_BIN, "addr", "add", str(addr), "dev", self.ifname(ifindex)])
self._netif[ifindex].addaddr(addr)
def deladdr(self, ifindex, addr):
"""
same as SimpleLxcNode.deladdr()
"""
try:
self._netif[ifindex].deladdr(addr)
except ValueError:
logging.exception("trying to delete unknown address: %s", addr)
if self.up:
self.check_cmd([constants.IP_BIN, "addr", "del", str(addr), "dev", self.ifname(ifindex)])
def adoptnetif(self, netif, ifindex, hwaddr, addrlist):
"""
The broker builds a GreTap tunnel device to this physical node.
When a link message is received linking this node to another part of
the emulation, no new interface is created; instead, adopt the
GreTap netif as the node interface.
"""
netif.name = "gt%d" % ifindex
netif.node = self
self.addnetif(netif, ifindex)
# use a more reasonable name, e.g. "gt0" instead of "gt.56286.150"
if self.up:
self.check_cmd([constants.IP_BIN, "link", "set", "dev", netif.localname, "down"])
self.check_cmd([constants.IP_BIN, "link", "set", netif.localname, "name", netif.name])
netif.localname = netif.name
if hwaddr:
self.sethwaddr(ifindex, hwaddr)
for addr in utils.make_tuple(addrlist):
self.addaddr(ifindex, addr)
if self.up:
self.check_cmd([constants.IP_BIN, "link", "set", "dev", netif.localname, "up"])
def linkconfig(self, netif, bw=None, delay=None, loss=None, duplicate=None, jitter=None, netif2=None):
"""
Apply tc queing disciplines using LxBrNet.linkconfig()
"""
# borrow the tc qdisc commands from LxBrNet.linkconfig()
linux_bridge = LxBrNet(session=self.session, start=False)
linux_bridge.up = True
linux_bridge.linkconfig(netif, bw=bw, delay=delay, loss=loss, duplicate=duplicate, jitter=jitter, netif2=netif2)
del linux_bridge
def newifindex(self):
with self.lock:
while self.ifindex in self._netif:
self.ifindex += 1
ifindex = self.ifindex
self.ifindex += 1
return ifindex
def newnetif(self, net=None, addrlist=None, hwaddr=None, ifindex=None, ifname=None):
logging.info("creating interface")
if not addrlist:
addrlist = []
if self.up and net is None:
raise NotImplementedError
if ifindex is None:
ifindex = self.newifindex()
if self.up:
# 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
gt = self.session.broker.addnettunnel(net.objid)
if gt is None or len(gt) != 1:
raise ValueError("error building tunnel from adding a new network interface: %s" % gt)
gt = gt[0]
net.detach(gt)
self.adoptnetif(gt, ifindex, hwaddr, addrlist)
return ifindex
# this is reached when configuring services (self.up=False)
if ifname is None:
ifname = "gt%d" % ifindex
netif = GreTap(node=self, name=ifname, session=self.session, start=False)
self.adoptnetif(netif, ifindex, hwaddr, addrlist)
return ifindex
def privatedir(self, path):
if path[0] != "/":
raise ValueError("path not fully qualified: %s" % path)
hostpath = os.path.join(self.nodedir, os.path.normpath(path).strip('/').replace('/', '.'))
os.mkdir(hostpath)
self.mount(hostpath, path)
def mount(self, source, target):
source = os.path.abspath(source)
logging.info("mounting %s at %s", source, target)
os.makedirs(target)
self.check_cmd([constants.MOUNT_BIN, "--bind", source, target])
self._mounts.append((source, target))
def umount(self, target):
logging.info("unmounting '%s'" % target)
try:
self.check_cmd([constants.UMOUNT_BIN, "-l", target])
except CoreCommandError:
logging.exception("unmounting failed for %s", target)
def opennodefile(self, filename, mode="w"):
dirname, basename = os.path.split(filename)
if not basename:
raise ValueError("no basename for filename: " + filename)
if dirname and dirname[0] == "/":
dirname = dirname[1:]
dirname = dirname.replace("/", ".")
dirname = os.path.join(self.nodedir, dirname)
if not os.path.isdir(dirname):
os.makedirs(dirname, mode=0755)
hostfilename = os.path.join(dirname, basename)
return open(hostfilename, mode)
def nodefile(self, filename, contents, mode=0644):
with self.opennodefile(filename, "w") as node_file:
node_file.write(contents)
os.chmod(node_file.name, mode)
logging.info("created nodefile: '%s'; mode: 0%o", node_file.name, mode)

View file

View file

@ -4,19 +4,18 @@ sdt.py: Scripted Display Tool (SDT3D) helper
import logging
import socket
from urlparse import urlparse
from future.moves.urllib.parse import urlparse
from core import constants
from core.coreobj import PyCoreNet
from core.coreobj import PyCoreObj
from core.enumerations import EventTypes
from core.enumerations import LinkTlvs
from core.enumerations import LinkTypes
from core.enumerations import MessageFlags
from core.enumerations import MessageTypes
from core.enumerations import NodeTlvs
from core.enumerations import NodeTypes
from core.misc import nodeutils
from core.emulator.enumerations import EventTypes
from core.emulator.enumerations import LinkTlvs
from core.emulator.enumerations import LinkTypes
from core.emulator.enumerations import MessageFlags
from core.emulator.enumerations import MessageTypes
from core.emulator.enumerations import NodeTlvs
from core.emulator.enumerations import NodeTypes
from core.nodes import nodeutils
from core.nodes.base import NodeBase, CoreNetworkBase
# TODO: A named tuple may be more appropriate, than abusing a class dict like this
@ -321,29 +320,28 @@ class Sdt(object):
:return: nothing
"""
nets = []
with self.session._objects_lock:
for obj in self.session.objects.itervalues():
if isinstance(obj, PyCoreNet):
nets.append(obj)
if not isinstance(obj, PyCoreObj):
with self.session._nodes_lock:
for node_id in self.session.nodes:
node = self.session.nodes[node_id]
if isinstance(node, CoreNetworkBase):
nets.append(node)
if not isinstance(node, NodeBase):
continue
(x, y, z) = obj.getposition()
(x, y, z) = node.getposition()
if x is None or y is None:
continue
self.updatenode(obj.objid, MessageFlags.ADD.value, x, y, z,
obj.name, obj.type, obj.icon)
self.updatenode(node.id, MessageFlags.ADD.value, x, y, z, node.name, node.type, node.icon)
for nodenum in sorted(self.remotes.keys()):
r = self.remotes[nodenum]
x, y, z = r.pos
self.updatenode(nodenum, MessageFlags.ADD.value, x, y, z,
r.name, r.type, r.icon)
self.updatenode(nodenum, MessageFlags.ADD.value, x, y, z, r.name, r.type, r.icon)
for net in nets:
all_links = net.all_link_data(flags=MessageFlags.ADD.value)
for link_data in all_links:
is_wireless = nodeutils.is_node(net, (NodeTypes.WIRELESS_LAN, NodeTypes.EMANE))
wireless_link = link_data.message_type == LinkTypes.WIRELESS.value
if is_wireless and link_data.node1_id == net.objid:
if is_wireless and link_data.node1_id == net.id:
continue
self.updatelink(
@ -385,7 +383,7 @@ class Sdt(object):
# enabled prior to starting the session
if not self.is_enabled():
return False
# node.(objid, type, icon, name) are used.
# node.(_id, type, icon, name) are used.
nodenum = msg.get_tlv(NodeTlvs.NUMBER.value)
if not nodenum:
return
@ -411,11 +409,11 @@ class Sdt(object):
nodetype = None
try:
node = self.session.get_object(nodenum)
node = self.session.get_node(nodenum)
except KeyError:
node = None
if node:
self.updatenode(node.objid, msg.flags, x, y, z, node.name, node.type, node.icon)
self.updatenode(node.id, msg.flags, x, y, z, node.name, node.type, node.icon)
else:
if nodenum in self.remotes:
remote = self.remotes[nodenum]
@ -426,7 +424,7 @@ class Sdt(object):
if icon is None:
icon = remote.icon
else:
remote = Bunch(objid=nodenum, type=nodetype, icon=icon, name=name, net=net, links=set())
remote = Bunch(_id=nodenum, type=nodetype, icon=icon, name=name, net=net, links=set())
self.remotes[nodenum] = remote
remote.pos = (x, y, z)
self.updatenode(nodenum, msg.flags, x, y, z, name, nodetype, icon)
@ -472,7 +470,7 @@ class Sdt(object):
return True
else:
try:
n = self.session.get_object(nodenum)
n = self.session.get_node(nodenum)
except KeyError:
return False
if nodeutils.is_node(n, (NodeTypes.WIRELESS_LAN, NodeTypes.EMANE)):

View file

@ -6,7 +6,7 @@ __all__ is automatically loaded by the main core module.
"""
import os
from core.service import ServiceManager
from core.services.coreservices import ServiceManager
_PATH = os.path.abspath(os.path.dirname(__file__))

View file

@ -2,7 +2,7 @@
bird.py: defines routing services provided by the BIRD Internet Routing Daemon.
"""
from core.service import CoreService
from core.services.coreservices import CoreService
class Bird(CoreService):

View file

@ -7,18 +7,16 @@ a list of available services to the GUI and for configuring individual
services.
"""
import enum
import logging
import time
from multiprocessing.pool import ThreadPool
import enum
from core import CoreCommandError, utils
from core.constants import which
from core import CoreCommandError
from core.data import FileData
from core.enumerations import MessageFlags
from core.enumerations import RegisterTlvs
from core.misc import utils
from core.emulator.data import FileData
from core.emulator.enumerations import MessageFlags
from core.emulator.enumerations import RegisterTlvs
class ServiceBootError(Exception):
@ -58,10 +56,11 @@ class ServiceDependencies(object):
Generates the boot paths for the services provided to the class.
:return: list of services to boot, in order
:rtype: list[core.service.CoreService]
:rtype: list[core.coreservices.CoreService]
"""
paths = []
for service in self.node_services.itervalues():
for name in self.node_services:
service = self.node_services[name]
if service.name in self.booted:
logging.debug("skipping service that will already be booted: %s", service.name)
continue
@ -70,7 +69,7 @@ class ServiceDependencies(object):
if path:
paths.append(path)
if self.booted != set(self.node_services.iterkeys()):
if self.booted != set(self.node_services):
raise ValueError("failure to boot all services: %s != %s" % (self.booted, self.node_services.keys()))
return paths
@ -126,7 +125,7 @@ class ServiceShim(object):
Convert service properties into a string list of key=value pairs,
separated by "|".
:param core.netns.nodes.CoreNode node: node to get value list for
:param core.netns.vnode.CoreNode node: node to get value list for
:param CoreService service: service to get value list for
:return: value list string
:rtype: str
@ -318,7 +317,7 @@ class CoreServices(object):
logging.debug("checking for service with service manager: %s", name)
service = ServiceManager.get(name)
if not service:
logging.warn("default service %s is unknown", name)
logging.warning("default service %s is unknown", name)
else:
results.append(service)
return results
@ -374,9 +373,9 @@ class CoreServices(object):
logging.info("setting services for node(%s): %s", node.name, services)
for service_name in services:
service = self.get_service(node.objid, service_name, default_service=True)
service = self.get_service(node.id, service_name, default_service=True)
if not service:
logging.warn("unknown service(%s) for node(%s)", service_name, node.name)
logging.warning("unknown service(%s) for node(%s)", service_name, node.name)
continue
logging.info("adding service to node(%s): %s", node.name, service_name)
node.addservice(service)
@ -390,8 +389,10 @@ class CoreServices(object):
:rtype: list[tuple]
"""
configs = []
for node_id in self.custom_services.iterkeys():
for service in self.custom_services[node_id].itervalues():
for node_id in self.custom_services:
custom_services = self.custom_services[node_id]
for name in custom_services:
service = custom_services[name]
configs.append((node_id, service))
return configs
@ -462,15 +463,15 @@ class CoreServices(object):
:return: nothing
"""
logging.info("starting node(%s) service(%s) validation(%s)", node.name, service.name,
service.validation_mode.name)
service.validation_mode.name)
# create service directories
for directory in service.dirs:
try:
node.privatedir(directory)
except (CoreCommandError, ValueError) as e:
logging.warn("error mounting private dir '%s' for service '%s': %s",
directory, service.name, e)
logging.warning("error mounting private dir '%s' for service '%s': %s",
directory, service.name, e)
# create service files
self.create_service_files(node, service)
@ -521,7 +522,7 @@ class CoreServices(object):
src = src.split('\n')[0]
src = utils.expand_corepath(src, node.session, node)
# TODO: glob here
node.nodefilecopy(filename, src, mode=0644)
node.nodefilecopy(filename, src, mode=0o644)
return True
return False
@ -556,7 +557,7 @@ class CoreServices(object):
"""
Stop all services on a node.
:param core.netns.nodes.CoreNode node: node to stop services on
:param core.netns.vnode.CoreNode node: node to stop services on
:return: nothing
"""
for service in node.services:
@ -591,7 +592,7 @@ class CoreServices(object):
:return: file message for node
"""
# get service to get file from
service = self.get_service(node.objid, service_name, default_service=True)
service = self.get_service(node.id, service_name, default_service=True)
if not service:
raise ValueError("invalid service: %s", service_name)
@ -614,7 +615,7 @@ class CoreServices(object):
filetypestr = "service:%s" % service.name
return FileData(
message_type=MessageFlags.ADD.value,
node=node.objid,
node=node.id,
name=filename,
type=filetypestr,
data=data
@ -638,13 +639,13 @@ class CoreServices(object):
# retrieve custom service
service = self.get_service(node_id, service_name)
if service is None:
logging.warn("received file name for unknown service: %s", service_name)
logging.warning("received file name for unknown service: %s", service_name)
return
# validate file being set is valid
config_files = service.configs
if file_name not in config_files:
logging.warn("received unknown file(%s) for service(%s)", file_name, service_name)
logging.warning("received unknown file(%s) for service(%s)", file_name, service_name)
return
# set custom service file data

View file

@ -99,8 +99,8 @@ Limitations:
import logging
from core.service import CoreService
from core.service import ServiceManager
from core.services.coreservices import CoreService
from core.services.coreservices import ServiceManager
try:
from docker import Client

View file

@ -1,6 +1,6 @@
from core.enumerations import NodeTypes
from core.misc import nodeutils
from core.service import CoreService
from core.emulator.enumerations import NodeTypes
from core.nodes import nodeutils
from core.services.coreservices import CoreService
from core.xml import emanexml
@ -21,9 +21,9 @@ class EmaneTransportService(CoreService):
if filename == cls.configs[0]:
transport_commands = []
for interface in node.netifs(sort=True):
network_node = node.session.get_object(interface.net.objid)
network_node = node.session.get_node(interface.net.id)
if nodeutils.is_node(network_node, NodeTypes.EMANE):
config = node.session.emane.get_configs(network_node.objid, network_node.model.name)
config = node.session.emane.get_configs(network_node.id, network_node.model.name)
if config and emanexml.is_external(config):
nem_id = network_node.getnemid(interface)
command = "emanetransportd -r -l 0 -d ../transportdaemon%s.xml" % nem_id
@ -32,6 +32,6 @@ class EmaneTransportService(CoreService):
return """
emanegentransportxml -o ../ ../platform%s.xml
%s
""" % (node.objid, transport_commands)
""" % (node.id, transport_commands)
else:
raise ValueError

View file

@ -4,10 +4,9 @@ Assumes installation of FRR via https://deb.frrouting.org/
"""
from core import constants
from core.enumerations import LinkTypes, NodeTypes
from core.misc import ipaddress
from core.misc import nodeutils
from core.service import CoreService
from core.emulator.enumerations import LinkTypes, NodeTypes
from core.nodes import nodeutils, ipaddress
from core.services.coreservices import CoreService
class FRRZebra(CoreService):
@ -525,7 +524,7 @@ class FRRBgp(FrrService):
cfg = "!\n! BGP configuration\n!\n"
cfg += "! You should configure the AS number below,\n"
cfg += "! along with this router's peers.\n!\n"
cfg += "router bgp %s\n" % node.objid
cfg += "router bgp %s\n" % node.id
rtrid = cls.routerid(node)
cfg += " bgp router-id %s\n" % rtrid
cfg += " redistribute connected\n"

View file

@ -3,9 +3,9 @@ nrl.py: defines services provided by NRL protolib tools hosted here:
http://www.nrl.navy.mil/itd/ncs/products
"""
from core.misc import utils
from core.misc.ipaddress import Ipv4Prefix
from core.service import CoreService
from core import utils
from core.nodes.ipaddress import Ipv4Prefix
from core.services.coreservices import CoreService
class NrlService(CoreService):

View file

@ -3,10 +3,9 @@ quagga.py: defines routing services provided by Quagga.
"""
from core import constants
from core.enumerations import LinkTypes, NodeTypes
from core.misc import ipaddress
from core.misc import nodeutils
from core.service import CoreService
from core.emulator.enumerations import LinkTypes, NodeTypes
from core.nodes import nodeutils, ipaddress
from core.services.coreservices import CoreService
class Zebra(CoreService):
@ -474,7 +473,7 @@ class Bgp(QuaggaService):
cfg = "!\n! BGP configuration\n!\n"
cfg += "! You should configure the AS number below,\n"
cfg += "! along with this router's peers.\n!\n"
cfg += "router bgp %s\n" % node.objid
cfg += "router bgp %s\n" % node.id
rtrid = cls.routerid(node)
cfg += " bgp router-id %s\n" % rtrid
cfg += " redistribute connected\n"

View file

@ -4,7 +4,7 @@ sdn.py defines services to start Open vSwitch and the Ryu SDN Controller.
import re
from core.service import CoreService
from core.services.coreservices import CoreService
class SdnService(CoreService):

View file

@ -6,7 +6,7 @@ firewall)
import logging
from core import constants
from core.service import CoreService
from core.services.coreservices import CoreService
class VPNClient(CoreService):

View file

@ -2,7 +2,7 @@
ucarp.py: defines high-availability IP address controlled by ucarp
"""
from core.service import CoreService
from core.services.coreservices import CoreService
UCARP_ETC = "/usr/local/etc/ucarp"

View file

@ -4,12 +4,11 @@ utility.py: defines miscellaneous utility services.
import os
from core import CoreCommandError
from core import CoreCommandError, utils
from core import constants
from core.misc import utils
from core.misc.ipaddress import Ipv4Prefix
from core.misc.ipaddress import Ipv6Prefix
from core.service import CoreService
from core.nodes.ipaddress import Ipv4Prefix
from core.nodes.ipaddress import Ipv6Prefix
from core.services.coreservices import CoreService
class UtilService(CoreService):

View file

@ -4,7 +4,7 @@ xorp.py: defines routing services provided by the XORP routing suite.
import logging
from core.service import CoreService
from core.services.coreservices import CoreService
class XorpRtrmgr(CoreService):

File diff suppressed because it is too large Load diff

View file

@ -2,6 +2,7 @@
Miscellaneous utility functions, wrappers around some subprocess procedures.
"""
import fcntl
import importlib
import inspect
import logging
@ -9,8 +10,7 @@ import os
import shlex
import subprocess
import sys
import fcntl
from past.builtins import basestring
from core import CoreCommandError
@ -126,7 +126,7 @@ def make_tuple_fromstr(s, value_type):
"""
Create a tuple from a string.
:param str|unicode s: string to convert to a tuple
:param str s: string to convert to a tuple
:param value_type: type of values to be contained within tuple
:return: tuple from string
:rtype: tuple
@ -148,7 +148,9 @@ def split_args(args):
:return: shell-like syntax list
:rtype: list
"""
logging.info("split args: %s - %s", args, type(args))
if isinstance(args, basestring):
logging.info("splitting args")
args = shlex.split(args)
return args
@ -205,7 +207,7 @@ def cmd_output(args):
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout, _ = p.communicate()
status = p.wait()
return status, stdout.strip()
return status, stdout.decode("utf-8").strip()
except OSError:
raise CoreCommandError(-1, args)
@ -231,7 +233,7 @@ def check_cmd(args, **kwargs):
status = p.wait()
if status != 0:
raise CoreCommandError(status, args, stdout)
return stdout.strip()
return stdout.decode("utf-8").strip()
except OSError:
raise CoreCommandError(-1, args)
@ -252,8 +254,7 @@ def hex_dump(s, bytes_per_word=2, words_per_line=8):
while s:
line = s[:total_bytes]
s = s[total_bytes:]
tmp = map(lambda x: ("%02x" * bytes_per_word) % x,
zip(*[iter(map(ord, line))] * bytes_per_word))
tmp = map(lambda x: ("%02x" * bytes_per_word) % x, zip(*[iter(map(ord, line))] * bytes_per_word))
if len(line) % 2:
tmp.append("%x" % ord(line[-1]))
dump += "0x%08x: %s\n" % (count, " ".join(tmp))
@ -324,7 +325,7 @@ def expand_corepath(pathname, session=None, node=None):
pathname = pathname.replace("%SESSION_USER%", session.user)
if node is not None:
pathname = pathname.replace("%NODE%", str(node.objid))
pathname = pathname.replace("%NODE%", str(node.id))
pathname = pathname.replace("%NODENAME%", node.name)
return pathname
@ -376,7 +377,7 @@ def load_classes(path, clazz):
# validate path exists
logging.debug("attempting to load modules from path: %s", path)
if not os.path.isdir(path):
logging.warn("invalid custom module directory specified" ": %s" % path)
logging.warning("invalid custom module directory specified" ": %s" % path)
# check if path is in sys.path
parent_path = os.path.dirname(path)
if parent_path not in sys.path:

View file

@ -1,20 +1,20 @@
import logging
from core.nodes.base import CoreNetworkBase
from lxml import etree
from core import coreobj
import core.nodes.base
import core.nodes.physical
from core.emulator.emudata import InterfaceData
from core.emulator.emudata import LinkOptions
from core.emulator.emudata import NodeOptions
from core.enumerations import NodeTypes
from core.misc import nodeutils
from core.misc.ipaddress import MacAddress
from core.netns import nodes
from core.emulator.enumerations import NodeTypes
from core.nodes import nodeutils
from core.nodes.ipaddress import MacAddress
def write_xml_file(xml_element, file_path, doctype=None):
xml_data = etree.tostring(xml_element, xml_declaration=True, pretty_print=True, encoding="UTF-8", doctype=doctype)
with open(file_path, "w") as xml_file:
with open(file_path, "wb") as xml_file:
xml_file.write(xml_data)
@ -103,7 +103,7 @@ class NodeElement(object):
self.session = session
self.node = node
self.element = etree.Element(element_name)
add_attribute(self.element, "id", node.objid)
add_attribute(self.element, "id", node.id)
add_attribute(self.element, "name", node.name)
add_attribute(self.element, "icon", node.icon)
add_attribute(self.element, "canvas", node.canvas)
@ -149,7 +149,8 @@ class ServiceElement(object):
def add_files(self):
# get custom files
file_elements = etree.Element("files")
for file_name, data in self.service.config_data.iteritems():
for file_name in self.service.config_data:
data = self.service.config_data[file_name]
file_element = etree.SubElement(file_elements, "file")
add_attribute(file_element, "name", file_name)
file_element.text = data
@ -292,7 +293,9 @@ class CoreXmlWriter(object):
if not options_config:
return
for _id, default_value in self.session.options.default_values().iteritems():
default_options = self.session.options.default_values()
for _id in default_options:
default_value = default_options[_id]
# TODO: should we just save the current config regardless, since it may change?
value = options_config[_id]
if value != default_value:
@ -308,7 +311,8 @@ class CoreXmlWriter(object):
if not config:
return
for _id, value in config.iteritems():
for _id in config:
value = config[_id]
add_configuration(metadata_elements, _id, value)
if metadata_elements.getchildren():
@ -321,7 +325,8 @@ class CoreXmlWriter(object):
if not all_configs:
continue
for model_name, config in all_configs.iteritems():
for model_name in all_configs:
config = all_configs[model_name]
logging.info("writing emane config node(%s) model(%s)", node_id, model_name)
if model_name == -1:
emane_configuration = create_emane_config(node_id, self.session.emane.emane_config, config)
@ -340,12 +345,14 @@ class CoreXmlWriter(object):
if not all_configs:
continue
for model_name, config in all_configs.iteritems():
for model_name in all_configs:
config = all_configs[model_name]
logging.info("writing mobility config node(%s) model(%s)", node_id, model_name)
mobility_configuration = etree.SubElement(mobility_configurations, "mobility_configuration")
add_attribute(mobility_configuration, "node", node_id)
add_attribute(mobility_configuration, "model", model_name)
for name, value in config.iteritems():
for name in config:
value = config[name]
add_configuration(mobility_configuration, name, value)
if mobility_configurations.getchildren():
@ -364,7 +371,8 @@ class CoreXmlWriter(object):
def write_default_services(self):
node_types = etree.Element("default_services")
for node_type, services in self.session.services.default_services.iteritems():
for node_type in self.session.services.default_services:
services = self.session.services.default_services[node_type]
node_type = etree.SubElement(node_types, "node", type=node_type)
for service in services:
etree.SubElement(node_type, "service", name=service)
@ -377,13 +385,18 @@ class CoreXmlWriter(object):
self.devices = etree.SubElement(self.scenario, "devices")
links = []
for node in self.session.objects.itervalues():
for node_id in self.session.nodes:
node = self.session.nodes[node_id]
# network node
if isinstance(node, (coreobj.PyCoreNet, nodes.RJ45Node)) and not nodeutils.is_node(node, NodeTypes.CONTROL_NET):
is_network_or_rj45 = isinstance(node, (core.nodes.base.CoreNetworkBase, core.nodes.physical.Rj45Node))
is_controlnet = nodeutils.is_node(node, NodeTypes.CONTROL_NET)
if is_network_or_rj45 and not is_controlnet:
self.write_network(node)
# device node
elif isinstance(node, nodes.PyCoreNode):
elif isinstance(node, core.nodes.base.CoreNodeBase):
self.write_device(node)
else:
logging.error("unknown node: %s", node)
# add known links
links.extend(node.all_link_data(0))
@ -393,16 +406,9 @@ class CoreXmlWriter(object):
def write_network(self, node):
# ignore p2p and other nodes that are not part of the api
if not node.apitype:
logging.warning("ignoring node with no apitype: %s", node)
return
# ignore nodes tied to a different network
if nodeutils.is_node(node, (NodeTypes.SWITCH, NodeTypes.HUB)):
for netif in node.netifs(sort=True):
othernet = getattr(netif, "othernet", None)
if othernet and othernet.objid != node.objid:
logging.info("writer ignoring node(%s) othernet(%s)", node.name, othernet.name)
return
network = NetworkElement(self.session, node)
self.networks.append(network.element)
@ -424,6 +430,29 @@ class CoreXmlWriter(object):
device = DeviceElement(self.session, node)
self.devices.append(device.element)
def create_interface_element(self, element_name, node_id, interface_id, mac, ip4, ip4_mask, ip6, ip6_mask):
interface = etree.Element(element_name)
node = self.session.get_node(node_id)
interface_name = None
if not isinstance(node, CoreNetworkBase):
node_interface = node.netif(interface_id)
interface_name = node_interface.name
# check if emane interface
if nodeutils.is_node(node_interface.net, NodeTypes.EMANE):
nem = node_interface.net.getnemid(node_interface)
add_attribute(interface, "nem", nem)
add_attribute(interface, "id", interface_id)
add_attribute(interface, "name", interface_name)
add_attribute(interface, "mac", mac)
add_attribute(interface, "ip4", ip4)
add_attribute(interface, "ip4_mask", ip4_mask)
add_attribute(interface, "ip6", ip6)
add_attribute(interface, "ip6_mask", ip6_mask)
return interface
def create_link_element(self, link_data):
link_element = etree.Element("link")
add_attribute(link_element, "node_one", link_data.node1_id)
@ -431,44 +460,30 @@ class CoreXmlWriter(object):
# check for interface one
if link_data.interface1_id is not None:
interface_one = etree.Element("interface_one")
node = self.session.get_object(link_data.node1_id)
node_interface = node.netif(link_data.interface1_id)
add_attribute(interface_one, "id", link_data.interface1_id)
add_attribute(interface_one, "name", node_interface.name)
add_attribute(interface_one, "mac", link_data.interface1_mac)
add_attribute(interface_one, "ip4", link_data.interface1_ip4)
add_attribute(interface_one, "ip4_mask", link_data.interface1_ip4_mask)
add_attribute(interface_one, "ip6", link_data.interface1_ip6)
add_attribute(interface_one, "ip6_mask", link_data.interface1_ip6_mask)
# check if emane interface
if nodeutils.is_node(node_interface.net, NodeTypes.EMANE):
nem = node_interface.net.getnemid(node_interface)
add_attribute(interface_one, "nem", nem)
interface_one = self.create_interface_element(
"interface_one",
link_data.node1_id,
link_data.interface1_id,
link_data.interface1_mac,
link_data.interface1_ip4,
link_data.interface1_ip4_mask,
link_data.interface1_ip6,
link_data.interface1_ip6_mask
)
link_element.append(interface_one)
# check for interface two
if link_data.interface2_id is not None:
interface_two = etree.Element("interface_two")
node = self.session.get_object(link_data.node2_id)
node_interface = node.netif(link_data.interface2_id)
add_attribute(interface_two, "id", link_data.interface2_id)
add_attribute(interface_two, "name", node_interface.name)
add_attribute(interface_two, "mac", link_data.interface2_mac)
add_attribute(interface_two, "ip4", link_data.interface2_ip4)
add_attribute(interface_two, "ip4_mask", link_data.interface2_ip4_mask)
add_attribute(interface_two, "ip6", link_data.interface2_ip6)
add_attribute(interface_two, "ip6_mask", link_data.interface2_ip6_mask)
# check if emane interface
if nodeutils.is_node(node_interface.net, NodeTypes.EMANE):
nem = node_interface.net.getnemid(node_interface)
add_attribute(interface_two, "nem", nem)
interface_two = self.create_interface_element(
"interface_two",
link_data.node2_id,
link_data.interface2_id,
link_data.interface2_mac,
link_data.interface2_ip4,
link_data.interface2_ip4_mask,
link_data.interface2_ip6,
link_data.interface2_ip6_mask
)
link_element.append(interface_two)
# check for options
@ -699,8 +714,8 @@ class CoreXmlReader(object):
position_element = device_element.find("position")
if position_element is not None:
x = get_float(position_element, "x")
y = get_float(position_element, "y")
x = get_int(position_element, "x")
y = get_int(position_element, "y")
if all([x, y]):
node_options.set_position(x, y)
@ -721,8 +736,8 @@ class CoreXmlReader(object):
position_element = network_element.find("position")
if position_element is not None:
x = get_float(position_element, "x")
y = get_float(position_element, "y")
x = get_int(position_element, "x")
y = get_int(position_element, "y")
if all([x, y]):
node_options.set_position(x, y)

View file

@ -3,10 +3,10 @@ import socket
from lxml import etree
from core import constants
from core.coreobj import PyCoreNode
from core.enumerations import NodeTypes
from core.misc import utils, nodeutils, ipaddress
from core import constants, utils
from core.nodes.base import CoreNodeBase
from core.emulator.enumerations import NodeTypes
from core.nodes import nodeutils, ipaddress
def add_type(parent_element, name):
@ -100,8 +100,9 @@ class CoreXmlDeployment(object):
# servers = self.session.broker.getservernames()
# servers.remove("localhost")
for node in self.session.objects.itervalues():
if isinstance(node, PyCoreNode):
for node_id in self.session.nodes:
node = self.session.nodes[node_id]
if isinstance(node, CoreNodeBase):
self.add_virtual_host(physical_host, node)
def add_physical_host(self, name):
@ -119,7 +120,7 @@ class CoreXmlDeployment(object):
return host_element
def add_virtual_host(self, physical_host, node):
if not isinstance(node, PyCoreNode):
if not isinstance(node, CoreNodeBase):
raise TypeError("invalid node type: %s" % node)
# create virtual host element

View file

@ -3,8 +3,8 @@ import os
from lxml import etree
from core.misc import utils
from core.misc.ipaddress import MacAddress
from core import utils
from core.nodes.ipaddress import MacAddress
from core.xml import corexml
_hwaddr_prefix = "02:02"
@ -101,7 +101,7 @@ def build_node_platform_xml(emane_manager, control_net, node, nem_id, platform_x
Create platform xml for a specific node.
:param core.emane.emanemanager.EmaneManager emane_manager: emane manager with emane configurations
:param core.netns.nodes.CtrlNet control_net: control net node for this emane network
:param core.nodes.network.CtrlNet control_net: control net node for this emane network
:param core.emane.nodes.EmaneNode node: node to write platform xml for
:param int nem_id: nem id to use for interfaces for this node
:param dict platform_xmls: stores platform xml elements to append nem entries to
@ -112,7 +112,7 @@ def build_node_platform_xml(emane_manager, control_net, node, nem_id, platform_x
nem_entries = {}
if node.model is None:
logging.warn("warning: EmaneNode %s has no associated model", node.name)
logging.warning("warning: EmaneNode %s has no associated model", node.name)
return nem_entries
for netif in node.netifs():
@ -121,7 +121,7 @@ def build_node_platform_xml(emane_manager, control_net, node, nem_id, platform_x
nem_element = etree.Element("nem", id=str(nem_id), name=netif.localname, definition=nem_definition)
# check if this is an external transport, get default config if an interface specific one does not exist
config = emane_manager.getifcconfig(node.model.object_id, netif, node.model.name)
config = emane_manager.getifcconfig(node.model.id, netif, node.model.name)
if is_external(config):
nem_element.set("transport", "external")
@ -135,7 +135,7 @@ def build_node_platform_xml(emane_manager, control_net, node, nem_id, platform_x
if not transport_type:
logging.info("warning: %s interface type unsupported!", netif.name)
transport_type = "raw"
transport_file = transport_file_name(node.objid, transport_type)
transport_file = transport_file_name(node.id, transport_type)
transport_element = etree.SubElement(nem_element, "transport", definition=transport_file)
# add transport parameter
@ -145,7 +145,7 @@ def build_node_platform_xml(emane_manager, control_net, node, nem_id, platform_x
nem_entries[netif] = nem_element
# merging code
key = netif.node.objid
key = netif.node.id
if netif.transport_type == "raw":
key = "host"
otadev = control_net.brname
@ -214,7 +214,7 @@ def build_xml_files(emane_manager, node):
return
# get model configurations
config = emane_manager.get_configs(node.model.object_id, node.model.name)
config = emane_manager.get_configs(node.model.id, node.model.name)
if not config:
return
@ -229,7 +229,7 @@ def build_xml_files(emane_manager, node):
for netif in node.netifs():
# check for interface specific emane configuration and write xml files, if needed
config = emane_manager.getifcconfig(node.model.object_id, netif, node.model.name)
config = emane_manager.getifcconfig(node.model.id, netif, node.model.name)
if config:
node.model.build_xml_files(config, netif)
@ -267,7 +267,7 @@ def build_transport_xml(emane_manager, node, transport_type):
add_param(transport_element, "bitrate", "0")
# get emane model cnfiguration
config = emane_manager.get_configs(node.objid, node.model.name)
config = emane_manager.get_configs(node.id, node.model.name)
flowcontrol = config.get("flowcontrolenable", "0") == "1"
if "virtual" in transport_type.lower():
@ -280,7 +280,7 @@ def build_transport_xml(emane_manager, node, transport_type):
add_param(transport_element, "flowcontrolenable", "on")
doc_name = "transport"
file_name = transport_file_name(node.objid, transport_type)
file_name = transport_file_name(node.id, transport_type)
file_path = os.path.join(emane_manager.session.session_dir, file_name)
create_file(transport_element, doc_name, file_path)
@ -379,10 +379,10 @@ def _basename(emane_model, interface=None):
:return: basename used for file creation
:rtype: str
"""
name = "n%s" % emane_model.object_id
name = "n%s" % emane_model.id
if interface:
node_id = interface.node.objid
node_id = interface.node.id
if emane_model.session.emane.getifcconfig(node_id, interface, emane_model.name):
name = interface.localname.replace(".", "_")

View file

@ -14,7 +14,7 @@
}
},
"root": {
"level": "INFO",
"level": "DEBUG",
"handlers": ["console"]
}
}

View file

@ -3,13 +3,14 @@
# Example CORE Python script that attaches N nodes to an EMANE 802.11abg network.
import datetime
from builtins import range
import parser
from core import load_logging_config
from core.emane.ieee80211abg import EmaneIeee80211abgModel
from core.emulator.coreemu import CoreEmu
from core.emulator.emudata import IpPrefixes
from core.enumerations import EventTypes
from core.emulator.enumerations import EventTypes
load_logging_config()
@ -33,17 +34,17 @@ def example(options):
emane_network.setposition(x=80, y=50)
# create nodes
for i in xrange(options.nodes):
for i in range(options.nodes):
node = session.create_wireless_node()
node.setposition(x=150 * (i + 1), y=150)
interface = prefixes.create_interface(node)
session.add_link(node.objid, emane_network.objid, interface_one=interface)
session.add_link(node.id, emane_network.id, interface_one=interface)
# instantiate session
session.instantiate()
# start a shell on the first node
node = session.get_object(2)
node = session.get_node(2)
node.client.term("bash")
# shutdown session
@ -54,9 +55,9 @@ def example(options):
def main():
options = parser.parse_options("emane80211")
start = datetime.datetime.now()
print "running emane 80211 example: nodes(%s) time(%s)" % (options.nodes, options.time)
print("running emane 80211 example: nodes(%s) time(%s)" % (options.nodes, options.time))
example(options)
print "elapsed time: %s" % (datetime.datetime.now() - start)
print("elapsed time: %s" % (datetime.datetime.now() - start))
if __name__ == "__main__" or __name__ == "__builtin__":

View file

@ -6,12 +6,13 @@
# nodestep
import datetime
from builtins import range
import parser
from core import load_logging_config
from core.emulator.coreemu import CoreEmu
from core.emulator.emudata import IpPrefixes
from core.enumerations import NodeTypes, EventTypes
from core.emulator.enumerations import NodeTypes, EventTypes
load_logging_config()
@ -31,22 +32,22 @@ def example(options):
switch = session.add_node(_type=NodeTypes.SWITCH)
# create nodes
for _ in xrange(options.nodes):
for _ in range(options.nodes):
node = session.add_node()
interface = prefixes.create_interface(node)
session.add_link(node.objid, switch.objid, interface_one=interface)
session.add_link(node.id, switch.id, interface_one=interface)
# instantiate session
session.instantiate()
# get nodes to run example
first_node = session.get_object(2)
last_node = session.get_object(options.nodes + 1)
first_node = session.get_node(2)
last_node = session.get_node(options.nodes + 1)
print "starting iperf server on node: %s" % first_node.name
print("starting iperf server on node: %s" % first_node.name)
first_node.cmd(["iperf", "-s", "-D"])
first_node_address = prefixes.ip4_address(first_node)
print "node %s connecting to %s" % (last_node.name, first_node_address)
print("node %s connecting to %s" % (last_node.name, first_node_address))
last_node.client.icmd(["iperf", "-t", str(options.time), "-c", first_node_address])
first_node.cmd(["killall", "-9", "iperf"])
@ -58,9 +59,9 @@ def main():
options = parser.parse_options("switch")
start = datetime.datetime.now()
print "running switch example: nodes(%s) time(%s)" % (options.nodes, options.time)
print("running switch example: nodes(%s) time(%s)" % (options.nodes, options.time))
example(options)
print "elapsed time: %s" % (datetime.datetime.now() - start)
print("elapsed time: %s" % (datetime.datetime.now() - start))
if __name__ == "__main__":

View file

@ -4,9 +4,11 @@
# n nodes are connected to a virtual wlan; run test for testsec
# and repeat for minnodes <= n <= maxnodes with a step size of
# nodestep
from builtins import range
from core import load_logging_config
from core.emulator.emudata import IpPrefixes
from core.enumerations import NodeTypes, EventTypes
from core.emulator.enumerations import NodeTypes, EventTypes
load_logging_config()
@ -26,10 +28,10 @@ def example(nodes):
switch = session.add_node(_type=NodeTypes.SWITCH)
# create nodes
for _ in xrange(nodes):
for _ in range(nodes):
node = session.add_node()
interface = prefixes.create_interface(node)
session.add_link(node.objid, switch.objid, interface_one=interface)
session.add_link(node.id, switch.id, interface_one=interface)
# instantiate session
session.instantiate()

View file

@ -6,13 +6,14 @@
# nodestep
import datetime
from builtins import range
import parser
from core import load_logging_config
from core.emulator.coreemu import CoreEmu
from core.emulator.emudata import IpPrefixes, NodeOptions
from core.enumerations import NodeTypes, EventTypes
from core.mobility import BasicRangeModel
from core.emulator.enumerations import NodeTypes, EventTypes
from core.location.mobility import BasicRangeModel
load_logging_config()
@ -35,22 +36,22 @@ def example(options):
# create nodes, must set a position for wlan basic range model
node_options = NodeOptions()
node_options.set_position(0, 0)
for _ in xrange(options.nodes):
for _ in range(options.nodes):
node = session.add_node(node_options=node_options)
interface = prefixes.create_interface(node)
session.add_link(node.objid, wlan.objid, interface_one=interface)
session.add_link(node.id, wlan.id, interface_one=interface)
# instantiate session
session.instantiate()
# get nodes for example run
first_node = session.get_object(2)
last_node = session.get_object(options.nodes + 1)
first_node = session.get_node(2)
last_node = session.get_node(options.nodes + 1)
print "starting iperf server on node: %s" % first_node.name
print("starting iperf server on node: %s" % first_node.name)
first_node.cmd(["iperf", "-s", "-D"])
address = prefixes.ip4_address(first_node)
print "node %s connecting to %s" % (last_node.name, address)
print("node %s connecting to %s" % (last_node.name, address))
last_node.client.icmd(["iperf", "-t", str(options.time), "-c", address])
first_node.cmd(["killall", "-9", "iperf"])
@ -62,9 +63,9 @@ def main():
options = parser.parse_options("wlan")
start = datetime.datetime.now()
print "running wlan example: nodes(%s) time(%s)" % (options.nodes, options.time)
print("running wlan example: nodes(%s) time(%s)" % (options.nodes, options.time))
example(options)
print "elapsed time: %s" % (datetime.datetime.now() - start)
print("elapsed time: %s" % (datetime.datetime.now() - start))
if __name__ == "__main__":

View file

@ -1,7 +1,7 @@
import logging
import time
from core.misc.event import EventLoop
from core.location.event import EventLoop
def main():

View file

@ -1,7 +1,7 @@
import logging
from builtins import range
from core.grpc import client
from core.grpc import core_pb2
from core.api.grpc import client, core_pb2
def log_event(event):
@ -33,7 +33,7 @@ def main():
# helper to create interfaces
interface_helper = client.InterfaceHelper(ip4_prefix="10.83.0.0/16")
for i in xrange(2):
for i in range(2):
# create node
position = core_pb2.Position(x=50 + 50 * i, y=50)
node = core_pb2.Node(position=position)

View file

@ -2,8 +2,8 @@
Sample user-defined service.
"""
from core.service import CoreService
from core.service import ServiceMode
from core.services.coreservices import CoreService
from core.services.coreservices import ServiceMode
## Custom CORE Service

View file

@ -13,25 +13,25 @@
import datetime
import optparse
import sys
from builtins import range
from core.api import coreapi
from core.api import dataconversion
from core.api.coreapi import CoreExecuteTlv
from core.enumerations import CORE_API_PORT
from core.enumerations import EventTlvs
from core.enumerations import EventTypes
from core.enumerations import ExecuteTlvs
from core.enumerations import LinkTlvs
from core.enumerations import LinkTypes
from core.enumerations import MessageFlags
from core.enumerations import MessageTypes
from core.misc import ipaddress
from core.netns import nodes
import core.nodes.base
import core.nodes.network
from core.api.tlv import coreapi, dataconversion
from core.api.tlv.coreapi import CoreExecuteTlv
from core.emulator.enumerations import CORE_API_PORT
from core.emulator.enumerations import EventTlvs
from core.emulator.enumerations import EventTypes
from core.emulator.enumerations import ExecuteTlvs
from core.emulator.enumerations import LinkTlvs
from core.emulator.enumerations import LinkTypes
from core.emulator.enumerations import MessageFlags
from core.emulator.enumerations import MessageTypes
from core.emulator.session import Session
from core.nodes import ipaddress
# declare classes for use with Broker
from core.session import Session
# node list (count from 1)
n = [None]
exec_num = 1
@ -46,7 +46,7 @@ def cmd(node, exec_cmd):
global exec_num
# Set up the command api message
tlvdata = CoreExecuteTlv.pack(ExecuteTlvs.NODE.value, node.objid)
tlvdata = CoreExecuteTlv.pack(ExecuteTlvs.NODE.value, node.id)
tlvdata += CoreExecuteTlv.pack(ExecuteTlvs.NUMBER.value, exec_num)
tlvdata += CoreExecuteTlv.pack(ExecuteTlvs.COMMAND.value, exec_cmd)
msg = coreapi.CoreExecMessage.pack(MessageFlags.STRING.value | MessageFlags.TEXT.value, tlvdata)
@ -65,7 +65,7 @@ def cmd(node, exec_cmd):
msgdata = server.sock.recv(msglen)
# If we get the right response return the results
print "received response message: %s" % MessageTypes(msgtype)
print("received response message: %s" % MessageTypes(msgtype))
if msgtype == MessageTypes.EXECUTE.value:
msg = coreapi.CoreExecMessage(msgflags, msghdr, msgdata)
result = msg.get_tlv(ExecuteTlvs.RESULT.value)
@ -120,7 +120,7 @@ def main():
port = int(daemonport[1])
else:
port = CORE_API_PORT
print "connecting to daemon at %s:%d" % (daemon, port)
print("connecting to daemon at %s:%d" % (daemon, port))
session.broker.addserver(daemon, daemonip, port)
# Set the local session id to match the port.
@ -136,7 +136,7 @@ def main():
session.broker.handlerawmsg(coreapi.CoreEventMessage.pack(0, tlvdata))
flags = MessageFlags.ADD.value
switch = nodes.SwitchNode(session=session, name="switch", start=False)
switch = core.nodes.network.SwitchNode(session=session, name="switch", start=False)
switch.setposition(x=80, y=50)
switch.server = daemon
switch_data = switch.data(flags)
@ -145,11 +145,11 @@ def main():
number_of_nodes = options.numnodes
print "creating %d remote nodes with addresses from %s" % (options.numnodes, prefix)
print("creating %d remote nodes with addresses from %s" % (options.numnodes, prefix))
# create remote nodes via API
for i in xrange(1, number_of_nodes + 1):
node = nodes.CoreNode(session=session, objid=i, name="n%d" % i, start=False)
for i in range(1, number_of_nodes + 1):
node = core.nodes.base.CoreNode(session=session, _id=i, name="n%d" % i, start=False)
node.setposition(x=150 * i, y=150)
node.server = daemon
node_data = node.data(flags)
@ -158,8 +158,8 @@ def main():
n.append(node)
# create remote links via API
for i in xrange(1, number_of_nodes + 1):
tlvdata = coreapi.CoreLinkTlv.pack(LinkTlvs.N1_NUMBER.value, switch.objid)
for i in range(1, number_of_nodes + 1):
tlvdata = coreapi.CoreLinkTlv.pack(LinkTlvs.N1_NUMBER.value, switch.id)
tlvdata += coreapi.CoreLinkTlv.pack(LinkTlvs.N2_NUMBER.value, i)
tlvdata += coreapi.CoreLinkTlv.pack(LinkTlvs.TYPE.value, LinkTypes.WIRED.value)
tlvdata += coreapi.CoreLinkTlv.pack(LinkTlvs.INTERFACE2_NUMBER.value, 0)
@ -175,13 +175,11 @@ def main():
session.broker.handlerawmsg(msg)
# Get the ip or last node and ping it from the first
print "Pinging from the first to the last node"
print("Pinging from the first to the last node")
pingip = cmd(n[-1], "ip -4 -o addr show dev eth0").split()[3].split("/")[0]
print cmd(n[1], "ping -c 5 " + pingip)
print "elapsed time: %s" % (datetime.datetime.now() - start)
print "To stop this session, use the core-cleanup script on the remote daemon server."
print(cmd(n[1], "ping -c 5 " + pingip))
print("elapsed time: %s" % (datetime.datetime.now() - start))
print("To stop this session, use the core-cleanup script on the remote daemon server.")
raw_input("press enter to exit")

View file

@ -12,13 +12,15 @@
import datetime
import optparse
import sys
from builtins import range
import core.nodes.base
import core.nodes.network
from core import constants
from core.api import coreapi, dataconversion
from core.enumerations import CORE_API_PORT, EventTypes, EventTlvs, LinkTlvs, LinkTypes, MessageFlags
from core.misc import ipaddress
from core.netns import nodes
from core.session import Session
from core.api.tlv import coreapi, dataconversion
from core.emulator.enumerations import CORE_API_PORT, EventTypes, EventTlvs, LinkTlvs, LinkTypes, MessageFlags
from core.emulator.session import Session
from core.nodes import ipaddress
# node list (count from 1)
n = [None]
@ -66,21 +68,21 @@ def main():
port = int(slaveport[1])
else:
port = CORE_API_PORT
print "connecting to slave at %s:%d" % (slave, port)
print("connecting to slave at %s:%d" % (slave, port))
session.broker.addserver(slave, slave, port)
session.broker.setupserver(slave)
session.set_state(EventTypes.CONFIGURATION_STATE)
tlvdata = coreapi.CoreEventTlv.pack(EventTlvs.TYPE.value, EventTypes.CONFIGURATION_STATE.value)
session.broker.handlerawmsg(coreapi.CoreEventMessage.pack(0, tlvdata))
switch = session.add_object(cls=nodes.SwitchNode, name="switch")
switch = session.create_node(cls=core.nodes.network.SwitchNode, name="switch")
switch.setposition(x=80, y=50)
num_local = options.numnodes / 2
num_remote = options.numnodes / 2 + options.numnodes % 2
print "creating %d (%d local / %d remote) nodes with addresses from %s" % \
(options.numnodes, num_local, num_remote, prefix)
for i in xrange(1, num_local + 1):
node = session.add_object(cls=nodes.CoreNode, name="n%d" % i, objid=i)
print("creating %d (%d local / %d remote) nodes with addresses from %s" % \
(options.numnodes, num_local, num_remote, prefix))
for i in range(1, num_local + 1):
node = session.create_node(cls=core.nodes.base.CoreNode, name="n%d" % i, _id=i)
node.newnetif(switch, ["%s/%s" % (prefix.addr(i), prefix.prefixlen)])
node.cmd([constants.SYSCTL_BIN, "net.ipv4.icmp_echo_ignore_broadcasts=0"])
node.setposition(x=150 * i, y=150)
@ -90,8 +92,8 @@ def main():
session.broker.handlerawmsg(switch.tonodemsg(flags=flags))
# create remote nodes via API
for i in xrange(num_local + 1, options.numnodes + 1):
node = nodes.CoreNode(session=session, objid=i, name="n%d" % i, start=False)
for i in range(num_local + 1, options.numnodes + 1):
node = core.nodes.base.CoreNode(session=session, _id=i, name="n%d" % i, start=False)
node.setposition(x=150 * i, y=150)
node.server = slave
n.append(node)
@ -100,8 +102,8 @@ def main():
session.broker.handlerawmsg(node_message)
# create remote links via API
for i in xrange(num_local + 1, options.numnodes + 1):
tlvdata = coreapi.CoreLinkTlv.pack(LinkTlvs.N1_NUMBER.value, switch.objid)
for i in range(num_local + 1, options.numnodes + 1):
tlvdata = coreapi.CoreLinkTlv.pack(LinkTlvs.N1_NUMBER.value, switch.id)
tlvdata += coreapi.CoreLinkTlv.pack(LinkTlvs.N2_NUMBER.value, i)
tlvdata += coreapi.CoreLinkTlv.pack(LinkTlvs.TYPE.value, LinkTypes.WIRED.value)
tlvdata += coreapi.CoreLinkTlv.pack(LinkTlvs.INTERFACE2_NUMBER.value, 0)
@ -118,9 +120,9 @@ def main():
# start a shell on node 1
n[1].client.term("bash")
print "elapsed time: %s" % (datetime.datetime.now() - start)
print "To stop this session, use the 'core-cleanup' script on this server"
print "and on the remote slave server."
print("elapsed time: %s" % (datetime.datetime.now() - start))
print("To stop this session, use the 'core-cleanup' script on this server")
print("and on the remote slave server.")
if __name__ == "__main__" or __name__ == "__builtin__":

View file

@ -19,10 +19,11 @@ import shutil
import sys
import time
import core.nodes.base
import core.nodes.network
from core import constants
from core.misc import ipaddress
from core.netns import nodes
from core.session import Session
from core.nodes import ipaddress
from core.emulator.session import Session
GBD = 1024.0 * 1024.0
@ -114,16 +115,16 @@ def main():
start = datetime.datetime.now()
prefix = ipaddress.Ipv4Prefix("10.83.0.0/16")
print "Testing how many network namespace nodes this machine can create."
print " - %s" % linuxversion()
print("Testing how many network namespace nodes this machine can create.")
print(" - %s" % linuxversion())
mem = memfree()
print " - %.02f GB total memory (%.02f GB swap)" % (mem["total"] / GBD, mem["stotal"] / GBD)
print " - using IPv4 network prefix %s" % prefix
print " - using wait time of %s" % options.waittime
print " - using %d nodes per bridge" % options.bridges
print " - will retry %d times on failure" % options.retries
print " - adding these services to each node: %s" % options.services
print " "
print(" - %.02f GB total memory (%.02f GB swap)" % (mem["total"] / GBD, mem["stotal"] / GBD))
print(" - using IPv4 network prefix %s" % prefix)
print(" - using wait time of %s" % options.waittime)
print(" - using %d nodes per bridge" % options.bridges)
print(" - will retry %d times on failure" % options.retries)
print(" - adding these services to each node: %s" % options.services)
print(" ")
lfp = None
if options.logfile is not None:
@ -135,9 +136,9 @@ def main():
lfp.flush()
session = Session(1)
switch = session.add_object(cls=nodes.SwitchNode)
switch = session.create_node(cls=core.nodes.network.SwitchNode)
switchlist.append(switch)
print "Added bridge %s (%d)." % (switch.brname, len(switchlist))
print("Added bridge %s (%d)." % (switch.brname, len(switchlist)))
i = 0
retry_count = options.retries
@ -146,16 +147,16 @@ def main():
# optionally add a bridge (options.bridges nodes per bridge)
try:
if 0 < options.bridges <= switch.numnetif():
switch = session.add_object(cls=nodes.SwitchNode)
switch = session.create_node(cls=core.nodes.network.SwitchNode)
switchlist.append(switch)
print "\nAdded bridge %s (%d) for node %d." % (switch.brname, len(switchlist), i)
except Exception, e:
print "At %d bridges (%d nodes) caught exception:\n%s\n" % (len(switchlist), i - 1, e)
print("\nAdded bridge %s (%d) for node %d." % (switch.brname, len(switchlist), i))
except Exception as e:
print("At %d bridges (%d nodes) caught exception:\n%s\n" % (len(switchlist), i - 1, e))
break
# create a node
try:
n = session.add_object(cls=nodes.LxcNode, name="n%d" % i)
n = session.create_node(cls=core.nodes.base.CoreNode, name="n%d" % i)
n.newnetif(switch, ["%s/%s" % (prefix.addr(i), prefix.prefixlen)])
n.cmd([constants.SYSCTL_BIN, "net.ipv4.icmp_echo_ignore_broadcasts=0"])
if options.services is not None:
@ -163,11 +164,11 @@ def main():
session.services.boot_services(n)
nodelist.append(n)
if i % 25 == 0:
print "\n%s nodes created " % i,
print("\n%s nodes created " % i,)
mem = memfree()
free = mem["free"] + mem["buff"] + mem["cached"]
swap = mem["stotal"] - mem["sfree"]
print "(%.02f/%.02f GB free/swap)" % (free / GBD, swap / GBD),
print("(%.02f/%.02f GB free/swap)" % (free / GBD, swap / GBD),)
if lfp:
lfp.write("%d," % i)
lfp.write("%s\n" % ",".join(str(mem[x]) for x in MEMKEYS))
@ -176,21 +177,21 @@ def main():
sys.stdout.write(".")
sys.stdout.flush()
time.sleep(options.waittime)
except Exception, e:
print "At %d nodes caught exception:\n" % i, e
except Exception as e:
print("At %d nodes caught exception:\n" % i, e)
if retry_count > 0:
print "\nWill retry creating node %d." % i
print("\nWill retry creating node %d." % i)
shutil.rmtree(n.nodedir, ignore_errors=True)
retry_count -= 1
i -= 1
time.sleep(options.waittime)
continue
else:
print "Stopping at %d nodes!" % i
print("Stopping at %d nodes!" % i)
break
if i == options.numnodes:
print "Stopping at %d nodes due to numnodes option." % i
print("Stopping at %d nodes due to numnodes option." % i)
break
# node creation was successful at this point
retry_count = options.retries
@ -199,8 +200,8 @@ def main():
lfp.flush()
lfp.close()
print "elapsed time: %s" % (datetime.datetime.now() - start)
print "Use the core-cleanup script to remove nodes and bridges."
print("elapsed time: %s" % (datetime.datetime.now() - start))
print("Use the core-cleanup script to remove nodes and bridges.")
if __name__ == "__main__":

View file

@ -13,16 +13,16 @@ import os
import random
import sys
import time
from builtins import range
from string import Template
import core.nodes.base
import core.nodes.network
from core.constants import QUAGGA_STATE_DIR
from core.misc import ipaddress
from core.misc.utils import check_cmd
from core.netns import nodes
# this is the /etc/core/core.conf default
from core.session import Session
from core.emulator.session import Session
from core.nodes import ipaddress
from core.utils import check_cmd
quagga_sbin_search = ("/usr/local/sbin", "/usr/sbin", "/usr/lib/quagga")
quagga_path = "zebra"
@ -39,7 +39,7 @@ except OSError:
sys.exit(1)
class ManetNode(nodes.LxcNode):
class ManetNode(core.nodes.base.CoreNode):
""" An Lxc namespace node configured for Quagga OSPFv3 MANET MDR
"""
conftemp = Template("""\
@ -64,12 +64,12 @@ ip forwarding
confdir = "/usr/local/etc/quagga"
def __init__(self, core, ipaddr, routerid=None,
objid=None, name=None, nodedir=None):
_id=None, name=None, nodedir=None):
if routerid is None:
routerid = ipaddr.split("/")[0]
self.ipaddr = ipaddr
self.routerid = routerid
nodes.LxcNode.__init__(self, core, objid, name, nodedir)
core.nodes.base.CoreBaseNode.__init__(self, core, _id, name, nodedir)
self.privatedir(self.confdir)
self.privatedir(QUAGGA_STATE_DIR)
@ -84,7 +84,7 @@ ip forwarding
f.close()
tmp = self.bootscript()
if tmp:
self.nodefile(self.bootsh, tmp, mode=0755)
self.nodefile(self.bootsh, tmp, mode=0o755)
def boot(self):
self.config()
@ -129,9 +129,8 @@ class Route(object):
def __init__(self, prefix=None, gw=None, metric=None):
try:
self.prefix = ipaddress.Ipv4Prefix(prefix)
except Exception, e:
raise ValueError, "Invalid prefix given to Route object: %s\n%s" % \
(prefix, e)
except Exception as e:
raise ValueError("Invalid prefix given to Route object: %s\n%s" % (prefix, e))
self.gw = gw
self.metric = metric
@ -171,13 +170,13 @@ class ManetExperiment(object):
def info(self, msg):
''' Utility method for writing output to stdout. '''
print msg
print(msg)
sys.stdout.flush()
self.log(msg)
def warn(self, msg):
''' Utility method for writing output to stderr. '''
print >> sys.stderr, msg
sys.stderr.write(msg)
sys.stderr.flush()
self.log(msg)
@ -204,7 +203,7 @@ class ManetExperiment(object):
""" Write to the log file, if any. """
if not self.logfp:
return
print >> self.logfp, msg
self.logfp.write(msg)
def logdata(self, nbrs, mdrs, lsdbs, krs, zrs):
""" Dump experiment parameters and data to the log file. """
@ -243,15 +242,15 @@ class ManetExperiment(object):
prefix = ipaddress.Ipv4Prefix("10.14.0.0/16")
self.session = Session(1)
# emulated network
self.net = self.session.add_object(cls=nodes.WlanNode)
for i in xrange(1, numnodes + 1):
self.net = self.session.create_node(cls=core.nodes.network.WlanNode)
for i in range(1, numnodes + 1):
addr = "%s/%s" % (prefix.addr(i), 32)
tmp = self.session.add_object(cls=ManetNode, ipaddr=addr, objid="%d" % i, name="n%d" % i)
tmp = self.session.create_node(cls=ManetNode, ipaddr=addr, _id="%d" % i, name="n%d" % i)
tmp.newnetif(self.net, [addr])
self.nodes.append(tmp)
# connect nodes with probability linkprob
for i in xrange(numnodes):
for j in xrange(i + 1, numnodes):
for i in range(numnodes):
for j in range(i + 1, numnodes):
r = random.random()
if r < linkprob:
if self.verbose:
@ -266,7 +265,7 @@ class ManetExperiment(object):
self.net.link(self.nodes[i].netif(0), self.nodes[j].netif(0))
self.nodes[i].boot()
# run the boot.sh script on all nodes to start Quagga
for i in xrange(numnodes):
for i in range(numnodes):
self.nodes[i].cmd(["./%s" % self.nodes[i].bootsh])
def compareroutes(self, node, kr, zr):
@ -368,12 +367,12 @@ class Cmd:
def info(self, msg):
''' Utility method for writing output to stdout.'''
print msg
print(msg)
sys.stdout.flush()
def warn(self, msg):
''' Utility method for writing output to stderr. '''
print >> sys.stderr, "XXX %s:" % self.node.routerid, msg
sys.stderr.write("XXX %s:" % self.node.routerid, msg)
sys.stderr.flush()
def run(self):
@ -473,7 +472,7 @@ class ZebraRoutes(VtyshCmd):
args = "show ip route"
def parse(self):
for i in xrange(0, 3):
for i in range(0, 3):
# skip first three lines
self.out.readline()
r = []

View file

@ -37,22 +37,23 @@ import os
import sys
import time
import core.nodes.base
import core.nodes.network
from core import emane
from core.emane.bypass import EmaneBypassModel
from core.emane.nodes import EmaneNode
from core.emane.rfpipe import EmaneRfPipeModel
from core.misc import ipaddress
from core.netns import nodes
from core.session import Session
from core.emulator.session import Session
from core.nodes import ipaddress
try:
import emaneeventservice
import emaneeventpathloss
except Exception, e:
except Exception as e:
try:
from emanesh.events import EventService
from emanesh.events import PathlossEvent
except Exception, e2:
except Exception as e2:
raise ImportError("failed to import EMANE Python bindings:\n%s\n%s" % (e, e2))
# global Experiment object (for interaction with "python -i")
@ -113,12 +114,12 @@ class Cmd(object):
def info(self, msg):
""" Utility method for writing output to stdout."""
print msg
print(msg)
sys.stdout.flush()
def warn(self, msg):
""" Utility method for writing output to stderr. """
print >> sys.stderr, "XXX %s:" % self.node.name, msg
sys.stderr.write("XXX %s:" % self.node.name, msg)
sys.stderr.flush()
def run(self):
@ -255,7 +256,7 @@ class IperfCmd(ClientServerCmd):
lines = self.out.readlines()
try:
bps = int(lines[-1].split(",")[-1].strip("\n"))
except Exception, e:
except Exception as e:
self.warn("iperf parsing exception: %s" % e)
bps = 0
return bps
@ -357,13 +358,13 @@ class Experiment(object):
def info(self, msg):
""" Utility method for writing output to stdout. """
print msg
print(msg)
sys.stdout.flush()
self.log(msg)
def warn(self, msg):
""" Utility method for writing output to stderr. """
print >> sys.stderr, msg
sys.stderr.write(msg)
sys.stderr.flush()
self.log(msg)
@ -393,7 +394,7 @@ class Experiment(object):
""" Write to the log file, if any. """
if not self.logfp:
return
print >> self.logfp, msg
self.logfp.write(msg)
def reset(self):
""" Prepare for another experiment run.
@ -413,11 +414,11 @@ class Experiment(object):
prefix = ipaddress.Ipv4Prefix("10.0.0.0/16")
self.session = Session(1)
# emulated network
self.net = self.session.add_object(cls=nodes.WlanNode, name="wlan1")
self.net = self.session.create_node(cls=core.nodes.network.WlanNode, name="wlan1")
prev = None
for i in xrange(1, numnodes + 1):
for i in range(1, numnodes + 1):
addr = "%s/%s" % (prefix.addr(i), 32)
tmp = self.session.add_object(cls=nodes.CoreNode, objid=i, name="n%d" % i)
tmp = self.session.create_node(cls=core.nodes.base.CoreNode, _id=i, name="n%d" % i)
tmp.newnetif(self.net, [addr])
self.nodes.append(tmp)
self.session.services.add_services(tmp, "router", "IPForward")
@ -440,13 +441,12 @@ class Experiment(object):
self.session.location.setrefgeo(47.57917, -122.13232, 2.00000)
self.session.location.refscale = 150.0
self.session.emane.loadmodels()
self.net = self.session.add_object(cls=EmaneNode, objid=numnodes + 1, name="wlan1")
self.net = self.session.create_node(cls=EmaneNode, _id=numnodes + 1, name="wlan1")
self.net.verbose = verbose
# self.session.emane.addobj(self.net)
for i in xrange(1, numnodes + 1):
for i in range(1, numnodes + 1):
addr = "%s/%s" % (prefix.addr(i), 32)
tmp = self.session.add_object(cls=nodes.CoreNode, objid=i,
name="n%d" % i)
tmp = self.session.create_node(cls=core.nodes.base.CoreNode, _id=i, name="n%d" % i)
# tmp.setposition(i * 20, 50, None)
tmp.setposition(50, 50, None)
tmp.newnetif(self.net, [addr])
@ -455,13 +455,13 @@ class Experiment(object):
if values is None:
values = cls.getdefaultvalues()
self.session.emane.setconfig(self.net.objid, cls.name, values)
self.session.emane.setconfig(self.net.id, cls.name, values)
self.session.instantiate()
self.info("waiting %s sec (TAP bring-up)" % 2)
time.sleep(2)
for i in xrange(1, numnodes + 1):
for i in range(1, numnodes + 1):
tmp = self.nodes[i - 1]
self.session.services.boot_services(tmp)
self.staticroutes(i, prefix, numnodes)
@ -496,7 +496,7 @@ class Experiment(object):
self.warn("failed to add interface route: %s" % cmd)
# add static routes to all other nodes via left/right neighbors
for j in xrange(1, numnodes + 1):
for j in range(1, numnodes + 1):
if abs(j - i) < 2:
continue
addr = "%s" % prefix.addr(j)
@ -525,7 +525,7 @@ class Experiment(object):
otachannel=None)
old = False
for i in xrange(1, numnodes + 1):
for i in range(1, numnodes + 1):
rxnem = i
# inform rxnem that it can hear node to the left with 10dB noise
txnem = rxnem - 1

View file

@ -8,8 +8,8 @@
import optparse
import socket
from core.api import coreapi
from core.enumerations import MessageFlags, SessionTlvs, CORE_API_PORT
from core.api.tlv import coreapi
from core.emulator.enumerations import MessageFlags, SessionTlvs, CORE_API_PORT
def main():
@ -40,7 +40,7 @@ def main():
data = sock.recv(msglen)
message = coreapi.CoreMessage(msgflags, hdr, data)
sessions = message.get_tlv(coreapi.SessionTlvs.NUMBER.value)
print "sessions:", sessions
print("sessions: {}".format(sessions))
sock.close()

View file

@ -1,5 +1,5 @@
all:
$(PYTHON) -m grpc_tools.protoc -I . --python_out=../core/grpc --grpc_python_out=../core/grpc core.proto
$(PYTHON) -m grpc_tools.protoc -I . --python_out=.. --grpc_python_out=.. core/api/grpc/core.proto
clean:
-rm -f ../core/grpc/core_pb2*
-rm -f ../core/api/grpc/core_pb2*

View file

@ -242,7 +242,7 @@ message SessionEvent {
int32 node_id = 1;
int32 event = 2;
string name = 3;
bytes data = 4;
string data = 4;
float time = 5;
int32 session_id = 6;
}
@ -283,8 +283,8 @@ message FileEvent {
string type = 6;
string source = 7;
int32 session_id = 8;
bytes data = 9;
bytes compressed_data = 10;
string data = 9;
string compressed_data = 10;
}
message AddNodeRequest {
@ -487,7 +487,7 @@ message GetNodeServiceFileRequest {
}
message GetNodeServiceFileResponse {
bytes data = 1;
string data = 1;
}
message SetNodeServiceRequest {
@ -508,7 +508,7 @@ message SetNodeServiceFileRequest {
int32 node_id = 2;
string service = 3;
string file = 4;
bytes data = 5;
string data = 5;
}
message SetNodeServiceFileResponse {
@ -610,11 +610,11 @@ message SaveXmlRequest {
}
message SaveXmlResponse {
bytes data = 1;
string data = 1;
}
message OpenXmlRequest {
bytes data = 1;
string data = 1;
}
message OpenXmlResponse {
@ -712,7 +712,7 @@ message ExceptionLevel {
message Hook {
SessionState.Enum state = 1;
string file = 2;
bytes data = 3;
string data = 3;
}
message ServiceDefaults {

View file

@ -1,5 +1,9 @@
configparser==3.7.4
enum34==1.1.6
future==0.17.1
futures==3.2.0
grpcio==1.18.0
lxml==3.5.0
grpcio==1.21.1
grpcio-tools==1.21.1
lxml==4.3.3
protobuf==3.8.0
six==1.12.0

View file

@ -6,7 +6,7 @@ message handlers are defined and some support for sending messages.
"""
import argparse
import ConfigParser
from configparser import ConfigParser
import logging
import sys
import threading
@ -14,11 +14,11 @@ import time
from core import load_logging_config
from core import constants
from core import enumerations
from core.corehandlers import CoreHandler
from core.coreserver import CoreServer
from core.grpc.server import CoreGrpcServer
from core.misc.utils import close_onexec
from core.emulator import enumerations
from core.api.tlv.corehandlers import CoreHandler
from core.api.tlv.coreserver import CoreServer
from core.api.grpc.server import CoreGrpcServer
from core.utils import close_onexec
load_logging_config()
@ -48,7 +48,7 @@ def cored(cfg):
try:
server = CoreServer((host, port), CoreHandler, cfg)
if cfg["ovs"] == "True":
from core.netns.openvswitch import OVS_NODES
from core.nodes.openvswitch import OVS_NODES
server.coreemu.update_nodes(OVS_NODES)
except:
logging.exception("error starting main server on: %s:%s", host, port)
@ -107,7 +107,7 @@ def get_merged_config(filename):
if args.configfile is not None:
filename = args.configfile
del args.configfile
cfg = ConfigParser.SafeConfigParser(defaults)
cfg = ConfigParser(defaults)
cfg.read(filename)
section = "core-daemon"

View file

@ -119,13 +119,13 @@ class FileUpdater(object):
search = "emane_models ="
elif target == "nodetype":
if self.options.userpath is None:
raise ValueError, "missing user path"
raise ValueError("missing user path")
filename = os.path.join(self.options.userpath, "nodes.conf")
search = self.data
else:
raise ValueError, "unknown target"
raise ValueError("unknown target")
if not os.path.exists(filename):
raise ValueError, "file %s does not exist" % filename
raise ValueError("file %s does not exist" % filename)
return search, filename
def update_file(self, fn=None):
@ -236,7 +236,7 @@ def main():
try:
up = FileUpdater(action, target, data, options)
r = up.process()
except Exception, e:
except Exception as e:
sys.stderr.write("Exception: %s\n" % e)
sys.exit(1)
if not r:

View file

@ -8,20 +8,20 @@ import os
import socket
import sys
from core.api import coreapi
from core.enumerations import CORE_API_PORT
from core.enumerations import MessageFlags
from core.enumerations import MessageTypes
from core.enumerations import SessionTlvs
from core.api.tlv import coreapi
from core.emulator.enumerations import CORE_API_PORT
from core.emulator.enumerations import MessageFlags
from core.emulator.enumerations import MessageTypes
from core.emulator.enumerations import SessionTlvs
def print_available_tlvs(t, tlv_class):
"""
Print a TLV list.
"""
print "TLVs available for %s message:" % t
print("TLVs available for %s message:" % t)
for tlv in sorted([tlv for tlv in tlv_class.tlv_type_map], key=lambda x: x.name):
print "%s:%s" % (tlv.value, tlv.name)
print("%s:%s" % (tlv.value, tlv.name))
def print_examples(name):
@ -52,9 +52,9 @@ def print_examples(name):
"srcname=\"./test.log\"",
"move a test.log file from host to node 2"),
]
print "Example %s invocations:" % name
print("Example %s invocations:" % name)
for cmd, descr in examples:
print " %s %s\n\t\t%s" % (name, cmd, descr)
print(" %s %s\n\t\t%s" % (name, cmd, descr))
def receive_message(sock):
@ -68,7 +68,7 @@ def receive_message(sock):
data = sock.recv(4096)
msghdr = data[:coreapi.CoreMessage.header_len]
except KeyboardInterrupt:
print "CTRL+C pressed"
print("CTRL+C pressed")
sys.exit(1)
if len(msghdr) == 0:
@ -84,11 +84,11 @@ def receive_message(sock):
except KeyError:
msg = coreapi.CoreMessage(msgflags, msghdr, msgdata)
msg.message_type = msgtype
print "unimplemented CORE message type: %s" % msg.type_str()
print("unimplemented CORE message type: %s" % msg.type_str())
return msg
if len(data) > msglen + coreapi.CoreMessage.header_len:
print "received a message of type %d, dropping %d bytes of extra data" \
% (msgtype, len(data) - (msglen + coreapi.CoreMessage.header_len))
print("received a message of type %d, dropping %d bytes of extra data" \
% (msgtype, len(data) - (msglen + coreapi.CoreMessage.header_len)))
return msgcls(msgflags, msghdr, msgdata)
@ -103,15 +103,15 @@ def connect_to_session(sock, requested):
smsg = coreapi.CoreSessionMessage.pack(flags, tlvdata)
sock.sendall(smsg)
print "waiting for session list..."
print("waiting for session list...")
smsgreply = receive_message(sock)
if smsgreply is None:
print "disconnected"
print("disconnected")
return False
sessstr = smsgreply.get_tlv(SessionTlvs.NUMBER.value)
if sessstr is None:
print "missing session numbers"
print("missing session numbers")
return False
# join the first session (that is not our own connection)
@ -119,7 +119,7 @@ def connect_to_session(sock, requested):
sessions = sessstr.split("|")
sessions.remove(str(localport))
if len(sessions) == 0:
print "no sessions to join"
print("no sessions to join")
return False
if not requested:
@ -127,10 +127,10 @@ def connect_to_session(sock, requested):
elif requested in sessions:
session = requested
else:
print "requested session not found!"
print("requested session not found!")
return False
print "joining session: %s" % session
print("joining session: %s" % session)
tlvdata = coreapi.CoreSessionTlv.pack(SessionTlvs.NUMBER.value, session)
flags = MessageFlags.ADD.value
smsg = coreapi.CoreSessionMessage.pack(flags, tlvdata)
@ -142,12 +142,12 @@ def receive_response(sock, opt):
"""
Receive and print a CORE message from the given socket.
"""
print "waiting for response..."
print("waiting for response...")
msg = receive_message(sock)
if msg is None:
print "disconnected from %s:%s" % (opt.address, opt.port)
print("disconnected from %s:%s" % (opt.address, opt.port))
sys.exit(0)
print "received message:", msg
print("received message: %s" % msg)
def main():
@ -162,13 +162,13 @@ def main():
usagestr += "Supported message flags (flags=f1,f2,...):\n %s" % flags
parser = optparse.OptionParser(usage=usagestr)
parser.set_defaults(
port=CORE_API_PORT,
address="localhost",
session=None,
listen=False,
examples=False,
tlvs=False,
tcp=False
port=CORE_API_PORT,
address="localhost",
session=None,
listen=False,
examples=False,
tlvs=False,
tcp=False
)
parser.add_option("-H", dest="examples", action="store_true",
@ -217,7 +217,7 @@ def main():
# build a message consisting of TLVs from "type=value" arguments
flagstr = ""
tlvdata = ""
tlvdata = b""
for a in args:
typevalue = a.split("=")
if len(typevalue) < 2:
@ -255,11 +255,11 @@ def main():
try:
sock.connect((opt.address, opt.port))
except Exception as e:
print "Error connecting to %s:%s:\n\t%s" % (opt.address, opt.port, e)
print("Error connecting to %s:%s:\n\t%s" % (opt.address, opt.port, e))
sys.exit(1)
if not connect_to_session(sock, opt.session):
print "warning: continuing without joining a session!"
print("warning: continuing without joining a session!")
sock.sendall(msg)
if opt.listen:

View file

@ -42,7 +42,10 @@ setup(
version="@PACKAGE_VERSION@",
packages=find_packages(),
install_requires=[
"configparser",
"enum34",
"future",
"grpcio",
"lxml"
],
tests_require=[

View file

@ -9,39 +9,39 @@ import time
import pytest
from mock.mock import MagicMock
from core.api.coreapi import CoreConfMessage
from core.api.coreapi import CoreEventMessage
from core.api.coreapi import CoreExecMessage
from core.api.coreapi import CoreLinkMessage
from core.api.coreapi import CoreNodeMessage
from core.corehandlers import CoreHandler
from core.coreserver import CoreServer
from core.api.tlv.coreapi import CoreConfMessage
from core.api.tlv.coreapi import CoreEventMessage
from core.api.tlv.coreapi import CoreExecMessage
from core.api.tlv.coreapi import CoreLinkMessage
from core.api.tlv.coreapi import CoreNodeMessage
from core.api.tlv.corehandlers import CoreHandler
from core.api.tlv.coreserver import CoreServer
from core.emulator.coreemu import CoreEmu
from core.emulator.emudata import IpPrefixes
from core.enumerations import CORE_API_PORT
from core.enumerations import ConfigTlvs
from core.enumerations import EventTlvs
from core.enumerations import EventTypes
from core.enumerations import ExecuteTlvs
from core.enumerations import LinkTlvs
from core.enumerations import LinkTypes
from core.enumerations import MessageFlags
from core.enumerations import NodeTlvs
from core.enumerations import NodeTypes
from core.grpc.client import InterfaceHelper
from core.grpc.server import CoreGrpcServer
from core.misc import ipaddress
from core.misc.ipaddress import MacAddress
from core.service import ServiceManager
from core.emulator.enumerations import CORE_API_PORT
from core.emulator.enumerations import ConfigTlvs
from core.emulator.enumerations import EventTlvs
from core.emulator.enumerations import EventTypes
from core.emulator.enumerations import ExecuteTlvs
from core.emulator.enumerations import LinkTlvs
from core.emulator.enumerations import LinkTypes
from core.emulator.enumerations import MessageFlags
from core.emulator.enumerations import NodeTlvs
from core.emulator.enumerations import NodeTypes
from core.api.grpc.client import InterfaceHelper
from core.api.grpc.server import CoreGrpcServer
from core.nodes import ipaddress
from core.nodes.ipaddress import MacAddress
from core.services.coreservices import ServiceManager
EMANE_SERVICES = "zebra|OSPFv3MDR|IPForward"
def node_message(objid, name, emulation_server=None, node_type=NodeTypes.DEFAULT, model=None):
def node_message(_id, name, emulation_server=None, node_type=NodeTypes.DEFAULT, model=None):
"""
Convenience method for creating a node TLV messages.
:param int objid: node id
:param int _id: node id
:param str name: node name
:param str emulation_server: distributed server name, if desired
:param core.enumerations.NodeTypes node_type: node type
@ -50,7 +50,7 @@ def node_message(objid, name, emulation_server=None, node_type=NodeTypes.DEFAULT
:rtype: core.api.coreapi.CoreNodeMessage
"""
values = [
(NodeTlvs.NUMBER, objid),
(NodeTlvs.NUMBER, _id),
(NodeTlvs.TYPE, node_type.value),
(NodeTlvs.NAME, name),
(NodeTlvs.EMULATION_SERVER, emulation_server),
@ -118,7 +118,7 @@ def command_message(node, command):
"""
flags = MessageFlags.STRING.value | MessageFlags.TEXT.value
return CoreExecMessage.create(flags, [
(ExecuteTlvs.NODE, node.objid),
(ExecuteTlvs.NODE, node.id),
(ExecuteTlvs.NUMBER, 1),
(ExecuteTlvs.COMMAND, command)
])

View file

@ -4,12 +4,12 @@ Unit tests for testing CORE with distributed networks.
import conftest
from core.api.coreapi import CoreExecMessage
from core.enumerations import EventTypes
from core.enumerations import ExecuteTlvs
from core.enumerations import MessageFlags
from core.enumerations import NodeTypes
from core.misc.ipaddress import IpAddress
from core.api.tlv.coreapi import CoreExecMessage
from core.emulator.enumerations import EventTypes
from core.emulator.enumerations import ExecuteTlvs
from core.emulator.enumerations import MessageFlags
from core.emulator.enumerations import NodeTypes
from core.nodes.ipaddress import IpAddress
def validate_response(replies, _):
@ -40,7 +40,7 @@ class TestDistributed:
# create local node
message = conftest.node_message(
objid=1,
_id=1,
name="n1",
model="host"
)
@ -48,7 +48,7 @@ class TestDistributed:
# create distributed node and assign to distributed server
message = conftest.node_message(
objid=2,
_id=2,
name="n2",
emulation_server=cored.distributed_server,
model="host"
@ -57,7 +57,7 @@ class TestDistributed:
# create distributed switch and assign to distributed server
message = conftest.node_message(
objid=3,
_id=3,
name="n3",
emulation_server=cored.distributed_server,
node_type=NodeTypes.SWITCH
@ -89,7 +89,7 @@ class TestDistributed:
cored.request_handler.handle_message(message)
# test a ping command
node_one = cored.session.get_object(1)
node_one = cored.session.get_node(1)
message = conftest.command_message(node_one, "ping -c 5 %s" % ip4_address)
cored.request_handler.dispatch_replies = validate_response
cored.request_handler.handle_message(message)
@ -106,7 +106,7 @@ class TestDistributed:
# create local node
message = conftest.node_message(
objid=1,
_id=1,
name="n1",
model="host"
)
@ -114,7 +114,7 @@ class TestDistributed:
# create distributed node and assign to distributed server
message = conftest.node_message(
objid=2,
_id=2,
name="n2",
emulation_server=cored.distributed_server,
node_type=NodeTypes.PHYSICAL,
@ -124,7 +124,7 @@ class TestDistributed:
# create distributed switch and assign to distributed server
message = conftest.node_message(
objid=3,
_id=3,
name="n3",
node_type=NodeTypes.SWITCH
)
@ -155,7 +155,7 @@ class TestDistributed:
cored.request_handler.handle_message(message)
# test a ping command
node_one = cored.session.get_object(1)
node_one = cored.session.get_node(1)
message = conftest.command_message(node_one, "ping -c 5 %s" % ip4_address)
cored.request_handler.dispatch_replies = validate_response
cored.request_handler.handle_message(message)
@ -173,7 +173,7 @@ class TestDistributed:
# create local node
message = conftest.node_message(
objid=1,
_id=1,
name="n1",
model="host"
)
@ -181,7 +181,7 @@ class TestDistributed:
# create distributed node and assign to distributed server
message = conftest.node_message(
objid=2,
_id=2,
name=distributed_address,
emulation_server=cored.distributed_server,
node_type=NodeTypes.TUNNEL

View file

@ -2,7 +2,7 @@
Sample user-defined services for testing.
"""
from core.service import CoreService
from core.services.coreservices import CoreService
class MyService(CoreService):

View file

@ -1,13 +1,13 @@
import pytest
from core.conf import ConfigurableManager
from core.conf import ConfigurableOptions
from core.conf import Configuration
from core.conf import ModelManager
from core.config import ConfigurableManager
from core.config import ConfigurableOptions
from core.config import Configuration
from core.config import ModelManager
from core.emane.ieee80211abg import EmaneIeee80211abgModel
from core.enumerations import ConfigDataTypes
from core.enumerations import NodeTypes
from core.mobility import BasicRangeModel
from core.emulator.enumerations import ConfigDataTypes
from core.emulator.enumerations import NodeTypes
from core.location.mobility import BasicRangeModel
class TestConfigurableOptions(ConfigurableOptions):
@ -160,7 +160,7 @@ class TestConf:
session.mobility.set_model(wlan_node, BasicRangeModel)
# then
assert session.mobility.get_model_config(wlan_node.objid, BasicRangeModel.name)
assert session.mobility.get_model_config(wlan_node.id, BasicRangeModel.name)
def test_model_set_error(self, session):
# given

View file

@ -4,17 +4,17 @@ Unit tests for testing basic CORE networks.
import os
import stat
import subprocess
import threading
import pytest
from mock import MagicMock
from core.emulator.emudata import NodeOptions
from core.enumerations import MessageFlags
from core.enumerations import NodeTypes
from core.mobility import BasicRangeModel
from core.mobility import Ns2ScriptedMobility
from core.netns.vnodeclient import VnodeClient
from core.emulator.enumerations import MessageFlags
from core.emulator.enumerations import NodeTypes
from core.location.mobility import BasicRangeModel
from core.location.mobility import Ns2ScriptedMobility
from core.nodes.client import VnodeClient
_PATH = os.path.abspath(os.path.dirname(__file__))
_MOBILITY_FILE = os.path.join(_PATH, "mobility.scen")
@ -36,9 +36,9 @@ def createclients(sessiondir, clientcls=VnodeClient, cmdchnlfilterfunc=None):
:rtype: list
"""
direntries = map(lambda x: os.path.join(sessiondir, x), os.listdir(sessiondir))
cmdchnls = filter(lambda x: stat.S_ISSOCK(os.stat(x).st_mode), direntries)
cmdchnls = list(filter(lambda x: stat.S_ISSOCK(os.stat(x).st_mode), direntries))
if cmdchnlfilterfunc:
cmdchnls = filter(cmdchnlfilterfunc, cmdchnls)
cmdchnls = list(filter(cmdchnlfilterfunc, cmdchnls))
cmdchnls.sort()
return map(lambda x: clientcls(os.path.basename(x), x), cmdchnls)
@ -69,7 +69,7 @@ class TestCore:
# link nodes to net node
for node in [node_one, node_two]:
interface = ip_prefixes.create_interface(node)
session.add_link(node.objid, net_node.objid, interface_one=interface)
session.add_link(node.id, net_node.id, interface_one=interface)
# instantiate session
session.instantiate()
@ -96,7 +96,7 @@ class TestCore:
# link nodes to ptp net
for node in [node_one, node_two]:
interface = ip_prefixes.create_interface(node)
session.add_link(node.objid, ptp_node.objid, interface_one=interface)
session.add_link(node.id, ptp_node.id, interface_one=interface)
# get node client for testing
client = node_one.client
@ -113,9 +113,9 @@ class TestCore:
status, output = client.cmd_output(command)
assert not status
p, stdin, stdout, stderr = client.popen(command)
assert not p.status()
assert not p.wait()
assert not client.icmd(command)
assert not client.redircmd(MagicMock(), MagicMock(), MagicMock(), command)
assert not client.redircmd(subprocess.PIPE, subprocess.PIPE, subprocess.PIPE, command)
assert not client.shcmd(command[0])
# check various command using command line
@ -152,7 +152,7 @@ class TestCore:
# link nodes to ptp net
for node in [node_one, node_two]:
interface = ip_prefixes.create_interface(node)
session.add_link(node.objid, ptp_node.objid, interface_one=interface)
session.add_link(node.id, ptp_node.id, interface_one=interface)
# instantiate session
session.instantiate()
@ -199,7 +199,7 @@ class TestCore:
# link nodes
for node in [node_one, node_two]:
interface = ip_prefixes.create_interface(node)
session.add_link(node.objid, wlan_node.objid, interface_one=interface)
session.add_link(node.id, wlan_node.id, interface_one=interface)
# instantiate session
session.instantiate()
@ -229,7 +229,7 @@ class TestCore:
# link nodes
for node in [node_one, node_two]:
interface = ip_prefixes.create_interface(node)
session.add_link(node.objid, wlan_node.objid, interface_one=interface)
session.add_link(node.id, wlan_node.id, interface_one=interface)
# configure mobility script for session
config = {

View file

@ -43,7 +43,7 @@ class TestEmane:
# configure tdma
if model == EmaneTdmaModel:
session.emane.set_model_config(emane_network.objid, EmaneTdmaModel.name, {
session.emane.set_model_config(emane_network.id, EmaneTdmaModel.name, {
"schedule": os.path.join(_DIR, "../examples/tdma/schedule.xml")
})
@ -57,7 +57,7 @@ class TestEmane:
for i, node in enumerate([node_one, node_two]):
node.setposition(x=150 * (i + 1), y=150)
interface = ip_prefixes.create_interface(node)
session.add_link(node.objid, emane_network.objid, interface_one=interface)
session.add_link(node.id, emane_network.id, interface_one=interface)
# instantiate session
session.instantiate()

View file

@ -1,17 +1,18 @@
import time
from Queue import Queue
import grpc
import pytest
from builtins import int
from queue import Queue
from core.conf import ConfigShim
from core.data import EventData
from core.api.grpc import core_pb2
from core.api.grpc.client import CoreGrpcClient
from core.config import ConfigShim
from core.emane.ieee80211abg import EmaneIeee80211abgModel
from core.emulator.data import EventData
from core.emulator.emudata import NodeOptions
from core.enumerations import NodeTypes, EventTypes, ConfigFlags, ExceptionLevels
from core.grpc import core_pb2
from core.grpc.client import CoreGrpcClient
from core.mobility import BasicRangeModel, Ns2ScriptedMobility
from core.emulator.enumerations import NodeTypes, EventTypes, ConfigFlags, ExceptionLevels
from core.location.mobility import BasicRangeModel, Ns2ScriptedMobility
class TestGrpc:
@ -182,7 +183,7 @@ class TestGrpc:
# then
assert response.node_id is not None
assert session.get_object(response.node_id) is not None
assert session.get_node(response.node_id) is not None
def test_get_node(self, grpc_server):
# given
@ -192,10 +193,10 @@ class TestGrpc:
# then
with client.context_connect():
response = client.get_node(session.id, node.objid)
response = client.get_node(session.id, node.id)
# then
assert response.node.id == node.objid
assert response.node.id == node.id
@pytest.mark.parametrize("node_id, expected", [
(1, True),
@ -237,7 +238,7 @@ class TestGrpc:
assert response.result is expected
if expected is True:
with pytest.raises(KeyError):
assert session.get_object(node.objid)
assert session.get_node(node.id)
def test_node_command(self, grpc_server):
# given
@ -252,7 +253,7 @@ class TestGrpc:
# then
command = "echo %s" % output
with client.context_connect():
response = client.node_command(session.id, node.objid, command)
response = client.node_command(session.id, node.id, command)
# then
assert response.output == output
@ -268,7 +269,7 @@ class TestGrpc:
# then
with client.context_connect():
response = client.get_node_terminal(session.id, node.objid)
response = client.get_node_terminal(session.id, node.id)
# then
assert response.terminal is not None
@ -341,11 +342,11 @@ class TestGrpc:
switch = session.add_node(_type=NodeTypes.SWITCH)
node = session.add_node()
interface = ip_prefixes.create_interface(node)
session.add_link(node.objid, switch.objid, interface)
session.add_link(node.id, switch.id, interface)
# then
with client.context_connect():
response = client.get_node_links(session.id, switch.objid)
response = client.get_node_links(session.id, switch.id)
# then
assert len(response.links) == 1
@ -357,7 +358,7 @@ class TestGrpc:
switch = session.add_node(_type=NodeTypes.SWITCH)
node = session.add_node()
interface = ip_prefixes.create_interface(node)
session.add_link(node.objid, switch.objid, interface)
session.add_link(node.id, switch.id, interface)
# then
with pytest.raises(grpc.RpcError):
@ -373,9 +374,9 @@ class TestGrpc:
assert len(switch.all_link_data(0)) == 0
# then
interface = interface_helper.create_interface(node.objid, 0)
interface = interface_helper.create_interface(node.id, 0)
with client.context_connect():
response = client.add_link(session.id, node.objid, switch.objid, interface)
response = client.add_link(session.id, node.id, switch.id, interface)
# then
assert response.result is True
@ -388,7 +389,7 @@ class TestGrpc:
node = session.add_node()
# then
interface = interface_helper.create_interface(node.objid, 0)
interface = interface_helper.create_interface(node.id, 0)
with pytest.raises(grpc.RpcError):
with client.context_connect():
client.add_link(session.id, 1, 3, interface)
@ -400,14 +401,14 @@ class TestGrpc:
switch = session.add_node(_type=NodeTypes.SWITCH)
node = session.add_node()
interface = ip_prefixes.create_interface(node)
session.add_link(node.objid, switch.objid, interface)
session.add_link(node.id, switch.id, interface)
options = core_pb2.LinkOptions(bandwidth=30000)
link = switch.all_link_data(0)[0]
assert options.bandwidth != link.bandwidth
# then
with client.context_connect():
response = client.edit_link(session.id, node.objid, switch.objid, options)
response = client.edit_link(session.id, node.id, switch.id, options, interface_one_id=interface.id)
# then
assert response.result is True
@ -422,11 +423,11 @@ class TestGrpc:
interface_one = ip_prefixes.create_interface(node_one)
node_two = session.add_node()
interface_two = ip_prefixes.create_interface(node_two)
session.add_link(node_one.objid, node_two.objid, interface_one, interface_two)
session.add_link(node_one.id, node_two.id, interface_one, interface_two)
link_node = None
for node_id in session.objects:
node = session.objects[node_id]
if node.objid not in {node_one.objid, node_two.objid}:
for node_id in session.nodes:
node = session.nodes[node_id]
if node.id not in {node_one.id, node_two.id}:
link_node = node
break
assert len(link_node.all_link_data(0)) == 1
@ -434,7 +435,7 @@ class TestGrpc:
# then
with client.context_connect():
response = client.delete_link(
session.id, node_one.objid, node_two.objid, interface_one.id, interface_two.id)
session.id, node_one.id, node_two.id, interface_one.id, interface_two.id)
# then
assert response.result is True
@ -448,7 +449,7 @@ class TestGrpc:
# then
with client.context_connect():
response = client.get_wlan_config(session.id, wlan.objid)
response = client.get_wlan_config(session.id, wlan.id)
# then
assert len(response.groups) > 0
@ -463,11 +464,11 @@ class TestGrpc:
# then
with client.context_connect():
response = client.set_wlan_config(session.id, wlan.objid, {range_key: range_value})
response = client.set_wlan_config(session.id, wlan.id, {range_key: range_value})
# then
assert response.result is True
config = session.mobility.get_model_config(wlan.objid, BasicRangeModel.name)
config = session.mobility.get_model_config(wlan.id, BasicRangeModel.name)
assert config[range_key] == range_value
def test_get_emane_config(self, grpc_server):
@ -509,7 +510,7 @@ class TestGrpc:
)
config_key = "platform_id_start"
config_value = "2"
session.emane.set_model_config(emane_network.objid, EmaneIeee80211abgModel.name, {config_key: config_value})
session.emane.set_model_config(emane_network.id, EmaneIeee80211abgModel.name, {config_key: config_value})
# then
with client.context_connect():
@ -517,7 +518,7 @@ class TestGrpc:
# then
assert len(response.configs) == 1
assert emane_network.objid in response.configs
assert emane_network.id in response.configs
def test_set_emane_model_config(self, grpc_server):
# given
@ -533,11 +534,11 @@ class TestGrpc:
# then
with client.context_connect():
response = client.set_emane_model_config(
session.id, emane_network.objid, EmaneIeee80211abgModel.name, {config_key: config_value})
session.id, emane_network.id, EmaneIeee80211abgModel.name, {config_key: config_value})
# then
assert response.result is True
config = session.emane.get_model_config(emane_network.objid, EmaneIeee80211abgModel.name)
config = session.emane.get_model_config(emane_network.id, EmaneIeee80211abgModel.name)
assert config[config_key] == config_value
def test_get_emane_model_config(self, grpc_server):
@ -552,7 +553,7 @@ class TestGrpc:
# then
with client.context_connect():
response = client.get_emane_model_config(
session.id, emane_network.objid, EmaneIeee80211abgModel.name)
session.id, emane_network.id, EmaneIeee80211abgModel.name)
# then
assert len(response.groups) > 0
@ -574,7 +575,7 @@ class TestGrpc:
client = CoreGrpcClient()
session = grpc_server.coreemu.create_session()
wlan = session.add_node(_type=NodeTypes.WIRELESS_LAN)
session.mobility.set_model_config(wlan.objid, Ns2ScriptedMobility.name, {})
session.mobility.set_model_config(wlan.id, Ns2ScriptedMobility.name, {})
# then
with client.context_connect():
@ -582,18 +583,18 @@ class TestGrpc:
# then
assert len(response.configs) > 0
assert wlan.objid in response.configs
assert wlan.id in response.configs
def test_get_mobility_config(self, grpc_server):
# given
client = CoreGrpcClient()
session = grpc_server.coreemu.create_session()
wlan = session.add_node(_type=NodeTypes.WIRELESS_LAN)
session.mobility.set_model_config(wlan.objid, Ns2ScriptedMobility.name, {})
session.mobility.set_model_config(wlan.id, Ns2ScriptedMobility.name, {})
# then
with client.context_connect():
response = client.get_mobility_config(session.id, wlan.objid)
response = client.get_mobility_config(session.id, wlan.id)
# then
assert len(response.groups) > 0
@ -608,11 +609,11 @@ class TestGrpc:
# then
with client.context_connect():
response = client.set_mobility_config(session.id, wlan.objid, {config_key: config_value})
response = client.set_mobility_config(session.id, wlan.id, {config_key: config_value})
# then
assert response.result is True
config = session.mobility.get_model_config(wlan.objid, Ns2ScriptedMobility.name)
config = session.mobility.get_model_config(wlan.id, Ns2ScriptedMobility.name)
assert config[config_key] == config_value
def test_mobility_action(self, grpc_server):
@ -620,12 +621,12 @@ class TestGrpc:
client = CoreGrpcClient()
session = grpc_server.coreemu.create_session()
wlan = session.add_node(_type=NodeTypes.WIRELESS_LAN)
session.mobility.set_model_config(wlan.objid, Ns2ScriptedMobility.name, {})
session.mobility.set_model_config(wlan.id, Ns2ScriptedMobility.name, {})
session.instantiate()
# then
with client.context_connect():
response = client.mobility_action(session.id, wlan.objid, core_pb2.MobilityAction.STOP)
response = client.mobility_action(session.id, wlan.id, core_pb2.MobilityAction.STOP)
# then
assert response.result is True
@ -676,7 +677,7 @@ class TestGrpc:
# then
with client.context_connect():
response = client.get_node_service(session.id, node.objid, "IPForward")
response = client.get_node_service(session.id, node.id, "DefaultRoute")
# then
assert len(response.service.configs) > 0
@ -689,7 +690,7 @@ class TestGrpc:
# then
with client.context_connect():
response = client.get_node_service_file(session.id, node.objid, "IPForward", "ipforward.sh")
response = client.get_node_service_file(session.id, node.id, "DefaultRoute", "defaultroute.sh")
# then
assert response.data is not None
@ -699,16 +700,16 @@ class TestGrpc:
client = CoreGrpcClient()
session = grpc_server.coreemu.create_session()
node = session.add_node()
service_name = "IPForward"
service_name = "DefaultRoute"
validate = ["echo hello"]
# then
with client.context_connect():
response = client.set_node_service(session.id, node.objid, service_name, [], validate, [])
response = client.set_node_service(session.id, node.id, service_name, [], validate, [])
# then
assert response.result is True
service = session.services.get_service(node.objid, service_name, default_service=True)
service = session.services.get_service(node.id, service_name, default_service=True)
assert service.validate == tuple(validate)
def test_set_node_service_file(self, grpc_server):
@ -716,13 +717,13 @@ class TestGrpc:
client = CoreGrpcClient()
session = grpc_server.coreemu.create_session()
node = session.add_node()
service_name = "IPForward"
file_name = "ipforward.sh"
service_name = "DefaultRoute"
file_name = "defaultroute.sh"
file_data = "echo hello"
# then
with client.context_connect():
response = client.set_node_service_file(session.id, node.objid, service_name, file_name, file_data)
response = client.set_node_service_file(session.id, node.id, service_name, file_name, file_data)
# then
assert response.result is True
@ -734,11 +735,11 @@ class TestGrpc:
client = CoreGrpcClient()
session = grpc_server.coreemu.create_session()
node = session.add_node()
service_name = "IPForward"
service_name = "DefaultRoute"
# then
with client.context_connect():
response = client.service_action(session.id, node.objid, service_name, core_pb2.ServiceAction.STOP)
response = client.service_action(session.id, node.id, service_name, core_pb2.ServiceAction.STOP)
# then
assert response.result is True
@ -771,7 +772,7 @@ class TestGrpc:
wlan = session.add_node(_type=NodeTypes.WIRELESS_LAN)
node = session.add_node()
interface = ip_prefixes.create_interface(node)
session.add_link(node.objid, wlan.objid, interface)
session.add_link(node.id, wlan.id, interface)
link_data = wlan.all_link_data(0)[0]
queue = Queue()
@ -880,7 +881,7 @@ class TestGrpc:
with client.context_connect():
client.events(session.id, handle_event)
time.sleep(0.1)
file_data = session.services.get_service_file(node, "IPForward", "ipforward.sh")
file_data = session.services.get_service_file(node, "DefaultRoute", "defaultroute.sh")
session.broadcast_file(file_data)
# then

View file

@ -4,17 +4,17 @@ Unit tests for testing with a CORE switch.
import threading
from core.api import coreapi, dataconversion
from core.api.coreapi import CoreExecuteTlv
from core.enumerations import CORE_API_PORT, NodeTypes
from core.enumerations import EventTlvs
from core.enumerations import EventTypes
from core.enumerations import ExecuteTlvs
from core.enumerations import LinkTlvs
from core.enumerations import LinkTypes
from core.enumerations import MessageFlags
from core.enumerations import MessageTypes
from core.misc import ipaddress
from core.api.tlv import coreapi, dataconversion
from core.api.tlv.coreapi import CoreExecuteTlv
from core.emulator.enumerations import CORE_API_PORT, NodeTypes
from core.emulator.enumerations import EventTlvs
from core.emulator.enumerations import EventTypes
from core.emulator.enumerations import ExecuteTlvs
from core.emulator.enumerations import LinkTlvs
from core.emulator.enumerations import LinkTypes
from core.emulator.enumerations import MessageFlags
from core.emulator.enumerations import MessageTypes
from core.nodes import ipaddress
def command_message(node, command):
@ -25,7 +25,7 @@ def command_message(node, command):
:param command: command to execute
:return: packed execute message
"""
tlv_data = CoreExecuteTlv.pack(ExecuteTlvs.NODE.value, node.objid)
tlv_data = CoreExecuteTlv.pack(ExecuteTlvs.NODE.value, node.id)
tlv_data += CoreExecuteTlv.pack(ExecuteTlvs.NUMBER.value, 1)
tlv_data += CoreExecuteTlv.pack(ExecuteTlvs.COMMAND.value, command)
return coreapi.CoreExecMessage.pack(MessageFlags.STRING.value | MessageFlags.TEXT.value, tlv_data)
@ -52,8 +52,8 @@ def switch_link_message(switch, node, address, prefix_len):
:param prefix_len: prefix length of address
:return: packed link message
"""
tlv_data = coreapi.CoreLinkTlv.pack(LinkTlvs.N1_NUMBER.value, switch.objid)
tlv_data += coreapi.CoreLinkTlv.pack(LinkTlvs.N2_NUMBER.value, node.objid)
tlv_data = coreapi.CoreLinkTlv.pack(LinkTlvs.N1_NUMBER.value, switch.id)
tlv_data += coreapi.CoreLinkTlv.pack(LinkTlvs.N2_NUMBER.value, node.id)
tlv_data += coreapi.CoreLinkTlv.pack(LinkTlvs.TYPE.value, LinkTypes.WIRED.value)
tlv_data += coreapi.CoreLinkTlv.pack(LinkTlvs.INTERFACE2_NUMBER.value, 0)
tlv_data += coreapi.CoreLinkTlv.pack(LinkTlvs.INTERFACE2_IP4.value, address)
@ -70,7 +70,7 @@ def run_cmd(node, exec_cmd):
:return: Returns the result of the command
"""
# Set up the command api message
# tlv_data = CoreExecuteTlv.pack(ExecuteTlvs.NODE.value, node.objid)
# tlv_data = CoreExecuteTlv.pack(ExecuteTlvs.NODE.value, node.id)
# tlv_data += CoreExecuteTlv.pack(ExecuteTlvs.NUMBER.value, 1)
# tlv_data += CoreExecuteTlv.pack(ExecuteTlvs.COMMAND.value, exec_cmd)
# message = coreapi.CoreExecMessage.pack(MessageFlags.STRING.value | MessageFlags.TEXT.value, tlv_data)
@ -90,7 +90,7 @@ def run_cmd(node, exec_cmd):
message_data = server.sock.recv(message_length)
# If we get the right response return the results
print "received response message: %s" % message_type
print("received response message: %s" % message_type)
if message_type == MessageTypes.EXECUTE.value:
message = coreapi.CoreExecMessage(message_flags, message_header, message_data)
result = message.get_tlv(ExecuteTlvs.RESULT.value)

View file

@ -1,6 +1,6 @@
from core.emulator.emudata import LinkOptions
from core.enumerations import NodeTypes
from core.misc import utils
from core.emulator.enumerations import NodeTypes
from core import utils
def create_ptp_network(session, ip_prefixes):
@ -11,7 +11,7 @@ def create_ptp_network(session, ip_prefixes):
# link nodes to net node
interface_one = ip_prefixes.create_interface(node_one)
interface_two = ip_prefixes.create_interface(node_two)
session.add_link(node_one.objid, node_two.objid, interface_one, interface_two)
session.add_link(node_one.id, node_two.id, interface_one, interface_two)
# instantiate session
session.instantiate()
@ -31,7 +31,7 @@ def iperf(from_node, to_node, ip_prefixes):
vcmd, stdin, stdout, stderr = to_node.client.popen(["iperf", "-s", "-u", "-y", "C"])
from_node.cmd(["iperf", "-u", "-t", "5", "-c", address])
to_node.cmd(["killall", "-9", "iperf"])
return stdout.read().strip()
return stdout.read().decode("utf-8").strip()
class TestLinks:
@ -43,7 +43,7 @@ class TestLinks:
inteface_two = ip_prefixes.create_interface(node_two)
# when
session.add_link(node_one.objid, node_two.objid, interface_one, inteface_two)
session.add_link(node_one.id, node_two.id, interface_one, inteface_two)
# then
assert node_one.netif(interface_one.id)
@ -56,7 +56,7 @@ class TestLinks:
interface_one = ip_prefixes.create_interface(node_one)
# when
session.add_link(node_one.objid, node_two.objid, interface_one)
session.add_link(node_one.id, node_two.id, interface_one)
# then
assert node_two.all_link_data(0)
@ -69,7 +69,7 @@ class TestLinks:
interface_two = ip_prefixes.create_interface(node_two)
# when
session.add_link(node_one.objid, node_two.objid, interface_two=interface_two)
session.add_link(node_one.id, node_two.id, interface_two=interface_two)
# then
assert node_one.all_link_data(0)
@ -81,7 +81,7 @@ class TestLinks:
node_two = session.add_node(_type=NodeTypes.SWITCH)
# when
session.add_link(node_one.objid, node_two.objid)
session.add_link(node_one.id, node_two.id)
# then
assert node_one.all_link_data(0)
@ -91,7 +91,7 @@ class TestLinks:
node_one = session.add_node()
node_two = session.add_node(_type=NodeTypes.SWITCH)
interface_one = ip_prefixes.create_interface(node_one)
session.add_link(node_one.objid, node_two.objid, interface_one)
session.add_link(node_one.id, node_two.id, interface_one)
interface = node_one.netif(interface_one.id)
output = utils.check_cmd(["tc", "qdisc", "show", "dev", interface.localname])
assert "delay" not in output
@ -105,7 +105,7 @@ class TestLinks:
link_options.bandwidth = 5000000
link_options.per = 25
link_options.dup = 25
session.update_link(node_one.objid, node_two.objid,
session.update_link(node_one.id, node_two.id,
interface_one_id=interface_one.id, link_options=link_options)
# then
@ -121,12 +121,12 @@ class TestLinks:
node_two = session.add_node()
interface_one = ip_prefixes.create_interface(node_one)
interface_two = ip_prefixes.create_interface(node_two)
session.add_link(node_one.objid, node_two.objid, interface_one, interface_two)
session.add_link(node_one.id, node_two.id, interface_one, interface_two)
assert node_one.netif(interface_one.id)
assert node_two.netif(interface_two.id)
# when
session.delete_link(node_one.objid, node_two.objid, interface_one.id, interface_two.id)
session.delete_link(node_one.id, node_two.id, interface_one.id, interface_two.id)
# then
assert not node_one.netif(interface_one.id)
@ -155,7 +155,7 @@ class TestLinks:
# change bandwidth in bits per second
link_options = LinkOptions()
link_options.bandwidth = 500000
session.update_link(node_one.objid, node_two.objid, link_options=link_options)
session.update_link(node_one.id, node_two.id, link_options=link_options)
# run iperf again
stdout = iperf(node_one, node_two, ip_prefixes)
@ -186,7 +186,7 @@ class TestLinks:
# change bandwidth in bits per second
link_options = LinkOptions()
link_options.per = 50
session.update_link(node_one.objid, node_two.objid, link_options=link_options)
session.update_link(node_one.id, node_two.id, link_options=link_options)
# run iperf again
stdout = iperf(node_one, node_two, ip_prefixes)
@ -216,7 +216,7 @@ class TestLinks:
# change delay in microseconds
link_options = LinkOptions()
link_options.delay = 1000000
session.update_link(node_one.objid, node_two.objid, link_options=link_options)
session.update_link(node_one.id, node_two.id, link_options=link_options)
# run ping for delay information again
stdout = ping_output(node_one, node_two, ip_prefixes)
@ -249,7 +249,7 @@ class TestLinks:
# change jitter in microseconds
link_options = LinkOptions()
link_options.jitter = 1000000
session.update_link(node_one.objid, node_two.objid, link_options=link_options)
session.update_link(node_one.id, node_two.id, link_options=link_options)
# run iperf again
stdout = iperf(node_one, node_two, ip_prefixes)

Some files were not shown because too many files have changed in this diff Show more