added flake8/black, pre-commit integration for flake8/black, and black formatting changes

This commit is contained in:
bharnden 2019-09-10 15:10:24 -07:00
parent d5055f85d3
commit 1fc8d647c3
77 changed files with 4452 additions and 1964 deletions

View file

@ -7,3 +7,18 @@ repos:
language: system
entry: bash -c 'cd daemon && pipenv run isort --atomic -y'
types: [python]
- id: black
name: black
stages: [commit]
language: system
entry: bash -c 'cd daemon && pipenv run black --exclude ".+_pb2.*.py|doc|build|utm\.py" .'
types: [python]
- id: flake8
name: flake8
stages: [commit]
language: system
entry: bash -c 'cd daemon && pipenv run flake8'
types: [python]
exclude: setup.py

View file

@ -11,6 +11,8 @@ grpcio-tools = "*"
core = {editable = true,path = "."}
isort = "*"
pre-commit = "*"
flake8 = "*"
black = "==19.3b0"
[packages]
configparser = "*"

67
daemon/Pipfile.lock generated
View file

@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
"sha256": "e8457883200e399e412b1817f314ba5c7f2dc2f459870e6ae0101070adfcd338"
"sha256": "d1efe01da7622bbc3021b1b5f20d2f20753281627fe8a515c0d4529a20f506ba"
},
"pipfile-spec": 6,
"requires": {},
@ -145,6 +145,13 @@
}
},
"develop": {
"appdirs": {
"hashes": [
"sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92",
"sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e"
],
"version": "==1.4.3"
},
"aspy.yaml": {
"hashes": [
"sha256:463372c043f70160a9ec950c3f1e4c3a82db5fca01d334b6bc89c7164d744bdc",
@ -152,6 +159,21 @@
],
"version": "==1.3.0"
},
"attrs": {
"hashes": [
"sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79",
"sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399"
],
"version": "==19.1.0"
},
"black": {
"hashes": [
"sha256:09a9dcb7c46ed496a9850b76e4e825d6049ecd38b611f1224857a79bd985a8cf",
"sha256:68950ffd4d9169716bcb8719a56c07a2f4485354fec061cdd5910aa07369731c"
],
"index": "pypi",
"version": "==19.3b0"
},
"cfgv": {
"hashes": [
"sha256:edb387943b665bf9c434f717bf630fa78aecd53d5900d2e05da6ad6048553144",
@ -159,6 +181,13 @@
],
"version": "==2.0.1"
},
"click": {
"hashes": [
"sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13",
"sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"
],
"version": "==7.0"
},
"configparser": {
"hashes": [
"sha256:296a9c0d0607f689f2a262d4ca3fa2b22146ac0acb07fd281125c86dee3bcf50",
@ -171,6 +200,13 @@
"editable": true,
"path": "."
},
"entrypoints": {
"hashes": [
"sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19",
"sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"
],
"version": "==0.3"
},
"enum34": {
"hashes": [
"sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850",
@ -181,6 +217,14 @@
"index": "pypi",
"version": "==1.1.6"
},
"flake8": {
"hashes": [
"sha256:19241c1cbc971b9962473e4438a2ca19749a7dd002dd1a946eaba171b4114548",
"sha256:8e9dfa3cecb2400b3738a42c54c3043e821682b9c840b0448c0503f781130696"
],
"index": "pypi",
"version": "==3.7.8"
},
"future": {
"hashes": [
"sha256:67045236dcfd6816dc439556d009594abf643e5eb48992e36beac09c2ca659b8"
@ -322,6 +366,13 @@
"index": "pypi",
"version": "==4.4.1"
},
"mccabe": {
"hashes": [
"sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
"sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"
],
"version": "==0.6.1"
},
"more-itertools": {
"hashes": [
"sha256:409cd48d4db7052af495b09dec721011634af3753ae1ef92d2b32f73a745f832",
@ -365,6 +416,20 @@
"index": "pypi",
"version": "==3.9.1"
},
"pycodestyle": {
"hashes": [
"sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56",
"sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"
],
"version": "==2.5.0"
},
"pyflakes": {
"hashes": [
"sha256:17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0",
"sha256:d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2"
],
"version": "==2.1.1"
},
"pyyaml": {
"hashes": [
"sha256:0113bc0ec2ad727182326b61326afa3d1d8280ae1122493553fd6f4397f33df9",

View file

@ -98,7 +98,7 @@ class InterfaceHelper(object):
ip4mask=ip4_mask,
ip6=ip6,
ip6mask=ip6_mask,
mac=str(mac)
mac=str(mac),
)
@ -214,7 +214,9 @@ class CoreGrpcClient(object):
:rtype: core_pb2.SetSessionOptionsResponse
:raises grpc.RpcError: when session doesn't exist
"""
request = core_pb2.SetSessionOptionsRequest(session_id=session_id, config=config)
request = core_pb2.SetSessionOptionsRequest(
session_id=session_id, config=config
)
return self.stub.SetSessionOptions(request)
def get_session_location(self, session_id):
@ -229,7 +231,17 @@ class CoreGrpcClient(object):
request = core_pb2.GetSessionLocationRequest(session_id=session_id)
return self.stub.GetSessionLocation(request)
def set_session_location(self, session_id, x=None, y=None, z=None, lat=None, lon=None, alt=None, scale=None):
def set_session_location(
self,
session_id,
x=None,
y=None,
z=None,
lat=None,
lon=None,
alt=None,
scale=None,
):
"""
Set session location.
@ -246,7 +258,9 @@ class CoreGrpcClient(object):
:raises grpc.RpcError: when session doesn't exist
"""
position = core_pb2.SessionPosition(x=x, y=y, z=z, lat=lat, lon=lon, alt=alt)
request = core_pb2.SetSessionLocationRequest(session_id=session_id, position=position, scale=scale)
request = core_pb2.SetSessionLocationRequest(
session_id=session_id, position=position, scale=scale
)
return self.stub.SetSessionLocation(request)
def set_session_state(self, session_id, state):
@ -323,7 +337,9 @@ class CoreGrpcClient(object):
:rtype: core_pb2.EditNodeResponse
:raises grpc.RpcError: when session or node doesn't exist
"""
request = core_pb2.EditNodeRequest(session_id=session_id, node_id=node_id, position=position)
request = core_pb2.EditNodeRequest(
session_id=session_id, node_id=node_id, position=position
)
return self.stub.EditNode(request)
def delete_node(self, session_id, node_id):
@ -349,7 +365,9 @@ class CoreGrpcClient(object):
:rtype: core_pb2.NodeCommandResponse
:raises grpc.RpcError: when session or node doesn't exist
"""
request = core_pb2.NodeCommandRequest(session_id=session_id, node_id=node_id, command=command)
request = core_pb2.NodeCommandRequest(
session_id=session_id, node_id=node_id, command=command
)
return self.stub.NodeCommand(request)
def get_node_terminal(self, session_id, node_id):
@ -362,7 +380,9 @@ class CoreGrpcClient(object):
:rtype: core_pb2.GetNodeTerminalResponse
:raises grpc.RpcError: when session or node doesn't exist
"""
request = core_pb2.GetNodeTerminalRequest(session_id=session_id, node_id=node_id)
request = core_pb2.GetNodeTerminalRequest(
session_id=session_id, node_id=node_id
)
return self.stub.GetNodeTerminal(request)
def get_node_links(self, session_id, node_id):
@ -378,7 +398,15 @@ class CoreGrpcClient(object):
request = core_pb2.GetNodeLinksRequest(session_id=session_id, node_id=node_id)
return self.stub.GetNodeLinks(request)
def add_link(self, session_id, node_one_id, node_two_id, interface_one=None, interface_two=None, options=None):
def add_link(
self,
session_id,
node_one_id,
node_two_id,
interface_one=None,
interface_two=None,
options=None,
):
"""
Add a link between nodes.
@ -393,12 +421,25 @@ class CoreGrpcClient(object):
:raises grpc.RpcError: when session or one of the nodes don't exist
"""
link = core_pb2.Link(
node_one_id=node_one_id, node_two_id=node_two_id, type=core_pb2.LinkType.WIRED,
interface_one=interface_one, interface_two=interface_two, options=options)
node_one_id=node_one_id,
node_two_id=node_two_id,
type=core_pb2.LinkType.WIRED,
interface_one=interface_one,
interface_two=interface_two,
options=options,
)
request = core_pb2.AddLinkRequest(session_id=session_id, link=link)
return self.stub.AddLink(request)
def edit_link(self, session_id, node_one_id, node_two_id, options, interface_one_id=None, interface_two_id=None):
def edit_link(
self,
session_id,
node_one_id,
node_two_id,
options,
interface_one_id=None,
interface_two_id=None,
):
"""
Edit a link between nodes.
@ -413,11 +454,23 @@ class CoreGrpcClient(object):
:raises grpc.RpcError: when session or one of the nodes don't exist
"""
request = core_pb2.EditLinkRequest(
session_id=session_id, node_one_id=node_one_id, node_two_id=node_two_id, options=options,
interface_one_id=interface_one_id, interface_two_id=interface_two_id)
session_id=session_id,
node_one_id=node_one_id,
node_two_id=node_two_id,
options=options,
interface_one_id=interface_one_id,
interface_two_id=interface_two_id,
)
return self.stub.EditLink(request)
def delete_link(self, session_id, node_one_id, node_two_id, interface_one_id=None, interface_two_id=None):
def delete_link(
self,
session_id,
node_one_id,
node_two_id,
interface_one_id=None,
interface_two_id=None,
):
"""
Delete a link between nodes.
@ -431,8 +484,12 @@ class CoreGrpcClient(object):
:raises grpc.RpcError: when session doesn't exist
"""
request = core_pb2.DeleteLinkRequest(
session_id=session_id, node_one_id=node_one_id, node_two_id=node_two_id,
interface_one_id=interface_one_id, interface_two_id=interface_two_id)
session_id=session_id,
node_one_id=node_one_id,
node_two_id=node_two_id,
interface_one_id=interface_one_id,
interface_two_id=interface_two_id,
)
return self.stub.DeleteLink(request)
def get_hooks(self, session_id):
@ -485,7 +542,9 @@ class CoreGrpcClient(object):
:rtype: core_pb2.GetMobilityConfigResponse
:raises grpc.RpcError: when session or node doesn't exist
"""
request = core_pb2.GetMobilityConfigRequest(session_id=session_id, node_id=node_id)
request = core_pb2.GetMobilityConfigRequest(
session_id=session_id, node_id=node_id
)
return self.stub.GetMobilityConfig(request)
def set_mobility_config(self, session_id, node_id, config):
@ -499,7 +558,9 @@ class CoreGrpcClient(object):
:rtype: core_pb2.SetMobilityConfigResponse
:raises grpc.RpcError: when session or node doesn't exist
"""
request = core_pb2.SetMobilityConfigRequest(session_id=session_id, node_id=node_id, config=config)
request = core_pb2.SetMobilityConfigRequest(
session_id=session_id, node_id=node_id, config=config
)
return self.stub.SetMobilityConfig(request)
def mobility_action(self, session_id, node_id, action):
@ -513,7 +574,9 @@ class CoreGrpcClient(object):
:rtype: core_pb2.MobilityActionResponse
:raises grpc.RpcError: when session or node doesn't exist
"""
request = core_pb2.MobilityActionRequest(session_id=session_id, node_id=node_id, action=action)
request = core_pb2.MobilityActionRequest(
session_id=session_id, node_id=node_id, action=action
)
return self.stub.MobilityAction(request)
def get_services(self):
@ -553,7 +616,9 @@ class CoreGrpcClient(object):
services = service_defaults[node_type]
default = core_pb2.ServiceDefaults(node_type=node_type, services=services)
defaults.append(default)
request = core_pb2.SetServiceDefaultsRequest(session_id=session_id, defaults=defaults)
request = core_pb2.SetServiceDefaultsRequest(
session_id=session_id, defaults=defaults
)
return self.stub.SetServiceDefaults(request)
def get_node_service(self, session_id, node_id, service):
@ -567,7 +632,9 @@ class CoreGrpcClient(object):
:rtype: core_pb2.GetNodeServiceResponse
:raises grpc.RpcError: when session or node doesn't exist
"""
request = core_pb2.GetNodeServiceRequest(session_id=session_id, node_id=node_id, service=service)
request = core_pb2.GetNodeServiceRequest(
session_id=session_id, node_id=node_id, service=service
)
return self.stub.GetNodeService(request)
def get_node_service_file(self, session_id, node_id, service, file_name):
@ -583,10 +650,13 @@ class CoreGrpcClient(object):
:raises grpc.RpcError: when session or node doesn't exist
"""
request = core_pb2.GetNodeServiceFileRequest(
session_id=session_id, node_id=node_id, service=service, file=file_name)
session_id=session_id, node_id=node_id, service=service, file=file_name
)
return self.stub.GetNodeServiceFile(request)
def set_node_service(self, session_id, node_id, service, startup, validate, shutdown):
def set_node_service(
self, session_id, node_id, service, startup, validate, shutdown
):
"""
Set service data for a node.
@ -601,8 +671,13 @@ class CoreGrpcClient(object):
:raises grpc.RpcError: when session or node doesn't exist
"""
request = core_pb2.SetNodeServiceRequest(
session_id=session_id, node_id=node_id, service=service, startup=startup, validate=validate,
shutdown=shutdown)
session_id=session_id,
node_id=node_id,
service=service,
startup=startup,
validate=validate,
shutdown=shutdown,
)
return self.stub.SetNodeService(request)
def set_node_service_file(self, session_id, node_id, service, file_name, data):
@ -619,7 +694,12 @@ class CoreGrpcClient(object):
:raises grpc.RpcError: when session or node doesn't exist
"""
request = core_pb2.SetNodeServiceFileRequest(
session_id=session_id, node_id=node_id, service=service, file=file_name, data=data)
session_id=session_id,
node_id=node_id,
service=service,
file=file_name,
data=data,
)
return self.stub.SetNodeServiceFile(request)
def service_action(self, session_id, node_id, service, action):
@ -634,7 +714,9 @@ class CoreGrpcClient(object):
:rtype: core_pb2.ServiceActionResponse
:raises grpc.RpcError: when session or node doesn't exist
"""
request = core_pb2.ServiceActionRequest(session_id=session_id, node_id=node_id, service=service, action=action)
request = core_pb2.ServiceActionRequest(
session_id=session_id, node_id=node_id, service=service, action=action
)
return self.stub.ServiceAction(request)
def get_wlan_config(self, session_id, node_id):
@ -661,7 +743,9 @@ class CoreGrpcClient(object):
:rtype: core_pb2.SetWlanConfigResponse
:raises grpc.RpcError: when session doesn't exist
"""
request = core_pb2.SetWlanConfigRequest(session_id=session_id, node_id=node_id, config=config)
request = core_pb2.SetWlanConfigRequest(
session_id=session_id, node_id=node_id, config=config
)
return self.stub.SetWlanConfig(request)
def get_emane_config(self, session_id):
@ -714,10 +798,13 @@ class CoreGrpcClient(object):
:raises grpc.RpcError: when session doesn't exist
"""
request = core_pb2.GetEmaneModelConfigRequest(
session_id=session_id, node_id=node_id, model=model, interface=interface_id)
session_id=session_id, node_id=node_id, model=model, interface=interface_id
)
return self.stub.GetEmaneModelConfig(request)
def set_emane_model_config(self, session_id, node_id, model, config, interface_id=-1):
def set_emane_model_config(
self, session_id, node_id, model, config, interface_id=-1
):
"""
Set emane model configuration for a node or a node's interface.
@ -731,7 +818,12 @@ class CoreGrpcClient(object):
:raises grpc.RpcError: when session doesn't exist
"""
request = core_pb2.SetEmaneModelConfigRequest(
session_id=session_id, node_id=node_id, model=model, config=config, interface_id=interface_id)
session_id=session_id,
node_id=node_id,
model=model,
config=config,
interface_id=interface_id,
)
return self.stub.SetEmaneModelConfig(request)
def get_emane_model_configs(self, session_id):

View file

@ -11,7 +11,14 @@ from queue import Empty, Queue
import grpc
from core.api.grpc import core_pb2, core_pb2_grpc
from core.emulator.data import ConfigData, EventData, ExceptionData, FileData, LinkData, NodeData
from core.emulator.data import (
ConfigData,
EventData,
ExceptionData,
FileData,
LinkData,
NodeData,
)
from core.emulator.emudata import InterfaceData, LinkOptions, NodeOptions
from core.emulator.enumerations import EventTypes, LinkTypes, NodeTypes
from core.location.mobility import BasicRangeModel, Ns2ScriptedMobility
@ -49,8 +56,10 @@ def get_config_groups(config, configurable_options):
for config_group in configurable_options.config_groups():
start = config_group.start - 1
stop = config_group.stop
options = config_options[start: stop]
config_group_proto = core_pb2.ConfigGroup(name=config_group.name, options=options)
options = config_options[start:stop]
config_group_proto = core_pb2.ConfigGroup(
name=config_group.name, options=options
)
groups.append(config_group_proto)
return groups
@ -80,9 +89,14 @@ def convert_link(session, link_data):
interface = node.netif(link_data.interface1_id)
interface_name = interface.name
interface_one = core_pb2.Interface(
id=link_data.interface1_id, name=interface_name, mac=convert_value(link_data.interface1_mac),
ip4=convert_value(link_data.interface1_ip4), ip4mask=link_data.interface1_ip4_mask,
ip6=convert_value(link_data.interface1_ip6), ip6mask=link_data.interface1_ip6_mask)
id=link_data.interface1_id,
name=interface_name,
mac=convert_value(link_data.interface1_mac),
ip4=convert_value(link_data.interface1_ip4),
ip4mask=link_data.interface1_ip4_mask,
ip6=convert_value(link_data.interface1_ip6),
ip6mask=link_data.interface1_ip6_mask,
)
interface_two = None
if link_data.interface2_id is not None:
@ -92,9 +106,14 @@ def convert_link(session, link_data):
interface = node.netif(link_data.interface2_id)
interface_name = interface.name
interface_two = core_pb2.Interface(
id=link_data.interface2_id, name=interface_name, mac=convert_value(link_data.interface2_mac),
ip4=convert_value(link_data.interface2_ip4), ip4mask=link_data.interface2_ip4_mask,
ip6=convert_value(link_data.interface2_ip6), ip6mask=link_data.interface2_ip6_mask)
id=link_data.interface2_id,
name=interface_name,
mac=convert_value(link_data.interface2_mac),
ip4=convert_value(link_data.interface2_ip4),
ip4mask=link_data.interface2_ip4_mask,
ip6=convert_value(link_data.interface2_ip6),
ip6mask=link_data.interface2_ip6_mask,
)
options = core_pb2.LinkOptions(
opaque=link_data.opaque,
@ -107,12 +126,16 @@ def convert_link(session, link_data):
burst=link_data.burst,
delay=link_data.delay,
dup=link_data.dup,
unidirectional=link_data.unidirectional
unidirectional=link_data.unidirectional,
)
return core_pb2.Link(
type=link_data.link_type, node_one_id=link_data.node1_id, node_two_id=link_data.node2_id,
interface_one=interface_one, interface_two=interface_two, options=options
type=link_data.link_type,
node_one_id=link_data.node1_id,
node_two_id=link_data.node2_id,
interface_one=interface_one,
interface_two=interface_two,
options=options,
)
@ -166,14 +189,18 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
def get_session(self, session_id, context):
session = self.coreemu.sessions.get(session_id)
if not session:
context.abort(grpc.StatusCode.NOT_FOUND, "session {} not found".format(session_id))
context.abort(
grpc.StatusCode.NOT_FOUND, "session {} not found".format(session_id)
)
return session
def get_node(self, session, node_id, context):
try:
return session.get_node(node_id)
except KeyError:
context.abort(grpc.StatusCode.NOT_FOUND, "node {} not found".format(node_id))
context.abort(
grpc.StatusCode.NOT_FOUND, "node {} not found".format(node_id)
)
def CreateSession(self, request, context):
logging.debug("create session: %s", request)
@ -181,7 +208,9 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
session.set_state(EventTypes.DEFINITION_STATE)
session.location.setrefgeo(47.57917, -122.13232, 2.0)
session.location.refscale = 150000.0
return core_pb2.CreateSessionResponse(session_id=session.id, state=session.state)
return core_pb2.CreateSessionResponse(
session_id=session.id, state=session.state
)
def DeleteSession(self, request, context):
logging.debug("delete session: %s", request)
@ -194,7 +223,8 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
for session_id in self.coreemu.sessions:
session = self.coreemu.sessions[session_id]
session_summary = core_pb2.SessionSummary(
id=session_id, state=session.state, nodes=session.get_node_count())
id=session_id, state=session.state, nodes=session.get_node_count()
)
sessions.append(session_summary)
return core_pb2.GetSessionsResponse(sessions=sessions)
@ -204,13 +234,21 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
x, y, z = session.location.refxyz
lat, lon, alt = session.location.refgeo
position = core_pb2.SessionPosition(x=x, y=y, z=z, lat=lat, lon=lon, alt=alt)
return core_pb2.GetSessionLocationResponse(position=position, scale=session.location.refscale)
return core_pb2.GetSessionLocationResponse(
position=position, scale=session.location.refscale
)
def SetSessionLocation(self, request, context):
logging.debug("set session location: %s", request)
session = self.get_session(request.session_id, context)
session.location.refxyz = (request.position.x, request.position.y, request.position.z)
session.location.setrefgeo(request.position.lat, request.position.lon, request.position.alt)
session.location.refxyz = (
request.position.x,
request.position.y,
request.position.z,
)
session.location.setrefgeo(
request.position.lat, request.position.lon, request.position.alt
)
session.location.refscale = request.scale
return core_pb2.SetSessionLocationResponse(result=True)
@ -268,7 +306,9 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
node_type = nodeutils.get_node_type(node.__class__).value
model = getattr(node, "type", None)
position = core_pb2.Position(x=node.position.x, y=node.position.y, z=node.position.z)
position = core_pb2.Position(
x=node.position.x, y=node.position.y, z=node.position.z
)
services = getattr(node, "services", [])
if services is None:
@ -280,8 +320,14 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
emane_model = node.model.name
node_proto = core_pb2.Node(
id=node.id, name=node.name, emane=emane_model, model=model,
type=node_type, position=position, services=services)
id=node.id,
name=node.name,
emane=emane_model,
model=model,
type=node_type,
position=position,
services=services,
)
if isinstance(node, (DockerNode, LxcNode)):
node_proto.image = node.image
nodes.append(node_proto)
@ -341,23 +387,38 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
services = event.services or ""
services = services.split("|")
node_proto = core_pb2.Node(
id=event.id, name=event.name, model=event.model, position=position, services=services)
id=event.id,
name=event.name,
model=event.model,
position=position,
services=services,
)
return core_pb2.NodeEvent(node=node_proto)
def _handle_link_event(self, event):
interface_one = None
if event.interface1_id is not None:
interface_one = core_pb2.Interface(
id=event.interface1_id, name=event.interface1_name, mac=convert_value(event.interface1_mac),
ip4=convert_value(event.interface1_ip4), ip4mask=event.interface1_ip4_mask,
ip6=convert_value(event.interface1_ip6), ip6mask=event.interface1_ip6_mask)
id=event.interface1_id,
name=event.interface1_name,
mac=convert_value(event.interface1_mac),
ip4=convert_value(event.interface1_ip4),
ip4mask=event.interface1_ip4_mask,
ip6=convert_value(event.interface1_ip6),
ip6mask=event.interface1_ip6_mask,
)
interface_two = None
if event.interface2_id is not None:
interface_two = core_pb2.Interface(
id=event.interface2_id, name=event.interface2_name, mac=convert_value(event.interface2_mac),
ip4=convert_value(event.interface2_ip4), ip4mask=event.interface2_ip4_mask,
ip6=convert_value(event.interface2_ip6), ip6mask=event.interface2_ip6_mask)
id=event.interface2_id,
name=event.interface2_name,
mac=convert_value(event.interface2_mac),
ip4=convert_value(event.interface2_ip4),
ip4mask=event.interface2_ip4_mask,
ip6=convert_value(event.interface2_ip6),
ip6mask=event.interface2_ip6_mask,
)
options = core_pb2.LinkOptions(
opaque=event.opaque,
@ -370,11 +431,16 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
burst=event.burst,
delay=event.delay,
dup=event.dup,
unidirectional=event.unidirectional
unidirectional=event.unidirectional,
)
link = core_pb2.Link(
type=event.link_type, node_one_id=event.node1_id, node_two_id=event.node2_id,
interface_one=interface_one, interface_two=interface_two, options=options)
type=event.link_type,
node_one_id=event.node1_id,
node_two_id=event.node2_id,
interface_one=interface_one,
interface_two=interface_two,
options=options,
)
return core_pb2.LinkEvent(message_type=event.message_type, link=link)
def _handle_session_event(self, event):
@ -387,7 +453,7 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
name=event.name,
data=event.data,
time=event_time,
session_id=event.session
session_id=event.session,
)
def _handle_config_event(self, event):
@ -408,7 +474,7 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
interface=event.interface_number,
network_id=event.network_id,
opaque=event.opaque,
data_types=event.data_types
data_types=event.data_types,
)
def _handle_exception_event(self, event):
@ -419,7 +485,7 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
source=event.source,
date=event.date,
text=event.text,
opaque=event.opaque
opaque=event.opaque,
)
def _handle_file_event(self, event):
@ -433,7 +499,7 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
source=event.source,
session_id=event.session,
data=event.data,
compressed_data=event.compressed_data
compressed_data=event.compressed_data,
)
def Throughputs(self, request, context):
@ -453,21 +519,29 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
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
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
if key.startswith("veth"):
key = key.split(".")
node_id = int(_INTERFACE_REGEX.search(key[0]).group())
interface_id = int(key[1])
interface_throughput = throughputs_event.interface_throughputs.add()
interface_throughput = (
throughputs_event.interface_throughputs.add()
)
interface_throughput.node_id = node_id
interface_throughput.interface_id = interface_id
interface_throughput.throughput = throughput
elif key.startswith("b."):
try:
node_id = int(key.split(".")[1])
bridge_throughput = throughputs_event.bridge_throughputs.add()
bridge_throughput = (
throughputs_event.bridge_throughputs.add()
)
bridge_throughput.node_id = node_id
bridge_throughput.throughput = throughput
except ValueError:
@ -520,8 +594,13 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
if interface.net:
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)
id=interface_id,
netid=net_id,
name=interface.name,
mac=str(interface.hwaddr),
mtu=interface.mtu,
flowid=interface.flow_id,
)
interfaces.append(interface_proto)
emane_model = None
@ -529,11 +608,19 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
emane_model = node.model.name
services = [x.name for x in getattr(node, "services", [])]
position = core_pb2.Position(x=node.position.x, y=node.position.y, z=node.position.z)
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_proto = core_pb2.Node(
id=node.id, name=node.name, type=node_type, emane=emane_model, model=node.type, position=position,
services=services)
id=node.id,
name=node.name,
type=node_type,
emane=emane_model,
model=node.type,
position=position,
services=services,
)
if isinstance(node, (DockerNode, LxcNode)):
node_proto.image = node.image
@ -653,7 +740,13 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
link_options.key = options_data.key
link_options.opaque = options_data.opaque
session.add_link(node_one_id, node_two_id, interface_one, interface_two, link_options=link_options)
session.add_link(
node_one_id,
node_two_id,
interface_one,
interface_two,
link_options=link_options,
)
return core_pb2.AddLinkResponse(result=True)
def EditLink(self, request, context):
@ -676,7 +769,9 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
link_options.unidirectional = options_data.unidirectional
link_options.key = options_data.key
link_options.opaque = options_data.opaque
session.update_link(node_one_id, node_two_id, interface_one_id, interface_two_id, link_options)
session.update_link(
node_one_id, node_two_id, interface_one_id, interface_two_id, link_options
)
return core_pb2.EditLinkResponse(result=True)
def DeleteLink(self, request, context):
@ -686,7 +781,9 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
node_two_id = request.node_two_id
interface_one_id = request.interface_one_id
interface_two_id = request.interface_two_id
session.delete_link(node_one_id, node_two_id, interface_one_id, interface_two_id)
session.delete_link(
node_one_id, node_two_id, interface_one_id, interface_two_id
)
return core_pb2.DeleteLinkResponse(result=True)
def GetHooks(self, request, context):
@ -726,14 +823,18 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
def GetMobilityConfig(self, request, context):
logging.debug("get mobility config: %s", request)
session = self.get_session(request.session_id, context)
config = session.mobility.get_model_config(request.node_id, Ns2ScriptedMobility.name)
config = session.mobility.get_model_config(
request.node_id, Ns2ScriptedMobility.name
)
groups = get_config_groups(config, Ns2ScriptedMobility)
return core_pb2.GetMobilityConfigResponse(groups=groups)
def SetMobilityConfig(self, request, context):
logging.debug("set mobility config: %s", request)
session = self.get_session(request.session_id, context)
session.mobility.set_model_config(request.node_id, Ns2ScriptedMobility.name, request.config)
session.mobility.set_model_config(
request.node_id, Ns2ScriptedMobility.name, request.config
)
return core_pb2.SetMobilityConfigResponse(result=True)
def MobilityAction(self, request, context):
@ -766,7 +867,9 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
all_service_defaults = []
for node_type in session.services.default_services:
services = session.services.default_services[node_type]
service_defaults = core_pb2.ServiceDefaults(node_type=node_type, services=services)
service_defaults = core_pb2.ServiceDefaults(
node_type=node_type, services=services
)
all_service_defaults.append(service_defaults)
return core_pb2.GetServiceDefaultsResponse(defaults=all_service_defaults)
@ -775,13 +878,17 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
session = self.get_session(request.session_id, context)
session.services.default_services.clear()
for service_defaults in request.defaults:
session.services.default_services[service_defaults.node_type] = service_defaults.services
session.services.default_services[
service_defaults.node_type
] = service_defaults.services
return core_pb2.SetServiceDefaultsResponse(result=True)
def GetNodeService(self, request, context):
logging.debug("get node service: %s", request)
session = self.get_session(request.session_id, context)
service = session.services.get_service(request.node_id, request.service, default_service=True)
service = session.services.get_service(
request.node_id, request.service, default_service=True
)
service_proto = core_pb2.NodeServiceData(
executables=service.executables,
dependencies=service.dependencies,
@ -792,7 +899,7 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
validation_mode=service.validation_mode.value,
validation_timer=service.validation_timer,
shutdown=service.shutdown,
meta=service.meta
meta=service.meta,
)
return core_pb2.GetNodeServiceResponse(service=service_proto)
@ -807,7 +914,9 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
break
if not service:
context.abort(grpc.StatusCode.NOT_FOUND, "service not found")
file_data = session.services.get_service_file(node, request.service, request.file)
file_data = session.services.get_service_file(
node, request.service, request.file
)
return core_pb2.GetNodeServiceFileResponse(data=file_data.data)
def SetNodeService(self, request, context):
@ -823,7 +932,9 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
def SetNodeServiceFile(self, request, context):
logging.debug("set node service file: %s", request)
session = self.get_session(request.session_id, context)
session.services.set_service_file(request.node_id, request.service, request.file, request.data)
session.services.set_service_file(
request.node_id, request.service, request.file, request.data
)
return core_pb2.SetNodeServiceFileResponse(result=True)
def ServiceAction(self, request, context):
@ -860,14 +971,18 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
def GetWlanConfig(self, request, context):
logging.debug("get wlan config: %s", request)
session = self.get_session(request.session_id, context)
config = session.mobility.get_model_config(request.node_id, BasicRangeModel.name)
config = session.mobility.get_model_config(
request.node_id, BasicRangeModel.name
)
groups = get_config_groups(config, BasicRangeModel)
return core_pb2.GetWlanConfigResponse(groups=groups)
def SetWlanConfig(self, request, context):
logging.debug("set wlan config: %s", request)
session = self.get_session(request.session_id, context)
session.mobility.set_model_config(request.node_id, BasicRangeModel.name, request.config)
session.mobility.set_model_config(
request.node_id, BasicRangeModel.name, request.config
)
if session.state == EventTypes.RUNTIME_STATE.value:
node = self.get_node(session, request.node_id, context)
node.updatemodel(request.config)
@ -963,7 +1078,11 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
def GetInterfaces(self, request, context):
interfaces = []
for interface in os.listdir("/sys/class/net"):
if interface.startswith("b.") or interface.startswith("veth") or interface == "lo":
if (
interface.startswith("b.")
or interface.startswith("veth")
or interface == "lo"
):
continue
interfaces.append(interface)
return core_pb2.GetInterfacesResponse(interfaces=interfaces)

View file

@ -149,7 +149,12 @@ class CoreBroker(object):
while len(self.servers) > 0:
name, server = self.servers.popitem()
if server.sock is not None:
logging.info("closing connection with %s: %s:%s", name, server.host, server.port)
logging.info(
"closing connection with %s: %s:%s",
name,
server.host,
server.port,
)
server.close()
self.dorecvloop = False
if self.recvthread is not None:
@ -210,14 +215,22 @@ class CoreBroker(object):
r, _w, _x = select.select(rlist, [], [], 1.0)
for sock in r:
server = self.getserverbysock(sock)
logging.info("attempting to receive from server: peer:%s remote:%s",
server.sock.getpeername(), server.sock.getsockname())
logging.info(
"attempting to receive from server: peer:%s remote:%s",
server.sock.getpeername(),
server.sock.getsockname(),
)
if server is None:
# servers may have changed; loop again
continue
rcvlen = self.recv(server)
if rcvlen == 0:
logging.info("connection with server(%s) closed: %s:%s", server.name, server.host, server.port)
logging.info(
"connection with server(%s) closed: %s:%s",
server.name,
server.host,
server.port,
)
def recv(self, server):
"""
@ -238,7 +251,9 @@ class CoreBroker(object):
return 0
if len(msghdr) != coreapi.CoreMessage.header_len:
logging.warning("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)
@ -295,11 +310,17 @@ class CoreBroker(object):
with self.servers_lock:
server = self.servers.get(name)
if server is not None:
if host == server.host and port == server.port and server.sock is not None:
if (
host == server.host
and port == server.port
and server.sock is not None
):
# leave this socket connected
return
logging.info("closing connection with %s @ %s:%s", name, server.host, server.port)
logging.info(
"closing connection with %s @ %s:%s", name, server.host, server.port
)
server.close()
del self.servers[name]
@ -309,7 +330,9 @@ class CoreBroker(object):
try:
server.connect()
except IOError:
logging.exception("error connecting to server(%s): %s:%s", name, host, port)
logging.exception(
"error connecting to server(%s): %s:%s", name, host, port
)
if server.sock is not None:
self.startrecvloop()
self.servers[name] = server
@ -330,7 +353,12 @@ class CoreBroker(object):
logging.exception("error deleting server")
if server.sock is not None:
logging.info("closing connection with %s @ %s:%s", server.name, server.host, server.port)
logging.info(
"closing connection with %s @ %s:%s",
server.name,
server.host,
server.port,
)
server.close()
def getserverbyname(self, name):
@ -416,16 +444,31 @@ class CoreBroker(object):
remotenum = n2num
if key in self.tunnels.keys():
logging.warning("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:
_id = key & ((1 << 16) - 1)
logging.info("adding tunnel for %s-%s to %s with key %s", n1num, n2num, remoteip, key)
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)
gt = GreTap(
node=None,
name=None,
session=self.session,
remoteip=remoteip,
key=key,
)
else:
gt = self.session.create_node(cls=GreTapBridge, _id=_id, 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
@ -459,8 +502,13 @@ class CoreBroker(object):
return None
server_interface = getattr(net, "serverintf", None)
if nodeutils.is_node(net, NodeTypes.CONTROL_NET) and server_interface is not None:
logging.warning("control networks with server interfaces do not need a tunnel")
if (
nodeutils.is_node(net, NodeTypes.CONTROL_NET)
and server_interface is not None
):
logging.warning(
"control networks with server interfaces do not need a tunnel"
)
return None
servers = self.getserversbynode(node_id)
@ -493,12 +541,18 @@ class CoreBroker(object):
myip = host
key = self.tunnelkey(node_id, IpAddress.to_int(myip))
if key in self.tunnels.keys():
logging.info("tunnel already exists, returning existing tunnel: %s", key)
logging.info(
"tunnel already exists, returning existing tunnel: %s", key
)
gt = self.tunnels[key]
r.append(gt)
continue
logging.info("adding tunnel for net %s to %s with key %s", node_id, host, key)
gt = GreTap(node=None, name=None, session=self.session, remoteip=host, key=key)
logging.info(
"adding tunnel for net %s to %s with key %s", node_id, host, key
)
gt = GreTap(
node=None, name=None, session=self.session, remoteip=host, key=key
)
self.tunnels[key] = gt
r.append(gt)
# attaching to net will later allow gt to be destroyed
@ -517,7 +571,9 @@ class CoreBroker(object):
"""
key = self.tunnelkey(n1num, n2num)
try:
logging.info("deleting tunnel between %s - %s with key: %s", n1num, n2num, key)
logging.info(
"deleting tunnel between %s - %s with key: %s", n1num, n2num, key
)
gt = self.tunnels.pop(key)
except KeyError:
gt = None
@ -645,12 +701,19 @@ class CoreBroker(object):
elif message.message_type == MessageTypes.CONFIG.value:
# broadcast location and services configuration everywhere
confobj = message.get_tlv(ConfigTlvs.OBJECT.value)
if confobj == "location" or confobj == "services" or confobj == "session" or confobj == "all":
if (
confobj == "location"
or confobj == "services"
or confobj == "session"
or confobj == "all"
):
servers = self.getservers()
elif message.message_type == MessageTypes.FILE.value:
# broadcast hook scripts and custom service files everywhere
filetype = message.get_tlv(FileTlvs.TYPE.value)
if filetype is not None and (filetype[:5] == "hook:" or filetype[:8] == "service:"):
if filetype is not None and (
filetype[:5] == "hook:" or filetype[:8] == "service:"
):
servers = self.getservers()
if message.message_type == MessageTypes.LINK.value:
# prepare a server list from two node numbers in link message
@ -697,11 +760,19 @@ class CoreBroker(object):
# server of its local name
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,))
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.VALUES.value,
"%s:%s:%s" % (server.name, server.host, server.port))
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.SESSION.value, "%s" % self.session.id)
tlvdata += coreapi.CoreConfigTlv.pack(
ConfigTlvs.TYPE.value, ConfigFlags.UPDATE.value
)
tlvdata += coreapi.CoreConfigTlv.pack(
ConfigTlvs.DATA_TYPES.value, (ConfigDataTypes.STRING.value,)
)
tlvdata += coreapi.CoreConfigTlv.pack(
ConfigTlvs.VALUES.value,
"%s:%s:%s" % (server.name, server.host, server.port),
)
tlvdata += coreapi.CoreConfigTlv.pack(
ConfigTlvs.SESSION.value, "%s" % self.session.id
)
msg = coreapi.CoreConfMessage.pack(0, tlvdata)
server.sock.send(msg)
@ -762,7 +833,10 @@ class CoreBroker(object):
if nodecls is None:
logging.warning("broker unimplemented node type %s", nodetype)
return handle_locally, servers
if issubclass(nodecls, CoreNetworkBase) 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()
@ -812,7 +886,9 @@ class CoreBroker(object):
# determine link message destination using non-network nodes
nn = message.node_numbers()
logging.debug("checking link nodes (%s) with network nodes (%s)", nn, self.network_nodes)
logging.debug(
"checking link nodes (%s) with network nodes (%s)", nn, self.network_nodes
)
if nn[0] in self.network_nodes:
if nn[1] in self.network_nodes:
# two network nodes linked together - prevent loops caused by
@ -856,7 +932,9 @@ class CoreBroker(object):
if host is None:
host = self.getlinkendpoint(message, localn == nn[0])
logging.debug("handle locally(%s) and local node(%s)", handle_locally, localn)
logging.debug(
"handle locally(%s) and local node(%s)", handle_locally, localn
)
if localn is None:
message = self.addlinkendpoints(message, servers1, servers2)
elif message.flags & MessageFlags.ADD.value:
@ -891,10 +969,10 @@ class CoreBroker(object):
if server.host is not None:
ip2 = server.host
break
tlvdata = message.raw_message[coreapi.CoreMessage.header_len:]
tlvdata = message.raw_message[coreapi.CoreMessage.header_len :]
tlvdata += coreapi.CoreLinkTlv.pack(LinkTlvs.OPAQUE.value, "%s:%s" % (ip1, ip2))
newraw = coreapi.CoreLinkMessage.pack(message.flags, tlvdata)
msghdr = newraw[:coreapi.CoreMessage.header_len]
msghdr = newraw[: coreapi.CoreMessage.header_len]
return coreapi.CoreLinkMessage(message.flags, msghdr, tlvdata)
def getlinkendpoint(self, msg, first_is_local):
@ -936,10 +1014,12 @@ class CoreBroker(object):
:return: should handle locally or not
:rtype: bool
"""
hdr = msg[:coreapi.CoreMessage.header_len]
hdr = msg[: coreapi.CoreMessage.header_len]
msgtype, flags, _msglen = coreapi.CoreMessage.unpack_header(hdr)
msgcls = coreapi.CLASS_MAP[msgtype]
return self.handle_message(msgcls(flags, hdr, msg[coreapi.CoreMessage.header_len:]))
return self.handle_message(
msgcls(flags, hdr, msg[coreapi.CoreMessage.header_len :])
)
def forwardmsg(self, message, servers):
"""
@ -959,9 +1039,19 @@ class CoreBroker(object):
# local emulation server, handle this locally
handle_locally = True
elif server.sock is None:
logging.info("server %s @ %s:%s is disconnected", server.name, server.host, server.port)
logging.info(
"server %s @ %s:%s is disconnected",
server.name,
server.host,
server.port,
)
else:
logging.info("forwarding message to server(%s): %s:%s", server.name, server.host, server.port)
logging.info(
"forwarding message to server(%s): %s:%s",
server.name,
server.host,
server.port,
)
logging.debug("message being forwarded:\n%s", message)
server.sock.send(message.raw_message)
return handle_locally
@ -988,7 +1078,10 @@ class CoreBroker(object):
lhost, lport = None, None
if server.sock:
lhost, lport = server.sock.getsockname()
f.write("%s %s %s %s %s\n" % (server.name, server.host, server.port, lhost, lport))
f.write(
"%s %s %s %s %s\n"
% (server.name, server.host, server.port, lhost, lport)
)
except IOError:
logging.exception("error writing server list to the file: %s", filename)
@ -1017,7 +1110,9 @@ class CoreBroker(object):
with open(filename, "w") as f:
f.write("%s\n%s\n" % (serverstr, nodestr))
except IOError:
logging.exception("error writing server file %s for node %s", filename, name)
logging.exception(
"error writing server file %s for node %s", filename, name
)
def local_instantiation_complete(self):
"""
@ -1033,7 +1128,9 @@ class CoreBroker(object):
# broadcast out instantiate complete
tlvdata = b""
tlvdata += coreapi.CoreEventTlv.pack(EventTlvs.TYPE.value, EventTypes.INSTANTIATION_COMPLETE.value)
tlvdata += coreapi.CoreEventTlv.pack(
EventTlvs.TYPE.value, EventTypes.INSTANTIATION_COMPLETE.value
)
message = coreapi.CoreEventMessage.pack(0, tlvdata)
for session_client in self.session_clients:
session_client.sendall(message)

View file

@ -140,6 +140,7 @@ class CoreTlvDataUint16(CoreTlvData):
"""
Helper class for packing uint16 data.
"""
data_format = "!H"
data_type = int
pad_len = 0
@ -149,6 +150,7 @@ class CoreTlvDataUint32(CoreTlvData):
"""
Helper class for packing uint32 data.
"""
data_format = "!2xI"
data_type = int
pad_len = 2
@ -158,6 +160,7 @@ class CoreTlvDataUint64(CoreTlvData):
"""
Helper class for packing uint64 data.
"""
data_format = "!2xQ"
data_type = int
pad_len = 2
@ -167,6 +170,7 @@ class CoreTlvDataString(CoreTlvData):
"""
Helper class for packing string data.
"""
data_type = str
@classmethod
@ -205,6 +209,7 @@ class CoreTlvDataUint16List(CoreTlvData):
"""
List of unsigned 16-bit values.
"""
data_type = tuple
data_format = "!H"
@ -254,6 +259,7 @@ class CoreTlvDataIpv4Addr(CoreTlvDataObj):
"""
Utility class for packing/unpacking Ipv4 addresses.
"""
data_type = IpAddress.from_string
data_format = "!2x4s"
pad_len = 2
@ -284,6 +290,7 @@ class CoreTlvDataIPv6Addr(CoreTlvDataObj):
"""
Utility class for packing/unpacking Ipv6 addresses.
"""
data_format = "!16s2x"
data_type = IpAddress.from_string
pad_len = 2
@ -314,6 +321,7 @@ class CoreTlvDataMacAddr(CoreTlvDataObj):
"""
Utility class for packing/unpacking mac addresses.
"""
data_format = "!2x8s"
data_type = MacAddress.from_string
pad_len = 2
@ -346,6 +354,7 @@ class CoreTlv(object):
"""
Base class for representing CORE TLVs.
"""
header_format = "!BB"
header_len = struct.calcsize(header_format)
@ -380,10 +389,12 @@ class CoreTlv(object):
:param data: data to unpack
:return: unpacked data class
"""
tlv_type, tlv_len = struct.unpack(cls.header_format, data[:cls.header_len])
tlv_type, tlv_len = struct.unpack(cls.header_format, data[: cls.header_len])
header_len = cls.header_len
if tlv_len == 0:
tlv_type, _zero, tlv_len = struct.unpack(cls.long_header_format, data[:cls.long_header_len])
tlv_type, _zero, tlv_len = struct.unpack(
cls.long_header_format, data[: cls.long_header_len]
)
header_len = cls.long_header_len
tlv_size = header_len + tlv_len
# for 32-bit alignment
@ -436,7 +447,11 @@ class CoreTlv(object):
:return: string representation
:rtype: str
"""
return "%s <tlvtype = %s, value = %s>" % (self.__class__.__name__, self.type_str(), self.value)
return "%s <tlvtype = %s, value = %s>" % (
self.__class__.__name__,
self.type_str(),
self.value,
)
class CoreNodeTlv(CoreTlv):
@ -687,14 +702,16 @@ class CoreMessage(object):
:return: unpacked tuple
:rtype: tuple
"""
message_type, message_flags, message_len = struct.unpack(cls.header_format, data[:cls.header_len])
message_type, message_flags, message_len = struct.unpack(
cls.header_format, data[: cls.header_len]
)
return message_type, message_flags, message_len
@classmethod
def create(cls, flags, values):
tlv_data = structutils.pack_values(cls.tlv_class, values)
packed = cls.pack(flags, tlv_data)
header_data = packed[:cls.header_len]
header_data = packed[: cls.header_len]
return cls(flags, header_data, tlv_data)
@classmethod
@ -706,7 +723,9 @@ class CoreMessage(object):
:param tlv_data: data to get length from for packing
:return: combined header and tlv data
"""
header = struct.pack(cls.header_format, cls.message_type, message_flags, len(tlv_data))
header = struct.pack(
cls.header_format, cls.message_type, message_flags, len(tlv_data)
)
return header + tlv_data
def add_tlv_data(self, key, value):
@ -808,7 +827,11 @@ class CoreMessage(object):
:return: string representation
:rtype: str
"""
result = "%s <msgtype = %s, flags = %s>" % (self.__class__.__name__, self.type_str(), self.flag_str())
result = "%s <msgtype = %s, flags = %s>" % (
self.__class__.__name__,
self.type_str(),
self.flag_str(),
)
for key in self.tlv_data:
value = self.tlv_data[key]
@ -880,6 +903,7 @@ class CoreNodeMessage(CoreMessage):
"""
CORE node message class.
"""
message_type = MessageTypes.NODE.value
tlv_class = CoreNodeTlv
@ -888,6 +912,7 @@ class CoreLinkMessage(CoreMessage):
"""
CORE link message class.
"""
message_type = MessageTypes.LINK.value
tlv_class = CoreLinkTlv
@ -896,6 +921,7 @@ class CoreExecMessage(CoreMessage):
"""
CORE execute message class.
"""
message_type = MessageTypes.EXECUTE.value
tlv_class = CoreExecuteTlv
@ -904,6 +930,7 @@ class CoreRegMessage(CoreMessage):
"""
CORE register message class.
"""
message_type = MessageTypes.REGISTER.value
tlv_class = CoreRegisterTlv
@ -912,6 +939,7 @@ class CoreConfMessage(CoreMessage):
"""
CORE configuration message class.
"""
message_type = MessageTypes.CONFIG.value
tlv_class = CoreConfigTlv
@ -920,6 +948,7 @@ class CoreFileMessage(CoreMessage):
"""
CORE file message class.
"""
message_type = MessageTypes.FILE.value
tlv_class = CoreFileTlv
@ -928,6 +957,7 @@ class CoreIfaceMessage(CoreMessage):
"""
CORE interface message class.
"""
message_type = MessageTypes.INTERFACE.value
tlv_class = CoreInterfaceTlv
@ -936,6 +966,7 @@ class CoreEventMessage(CoreMessage):
"""
CORE event message class.
"""
message_type = MessageTypes.EVENT.value
tlv_class = CoreEventTlv
@ -944,6 +975,7 @@ class CoreSessionMessage(CoreMessage):
"""
CORE session message class.
"""
message_type = MessageTypes.SESSION.value
tlv_class = CoreSessionTlv
@ -952,6 +984,7 @@ class CoreExceptionMessage(CoreMessage):
"""
CORE exception message class.
"""
message_type = MessageTypes.EXCEPTION.value
tlv_class = CoreExceptionTlv

File diff suppressed because it is too large Load diff

View file

@ -12,6 +12,7 @@ class CoreServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
TCP server class, manages sessions and spawns request handlers for
incoming connections.
"""
daemon_threads = True
allow_reuse_address = True
@ -34,6 +35,7 @@ class CoreUdpServer(socketserver.ThreadingMixIn, socketserver.UDPServer):
UDP server class, manages sessions and spawns request handlers for
incoming connections.
"""
daemon_threads = True
allow_reuse_address = True

View file

@ -13,28 +13,31 @@ def convert_node(node_data):
:param core.emulator.data.NodeData node_data: node data to convert
:return: packed node message
"""
tlv_data = structutils.pack_values(coreapi.CoreNodeTlv, [
(NodeTlvs.NUMBER, node_data.id),
(NodeTlvs.TYPE, node_data.node_type),
(NodeTlvs.NAME, node_data.name),
(NodeTlvs.IP_ADDRESS, node_data.ip_address),
(NodeTlvs.MAC_ADDRESS, node_data.mac_address),
(NodeTlvs.IP6_ADDRESS, node_data.ip6_address),
(NodeTlvs.MODEL, node_data.model),
(NodeTlvs.EMULATION_ID, node_data.emulation_id),
(NodeTlvs.EMULATION_SERVER, node_data.emulation_server),
(NodeTlvs.SESSION, node_data.session),
(NodeTlvs.X_POSITION, node_data.x_position),
(NodeTlvs.Y_POSITION, node_data.y_position),
(NodeTlvs.CANVAS, node_data.canvas),
(NodeTlvs.NETWORK_ID, node_data.network_id),
(NodeTlvs.SERVICES, node_data.services),
(NodeTlvs.LATITUDE, node_data.latitude),
(NodeTlvs.LONGITUDE, node_data.longitude),
(NodeTlvs.ALTITUDE, node_data.altitude),
(NodeTlvs.ICON, node_data.icon),
(NodeTlvs.OPAQUE, node_data.opaque)
])
tlv_data = structutils.pack_values(
coreapi.CoreNodeTlv,
[
(NodeTlvs.NUMBER, node_data.id),
(NodeTlvs.TYPE, node_data.node_type),
(NodeTlvs.NAME, node_data.name),
(NodeTlvs.IP_ADDRESS, node_data.ip_address),
(NodeTlvs.MAC_ADDRESS, node_data.mac_address),
(NodeTlvs.IP6_ADDRESS, node_data.ip6_address),
(NodeTlvs.MODEL, node_data.model),
(NodeTlvs.EMULATION_ID, node_data.emulation_id),
(NodeTlvs.EMULATION_SERVER, node_data.emulation_server),
(NodeTlvs.SESSION, node_data.session),
(NodeTlvs.X_POSITION, node_data.x_position),
(NodeTlvs.Y_POSITION, node_data.y_position),
(NodeTlvs.CANVAS, node_data.canvas),
(NodeTlvs.NETWORK_ID, node_data.network_id),
(NodeTlvs.SERVICES, node_data.services),
(NodeTlvs.LATITUDE, node_data.latitude),
(NodeTlvs.LONGITUDE, node_data.longitude),
(NodeTlvs.ALTITUDE, node_data.altitude),
(NodeTlvs.ICON, node_data.icon),
(NodeTlvs.OPAQUE, node_data.opaque),
],
)
return coreapi.CoreNodeMessage.pack(node_data.message_type, tlv_data)
@ -45,19 +48,22 @@ def convert_config(config_data):
:param core.emulator.data.ConfigData config_data: config data to convert
:return: packed message
"""
tlv_data = structutils.pack_values(coreapi.CoreConfigTlv, [
(ConfigTlvs.NODE, config_data.node),
(ConfigTlvs.OBJECT, config_data.object),
(ConfigTlvs.TYPE, config_data.type),
(ConfigTlvs.DATA_TYPES, config_data.data_types),
(ConfigTlvs.VALUES, config_data.data_values),
(ConfigTlvs.CAPTIONS, config_data.captions),
(ConfigTlvs.BITMAP, config_data.bitmap),
(ConfigTlvs.POSSIBLE_VALUES, config_data.possible_values),
(ConfigTlvs.GROUPS, config_data.groups),
(ConfigTlvs.SESSION, config_data.session),
(ConfigTlvs.INTERFACE_NUMBER, config_data.interface_number),
(ConfigTlvs.NETWORK_ID, config_data.network_id),
(ConfigTlvs.OPAQUE, config_data.opaque),
])
tlv_data = structutils.pack_values(
coreapi.CoreConfigTlv,
[
(ConfigTlvs.NODE, config_data.node),
(ConfigTlvs.OBJECT, config_data.object),
(ConfigTlvs.TYPE, config_data.type),
(ConfigTlvs.DATA_TYPES, config_data.data_types),
(ConfigTlvs.VALUES, config_data.data_values),
(ConfigTlvs.CAPTIONS, config_data.captions),
(ConfigTlvs.BITMAP, config_data.bitmap),
(ConfigTlvs.POSSIBLE_VALUES, config_data.possible_values),
(ConfigTlvs.GROUPS, config_data.groups),
(ConfigTlvs.SESSION, config_data.session),
(ConfigTlvs.INTERFACE_NUMBER, config_data.interface_number),
(ConfigTlvs.NETWORK_ID, config_data.network_id),
(ConfigTlvs.OPAQUE, config_data.opaque),
],
)
return coreapi.CoreConfMessage.pack(config_data.message_type, tlv_data)

View file

@ -40,7 +40,11 @@ class ConfigShim(object):
"""
group_strings = []
for config_group in config_groups:
group_string = "%s:%s-%s" % (config_group.name, config_group.start, config_group.stop)
group_string = "%s:%s-%s" % (
config_group.name,
config_group.start,
config_group.stop,
)
group_strings.append(group_string)
return "|".join(group_strings)
@ -96,7 +100,7 @@ class ConfigShim(object):
captions=captions,
possible_values="|".join(possible_values),
bitmap=configurable_options.bitmap,
groups=groups_str
groups=groups_str,
)
@ -127,13 +131,19 @@ class Configuration(object):
def __str__(self):
return "%s(id=%s, type=%s, default=%s, options=%s)" % (
self.__class__.__name__, self.id, self.type, self.default, self.options)
self.__class__.__name__,
self.id,
self.type,
self.default,
self.options,
)
class ConfigurableManager(object):
"""
Provides convenience methods for storing and retrieving configuration options for nodes.
"""
_default_node = -1
_default_type = _default_node
@ -187,11 +197,15 @@ class ConfigurableManager(object):
:param str config_type: configuration type to store configuration for
:return: nothing
"""
logging.debug("setting config for node(%s) type(%s): %s", node_id, config_type, config)
logging.debug(
"setting config for node(%s) type(%s): %s", node_id, config_type, config
)
node_configs = self.node_configurations.setdefault(node_id, OrderedDict())
node_configs[config_type] = config
def get_config(self, _id, node_id=_default_node, config_type=_default_type, default=None):
def get_config(
self, _id, node_id=_default_node, config_type=_default_type, default=None
):
"""
Retrieves a specific configuration for a node and configuration type.
@ -256,6 +270,7 @@ class ConfigurableOptions(object):
"""
Provides a base for defining configuration options within CORE.
"""
name = None
bitmap = None
options = []
@ -278,9 +293,7 @@ class ConfigurableOptions(object):
:return: configuration group definition
:rtype: list[ConfigGroup]
"""
return [
ConfigGroup("Options", 1, len(cls.configurations()))
]
return [ConfigGroup("Options", 1, len(cls.configurations()))]
@classmethod
def default_values(cls):
@ -290,7 +303,9 @@ class ConfigurableOptions(object):
:return: ordered configuration mapping default values
:rtype: OrderedDict
"""
return OrderedDict([(config.id, config.default) for config in cls.configurations()])
return OrderedDict(
[(config.id, config.default) for config in cls.configurations()]
)
class ModelManager(ConfigurableManager):
@ -365,7 +380,12 @@ 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.id, config)
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)

