Merge pull request #250 from coreemu/refactor_pure
Merging directory layout changes and 2/3 support
This commit is contained in:
commit
2dd1538184
112 changed files with 5424 additions and 5895 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)",
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
"""
|
||||
Contains code specific to the legacy TCP API for interacting with the TCL based GUI.
|
||||
"""
|
|
@ -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)
|
|
@ -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:
|
|
@ -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")
|
|
@ -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:
|
|
@ -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,
|
|
@ -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)
|
|
@ -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):
|
|
@ -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
|
|
@ -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
|
|
@ -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)
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
1657
daemon/core/emulator/session.py
Normal file
1657
daemon/core/emulator/session.py
Normal file
File diff suppressed because it is too large
Load diff
62
daemon/core/emulator/sessionconfig.py
Normal file
62
daemon/core/emulator/sessionconfig.py
Normal 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
|
|
@ -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):
|
|
@ -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):
|
|
@ -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"]
|
|
@ -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)
|
|
@ -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
|
||||
}
|
|
@ -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)
|
|
@ -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"
|
|
@ -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
1159
daemon/core/nodes/base.py
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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:
|
|
@ -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:
|
|
@ -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__()
|
||||
|
|
@ -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"
|
29
daemon/core/nodes/nodemaps.py
Normal file
29
daemon/core/nodes/nodemaps.py
Normal 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
|
||||
}
|
|
@ -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)
|
||||
|
||||
|
|
@ -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
|
544
daemon/core/nodes/physical.py
Normal file
544
daemon/core/nodes/physical.py
Normal 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
|
|
@ -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)
|
0
daemon/core/plugins/__init__.py
Normal file
0
daemon/core/plugins/__init__.py
Normal 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)):
|
|
@ -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__))
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
@ -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:
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(".", "_")
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
}
|
||||
},
|
||||
"root": {
|
||||
"level": "INFO",
|
||||
"level": "DEBUG",
|
||||
"handlers": ["console"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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__":
|
||||
|
|
|
@ -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__":
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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__":
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import logging
|
||||
import time
|
||||
|
||||
from core.misc.event import EventLoop
|
||||
from core.location.event import EventLoop
|
||||
|
||||
|
||||
def main():
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
||||
|
|
|
@ -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__":
|
||||
|
|
|
@ -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__":
|
||||
|
|
|
@ -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 = []
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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*
|
||||
|
|
|
@ -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 {
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -42,7 +42,10 @@ setup(
|
|||
version="@PACKAGE_VERSION@",
|
||||
packages=find_packages(),
|
||||
install_requires=[
|
||||
"configparser",
|
||||
"enum34",
|
||||
"future",
|
||||
"grpcio",
|
||||
"lxml"
|
||||
],
|
||||
tests_require=[
|
||||
|
|
|
@ -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)
|
||||
])
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Sample user-defined services for testing.
|
||||
"""
|
||||
|
||||
from core.service import CoreService
|
||||
from core.services.coreservices import CoreService
|
||||
|
||||
|
||||
class MyService(CoreService):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue