added flake8/black, pre-commit integration for flake8/black, and black formatting changes
This commit is contained in:
parent
d5055f85d3
commit
1fc8d647c3
77 changed files with 4452 additions and 1964 deletions
|
@ -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
|
||||
|
|
|
@ -11,6 +11,8 @@ grpcio-tools = "*"
|
|||
core = {editable = true,path = "."}
|
||||
isort = "*"
|
||||
pre-commit = "*"
|
||||
flake8 = "*"
|
||||
black = "==19.3b0"
|
||||
|
||||
[packages]
|
||||
configparser = "*"
|
||||
|
|
67
daemon/Pipfile.lock
generated
67
daemon/Pipfile.lock
generated
|
@ -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",
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
)
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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"):
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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"])
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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="#")
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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."
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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 = ()
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"]
|
||||
)
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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),
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
@ -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):
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in a new issue