View file

@ -20,7 +20,7 @@ class EmaneBypassModel(emanemodel.EmaneModel):
_type=ConfigDataTypes.BOOL,
default="0",
options=["True", "False"],
label="There are no parameters for the bypass model."
label="There are no parameters for the bypass model.",
)
]
@ -36,6 +36,4 @@ class EmaneBypassModel(emanemodel.EmaneModel):
# override config groups
@classmethod
def config_groups(cls):
return [
ConfigGroup("Bypass Parameters", 1, 1),
]
return [ConfigGroup("Bypass Parameters", 1, 1)]

View file

@ -56,9 +56,7 @@ class EmaneCommEffectModel(emanemodel.EmaneModel):
@classmethod
def config_groups(cls):
return [
ConfigGroup("CommEffect SHIM Parameters", 1, len(cls.configurations()))
]
return [ConfigGroup("CommEffect SHIM Parameters", 1, len(cls.configurations()))]
def build_xml_files(self, config, interface=None):
"""
@ -76,7 +74,9 @@ class EmaneCommEffectModel(emanemodel.EmaneModel):
shim_name = emanexml.shim_file_name(self, interface)
# create and write nem document
nem_element = etree.Element("nem", name="%s NEM" % self.name, type="unstructured")
nem_element = etree.Element(
"nem", name="%s NEM" % self.name, type="unstructured"
)
transport_type = "virtual"
if interface and interface.transport_type == "raw":
transport_type = "raw"
@ -90,7 +90,9 @@ class EmaneCommEffectModel(emanemodel.EmaneModel):
emanexml.create_file(nem_element, "nem", nem_file)
# create and write shim document
shim_element = etree.Element("shim", name="%s SHIM" % self.name, library=self.shim_library)
shim_element = etree.Element(
"shim", name="%s SHIM" % self.name, library=self.shim_library
)
# append all shim options (except filterfile) to shimdoc
for configuration in self.config_shim:
@ -108,7 +110,16 @@ class EmaneCommEffectModel(emanemodel.EmaneModel):
shim_file = os.path.join(self.session.session_dir, shim_name)
emanexml.create_file(shim_element, "shim", shim_file)
def linkconfig(self, netif, bw=None, delay=None, loss=None, duplicate=None, jitter=None, netif2=None):
def linkconfig(
self,
netif,
bw=None,
delay=None,
loss=None,
duplicate=None,
jitter=None,
netif2=None,
):
"""
Generate CommEffect events when a Link Message is received having
link parameters.
@ -137,6 +148,6 @@ class EmaneCommEffectModel(emanemodel.EmaneModel):
loss=convert_none(loss),
duplicate=convert_none(duplicate),
unicast=long(convert_none(bw)),
broadcast=long(convert_none(mbw))
broadcast=long(convert_none(mbw)),
)
service.publish(nemid2, event)

View file

@ -46,7 +46,7 @@ EMANE_MODELS = [
EmaneIeee80211abgModel,
EmaneCommEffectModel,
EmaneBypassModel,
EmaneTdmaModel
EmaneTdmaModel,
]
DEFAULT_EMANE_PREFIX = "/usr"
@ -57,6 +57,7 @@ class EmaneManager(ModelManager):
building EMANE config files from all of the EmaneNode objects in this
emulation, and for controlling the EMANE daemons.
"""
name = "emane"
config_type = RegisterTlvs.EMULATION_SERVER.value
SUCCESS, NOT_NEEDED, NOT_READY = (0, 1, 2)
@ -77,8 +78,12 @@ class EmaneManager(ModelManager):
self._ifccounts = {}
self._ifccountslock = threading.Lock()
# port numbers are allocated from these counters
self.platformport = self.session.options.get_config_int("emane_platform_port", 8100)
self.transformport = self.session.options.get_config_int("emane_transform_port", 8200)
self.platformport = self.session.options.get_config_int(
"emane_platform_port", 8100
)
self.transformport = self.session.options.get_config_int(
"emane_transform_port", 8200
)
self.doeventloop = False
self.eventmonthread = None
@ -122,7 +127,9 @@ class EmaneManager(ModelManager):
# otherwise retrieve the interfaces node configuration, avoid using defaults
if not config:
config = self.get_configs(node_id=interface.node.id, 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:
@ -184,11 +191,15 @@ class EmaneManager(ModelManager):
self.event_device = self.get_config("eventservicedevice")
eventnetidx = self.session.get_control_net_index(self.event_device)
if eventnetidx < 0:
logging.error("invalid emane event service device provided: %s", self.event_device)
logging.error(
"invalid emane event service device provided: %s", self.event_device
)
return False
# make sure the event control network is in place
eventnet = self.session.add_remove_control_net(net_index=eventnetidx, remove=False, conf_required=False)
eventnet = self.session.add_remove_control_net(
net_index=eventnetidx, remove=False, conf_required=False
)
if eventnet is not None:
# direct EMANE events towards control net bridge
self.event_device = eventnet.brname
@ -210,7 +221,9 @@ class EmaneManager(ModelManager):
"""
for emane_model in emane_models:
logging.info("loading emane model: %s", emane_model.__name__)
emane_prefix = self.session.options.get_config("emane_prefix", default=DEFAULT_EMANE_PREFIX)
emane_prefix = self.session.options.get_config(
"emane_prefix", default=DEFAULT_EMANE_PREFIX
)
emane_model.load(emane_prefix)
self.models[emane_model.name] = emane_model
@ -223,7 +236,9 @@ class EmaneManager(ModelManager):
"""
with self._emane_node_lock:
if emane_node.id in self._emane_nodes:
raise KeyError("non-unique EMANE object id %s for %s" % (emane_node.id, emane_node))
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):
@ -252,7 +267,9 @@ class EmaneManager(ModelManager):
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.id, node.name)
logging.debug(
"adding emane node: id(%s) name(%s)", node.id, node.name
)
self.add_node(node)
if not self._emane_nodes:
@ -265,12 +282,19 @@ class EmaneManager(ModelManager):
if self.session.master:
otadev = self.get_config("otamanagerdevice")
netidx = self.session.get_control_net_index(otadev)
logging.debug("emane ota manager device: index(%s) otadev(%s)", netidx, otadev)
logging.debug(
"emane ota manager device: index(%s) otadev(%s)", netidx, otadev
)
if netidx < 0:
logging.error("EMANE cannot start, check core config. invalid OTA device provided: %s", otadev)
logging.error(
"EMANE cannot start, check core config. invalid OTA device provided: %s",
otadev,
)
return EmaneManager.NOT_READY
ctrlnet = self.session.add_remove_control_net(net_index=netidx, remove=False, conf_required=False)
ctrlnet = self.session.add_remove_control_net(
net_index=netidx, remove=False, conf_required=False
)
self.distributedctrlnet(ctrlnet)
eventdev = self.get_config("eventservicedevice")
logging.debug("emane event service device: eventdev(%s)", eventdev)
@ -278,10 +302,15 @@ class EmaneManager(ModelManager):
netidx = self.session.get_control_net_index(eventdev)
logging.debug("emane event service device index: %s", netidx)
if netidx < 0:
logging.error("EMANE cannot start, check core config. invalid event service device: %s", eventdev)
logging.error(
"EMANE cannot start, check core config. invalid event service device: %s",
eventdev,
)
return EmaneManager.NOT_READY
ctrlnet = self.session.add_remove_control_net(net_index=netidx, remove=False, conf_required=False)
ctrlnet = self.session.add_remove_control_net(
net_index=netidx, remove=False, conf_required=False
)
self.distributedctrlnet(ctrlnet)
if self.checkdistributed():
@ -321,7 +350,9 @@ class EmaneManager(ModelManager):
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)))
nems.append(
(netif.node.name, netif.name, emane_node.getnemid(netif))
)
if nems:
emane_nems_filename = os.path.join(self.session.session_dir, "emane_nems")
@ -344,7 +375,11 @@ 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.id, 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()
@ -359,8 +394,12 @@ class EmaneManager(ModelManager):
self._emane_nodes.clear()
# don't clear self._ifccounts here; NEM counts are needed for buildxml
self.platformport = self.session.options.get_config_int("emane_platform_port", 8100)
self.transformport = self.session.options.get_config_int("emane_transform_port", 8200)
self.platformport = self.session.options.get_config_int(
"emane_platform_port", 8100
)
self.transformport = self.session.options.get_config_int(
"emane_transform_port", 8200
)
def shutdown(self):
"""
@ -383,7 +422,10 @@ class EmaneManager(ModelManager):
received. This is used to snoop the Link add messages to get NEM
counts of NEMs that exist on other servers.
"""
if message.message_type == MessageTypes.LINK.value and message.flags & MessageFlags.ADD.value:
if (
message.message_type == MessageTypes.LINK.value
and message.flags & MessageFlags.ADD.value
):
nn = message.node_numbers()
# first node is always link layer node in Link add message
if nn[0] in self.session.broker.network_nodes:
@ -448,7 +490,9 @@ class EmaneManager(ModelManager):
config = copy.deepcopy(self.get_configs())
config["platform_id_start"] = str(platformid)
config["nem_id_start"] = str(nemid)
config_data = ConfigShim.config_data(0, None, typeflags, self.emane_config, config)
config_data = ConfigShim.config_data(
0, None, typeflags, self.emane_config, config
)
message = dataconversion.convert_config(config_data)
server.sock.send(message)
# increment nemid for next server by number of interfaces
@ -467,7 +511,9 @@ class EmaneManager(ModelManager):
# assume self._objslock is already held here
logging.info("emane building xml...")
# on master, control network bridge added earlier in startup()
ctrlnet = self.session.add_remove_control_net(net_index=0, remove=False, conf_required=False)
ctrlnet = self.session.add_remove_control_net(
net_index=0, remove=False, conf_required=False
)
self.buildplatformxml(ctrlnet)
self.buildnemxml()
self.buildeventservicexml()
@ -493,7 +539,10 @@ class EmaneManager(ModelManager):
prefix = session.options.get_config("controlnet", default="")
prefixes = prefix.split()
if len(prefixes) < len(servers):
logging.info("setting up default controlnet prefixes for distributed (%d configured)", len(prefixes))
logging.info(
"setting up default controlnet prefixes for distributed (%d configured)",
len(prefixes),
)
prefix = ctrlnet.DEFAULT_PREFIX_LIST[0]
prefixes = prefix.split()
servers.remove("localhost")
@ -508,8 +557,10 @@ class EmaneManager(ModelManager):
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.TYPE.value, 0)
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.VALUES.value, vals)
rawmsg = coreapi.CoreConfMessage.pack(0, tlvdata)
msghdr = rawmsg[:coreapi.CoreMessage.header_len]
msg = coreapi.CoreConfMessage(flags=0, hdr=msghdr, data=rawmsg[coreapi.CoreMessage.header_len:])
msghdr = rawmsg[: coreapi.CoreMessage.header_len]
msg = coreapi.CoreConfMessage(
flags=0, hdr=msghdr, data=rawmsg[coreapi.CoreMessage.header_len :]
)
logging.debug("sending controlnet message:\n%s", msg)
self.session.broker.handle_message(msg)
@ -524,7 +575,11 @@ 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.id, 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
@ -576,7 +631,9 @@ class EmaneManager(ModelManager):
# assume self._objslock is already held here
for key in sorted(self._emane_nodes.keys()):
emane_node = self._emane_nodes[key]
nemid = emanexml.build_node_platform_xml(self, ctrlnet, emane_node, nemid, platform_xmls)
nemid = emanexml.build_node_platform_xml(
self, ctrlnet, emane_node, nemid, platform_xmls
)
def buildnemxml(self):
"""
@ -591,7 +648,9 @@ class EmaneManager(ModelManager):
"""
Calls emanegentransportxml using a platform.xml file to build the transportdaemon*.xml.
"""
utils.check_cmd(["emanegentransportxml", "platform.xml"], cwd=self.session.session_dir)
utils.check_cmd(
["emanegentransportxml", "platform.xml"], cwd=self.session.session_dir
)
def buildeventservicexml(self):
"""
@ -636,7 +695,7 @@ class EmaneManager(ModelManager):
emanecmd = ["emane", "-d", "-l", loglevel]
if realtime:
emanecmd += "-r",
emanecmd += ("-r",)
otagroup, _otaport = self.get_config("otamanagergroup").split(":")
otadev = self.get_config("otamanagerdevice")
@ -655,15 +714,21 @@ class EmaneManager(ModelManager):
n = node.id
# control network not yet started here
self.session.add_remove_control_interface(node, 0, remove=False, conf_required=False)
self.session.add_remove_control_interface(
node, 0, remove=False, conf_required=False
)
if otanetidx > 0:
logging.info("adding ota device ctrl%d", otanetidx)
self.session.add_remove_control_interface(node, otanetidx, remove=False, conf_required=False)
self.session.add_remove_control_interface(
node, otanetidx, remove=False, conf_required=False
)
if eventservicenetidx >= 0:
logging.info("adding event service device ctrl%d", eventservicenetidx)
self.session.add_remove_control_interface(node, eventservicenetidx, remove=False, conf_required=False)
self.session.add_remove_control_interface(
node, eventservicenetidx, remove=False, conf_required=False
)
# multicast route is needed for OTA data
args = [constants.IP_BIN, "route", "add", otagroup, "dev", otadev]
@ -675,7 +740,11 @@ class EmaneManager(ModelManager):
node.network_cmd(args)
# start emane
args = emanecmd + ["-f", os.path.join(path, "emane%d.log" % n), os.path.join(path, "platform%d.xml" % n)]
args = emanecmd + [
"-f",
os.path.join(path, "emane%d.log" % n),
os.path.join(path, "platform%d.xml" % n),
]
output = node.check_cmd(args)
logging.info("node(%s) emane daemon running: %s", node.name, args)
logging.info("node(%s) emane daemon output: %s", node.name, output)
@ -758,10 +827,12 @@ class EmaneManager(ModelManager):
return
if self.service is None:
logging.error("Warning: EMANE events will not be generated "
"because the emaneeventservice\n binding was "
"unable to load "
"(install the python-emaneeventservice bindings)")
logging.error(
"Warning: EMANE events will not be generated "
"because the emaneeventservice\n binding was "
"unable to load "
"(install the python-emaneeventservice bindings)"
)
return
self.doeventloop = True
self.eventmonthread = threading.Thread(target=self.eventmonitorloop)
@ -790,7 +861,10 @@ class EmaneManager(ModelManager):
"""
if self.service is None:
return
logging.info("subscribing to EMANE location events. (%s)", threading.currentThread().getName())
logging.info(
"subscribing to EMANE location events. (%s)",
threading.currentThread().getName(),
)
while self.doeventloop is True:
_uuid, _seq, events = self.service.nextEvent()
@ -803,7 +877,10 @@ class EmaneManager(ModelManager):
if eid == LocationEvent.IDENTIFIER:
self.handlelocationevent(nem, eid, data)
logging.info("unsubscribing from EMANE location events. (%s)", threading.currentThread().getName())
logging.info(
"unsubscribing from EMANE location events. (%s)",
threading.currentThread().getName(),
)
def handlelocationevent(self, rxnemid, eid, data):
"""
@ -813,7 +890,11 @@ class EmaneManager(ModelManager):
events.restore(data)
for event in events:
txnemid, attrs = event
if "latitude" not in attrs or "longitude" not in attrs or "altitude" not in attrs:
if (
"latitude" not in attrs
or "longitude" not in attrs
or "altitude" not in attrs
):
logging.warning("dropped invalid location event")
continue
@ -842,20 +923,37 @@ class EmaneManager(ModelManager):
x = int(x)
y = int(y)
z = int(z)
logging.info("location event NEM %s (%s, %s, %s) -> (%s, %s, %s)", nemid, lat, lon, alt, x, y, z)
logging.info(
"location event NEM %s (%s, %s, %s) -> (%s, %s, %s)",
nemid,
lat,
lon,
alt,
x,
y,
z,
)
xbit_check = x.bit_length() > 16 or x < 0
ybit_check = y.bit_length() > 16 or y < 0
zbit_check = z.bit_length() > 16 or z < 0
if any([xbit_check, ybit_check, zbit_check]):
logging.error("Unable to build node location message, received lat/long/alt exceeds coordinate "
"space: NEM %s (%d, %d, %d)", nemid, x, y, z)
logging.error(
"Unable to build node location message, received lat/long/alt exceeds coordinate "
"space: NEM %s (%d, %d, %d)",
nemid,
x,
y,
z,
)
return False
# generate a node message for this location update
try:
node = self.session.get_node(n)
except KeyError:
logging.exception("location event NEM %s has no corresponding node %s" % (nemid, n))
logging.exception(
"location event NEM %s has no corresponding node %s" % (nemid, n)
)
return False
# don"t use node.setposition(x,y,z) which generates an event
@ -887,18 +985,26 @@ class EmaneGlobalModel(EmaneModel):
"eventservicedevice": _DEFAULT_DEV,
"eventservicegroup": "224.1.2.8:45703",
"otamanagerdevice": _DEFAULT_DEV,
"otamanagergroup": "224.1.2.8:45702"
"otamanagergroup": "224.1.2.8:45702",
}
emulator_config = emanemanifest.parse(emulator_xml, emulator_defaults)
emulator_config.insert(
0,
Configuration(_id="platform_id_start", _type=ConfigDataTypes.INT32, default="1",
label="Starting Platform ID (core)")
Configuration(
_id="platform_id_start",
_type=ConfigDataTypes.INT32,
default="1",
label="Starting Platform ID (core)",
),
)
nem_config = [
Configuration(_id="nem_id_start", _type=ConfigDataTypes.INT32, default="1",
label="Starting NEM ID (core)")
Configuration(
_id="nem_id_start",
_type=ConfigDataTypes.INT32,
default="1",
label="Starting NEM ID (core)",
)
]
@classmethod
@ -911,7 +1017,7 @@ class EmaneGlobalModel(EmaneModel):
config_len = len(cls.configurations())
return [
ConfigGroup("Platform Attributes", 1, emulator_len),
ConfigGroup("NEM Parameters", emulator_len + 1, config_len)
ConfigGroup("NEM Parameters", emulator_len + 1, config_len),
]
def __init__(self, session, _id=None):

View file

@ -122,7 +122,7 @@ def parse(manifest_path, defaults):
_type=config_type_value,
default=config_default,
options=possible,
label=config_descriptions
label=config_descriptions,
)
configurations.append(configuration)

View file

@ -17,6 +17,7 @@ class EmaneModel(WirelessModel):
handling configuration messages based on the list of
configurable parameters. Helper functions also live here.
"""
# default mac configuration settings
mac_library = None
mac_xml = None
@ -26,18 +27,18 @@ class EmaneModel(WirelessModel):
# default phy configuration settings, using the universal model
phy_library = None
phy_xml = "emanephy.xml"
phy_defaults = {
"subid": "1",
"propagationmodel": "2ray",
"noisemode": "none"
}
phy_defaults = {"subid": "1", "propagationmodel": "2ray", "noisemode": "none"}
phy_config = []
# support for external configurations
external_config = [
Configuration("external", ConfigDataTypes.BOOL, default="0"),
Configuration("platformendpoint", ConfigDataTypes.STRING, default="127.0.0.1:40001"),
Configuration("transportendpoint", ConfigDataTypes.STRING, default="127.0.0.1:50002")
Configuration(
"platformendpoint", ConfigDataTypes.STRING, default="127.0.0.1:40001"
),
Configuration(
"transportendpoint", ConfigDataTypes.STRING, default="127.0.0.1:50002"
),
]
config_ignore = set()
@ -84,7 +85,7 @@ class EmaneModel(WirelessModel):
return [
ConfigGroup("MAC Parameters", 1, mac_len),
ConfigGroup("PHY Parameters", mac_len + 1, phy_len),
ConfigGroup("External Parameters", phy_len + 1, config_len)
ConfigGroup("External Parameters", phy_len + 1, config_len),
]
def build_xml_files(self, config, interface=None):
@ -108,7 +109,9 @@ class EmaneModel(WirelessModel):
# create nem xml file
nem_file = os.path.join(self.session.session_dir, nem_name)
emanexml.create_nem_xml(self, config, nem_file, transport_name, mac_name, phy_name)
emanexml.create_nem_xml(
self, config, nem_file, transport_name, mac_name, phy_name
)
# create mac xml file
mac_file = os.path.join(self.session.session_dir, mac_name)
@ -142,7 +145,16 @@ class EmaneModel(WirelessModel):
except KeyError:
logging.exception("error during update")
def linkconfig(self, netif, bw=None, delay=None, loss=None, duplicate=None, jitter=None, netif2=None):
def linkconfig(
self,
netif,
bw=None,
delay=None,
loss=None,
duplicate=None,
jitter=None,
netif2=None,
):
"""
Invoked when a Link Message is received. Default is unimplemented.
@ -155,4 +167,6 @@ class EmaneModel(WirelessModel):
:param core.netns.vif.Veth netif2: interface two
:return: nothing
"""
logging.warning("emane model(%s) does not support link configuration", self.name)
logging.warning(
"emane model(%s) does not support link configuration", self.name
)

View file

@ -17,7 +17,6 @@ class EmaneIeee80211abgModel(emanemodel.EmaneModel):
@classmethod
def load(cls, emane_prefix):
cls.mac_defaults["pcrcurveuri"] = os.path.join(
emane_prefix,
"share/emane/xml/models/mac/ieee80211abg/ieee80211pcr.xml"
emane_prefix, "share/emane/xml/models/mac/ieee80211abg/ieee80211pcr.xml"
)
super(EmaneIeee80211abgModel, cls).load(emane_prefix)

View file

@ -22,6 +22,7 @@ class EmaneNet(CoreNetworkBase):
"""
EMANE network base class.
"""
apitype = NodeTypes.EMANE.value
linktype = LinkTypes.WIRELESS.value
# icon used
@ -43,14 +44,30 @@ class EmaneNode(EmaneNet):
self.model = None
self.mobility = None
def linkconfig(self, netif, bw=None, delay=None, loss=None, duplicate=None, jitter=None, netif2=None):
def linkconfig(
self,
netif,
bw=None,
delay=None,
loss=None,
duplicate=None,
jitter=None,
netif2=None,
):
"""
The CommEffect model supports link configuration.
"""
if not self.model:
return
return self.model.linkconfig(netif=netif, bw=bw, delay=delay, loss=loss,
duplicate=duplicate, jitter=jitter, netif2=netif2)
return self.model.linkconfig(
netif=netif,
bw=bw,
delay=delay,
loss=loss,
duplicate=duplicate,
jitter=jitter,
netif2=netif2,
)
def config(self, conf):
self.conf = conf
@ -67,7 +84,9 @@ class EmaneNode(EmaneNet):
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)
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):
@ -122,13 +141,18 @@ class EmaneNode(EmaneNet):
EMANE daemons have been started, because that is their only chance
to bind to the TAPs.
"""
if self.session.emane.genlocationevents() and self.session.emane.service is None:
if (
self.session.emane.genlocationevents()
and self.session.emane.service is None
):
warntxt = "unable to publish EMANE events because the eventservice "
warntxt += "Python bindings failed to load"
logging.error(warntxt)
for netif in self.netifs():
external = self.session.emane.get_config("external", self.id, self.model.name)
external = self.session.emane.get_config(
"external", self.id, self.model.name
)
if external == "0":
netif.setaddrs()
@ -166,7 +190,17 @@ class EmaneNode(EmaneNet):
logging.info("nemid for %s is unknown", ifname)
return
lat, lon, alt = self.session.location.getgeo(x, y, z)
logging.info("setnemposition %s (%s) x,y,z=(%d,%d,%s)(%.6f,%.6f,%.6f)", ifname, nemid, x, y, z, lat, lon, alt)
logging.info(
"setnemposition %s (%s) x,y,z=(%d,%d,%s)(%.6f,%.6f,%.6f)",
ifname,
nemid,
x,
y,
z,
lat,
lon,
alt,
)
event = LocationEvent()
# altitude must be an integer or warning is printed
@ -198,8 +232,18 @@ class EmaneNode(EmaneNet):
continue
x, y, z = netif.node.getposition()
lat, lon, alt = self.session.location.getgeo(x, y, z)
logging.info("setnempositions %d %s (%s) x,y,z=(%d,%d,%s)(%.6f,%.6f,%.6f)",
i, ifname, nemid, x, y, z, lat, lon, alt)
logging.info(
"setnempositions %d %s (%s) x,y,z=(%d,%d,%s)(%.6f,%.6f,%.6f)",
i,
ifname,
nemid,
x,
y,
z,
lat,
lon,
alt,
)
# altitude must be an integer or warning is printed
alt = int(round(alt))
event.append(nemid, latitude=lat, longitude=lon, altitude=alt)

View file

@ -17,7 +17,6 @@ class EmaneRfPipeModel(emanemodel.EmaneModel):
@classmethod
def load(cls, emane_prefix):
cls.mac_defaults["pcrcurveuri"] = os.path.join(
emane_prefix,
"share/emane/xml/models/mac/rfpipe/rfpipepcr.xml"
emane_prefix, "share/emane/xml/models/mac/rfpipe/rfpipepcr.xml"
)
super(EmaneRfPipeModel, cls).load(emane_prefix)

View file

@ -21,14 +21,16 @@ class EmaneTdmaModel(emanemodel.EmaneModel):
# add custom schedule options and ignore it when writing emane xml
schedule_name = "schedule"
default_schedule = os.path.join(constants.CORE_DATA_DIR, "examples", "tdma", "schedule.xml")
default_schedule = os.path.join(
constants.CORE_DATA_DIR, "examples", "tdma", "schedule.xml"
)
config_ignore = {schedule_name}
@classmethod
def load(cls, emane_prefix):
cls.mac_defaults["pcrcurveuri"] = os.path.join(
emane_prefix,
"share/emane/xml/models/mac/tdmaeventscheduler/tdmabasemodelpcr.xml"
"share/emane/xml/models/mac/tdmaeventscheduler/tdmabasemodelpcr.xml",
)
super(EmaneTdmaModel, cls).load(emane_prefix)
cls.mac_config.insert(
@ -37,8 +39,8 @@ class EmaneTdmaModel(emanemodel.EmaneModel):
_id=cls.schedule_name,
_type=ConfigDataTypes.STRING,
default=cls.default_schedule,
label="TDMA schedule file (core)"
)
label="TDMA schedule file (core)",
),
)
def post_startup(self):
@ -57,5 +59,7 @@ class EmaneTdmaModel(emanemodel.EmaneModel):
event_device = self.session.emane.event_device
# initiate tdma schedule
logging.info("setting up tdma schedule: schedule(%s) device(%s)", schedule, event_device)
logging.info(
"setting up tdma schedule: schedule(%s) device(%s)", schedule, event_device
)
utils.check_cmd(["emaneevent-tdmaschedule", "-i", event_device, schedule])

View file

@ -72,7 +72,7 @@ class CoreEmu(object):
service_paths = self.config.get("custom_services_dir")
logging.debug("custom service paths: %s", service_paths)
if service_paths:
for service_path in service_paths.split(','):
for service_path in service_paths.split(","):
service_path = service_path.strip()
custom_service_errors = ServiceManager.add_services(service_path)
self.service_errors.extend(custom_service_errors)

View file

@ -4,117 +4,118 @@ CORE data objects.
import collections
ConfigData = collections.namedtuple("ConfigData", [
"message_type",
"node",
"object",
"type",
"data_types",
"data_values",
"captions",
"bitmap",
"possible_values",
"groups",
"session",
"interface_number",
"network_id",
"opaque"
])
ConfigData = collections.namedtuple(
"ConfigData",
[
"message_type",
"node",
"object",
"type",
"data_types",
"data_values",
"captions",
"bitmap",
"possible_values",
"groups",
"session",
"interface_number",
"network_id",
"opaque",
],
)
ConfigData.__new__.__defaults__ = (None,) * len(ConfigData._fields)
EventData = collections.namedtuple("EventData", [
"node",
"event_type",
"name",
"data",
"time",
"session"
])
EventData = collections.namedtuple(
"EventData", ["node", "event_type", "name", "data", "time", "session"]
)
EventData.__new__.__defaults__ = (None,) * len(EventData._fields)
ExceptionData = collections.namedtuple("ExceptionData", [
"node",
"session",
"level",
"source",
"date",
"text",
"opaque"
])
ExceptionData = collections.namedtuple(
"ExceptionData", ["node", "session", "level", "source", "date", "text", "opaque"]
)
ExceptionData.__new__.__defaults__ = (None,) * len(ExceptionData._fields)
FileData = collections.namedtuple("FileData", [
"message_type",
"node",
"name",
"mode",
"number",
"type",
"source",
"session",
"data",
"compressed_data"
])
FileData = collections.namedtuple(
"FileData",
[
"message_type",
"node",
"name",
"mode",
"number",
"type",
"source",
"session",
"data",
"compressed_data",
],
)
FileData.__new__.__defaults__ = (None,) * len(FileData._fields)
NodeData = collections.namedtuple("NodeData", [
"message_type",
"id",
"node_type",
"name",
"ip_address",
"mac_address",
"ip6_address",
"model",
"emulation_id",
"emulation_server",
"session",
"x_position",
"y_position",
"canvas",
"network_id",
"services",
"latitude",
"longitude",
"altitude",
"icon",
"opaque"
])
NodeData = collections.namedtuple(
"NodeData",
[
"message_type",
"id",
"node_type",
"name",
"ip_address",
"mac_address",
"ip6_address",
"model",
"emulation_id",
"emulation_server",
"session",
"x_position",
"y_position",
"canvas",
"network_id",
"services",
"latitude",
"longitude",
"altitude",
"icon",
"opaque",
],
)
NodeData.__new__.__defaults__ = (None,) * len(NodeData._fields)
LinkData = collections.namedtuple("LinkData", [
"message_type",
"node1_id",
"node2_id",
"delay",
"bandwidth",
"per",
"dup",
"jitter",
"mer",
"burst",
"session",
"mburst",
"link_type",
"gui_attributes",
"unidirectional",
"emulation_id",
"network_id",
"key",
"interface1_id",
"interface1_name",
"interface1_ip4",
"interface1_ip4_mask",
"interface1_mac",
"interface1_ip6",
"interface1_ip6_mask",
"interface2_id",
"interface2_name",
"interface2_ip4",
"interface2_ip4_mask",
"interface2_mac",
"interface2_ip6",
"interface2_ip6_mask",
"opaque"
])
LinkData = collections.namedtuple(
"LinkData",
[
"message_type",
"node1_id",
"node2_id",
"delay",
"bandwidth",
"per",
"dup",
"jitter",
"mer",
"burst",
"session",
"mburst",
"link_type",
"gui_attributes",
"unidirectional",
"emulation_id",
"network_id",
"key",
"interface1_id",
"interface1_name",
"interface1_ip4",
"interface1_ip4_mask",
"interface1_mac",
"interface1_ip6",
"interface1_ip6_mask",
"interface2_id",
"interface2_name",
"interface2_ip4",
"interface2_ip4_mask",
"interface2_mac",
"interface2_ip6",
"interface2_ip6_mask",
"opaque",
],
)
LinkData.__new__.__defaults__ = (None,) * len(LinkData._fields)

View file

@ -38,7 +38,7 @@ def create_interface(node, network, interface_data):
addrlist=interface_data.get_addresses(),
hwaddr=interface_data.mac,
ifindex=interface_data.id,
ifname=interface_data.name
ifname=interface_data.name,
)
return node.netif(interface_data.id, network)
@ -61,7 +61,7 @@ def link_config(network, interface, link_options, devname=None, interface_two=No
"loss": link_options.per,
"duplicate": link_options.dup,
"jitter": link_options.jitter,
"netif2": interface_two
"netif2": interface_two,
}
# hacky check here, because physical and emane nodes do not conform to the same linkconfig interface
@ -239,7 +239,7 @@ class IpPrefixes(object):
ip4_mask=ip4_mask,
ip6=ip6,
ip6_mask=ip6_mask,
mac=mac
mac=mac,
)

View file

@ -12,6 +12,7 @@ class MessageTypes(Enum):
"""
CORE message types.
"""
NODE = 0x01
LINK = 0x02
EXECUTE = 0x03
@ -28,6 +29,7 @@ class MessageFlags(Enum):
"""
CORE message flags.
"""
ADD = 0x01
DELETE = 0x02
CRI = 0x04
@ -41,6 +43,7 @@ class NodeTlvs(Enum):
"""
Node type, length, value enumerations.
"""
NUMBER = 0x01
TYPE = 0x02
NAME = 0x03
@ -67,6 +70,7 @@ class NodeTypes(Enum):
"""
Node types.
"""
DEFAULT = 0
PHYSICAL = 1
TBD = 3
@ -89,6 +93,7 @@ class Rj45Models(Enum):
"""
RJ45 model types.
"""
LINKED = 0
WIRELESS = 1
INSTALLED = 2
@ -99,6 +104,7 @@ class LinkTlvs(Enum):
"""
Link type, length, value enumerations.
"""
N1_NUMBER = 0x01
N2_NUMBER = 0x02
DELAY = 0x03
@ -137,6 +143,7 @@ class LinkTypes(Enum):
"""
Link types.
"""
WIRELESS = 0
WIRED = 1
@ -145,6 +152,7 @@ class ExecuteTlvs(Enum):
"""
Execute type, length, value enumerations.
"""
NODE = 0x01
NUMBER = 0x02
TIME = 0x03
@ -158,6 +166,7 @@ class RegisterTlvs(Enum):
"""
Register type, length, value enumerations.
"""
WIRELESS = 0x01
MOBILITY = 0x02
UTILITY = 0x03
@ -171,6 +180,7 @@ class ConfigTlvs(Enum):
"""
Configuration type, length, value enumerations.
"""
NODE = 0x01
OBJECT = 0x02
TYPE = 0x03
@ -190,6 +200,7 @@ class ConfigFlags(Enum):
"""
Configuration flags.
"""
NONE = 0x00
REQUEST = 0x01
UPDATE = 0x02
@ -200,6 +211,7 @@ class ConfigDataTypes(Enum):
"""
Configuration data types.
"""
UINT8 = 0x01
UINT16 = 0x02
UINT32 = 0x03
@ -217,6 +229,7 @@ class FileTlvs(Enum):
"""
File type, length, value enumerations.
"""
NODE = 0x01
NAME = 0x02
MODE = 0x03
@ -232,6 +245,7 @@ class InterfaceTlvs(Enum):
"""
Interface type, length, value enumerations.
"""
NODE = 0x01
NUMBER = 0x02
NAME = 0x03
@ -251,6 +265,7 @@ class EventTlvs(Enum):
"""
Event type, length, value enumerations.
"""
NODE = 0x01
TYPE = 0x02
NAME = 0x03
@ -263,6 +278,7 @@ class EventTypes(Enum):
"""
Event types.
"""
NONE = 0
DEFINITION_STATE = 1
CONFIGURATION_STATE = 2
@ -285,6 +301,7 @@ class SessionTlvs(Enum):
"""
Session type, length, value enumerations.
"""
NUMBER = 0x01
NAME = 0x02
FILE = 0x03
@ -299,6 +316,7 @@ class ExceptionTlvs(Enum):
"""
Exception type, length, value enumerations.
"""
NODE = 0x01
SESSION = 0x02
LEVEL = 0x03
@ -312,6 +330,7 @@ class ExceptionLevels(Enum):
"""
Exception levels.
"""
NONE = 0
FATAL = 1
ERROR = 2

View file

@ -82,7 +82,9 @@ class Session(object):
# hooks handlers
self._hooks = {}
self._state_hooks = {}
self.add_state_hook(state=EventTypes.RUNTIME_STATE.value, hook=self.runtime_state_hook)
self.add_state_hook(
state=EventTypes.RUNTIME_STATE.value, hook=self.runtime_state_hook
)
# handlers for broadcasting information
self.event_handlers = []
@ -128,7 +130,9 @@ class Session(object):
: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)
logging.debug(
"link message between node1(%s) and node2(%s)", node_one_id, node_two_id
)
# values to fill
net_one = None
@ -168,8 +172,14 @@ class Session(object):
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)
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
@ -184,23 +194,42 @@ class Session(object):
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)
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)
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)
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=None):
def add_link(
self,
node_one_id,
node_two_id,
interface_one=None,
interface_two=None,
link_options=None,
):
"""
Add a link between nodes.
@ -215,7 +244,9 @@ class Session(object):
link_options = LinkOptions()
# 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)
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()
@ -231,27 +262,43 @@ class Session(object):
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)
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.create_node(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)
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)
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)
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:
@ -261,7 +308,9 @@ class Session(object):
if not link_options.unidirectional:
interface.swapparams("_params_up")
link_config(net_two, interface, link_options, devname=interface.name)
link_config(
net_two, interface, link_options, devname=interface.name
)
interface.swapparams("_params_up")
# a tunnel node was found for the nodes
@ -290,12 +339,16 @@ class Session(object):
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)
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)
node_two.adoptnetif(
tunnel, interface_two.id, interface_two.mac, addresses
)
link_config(node_two, tunnel, link_options)
finally:
if node_one:
@ -303,7 +356,14 @@ class Session(object):
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):
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.
@ -315,7 +375,9 @@ class Session(object):
: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)
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()
@ -339,18 +401,31 @@ class Session(object):
# 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:
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]):
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)
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()
@ -361,15 +436,23 @@ class Session(object):
elif node_one and net_one:
interface = node_one.netif(interface_one_id)
if interface:
logging.info("deleting link node(%s):interface(%s) node(%s)",
node_one.name, interface.name, net_one.name)
logging.info(
"deleting link node(%s):interface(%s) node(%s)",
node_one.name,
interface.name,
net_one.name,
)
interface.detachnet()
node_one.delnetif(interface.netindex)
elif node_two and net_one:
interface = node_two.netif(interface_two_id)
if interface:
logging.info("deleting link node(%s):interface(%s) node(%s)",
node_two.name, interface.name, net_one.name)
logging.info(
"deleting link node(%s):interface(%s) node(%s)",
node_two.name,
interface.name,
net_one.name,
)
interface.detachnet()
node_two.delnetif(interface.netindex)
finally:
@ -378,7 +461,14 @@ class Session(object):
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=None):
def update_link(
self,
node_one_id,
node_two_id,
interface_one_id=None,
interface_two_id=None,
link_options=None,
):
"""
Update link information between nodes.
@ -393,7 +483,9 @@ class Session(object):
link_options = LinkOptions()
# 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)
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()
@ -420,7 +512,9 @@ class Session(object):
if upstream:
interface.swapparams("_params_up")
link_config(net_one, interface, link_options, devname=interface.name)
link_config(
net_one, interface, link_options, devname=interface.name
)
interface.swapparams("_params_up")
else:
link_config(net_one, interface, link_options)
@ -430,7 +524,12 @@ class Session(object):
link_config(net_two, interface, link_options)
else:
interface.swapparams("_params_up")
link_config(net_two, interface, link_options, devname=interface.name)
link_config(
net_two,
interface,
link_options,
devname=interface.name,
)
interface.swapparams("_params_up")
else:
raise ValueError("modify link for unknown nodes")
@ -448,12 +547,25 @@ class Session(object):
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):
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)
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)
link_config(
net_one,
interface_two,
link_options,
interface_two=interface_one,
)
finally:
if node_one:
node_one.lock.release()
@ -498,9 +610,21 @@ class Session(object):
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)
logging.info(
"creating node(%s) id(%s) name(%s) start(%s)",
node_class.__name__,
_id,
name,
start,
)
if _type in [NodeTypes.DOCKER, NodeTypes.LXC]:
node = self.create_node(cls=node_class, _id=_id, name=name, start=start, image=node_options.image)
node = self.create_node(
cls=node_class,
_id=_id,
name=name,
start=start,
image=node_options.image,
)
else:
node = self.create_node(cls=node_class, _id=_id, name=name, start=start)
@ -513,13 +637,20 @@ class Session(object):
self.set_node_position(node, node_options)
# add services to default and physical nodes only
if _type in [NodeTypes.DEFAULT, NodeTypes.PHYSICAL, NodeTypes.DOCKER, NodeTypes.LXC]:
if _type in [
NodeTypes.DEFAULT,
NodeTypes.PHYSICAL,
NodeTypes.DOCKER,
NodeTypes.LXC,
]:
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, CoreNodeBase) and not nodeutils.is_node(node, NodeTypes.RJ45)
is_boot_node = isinstance(node, CoreNodeBase) and not nodeutils.is_node(
node, NodeTypes.RJ45
)
if self.state == EventTypes.RUNTIME_STATE.value and is_boot_node:
self.write_nodes()
self.add_remove_control_interface(node=node, remove=False)
@ -596,7 +727,7 @@ class Session(object):
message_type=0,
id=node.id,
x_position=node.position.x,
y_position=node.position.y
y_position=node.position.y,
)
self.broadcast_node(node_data)
@ -615,7 +746,10 @@ class Session(object):
:return: True if active, False otherwise
"""
result = self.state in {EventTypes.RUNTIME_STATE.value, EventTypes.DATACOLLECT_STATE.value}
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
@ -723,9 +857,18 @@ class Session(object):
if not node_options:
node_options = NodeOptions()
node_options.model = "mdr"
return self.add_node(_type=NodeTypes.DEFAULT, _id=_id, node_options=node_options)
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):
def create_emane_network(
self,
model,
geo_reference,
geo_scale=None,
node_options=NodeOptions(),
config=None,
):
"""
Convenience method for creating an emane network.
@ -849,7 +992,11 @@ class Session(object):
state_name = state.name
if self.state == state_value:
logging.info("session(%s) is already in state: %s, skipping change", self.id, state_name)
logging.info(
"session(%s) is already in state: %s, skipping change",
self.id,
state_name,
)
return
self.state = state_value
@ -910,9 +1057,11 @@ class Session(object):
:param str data: hook data
:return: nothing
"""
logging.info("setting state hook: %s - %s from %s", hook_type, file_name, source_name)
logging.info(
"setting state hook: %s - %s from %s", hook_type, file_name, source_name
)
_hook_id, state = hook_type.split(':')[:2]
_hook_id, state = hook_type.split(":")[:2]
if not state.isdigit():
logging.error("error setting hook having state '%s'", state)
return
@ -966,8 +1115,14 @@ class Session(object):
# execute hook file
try:
args = ["/bin/sh", file_name]
subprocess.check_call(args, stdout=stdout, stderr=stderr,
close_fds=True, cwd=self.session_dir, env=self.get_environment())
subprocess.check_call(
args,
stdout=stdout,
stderr=stderr,
close_fds=True,
cwd=self.session_dir,
env=self.get_environment(),
)
except (OSError, subprocess.CalledProcessError):
logging.exception("error running hook: %s", file_name)
@ -982,9 +1137,14 @@ class Session(object):
try:
hook(state)
except:
message = "exception occured when running %s state hook: %s" % (coreapi.state_name(state), hook)
message = "exception occured when running %s state hook: %s" % (
coreapi.state_name(state),
hook,
)
logging.exception(message)
self.exception(ExceptionLevels.ERROR, "Session.run_state_hooks", None, message)
self.exception(
ExceptionLevels.ERROR, "Session.run_state_hooks", None, message
)
def add_state_hook(self, state, hook):
"""
@ -1057,15 +1217,23 @@ class Session(object):
if os.path.isfile(environment_config_file):
utils.load_config(environment_config_file, env)
except IOError:
logging.warning("environment configuration file does not exist: %s", environment_config_file)
logging.warning(
"environment configuration file does not exist: %s",
environment_config_file,
)
# attempt to read and add user environment file
if self.user:
environment_user_file = os.path.join("/home", self.user, ".core", "environment")
environment_user_file = os.path.join(
"/home", self.user, ".core", "environment"
)
try:
utils.load_config(environment_user_file, env)
except IOError:
logging.debug("user core environment settings file not present: %s", environment_user_file)
logging.debug(
"user core environment settings file not present: %s",
environment_user_file,
)
return env
@ -1187,7 +1355,9 @@ class Session(object):
with open(file_path, "w") as f:
for _id in self.nodes.keys():
node = self.nodes[_id]
f.write("%s %s %s %s\n" % (_id, node.name, node.apitype, type(node)))
f.write(
"%s %s %s %s\n" % (_id, node.name, node.apitype, type(node))
)
except IOError:
logging.exception("error writing nodes file")
@ -1196,8 +1366,13 @@ class Session(object):
Log information about the session in its current state.
"""
logging.info("session id=%s name=%s state=%s", self.id, self.name, self.state)
logging.info("file=%s thumbnail=%s node_count=%s/%s",
self.file_name, self.thumbnail, self.get_node_count(), len(self.nodes))
logging.info(
"file=%s thumbnail=%s node_count=%s/%s",
self.file_name,
self.thumbnail,
self.get_node_count(),
len(self.nodes),
)
def exception(self, level, source, node_id, text):
"""
@ -1216,7 +1391,7 @@ class Session(object):
level=level,
source=source,
date=time.ctime(),
text=text
text=text,
)
self.broadcast_exception(exception_data)
@ -1267,8 +1442,12 @@ class Session(object):
count = 0
for node_id in self.nodes:
node = self.nodes[node_id]
is_p2p_ctrlnet = nodeutils.is_node(node, (NodeTypes.PEER_TO_PEER, NodeTypes.CONTROL_NET))
is_tap = nodeutils.is_node(node, NodeTypes.TAP_BRIDGE) and not nodeutils.is_node(node, NodeTypes.TUNNEL)
is_p2p_ctrlnet = nodeutils.is_node(
node, (NodeTypes.PEER_TO_PEER, NodeTypes.CONTROL_NET)
)
is_tap = nodeutils.is_node(
node, NodeTypes.TAP_BRIDGE
) and not nodeutils.is_node(node, NodeTypes.TUNNEL)
if is_p2p_ctrlnet or is_tap:
continue
@ -1285,8 +1464,11 @@ class Session(object):
# this is called from instantiate() after receiving an event message
# for the instantiation state, and from the broker when distributed
# nodes have been started
logging.info("session(%s) checking if not in runtime state, current state: %s", self.id,
coreapi.state_name(self.state))
logging.info(
"session(%s) checking if not in runtime state, current state: %s",
self.id,
coreapi.state_name(self.state),
)
if self.state == EventTypes.RUNTIME_STATE.value:
logging.info("valid runtime state found, returning")
return
@ -1333,7 +1515,9 @@ class Session(object):
and links remain.
"""
node_count = self.get_node_count()
logging.info("session(%s) checking shutdown: %s nodes remaining", self.id, node_count)
logging.info(
"session(%s) checking shutdown: %s nodes remaining", self.id, node_count
)
shutdown = False
if node_count == 0:
@ -1364,7 +1548,9 @@ class Session(object):
for _id in self.nodes:
node = self.nodes[_id]
# TODO: PyCoreNode is not the type to check
if isinstance(node, CoreNodeBase) and not nodeutils.is_node(node, NodeTypes.RJ45):
if isinstance(node, CoreNodeBase) and not nodeutils.is_node(
node, NodeTypes.RJ45
):
# add a control interface if configured
logging.info("booting node(%s): %s", node.name, node.services)
self.add_remove_control_interface(node=node, remove=False)
@ -1446,7 +1632,12 @@ class Session(object):
:return: control net node
:rtype: core.nodes.network.CtrlNet
"""
logging.debug("add/remove control net: index(%s) remove(%s) conf_required(%s)", net_index, remove, conf_required)
logging.debug(
"add/remove control net: index(%s) remove(%s) conf_required(%s)",
net_index,
remove,
conf_required,
)
prefix_spec_list = self.get_control_net_prefixes()
prefix_spec = prefix_spec_list[net_index]
if not prefix_spec:
@ -1515,10 +1706,12 @@ class Session(object):
break
if not prefix:
logging.error("control network prefix not found for server: %s", servers[0])
logging.error(
"control network prefix not found for server: %s", servers[0]
)
assign_address = False
try:
prefix = prefixes[0].split(':', 1)[1]
prefix = prefixes[0].split(":", 1)[1]
except IndexError:
prefix = prefixes[0]
# len(prefixes) == 1
@ -1530,9 +1723,14 @@ class Session(object):
logging.info("controlnet prefix: %s - %s", type(prefix), prefix)
control_net_class = nodeutils.get_node_class(NodeTypes.CONTROL_NET)
control_net = self.create_node(cls=control_net_class, _id=_id, prefix=prefix,
assign_address=assign_address,
updown_script=updown_script, serverintf=server_interface)
control_net = self.create_node(
cls=control_net_class,
_id=_id,
prefix=prefix,
assign_address=assign_address,
updown_script=updown_script,
serverintf=server_interface,
)
# tunnels between controlnets will be built with Broker.addnettunnels()
# TODO: potentially remove documentation saying node ids are ints
@ -1543,7 +1741,9 @@ class Session(object):
return control_net
def add_remove_control_interface(self, node, net_index=0, remove=False, conf_required=True):
def add_remove_control_interface(
self, node, net_index=0, remove=False, conf_required=True
):
"""
Add a control interface to a node when a 'controlnet' prefix is
listed in the config file or session options. Uses
@ -1571,7 +1771,10 @@ class Session(object):
control_ip = node.id
try:
addrlist = ["%s/%s" % (control_net.prefix.addr(control_ip), control_net.prefix.prefixlen)]
addrlist = [
"%s/%s"
% (control_net.prefix.addr(control_ip), control_net.prefix.prefixlen)
]
except ValueError:
msg = "Control interface not added to node %s. " % node.id
msg += "Invalid control network prefix (%s). " % control_net.prefix
@ -1579,10 +1782,13 @@ class Session(object):
logging.exception(msg)
return
interface1 = node.newnetif(net=control_net,
ifindex=control_net.CTRLIF_IDX_BASE + net_index,
ifname="ctrl%d" % net_index, hwaddr=MacAddress.random(),
addrlist=addrlist)
interface1 = node.newnetif(
net=control_net,
ifindex=control_net.CTRLIF_IDX_BASE + net_index,
ifname="ctrl%d" % net_index,
hwaddr=MacAddress.random(),
addrlist=addrlist,
)
node.netif(interface1).control = True
def update_control_interface_hosts(self, net_index=0, remove=False):
@ -1644,15 +1850,26 @@ class Session(object):
if current_time > 0:
if event_time <= current_time:
logging.warning("could not schedule past event for time %s (run time is now %s)", event_time, current_time)
logging.warning(
"could not schedule past event for time %s (run time is now %s)",
event_time,
current_time,
)
return
event_time = event_time - current_time
self.event_loop.add_event(event_time, self.run_event, node=node, name=name, data=data)
self.event_loop.add_event(
event_time, self.run_event, node=node, name=name, data=data
)
if not name:
name = ""
logging.info("scheduled event %s at time %s data=%s", name, event_time + current_time, data)
logging.info(
"scheduled event %s at time %s data=%s",
name,
event_time + current_time,
data,
)
# TODO: if data is None, this blows up, but this ties into how event functions are ran, need to clean that up
def run_event(self, node_id=None, name=None, data=None):

View file

@ -7,21 +7,56 @@ 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")
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
@ -29,9 +64,16 @@ class SessionConfig(ConfigurableManager, ConfigurableOptions):
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)
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
@ -55,5 +97,6 @@ class SessionMetaData(ConfigurableManager):
passed in from configure messages destined to the "metadata" object.
The data is not otherwise interpreted or processed.
"""
name = "metadata"
config_type = RegisterTlvs.UTILITY.value

View file

@ -17,6 +17,7 @@ class CoreLocation(object):
track of a latitude/longitude/altitude reference point and scale in
order to convert between X,Y and geo coordinates.
"""
name = "location"
config_type = RegisterTlvs.UTILITY.value
@ -118,7 +119,14 @@ class CoreLocation(object):
try:
lat, lon = utm.to_latlon(e, n, zone[0], zone[1])
except utm.OutOfRangeError:
logging.exception("UTM out of range error for n=%s zone=%s xyz=(%s,%s,%s)", n, zone, x, y, z)
logging.exception(
"UTM out of range error for n=%s zone=%s xyz=(%s,%s,%s)",
n,
zone,
x,
y,
z,
)
lat, lon = self.refgeo[:2]
# self.info("getgeo(%s,%s,%s) e=%s n=%s zone=%s lat,lon,alt=" \
# "%.3f,%.3f,%.3f" % (x, y, z, e, n, zone, lat, lon, alt))
@ -265,9 +273,9 @@ class CoreLocation(object):
if n < 0:
# refpt in northern hemisphere and we crossed south of equator
n += 10000000
zone = (zone[0], 'M')
zone = (zone[0], "M")
elif n > 10000000:
# refpt in southern hemisphere and we crossed north of equator
n -= 10000000
zone = (zone[0], 'N')
zone = (zone[0], "N")
return e, n, zone

View file

@ -32,6 +32,7 @@ class MobilityManager(ModelManager):
Member of session class for handling configuration data for mobility and
range models.
"""
name = "MobilityManager"
config_type = RegisterTlvs.WIRELESS.value
@ -72,12 +73,16 @@ class MobilityManager(ModelManager):
for node_id in node_ids:
logging.info("checking mobility startup for node: %s", node_id)
logging.info("node mobility configurations: %s", self.get_all_configs(node_id))
logging.info(
"node mobility configurations: %s", self.get_all_configs(node_id)
)
try:
node = self.session.get_node(node_id)
except KeyError:
logging.warning("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:
@ -108,11 +113,13 @@ class MobilityManager(ModelManager):
try:
node = self.session.get_node(node_id)
except KeyError:
logging.exception("Ignoring event for model '%s', unknown node '%s'", name, node_id)
logging.exception(
"Ignoring event for model '%s', unknown node '%s'", name, node_id
)
return
# name is e.g. "mobility:ns2script"
models = name[9:].split(',')
models = name[9:].split(",")
for model in models:
try:
cls = self.models[model]
@ -120,7 +127,10 @@ class MobilityManager(ModelManager):
logging.warning("Ignoring event for unknown model '%s'", model)
continue
if cls.config_type in [RegisterTlvs.WIRELESS.value, RegisterTlvs.MOBILITY.value]:
if cls.config_type in [
RegisterTlvs.WIRELESS.value,
RegisterTlvs.MOBILITY.value,
]:
model = node.mobility
else:
continue
@ -130,12 +140,23 @@ class MobilityManager(ModelManager):
continue
if cls.name != model.name:
logging.warning("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:
if (
event_type == EventTypes.STOP.value
or event_type == EventTypes.RESTART.value
):
model.stop(move_initial=True)
if event_type == EventTypes.START.value or event_type == EventTypes.RESTART.value:
if (
event_type == EventTypes.START.value
or event_type == EventTypes.RESTART.value
):
model.start()
if event_type == EventTypes.PAUSE.value:
model.pause()
@ -164,7 +185,7 @@ class MobilityManager(ModelManager):
event_type=event_type,
name="mobility:%s" % model.name,
data=data,
time="%s" % time.time()
time="%s" % time.time(),
)
self.session.broadcast_event(event_data)
@ -198,7 +219,7 @@ class MobilityManager(ModelManager):
node_id = node.id
self.phys[node_id] = node
if netnum not in self.physnets:
self.physnets[netnum] = [node_id, ]
self.physnets[netnum] = [node_id]
else:
self.physnets[netnum].append(node_id)
@ -214,14 +235,19 @@ class MobilityManager(ModelManager):
:param message: link message to handle
:return: nothing
"""
if message.message_type == MessageTypes.LINK.value and message.flags & MessageFlags.ADD.value:
if (
message.message_type == MessageTypes.LINK.value
and message.flags & MessageFlags.ADD.value
):
nn = message.node_numbers()
# first node is always link layer node in Link add message
if nn[0] not in self.session.broker.network_nodes:
return
if nn[1] in self.session.broker.physical_nodes:
# record the fact that this PhysicalNode is linked to a net
dummy = CoreNodeBase(session=self.session, _id=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
@ -269,6 +295,7 @@ class WirelessModel(ConfigurableOptions):
Base class used by EMANE models and the basic range model.
Used for managing arbitrary configuration parameters.
"""
config_type = RegisterTlvs.WIRELESS.value
bitmap = None
position_callback = None
@ -321,21 +348,44 @@ class BasicRangeModel(WirelessModel):
and unlinks nodes based on this distance. This was formerly done from
the GUI.
"""
name = "basic_range"
options = [
Configuration(_id="range", _type=ConfigDataTypes.UINT32, default="275", label="wireless range (pixels)"),
Configuration(_id="bandwidth", _type=ConfigDataTypes.UINT64, default="54000000", label="bandwidth (bps)"),
Configuration(_id="jitter", _type=ConfigDataTypes.UINT64, default="0", label="transmission jitter (usec)"),
Configuration(_id="delay", _type=ConfigDataTypes.UINT64, default="5000",
label="transmission delay (usec)"),
Configuration(_id="error", _type=ConfigDataTypes.STRING, default="0", label="error rate (%)")
Configuration(
_id="range",
_type=ConfigDataTypes.UINT32,
default="275",
label="wireless range (pixels)",
),
Configuration(
_id="bandwidth",
_type=ConfigDataTypes.UINT64,
default="54000000",
label="bandwidth (bps)",
),
Configuration(
_id="jitter",
_type=ConfigDataTypes.UINT64,
default="0",
label="transmission jitter (usec)",
),
Configuration(
_id="delay",
_type=ConfigDataTypes.UINT64,
default="5000",
label="transmission delay (usec)",
),
Configuration(
_id="error",
_type=ConfigDataTypes.STRING,
default="0",
label="error rate (%)",
),
]
@classmethod
def config_groups(cls):
return [
ConfigGroup("Basic Range Parameters", 1, len(cls.configurations()))
]
return [ConfigGroup("Basic Range Parameters", 1, len(cls.configurations()))]
def __init__(self, session, _id):
"""
@ -365,7 +415,11 @@ class BasicRangeModel(WirelessModel):
:return: nothing
"""
self.range = int(float(config["range"]))
logging.info("basic range model configured for WLAN %d using range %d", self.wlan.id, 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:
self.bw = None
@ -386,8 +440,14 @@ class BasicRangeModel(WirelessModel):
"""
with self._netifslock:
for netif in self._netifs:
self.wlan.linkconfig(netif, bw=self.bw, delay=self.delay, loss=self.loss, duplicate=None,
jitter=self.jitter)
self.wlan.linkconfig(
netif,
bw=self.bw,
delay=self.delay,
loss=self.loss,
duplicate=None,
jitter=self.jitter,
)
def get_position(self, netif):
"""
@ -530,7 +590,7 @@ class BasicRangeModel(WirelessModel):
node1_id=interface1.node.id,
node2_id=interface2.node.id,
network_id=self.wlan.id,
link_type=LinkTypes.WIRELESS.value
link_type=LinkTypes.WIRELESS.value,
)
def sendlinkmsg(self, netif, netif2, unlink=False):
@ -604,6 +664,7 @@ class WayPointMobility(WirelessModel):
"""
Abstract class for mobility models that set node waypoints.
"""
name = "waypoint"
config_type = RegisterTlvs.MOBILITY.value
@ -664,7 +725,9 @@ class WayPointMobility(WirelessModel):
# no more waypoints or queued items, loop?
if not self.empty_queue_stop:
# keep running every refresh_ms, even with empty queue
self.session.event_loop.add_event(0.001 * self.refresh_ms, self.runround)
self.session.event_loop.add_event(
0.001 * self.refresh_ms, self.runround
)
return
if not self.loopwaypoints():
return self.stop(move_initial=False)
@ -916,16 +979,50 @@ class Ns2ScriptedMobility(WayPointMobility):
Handles the ns-2 script format, generated by scengen/setdest or
BonnMotion.
"""
name = "ns2script"
options = [
Configuration(_id="file", _type=ConfigDataTypes.STRING, label="mobility script file"),
Configuration(_id="refresh_ms", _type=ConfigDataTypes.UINT32, default="50", label="refresh time (ms)"),
Configuration(_id="loop", _type=ConfigDataTypes.BOOL, default="1", options=["On", "Off"], label="loop"),
Configuration(_id="autostart", _type=ConfigDataTypes.STRING, label="auto-start seconds (0.0 for runtime)"),
Configuration(_id="map", _type=ConfigDataTypes.STRING, label="node mapping (optional, e.g. 0:1,1:2,2:3)"),
Configuration(_id="script_start", _type=ConfigDataTypes.STRING, label="script file to run upon start"),
Configuration(_id="script_pause", _type=ConfigDataTypes.STRING, label="script file to run upon pause"),
Configuration(_id="script_stop", _type=ConfigDataTypes.STRING, label="script file to run upon stop")
Configuration(
_id="file", _type=ConfigDataTypes.STRING, label="mobility script file"
),
Configuration(
_id="refresh_ms",
_type=ConfigDataTypes.UINT32,
default="50",
label="refresh time (ms)",
),
Configuration(
_id="loop",
_type=ConfigDataTypes.BOOL,
default="1",
options=["On", "Off"],
label="loop",
),
Configuration(
_id="autostart",
_type=ConfigDataTypes.STRING,
label="auto-start seconds (0.0 for runtime)",
),
Configuration(
_id="map",
_type=ConfigDataTypes.STRING,
label="node mapping (optional, e.g. 0:1,1:2,2:3)",
),
Configuration(
_id="script_start",
_type=ConfigDataTypes.STRING,
label="script file to run upon start",
),
Configuration(
_id="script_pause",
_type=ConfigDataTypes.STRING,
label="script file to run upon pause",
),
Configuration(
_id="script_stop",
_type=ConfigDataTypes.STRING,
label="script file to run upon stop",
),
]
@classmethod
@ -956,7 +1053,11 @@ 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.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"]
@ -980,7 +1081,9 @@ class Ns2ScriptedMobility(WayPointMobility):
try:
f = open(filename, "r")
except IOError:
logging.exception("ns-2 scripted mobility failed to load file: %s", self.file)
logging.exception(
"ns-2 scripted mobility failed to load file: %s", self.file
)
return
logging.info("reading ns-2 script file: %s" % filename)
ln = 0
@ -988,7 +1091,7 @@ class Ns2ScriptedMobility(WayPointMobility):
inodenum = None
for line in f:
ln += 1
if line[:2] != '$n':
if line[:2] != "$n":
continue
try:
if line[:8] == "$ns_ at ":
@ -999,7 +1102,7 @@ class Ns2ScriptedMobility(WayPointMobility):
# $ns_ at 1.00 "$node_(6) setdest 500.0 178.0 25.0"
parts = line.split()
time = float(parts[2])
nodenum = parts[3][1 + parts[3].index('('):parts[3].index(')')]
nodenum = parts[3][1 + parts[3].index("(") : parts[3].index(")")]
x = float(parts[5])
y = float(parts[6])
z = None
@ -1010,15 +1113,15 @@ class Ns2ScriptedMobility(WayPointMobility):
# $node_(6) set X_ 780.0
parts = line.split()
time = 0.0
nodenum = parts[0][1 + parts[0].index('('):parts[0].index(')')]
if parts[2] == 'X_':
nodenum = parts[0][1 + parts[0].index("(") : parts[0].index(")")]
if parts[2] == "X_":
if ix is not None and iy is not None:
self.addinitial(self.map(inodenum), ix, iy, iz)
ix = iy = iz = None
ix = float(parts[3])
elif parts[2] == 'Y_':
elif parts[2] == "Y_":
iy = float(parts[3])
elif parts[2] == 'Z_':
elif parts[2] == "Z_":
iz = float(parts[3])
self.addinitial(self.map(nodenum), ix, iy, iz)
ix = iy = iz = None
@ -1026,7 +1129,9 @@ class Ns2ScriptedMobility(WayPointMobility):
else:
raise ValueError
except ValueError:
logging.exception("skipping line %d of file %s '%s'", ln, self.file, line)
logging.exception(
"skipping line %d of file %s '%s'", ln, self.file, line
)
continue
if ix is not None and iy is not None:
self.addinitial(self.map(inodenum), ix, iy, iz)
@ -1052,7 +1157,9 @@ class Ns2ScriptedMobility(WayPointMobility):
return sessfn
if self.session.user is not None:
userfn = os.path.join('/home', self.session.user, '.core', 'configs', file_name)
userfn = os.path.join(
"/home", self.session.user, ".core", "configs", file_name
)
if os.path.exists(userfn):
return userfn
@ -1098,16 +1205,22 @@ class Ns2ScriptedMobility(WayPointMobility):
:return: nothing
"""
if self.autostart == '':
if self.autostart == "":
logging.info("not auto-starting ns-2 script for %s" % self.wlan.name)
return
try:
t = float(self.autostart)
except ValueError:
logging.exception("Invalid auto-start seconds specified '%s' for %s", self.autostart, self.wlan.name)
logging.exception(
"Invalid auto-start seconds specified '%s' for %s",
self.autostart,
self.wlan.name,
)
return
self.movenodesinitial()
logging.info("scheduling ns-2 script for %s autostart at %s" % (self.wlan.name, t))
logging.info(
"scheduling ns-2 script for %s autostart at %s" % (self.wlan.name, t)
)
self.state = self.STATE_RUNNING
self.session.event_loop.add_event(t, self.run)
@ -1165,8 +1278,10 @@ class Ns2ScriptedMobility(WayPointMobility):
filename = self.script_pause
elif typestr == "stop":
filename = self.script_stop
if filename is None or filename == '':
if filename is None or filename == "":
return
filename = self.findfile(filename)
args = ["/bin/sh", filename, typestr]
utils.check_cmd(args, cwd=self.session.session_dir, env=self.session.get_environment())
utils.check_cmd(
args, cwd=self.session.session_dir, env=self.session.get_environment()
)

View file

@ -29,6 +29,7 @@ class NodeBase(object):
"""
Base class for CORE nodes (nodes and networks)
"""
apitype = None
# TODO: appears start has no usage, verify and remove
@ -196,7 +197,7 @@ class NodeBase(object):
altitude=alt,
model=model,
emulation_server=emulation_server,
services=services
services=services,
)
return node_data
@ -415,10 +416,13 @@ class CoreNode(CoreNodeBase):
"""
Provides standard core node logic.
"""
apitype = NodeTypes.DEFAULT.value
valid_address_types = {"inet", "inet6", "inet6link"}
def __init__(self, session, _id=None, name=None, nodedir=None, bootsh="boot.sh", start=True):
def __init__(
self, session, _id=None, name=None, nodedir=None, bootsh="boot.sh", start=True
):
"""
Create a CoreNode instance.
@ -431,7 +435,9 @@ class CoreNode(CoreNodeBase):
"""
super(CoreNode, self).__init__(session, _id, name, start)
self.nodedir = nodedir
self.ctrlchnlname = os.path.abspath(os.path.join(self.session.session_dir, self.name))
self.ctrlchnlname = os.path.abspath(
os.path.join(self.session.session_dir, self.name)
)
self.client = None
self.pid = None
self.up = False
@ -472,9 +478,12 @@ class CoreNode(CoreNodeBase):
vnoded = [
constants.VNODED_BIN,
"-v",
"-c", self.ctrlchnlname,
"-l", self.ctrlchnlname + ".log",
"-p", self.ctrlchnlname + ".pid"
"-c",
self.ctrlchnlname,
"-l",
self.ctrlchnlname + ".log",
"-p",
self.ctrlchnlname + ".pid",
]
if self.nodedir:
vnoded += ["-C", self.nodedir]
@ -609,7 +618,9 @@ class CoreNode(CoreNodeBase):
"""
if path[0] != "/":
raise ValueError("path not fully qualified: %s" % path)
hostpath = os.path.join(self.nodedir, os.path.normpath(path).strip("/").replace("/", "."))
hostpath = os.path.join(
self.nodedir, os.path.normpath(path).strip("/").replace("/", ".")
)
os.mkdir(hostpath)
self.mount(hostpath, path)
@ -624,7 +635,12 @@ class CoreNode(CoreNodeBase):
"""
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)
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)
@ -671,12 +687,20 @@ class CoreNode(CoreNodeBase):
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)
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.network_cmd([constants.IP_BIN, "link", "set", veth.name, "name", ifname])
self.network_cmd([constants.ETHTOOL_BIN, "-K", ifname, "rx", "off", "tx", "off"])
utils.check_cmd(
[constants.IP_BIN, "link", "set", veth.name, "netns", str(self.pid)]
)
self.network_cmd(
[constants.IP_BIN, "link", "set", veth.name, "name", ifname]
)
self.network_cmd(
[constants.ETHTOOL_BIN, "-K", ifname, "rx", "off", "tx", "off"]
)
veth.name = ifname
@ -721,7 +745,9 @@ class CoreNode(CoreNodeBase):
sessionid = self.session.short_session_id()
localname = "tap%s.%s.%s" % (self.id, ifindex, sessionid)
name = ifname
tuntap = TunTap(node=self, name=name, localname=localname, net=net, start=self.up)
tuntap = TunTap(
node=self, name=name, localname=localname, net=net, start=self.up
)
try:
self.addnetif(tuntap, ifindex)
@ -743,7 +769,15 @@ class CoreNode(CoreNodeBase):
"""
self._netif[ifindex].sethwaddr(addr)
if self.up:
args = [constants.IP_BIN, "link", "set", "dev", self.ifname(ifindex), "address", str(addr)]
args = [
constants.IP_BIN,
"link",
"set",
"dev",
self.ifname(ifindex),
"address",
str(addr),
]
self.network_cmd(args)
def addaddr(self, ifindex, addr):
@ -757,10 +791,26 @@ class CoreNode(CoreNodeBase):
if self.up:
# check if addr is ipv6
if ":" in str(addr):
args = [constants.IP_BIN, "addr", "add", str(addr), "dev", self.ifname(ifindex)]
args = [
constants.IP_BIN,
"addr",
"add",
str(addr),
"dev",
self.ifname(ifindex),
]
self.network_cmd(args)
else:
args = [constants.IP_BIN, "addr", "add", str(addr), "broadcast", "+", "dev", self.ifname(ifindex)]
args = [
constants.IP_BIN,
"addr",
"add",
str(addr),
"broadcast",
"+",
"dev",
self.ifname(ifindex),
]
self.network_cmd(args)
self._netif[ifindex].addaddr(addr)
@ -780,7 +830,16 @@ class CoreNode(CoreNodeBase):
logging.exception("trying to delete unknown address: %s" % addr)
if self.up:
self.network_cmd([constants.IP_BIN, "addr", "del", str(addr), "dev", self.ifname(ifindex)])
self.network_cmd(
[
constants.IP_BIN,
"addr",
"del",
str(addr),
"dev",
self.ifname(ifindex),
]
)
def delalladdr(self, ifindex, address_types=None):
"""
@ -799,7 +858,9 @@ class CoreNode(CoreNodeBase):
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))
raise ValueError(
"addr type must be in: %s" % " ".join(self.valid_address_types)
)
for address in addresses[address_type]:
self.deladdr(ifindex, address)
@ -814,7 +875,9 @@ class CoreNode(CoreNodeBase):
:return: nothing
"""
if self.up:
self.network_cmd([constants.IP_BIN, "link", "set", self.ifname(ifindex), "up"])
self.network_cmd(
[constants.IP_BIN, "link", "set", self.ifname(ifindex), "up"]
)
def newnetif(self, net=None, addrlist=None, hwaddr=None, ifindex=None, ifname=None):
"""
@ -870,18 +933,41 @@ class CoreNode(CoreNodeBase):
:return: nothing
"""
tmplen = 8
tmp1 = "tmp." + "".join([random.choice(string.ascii_lowercase) for _ in range(tmplen)])
tmp2 = "tmp." + "".join([random.choice(string.ascii_lowercase) for _ in range(tmplen)])
utils.check_cmd([constants.IP_BIN, "link", "add", "name", tmp1, "type", "veth", "peer", "name", tmp2])
tmp1 = "tmp." + "".join(
[random.choice(string.ascii_lowercase) for _ in range(tmplen)]
)
tmp2 = "tmp." + "".join(
[random.choice(string.ascii_lowercase) for _ in range(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.network_cmd([constants.IP_BIN, "link", "set", tmp1, "name", ifname])
interface = CoreInterface(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.network_cmd([constants.IP_BIN, "link", "set", tmp2, "name", otherifname])
other_interface = CoreInterface(node=othernode, name=otherifname, mtu=_DEFAULT_MTU)
utils.check_cmd(
[constants.IP_BIN, "link", "set", tmp2, "netns", str(othernode.pid)]
)
othernode.network_cmd(
[constants.IP_BIN, "link", "set", tmp2, "name", otherifname]
)
other_interface = CoreInterface(
node=othernode, name=otherifname, mtu=_DEFAULT_MTU
)
othernode.addnetif(other_interface, othernode.newifindex())
def addfile(self, srcname, filename):
@ -944,7 +1030,9 @@ class CoreNode(CoreNodeBase):
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)
logging.info(
"node(%s) added file: %s; mode: 0%o", self.name, open_file.name, mode
)
def nodefilecopy(self, filename, srcfilename, mode=None):
"""
@ -960,13 +1048,16 @@ class CoreNode(CoreNodeBase):
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)
logging.info(
"node(%s) copied file: %s; mode: %s", self.name, hostfilename, mode
)
class CoreNetworkBase(NodeBase):
"""
Base class for networks
"""
linktype = LinkTypes.WIRED.value
def __init__(self, session, _id, name, start=True):
@ -1044,9 +1135,9 @@ class CoreNetworkBase(NodeBase):
linked_node = netif.othernet
if linked_node.id == self.id:
continue
netif.swapparams('_params_up')
netif.swapparams("_params_up")
upstream_params = netif.getparams()
netif.swapparams('_params_up')
netif.swapparams("_params_up")
if netif.getparams() != upstream_params:
uni = True
@ -1088,7 +1179,7 @@ class CoreNetworkBase(NodeBase):
bandwidth=netif.getparam("bw"),
dup=netif.getparam("duplicate"),
jitter=netif.getparam("jitter"),
per=netif.getparam("loss")
per=netif.getparam("loss"),
)
all_links.append(link_data)
@ -1096,7 +1187,7 @@ class CoreNetworkBase(NodeBase):
if not uni:
continue
netif.swapparams('_params_up')
netif.swapparams("_params_up")
link_data = LinkData(
message_type=0,
node1_id=linked_node.id,
@ -1106,9 +1197,9 @@ class CoreNetworkBase(NodeBase):
bandwidth=netif.getparam("bw"),
dup=netif.getparam("duplicate"),
jitter=netif.getparam("jitter"),
per=netif.getparam("loss")
per=netif.getparam("loss"),
)
netif.swapparams('_params_up')
netif.swapparams("_params_up")
all_links.append(link_data)

View file

@ -135,7 +135,15 @@ class VnodeClient(object):
:rtype: int
"""
args = utils.split_args(args)
return os.spawnlp(os.P_WAIT, constants.VCMD_BIN, constants.VCMD_BIN, "-c", self.ctrlchnlname, "--", *args)
return os.spawnlp(
os.P_WAIT,
constants.VCMD_BIN,
constants.VCMD_BIN,
"-c",
self.ctrlchnlname,
"--",
*args
)
def redircmd(self, infd, outfd, errfd, args, wait=True):
"""
@ -175,11 +183,27 @@ class VnodeClient(object):
:return: terminal command result
:rtype: int
"""
args = ("xterm", "-ut", "-title", self.name, "-e", constants.VCMD_BIN, "-c", self.ctrlchnlname, "--", sh)
args = (
"xterm",
"-ut",
"-title",
self.name,
"-e",
constants.VCMD_BIN,
"-c",
self.ctrlchnlname,
"--",
sh,
)
if "SUDO_USER" in os.environ:
args = ("su", "-s", "/bin/sh", "-c",
"exec " + " ".join(map(lambda x: "'%s'" % x, args)),
os.environ["SUDO_USER"])
args = (
"su",
"-s",
"/bin/sh",
"-c",
"exec " + " ".join(map(lambda x: "'%s'" % x, args)),
os.environ["SUDO_USER"],
)
return os.spawnvp(os.P_NOWAIT, args[0], args)
def termcmdstring(self, sh="/bin/sh"):

View file

@ -219,8 +219,20 @@ class Veth(CoreInterface):
:return: nothing
:raises CoreCommandError: when there is a command exception
"""
utils.check_cmd([constants.IP_BIN, "link", "add", "name", self.localname,
"type", "veth", "peer", "name", self.name])
utils.check_cmd(
[
constants.IP_BIN,
"link",
"add",
"name",
self.localname,
"type",
"veth",
"peer",
"name",
self.name,
]
)
utils.check_cmd([constants.IP_BIN, "link", "set", self.localname, "up"])
self.up = True
@ -235,7 +247,9 @@ class Veth(CoreInterface):
if self.node:
try:
self.node.network_cmd([constants.IP_BIN, "-6", "addr", "flush", "dev", self.name])
self.node.network_cmd(
[constants.IP_BIN, "-6", "addr", "flush", "dev", self.name]
)
except CoreCommandError:
logging.exception("error shutting down interface")
@ -296,7 +310,9 @@ class TunTap(CoreInterface):
return
try:
self.node.network_cmd([constants.IP_BIN, "-6", "addr", "flush", "dev", self.name])
self.node.network_cmd(
[constants.IP_BIN, "-6", "addr", "flush", "dev", self.name]
)
except CoreCommandError:
logging.exception("error shutting down tunnel tap")
@ -394,8 +410,12 @@ class TunTap(CoreInterface):
"""
self.waitfordevicelocal()
netns = str(self.node.pid)
utils.check_cmd([constants.IP_BIN, "link", "set", self.localname, "netns", netns])
self.node.network_cmd([constants.IP_BIN, "link", "set", self.localname, "name", self.name])
utils.check_cmd(
[constants.IP_BIN, "link", "set", self.localname, "netns", netns]
)
self.node.network_cmd(
[constants.IP_BIN, "link", "set", self.localname, "name", self.name]
)
self.node.network_cmd([constants.IP_BIN, "link", "set", self.name, "up"])
def setaddrs(self):
@ -406,7 +426,9 @@ class TunTap(CoreInterface):
"""
self.waitfordevicenode()
for addr in self.addrlist:
self.node.network_cmd([constants.IP_BIN, "addr", "add", str(addr), "dev", self.name])
self.node.network_cmd(
[constants.IP_BIN, "addr", "add", str(addr), "dev", self.name]
)
class GreTap(CoreInterface):
@ -416,9 +438,19 @@ class GreTap(CoreInterface):
having a MAC address. The MAC address is required for bridging.
"""
def __init__(self, node=None, name=None, session=None, mtu=1458,
remoteip=None, _id=None, localip=None, ttl=255,
key=None, start=True):
def __init__(
self,
node=None,
name=None,
session=None,
mtu=1458,
remoteip=None,
_id=None,
localip=None,
ttl=255,
key=None,
start=True,
):
"""
Creates a GreTap instance.
@ -438,7 +470,7 @@ class GreTap(CoreInterface):
self.session = session
if _id is None:
# from PyCoreObj
_id = ((id(self) >> 16) ^ (id(self) & 0xffff)) & 0xffff
_id = ((id(self) >> 16) ^ (id(self) & 0xFFFF)) & 0xFFFF
self.id = _id
sessionid = self.session.short_session_id()
# interface name on the local host machine
@ -450,8 +482,16 @@ class GreTap(CoreInterface):
if remoteip is None:
raise ValueError("missing remote IP required for GRE TAP device")
args = [constants.IP_BIN, "link", "add", self.localname, "type", "gretap",
"remote", str(remoteip)]
args = [
constants.IP_BIN,
"link",
"add",
self.localname,
"type",
"gretap",
"remote",
str(remoteip),
]
if localip:
args += ["local", str(localip)]
if ttl:

View file

@ -49,7 +49,7 @@ class MacAddress(object):
oui ^= 0x020000000000
# append EUI-48 octets
oui = (oui << 16) | 0xFFFE000000
return IpAddress(AF_INET6, struct.pack("!QQ", 0xfe80 << 48, oui | nic))
return IpAddress(AF_INET6, struct.pack("!QQ", 0xFE80 << 48, oui | nic))
@classmethod
def from_string(cls, s):
@ -156,7 +156,7 @@ class IpAddress(object):
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
tmp[i] = x & 0xFF
carry = x >> 8
if carry == 0:
break
@ -237,7 +237,7 @@ class IpPrefix(object):
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
prefix = bytes([self.prefix[i] & (netmask & 0xFF)]) + prefix
netmask >>= 8
self.prefix = self.prefix[:i] + prefix
@ -263,7 +263,11 @@ class IpPrefix(object):
elif self is other:
return True
else:
return other.af == self.af and other.prefixlen == self.prefixlen and other.prefix == self.prefix
return (
other.af == self.af
and other.prefixlen == self.prefixlen
and other.prefix == self.prefix
)
def __add__(self, other):
"""
@ -314,15 +318,20 @@ class IpPrefix(object):
if tmp in [-1, 0, 1] and self.addrlen == self.prefixlen:
return IpAddress(self.af, self.prefix)
if tmp == 0 or tmp > (1 << (self.addrlen - self.prefixlen)) - 1 or (
self.af == AF_INET and tmp == (1 << (self.addrlen - self.prefixlen)) - 1):
if (
tmp == 0
or tmp > (1 << (self.addrlen - self.prefixlen)) - 1
or (
self.af == AF_INET and tmp == (1 << (self.addrlen - self.prefixlen)) - 1
)
):
raise ValueError("invalid hostid for prefix %s: %s" % (self, hostid))
addr = bytes(b"")
prefix_endpoint = -1
for i in range(-1, -(self.addrlen >> 3) - 1, -1):
prefix_endpoint = i
addr = bytes([self.prefix[i] | (tmp & 0xff)]) + addr
addr = bytes([self.prefix[i] | (tmp & 0xFF)]) + addr
tmp >>= 8
if not tmp:
break

View file

@ -16,10 +16,9 @@ class LxdClient(object):
self._addr = {}
def create_container(self):
utils.check_cmd("lxc launch {image} {name}".format(
name=self.name,
image=self.image
))
utils.check_cmd(
"lxc launch {image} {name}".format(name=self.name, image=self.image)
)
data = self.get_info()
self.pid = data["state"]["pid"]
return self.pid
@ -31,7 +30,9 @@ class LxdClient(object):
raise CoreCommandError(status, args, output)
data = json.loads(output)
if not data:
raise CoreCommandError(status, args, "LXC({name}) not present".format(name=self.name))
raise CoreCommandError(
status, args, "LXC({name}) not present".format(name=self.name)
)
return data[0]
def is_alive(self):
@ -42,15 +43,10 @@ class LxdClient(object):
return False
def stop_container(self):
utils.check_cmd("lxc delete --force {name}".format(
name=self.name
))
utils.check_cmd("lxc delete --force {name}".format(name=self.name))
def _cmd_args(self, cmd):
return "lxc exec -nT {name} -- {cmd}".format(
name=self.name,
cmd=cmd
)
return "lxc exec -nT {name} -- {cmd}".format(name=self.name, cmd=cmd)
def cmd_output(self, cmd):
if isinstance(cmd, list):
@ -67,10 +63,7 @@ class LxdClient(object):
return utils.cmd(args, wait)
def _ns_args(self, cmd):
return "nsenter -t {pid} -m -u -i -p -n {cmd}".format(
pid=self.pid,
cmd=cmd
)
return "nsenter -t {pid} -m -u -i -p -n {cmd}".format(pid=self.pid, cmd=cmd)
def ns_cmd_output(self, cmd):
if isinstance(cmd, list):
@ -91,9 +84,7 @@ class LxdClient(object):
destination = os.path.join("/root/", destination)
args = "lxc file push {source} {name}/{destination}".format(
source=source,
name=self.name,
destination=destination
source=source, name=self.name, destination=destination
)
status, output = utils.cmd_output(args)
if status:
@ -137,7 +128,16 @@ class LxdClient(object):
class LxcNode(CoreNode):
apitype = NodeTypes.LXC.value
def __init__(self, session, _id=None, name=None, nodedir=None, bootsh="boot.sh", start=True, image=None):
def __init__(
self,
session,
_id=None,
name=None,
nodedir=None,
bootsh="boot.sh",
start=True,
image=None,
):
"""
Create a LxcNode instance.
@ -292,7 +292,9 @@ class LxcNode(CoreNode):
:param int mode: mode to copy to
:return: nothing
"""
logging.info("node file copy file(%s) source(%s) mode(%s)", filename, srcfilename, mode)
logging.info(
"node file copy file(%s) source(%s) mode(%s)", filename, srcfilename, mode
)
raise Exception("not supported")
def addnetif(self, netif, ifindex):

View file

@ -16,12 +16,9 @@ from core.nodes import ipaddress
from core.nodes.base import CoreNetworkBase
from core.nodes.interface import GreTap, Veth
utils.check_executables([
constants.BRCTL_BIN,
constants.IP_BIN,
constants.EBTABLES_BIN,
constants.TC_BIN
])
utils.check_executables(
[constants.BRCTL_BIN, constants.IP_BIN, constants.EBTABLES_BIN, constants.TC_BIN]
)
ebtables_lock = threading.Lock()
@ -32,6 +29,7 @@ class EbtablesQueue(object):
atomic commits. This improves performance and reliability when there are
many WLAN link updates.
"""
# update rate is every 300ms
rate = 0.3
# ebtables
@ -81,7 +79,9 @@ class EbtablesQueue(object):
try:
del self.last_update_time[wlan]
except KeyError:
logging.exception("error deleting last update time for wlan, ignored before: %s", wlan)
logging.exception(
"error deleting last update time for wlan, ignored before: %s", wlan
)
if len(self.last_update_time) > 0:
return
@ -166,7 +166,7 @@ class EbtablesQueue(object):
:return: nothing
"""
# save kernel ebtables snapshot to a file
args = self.ebatomiccmd(["--atomic-save", ])
args = self.ebatomiccmd(["--atomic-save"])
utils.check_cmd(args)
# modify the table file using queued ebtables commands
@ -176,7 +176,7 @@ class EbtablesQueue(object):
self.cmds = []
# commit the table file to the kernel
args = self.ebatomiccmd(["--atomic-commit", ])
args = self.ebatomiccmd(["--atomic-commit"])
utils.check_cmd(args)
try:
@ -203,20 +203,60 @@ class EbtablesQueue(object):
"""
with wlan._linked_lock:
# flush the chain
self.cmds.extend([["-F", wlan.brname], ])
self.cmds.extend([["-F", wlan.brname]])
# rebuild the chain
for netif1, v in wlan._linked.items():
for netif2, linked in v.items():
if wlan.policy == "DROP" and linked:
self.cmds.extend([["-A", wlan.brname, "-i", netif1.localname,
"-o", netif2.localname, "-j", "ACCEPT"],
["-A", wlan.brname, "-o", netif1.localname,
"-i", netif2.localname, "-j", "ACCEPT"]])
self.cmds.extend(
[
[
"-A",
wlan.brname,
"-i",
netif1.localname,
"-o",
netif2.localname,
"-j",
"ACCEPT",
],
[
"-A",
wlan.brname,
"-o",
netif1.localname,
"-i",
netif2.localname,
"-j",
"ACCEPT",
],
]
)
elif wlan.policy == "ACCEPT" and not linked:
self.cmds.extend([["-A", wlan.brname, "-i", netif1.localname,
"-o", netif2.localname, "-j", "DROP"],
["-A", wlan.brname, "-o", netif1.localname,
"-i", netif2.localname, "-j", "DROP"]])
self.cmds.extend(
[
[
"-A",
wlan.brname,
"-i",
netif1.localname,
"-o",
netif2.localname,
"-j",
"DROP",
],
[
"-A",
wlan.brname,
"-o",
netif1.localname,
"-i",
netif2.localname,
"-j",
"DROP",
],
]
)
# a global object because all WLANs share the same queue
@ -241,6 +281,7 @@ class CoreNetwork(CoreNetworkBase):
"""
Provides linux bridge network functionality for core nodes.
"""
policy = "DROP"
def __init__(self, session, _id=None, name=None, start=True, policy=None):
@ -280,10 +321,21 @@ class CoreNetwork(CoreNetworkBase):
utils.check_cmd([constants.BRCTL_BIN, "setfd", self.brname, "0"])
utils.check_cmd([constants.IP_BIN, "link", "set", self.brname, "up"])
# create a new ebtables chain for this bridge
ebtablescmds(utils.check_cmd, [
[constants.EBTABLES_BIN, "-N", self.brname, "-P", self.policy],
[constants.EBTABLES_BIN, "-A", "FORWARD", "--logical-in", self.brname, "-j", self.brname]
])
ebtablescmds(
utils.check_cmd,
[
[constants.EBTABLES_BIN, "-N", self.brname, "-P", self.policy],
[
constants.EBTABLES_BIN,
"-A",
"FORWARD",
"--logical-in",
self.brname,
"-j",
self.brname,
],
],
)
# turn off multicast snooping so mcast forwarding occurs w/o IGMP joins
snoop = "/sys/devices/virtual/net/%s/bridge/multicast_snooping" % self.brname
if os.path.exists(snoop):
@ -306,10 +358,21 @@ class CoreNetwork(CoreNetworkBase):
try:
utils.check_cmd([constants.IP_BIN, "link", "set", self.brname, "down"])
utils.check_cmd([constants.BRCTL_BIN, "delbr", self.brname])
ebtablescmds(utils.check_cmd, [
[constants.EBTABLES_BIN, "-D", "FORWARD", "--logical-in", self.brname, "-j", self.brname],
[constants.EBTABLES_BIN, "-X", self.brname]
])
ebtablescmds(
utils.check_cmd,
[
[
constants.EBTABLES_BIN,
"-D",
"FORWARD",
"--logical-in",
self.brname,
"-j",
self.brname,
],
[constants.EBTABLES_BIN, "-X", self.brname],
],
)
except CoreCommandError:
logging.exception("error during shutdown")
@ -331,7 +394,9 @@ class CoreNetwork(CoreNetworkBase):
:return: nothing
"""
if self.up:
utils.check_cmd([constants.BRCTL_BIN, "addif", self.brname, netif.localname])
utils.check_cmd(
[constants.BRCTL_BIN, "addif", self.brname, netif.localname]
)
utils.check_cmd([constants.IP_BIN, "link", "set", netif.localname, "up"])
CoreNetworkBase.attach(self, netif)
@ -344,7 +409,9 @@ class CoreNetwork(CoreNetworkBase):
:return: nothing
"""
if self.up:
utils.check_cmd([constants.BRCTL_BIN, "delif", self.brname, netif.localname])
utils.check_cmd(
[constants.BRCTL_BIN, "delif", self.brname, netif.localname]
)
CoreNetworkBase.detach(self, netif)
@ -409,8 +476,17 @@ class CoreNetwork(CoreNetworkBase):
ebq.ebchange(self)
def linkconfig(self, netif, bw=None, delay=None, loss=None, duplicate=None,
jitter=None, netif2=None, devname=None):
def linkconfig(
self,
netif,
bw=None,
delay=None,
loss=None,
duplicate=None,
jitter=None,
netif2=None,
devname=None,
):
"""
Configure link parameters by applying tc queuing disciplines on the interface.
@ -434,12 +510,13 @@ class CoreNetwork(CoreNetworkBase):
if bw is not None:
burst = max(2 * netif.mtu, bw / 1000)
# max IP payload
limit = 0xffff
tbf = ["tbf", "rate", str(bw),
"burst", str(burst), "limit", str(limit)]
limit = 0xFFFF
tbf = ["tbf", "rate", str(bw), "burst", str(burst), "limit", str(limit)]
if bw > 0:
if self.up:
logging.debug("linkconfig: %s" % ([tc + parent + ["handle", "1:"] + tbf],))
logging.debug(
"linkconfig: %s" % ([tc + parent + ["handle", "1:"] + tbf],)
)
utils.check_cmd(tc + parent + ["handle", "1:"] + tbf)
netif.setparam("has_tbf", True)
changed = True
@ -494,7 +571,9 @@ class CoreNetwork(CoreNetworkBase):
netif.setparam("has_netem", False)
elif len(netem) > 1:
if self.up:
logging.debug("linkconfig: %s" % ([tc + parent + ["handle", "10:"] + netem],))
logging.debug(
"linkconfig: %s" % ([tc + parent + ["handle", "10:"] + netem],)
)
utils.check_cmd(tc + parent + ["handle", "10:"] + netem)
netif.setparam("has_netem", True)
@ -526,7 +605,9 @@ class CoreNetwork(CoreNetworkBase):
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
@ -567,7 +648,9 @@ class CoreNetwork(CoreNetworkBase):
return
for addr in addrlist:
utils.check_cmd([constants.IP_BIN, "addr", "add", str(addr), "dev", self.brname])
utils.check_cmd(
[constants.IP_BIN, "addr", "add", str(addr), "dev", self.brname]
)
class GreTapBridge(CoreNetwork):
@ -576,8 +659,18 @@ class GreTapBridge(CoreNetwork):
another system.
"""
def __init__(self, session, remoteip=None, _id=None, name=None,
policy="ACCEPT", localip=None, ttl=255, key=None, start=True):
def __init__(
self,
session,
remoteip=None,
_id=None,
name=None,
policy="ACCEPT",
localip=None,
ttl=255,
key=None,
start=True,
):
"""
Create a GreTapBridge instance.
@ -591,7 +684,9 @@ class GreTapBridge(CoreNetwork):
:param key: gre tap key
:param bool start: start flag
"""
CoreNetwork.__init__(self, session=session, _id=_id, 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.id
@ -603,8 +698,14 @@ class GreTapBridge(CoreNetwork):
if remoteip is None:
self.gretap = None
else:
self.gretap = GreTap(node=self, session=session, remoteip=remoteip,
localip=localip, ttl=ttl, key=self.grekey)
self.gretap = GreTap(
node=self,
session=session,
remoteip=remoteip,
localip=localip,
ttl=ttl,
key=self.grekey,
)
if start:
self.startup()
@ -646,8 +747,13 @@ class GreTapBridge(CoreNetwork):
localip = None
if len(addrlist) > 1:
localip = addrlist[1].split("/")[0]
self.gretap = GreTap(session=self.session, remoteip=remoteip,
localip=localip, ttl=self.ttl, key=self.grekey)
self.gretap = GreTap(
session=self.session,
remoteip=remoteip,
localip=localip,
ttl=self.ttl,
key=self.grekey,
)
self.attach(self.gretap)
def setkey(self, key):
@ -665,6 +771,7 @@ class CtrlNet(CoreNetwork):
"""
Control network functionality.
"""
policy = "ACCEPT"
# base control interface index
CTRLIF_IDX_BASE = 99
@ -672,12 +779,21 @@ class CtrlNet(CoreNetwork):
"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"
"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):
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.
@ -724,12 +840,18 @@ class CtrlNet(CoreNetwork):
logging.info("address %s", addr)
if self.updown_script:
logging.info("interface %s updown script (%s startup) called", self.brname, 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])
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"])
@ -756,7 +878,9 @@ class CtrlNet(CoreNetwork):
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
"Stop all sessions and, if needed, delete %s to continue.",
oldbr,
oldbr,
)
return True
return False
@ -769,13 +893,23 @@ class CtrlNet(CoreNetwork):
"""
if self.serverintf is not None:
try:
utils.check_cmd([constants.BRCTL_BIN, "delif", self.brname, self.serverintf])
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)
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)
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")
@ -797,6 +931,7 @@ class PtpNet(CoreNetwork):
"""
Peer to peer network node.
"""
policy = "ACCEPT"
def attach(self, netif):
@ -807,7 +942,9 @@ class PtpNet(CoreNetwork):
:return: nothing
"""
if len(self._netif) >= 2:
raise ValueError("Point-to-point links support at most 2 network interfaces")
raise ValueError(
"Point-to-point links support at most 2 network interfaces"
)
CoreNetwork.attach(self, netif)
@ -922,7 +1059,7 @@ class PtpNet(CoreNetwork):
jitter=if2.getparam("jitter"),
unidirectional=1,
interface1_id=if2.node.getifindex(if2),
interface2_id=if1.node.getifindex(if1)
interface2_id=if1.node.getifindex(if1),
)
all_links.append(link_data)
@ -933,6 +1070,7 @@ class SwitchNode(CoreNetwork):
"""
Provides switch functionality within a core node.
"""
apitype = NodeTypes.SWITCH.value
policy = "ACCEPT"
type = "lanswitch"
@ -943,6 +1081,7 @@ 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"
@ -968,6 +1107,7 @@ class WlanNode(CoreNetwork):
"""
Provides wireless lan functionality within a core node.
"""
apitype = NodeTypes.WIRELESS_LAN.value
linktype = LinkTypes.WIRELESS.value
policy = "DROP"
@ -1029,7 +1169,9 @@ class WlanNode(CoreNetwork):
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)
logging.info(
"node(%s) updating model(%s): %s", self.id, self.model.name, config
)
self.model.update_config(config)
if self.model.position_callback:
for netif in self.netifs():
@ -1058,6 +1200,7 @@ class TunnelNode(GreTapBridge):
"""
Provides tunnel functionality in a core node.
"""
apitype = NodeTypes.TUNNEL.value
policy = "ACCEPT"
type = "tunnel"

View file

@ -28,5 +28,5 @@ NODES = {
NodeTypes.PEER_TO_PEER: core.nodes.network.PtpNet,
NodeTypes.CONTROL_NET: core.nodes.network.CtrlNet,
NodeTypes.DOCKER: core.nodes.docker.DockerNode,
NodeTypes.LXC: core.nodes.lxd.LxcNode
NodeTypes.LXC: core.nodes.lxd.LxcNode,
}

View file

@ -21,11 +21,7 @@ ebtables_queue = EbtablesQueue()
ebtables_lock = threading.Lock()
utils.check_executables([
constants.IP_BIN,
constants.EBTABLES_BIN,
constants.TC_BIN
])
utils.check_executables([constants.IP_BIN, constants.EBTABLES_BIN, constants.TC_BIN])
def ebtables_commands(call, commands):
@ -83,10 +79,21 @@ class OvsNet(CoreNetworkBase):
utils.check_cmd([constants.IP_BIN, "link", "set", self.bridge_name, "up"])
# create a new ebtables chain for this bridge
ebtables_commands(utils.check_cmd, [
[constants.EBTABLES_BIN, "-N", self.bridge_name, "-P", self.policy],
[constants.EBTABLES_BIN, "-A", "FORWARD", "--logical-in", self.bridge_name, "-j", self.bridge_name]
])
ebtables_commands(
utils.check_cmd,
[
[constants.EBTABLES_BIN, "-N", self.bridge_name, "-P", self.policy],
[
constants.EBTABLES_BIN,
"-A",
"FORWARD",
"--logical-in",
self.bridge_name,
"-j",
self.bridge_name,
],
],
)
self.up = True
@ -100,10 +107,21 @@ class OvsNet(CoreNetworkBase):
try:
utils.check_cmd([constants.IP_BIN, "link", "set", self.bridge_name, "down"])
utils.check_cmd([constants.OVS_BIN, "del-br", self.bridge_name])
ebtables_commands(utils.check_cmd, [
[constants.EBTABLES_BIN, "-D", "FORWARD", "--logical-in", self.bridge_name, "-j", self.bridge_name],
[constants.EBTABLES_BIN, "-X", self.bridge_name]
])
ebtables_commands(
utils.check_cmd,
[
[
constants.EBTABLES_BIN,
"-D",
"FORWARD",
"--logical-in",
self.bridge_name,
"-j",
self.bridge_name,
],
[constants.EBTABLES_BIN, "-X", self.bridge_name],
],
)
except CoreCommandError:
logging.exception("error bringing bridge down and removing it")
@ -118,14 +136,20 @@ class OvsNet(CoreNetworkBase):
def attach(self, interface):
if self.up:
utils.check_cmd([constants.OVS_BIN, "add-port", self.bridge_name, interface.localname])
utils.check_cmd([constants.IP_BIN, "link", "set", interface.localname, "up"])
utils.check_cmd(
[constants.OVS_BIN, "add-port", self.bridge_name, interface.localname]
)
utils.check_cmd(
[constants.IP_BIN, "link", "set", interface.localname, "up"]
)
CoreNetworkBase.attach(self, interface)
def detach(self, interface):
if self.up:
utils.check_cmd([constants.OVS_BIN, "del-port", self.bridge_name, interface.localname])
utils.check_cmd(
[constants.OVS_BIN, "del-port", self.bridge_name, interface.localname]
)
CoreNetworkBase.detach(self, interface)
@ -177,8 +201,17 @@ class OvsNet(CoreNetworkBase):
ebtables_queue.ebchange(self)
def linkconfig(self, netif, bw=None, delay=None, loss=None, duplicate=None,
jitter=None, netif2=None, devname=None):
def linkconfig(
self,
netif,
bw=None,
delay=None,
loss=None,
duplicate=None,
jitter=None,
netif2=None,
devname=None,
):
"""
Configure link parameters by applying tc queuing disciplines on the
interface.
@ -196,9 +229,19 @@ class OvsNet(CoreNetworkBase):
if bw > 0:
if self.up:
burst = max(2 * netif.mtu, bw / 1000)
limit = 0xffff # max IP payload
tbf = ["tbf", "rate", str(bw), "burst", str(burst), "limit", str(limit)]
logging.info("linkconfig: %s" % [tc + parent + ["handle", "1:"] + tbf])
limit = 0xFFFF # max IP payload
tbf = [
"tbf",
"rate",
str(bw),
"burst",
str(burst),
"limit",
str(limit),
]
logging.info(
"linkconfig: %s" % [tc + parent + ["handle", "1:"] + tbf]
)
utils.check_cmd(tc + parent + ["handle", "1:"] + tbf)
netif.setparam("has_tbf", True)
elif netif.getparam("has_tbf") and bw <= 0:
@ -228,7 +271,15 @@ class OvsNet(CoreNetworkBase):
jitter_changed = netif.setparam("jitter", jitter)
# if nothing changed return
if not any([bandwidth_changed, delay_changed, loss_changed, duplicate_changed, jitter_changed]):
if not any(
[
bandwidth_changed,
delay_changed,
loss_changed,
duplicate_changed,
jitter_changed,
]
):
return
# jitter and delay use the same delay statement
@ -259,7 +310,9 @@ class OvsNet(CoreNetworkBase):
netif.setparam("has_netem", False)
elif len(netem) > 1:
if self.up:
logging.info("linkconfig: %s" % ([tc + parent + ["handle", "10:"] + netem],))
logging.info(
"linkconfig: %s" % ([tc + parent + ["handle", "10:"] + netem],)
)
utils.check_cmd(tc + parent + ["handle", "10:"] + netem)
netif.setparam("has_netem", True)
@ -289,11 +342,15 @@ class OvsNet(CoreNetworkBase):
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 of localname
utils.check_cmd([constants.OVS_BIN, "add-port", network.bridge_name, interface.name])
utils.check_cmd(
[constants.OVS_BIN, "add-port", network.bridge_name, interface.name]
)
utils.check_cmd([constants.IP_BIN, "link", "set", interface.name, "up"])
network.attach(interface)
@ -320,7 +377,9 @@ class OvsNet(CoreNetworkBase):
return
for address in addresses:
utils.check_cmd([constants.IP_BIN, "addr", "add", str(address), "dev", self.bridge_name])
utils.check_cmd(
[constants.IP_BIN, "addr", "add", str(address), "dev", self.bridge_name]
)
class OvsCtrlNet(OvsNet):
@ -330,11 +389,21 @@ class OvsCtrlNet(OvsNet):
"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"
"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):
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
@ -352,7 +421,10 @@ class OvsCtrlNet(OvsNet):
else:
addr = self.prefix.max_addr()
message = "Added control network bridge: %s %s" % (self.bridge_name, self.prefix)
message = "Added control network bridge: %s %s" % (
self.bridge_name,
self.prefix,
)
addresses = ["%s/%s" % (addr, self.prefix.prefixlen)]
if self.assign_address:
self.addrconfig(addresses=addresses)
@ -360,11 +432,16 @@ class OvsCtrlNet(OvsNet):
logging.info(message)
if self.updown_script:
logging.info("interface %s updown script %s startup called" % (self.bridge_name, self.updown_script))
logging.info(
"interface %s updown script %s startup called"
% (self.bridge_name, self.updown_script)
)
utils.check_cmd([self.updown_script, self.bridge_name, "startup"])
if self.serverintf:
utils.check_cmd([constants.OVS_BIN, "add-port", self.bridge_name, self.serverintf])
utils.check_cmd(
[constants.OVS_BIN, "add-port", self.bridge_name, self.serverintf]
)
utils.check_cmd([constants.IP_BIN, "link", "set", self.serverintf, "up"])
def detectoldbridge(self):
@ -379,7 +456,10 @@ class OvsCtrlNet(OvsNet):
for line in output.split("\n"):
bride_name = line.split(".")
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)
logging.error(
"older session may still be running with conflicting id for bridge: %s",
line,
)
return True
return False
@ -387,14 +467,23 @@ class OvsCtrlNet(OvsNet):
def shutdown(self):
if self.serverintf:
try:
utils.check_cmd([constants.OVS_BIN, "del-port", self.bridge_name, self.serverintf])
utils.check_cmd(
[constants.OVS_BIN, "del-port", self.bridge_name, self.serverintf]
)
except CoreCommandError:
logging.exception("error deleting server interface %s to controlnet bridge %s",
self.serverintf, self.bridge_name)
logging.exception(
"error deleting server interface %s to controlnet bridge %s",
self.serverintf,
self.bridge_name,
)
if self.updown_script:
try:
logging.info("interface %s updown script (%s shutdown) called", self.bridge_name, self.updown_script)
logging.info(
"interface %s updown script (%s shutdown) called",
self.bridge_name,
self.updown_script,
)
utils.check_cmd([self.updown_script, self.bridge_name, "shutdown"])
except CoreCommandError:
logging.exception("error during updown script shutdown")
@ -413,7 +502,9 @@ class OvsPtpNet(OvsNet):
def attach(self, interface):
if len(self._netif) >= 2:
raise ValueError("point-to-point links support at most 2 network interfaces")
raise ValueError(
"point-to-point links support at most 2 network interfaces"
)
OvsNet.attach(self, interface)
def data(self, message_type, lat=None, lon=None, alt=None):
@ -516,7 +607,7 @@ class OvsPtpNet(OvsNet):
jitter=if1.getparam("jitter"),
unidirectional=1,
interface1_id=if2.node.getifindex(if2),
interface2_id=if1.node.getifindex(if1)
interface2_id=if1.node.getifindex(if1),
)
all_links.append(link_data)
@ -544,7 +635,9 @@ class OvsHubNode(OvsNet):
if start:
# TODO: verify that the below flow accomplishes what is desired for a "HUB"
# TODO: replace "brctl setageing 0"
utils.check_cmd([constants.OVS_FLOW_BIN, "add-flow", self.bridge_name, "action=flood"])
utils.check_cmd(
[constants.OVS_FLOW_BIN, "add-flow", self.bridge_name, "action=flood"]
)
class OvsWlanNode(OvsNet):
@ -596,7 +689,9 @@ class OvsWlanNode(OvsNet):
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)
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():
@ -627,9 +722,21 @@ class OvsGreTapBridge(OvsNet):
another system.
"""
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, _id=_id, name=name, policy=policy, start=False)
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, _id=_id, name=name, policy=policy, start=False
)
self.grekey = key
if self.grekey is None:
self.grekey = self.session.id ^ self.id
@ -643,8 +750,14 @@ class OvsGreTapBridge(OvsNet):
if remoteip is None:
self.gretap = None
else:
self.gretap = GreTap(node=self, session=session, remoteip=remoteip,
localip=localip, ttl=ttl, key=self.grekey)
self.gretap = GreTap(
node=self,
session=session,
remoteip=remoteip,
localip=localip,
ttl=ttl,
key=self.grekey,
)
if start:
self.startup()
@ -684,8 +797,13 @@ class OvsGreTapBridge(OvsNet):
if len(addresses) > 1:
localip = addresses[1].split("/")[0]
self.gretap = GreTap(session=self.session, remoteip=remoteip,
localip=localip, ttl=self.ttl, key=self.grekey)
self.gretap = GreTap(
session=self.session,
remoteip=remoteip,
localip=localip,
ttl=self.ttl,
key=self.grekey,
)
self.attach(self.gretap)
def setkey(self, key):
@ -703,5 +821,5 @@ OVS_NODES = {
NodeTypes.TUNNEL: OvsTunnelNode,
NodeTypes.TAP_BRIDGE: OvsGreTapBridge,
NodeTypes.PEER_TO_PEER: OvsPtpNet,
NodeTypes.CONTROL_NET: OvsCtrlNet
NodeTypes.CONTROL_NET: OvsCtrlNet,
}

View file

@ -102,14 +102,25 @@ class PhysicalNode(CoreNodeBase):
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)])
self.check_cmd(
[constants.IP_BIN, "link", "set", "dev", ifname, "address", str(addr)]
)
def addaddr(self, ifindex, addr):
"""
Add an address to an interface.
"""
if self.up:
self.check_cmd([constants.IP_BIN, "addr", "add", str(addr), "dev", self.ifname(ifindex)])
self.check_cmd(
[
constants.IP_BIN,
"addr",
"add",
str(addr),
"dev",
self.ifname(ifindex),
]
)
self._netif[ifindex].addaddr(addr)
@ -123,7 +134,16 @@ class PhysicalNode(CoreNodeBase):
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)])
self.check_cmd(
[
constants.IP_BIN,
"addr",
"del",
str(addr),
"dev",
self.ifname(ifindex),
]
)
def adoptnetif(self, netif, ifindex, hwaddr, addrlist):
"""
@ -138,8 +158,12 @@ class PhysicalNode(CoreNodeBase):
# 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])
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
@ -150,16 +174,35 @@ class PhysicalNode(CoreNodeBase):
self.addaddr(ifindex, addr)
if self.up:
self.check_cmd([constants.IP_BIN, "link", "set", "dev", netif.localname, "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):
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)
linux_bridge.linkconfig(
netif,
bw=bw,
delay=delay,
loss=loss,
duplicate=duplicate,
jitter=jitter,
netif2=netif2,
)
del linux_bridge
def newifindex(self):
@ -186,7 +229,9 @@ class PhysicalNode(CoreNodeBase):
# 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)
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)
@ -203,7 +248,9 @@ class PhysicalNode(CoreNodeBase):
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('/', '.'))
hostpath = os.path.join(
self.nodedir, os.path.normpath(path).strip("/").replace("/", ".")
)
os.mkdir(hostpath)
self.mount(hostpath, path)
@ -249,6 +296,7 @@ class Rj45Node(CoreNodeBase, CoreInterface):
RJ45Node is a physical interface on the host linked to the emulated
network.
"""
apitype = NodeTypes.RJ45.value
type = "rj45"
@ -302,7 +350,9 @@ class Rj45Node(CoreNodeBase, CoreInterface):
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"])
utils.check_cmd(
[constants.TC_BIN, "qdisc", "del", "dev", self.localname, "root"]
)
except CoreCommandError:
logging.exception("error shutting down")
@ -425,7 +475,9 @@ class Rj45Node(CoreNodeBase, CoreInterface):
:raises CoreCommandError: when there is a command exception
"""
if self.up:
utils.check_cmd([constants.IP_BIN, "addr", "add", str(addr), "dev", self.name])
utils.check_cmd(
[constants.IP_BIN, "addr", "add", str(addr), "dev", self.name]
)
CoreInterface.addaddr(self, addr)
@ -438,7 +490,9 @@ class Rj45Node(CoreNodeBase, CoreInterface):
:raises CoreCommandError: when there is a command exception
"""
if self.up:
utils.check_cmd([constants.IP_BIN, "addr", "del", str(addr), "dev", self.name])
utils.check_cmd(
[constants.IP_BIN, "addr", "del", str(addr), "dev", self.name]
)
CoreInterface.deladdr(self, addr)
@ -479,9 +533,22 @@ class Rj45Node(CoreNodeBase, CoreInterface):
"""
for addr in self.old_addrs:
if addr[1] is None:
utils.check_cmd([constants.IP_BIN, "addr", "add", addr[0], "dev", self.localname])
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])
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"])

View file

@ -43,6 +43,7 @@ class Sdt(object):
The connect() method initializes the display, and can be invoked
when a node position or link has changed.
"""
DEFAULT_SDT_URL = "tcp://127.0.0.1:50000/"
# default altitude (in meters) for flyto view
DEFAULT_ALT = 2500
@ -96,7 +97,12 @@ class Sdt(object):
alt = node_data.altitude
if all([lat, lon, alt]):
self.updatenodegeo(node_data.id, node_data.latitude, node_data.longitude, node_data.altitude)
self.updatenodegeo(
node_data.id,
node_data.latitude,
node_data.longitude,
node_data.altitude,
)
if node_data.message_type == 0:
# TODO: z is not currently supported by node messages
@ -110,7 +116,12 @@ class Sdt(object):
:return: nothing
"""
if link_data.link_type == LinkTypes.WIRELESS.value:
self.updatelink(link_data.node1_id, link_data.node2_id, link_data.message_type, wireless=True)
self.updatelink(
link_data.node1_id,
link_data.node2_id,
link_data.message_type,
wireless=True,
)
def is_enabled(self):
"""
@ -182,7 +193,7 @@ class Sdt(object):
:return: initialize command status
:rtype: bool
"""
if not self.cmd("path \"%s/icons/normal\"" % constants.CORE_DATA_DIR):
if not self.cmd('path "%s/icons/normal"' % constants.CORE_DATA_DIR):
return False
# send node type to icon mappings
for node_type, icon in self.DEFAULT_SPRITES:
@ -269,7 +280,9 @@ class Sdt(object):
icon = icon.replace("$CORE_DATA_DIR", constants.CORE_DATA_DIR)
icon = icon.replace("$CORE_CONF_DIR", constants.CORE_CONF_DIR)
self.cmd("sprite %s image %s" % (type, icon))
self.cmd("node %d type %s label on,\"%s\" %s" % (nodenum, node_type, name, pos))
self.cmd(
'node %d type %s label on,"%s" %s' % (nodenum, node_type, name, pos)
)
else:
self.cmd("node %d %s" % (nodenum, pos))
@ -333,16 +346,29 @@ class Sdt(object):
(x, y, z) = node.getposition()
if x is None or y is None:
continue
self.updatenode(node.id, MessageFlags.ADD.value, x, y, z, node.name, node.type, node.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))
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.id:
continue
@ -351,7 +377,7 @@ class Sdt(object):
link_data.node1_id,
link_data.node2_id,
MessageFlags.ADD.value,
wireless_link
wireless_link,
)
for n1num in sorted(self.remotes.keys()):
@ -400,8 +426,7 @@ class Sdt(object):
icon = msg.get_tlv(NodeTlvs.ICON.value)
net = False
if nodetype == NodeTypes.DEFAULT.value or \
nodetype == NodeTypes.PHYSICAL.value:
if nodetype == NodeTypes.DEFAULT.value or nodetype == NodeTypes.PHYSICAL.value:
if model is None:
model = "router"
nodetype = model
@ -416,7 +441,9 @@ class Sdt(object):
except KeyError:
node = None
if node:
self.updatenode(node.id, 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]
@ -427,7 +454,14 @@ class Sdt(object):
if icon is None:
icon = remote.icon
else:
remote = Bunch(_id=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)

View file

@ -9,6 +9,7 @@ class Bird(CoreService):
"""
Bird router support
"""
name = "bird"
executables = ("bird",)
group = "BIRD"
@ -34,11 +35,11 @@ class Bird(CoreService):
Helper to return the first IPv4 address of a node as its router ID.
"""
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control is True:
if hasattr(ifc, "control") and ifc.control is True:
continue
for a in ifc.addrlist:
if a.find(".") >= 0:
return a.split('/')[0]
return a.split("/")[0]
# raise ValueError, "no IPv4 address found for router ID"
return "0.0.0.0"
@ -72,7 +73,10 @@ protocol device {
scan time 10; # Scan interfaces every 10 seconds
}
""" % (cls.name, cls.routerid(node))
""" % (
cls.name,
cls.routerid(node),
)
# Generate protocol specific configurations
for s in node.services:
@ -113,7 +117,7 @@ class BirdService(CoreService):
cfg = ""
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control is True:
if hasattr(ifc, "control") and ifc.control is True:
continue
cfg += ' interface "%s";\n' % ifc.name
@ -160,18 +164,18 @@ class BirdOspf(BirdService):
@classmethod
def generatebirdconfig(cls, node):
cfg = 'protocol ospf {\n'
cfg += ' export filter {\n'
cfg += ' if source = RTS_BGP then {\n'
cfg += ' ospf_metric1 = 100;\n'
cfg += ' accept;\n'
cfg += ' }\n'
cfg += ' accept;\n'
cfg += ' };\n'
cfg += ' area 0.0.0.0 {\n'
cfg = "protocol ospf {\n"
cfg += " export filter {\n"
cfg += " if source = RTS_BGP then {\n"
cfg += " ospf_metric1 = 100;\n"
cfg += " accept;\n"
cfg += " }\n"
cfg += " accept;\n"
cfg += " };\n"
cfg += " area 0.0.0.0 {\n"
cfg += cls.generatebirdifcconfig(node)
cfg += ' };\n'
cfg += '}\n\n'
cfg += " };\n"
cfg += "}\n\n"
return cfg
@ -185,21 +189,21 @@ class BirdRadv(BirdService):
@classmethod
def generatebirdconfig(cls, node):
cfg = '/* This is a sample config that must be customized */\n'
cfg = "/* This is a sample config that must be customized */\n"
cfg += 'protocol radv {\n'
cfg += ' # auto configuration on all interfaces\n'
cfg += "protocol radv {\n"
cfg += " # auto configuration on all interfaces\n"
cfg += cls.generatebirdifcconfig(node)
cfg += ' # Advertise DNS\n'
cfg += ' rdnss {\n'
cfg += '# lifetime mult 10;\n'
cfg += '# lifetime mult 10;\n'
cfg += '# ns 2001:0DB8:1234::11;\n'
cfg += '# ns 2001:0DB8:1234::11;\n'
cfg += '# ns 2001:0DB8:1234::12;\n'
cfg += '# ns 2001:0DB8:1234::12;\n'
cfg += ' };\n'
cfg += '}\n\n'
cfg += " # Advertise DNS\n"
cfg += " rdnss {\n"
cfg += "# lifetime mult 10;\n"
cfg += "# lifetime mult 10;\n"
cfg += "# ns 2001:0DB8:1234::11;\n"
cfg += "# ns 2001:0DB8:1234::11;\n"
cfg += "# ns 2001:0DB8:1234::12;\n"
cfg += "# ns 2001:0DB8:1234::12;\n"
cfg += " };\n"
cfg += "}\n\n"
return cfg
@ -213,15 +217,15 @@ class BirdRip(BirdService):
@classmethod
def generatebirdconfig(cls, node):
cfg = 'protocol rip {\n'
cfg += ' period 10;\n'
cfg += ' garbage time 60;\n'
cfg = "protocol rip {\n"
cfg += " period 10;\n"
cfg += " garbage time 60;\n"
cfg += cls.generatebirdifcconfig(node)
cfg += ' honor neighbor;\n'
cfg += ' authentication none;\n'
cfg += ' import all;\n'
cfg += ' export all;\n'
cfg += '}\n\n'
cfg += " honor neighbor;\n"
cfg += " authentication none;\n"
cfg += " import all;\n"
cfg += " export all;\n"
cfg += "}\n\n"
return cfg
@ -236,10 +240,10 @@ class BirdStatic(BirdService):
@classmethod
def generatebirdconfig(cls, node):
cfg = '/* This is a sample config that must be customized */\n'
cfg += 'protocol static {\n'
cfg += '# route 0.0.0.0/0 via 198.51.100.130; # Default route. Do NOT advertise on BGP !\n'
cfg += '# route 203.0.113.0/24 reject; # Sink route\n'
cfg = "/* This is a sample config that must be customized */\n"
cfg += "protocol static {\n"
cfg += "# route 0.0.0.0/0 via 198.51.100.130; # Default route. Do NOT advertise on BGP !\n"
cfg += "# route 203.0.113.0/24 reject; # Sink route\n"
cfg += '# route 10.2.0.0/24 via "arc0"; # Secondary network\n'
cfg += '}\n\n'
cfg += "}\n\n"
return cfg

View file

@ -61,7 +61,9 @@ class ServiceDependencies(object):
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)
logging.debug(
"skipping service that will already be booted: %s", service.name
)
continue
path = self._start(service)
@ -69,7 +71,10 @@ class ServiceDependencies(object):
paths.append(path)
if self.booted != set(self.node_services):
raise ValueError("failure to boot all services: %s != %s" % (self.booted, self.node_services.keys()))
raise ValueError(
"failure to boot all services: %s != %s"
% (self.booted, self.node_services.keys())
)
return paths
@ -91,10 +96,16 @@ class ServiceDependencies(object):
# dive down
for service_name in current_service.dependencies:
if service_name not in self.node_services:
raise ValueError("required dependency was not included in node services: %s" % service_name)
raise ValueError(
"required dependency was not included in node services: %s"
% service_name
)
if service_name in self.visiting:
raise ValueError("cyclic dependency at service(%s): %s" % (current_service.name, service_name))
raise ValueError(
"cyclic dependency at service(%s): %s"
% (current_service.name, service_name)
)
if service_name not in self.visited:
service = self.node_services[service_name]
@ -116,7 +127,16 @@ class ServiceDependencies(object):
class ServiceShim(object):
keys = ["dirs", "files", "startidx", "cmdup", "cmddown", "cmdval", "meta", "starttime"]
keys = [
"dirs",
"files",
"startidx",
"cmdup",
"cmddown",
"cmdval",
"meta",
"starttime",
]
@classmethod
def tovaluelist(cls, node, service):
@ -131,8 +151,16 @@ class ServiceShim(object):
"""
start_time = 0
start_index = 0
valmap = [service.dirs, service.configs, start_index, service.startup,
service.shutdown, service.validate, service.meta, start_time]
valmap = [
service.dirs,
service.configs,
start_index,
service.startup,
service.shutdown,
service.validate,
service.meta,
start_time,
]
if not service.custom:
valmap[1] = service.get_configs(node)
valmap[3] = service.get_startup(node)
@ -200,16 +228,17 @@ class ServiceShim(object):
:return: services
:rtype: list
"""
servicesstring = opaque.split(':')
servicesstring = opaque.split(":")
if servicesstring[0] != "service":
return []
return servicesstring[1].split(',')
return servicesstring[1].split(",")
class ServiceManager(object):
"""
Manages services available for CORE nodes to use.
"""
services = {}
@classmethod
@ -230,8 +259,12 @@ class ServiceManager(object):
# validate dependent executables are present
for executable in service.executables:
if not which(executable):
logging.debug("service(%s) missing executable: %s", service.name, executable)
raise ValueError("service(%s) missing executable: %s" % (service.name, executable))
logging.debug(
"service(%s) missing executable: %s", service.name, executable
)
raise ValueError(
"service(%s) missing executable: %s" % (service.name, executable)
)
# make service available
cls.services[name] = service
@ -279,6 +312,7 @@ class CoreServices(object):
the default services configured for each node type, and any
custom service configuration. A CoreService is not a Configurable.
"""
name = "services"
config_type = RegisterTlvs.UTILITY.value
@ -367,14 +401,18 @@ class CoreServices(object):
:return: nothing
"""
if not services:
logging.info("using default services for node(%s) type(%s)", node.name, node_type)
logging.info(
"using default services for node(%s) type(%s)", node.name, node_type
)
services = self.default_services.get(node_type, [])
logging.info("setting services for node(%s): %s", node.name, services)
for service_name in services:
service = self.get_service(node.id, service_name, default_service=True)
if not service:
logging.warning("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)
@ -444,7 +482,9 @@ class CoreServices(object):
:param list[CoreService] boot_path: service to start in dependent order
:return: nothing
"""
logging.info("booting node services: %s", " -> ".join([x.name for x in boot_path]))
logging.info(
"booting node services: %s", " -> ".join([x.name for x in boot_path])
)
for service in boot_path:
try:
self.boot_service(node, service)
@ -461,16 +501,24 @@ class CoreServices(object):
:param CoreService service: service to start
:return: nothing
"""
logging.info("starting node(%s) service(%s) validation(%s)", node.name, service.name,
service.validation_mode.name)
logging.info(
"starting node(%s) service(%s) validation(%s)",
node.name,
service.name,
service.validation_mode.name,
)
# create service directories
for directory in service.dirs:
try:
node.privatedir(directory)
except (CoreCommandError, ValueError) as e:
logging.warning("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)
@ -479,7 +527,9 @@ class CoreServices(object):
wait = service.validation_mode == ServiceMode.BLOCKING
status = self.startup_service(node, service, wait)
if status:
raise ServiceBootError("node(%s) service(%s) error during startup" % (node.name, service.name))
raise ServiceBootError(
"node(%s) service(%s) error during startup" % (node.name, service.name)
)
# blocking mode is finished
if wait:
@ -502,7 +552,9 @@ class CoreServices(object):
time.sleep(service.validation_period)
if status:
raise ServiceBootError("node(%s) service(%s) failed validation" % (node.name, service.name))
raise ServiceBootError(
"node(%s) service(%s) failed validation" % (node.name, service.name)
)
def copy_service_file(self, node, filename, cfg):
"""
@ -516,9 +568,9 @@ class CoreServices(object):
:return: True if successful, False otherwise
:rtype: bool
"""
if cfg[:7] == 'file://':
if cfg[:7] == "file://":
src = cfg[7:]
src = src.split('\n')[0]
src = src.split("\n")[0]
src = utils.expand_corepath(src, node.session, node)
# TODO: glob here
node.nodefilecopy(filename, src, mode=0o644)
@ -545,7 +597,9 @@ class CoreServices(object):
try:
node.check_cmd(cmd)
except CoreCommandError as e:
logging.error("node(%s) service(%s) validate failed", node.name, service.name)
logging.error(
"node(%s) service(%s) validate failed", node.name, service.name
)
logging.error("cmd(%s): %s", e.cmd, e.output)
status = -1
break
@ -602,7 +656,9 @@ class CoreServices(object):
config_files = service.get_configs(node)
if filename not in config_files:
raise ValueError("unknown service(%s) config file: %s", service_name, filename)
raise ValueError(
"unknown service(%s) config file: %s", service_name, filename
)
# get the file data
data = service.config_data.get(filename)
@ -617,7 +673,7 @@ class CoreServices(object):
node=node.id,
name=filename,
type=filetypestr,
data=data
data=data,
)
def set_service_file(self, node_id, service_name, file_name, data):
@ -644,7 +700,9 @@ class CoreServices(object):
# validate file being set is valid
config_files = service.configs
if file_name not in config_files:
logging.warning("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
@ -685,7 +743,9 @@ class CoreServices(object):
:param CoreService service: service to reconfigure
:return: nothing
"""
logging.info("node(%s) service(%s) creating config files", node.name, service.name)
logging.info(
"node(%s) service(%s) creating config files", node.name, service.name
)
# get values depending on if custom or not
config_files = service.configs
if not service.custom:
@ -738,6 +798,7 @@ class CoreService(object):
"""
Parent class used for defining services.
"""
# service name should not include spaces
name = None

View file

@ -23,15 +23,23 @@ class EmaneTransportService(CoreService):
for interface in node.netifs(sort=True):
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.id, 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
command = (
"emanetransportd -r -l 0 -d ../transportdaemon%s.xml"
% nem_id
)
transport_commands.append(command)
transport_commands = "\n".join(transport_commands)
return """
emanegentransportxml -o ../ ../platform%s.xml
%s
""" % (node.id, transport_commands)
""" % (
node.id,
transport_commands,
)
else:
raise ValueError

View file

@ -12,11 +12,7 @@ from core.services.coreservices import CoreService
class FRRZebra(CoreService):
name = "FRRzebra"
group = "FRR"
dirs = (
"/usr/local/etc/frr",
"/var/run/frr",
"/var/log/frr",
)
dirs = ("/usr/local/etc/frr", "/var/run/frr", "/var/log/frr")
configs = (
"/usr/local/etc/frr/frr.conf",
"frrboot.sh",
@ -41,7 +37,9 @@ class FRRZebra(CoreService):
elif filename == cls.configs[3]:
return cls.generateFrrDaemons(node)
else:
raise ValueError("file name (%s) is not a known configuration: %s", filename, cls.configs)
raise ValueError(
"file name (%s) is not a known configuration: %s", filename, cls.configs
)
@classmethod
def generateVtyshConf(cls, node):
@ -62,7 +60,7 @@ class FRRZebra(CoreService):
for ifc in node.netifs():
cfg += "interface %s\n" % ifc.name
# include control interfaces in addressing but not routing daemons
if hasattr(ifc, 'control') and ifc.control is True:
if hasattr(ifc, "control") and ifc.control is True:
cfg += " "
cfg += "\n ".join(map(cls.addrstr, ifc.addrlist))
cfg += "\n"
@ -84,13 +82,17 @@ class FRRZebra(CoreService):
cfgv4 += ifccfg
if want_ipv4:
ipv4list = filter(lambda x: ipaddress.is_ipv4_address(x.split('/')[0]), ifc.addrlist)
ipv4list = filter(
lambda x: ipaddress.is_ipv4_address(x.split("/")[0]), ifc.addrlist
)
cfg += " "
cfg += "\n ".join(map(cls.addrstr, ipv4list))
cfg += "\n"
cfg += cfgv4
if want_ipv6:
ipv6list = filter(lambda x: ipaddress.is_ipv6_address(x.split('/')[0]), ifc.addrlist)
ipv6list = filter(
lambda x: ipaddress.is_ipv6_address(x.split("/")[0]), ifc.addrlist
)
cfg += " "
cfg += "\n ".join(map(cls.addrstr, ipv6list))
cfg += "\n"
@ -120,10 +122,12 @@ class FRRZebra(CoreService):
"""
Generate a shell script used to boot the FRR daemons.
"""
frr_bin_search = node.session.options.get_config("frr_bin_search",
default='"/usr/local/bin /usr/bin /usr/lib/frr"')
frr_sbin_search = node.session.options.get_config('frr_sbin_search',
default='"/usr/local/sbin /usr/sbin /usr/lib/frr"')
frr_bin_search = node.session.options.get_config(
"frr_bin_search", default='"/usr/local/bin /usr/bin /usr/lib/frr"'
)
frr_sbin_search = node.session.options.get_config(
"frr_sbin_search", default='"/usr/local/sbin /usr/sbin /usr/lib/frr"'
)
return """\
#!/bin/sh
# auto-generated by zebra service (frr.py)
@ -221,7 +225,12 @@ if [ "$1" != "zebra" ]; then
fi
confcheck
bootfrr
""" % (cls.configs[0], frr_sbin_search, frr_bin_search, constants.FRR_STATE_DIR)
""" % (
cls.configs[0],
frr_sbin_search,
frr_bin_search,
constants.FRR_STATE_DIR,
)
@classmethod
def generateFrrDaemons(cls, node):
@ -291,12 +300,12 @@ fabricd_options="-A 127.0.0.1"
"""
class FrrService(CoreService):
"""
Parent class for FRR services. Defines properties and methods
common to FRR's routing daemons.
"""
name = None
group = "FRR"
dependencies = ("FRRzebra",)
@ -315,11 +324,11 @@ class FrrService(CoreService):
Helper to return the first IPv4 address of a node as its router ID.
"""
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control is True:
if hasattr(ifc, "control") and ifc.control is True:
continue
for a in ifc.addrlist:
if a.find(".") >= 0:
return a.split('/')[0]
return a.split("/")[0]
# raise ValueError, "no IPv4 address found for router ID"
return "0.0.0.0"
@ -356,6 +365,7 @@ class FRROspfv2(FrrService):
not build its own configuration file but has hooks for adding to the
unified frr.conf file.
"""
name = "FRROSPFv2"
startup = ()
shutdown = ("killall ospfd",)
@ -397,7 +407,7 @@ class FRROspfv2(FrrService):
cfg += " router-id %s\n" % rtrid
# network 10.0.0.0/24 area 0
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control is True:
if hasattr(ifc, "control") and ifc.control is True:
continue
for a in ifc.addrlist:
if a.find(".") < 0:
@ -431,6 +441,7 @@ class FRROspfv3(FrrService):
not build its own configuration file but has hooks for adding to the
unified frr.conf file.
"""
name = "FRROSPFv3"
startup = ()
shutdown = ("killall ospf6d",)
@ -481,7 +492,7 @@ class FRROspfv3(FrrService):
rtrid = cls.routerid(node)
cfg += " router-id %s\n" % rtrid
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control is True:
if hasattr(ifc, "control") and ifc.control is True:
continue
cfg += " interface %s area 0.0.0.0\n" % ifc.name
cfg += "!\n"
@ -511,6 +522,7 @@ class FRRBgp(FrrService):
Peers must be manually configured, with a full mesh for those
having the same AS number.
"""
name = "FRRBGP"
startup = ()
shutdown = ("killall bgpd",)
@ -536,6 +548,7 @@ class FRRRip(FrrService):
"""
The RIP service provides IPv4 routing for wired networks.
"""
name = "FRRRIP"
startup = ()
shutdown = ("killall ripd",)
@ -559,6 +572,7 @@ class FRRRipng(FrrService):
"""
The RIP NG service provides IPv6 routing for wired networks.
"""
name = "FRRRIPNG"
startup = ()
shutdown = ("killall ripngd",)
@ -583,6 +597,7 @@ class FRRBabel(FrrService):
The Babel service provides a loop-avoiding distance-vector routing
protocol for IPv6 and IPv4 with fast convergence properties.
"""
name = "FRRBabel"
startup = ()
shutdown = ("killall babeld",)
@ -611,28 +626,29 @@ class FRRpimd(FrrService):
"""
PIM multicast routing based on XORP.
"""
name = 'FRRpimd'
name = "FRRpimd"
startup = ()
shutdown = ('killall pimd',)
validate = ('pidof pimd',)
shutdown = ("killall pimd",)
validate = ("pidof pimd",)
ipv4_routing = True
@classmethod
def generatefrrconfig(cls, node):
ifname = 'eth0'
ifname = "eth0"
for ifc in node.netifs():
if ifc.name != 'lo':
if ifc.name != "lo":
ifname = ifc.name
break
cfg = 'router mfea\n!\n'
cfg += 'router igmp\n!\n'
cfg += 'router pim\n'
cfg += ' !ip pim rp-address 10.0.0.1\n'
cfg += ' ip pim bsr-candidate %s\n' % ifname
cfg += ' ip pim rp-candidate %s\n' % ifname
cfg += ' !ip pim spt-threshold interval 10 bytes 80000\n'
cfg = "router mfea\n!\n"
cfg += "router igmp\n!\n"
cfg += "router pim\n"
cfg += " !ip pim rp-address 10.0.0.1\n"
cfg += " ip pim bsr-candidate %s\n" % ifname
cfg += " ip pim rp-candidate %s\n" % ifname
cfg += " !ip pim spt-threshold interval 10 bytes 80000\n"
return cfg
@classmethod
def generatefrrifcconfig(cls, node, ifc):
return ' ip mfea\n ip igmp\n ip pim\n'
return " ip mfea\n ip igmp\n ip pim\n"

View file

@ -12,7 +12,8 @@ class NrlService(CoreService):
"""
Parent class for NRL services. Defines properties and methods
common to NRL's routing daemons.
"""""
""" ""
name = None
group = "ProtoSvc"
dirs = ()
@ -32,11 +33,11 @@ class NrlService(CoreService):
interface's prefix length, so e.g. '/32' can turn into '/24'.
"""
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control is True:
if hasattr(ifc, "control") and ifc.control is True:
continue
for a in ifc.addrlist:
if a.find(".") >= 0:
addr = a.split('/')[0]
addr = a.split("/")[0]
pre = Ipv4Prefix("%s/%s" % (addr, prefixlen))
return str(pre)
# raise ValueError, "no IPv4 address found"
@ -63,13 +64,14 @@ class MgenSinkService(NrlService):
def get_startup(cls, node):
cmd = cls.startup[0]
cmd += " output /tmp/mgen_%s.log" % node.name
return cmd,
return (cmd,)
class NrlNhdp(NrlService):
"""
NeighborHood Discovery Protocol for MANET networks.
"""
name = "NHDP"
executables = ("nrlnhdp",)
startup = ("nrlnhdp",)
@ -90,19 +92,20 @@ class NrlNhdp(NrlService):
cmd += " -flooding ecds"
cmd += " -smfClient %s_smf" % node.name
netifs = filter(lambda x: not getattr(x, 'control', False), node.netifs())
netifs = filter(lambda x: not getattr(x, "control", False), node.netifs())
if len(netifs) > 0:
interfacenames = map(lambda x: x.name, netifs)
cmd += " -i "
cmd += " -i ".join(interfacenames)
return cmd,
return (cmd,)
class NrlSmf(NrlService):
"""
Simplified Multicast Forwarding for MANET networks.
"""
name = "SMF"
executables = ("nrlsmf",)
startup = ("sh startsmf.sh",)
@ -111,7 +114,7 @@ class NrlSmf(NrlService):
configs = ("startsmf.sh",)
@classmethod
def generate_config(cls, node, filename, ):
def generate_config(cls, node, filename):
"""
Generate a startup script for SMF. Because nrlsmf does not
daemonize, it can cause problems in some situations when launched
@ -123,7 +126,7 @@ class NrlSmf(NrlService):
cmd = "nrlsmf instance %s_smf" % node.name
servicenames = map(lambda x: x.name, node.services)
netifs = filter(lambda x: not getattr(x, 'control', False), node.netifs())
netifs = filter(lambda x: not getattr(x, "control", False), node.netifs())
if len(netifs) == 0:
return ""
@ -155,6 +158,7 @@ class NrlOlsr(NrlService):
"""
Optimized Link State Routing protocol for MANET networks.
"""
name = "OLSR"
executables = ("nrlolsrd",)
startup = ("nrlolsrd",)
@ -182,13 +186,14 @@ class NrlOlsr(NrlService):
if "zebra" in servicenames:
cmd += " -z"
return cmd,
return (cmd,)
class NrlOlsrv2(NrlService):
"""
Optimized Link State Routing protocol version 2 for MANET networks.
"""
name = "OLSRv2"
executables = ("nrlolsrv2",)
startup = ("nrlolsrv2",)
@ -211,19 +216,20 @@ class NrlOlsrv2(NrlService):
cmd += " -p olsr"
netifs = filter(lambda x: not getattr(x, 'control', False), node.netifs())
netifs = filter(lambda x: not getattr(x, "control", False), node.netifs())
if len(netifs) > 0:
interfacenames = map(lambda x: x.name, netifs)
cmd += " -i "
cmd += " -i ".join(interfacenames)
return cmd,
return (cmd,)
class OlsrOrg(NrlService):
"""
Optimized Link State Routing protocol from olsr.org for MANET networks.
"""
name = "OLSRORG"
executables = ("olsrd",)
configs = ("/etc/olsrd/olsrd.conf",)
@ -238,13 +244,13 @@ class OlsrOrg(NrlService):
Generate the appropriate command-line based on node interfaces.
"""
cmd = cls.startup[0]
netifs = filter(lambda x: not getattr(x, 'control', False), node.netifs())
netifs = filter(lambda x: not getattr(x, "control", False), node.netifs())
if len(netifs) > 0:
interfacenames = map(lambda x: x.name, netifs)
cmd += " -i "
cmd += " -i ".join(interfacenames)
return cmd,
return (cmd,)
@classmethod
def generate_config(cls, node, filename):
@ -582,7 +588,7 @@ class MgenActor(NrlService):
dirs = ()
# generated files (without a full path this file goes in the node's dir,
# e.g. /tmp/pycore.12345/n1.conf/)
configs = ('start_mgen_actor.sh',)
configs = ("start_mgen_actor.sh",)
# list of startup commands, also may be generated during startup
startup = ("sh start_mgen_actor.sh",)
# list of validation commands
@ -614,6 +620,7 @@ class Arouted(NrlService):
"""
Adaptive Routing
"""
name = "arouted"
executables = ("arouted",)
configs = ("startarouted.sh",)
@ -626,7 +633,8 @@ class Arouted(NrlService):
"""
Return the Quagga.conf or quaggaboot.sh file contents.
"""
cfg = """
cfg = (
"""
#!/bin/sh
for f in "/tmp/%s_smf"; do
count=1
@ -640,7 +648,9 @@ for f in "/tmp/%s_smf"; do
done
done
""" % node.name
"""
% node.name
)
cfg += "ip route add %s dev lo\n" % cls.firstipv4prefix(node, 24)
cfg += "arouted instance %s_smf tap %s_tap" % (node.name, node.name)
# seconds to consider a new route valid

View file

@ -15,7 +15,7 @@ class Zebra(CoreService):
configs = (
"/usr/local/etc/quagga/Quagga.conf",
"quaggaboot.sh",
"/usr/local/etc/quagga/vtysh.conf"
"/usr/local/etc/quagga/vtysh.conf",
)
startup = ("sh quaggaboot.sh zebra",)
shutdown = ("killall zebra",)
@ -33,7 +33,9 @@ class Zebra(CoreService):
elif filename == cls.configs[2]:
return cls.generateVtyshConf(node)
else:
raise ValueError("file name (%s) is not a known configuration: %s", filename, cls.configs)
raise ValueError(
"file name (%s) is not a known configuration: %s", filename, cls.configs
)
@classmethod
def generateVtyshConf(cls, node):
@ -54,7 +56,7 @@ class Zebra(CoreService):
for ifc in node.netifs():
cfg += "interface %s\n" % ifc.name
# include control interfaces in addressing but not routing daemons
if hasattr(ifc, 'control') and ifc.control is True:
if hasattr(ifc, "control") and ifc.control is True:
cfg += " "
cfg += "\n ".join(map(cls.addrstr, ifc.addrlist))
cfg += "\n"
@ -76,13 +78,17 @@ class Zebra(CoreService):
cfgv4 += ifccfg
if want_ipv4:
ipv4list = filter(lambda x: ipaddress.is_ipv4_address(x.split('/')[0]), ifc.addrlist)
ipv4list = filter(
lambda x: ipaddress.is_ipv4_address(x.split("/")[0]), ifc.addrlist
)
cfg += " "
cfg += "\n ".join(map(cls.addrstr, ipv4list))
cfg += "\n"
cfg += cfgv4
if want_ipv6:
ipv6list = filter(lambda x: ipaddress.is_ipv6_address(x.split('/')[0]), ifc.addrlist)
ipv6list = filter(
lambda x: ipaddress.is_ipv6_address(x.split("/")[0]), ifc.addrlist
)
cfg += " "
cfg += "\n ".join(map(cls.addrstr, ipv6list))
cfg += "\n"
@ -112,10 +118,12 @@ class Zebra(CoreService):
"""
Generate a shell script used to boot the Quagga daemons.
"""
quagga_bin_search = node.session.options.get_config("quagga_bin_search",
default='"/usr/local/bin /usr/bin /usr/lib/quagga"')
quagga_sbin_search = node.session.options.get_config('quagga_sbin_search',
default='"/usr/local/sbin /usr/sbin /usr/lib/quagga"')
quagga_bin_search = node.session.options.get_config(
"quagga_bin_search", default='"/usr/local/bin /usr/bin /usr/lib/quagga"'
)
quagga_sbin_search = node.session.options.get_config(
"quagga_sbin_search", default='"/usr/local/sbin /usr/sbin /usr/lib/quagga"'
)
return """\
#!/bin/sh
# auto-generated by zebra service (quagga.py)
@ -209,7 +217,12 @@ if [ "$1" != "zebra" ]; then
fi
confcheck
bootquagga
""" % (cls.configs[0], quagga_sbin_search, quagga_bin_search, constants.QUAGGA_STATE_DIR)
""" % (
cls.configs[0],
quagga_sbin_search,
quagga_bin_search,
constants.QUAGGA_STATE_DIR,
)
class QuaggaService(CoreService):
@ -217,6 +230,7 @@ class QuaggaService(CoreService):
Parent class for Quagga services. Defines properties and methods
common to Quagga's routing daemons.
"""
name = None
group = "Quagga"
dependencies = ("zebra",)
@ -235,11 +249,11 @@ class QuaggaService(CoreService):
Helper to return the first IPv4 address of a node as its router ID.
"""
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control is True:
if hasattr(ifc, "control") and ifc.control is True:
continue
for a in ifc.addrlist:
if a.find(".") >= 0:
return a.split('/')[0]
return a.split("/")[0]
# raise ValueError, "no IPv4 address found for router ID"
return "0.0.0.0"
@ -276,6 +290,7 @@ class Ospfv2(QuaggaService):
not build its own configuration file but has hooks for adding to the
unified Quagga.conf file.
"""
name = "OSPFv2"
startup = ()
shutdown = ("killall ospfd",)
@ -317,7 +332,7 @@ class Ospfv2(QuaggaService):
cfg += " router-id %s\n" % rtrid
# network 10.0.0.0/24 area 0
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control is True:
if hasattr(ifc, "control") and ifc.control is True:
continue
for a in ifc.addrlist:
if a.find(".") < 0:
@ -351,6 +366,7 @@ class Ospfv3(QuaggaService):
not build its own configuration file but has hooks for adding to the
unified Quagga.conf file.
"""
name = "OSPFv3"
startup = ()
shutdown = ("killall ospf6d",)
@ -401,7 +417,7 @@ class Ospfv3(QuaggaService):
rtrid = cls.routerid(node)
cfg += " router-id %s\n" % rtrid
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control is True:
if hasattr(ifc, "control") and ifc.control is True:
continue
cfg += " interface %s area 0.0.0.0\n" % ifc.name
cfg += "!\n"
@ -432,6 +448,7 @@ class Ospfv3mdr(Ospfv3):
configuration file but has hooks for adding to the
unified Quagga.conf file.
"""
name = "OSPFv3MDR"
ipv4_routing = True
@ -440,8 +457,12 @@ class Ospfv3mdr(Ospfv3):
cfg = cls.mtucheck(ifc)
# Uncomment the following line to use Address Family Translation for IPv4
cfg += " ipv6 ospf6 instance-id 65\n"
if ifc.net is not None and nodeutils.is_node(ifc.net, (NodeTypes.WIRELESS_LAN, NodeTypes.EMANE)):
return cfg + """\
if ifc.net is not None and nodeutils.is_node(
ifc.net, (NodeTypes.WIRELESS_LAN, NodeTypes.EMANE)
):
return (
cfg
+ """\
ipv6 ospf6 hello-interval 2
ipv6 ospf6 dead-interval 6
ipv6 ospf6 retransmit-interval 5
@ -450,6 +471,7 @@ class Ospfv3mdr(Ospfv3):
ipv6 ospf6 adjacencyconnectivity uniconnected
ipv6 ospf6 lsafullness mincostlsa
"""
)
else:
return cfg
@ -460,6 +482,7 @@ class Bgp(QuaggaService):
Peers must be manually configured, with a full mesh for those
having the same AS number.
"""
name = "BGP"
startup = ()
shutdown = ("killall bgpd",)
@ -485,6 +508,7 @@ class Rip(QuaggaService):
"""
The RIP service provides IPv4 routing for wired networks.
"""
name = "RIP"
startup = ()
shutdown = ("killall ripd",)
@ -508,6 +532,7 @@ class Ripng(QuaggaService):
"""
The RIP NG service provides IPv6 routing for wired networks.
"""
name = "RIPNG"
startup = ()
shutdown = ("killall ripngd",)
@ -532,6 +557,7 @@ class Babel(QuaggaService):
The Babel service provides a loop-avoiding distance-vector routing
protocol for IPv6 and IPv4 with fast convergence properties.
"""
name = "Babel"
startup = ()
shutdown = ("killall babeld",)
@ -560,28 +586,29 @@ class Xpimd(QuaggaService):
"""
PIM multicast routing based on XORP.
"""
name = 'Xpimd'
name = "Xpimd"
startup = ()
shutdown = ('killall xpimd',)
validate = ('pidof xpimd',)
shutdown = ("killall xpimd",)
validate = ("pidof xpimd",)
ipv4_routing = True
@classmethod
def generatequaggaconfig(cls, node):
ifname = 'eth0'
ifname = "eth0"
for ifc in node.netifs():
if ifc.name != 'lo':
if ifc.name != "lo":
ifname = ifc.name
break
cfg = 'router mfea\n!\n'
cfg += 'router igmp\n!\n'
cfg += 'router pim\n'
cfg += ' !ip pim rp-address 10.0.0.1\n'
cfg += ' ip pim bsr-candidate %s\n' % ifname
cfg += ' ip pim rp-candidate %s\n' % ifname
cfg += ' !ip pim spt-threshold interval 10 bytes 80000\n'
cfg = "router mfea\n!\n"
cfg += "router igmp\n!\n"
cfg += "router pim\n"
cfg += " !ip pim rp-address 10.0.0.1\n"
cfg += " ip pim bsr-candidate %s\n" % ifname
cfg += " ip pim rp-candidate %s\n" % ifname
cfg += " !ip pim spt-threshold interval 10 bytes 80000\n"
return cfg
@classmethod
def generatequaggaifcconfig(cls, node, ifc):
return ' ip mfea\n ip igmp\n ip pim\n'
return " ip mfea\n ip igmp\n ip pim\n"

View file

@ -11,6 +11,7 @@ class SdnService(CoreService):
"""
Parent class for SDN services.
"""
group = "SDN"
@classmethod
@ -78,8 +79,14 @@ class OvsService(SdnService):
for ifc in node.netifs():
if hasattr(ifc, "control") and ifc.control is True:
continue
cfg += "ovs-ofctl add-flow ovsbr0 priority=1000,in_port=%d,action=output:%d\n" % (portnum, portnum + 1)
cfg += "ovs-ofctl add-flow ovsbr0 priority=1000,in_port=%d,action=output:%d\n" % (portnum + 1, portnum)
cfg += (
"ovs-ofctl add-flow ovsbr0 priority=1000,in_port=%d,action=output:%d\n"
% (portnum, portnum + 1)
)
cfg += (
"ovs-ofctl add-flow ovsbr0 priority=1000,in_port=%d,action=output:%d\n"
% (portnum + 1, portnum)
)
portnum += 2
return cfg
@ -102,5 +109,7 @@ class RyuService(SdnService):
"""
cfg = "#!/bin/sh\n"
cfg += "# auto-generated by ryuService (ryuService.py)\n"
cfg += "ryu-manager --observe-links ryu.app.ofctl_rest ryu.app.rest_topology &\n"
cfg += (
"ryu-manager --observe-links ryu.app.ofctl_rest ryu.app.rest_topology &\n"
)
return cfg

View file

@ -30,7 +30,9 @@ class VPNClient(CoreService):
try:
cfg += open(fname, "rb").read()
except IOError:
logging.exception("Error opening VPN client configuration template (%s)", fname)
logging.exception(
"Error opening VPN client configuration template (%s)", fname
)
return cfg
@ -57,7 +59,9 @@ class VPNServer(CoreService):
try:
cfg += open(fname, "rb").read()
except IOError:
logging.exception("Error opening VPN server configuration template (%s)", fname)
logging.exception(
"Error opening VPN server configuration template (%s)", fname
)
return cfg
@ -108,7 +112,9 @@ class Firewall(CoreService):
try:
cfg += open(fname, "rb").read()
except IOError:
logging.exception("Error opening Firewall configuration template (%s)", fname)
logging.exception(
"Error opening Firewall configuration template (%s)", fname
)
return cfg
@ -117,10 +123,11 @@ class Nat(CoreService):
"""
IPv4 source NAT service.
"""
name = "NAT"
executables = ("iptables",)
group = "Security"
configs = ("nat.sh", )
configs = ("nat.sh",)
startup = ("sh nat.sh",)
custom_needed = False
@ -130,7 +137,7 @@ class Nat(CoreService):
Generate a NAT line for one interface.
"""
cfg = line_prefix + "iptables -t nat -A POSTROUTING -o "
cfg +=ifc.name + " -j MASQUERADE\n"
cfg += ifc.name + " -j MASQUERADE\n"
cfg += line_prefix + "iptables -A FORWARD -i " + ifc.name
cfg += " -m state --state RELATED,ESTABLISHED -j ACCEPT\n"
@ -149,7 +156,7 @@ class Nat(CoreService):
cfg += "# NAT out the first interface by default\n"
have_nat = False
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control == True:
if hasattr(ifc, "control") and ifc.control == True:
continue
if have_nat:
cfg += cls.generateifcnatrule(ifc, line_prefix="#")

View file

@ -12,7 +12,11 @@ class Ucarp(CoreService):
group = "Utility"
dirs = (UCARP_ETC,)
configs = (
UCARP_ETC + "/default.sh", UCARP_ETC + "/default-up.sh", UCARP_ETC + "/default-down.sh", "ucarpboot.sh",)
UCARP_ETC + "/default.sh",
UCARP_ETC + "/default-up.sh",
UCARP_ETC + "/default-down.sh",
"ucarpboot.sh",
)
startup = ("sh ucarpboot.sh",)
shutdown = ("killall ucarp",)
validate = ("pidof ucarp",)
@ -39,7 +43,7 @@ class Ucarp(CoreService):
Returns configuration file text.
"""
try:
ucarp_bin = node.session.cfg['ucarp_bin']
ucarp_bin = node.session.cfg["ucarp_bin"]
except KeyError:
ucarp_bin = "/usr/sbin/ucarp"
@ -100,14 +104,18 @@ STOP_SCRIPT=${UCARP_CFGDIR}/default-down.sh
UCARP_OPTS="$OPTIONS -b $UCARP_BASE -k $SKEW -i $INTERFACE -v $INSTANCE_ID -p $PASSWORD -u $START_SCRIPT -d $STOP_SCRIPT -a $VIRTUAL_ADDRESS -s $SOURCE_ADDRESS -f $FACILITY $XPARAM"
${UCARP_EXEC} -B ${UCARP_OPTS}
""" % (ucarp_bin, UCARP_ETC)
""" % (
ucarp_bin,
UCARP_ETC,
)
@classmethod
def generateUcarpBoot(cls, node):
"""
Generate a shell script used to boot the Ucarp daemons.
"""
return """\
return (
"""\
#!/bin/sh
# Location of the UCARP config directory
UCARP_CFGDIR=%s
@ -117,7 +125,9 @@ chmod a+x ${UCARP_CFGDIR}/*.sh
# Start the default ucarp daemon configuration
${UCARP_CFGDIR}/default.sh
""" % UCARP_ETC
"""
% UCARP_ETC
)
@classmethod
def generateVipUp(cls, node):

View file

@ -13,6 +13,7 @@ class UtilService(CoreService):
"""
Parent class for utility services.
"""
name = None
group = "Utility"
dirs = ()
@ -50,12 +51,19 @@ class IPForwardService(UtilService):
%(sysctl)s -w net.ipv4.conf.default.send_redirects=0
%(sysctl)s -w net.ipv4.conf.all.rp_filter=0
%(sysctl)s -w net.ipv4.conf.default.rp_filter=0
""" % {'sysctl': constants.SYSCTL_BIN}
""" % {
"sysctl": constants.SYSCTL_BIN
}
for ifc in node.netifs():
name = utils.sysctl_devname(ifc.name)
cfg += "%s -w net.ipv4.conf.%s.forwarding=1\n" % (constants.SYSCTL_BIN, name)
cfg += "%s -w net.ipv4.conf.%s.send_redirects=0\n" % \
(constants.SYSCTL_BIN, name)
cfg += "%s -w net.ipv4.conf.%s.forwarding=1\n" % (
constants.SYSCTL_BIN,
name,
)
cfg += "%s -w net.ipv4.conf.%s.send_redirects=0\n" % (
constants.SYSCTL_BIN,
name,
)
cfg += "%s -w net.ipv4.conf.%s.rp_filter=0\n" % (constants.SYSCTL_BIN, name)
return cfg
@ -70,7 +78,7 @@ class DefaultRouteService(UtilService):
cfg = "#!/bin/sh\n"
cfg += "# auto-generated by DefaultRoute service (utility.py)\n"
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control is True:
if hasattr(ifc, "control") and ifc.control is True:
continue
cfg += "\n".join(map(cls.addrstr, ifc.addrlist))
cfg += "\n"
@ -105,7 +113,7 @@ class DefaultMulticastRouteService(UtilService):
cfg += "as needed\n"
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control is True:
if hasattr(ifc, "control") and ifc.control is True:
continue
if os.uname()[0] == "Linux":
rtcmd = "ip route add 224.0.0.0/4 dev"
@ -130,7 +138,7 @@ class StaticRouteService(UtilService):
cfg += "# NOTE: this service must be customized to be of any use\n"
cfg += "# Below are samples that you can uncomment and edit.\n#\n"
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control is True:
if hasattr(ifc, "control") and ifc.control is True:
continue
cfg += "\n".join(map(cls.routestr, ifc.addrlist))
cfg += "\n"
@ -156,8 +164,8 @@ class StaticRouteService(UtilService):
class SshService(UtilService):
name = "SSH"
configs = ("startsshd.sh", "/etc/ssh/sshd_config",)
dirs = ("/etc/ssh", "/var/run/sshd",)
configs = ("startsshd.sh", "/etc/ssh/sshd_config")
dirs = ("/etc/ssh", "/var/run/sshd")
startup = ("sh startsshd.sh",)
shutdown = ("killall sshd",)
validate = ()
@ -179,7 +187,11 @@ ssh-keygen -q -t rsa -N "" -f %s/ssh_host_rsa_key
chmod 655 %s
# wait until RSA host key has been generated to launch sshd
/usr/sbin/sshd -f %s/sshd_config
""" % (sshcfgdir, sshstatedir, sshcfgdir)
""" % (
sshcfgdir,
sshstatedir,
sshcfgdir,
)
else:
return """\
# auto-generated by SSH service (utility.py)
@ -219,14 +231,18 @@ AcceptEnv LANG LC_*
Subsystem sftp %s/sftp-server
UsePAM yes
UseDNS no
""" % (sshcfgdir, sshstatedir, sshlibdir)
""" % (
sshcfgdir,
sshstatedir,
sshlibdir,
)
class DhcpService(UtilService):
name = "DHCP"
configs = ("/etc/dhcp/dhcpd.conf",)
dirs = ("/etc/dhcp","/var/lib/dhcp")
startup = ("touch /var/lib/dhcp/dhcpd.leases","dhcpd")
dirs = ("/etc/dhcp", "/var/lib/dhcp")
startup = ("touch /var/lib/dhcp/dhcpd.leases", "dhcpd")
shutdown = ("killall dhcpd",)
validate = ("pidof dhcpd",)
@ -251,7 +267,7 @@ max-lease-time 7200;
ddns-update-style none;
"""
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control is True:
if hasattr(ifc, "control") and ifc.control is True:
continue
cfg += "\n".join(map(cls.subnetentry, ifc.addrlist))
cfg += "\n"
@ -279,13 +295,20 @@ subnet %s netmask %s {
option routers %s;
}
}
""" % (net.prefix_str(), net.netmask_str(), rangelow, rangehigh, addr)
""" % (
net.prefix_str(),
net.netmask_str(),
rangelow,
rangehigh,
addr,
)
class DhcpClientService(UtilService):
"""
Use a DHCP client for all interfaces for addressing.
"""
name = "DHCPClient"
configs = ("startdhcpclient.sh",)
startup = ("sh startdhcpclient.sh",)
@ -304,7 +327,7 @@ class DhcpClientService(UtilService):
cfg += "#mkdir -p /var/run/resolvconf/interface\n"
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control is True:
if hasattr(ifc, "control") and ifc.control is True:
continue
cfg += "#ln -s /var/run/resolvconf/interface/%s.dhclient" % ifc.name
cfg += " /var/run/resolvconf/resolv.conf\n"
@ -317,9 +340,10 @@ class FtpService(UtilService):
"""
Start a vsftpd server.
"""
name = "FTP"
configs = ("vsftpd.conf",)
dirs = ("/var/run/vsftpd/empty", "/var/ftp",)
dirs = ("/var/run/vsftpd/empty", "/var/ftp")
startup = ("vsftpd ./vsftpd.conf",)
shutdown = ("killall vsftpd",)
validate = ("pidof vsftpd",)
@ -349,12 +373,22 @@ class HttpService(UtilService):
"""
Start an apache server.
"""
name = "HTTP"
configs = ("/etc/apache2/apache2.conf", "/etc/apache2/envvars",
"/var/www/index.html",)
dirs = ("/etc/apache2", "/var/run/apache2", "/var/log/apache2",
"/run/lock", "/var/lock/apache2", "/var/www",)
startup = ("chown www-data /var/lock/apache2", "apache2ctl start",)
configs = (
"/etc/apache2/apache2.conf",
"/etc/apache2/envvars",
"/var/www/index.html",
)
dirs = (
"/etc/apache2",
"/var/run/apache2",
"/var/log/apache2",
"/run/lock",
"/var/lock/apache2",
"/var/www",
)
startup = ("chown www-data /var/lock/apache2", "apache2ctl start")
shutdown = ("apache2ctl stop",)
validate = ("pidof apache2",)
@ -380,38 +414,40 @@ class HttpService(UtilService):
Detect the apache2 version using the 'a2query' command.
"""
try:
status, result = utils.cmd_output(['a2query', '-v'])
status, result = utils.cmd_output(["a2query", "-v"])
except CoreCommandError:
status = -1
if status == 0 and result[:3] == '2.4':
if status == 0 and result[:3] == "2.4":
return cls.APACHEVER24
return cls.APACHEVER22
@classmethod
def generateapache2conf(cls, node, filename):
lockstr = {cls.APACHEVER22:
'LockFile ${APACHE_LOCK_DIR}/accept.lock\n',
cls.APACHEVER24:
'Mutex file:${APACHE_LOCK_DIR} default\n', }
mpmstr = {cls.APACHEVER22: '', cls.APACHEVER24:
'LoadModule mpm_worker_module /usr/lib/apache2/modules/mod_mpm_worker.so\n', }
lockstr = {
cls.APACHEVER22: "LockFile ${APACHE_LOCK_DIR}/accept.lock\n",
cls.APACHEVER24: "Mutex file:${APACHE_LOCK_DIR} default\n",
}
mpmstr = {
cls.APACHEVER22: "",
cls.APACHEVER24: "LoadModule mpm_worker_module /usr/lib/apache2/modules/mod_mpm_worker.so\n",
}
permstr = {cls.APACHEVER22:
' Order allow,deny\n Deny from all\n Satisfy all\n',
cls.APACHEVER24:
' Require all denied\n', }
permstr = {
cls.APACHEVER22: " Order allow,deny\n Deny from all\n Satisfy all\n",
cls.APACHEVER24: " Require all denied\n",
}
authstr = {cls.APACHEVER22:
'LoadModule authz_default_module /usr/lib/apache2/modules/mod_authz_default.so\n',
cls.APACHEVER24:
'LoadModule authz_core_module /usr/lib/apache2/modules/mod_authz_core.so\n', }
authstr = {
cls.APACHEVER22: "LoadModule authz_default_module /usr/lib/apache2/modules/mod_authz_default.so\n",
cls.APACHEVER24: "LoadModule authz_core_module /usr/lib/apache2/modules/mod_authz_core.so\n",
}
permstr2 = {cls.APACHEVER22:
'\t\tOrder allow,deny\n\t\tallow from all\n',
cls.APACHEVER24:
'\t\tRequire all granted\n', }
permstr2 = {
cls.APACHEVER22: "\t\tOrder allow,deny\n\t\tallow from all\n",
cls.APACHEVER24: "\t\tRequire all granted\n",
}
version = cls.detectversionfromcmd()
cfg = "# apache2.conf generated by utility.py:HttpService\n"
@ -544,14 +580,17 @@ export LANG
@classmethod
def generatehtml(cls, node, filename):
body = """\
body = (
"""\
<!-- generated by utility.py:HttpService -->
<h1>%s web server</h1>
<p>This is the default web page for this server.</p>
<p>The web server software is running but no content has been added, yet.</p>
""" % node.name
"""
% node.name
)
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control is True:
if hasattr(ifc, "control") and ifc.control is True:
continue
body += "<li>%s - %s</li>\n" % (ifc.name, ifc.addrlist)
return "<html><body>%s</body></html>" % body
@ -561,6 +600,7 @@ class PcapService(UtilService):
"""
Pcap service for logging packets.
"""
name = "pcap"
configs = ("pcap.sh",)
dirs = ()
@ -584,11 +624,15 @@ if [ "x$1" = "xstart" ]; then
"""
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control is True:
cfg += '# '
if hasattr(ifc, "control") and ifc.control is True:
cfg += "# "
redir = "< /dev/null"
cfg += "tcpdump ${DUMPOPTS} -w %s.%s.pcap -i %s %s &\n" % \
(node.name, ifc.name, ifc.name, redir)
cfg += "tcpdump ${DUMPOPTS} -w %s.%s.pcap -i %s %s &\n" % (
node.name,
ifc.name,
ifc.name,
redir,
)
cfg += """
elif [ "x$1" = "xstop" ]; then
@ -615,12 +659,13 @@ class RadvdService(UtilService):
"""
cfg = "# auto-generated by RADVD service (utility.py)\n"
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control is True:
if hasattr(ifc, "control") and ifc.control is True:
continue
prefixes = map(cls.subnetentry, ifc.addrlist)
if len(prefixes) < 1:
continue
cfg += """\
cfg += (
"""\
interface %s
{
AdvSendAdvert on;
@ -628,18 +673,23 @@ interface %s
MaxRtrAdvInterval 10;
AdvDefaultPreference low;
AdvHomeAgentFlag off;
""" % ifc.name
"""
% ifc.name
)
for prefix in prefixes:
if prefix == "":
continue
cfg += """\
cfg += (
"""\
prefix %s
{
AdvOnLink on;
AdvAutonomous on;
AdvRouterAddr on;
};
""" % prefix
"""
% prefix
)
cfg += "};\n"
return cfg
@ -660,6 +710,7 @@ class AtdService(UtilService):
"""
Atd service for scheduling at jobs
"""
name = "atd"
configs = ("startatd.sh",)
dirs = ("/var/spool/cron/atjobs", "/var/spool/cron/atspool")
@ -681,5 +732,6 @@ class UserDefinedService(UtilService):
"""
Dummy service allowing customization of anything.
"""
name = "UserDefined"
meta = "Customize this service to do anything upon startup."

View file

@ -12,12 +12,16 @@ class XorpRtrmgr(CoreService):
XORP router manager service builds a config.boot file based on other
enabled XORP services, and launches necessary daemons upon startup.
"""
name = "xorp_rtrmgr"
executables = ("xorp_rtrmgr",)
group = "XORP"
dirs = ("/etc/xorp",)
configs = ("/etc/xorp/config.boot",)
startup = ("xorp_rtrmgr -d -b %s -l /var/log/%s.log -P /var/run/%s.pid" % (configs[0], name, name),)
startup = (
"xorp_rtrmgr -d -b %s -l /var/log/%s.log -P /var/run/%s.pid"
% (configs[0], name, name),
)
shutdown = ("killall xorp_rtrmgr",)
validate = ("pidof xorp_rtrmgr",)
@ -74,6 +78,7 @@ class XorpService(CoreService):
Parent class for XORP services. Defines properties and methods
common to XORP's routing daemons.
"""
name = None
executables = ("xorp_rtrmgr",)
group = "XORP"
@ -103,7 +108,7 @@ class XorpService(CoreService):
"""
names = []
for ifc in ifcs:
if hasattr(ifc, 'control') and ifc.control is True:
if hasattr(ifc, "control") and ifc.control is True:
continue
names.append(ifc.name)
names.append("register_vif")
@ -129,7 +134,7 @@ class XorpService(CoreService):
cfg += " policy-statement export-connected {\n"
cfg += "\tterm 100 {\n"
cfg += "\t from {\n"
cfg += "\t\tprotocol: \"connected\"\n"
cfg += '\t\tprotocol: "connected"\n'
cfg += "\t }\n"
cfg += "\t}\n"
cfg += " }\n"
@ -142,11 +147,11 @@ class XorpService(CoreService):
Helper to return the first IPv4 address of a node as its router ID.
"""
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control is True:
if hasattr(ifc, "control") and ifc.control is True:
continue
for a in ifc.addrlist:
if a.find(".") >= 0:
return a.split('/')[0]
return a.split("/")[0]
# raise ValueError, "no IPv4 address found for router ID"
return "0.0.0.0"
@ -165,6 +170,7 @@ class XorpOspfv2(XorpService):
not build its own configuration file but has hooks for adding to the
unified XORP configuration file.
"""
name = "XORP_OSPFv2"
@classmethod
@ -176,7 +182,7 @@ class XorpOspfv2(XorpService):
cfg += "\trouter-id: %s\n" % rtrid
cfg += "\tarea 0.0.0.0 {\n"
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control is True:
if hasattr(ifc, "control") and ifc.control is True:
continue
cfg += "\t interface %s {\n" % ifc.name
cfg += "\t\tvif %s {\n" % ifc.name
@ -200,6 +206,7 @@ class XorpOspfv3(XorpService):
not build its own configuration file but has hooks for adding to the
unified XORP configuration file.
"""
name = "XORP_OSPFv3"
@classmethod
@ -211,7 +218,7 @@ class XorpOspfv3(XorpService):
cfg += "\trouter-id: %s\n" % rtrid
cfg += "\tarea 0.0.0.0 {\n"
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control is True:
if hasattr(ifc, "control") and ifc.control is True:
continue
cfg += "\t interface %s {\n" % ifc.name
cfg += "\t\tvif %s {\n" % ifc.name
@ -227,6 +234,7 @@ class XorpBgp(XorpService):
"""
IPv4 inter-domain routing. AS numbers and peers must be customized.
"""
name = "XORP_BGP"
custom_needed = True
@ -241,7 +249,7 @@ class XorpBgp(XorpService):
cfg += " bgp {\n"
cfg += "\tbgp-id: %s\n" % rtrid
cfg += "\tlocal-as: 65001 /* change this */\n"
cfg += "\texport: \"export-connected\"\n"
cfg += '\texport: "export-connected"\n'
cfg += "\tpeer 10.0.1.1 { /* change this */\n"
cfg += "\t local-ip: 10.0.1.1\n"
cfg += "\t as: 65002\n"
@ -265,9 +273,9 @@ class XorpRip(XorpService):
cfg += cls.policyexportconnected()
cfg += "\nprotocols {\n"
cfg += " rip {\n"
cfg += "\texport: \"export-connected\"\n"
cfg += '\texport: "export-connected"\n'
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control is True:
if hasattr(ifc, "control") and ifc.control is True:
continue
cfg += "\tinterface %s {\n" % ifc.name
cfg += "\t vif %s {\n" % ifc.name
@ -289,6 +297,7 @@ class XorpRipng(XorpService):
"""
RIP NG IPv6 unicast routing.
"""
name = "XORP_RIPNG"
@classmethod
@ -297,9 +306,9 @@ class XorpRipng(XorpService):
cfg += cls.policyexportconnected()
cfg += "\nprotocols {\n"
cfg += " ripng {\n"
cfg += "\texport: \"export-connected\"\n"
cfg += '\texport: "export-connected"\n'
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control is True:
if hasattr(ifc, "control") and ifc.control is True:
continue
cfg += "\tinterface %s {\n" % ifc.name
cfg += "\t vif %s {\n" % ifc.name
@ -324,6 +333,7 @@ class XorpPimSm4(XorpService):
"""
PIM Sparse Mode IPv4 multicast routing.
"""
name = "XORP_PIMSM4"
@classmethod
@ -334,7 +344,7 @@ class XorpPimSm4(XorpService):
cfg += " igmp {\n"
names = []
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control is True:
if hasattr(ifc, "control") and ifc.control is True:
continue
names.append(ifc.name)
cfg += "\tinterface %s {\n" % ifc.name
@ -358,12 +368,12 @@ class XorpPimSm4(XorpService):
cfg += "\tbootstrap {\n"
cfg += "\t cand-bsr {\n"
cfg += "\t\tscope-zone 224.0.0.0/4 {\n"
cfg += "\t\t cand-bsr-by-vif-name: \"%s\"\n" % names[0]
cfg += '\t\t cand-bsr-by-vif-name: "%s"\n' % names[0]
cfg += "\t\t}\n"
cfg += "\t }\n"
cfg += "\t cand-rp {\n"
cfg += "\t\tgroup-prefix 224.0.0.0/4 {\n"
cfg += "\t\t cand-rp-by-vif-name: \"%s\"\n" % names[0]
cfg += '\t\t cand-rp-by-vif-name: "%s"\n' % names[0]
cfg += "\t\t}\n"
cfg += "\t }\n"
cfg += "\t}\n"
@ -383,6 +393,7 @@ class XorpPimSm6(XorpService):
"""
PIM Sparse Mode IPv6 multicast routing.
"""
name = "XORP_PIMSM6"
@classmethod
@ -393,7 +404,7 @@ class XorpPimSm6(XorpService):
cfg += " mld {\n"
names = []
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control is True:
if hasattr(ifc, "control") and ifc.control is True:
continue
names.append(ifc.name)
cfg += "\tinterface %s {\n" % ifc.name
@ -417,12 +428,12 @@ class XorpPimSm6(XorpService):
cfg += "\tbootstrap {\n"
cfg += "\t cand-bsr {\n"
cfg += "\t\tscope-zone ff00::/8 {\n"
cfg += "\t\t cand-bsr-by-vif-name: \"%s\"\n" % names[0]
cfg += '\t\t cand-bsr-by-vif-name: "%s"\n' % names[0]
cfg += "\t\t}\n"
cfg += "\t }\n"
cfg += "\t cand-rp {\n"
cfg += "\t\tgroup-prefix ff00::/8 {\n"
cfg += "\t\t cand-rp-by-vif-name: \"%s\"\n" % names[0]
cfg += '\t\t cand-rp-by-vif-name: "%s"\n' % names[0]
cfg += "\t\t}\n"
cfg += "\t }\n"
cfg += "\t}\n"
@ -442,6 +453,7 @@ class XorpOlsr(XorpService):
"""
OLSR IPv4 unicast MANET routing.
"""
name = "XORP_OLSR"
@classmethod
@ -452,7 +464,7 @@ class XorpOlsr(XorpService):
cfg += " olsr4 {\n"
cfg += "\tmain-address: %s\n" % rtrid
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control is True:
if hasattr(ifc, "control") and ifc.control is True:
continue
cfg += "\tinterface %s {\n" % ifc.name
cfg += "\t vif %s {\n" % ifc.name

View file

@ -31,10 +31,7 @@ def execute_file(path, exec_globals=None, exec_locals=None):
"""
if exec_globals is None:
exec_globals = {}
exec_globals.update({
"__file__": path,
"__name__": "__main__"
})
exec_globals.update({"__file__": path, "__name__": "__main__"})
with open(path, "rb") as f:
data = compile(f.read(), path, "exec")
exec(data, exec_globals, exec_locals)
@ -158,7 +155,7 @@ def make_tuple(obj):
if hasattr(obj, "__iter__"):
return tuple(obj)
else:
return obj,
return (obj,)
def make_tuple_fromstr(s, value_type):
@ -291,7 +288,10 @@ 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))
@ -439,6 +439,8 @@ def load_classes(path, clazz):
valid_class = member[1]
classes.append(valid_class)
except:
logging.exception("unexpected error during import, skipping: %s", import_statement)
logging.exception(
"unexpected error during import, skipping: %s", import_statement
)
return classes

View file

@ -12,7 +12,13 @@ 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)
xml_data = etree.tostring(
xml_element,
xml_declaration=True,
pretty_print=True,
encoding="UTF-8",
doctype=doctype,
)
with open(file_path, "wb") as xml_file:
xml_file.write(xml_data)
@ -251,7 +257,9 @@ class CoreXmlWriter(object):
# write out generated xml
xml_tree = etree.ElementTree(self.scenario)
xml_tree.write(file_name, xml_declaration=True, pretty_print=True, encoding="UTF-8")
xml_tree.write(
file_name, xml_declaration=True, pretty_print=True, encoding="UTF-8"
)
def write_session_origin(self):
# origin: geolocation of cartesian coordinate 0,0,0
@ -326,12 +334,18 @@ class CoreXmlWriter(object):
for model_name in all_configs:
config = all_configs[model_name]
logging.info("writing emane config node(%s) model(%s)", node_id, 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)
emane_configuration = create_emane_config(
node_id, self.session.emane.emane_config, config
)
else:
model = self.session.emane.models[model_name]
emane_configuration = create_emane_model_config(node_id, model, config)
emane_configuration = create_emane_model_config(
node_id, model, config
)
emane_configurations.append(emane_configuration)
if emane_configurations.getchildren():
@ -346,8 +360,12 @@ class CoreXmlWriter(object):
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")
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 in config:
@ -387,7 +405,9 @@ class CoreXmlWriter(object):
for node_id in self.session.nodes:
node = self.session.nodes[node_id]
# network node
is_network_or_rj45 = isinstance(node, (core.nodes.base.CoreNetworkBase, core.nodes.physical.Rj45Node))
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)
@ -429,7 +449,9 @@ 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):
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
@ -467,7 +489,7 @@ class CoreXmlWriter(object):
link_data.interface1_ip4,
link_data.interface1_ip4_mask,
link_data.interface1_ip6,
link_data.interface1_ip6_mask
link_data.interface1_ip6_mask,
)
link_element.append(interface_one)
@ -481,7 +503,7 @@ class CoreXmlWriter(object):
link_data.interface2_ip4,
link_data.interface2_ip4_mask,
link_data.interface2_ip6,
link_data.interface2_ip6_mask
link_data.interface2_ip6_mask,
)
link_element.append(interface_two)
@ -540,7 +562,9 @@ class CoreXmlReader(object):
services = []
for service in node.iterchildren():
services.append(service.get("name"))
logging.info("reading default services for nodes(%s): %s", node_type, services)
logging.info(
"reading default services for nodes(%s): %s", node_type, services
)
self.session.services.default_services[node_type] = services
def read_session_metadata(self):
@ -580,7 +604,9 @@ class CoreXmlReader(object):
data = hook.text
hook_type = "hook:%s" % state
logging.info("reading hook: state(%s) name(%s)", state, name)
self.session.set_hook(hook_type, file_name=name, source_name=None, data=data)
self.session.set_hook(
hook_type, file_name=name, source_name=None, data=data
)
def read_session_origin(self):
session_origin = self.scenario.find("session_origin")
@ -614,7 +640,9 @@ class CoreXmlReader(object):
for service_configuration in service_configurations.iterchildren():
node_id = get_int(service_configuration, "node")
service_name = service_configuration.get("name")
logging.info("reading custom service(%s) for node(%s)", service_name, node_id)
logging.info(
"reading custom service(%s) for node(%s)", service_name, node_id
)
self.session.services.set_service(node_id, service_name)
service = self.session.services.get_service(node_id, service_name)
@ -628,11 +656,15 @@ class CoreXmlReader(object):
validate_elements = service_configuration.find("validates")
if validate_elements is not None:
service.validate = tuple(x.text for x in validate_elements.iterchildren())
service.validate = tuple(
x.text for x in validate_elements.iterchildren()
)
shutdown_elements = service_configuration.find("shutdowns")
if shutdown_elements is not None:
service.shutdown = tuple(x.text for x in shutdown_elements.iterchildren())
service.shutdown = tuple(
x.text for x in shutdown_elements.iterchildren()
)
file_elements = service_configuration.find("files")
if file_elements is not None:
@ -669,7 +701,9 @@ class CoreXmlReader(object):
value = config.get("value")
configs[name] = value
logging.info("reading emane configuration node(%s) model(%s)", node_id, model_name)
logging.info(
"reading emane configuration node(%s) model(%s)", node_id, model_name
)
self.session.emane.set_model_config(node_id, model_name, configs)
def read_mobility_configs(self):
@ -687,7 +721,9 @@ class CoreXmlReader(object):
value = config.get("value")
configs[name] = value
logging.info("reading mobility configuration node(%s) model(%s)", node_id, model_name)
logging.info(
"reading mobility configuration node(%s) model(%s)", node_id, model_name
)
self.session.mobility.set_model_config(node_id, model_name, configs)
def read_nodes(self):
@ -709,7 +745,9 @@ class CoreXmlReader(object):
service_elements = device_element.find("services")
if service_elements is not None:
node_options.services = [x.get("name") for x in service_elements.iterchildren()]
node_options.services = [
x.get("name") for x in service_elements.iterchildren()
]
position_element = device_element.find("position")
if position_element is not None:
@ -746,7 +784,9 @@ class CoreXmlReader(object):
if all([lat, lon, alt]):
node_options.set_location(lat, lon, alt)
logging.info("reading node id(%s) node_type(%s) name(%s)", node_id, node_type, name)
logging.info(
"reading node id(%s) node_type(%s) name(%s)", node_id, node_type, name
)
self.session.add_node(_type=node_type, _id=node_id, node_options=node_options)
def read_links(self):
@ -790,10 +830,24 @@ class CoreXmlReader(object):
link_options.gui_attributes = options_element.get("gui_attributes")
if link_options.unidirectional == 1 and node_set in node_sets:
logging.info("updating link node_one(%s) node_two(%s): %s", node_one, node_two, link_options)
self.session.update_link(node_one, node_two, interface_one.id, interface_two.id, link_options)
logging.info(
"updating link node_one(%s) node_two(%s): %s",
node_one,
node_two,
link_options,
)
self.session.update_link(
node_one, node_two, interface_one.id, interface_two.id, link_options
)
else:
logging.info("adding link node_one(%s) node_two(%s): %s", node_one, node_two, link_options)
self.session.add_link(node_one, node_two, interface_one, interface_two, link_options)
logging.info(
"adding link node_one(%s) node_two(%s): %s",
node_one,
node_two,
link_options,
)
self.session.add_link(
node_one, node_two, interface_one, interface_two, link_options
)
node_sets.add(node_set)

View file

@ -31,16 +31,22 @@ def add_emane_interface(host_element, netif, platform_name="p1", transport_name=
# platform data
platform_id = "%s/%s" % (host_id, platform_name)
platform_element = etree.SubElement(host_element, "emanePlatform", id=platform_id, name=platform_name)
platform_element = etree.SubElement(
host_element, "emanePlatform", id=platform_id, name=platform_name
)
# transport data
transport_id = "%s/%s" % (host_id, transport_name)
etree.SubElement(platform_element, "transport", id=transport_id, name=transport_name)
etree.SubElement(
platform_element, "transport", id=transport_id, name=transport_name
)
# nem data
nem_name = "nem%s" % nem_id
nem_element_id = "%s/%s" % (host_id, nem_name)
nem_element = etree.SubElement(platform_element, "nem", id=nem_element_id, name=nem_name)
nem_element = etree.SubElement(
platform_element, "nem", id=nem_element_id, name=nem_name
)
nem_id_element = etree.SubElement(nem_element, "parameter", name="nemid")
nem_id_element.text = str(nem_id)
@ -81,7 +87,9 @@ class CoreXmlDeployment(object):
def __init__(self, session, scenario):
self.session = session
self.scenario = scenario
self.root = etree.SubElement(scenario, "container", id="TestBed", name="TestBed")
self.root = etree.SubElement(
scenario, "container", id="TestBed", name="TestBed"
)
self.add_deployment()
def find_device(self, name):
@ -89,8 +97,10 @@ class CoreXmlDeployment(object):
return device
def find_interface(self, device, name):
interface = self.scenario.find("devices/device[@name='%s']/interfaces/interface[@name='%s']" % (
device.name, name))
interface = self.scenario.find(
"devices/device[@name='%s']/interfaces/interface[@name='%s']"
% (device.name, name)
)
return interface
def add_deployment(self):
@ -125,7 +135,9 @@ class CoreXmlDeployment(object):
# create virtual host element
host_id = "%s/%s" % (physical_host.get("id"), node.name)
host_element = etree.SubElement(physical_host, "testHost", id=host_id, name=node.name)
host_element = etree.SubElement(
physical_host, "testHost", id=host_id, name=node.name
)
# add host type
add_type(host_element, "virtual")

View file

@ -53,7 +53,10 @@ def create_file(xml_element, doc_name, file_path):
:param str file_path: file path to write xml file to
:return: nothing
"""
doctype = '<!DOCTYPE %(doc_name)s SYSTEM "file:///usr/share/emane/dtd/%(doc_name)s.dtd">' % {"doc_name": doc_name}
doctype = (
'<!DOCTYPE %(doc_name)s SYSTEM "file:///usr/share/emane/dtd/%(doc_name)s.dtd">'
% {"doc_name": doc_name}
)
corexml.write_xml_file(xml_element, file_path, doctype=doctype)
@ -108,7 +111,12 @@ def build_node_platform_xml(emane_manager, control_net, node, nem_id, platform_x
:return: the next nem id that can be used for creating platform xml files
:rtype: int
"""
logging.debug("building emane platform xml for node(%s) nem_id(%s): %s", node, nem_id, node.name)
logging.debug(
"building emane platform xml for node(%s) nem_id(%s): %s",
node,
nem_id,
node.name,
)
nem_entries = {}
if node.model is None:
@ -116,10 +124,14 @@ def build_node_platform_xml(emane_manager, control_net, node, nem_id, platform_x
return nem_entries
for netif in node.netifs():
logging.debug("building platform xml for interface(%s) nem_id(%s)", netif.name, nem_id)
logging.debug(
"building platform xml for interface(%s) nem_id(%s)", netif.name, nem_id
)
# build nem xml
nem_definition = nem_file_name(node.model, netif)
nem_element = etree.Element("nem", id=str(nem_id), name=netif.localname, definition=nem_definition)
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.id, netif, node.model.name)
@ -137,7 +149,9 @@ def build_node_platform_xml(emane_manager, control_net, node, nem_id, platform_x
logging.info("warning: %s interface type unsupported!", netif.name)
transport_type = "raw"
transport_file = transport_file_name(node.id, transport_type)
transport_element = etree.SubElement(nem_element, "transport", definition=transport_file)
transport_element = etree.SubElement(
nem_element, "transport", definition=transport_file
)
# add transport parameter
add_param(transport_element, "device", netif.name)
@ -261,7 +275,7 @@ def build_transport_xml(emane_manager, node, transport_type):
transport_element = etree.Element(
"transport",
name="%s Transport" % transport_type.capitalize(),
library="trans%s" % transport_type.lower()
library="trans%s" % transport_type.lower(),
)
# add bitrate
@ -299,7 +313,9 @@ def create_phy_xml(emane_model, config, file_path):
if emane_model.phy_library:
phy_element.set("library", emane_model.phy_library)
add_configurations(phy_element, emane_model.phy_config, config, emane_model.config_ignore)
add_configurations(
phy_element, emane_model.phy_config, config, emane_model.config_ignore
)
create_file(phy_element, "phy", file_path)
@ -315,12 +331,18 @@ def create_mac_xml(emane_model, config, file_path):
if not emane_model.mac_library:
raise ValueError("must define emane model library")
mac_element = etree.Element("mac", name="%s MAC" % emane_model.name, library=emane_model.mac_library)
add_configurations(mac_element, emane_model.mac_config, config, emane_model.config_ignore)
mac_element = etree.Element(
"mac", name="%s MAC" % emane_model.name, library=emane_model.mac_library
)
add_configurations(
mac_element, emane_model.mac_config, config, emane_model.config_ignore
)
create_file(mac_element, "mac", file_path)
def create_nem_xml(emane_model, config, nem_file, transport_definition, mac_definition, phy_definition):
def create_nem_xml(
emane_model, config, nem_file, transport_definition, mac_definition, phy_definition
):
"""
Create the nem xml document.
@ -353,7 +375,13 @@ def create_event_service_xml(group, port, device, file_directory):
:return: nothing
"""
event_element = etree.Element("emaneeventmsgsvc")
for name, value in (("group", group), ("port", port), ("device", device), ("mcloop", "1"), ("ttl", "32")):
for name, value in (
("group", group),
("port", port),
("device", device),
("mcloop", "1"),
("ttl", "32"),
):
sub_element = etree.SubElement(event_element, name)
sub_element.text = value
file_name = "libemaneeventservice.xml"

View file

@ -28,8 +28,7 @@ def example(options):
# create emane network node
emane_network = session.create_emane_network(
model=EmaneIeee80211abgModel,
geo_reference=(47.57917, -122.13232, 2.00000)
model=EmaneIeee80211abgModel, geo_reference=(47.57917, -122.13232, 2.00000)
)
emane_network.setposition(x=80, y=50)
@ -55,7 +54,10 @@ 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))

View file

@ -7,10 +7,20 @@ DEFAULT_STEP = 1
def parse_options(name):
parser = argparse.ArgumentParser(description="Run %s example" % name)
parser.add_argument("-n", "--nodes", type=int, default=DEFAULT_NODES,
help="number of nodes to create in this example")
parser.add_argument("-t", "--time", type=int, default=DEFAULT_TIME,
help="example iperf run time in seconds")
parser.add_argument(
"-n",
"--nodes",
type=int,
default=DEFAULT_NODES,
help="number of nodes to create in this example",
)
parser.add_argument(
"-t",
"--time",
type=int,
default=DEFAULT_TIME,
help="example iperf run time in seconds",
)
options = parser.parse_args()

View file

@ -21,7 +21,9 @@ def main():
core.events(session_id, log_event)
# change session state
response = core.set_session_state(session_id, core_pb2.SessionState.CONFIGURATION)
response = core.set_session_state(
session_id, core_pb2.SessionState.CONFIGURATION
)
logging.info("set session state: %s", response)
# create switch node
@ -47,7 +49,9 @@ def main():
logging.info("created link: %s", response)
# change session state
response = core.set_session_state(session_id, core_pb2.SessionState.INSTANTIATION)
response = core.set_session_state(
session_id, core_pb2.SessionState.INSTANTIATION
)
logging.info("set session state: %s", response)

View file

@ -39,15 +39,11 @@ class ExampleModel(emanemodel.EmaneModel):
mac_library = "rfpipemaclayer"
mac_xml = "/usr/share/emane/manifest/rfpipemaclayer.xml"
mac_defaults = {
"pcrcurveuri": "/usr/share/emane/xml/models/mac/rfpipe/rfpipepcr.xml",
"pcrcurveuri": "/usr/share/emane/xml/models/mac/rfpipe/rfpipepcr.xml"
}
mac_config = emanemanifest.parse(mac_xml, mac_defaults)
phy_library = None
phy_xml = "/usr/share/emane/manifest/emanephy.xml"
phy_defaults = {
"subid": "1",
"propagationmodel": "2ray",
"noisemode": "none"
}
phy_defaults = {"subid": "1", "propagationmodel": "2ray", "noisemode": "none"}
phy_config = emanemanifest.parse(phy_xml, phy_defaults)
config_ignore = set()

View file

@ -30,6 +30,7 @@ class MyService(CoreService):
only used in NON_BLOCKING mode
:var tuple shutdown: shutdown commands to stop this service
"""
name = "MyService"
group = "Utility"
executables = ()

View file

@ -51,7 +51,9 @@ def cmd(node, exec_cmd):
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)
msg = coreapi.CoreExecMessage.pack(
MessageFlags.STRING.value | MessageFlags.TEXT.value, tlvdata
)
node.session.broker.handlerawmsg(msg)
exec_num += 1
@ -81,10 +83,16 @@ def main():
parser = optparse.OptionParser(usage=usagestr)
parser.set_defaults(numnodes=5, daemon="127.0.0.1:" + str(CORE_API_PORT))
parser.add_option("-n", "--numnodes", dest="numnodes", type=int,
help="number of nodes")
parser.add_option("-d", "--daemon-server", dest="daemon", type=str,
help="daemon server IP address")
parser.add_option(
"-n", "--numnodes", dest="numnodes", type=int, help="number of nodes"
)
parser.add_option(
"-d",
"--daemon-server",
dest="daemon",
type=str,
help="daemon server IP address",
)
def usage(msg=None, err=0):
sys.stdout.write("\n")
@ -134,7 +142,9 @@ def main():
# Change to configuration state on both machines
session.set_state(EventTypes.CONFIGURATION_STATE)
tlvdata = coreapi.CoreEventTlv.pack(EventTlvs.TYPE.value, EventTypes.CONFIGURATION_STATE.value)
tlvdata = coreapi.CoreEventTlv.pack(
EventTlvs.TYPE.value, EventTypes.CONFIGURATION_STATE.value
)
session.broker.handlerawmsg(coreapi.CoreEventMessage.pack(0, tlvdata))
flags = MessageFlags.ADD.value
@ -147,11 +157,15 @@ 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 range(1, number_of_nodes + 1):
node = core.nodes.base.CoreNode(session=session, _id=i, name="n%d" % i, start=False)
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)
@ -165,14 +179,20 @@ def main():
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)
tlvdata += coreapi.CoreLinkTlv.pack(LinkTlvs.INTERFACE2_IP4.value, prefix.addr(i))
tlvdata += coreapi.CoreLinkTlv.pack(LinkTlvs.INTERFACE2_IP4_MASK.value, prefix.prefixlen)
tlvdata += coreapi.CoreLinkTlv.pack(
LinkTlvs.INTERFACE2_IP4.value, prefix.addr(i)
)
tlvdata += coreapi.CoreLinkTlv.pack(
LinkTlvs.INTERFACE2_IP4_MASK.value, prefix.prefixlen
)
msg = coreapi.CoreLinkMessage.pack(flags, tlvdata)
session.broker.handlerawmsg(msg)
# We change the daemon to Instantiation state
# We do not change the local session as it would try and build a tunnel and fail
tlvdata = coreapi.CoreEventTlv.pack(EventTlvs.TYPE.value, EventTypes.INSTANTIATION_STATE.value)
tlvdata = coreapi.CoreEventTlv.pack(
EventTlvs.TYPE.value, EventTypes.INSTANTIATION_STATE.value
)
msg = coreapi.CoreEventMessage.pack(0, tlvdata)
session.broker.handlerawmsg(msg)
@ -181,7 +201,9 @@ def main():
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(
"To stop this session, use the core-cleanup script on the remote daemon server."
)
raw_input("press enter to exit")

View file

@ -38,10 +38,12 @@ def main():
parser = optparse.OptionParser(usage=usagestr)
parser.set_defaults(numnodes=5, slave=None)
parser.add_option("-n", "--numnodes", dest="numnodes", type=int,
help="number of nodes")
parser.add_option("-s", "--slave-server", dest="slave", type=str,
help="slave server IP address")
parser.add_option(
"-n", "--numnodes", dest="numnodes", type=int, help="number of nodes"
)
parser.add_option(
"-s", "--slave-server", dest="slave", type=str, help="slave server IP address"
)
def usage(msg=None, err=0):
sys.stdout.write("\n")
@ -65,11 +67,11 @@ def main():
prefix = ipaddress.Ipv4Prefix("10.83.0.0/16")
session = Session(1)
if 'server' in globals():
if "server" in globals():
server.addsession(session)
# distributed setup - connect to slave server
slaveport = options.slave.split(':')
slaveport = options.slave.split(":")
slave = slaveport[0]
if len(slaveport) > 1:
port = int(slaveport[1])
@ -79,15 +81,19 @@ def main():
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)
tlvdata = coreapi.CoreEventTlv.pack(
EventTlvs.TYPE.value, EventTypes.CONFIGURATION_STATE.value
)
session.broker.handlerawmsg(coreapi.CoreEventMessage.pack(0, tlvdata))
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))
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)])
@ -100,7 +106,9 @@ def main():
# create remote nodes via API
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 = 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)
@ -114,13 +122,19 @@ def main():
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)
tlvdata += coreapi.CoreLinkTlv.pack(LinkTlvs.INTERFACE2_IP4.value, prefix.addr(i))
tlvdata += coreapi.CoreLinkTlv.pack(LinkTlvs.INTERFACE2_IP4_MASK.value, prefix.prefixlen)
tlvdata += coreapi.CoreLinkTlv.pack(
LinkTlvs.INTERFACE2_IP4.value, prefix.addr(i)
)
tlvdata += coreapi.CoreLinkTlv.pack(
LinkTlvs.INTERFACE2_IP4_MASK.value, prefix.prefixlen
)
msg = coreapi.CoreLinkMessage.pack(flags, tlvdata)
session.broker.handlerawmsg(msg)
session.instantiate()
tlvdata = coreapi.CoreEventTlv.pack(EventTlvs.TYPE.value, EventTypes.INSTANTIATION_STATE.value)
tlvdata = coreapi.CoreEventTlv.pack(
EventTlvs.TYPE.value, EventTypes.INSTANTIATION_STATE.value
)
msg = coreapi.CoreEventMessage.pack(0, tlvdata)
session.broker.handlerawmsg(msg)

View file

@ -78,27 +78,57 @@ switchlist = []
def main():
usagestr = "usage: %prog [-h] [options] [args]"
parser = optparse.OptionParser(usage=usagestr)
parser.set_defaults(waittime=0.2, numnodes=0, bridges=0, retries=0,
logfile=None, services=None)
parser.set_defaults(
waittime=0.2, numnodes=0, bridges=0, retries=0, logfile=None, services=None
)
parser.add_option("-w", "--waittime", dest="waittime", type=float,
help="number of seconds to wait between node creation" \
" (default = %s)" % parser.defaults["waittime"])
parser.add_option("-n", "--numnodes", dest="numnodes", type=int,
help="number of nodes (default = unlimited)")
parser.add_option("-b", "--bridges", dest="bridges", type=int,
help="number of nodes per bridge; 0 = one bridge " \
"(def. = %s)" % parser.defaults["bridges"])
parser.add_option("-r", "--retry", dest="retries", type=int,
help="number of retries on error (default = %s)" % \
parser.defaults["retries"])
parser.add_option("-l", "--log", dest="logfile", type=str,
help="log memory usage to this file (default = %s)" % \
parser.defaults["logfile"])
parser.add_option("-s", "--services", dest="services", type=str,
help="pipe-delimited list of services added to each "
"node (default = %s)\n(Example: zebra|OSPFv2|OSPFv3|"
"IPForward)" % parser.defaults["services"])
parser.add_option(
"-w",
"--waittime",
dest="waittime",
type=float,
help="number of seconds to wait between node creation"
" (default = %s)" % parser.defaults["waittime"],
)
parser.add_option(
"-n",
"--numnodes",
dest="numnodes",
type=int,
help="number of nodes (default = unlimited)",
)
parser.add_option(
"-b",
"--bridges",
dest="bridges",
type=int,
help="number of nodes per bridge; 0 = one bridge "
"(def. = %s)" % parser.defaults["bridges"],
)
parser.add_option(
"-r",
"--retry",
dest="retries",
type=int,
help="number of retries on error (default = %s)" % parser.defaults["retries"],
)
parser.add_option(
"-l",
"--log",
dest="logfile",
type=str,
help="log memory usage to this file (default = %s)"
% parser.defaults["logfile"],
)
parser.add_option(
"-s",
"--services",
dest="services",
type=str,
help="pipe-delimited list of services added to each "
"node (default = %s)\n(Example: zebra|OSPFv2|OSPFv3|"
"IPForward)" % parser.defaults["services"],
)
def usage(msg=None, err=0):
sys.stdout.write("\n")
@ -118,7 +148,10 @@ def main():
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(
" - %.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)
@ -149,9 +182,15 @@ def main():
if 0 < options.bridges <= switch.numnetif():
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))
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))
print(
"At %d bridges (%d nodes) caught exception:\n%s\n"
% (len(switchlist), i - 1, e)
)
break
# create a node
@ -164,11 +203,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))

View file

@ -19,6 +19,7 @@ from string import Template
import core.nodes.base
import core.nodes.network
from core.constants import QUAGGA_STATE_DIR
# this is the /etc/core/core.conf default
from core.emulator.session import Session
from core.nodes import ipaddress
@ -42,7 +43,9 @@ except OSError:
class ManetNode(core.nodes.base.CoreNode):
""" An Lxc namespace node configured for Quagga OSPFv3 MANET MDR
"""
conftemp = Template("""\
conftemp = Template(
"""\
interface eth0
ip address $ipaddr
ipv6 ospf6 instance-id 65
@ -59,12 +62,12 @@ router ospf6
interface eth0 area 0.0.0.0
!
ip forwarding
""")
"""
)
confdir = "/usr/local/etc/quagga"
def __init__(self, core, ipaddr, routerid=None,
_id=None, name=None, nodedir=None):
def __init__(self, core, ipaddr, routerid=None, _id=None, name=None, nodedir=None):
if routerid is None:
routerid = ipaddr.split("/")[0]
self.ipaddr = ipaddr
@ -74,8 +77,7 @@ ip forwarding
self.privatedir(QUAGGA_STATE_DIR)
def qconf(self):
return self.conftemp.substitute(ipaddr=self.ipaddr,
routerid=self.routerid)
return self.conftemp.substitute(ipaddr=self.ipaddr, routerid=self.routerid)
def config(self):
filename = os.path.join(self.confdir, "Quagga.conf")
@ -120,7 +122,11 @@ waitfile $STATEDIR/zebra.vty
waitfile $STATEDIR/ospf6d.vty
vtysh -b
""" % (QUAGGA_STATE_DIR, quagga_path, quagga_path)
""" % (
QUAGGA_STATE_DIR,
quagga_path,
quagga_path,
)
class Route(object):
@ -130,14 +136,19 @@ class Route(object):
try:
self.prefix = ipaddress.Ipv4Prefix(prefix)
except Exception as e:
raise ValueError("Invalid prefix given to Route object: %s\n%s" % (prefix, e))
raise ValueError(
"Invalid prefix given to Route object: %s\n%s" % (prefix, e)
)
self.gw = gw
self.metric = metric
def __eq__(self, other):
try:
return self.prefix == other.prefix and self.gw == other.gw and \
self.metric == other.metric
return (
self.prefix == other.prefix
and self.gw == other.gw
and self.metric == other.metric
)
except:
return False
@ -169,13 +180,13 @@ class ManetExperiment(object):
self.logbegin()
def info(self, msg):
''' Utility method for writing output to stdout. '''
""" Utility method for writing output to stdout. """
print(msg)
sys.stdout.flush()
self.log(msg)
def warn(self, msg):
''' Utility method for writing output to stderr. '''
""" Utility method for writing output to stderr. """
sys.stderr.write(msg)
sys.stderr.flush()
self.log(msg)
@ -193,8 +204,7 @@ class ManetExperiment(object):
if not self.logfp:
return
end = datetime.datetime.now()
self.log("ospfmanetmdrtest end: %s (%s)\n" % \
(end.ctime(), end - self.start))
self.log("ospfmanetmdrtest end: %s (%s)\n" % (end.ctime(), end - self.start))
self.logfp.flush()
self.logfp.close()
self.logfp = None
@ -245,7 +255,9 @@ class ManetExperiment(object):
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.create_node(cls=ManetNode, ipaddr=addr, _id="%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
@ -301,8 +313,9 @@ class ManetExperiment(object):
break
if not connected:
msg = "All routers do not form a CDS"
self.warn("XXX %s: not in CDS; neighbors: %s" % \
(n.routerid, nbrs[n.routerid]))
self.warn(
"XXX %s: not in CDS; neighbors: %s" % (n.routerid, nbrs[n.routerid])
)
if self.verbose:
self.info(msg)
@ -315,8 +328,9 @@ class ManetExperiment(object):
db = lsdbs[n.routerid]
if lsdbs[prev.routerid] != db:
msg = "LSDBs of all routers are not consistent"
self.warn("XXX LSDBs inconsistent for %s and %s" % \
(n.routerid, prev.routerid))
self.warn(
"XXX LSDBs inconsistent for %s and %s" % (n.routerid, prev.routerid)
)
i = 0
for entry in lsdbs[n.routerid].split("\n"):
preventries = lsdbs[prev.routerid].split("\n")
@ -355,6 +369,7 @@ class ManetExperiment(object):
class Cmd:
""" Helper class for running a command on a node and parsing the result. """
args = ""
def __init__(self, node, verbose=False):
@ -366,12 +381,12 @@ class Cmd:
self.verbose = verbose
def info(self, msg):
''' Utility method for writing output to stdout.'''
""" Utility method for writing output to stdout."""
print(msg)
sys.stdout.flush()
def warn(self, msg):
''' Utility method for writing output to stderr. '''
""" Utility method for writing output to stderr. """
sys.stderr.write("XXX %s:" % self.node.routerid, msg)
sys.stderr.flush()
@ -412,6 +427,7 @@ class VtyshCmd(Cmd):
class Ospf6NeighState(VtyshCmd):
""" Check a node for OSPFv3 neighbors in the full/two-way states. """
args = "show ipv6 ospf6 neighbor"
def parse(self):
@ -435,6 +451,7 @@ class Ospf6NeighState(VtyshCmd):
class Ospf6MdrLevel(VtyshCmd):
""" Retrieve the OSPFv3 MDR level for a node. """
args = "show ipv6 ospf6 mdrlevel"
def parse(self):
@ -451,6 +468,7 @@ class Ospf6MdrLevel(VtyshCmd):
class Ospf6Database(VtyshCmd):
""" Retrieve the OSPFv3 LSDB summary for a node. """
args = "show ipv6 ospf6 database"
def parse(self):
@ -469,6 +487,7 @@ class ZebraRoutes(VtyshCmd):
""" Return a list of Route objects for a node based on its zebra
routing table.
"""
args = "show ip route"
def parse(self):
@ -510,6 +529,7 @@ class KernelRoutes(Cmd):
""" Return a list of Route objects for a node based on its kernel
routing table.
"""
args = ("/sbin/ip", "route", "show")
def parse(self):
@ -547,18 +567,32 @@ def main():
parser = optparse.OptionParser(usage=usagestr)
parser.set_defaults(numnodes=10, linkprob=0.35, delay=20, seed=None)
parser.add_option("-n", "--numnodes", dest="numnodes", type=int,
help="number of nodes")
parser.add_option("-p", "--linkprob", dest="linkprob", type=float,
help="link probabilty")
parser.add_option("-d", "--delay", dest="delay", type=float,
help="wait time before checking")
parser.add_option("-s", "--seed", dest="seed", type=int,
help="specify integer to use for random seed")
parser.add_option("-v", "--verbose", dest="verbose",
action="store_true", help="be more verbose")
parser.add_option("-l", "--logfile", dest="logfile", type=str,
help="log detailed output to the specified file")
parser.add_option(
"-n", "--numnodes", dest="numnodes", type=int, help="number of nodes"
)
parser.add_option(
"-p", "--linkprob", dest="linkprob", type=float, help="link probabilty"
)
parser.add_option(
"-d", "--delay", dest="delay", type=float, help="wait time before checking"
)
parser.add_option(
"-s",
"--seed",
dest="seed",
type=int,
help="specify integer to use for random seed",
)
parser.add_option(
"-v", "--verbose", dest="verbose", action="store_true", help="be more verbose"
)
parser.add_option(
"-l",
"--logfile",
dest="logfile",
type=str,
help="log detailed output to the specified file",
)
def usage(msg=None, err=0):
sys.stdout.write("\n")
@ -584,8 +618,10 @@ def main():
random.seed(options.seed)
me = ManetExperiment(options=options, start=datetime.datetime.now())
me.info("creating topology: numnodes = %s; linkprob = %s" % \
(options.numnodes, options.linkprob))
me.info(
"creating topology: numnodes = %s; linkprob = %s"
% (options.numnodes, options.linkprob)
)
me.topology(options.numnodes, options.linkprob)
me.info("waiting %s sec" % options.delay)

View file

@ -80,7 +80,7 @@ def getcputimes(line):
# assume columns are:
# cpu# user nice sys idle iowait irq softirq steal guest (man 5 proc)
items = line.split()
(user, nice, sys, idle) = map(lambda (x): int(x), items[1:5])
(user, nice, sys, idle) = map(lambda x: int(x), items[1:5])
return [user, nice, sys, idle]
@ -97,8 +97,10 @@ def calculatecpu(timesa, timesb):
# end move these to core.misc.utils
class Cmd(object):
""" Helper class for running a command on a node and parsing the result. """
args = ""
def __init__(self, node, verbose=False):
@ -149,6 +151,7 @@ class Cmd(object):
class ClientServerCmd(Cmd):
""" Helper class for running a command on a node and parsing the result. """
args = ""
client_args = ""
@ -171,8 +174,9 @@ class ClientServerCmd(Cmd):
def client_open(self):
""" Exceute call to client_node.popen(). """
self.client_id, self.client_stdin, self.client_out, self.client_err = \
self.client_node.client.popen(self.client_args)
self.client_id, self.client_stdin, self.client_out, self.client_err = self.client_node.client.popen(
self.client_args
)
def parse(self):
""" This method is overloaded by child classes and should return some
@ -195,7 +199,7 @@ class PingCmd(Cmd):
""" Test latency using ping.
"""
def __init__(self, node, verbose=False, addr=None, count=50, interval=0.1, ):
def __init__(self, node, verbose=False, addr=None, count=50, interval=0.1):
Cmd.__init__(self, node, verbose)
self.addr = addr
self.count = count
@ -205,14 +209,20 @@ class PingCmd(Cmd):
def run(self):
if self.verbose:
self.info("%s initial test ping (max 1 second)..." % self.node.name)
(status, result) = self.node.cmd_output(["ping", "-q", "-c", "1", "-w", "1", self.addr])
(status, result) = self.node.cmd_output(
["ping", "-q", "-c", "1", "-w", "1", self.addr]
)
if status != 0:
self.warn("initial ping from %s to %s failed! result:\n%s" %
(self.node.name, self.addr, result))
self.warn(
"initial ping from %s to %s failed! result:\n%s"
% (self.node.name, self.addr, result)
)
return 0.0, 0.0
if self.verbose:
self.info("%s pinging %s (%d seconds)..." %
(self.node.name, self.addr, self.count * self.interval))
self.info(
"%s pinging %s (%d seconds)..."
% (self.node.name, self.addr, self.count * self.interval)
)
return Cmd.run(self)
def parse(self):
@ -245,8 +255,10 @@ class IperfCmd(ClientServerCmd):
def run(self):
if self.verbose:
self.info("Launching the iperf server on %s..." % self.node.name)
self.info("Running the iperf client on %s (%s seconds)..." % \
(self.client_node.name, self.time))
self.info(
"Running the iperf client on %s (%s seconds)..."
% (self.client_node.name, self.time)
)
return ClientServerCmd.run(self)
def parse(self):
@ -263,19 +275,26 @@ class MgenCmd(ClientServerCmd):
""" Run a test traffic flow using an MGEN sender and receiver.
"""
def __init__(self, node, client_node, verbose=False, addr=None, time=10,
rate=512):
def __init__(self, node, client_node, verbose=False, addr=None, time=10, rate=512):
ClientServerCmd.__init__(self, node, client_node, verbose)
self.addr = addr
self.time = time
self.args = ["mgen", "event", "listen udp 5000", "output",
"/var/log/mgen.log"]
self.args = ["mgen", "event", "listen udp 5000", "output", "/var/log/mgen.log"]
self.rate = rate
sendevent = "ON 1 UDP DST %s/5000 PERIODIC [%s]" % \
(addr, self.mgenrate(self.rate))
sendevent = "ON 1 UDP DST %s/5000 PERIODIC [%s]" % (
addr,
self.mgenrate(self.rate),
)
stopevent = "%s OFF 1" % time
self.client_args = ["mgen", "event", sendevent, "event", stopevent,
"output", "/var/log/mgen.log"]
self.client_args = [
"mgen",
"event",
sendevent,
"event",
stopevent,
"output",
"/var/log/mgen.log",
]
@staticmethod
def mgenrate(kbps):
@ -291,8 +310,10 @@ class MgenCmd(ClientServerCmd):
def run(self):
if self.verbose:
self.info("Launching the MGEN receiver on %s..." % self.node.name)
self.info("Running the MGEN sender on %s (%s seconds)..." % \
(self.client_node.name, self.time))
self.info(
"Running the MGEN sender on %s (%s seconds)..."
% (self.client_node.name, self.time)
)
return ClientServerCmd.run(self)
def cleanup(self):
@ -328,8 +349,7 @@ class MgenCmd(ClientServerCmd):
else:
loss = 0
if self.verbose:
self.info("Receiver log shows %d of %d packets lost" % \
(numlost, lastseq))
self.info("Receiver log shows %d of %d packets lost" % (numlost, lastseq))
return loss
@ -381,8 +401,7 @@ class Experiment(object):
if not self.logfp:
return
end = datetime.datetime.now()
self.log("%s end: %s (%s)\n" % \
(sys.argv[0], end.ctime(), end - self.start))
self.log("%s end: %s (%s)\n" % (sys.argv[0], end.ctime(), end - self.start))
self.logfp.flush()
self.logfp.close()
self.logfp = None
@ -411,11 +430,15 @@ class Experiment(object):
prefix = ipaddress.Ipv4Prefix("10.0.0.0/16")
self.session = Session(1)
# emulated network
self.net = self.session.create_node(cls=core.nodes.network.WlanNode, name="wlan1")
self.net = self.session.create_node(
cls=core.nodes.network.WlanNode, name="wlan1"
)
prev = None
for i in range(1, numnodes + 1):
addr = "%s/%s" % (prefix.addr(i), 32)
tmp = self.session.create_node(cls=core.nodes.base.CoreNode, _id=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")
@ -438,12 +461,16 @@ 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.create_node(cls=EmaneNode, _id=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 range(1, numnodes + 1):
addr = "%s/%s" % (prefix.addr(i), 32)
tmp = self.session.create_node(cls=core.nodes.base.CoreNode, _id=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])
@ -518,8 +545,9 @@ class Experiment(object):
dev = "lo"
else:
dev = self.session.obj("ctrlnet").brname
service = EventService(eventchannel=("224.1.2.8", 45703, dev),
otachannel=None)
service = EventService(
eventchannel=("224.1.2.8", 45703, dev), otachannel=None
)
old = False
for i in range(1, numnodes + 1):
@ -529,9 +557,13 @@ class Experiment(object):
if txnem > 0:
if old:
e.set(0, txnem, 10.0, 10.0)
service.publish(emaneeventpathloss.EVENT_ID,
emaneeventservice.PLATFORMID_ANY, rxnem,
emaneeventservice.COMPONENTID_ANY, e.export())
service.publish(
emaneeventpathloss.EVENT_ID,
emaneeventservice.PLATFORMID_ANY,
rxnem,
emaneeventservice.COMPONENTID_ANY,
e.export(),
)
else:
e = PathlossEvent()
e.append(txnem, forward=10.0, reverse=10.0)
@ -542,9 +574,13 @@ class Experiment(object):
continue
if old:
e.set(0, txnem, 10.0, 10.0)
service.publish(emaneeventpathloss.EVENT_ID,
emaneeventservice.PLATFORMID_ANY, rxnem,
emaneeventservice.COMPONENTID_ANY, e.export())
service.publish(
emaneeventpathloss.EVENT_ID,
emaneeventservice.PLATFORMID_ANY,
rxnem,
emaneeventservice.COMPONENTID_ANY,
e.export(),
)
else:
e = PathlossEvent()
e.append(txnem, forward=10.0, reverse=10.0)
@ -567,12 +603,16 @@ class Experiment(object):
duration = self.opt.duration
rate = self.opt.rate
if len(title) > 0:
self.info("----- running %s tests (duration=%s, rate=%s) -----" % \
(title, duration, rate))
self.info(
"----- running %s tests (duration=%s, rate=%s) -----"
% (title, duration, rate)
)
(latency, mdev, throughput, cpu, loss) = (0, 0, 0, 0, 0)
self.info("number of runs: ping=%d, iperf=%d, mgen=%d" % \
(self.numping, self.numiperf, self.nummgen))
self.info(
"number of runs: ping=%d, iperf=%d, mgen=%d"
% (self.numping, self.numiperf, self.nummgen)
)
if self.numping > 0:
(latency, mdev) = self.pingtest(count=self.numping)
@ -595,8 +635,8 @@ class Experiment(object):
for i in range(1, self.nummgen + 1):
(cpu, loss) = self.cputest(time=duration, rate=rate)
if self.nummgen > 1:
cpus += cpu,
losses += loss,
cpus += (cpu,)
losses += (loss,)
if self.nummgen > 1:
cpu = sum(cpus) / len(cpus)
loss = sum(losses) / len(losses)
@ -608,8 +648,13 @@ class Experiment(object):
def pingtest(self, count=50):
""" Ping through a chain of nodes and report the average latency.
"""
p = PingCmd(node=self.firstnode, verbose=self.verbose,
addr=self.lastaddr, count=count, interval=0.1).run()
p = PingCmd(
node=self.firstnode,
verbose=self.verbose,
addr=self.lastaddr,
count=count,
interval=0.1,
).run()
(latency, mdev) = p
self.info("latency (ms): %.03f, %.03f" % (latency, mdev))
return p
@ -618,8 +663,13 @@ class Experiment(object):
""" Run iperf through a chain of nodes and report the maximum
throughput.
"""
bps = IperfCmd(node=self.lastnode, client_node=self.firstnode,
verbose=False, addr=self.lastaddr, time=time).run()
bps = IperfCmd(
node=self.lastnode,
client_node=self.firstnode,
verbose=False,
addr=self.lastaddr,
time=time,
).run()
self.info("throughput (bps): %s" % bps)
return bps
@ -628,19 +678,26 @@ class Experiment(object):
percent of lost packets. Rate is in kbps.
"""
if self.verbose:
self.info("%s initial test ping (max 1 second)..." % \
self.firstnode.name)
(status, result) = self.firstnode.cmd_output(["ping", "-q", "-c", "1",
"-w", "1", self.lastaddr])
self.info("%s initial test ping (max 1 second)..." % self.firstnode.name)
(status, result) = self.firstnode.cmd_output(
["ping", "-q", "-c", "1", "-w", "1", self.lastaddr]
)
if status != 0:
self.warn("initial ping from %s to %s failed! result:\n%s" % \
(self.firstnode.name, self.lastaddr, result))
self.warn(
"initial ping from %s to %s failed! result:\n%s"
% (self.firstnode.name, self.lastaddr, result)
)
return 0.0, 0.0
lines = readstat()
cpustart = getcputimes(lines[0])
loss = MgenCmd(node=self.lastnode, client_node=self.firstnode,
verbose=False, addr=self.lastaddr,
time=time, rate=rate).run()
loss = MgenCmd(
node=self.lastnode,
client_node=self.firstnode,
verbose=False,
addr=self.lastaddr,
time=time,
rate=rate,
).run()
lines = readstat()
cpuend = getcputimes(lines[0])
percent = calculatecpu(cpustart, cpuend)
@ -653,28 +710,59 @@ def main():
"""
usagestr = "usage: %prog [-h] [options] [args]"
parser = optparse.OptionParser(usage=usagestr)
parser.set_defaults(numnodes=10, delay=3, duration=10, rate=512,
verbose=False,
numping=50, numiperf=1, nummgen=1)
parser.set_defaults(
numnodes=10,
delay=3,
duration=10,
rate=512,
verbose=False,
numping=50,
numiperf=1,
nummgen=1,
)
parser.add_option("-d", "--delay", dest="delay", type=float,
help="wait time before testing")
parser.add_option("-l", "--logfile", dest="logfile", type=str,
help="log detailed output to the specified file")
parser.add_option("-n", "--numnodes", dest="numnodes", type=int,
help="number of nodes")
parser.add_option("-r", "--rate", dest="rate", type=float,
help="kbps rate to use for MGEN CPU tests")
parser.add_option("--numping", dest="numping", type=int,
help="number of ping latency test runs")
parser.add_option("--numiperf", dest="numiperf", type=int,
help="number of iperf throughput test runs")
parser.add_option("--nummgen", dest="nummgen", type=int,
help="number of MGEN CPU tests runs")
parser.add_option("-t", "--time", dest="duration", type=int,
help="duration in seconds of throughput and CPU tests")
parser.add_option("-v", "--verbose", dest="verbose",
action="store_true", help="be more verbose")
parser.add_option(
"-d", "--delay", dest="delay", type=float, help="wait time before testing"
)
parser.add_option(
"-l",
"--logfile",
dest="logfile",
type=str,
help="log detailed output to the specified file",
)
parser.add_option(
"-n", "--numnodes", dest="numnodes", type=int, help="number of nodes"
)
parser.add_option(
"-r",
"--rate",
dest="rate",
type=float,
help="kbps rate to use for MGEN CPU tests",
)
parser.add_option(
"--numping", dest="numping", type=int, help="number of ping latency test runs"
)
parser.add_option(
"--numiperf",
dest="numiperf",
type=int,
help="number of iperf throughput test runs",
)
parser.add_option(
"--nummgen", dest="nummgen", type=int, help="number of MGEN CPU tests runs"
)
parser.add_option(
"-t",
"--time",
dest="duration",
type=int,
help="duration in seconds of throughput and CPU tests",
)
parser.add_option(
"-v", "--verbose", dest="verbose", action="store_true", help="be more verbose"
)
def usage(msg=None, err=0):
sys.stdout.write("\n")
@ -735,7 +823,12 @@ def main():
# EMANE bypass model
exp.info("setting up EMANE tests 1/2 with bypass model")
exp.createemanesession(numnodes=opt.numnodes, verbose=opt.verbose, cls=EmaneBypassModel, values=None)
exp.createemanesession(
numnodes=opt.numnodes,
verbose=opt.verbose,
cls=EmaneBypassModel,
values=None,
)
exp.setnodes()
exp.info("waiting %s sec (node/route bring-up)" % opt.delay)
time.sleep(opt.delay)
@ -757,7 +850,12 @@ def main():
rfpipevals[rfpnames.index("defaultconnectivitymode")] = "1"
else:
rfpipevals[rfpnames.index("propagationmodel")] = "2ray"
exp.createemanesession(numnodes=opt.numnodes, verbose=opt.verbose, cls=EmaneRfPipeModel, values=rfpipevals)
exp.createemanesession(
numnodes=opt.numnodes,
verbose=opt.verbose,
cls=EmaneRfPipeModel,
values=rfpipevals,
)
exp.setnodes()
exp.info("waiting %s sec (node/route bring-up)" % opt.delay)
time.sleep(opt.delay)
@ -777,8 +875,12 @@ def main():
rfpipevals[rfpnames.index("defaultconnectivitymode")] = "1"
else:
rfpipevals[rfpnames.index("propagationmodel")] = "2ray"
exp.createemanesession(numnodes=opt.numnodes, verbose=opt.verbose,
cls=EmaneRfPipeModel, values=rfpipevals)
exp.createemanesession(
numnodes=opt.numnodes,
verbose=opt.verbose,
cls=EmaneRfPipeModel,
values=rfpipevals,
)
exp.setnodes()
exp.info("waiting %s sec (node/route bring-up)" % opt.delay)
time.sleep(opt.delay)
@ -796,8 +898,12 @@ def main():
rfpipevals[rfpnames.index("defaultconnectivitymode")] = "0"
else:
rfpipevals[rfpnames.index("propagationmodel")] = "precomputed"
exp.createemanesession(numnodes=opt.numnodes, verbose=opt.verbose,
cls=EmaneRfPipeModel, values=rfpipevals)
exp.createemanesession(
numnodes=opt.numnodes,
verbose=opt.verbose,
cls=EmaneRfPipeModel,
values=rfpipevals,
)
exp.setnodes()
exp.info("waiting %s sec (node/route bring-up)" % opt.delay)
time.sleep(opt.delay)
@ -815,8 +921,12 @@ def main():
rfpipevals[rfpnames.index("delay")] = "200"
rfpipevals[rfpnames.index("pathlossmode")] = "pathloss"
rfpipevals[rfpnames.index("defaultconnectivitymode")] = "0"
exp.createemanesession(numnodes=opt.numnodes, verbose=opt.verbose,
cls=EmaneRfPipeModel, values=rfpipevals)
exp.createemanesession(
numnodes=opt.numnodes,
verbose=opt.verbose,
cls=EmaneRfPipeModel,
values=rfpipevals,
)
exp.setnodes()
exp.info("waiting %s sec (node/route bring-up)" % opt.delay)
time.sleep(opt.delay)
@ -827,14 +937,18 @@ def main():
exp.reset()
# summary of results in CSV format
exp.info("----- summary of results (%s nodes, rate=%s, duration=%s) -----" \
% (opt.numnodes, opt.rate, opt.duration))
exp.info(
"----- summary of results (%s nodes, rate=%s, duration=%s) -----"
% (opt.numnodes, opt.rate, opt.duration)
)
exp.info("netname:latency,mdev,throughput,cpu,loss")
for test in sorted(results.keys()):
(latency, mdev, throughput, cpu, loss) = results[test]
exp.info("%s:%.03f,%.03f,%d,%.02f,%.02f" % \
(test, latency, mdev, throughput, cpu, loss))
exp.info(
"%s:%.03f,%.03f,%d,%.02f,%.02f"
% (test, latency, mdev, throughput, cpu, loss)
)
exp.logend()
return exp

View file

@ -14,12 +14,13 @@ from core.emulator.enumerations import CORE_API_PORT, MessageFlags, SessionTlvs
def main():
parser = optparse.OptionParser(usage="usage: %prog [-l] <sessionid>")
parser.add_option("-l", "--list", dest="list", action="store_true",
help="list running sessions")
parser.add_option(
"-l", "--list", dest="list", action="store_true", help="list running sessions"
)
(options, args) = parser.parse_args()
if options.list is True:
num = '0'
num = "0"
flags = MessageFlags.STRING.value
else:
num = args[0]
@ -28,7 +29,7 @@ def main():
message = coreapi.CoreSessionMessage.pack(flags, tlvdata)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('localhost', CORE_API_PORT))
sock.connect(("localhost", CORE_API_PORT))
sock.send(message)
# receive and print a session list

View file

@ -2,9 +2,16 @@
test=pytest
[isort]
skip_glob=*_pb2*.py
skip_glob=*_pb2*.py,utm.py,doc,build
multi_line_output=3
include_trailing_comma=True
force_grid_wrap=0
use_parentheses=True
line_length=100
[flake8]
ignore=E501
max-line-length=100
max-complexity=18
select=B,C,E,F,W,T4
exclude=*_pb2*.py,utm.py,doc,build

View file

@ -3,10 +3,6 @@ import sys
import pytest
distributed = sys.argv[1]
pytest.main([
"-v",
"--distributed", distributed,
"--cov-report", "xml",
"--cov=.",
"tests"
])
pytest.main(
["-v", "--distributed", distributed, "--cov-report", "xml", "--cov=.", "tests"]
)

View file

@ -27,10 +27,9 @@ class CoreServerTest(object):
self.host = "localhost"
self.port = port
address = (self.host, self.port)
self.server = CoreServer(address, CoreHandler, {
"numthreads": 1,
"daemonize": False,
})
self.server = CoreServer(
address, CoreHandler, {"numthreads": 1, "daemonize": False}
)
self.distributed_server = "core2"
self.prefix = ipaddress.Ipv4Prefix("10.83.0.0/16")
@ -62,36 +61,51 @@ class CoreServerTest(object):
# have broker handle a configuration state change
self.session.set_state(EventTypes.DEFINITION_STATE)
message = CoreEventMessage.create(0, [(EventTlvs.TYPE, EventTypes.CONFIGURATION_STATE.value)])
message = CoreEventMessage.create(
0, [(EventTlvs.TYPE, EventTypes.CONFIGURATION_STATE.value)]
)
self.request_handler.handle_message(message)
# add broker server for distributed core
distributed = "%s:%s:%s" % (self.distributed_server, distributed_address, self.port)
message = CoreConfMessage.create(0, [
(ConfigTlvs.OBJECT, "broker"),
(ConfigTlvs.TYPE, 0),
(ConfigTlvs.DATA_TYPES, (10,)),
(ConfigTlvs.VALUES, distributed)
])
distributed = "%s:%s:%s" % (
self.distributed_server,
distributed_address,
self.port,
)
message = CoreConfMessage.create(
0,
[
(ConfigTlvs.OBJECT, "broker"),
(ConfigTlvs.TYPE, 0),
(ConfigTlvs.DATA_TYPES, (10,)),
(ConfigTlvs.VALUES, distributed),
],
)
self.request_handler.handle_message(message)
# set session location
message = CoreConfMessage.create(0, [
(ConfigTlvs.OBJECT, "location"),
(ConfigTlvs.TYPE, 0),
(ConfigTlvs.DATA_TYPES, (9, 9, 9, 9, 9, 9)),
(ConfigTlvs.VALUES, "0|0| 47.5766974863|-122.125920191|0.0|150.0")
])
message = CoreConfMessage.create(
0,
[
(ConfigTlvs.OBJECT, "location"),
(ConfigTlvs.TYPE, 0),
(ConfigTlvs.DATA_TYPES, (9, 9, 9, 9, 9, 9)),
(ConfigTlvs.VALUES, "0|0| 47.5766974863|-122.125920191|0.0|150.0"),
],
)
self.request_handler.handle_message(message)
# set services for host nodes
message = CoreConfMessage.create(0, [
(ConfigTlvs.SESSION, str(self.session.id)),
(ConfigTlvs.OBJECT, "services"),
(ConfigTlvs.TYPE, 0),
(ConfigTlvs.DATA_TYPES, (10, 10, 10)),
(ConfigTlvs.VALUES, "host|DefaultRoute|SSH")
])
message = CoreConfMessage.create(
0,
[
(ConfigTlvs.SESSION, str(self.session.id)),
(ConfigTlvs.OBJECT, "services"),
(ConfigTlvs.TYPE, 0),
(ConfigTlvs.DATA_TYPES, (10, 10, 10)),
(ConfigTlvs.VALUES, "host|DefaultRoute|SSH"),
],
)
self.request_handler.handle_message(message)
def shutdown(self):

View file

@ -25,14 +25,19 @@ from core.nodes.ipaddress import IpAddress, Ipv4Prefix, MacAddress
def set_emane_model(node_id, model):
return CoreConfMessage.create(0, [
(ConfigTlvs.NODE, node_id),
(ConfigTlvs.OBJECT, model),
(ConfigTlvs.TYPE, ConfigFlags.UPDATE.value),
])
return CoreConfMessage.create(
0,
[
(ConfigTlvs.NODE, node_id),
(ConfigTlvs.OBJECT, model),
(ConfigTlvs.TYPE, ConfigFlags.UPDATE.value),
],
)
def node_message(_id, 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.
@ -59,7 +64,16 @@ def node_message(_id, name, emulation_server=None, node_type=NodeTypes.DEFAULT,
return CoreNodeMessage.create(MessageFlags.ADD.value, values)
def link_message(n1, n2, intf_one=None, address_one=None, intf_two=None, address_two=None, key=None, mask=24):
def link_message(
n1,
n2,
intf_one=None,
address_one=None,
intf_two=None,
address_two=None,
key=None,
mask=24,
):
"""
Convenience method for creating link TLV messages.
@ -115,11 +129,14 @@ def command_message(node, command):
:rtype: core.api.tlv.coreapi.CoreExecMessage
"""
flags = MessageFlags.STRING.value | MessageFlags.TEXT.value
return CoreExecMessage.create(flags, [
(ExecuteTlvs.NODE, node.id),
(ExecuteTlvs.NUMBER, 1),
(ExecuteTlvs.COMMAND, command)
])
return CoreExecMessage.create(
flags,
[
(ExecuteTlvs.NODE, node.id),
(ExecuteTlvs.NUMBER, 1),
(ExecuteTlvs.COMMAND, command),
],
)
def state_message(state):
@ -130,9 +147,7 @@ def state_message(state):
:return: tlv message
:rtype: core.api.tlv.coreapi.CoreEventMessage
"""
return CoreEventMessage.create(0, [
(EventTlvs.TYPE, state.value)
])
return CoreEventMessage.create(0, [(EventTlvs.TYPE, state.value)])
def validate_response(replies, _):
@ -144,8 +159,8 @@ def validate_response(replies, _):
:return: nothing
"""
response = replies[0]
header = response[:CoreExecMessage.header_len]
tlv_data = response[CoreExecMessage.header_len:]
header = response[: CoreExecMessage.header_len]
tlv_data = response[CoreExecMessage.header_len :]
response = CoreExecMessage(MessageFlags.TEXT, header, tlv_data)
assert not response.get_tlv(ExecuteTlvs.STATUS.value)
@ -162,48 +177,27 @@ class TestDistributed:
cored.setup(distributed_address)
# create local node
message = node_message(
_id=1,
name="n1",
model="host"
)
message = node_message(_id=1, name="n1", model="host")
cored.request_handler.handle_message(message)
# create distributed node and assign to distributed server
message = node_message(
_id=2,
name="n2",
emulation_server=cored.distributed_server,
model="host"
_id=2, name="n2", emulation_server=cored.distributed_server, model="host"
)
cored.request_handler.handle_message(message)
# create distributed switch and assign to distributed server
message = node_message(
_id=3,
name="n3",
node_type=NodeTypes.SWITCH
)
message = node_message(_id=3, name="n3", node_type=NodeTypes.SWITCH)
cored.request_handler.handle_message(message)
# link message one
ip4_address = cored.prefix.addr(1)
message = link_message(
n1=1,
n2=3,
intf_one=0,
address_one=ip4_address
)
message = link_message(n1=1, n2=3, intf_one=0, address_one=ip4_address)
cored.request_handler.handle_message(message)
# link message two
ip4_address = cored.prefix.addr(2)
message = link_message(
n1=3,
n2=2,
intf_two=0,
address_two=ip4_address
)
message = link_message(n1=3, n2=2, intf_two=0, address_two=ip4_address)
cored.request_handler.handle_message(message)
# change session to instantiation state
@ -227,31 +221,22 @@ class TestDistributed:
cored.setup(distributed_address)
# configure required controlnet
cored.session.options.set_config("controlnet", "core1:172.16.1.0/24 core2:172.16.2.0/24")
cored.session.options.set_config(
"controlnet", "core1:172.16.1.0/24 core2:172.16.2.0/24"
)
# create local node
message = node_message(
_id=1,
name="n1",
model="mdr"
)
message = node_message(_id=1, name="n1", model="mdr")
cored.request_handler.handle_message(message)
# create distributed node and assign to distributed server
message = node_message(
_id=2,
name="n2",
emulation_server=cored.distributed_server,
model="mdr"
_id=2, name="n2", emulation_server=cored.distributed_server, model="mdr"
)
cored.request_handler.handle_message(message)
# create distributed switch and assign to distributed server
message = node_message(
_id=3,
name="n3",
node_type=NodeTypes.EMANE
)
message = node_message(_id=3, name="n3", node_type=NodeTypes.EMANE)
cored.request_handler.handle_message(message)
# set emane model
@ -260,24 +245,12 @@ class TestDistributed:
# link message one
ip4_address = cored.prefix.addr(1)
message = link_message(
n1=1,
n2=3,
intf_one=0,
address_one=ip4_address,
mask=32
)
message = link_message(n1=1, n2=3, intf_one=0, address_one=ip4_address, mask=32)
cored.request_handler.handle_message(message)
# link message two
ip4_address = cored.prefix.addr(2)
message = link_message(
n1=2,
n2=3,
intf_one=0,
address_one=ip4_address,
mask=32
)
message = link_message(n1=2, n2=3, intf_one=0, address_one=ip4_address, mask=32)
cored.request_handler.handle_message(message)
# change session to instantiation state
@ -301,11 +274,7 @@ class TestDistributed:
cored.setup(distributed_address)
# create local node
message = node_message(
_id=1,
name="n1",
model="host"
)
message = node_message(_id=1, name="n1", model="host")
cored.request_handler.handle_message(message)
# create distributed node and assign to distributed server
@ -314,36 +283,22 @@ class TestDistributed:
name="n2",
emulation_server=cored.distributed_server,
node_type=NodeTypes.PHYSICAL,
model="prouter"
model="prouter",
)
cored.request_handler.handle_message(message)
# create distributed switch and assign to distributed server
message = node_message(
_id=3,
name="n3",
node_type=NodeTypes.SWITCH
)
message = node_message(_id=3, name="n3", node_type=NodeTypes.SWITCH)
cored.request_handler.handle_message(message)
# link message one
ip4_address = cored.prefix.addr(1)
message = link_message(
n1=1,
n2=3,
intf_one=0,
address_one=ip4_address
)
message = link_message(n1=1, n2=3, intf_one=0, address_one=ip4_address)
cored.request_handler.handle_message(message)
# link message two
ip4_address = cored.prefix.addr(2)
message = link_message(
n1=3,
n2=2,
intf_two=0,
address_two=ip4_address
)
message = link_message(n1=3, n2=2, intf_two=0, address_two=ip4_address)
cored.request_handler.handle_message(message)
# change session to instantiation state
@ -368,11 +323,7 @@ class TestDistributed:
cored.setup(distributed_address)
# create local node
message = node_message(
_id=1,
name="n1",
model="host"
)
message = node_message(_id=1, name="n1", model="host")
cored.request_handler.handle_message(message)
# create distributed node and assign to distributed server
@ -380,7 +331,7 @@ class TestDistributed:
_id=2,
name=distributed_address,
emulation_server=cored.distributed_server,
node_type=NodeTypes.TUNNEL
node_type=NodeTypes.TUNNEL,
)
cored.request_handler.handle_message(message)
@ -394,7 +345,7 @@ class TestDistributed:
address_one=ip4_address,
intf_two=0,
address_two=address_two,
key=1
key=1,
)
cored.request_handler.handle_message(message)

View file

@ -1,5 +1,10 @@
import pytest
from core.config import ConfigurableManager, ConfigurableOptions, Configuration, ModelManager
from core.config import (
ConfigurableManager,
ConfigurableOptions,
Configuration,
ModelManager,
)
from core.emane.ieee80211abg import EmaneIeee80211abgModel
from core.emulator.enumerations import ConfigDataTypes, NodeTypes
from core.location.mobility import BasicRangeModel
@ -9,16 +14,8 @@ class TestConfigurableOptions(ConfigurableOptions):
name_one = "value1"
name_two = "value2"
options = [
Configuration(
_id=name_one,
_type=ConfigDataTypes.STRING,
label=name_one
),
Configuration(
_id=name_two,
_type=ConfigDataTypes.STRING,
label=name_two
)
Configuration(_id=name_one, _type=ConfigDataTypes.STRING, label=name_one),
Configuration(_id=name_two, _type=ConfigDataTypes.STRING, label=name_two),
]

View file

@ -15,11 +15,7 @@ from core.nodes.client import VnodeClient
_PATH = os.path.abspath(os.path.dirname(__file__))
_MOBILITY_FILE = os.path.join(_PATH, "mobility.scen")
_WIRED = [
NodeTypes.PEER_TO_PEER,
NodeTypes.HUB,
NodeTypes.SWITCH
]
_WIRED = [NodeTypes.PEER_TO_PEER, NodeTypes.HUB, NodeTypes.SWITCH]
def createclients(sessiondir, clientcls=VnodeClient, cmdchnlfilterfunc=None):
@ -112,7 +108,9 @@ class TestCore:
p, stdin, stdout, stderr = client.popen(command)
assert not p.wait()
assert not client.icmd(command)
assert not client.redircmd(subprocess.PIPE, subprocess.PIPE, subprocess.PIPE, command)
assert not client.redircmd(
subprocess.PIPE, subprocess.PIPE, subprocess.PIPE, command
)
assert not client.shcmd(command[0])
# check various command using command line

View file

@ -35,16 +35,17 @@ class TestEmane:
# create emane node for networking the core nodes
emane_network = session.create_emane_network(
model,
geo_reference=(47.57917, -122.13232, 2.00000)
model, geo_reference=(47.57917, -122.13232, 2.00000)
)
emane_network.setposition(x=80, y=50)
# configure tdma
if model == EmaneTdmaModel:
session.emane.set_model_config(emane_network.id, EmaneTdmaModel.name, {
"schedule": os.path.join(_DIR, "../examples/tdma/schedule.xml")
})
session.emane.set_model_config(
emane_network.id,
EmaneTdmaModel.name,
{"schedule": os.path.join(_DIR, "../examples/tdma/schedule.xml")},
)
# create nodes
node_options = NodeOptions()

View file

@ -11,7 +11,12 @@ 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.emulator.enumerations import ConfigFlags, EventTypes, ExceptionLevels, NodeTypes
from core.emulator.enumerations import (
ConfigFlags,
EventTypes,
ExceptionLevels,
NodeTypes,
)
from core.location.mobility import BasicRangeModel, Ns2ScriptedMobility
@ -35,10 +40,7 @@ class TestGrpc:
assert response.session_id == session_id
assert session.id == session_id
@pytest.mark.parametrize("session_id, expected", [
(None, True),
(6013, False)
])
@pytest.mark.parametrize("session_id, expected", [(None, True), (6013, False)])
def test_delete_session(self, grpc_server, session_id, expected):
# given
client = CoreGrpcClient()
@ -130,9 +132,13 @@ class TestGrpc:
with client.context_connect():
response = client.set_session_location(
session.id,
x=xyz[0], y=xyz[1], z=xyz[2],
lat=lat_lon_alt[0], lon=lat_lon_alt[1], alt=lat_lon_alt[2],
scale=scale
x=xyz[0],
y=xyz[1],
z=xyz[2],
lat=lat_lon_alt[0],
lon=lat_lon_alt[1],
alt=lat_lon_alt[2],
scale=scale,
)
# then
@ -165,7 +171,9 @@ class TestGrpc:
# then
with client.context_connect():
response = client.set_session_state(session.id, core_pb2.SessionState.DEFINITION)
response = client.set_session_state(
session.id, core_pb2.SessionState.DEFINITION
)
# then
assert response.result is True
@ -198,10 +206,7 @@ class TestGrpc:
# then
assert response.node.id == node.id
@pytest.mark.parametrize("node_id, expected", [
(1, True),
(2, False)
])
@pytest.mark.parametrize("node_id, expected", [(1, True), (2, False)])
def test_edit_node(self, grpc_server, node_id, expected):
# given
client = CoreGrpcClient()
@ -220,10 +225,7 @@ class TestGrpc:
assert node.position.x == x
assert node.position.y == y
@pytest.mark.parametrize("node_id, expected", [
(1, True),
(2, False)
])
@pytest.mark.parametrize("node_id, expected", [(1, True), (2, False)])
def test_delete_node(self, grpc_server, node_id, expected):
# given
client = CoreGrpcClient()
@ -302,7 +304,9 @@ class TestGrpc:
file_name = "test"
file_data = "echo hello"
with client.context_connect():
response = client.add_hook(session.id, core_pb2.SessionState.RUNTIME, file_name, file_data)
response = client.add_hook(
session.id, core_pb2.SessionState.RUNTIME, file_name, file_data
)
# then
assert response.result is True
@ -408,7 +412,9 @@ class TestGrpc:
# then
with client.context_connect():
response = client.edit_link(session.id, node.id, switch.id, options, interface_one_id=interface.id)
response = client.edit_link(
session.id, node.id, switch.id, options, interface_one_id=interface.id
)
# then
assert response.result is True
@ -435,7 +441,8 @@ class TestGrpc:
# then
with client.context_connect():
response = client.delete_link(
session.id, node_one.id, node_two.id, 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
@ -467,14 +474,18 @@ class TestGrpc:
# then
with client.context_connect():
response = client.set_wlan_config(session.id, wlan.id, {
range_key: range_value,
"delay": "0",
"loss": "0",
"bandwidth": "50000",
"error": "0",
"jitter": "0"
})
response = client.set_wlan_config(
session.id,
wlan.id,
{
range_key: range_value,
"delay": "0",
"loss": "0",
"bandwidth": "50000",
"error": "0",
"jitter": "0",
},
)
# then
assert response.result is True
@ -516,12 +527,13 @@ class TestGrpc:
client = CoreGrpcClient()
session = grpc_server.coreemu.create_session()
emane_network = session.create_emane_network(
model=EmaneIeee80211abgModel,
geo_reference=(47.57917, -122.13232, 2.00000)
model=EmaneIeee80211abgModel, geo_reference=(47.57917, -122.13232, 2.00000)
)
config_key = "platform_id_start"
config_value = "2"
session.emane.set_model_config(emane_network.id, 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():
@ -536,8 +548,7 @@ class TestGrpc:
client = CoreGrpcClient()
session = grpc_server.coreemu.create_session()
emane_network = session.create_emane_network(
model=EmaneIeee80211abgModel,
geo_reference=(47.57917, -122.13232, 2.00000)
model=EmaneIeee80211abgModel, geo_reference=(47.57917, -122.13232, 2.00000)
)
config_key = "bandwidth"
config_value = "900000"
@ -545,11 +556,17 @@ class TestGrpc:
# then
with client.context_connect():
response = client.set_emane_model_config(
session.id, emane_network.id, 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.id, 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):
@ -557,14 +574,14 @@ class TestGrpc:
client = CoreGrpcClient()
session = grpc_server.coreemu.create_session()
emane_network = session.create_emane_network(
model=EmaneIeee80211abgModel,
geo_reference=(47.57917, -122.13232, 2.00000)
model=EmaneIeee80211abgModel, geo_reference=(47.57917, -122.13232, 2.00000)
)
# then
with client.context_connect():
response = client.get_emane_model_config(
session.id, emane_network.id, EmaneIeee80211abgModel.name)
session.id, emane_network.id, EmaneIeee80211abgModel.name
)
# then
assert len(response.groups) > 0
@ -620,7 +637,9 @@ class TestGrpc:
# then
with client.context_connect():
response = client.set_mobility_config(session.id, wlan.id, {config_key: config_value})
response = client.set_mobility_config(
session.id, wlan.id, {config_key: config_value}
)
# then
assert response.result is True
@ -637,7 +656,9 @@ class TestGrpc:
# then
with client.context_connect():
response = client.mobility_action(session.id, wlan.id, core_pb2.MobilityAction.STOP)
response = client.mobility_action(
session.id, wlan.id, core_pb2.MobilityAction.STOP
)
# then
assert response.result is True
@ -701,7 +722,9 @@ class TestGrpc:
# then
with client.context_connect():
response = client.get_node_service_file(session.id, node.id, "DefaultRoute", "defaultroute.sh")
response = client.get_node_service_file(
session.id, node.id, "DefaultRoute", "defaultroute.sh"
)
# then
assert response.data is not None
@ -716,11 +739,15 @@ class TestGrpc:
# then
with client.context_connect():
response = client.set_node_service(session.id, node.id, 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.id, 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):
@ -734,7 +761,9 @@ class TestGrpc:
# then
with client.context_connect():
response = client.set_node_service_file(session.id, node.id, 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
@ -750,7 +779,9 @@ class TestGrpc:
# then
with client.context_connect():
response = client.service_action(session.id, node.id, 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
@ -831,7 +862,9 @@ class TestGrpc:
with client.context_connect():
client.events(session.id, handle_event)
time.sleep(0.1)
event = EventData(event_type=EventTypes.RUNTIME_STATE.value, time="%s" % time.time())
event = EventData(
event_type=EventTypes.RUNTIME_STATE.value, time="%s" % time.time()
)
session.broadcast_event(event)
# then
@ -852,7 +885,9 @@ class TestGrpc:
client.events(session.id, handle_event)
time.sleep(0.1)
session_config = session.options.get_configs()
config_data = ConfigShim.config_data(0, None, ConfigFlags.UPDATE.value, session.options, session_config)
config_data = ConfigShim.config_data(
0, None, ConfigFlags.UPDATE.value, session.options, session_config
)
session.broadcast_config(config_data)
# then
@ -892,7 +927,9 @@ class TestGrpc:
with client.context_connect():
client.events(session.id, handle_event)
time.sleep(0.1)
file_data = session.services.get_service_file(node, "DefaultRoute", "defaultroute.sh")
file_data = session.services.get_service_file(
node, "DefaultRoute", "defaultroute.sh"
)
session.broadcast_file(file_data)
# then

File diff suppressed because it is too large Load diff

View file

@ -105,8 +105,12 @@ class TestLinks:
link_options.bandwidth = 5000000
link_options.per = 25
link_options.dup = 25
session.update_link(node_one.id, node_two.id,
interface_one_id=interface_one.id, link_options=link_options)
session.update_link(
node_one.id,
node_two.id,
interface_one_id=interface_one.id,
link_options=link_options,
)
# then
output = utils.check_cmd(["tc", "qdisc", "show", "dev", interface.localname])
@ -126,7 +130,9 @@ class TestLinks:
assert node_two.netif(interface_two.id)
# when
session.delete_link(node_one.id, node_two.id, 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)
@ -149,7 +155,7 @@ class TestLinks:
# run iperf, validate normal bandwidth
stdout = iperf(node_one, node_two, ip_prefixes)
assert stdout
value = int(stdout.split(',')[bandwidth_index])
value = int(stdout.split(",")[bandwidth_index])
assert 900000 <= value <= 1100000
# change bandwidth in bits per second
@ -160,7 +166,7 @@ class TestLinks:
# run iperf again
stdout = iperf(node_one, node_two, ip_prefixes)
assert stdout
value = int(stdout.split(',')[bandwidth_index])
value = int(stdout.split(",")[bandwidth_index])
assert 400000 <= value <= 600000
def test_link_loss(self, session, ip_prefixes):
@ -180,7 +186,7 @@ class TestLinks:
# run iperf, validate normal bandwidth
stdout = iperf(node_one, node_two, ip_prefixes)
assert stdout
value = float(stdout.split(',')[loss_index])
value = float(stdout.split(",")[loss_index])
assert 0 <= value <= 0.5
# change bandwidth in bits per second
@ -191,7 +197,7 @@ class TestLinks:
# run iperf again
stdout = iperf(node_one, node_two, ip_prefixes)
assert stdout
value = float(stdout.split(',')[loss_index])
value = float(stdout.split(",")[loss_index])
assert 40 <= value <= 60
def test_link_delay(self, session, ip_prefixes):

View file

@ -6,18 +6,9 @@ from core import utils
from core.emulator.emudata import NodeOptions
from core.emulator.enumerations import NodeTypes
MODELS = [
"router",
"host",
"PC",
"mdr",
]
MODELS = ["router", "host", "PC", "mdr"]
NET_TYPES = [
NodeTypes.SWITCH,
NodeTypes.HUB,
NodeTypes.WIRELESS_LAN
]
NET_TYPES = [NodeTypes.SWITCH, NodeTypes.HUB, NodeTypes.WIRELESS_LAN]
class TestNodes:

View file

@ -202,8 +202,12 @@ class TestServices:
file_name = my_service.configs[0]
file_data_one = "# custom file one"
file_data_two = "# custom file two"
session.services.set_service_file(node_one.id, my_service.name, file_name, file_data_one)
session.services.set_service_file(node_two.id, my_service.name, file_name, file_data_two)
session.services.set_service_file(
node_one.id, my_service.name, file_name, file_data_one
)
session.services.set_service_file(
node_two.id, my_service.name, file_name, file_data_two
)
# when
custom_service_one = session.services.get_service(node_one.id, my_service.name)
@ -238,9 +242,13 @@ class TestServices:
# when
no_service = session.services.get_service(node.id, SERVICE_ONE)
default_service = session.services.get_service(node.id, SERVICE_ONE, default_service=True)
default_service = session.services.get_service(
node.id, SERVICE_ONE, default_service=True
)
session.services.set_service(node.id, SERVICE_ONE)
custom_service = session.services.get_service(node.id, SERVICE_ONE, default_service=True)
custom_service = session.services.get_service(
node.id, SERVICE_ONE, default_service=True
)
# then
assert no_service is None
@ -249,13 +257,7 @@ class TestServices:
def test_services_dependencies(self):
# given
services = [
ServiceA,
ServiceB,
ServiceC,
ServiceD,
ServiceF
]
services = [ServiceA, ServiceB, ServiceC, ServiceD, ServiceF]
# when
boot_paths = ServiceDependencies(services).boot_paths()
@ -271,7 +273,7 @@ class TestServices:
ServiceC,
ServiceD,
ServiceF,
ServiceBadDependency
ServiceBadDependency,
]
# when, then
@ -282,13 +284,7 @@ class TestServices:
# given
service_d = ServiceD()
service_d.dependencies = ("C",)
services = [
ServiceA,
ServiceB,
ServiceC,
service_d,
ServiceF
]
services = [ServiceA, ServiceB, ServiceC, service_d, ServiceF]
# when, then
with pytest.raises(ValueError):

View file

@ -120,7 +120,9 @@ class TestXml:
session.services.set_service(node_one.id, SshService.name)
service_file = SshService.configs[0]
file_data = "# test"
session.services.set_service_file(node_one.id, SshService.name, service_file, file_data)
session.services.set_service_file(
node_one.id, SshService.name, service_file, file_data
)
# instantiate session
session.instantiate()
@ -231,7 +233,7 @@ class TestXml:
emane_network = session.create_emane_network(
EmaneIeee80211abgModel,
geo_reference=(47.57917, -122.13232, 2.00000),
config={"test": "1"}
config={"test": "1"},
)
emane_network.setposition(x=80, y=50)
@ -277,7 +279,9 @@ class TestXml:
session.open_xml(file_path, start=True)
# retrieve configuration we set originally
value = str(session.emane.get_config("test", emane_id, EmaneIeee80211abgModel.name))
value = str(
session.emane.get_config("test", emane_id, EmaneIeee80211abgModel.name)
)
# verify nodes and configuration were restored
assert session.get_node(n1_id)
@ -354,7 +358,9 @@ class TestXml:
link_options.jitter = 10
link_options.delay = 30
link_options.dup = 5
session.add_link(node_one.id, switch.id, interface_one, link_options=link_options)
session.add_link(
node_one.id, switch.id, interface_one, link_options=link_options
)
# instantiate session
session.instantiate()
@ -419,7 +425,9 @@ class TestXml:
link_options.jitter = 10
link_options.delay = 30
link_options.dup = 5
session.add_link(node_one.id, node_two.id, interface_one, interface_two, link_options)
session.add_link(
node_one.id, node_two.id, interface_one, interface_two, link_options
)
# instantiate session
session.instantiate()
@ -485,7 +493,9 @@ class TestXml:
link_options_one.per = 10.5
link_options_one.dup = 5
link_options_one.jitter = 5
session.add_link(node_one.id, node_two.id, interface_one, interface_two, link_options_one)
session.add_link(
node_one.id, node_two.id, interface_one, interface_two, link_options_one
)
link_options_two = LinkOptions()
link_options_two.unidirectional = 1
link_options_two.bandwidth = 10000
@ -493,7 +503,13 @@ class TestXml:
link_options_two.per = 10
link_options_two.dup = 10
link_options_two.jitter = 10
session.update_link(node_two.id, node_one.id, interface_two.id, interface_one.id, link_options_two)
session.update_link(
node_two.id,
node_one.id,
interface_two.id,
interface_one.id,
link_options_two,
)
# instantiate session
session.instantiate()