Skip to content

Commit b732bb2

Browse files
committed
DevService
- changes to RealWorldRouting -DevelopmentService for remote development with VSCode on the simulation nodes
1 parent ed6ef82 commit b732bb2

19 files changed

+926
-108
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Networking Application Development in SEED
2+
3+
//### Connect the simulation to the 'real world' outside Internet
4+
5+
6+
This example is similar to `A03_real_world`
7+
8+
A real-world AS included in the emulation
9+
will collect the real network prefixes from the real Internet,
10+
and announce them inside the emulator. Packets reaching this AS
11+
will exit the emulator and be routed to the real destination.
12+
Responses from the outside will come back to this real-world AS
13+
and be routed to the final destination in the emulator.
14+
15+
16+
17+
The DevelopmentService prepares a node for [Remote Development with VSCode](https://code.visualstudio.com/docs/remote/remote-overview).
18+
It installs the VSCode Remote Server on the Node during the docker image build, which allows to ssh into the running container later i.e. to debug software.
19+
20+
As of now the primary anticipated use of the seed-emulator has been the deployment of fully developed applications into an emulated szenario i.e. to observe its behaviour.
21+
22+
The DevService adapts the emulators primary paradigm of deploying fully develped applications into an emulated szenario,
23+
to meet the need of developing i.e. P2P software to maturity in a distributed environment.
24+
25+
The DevService allows for each individual node that it is installed on, to specify one or more Git repositories that shall be checked out
26+
(along with the desired filesystem path and branch) as well as the VSCode Extensions required for the projects software stack
27+
(i.e. golang.Go for the SCION-proto implementation which is written in Go)
28+
The DevService takes care to install the entirety of build and analysis tools that are needed for a given programming language at docker image build time (for Go this being i.e. the compiler, language server gopls, debugger delve) so that no annoying time delay arises once the emulator is running and you want to attach to a container.
29+
Any specified Git repositories are checked out on its own separate docker volume, for the changes to persist between runs of the simulator in case one forgets to push.
30+
31+
Since software development requires a 'real Internet' connection of the container be it to git push/pull or fetch project dependencies for a build (i.e. go get, cargo build etc. )
32+
This is achieved by promoting the nodes default gateway ( router node ) in the simulation into a 'RealWorldRouter' (which has access to the `000_svc` service network)
33+
Use of a separate service network inhibits 'short-circuiting' the simulated network topology (i.e. any crosstalk past the intended network topo among nodes)
34+
35+
36+
```
37+
devsvc = GolangDevService('jane.doe', '[email protected]')
38+
repo_url = 'https://github.com/scionproto/scion.git'
39+
repo_branch = 'v0.12.0'
40+
repo_path = '/home/root/repos/scion'
41+
42+
svc = devsvc.install(f'dev_152_cs1')
43+
svc.checkoutRepo(repo_url, repo_path, repo_branch, AccessMode.shared)
44+
emu.addBinding(Binding(f'dev_152_cs1', filter=Filter(nodeName=as152_cs1.getName(), asn=152)))
45+
46+
svc3 = devsvc.install(f'dev_153_cs1')
47+
svc3.checkoutRepo(repo_url, repo_path, repo_branch, AccessMode.shared)
48+
emu.addBinding(Binding(f'dev_153_cs1', filter=Filter(nodeName=as153_cs1.getName(), asn=153)))
49+
50+
```
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
#!/usr/bin/env python3
2+
# encoding: utf-8
3+
4+
5+
from seedemu.services import GolangDevService, AccessMode
6+
from seedemu.core import Emulator, Binding, Filter
7+
8+
from seedemu.compiler import Docker
9+
from seedemu.core import Emulator
10+
from seedemu.layers import ScionBase, ScionRouting, ScionIsd, Scion
11+
from seedemu.layers.Scion import LinkType as ScLinkType
12+
13+
from seedemu.compiler import Docker, Platform
14+
import os, sys
15+
16+
def run(dumpfile = None):
17+
###############################################################################
18+
# Set the platform information
19+
if dumpfile is None:
20+
script_name = os.path.basename(__file__)
21+
22+
if len(sys.argv) == 1:
23+
platform = Platform.AMD64
24+
elif len(sys.argv) == 2:
25+
if sys.argv[1].lower() == 'amd':
26+
platform = Platform.AMD64
27+
elif sys.argv[1].lower() == 'arm':
28+
platform = Platform.ARM64
29+
else:
30+
print(f"Usage: {script_name} amd|arm")
31+
sys.exit(1)
32+
else:
33+
print(f"Usage: {script_name} amd|arm")
34+
sys.exit(1)
35+
36+
# Initialize
37+
emu = Emulator()
38+
base = ScionBase()
39+
routing = ScionRouting()
40+
scion_isd = ScionIsd()
41+
scion = Scion()
42+
43+
devsvc = GolangDevService('jane.doe', '[email protected]')
44+
repo_url = 'https://github.com/scionproto/scion.git'
45+
repo_branch = 'v0.12.0'
46+
repo_path = '/home/root/repos/scion'
47+
48+
49+
50+
# SCION ISDs
51+
base.createIsolationDomain(1)
52+
53+
# Internet Exchange
54+
base.createInternetExchange(100, create_rs=False)
55+
56+
# AS-150
57+
as150 = base.createAutonomousSystem(150)
58+
scion_isd.addIsdAs(1, 150, is_core=True)
59+
as150.createNetwork('net0')
60+
as150.createControlService('cs1').joinNetwork('net0')
61+
as150_router = as150.createRealWorldRouter('br0', prefixes=['10.150.0.0/24'])# the 'auto' gen prefix of net0
62+
# expectation: hosts from within AS150 can ping outside world i.e. 8.8.8.8
63+
# Hosts in the other ASes can't!!
64+
as150_router.joinNetwork('net0').joinNetwork('ix100')
65+
as150_router.crossConnect(153, 'br0', '10.50.0.2/29')
66+
67+
# AS-151
68+
as151 = base.createAutonomousSystem(151)
69+
scion_isd.addIsdAs(1, 151, is_core=True)
70+
as151.createNetwork('net0')
71+
as151.createControlService('cs1').joinNetwork('net0')
72+
as151.createRouter('br0').joinNetwork('net0').joinNetwork('ix100')
73+
74+
# AS-152
75+
as152 = base.createAutonomousSystem(152)
76+
scion_isd.addIsdAs(1, 152, is_core=True)
77+
as152.createNetwork('net0')
78+
as152_cs1 = as152.createControlService('cs1').joinNetwork('net0')
79+
as152.createRouter('br0').joinNetwork('net0').joinNetwork('ix100')
80+
81+
# AS-153
82+
as153 = base.createAutonomousSystem(153)
83+
scion_isd.addIsdAs(1, 153, is_core=False)
84+
scion_isd.setCertIssuer((1, 153), issuer=150)
85+
as153.createNetwork('net0')
86+
as153_cs1 = as153.createControlService('cs1').joinNetwork('net0')
87+
88+
as153_router = as153.createRouter('br0')
89+
as153_router.joinNetwork('net0')
90+
as153_router.crossConnect(150, 'br0', '10.50.0.3/29')
91+
92+
# Inter-AS routing
93+
scion.addIxLink(100, (1, 150), (1, 151), ScLinkType.Core)
94+
scion.addIxLink(100, (1, 151), (1, 152), ScLinkType.Core)
95+
scion.addIxLink(100, (1, 152), (1, 150), ScLinkType.Core)
96+
scion.addXcLink((1, 150), (1, 153), ScLinkType.Transit)
97+
98+
svc = devsvc.install(f'dev_152_cs1')
99+
svc.checkoutRepo(repo_url, repo_path, repo_branch, AccessMode.shared)
100+
emu.addBinding(Binding(f'dev_152_cs1', filter=Filter(nodeName=as152_cs1.getName(), asn=152)))
101+
102+
svc3 = devsvc.install(f'dev_153_cs1')
103+
svc3.checkoutRepo(repo_url, repo_path, repo_branch, AccessMode.shared)
104+
emu.addBinding(Binding(f'dev_153_cs1', filter=Filter(nodeName=as153_cs1.getName(), asn=153)))
105+
106+
# Rendering
107+
emu.addLayer(base)
108+
emu.addLayer(routing)
109+
emu.addLayer(scion_isd)
110+
emu.addLayer(scion)
111+
emu.addLayer(devsvc)
112+
113+
114+
if dumpfile is not None:
115+
emu.dump(dumpfile)
116+
else:
117+
emu.render()
118+
119+
###############################################################################
120+
# Compilation
121+
122+
emu.compile(Docker(platform=platform), './output', override=True)
123+
124+
if __name__ == "__main__":
125+
run()

seedemu/core/AutonomousSystem.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from .Emulator import Emulator
1010
from .Configurable import Configurable
1111
from .Customizable import Customizable
12-
from .Node import RealWorldRouter
12+
from .Node import promote_to_real_world_router, RealWorldRouterMixin
1313
from ipaddress import IPv4Network
1414
from typing import Dict, List
1515
import requests
@@ -102,17 +102,22 @@ def registerNodes(self, emulator: Emulator):
102102

103103
for val in list(self.__nets.values()):
104104
net: Network = val
105+
# Rap creates a new node for the provider and thus has to be set up
106+
# before node registration
105107
if net.getRemoteAccessProvider() != None:
106108
rap = net.getRemoteAccessProvider()
107109

108110
brNode = self.createRouter('br-{}'.format(net.getName()))
109111
brNet = emulator.getServiceNetwork()
110112

111113
rap.configureRemoteAccess(emulator, net, brNode, brNet)
114+
# .. whereas RealWorldConnectivity doesn't, so it can be moved to a later point
115+
# (after the services[which might require real-world-access] have been configured)
116+
#if (p:=net.getExternalConnectivityProvider()) != None:
117+
# p.configureExternalLink(emulator, net, localNet of brNode , emulator.getServiceNet() )
112118

113-
for router in list(self.__routers.values()):
114-
if issubclass(router.__class__, RealWorldRouter):
115-
router.joinNetwork(emulator.getServiceNetwork().getName())
119+
if any([issubclass(r.__class__, RealWorldRouterMixin) for r in list(self.__routers.values())]):
120+
_ = emulator.getServiceNetwork() # this will construct and register Svc Net with registry
116121

117122
for (key, val) in self.__nets.items(): reg.register(str(self.__asn), 'net', key, val)
118123
for (key, val) in self.__hosts.items(): reg.register(str(self.__asn), 'hnode', key, val)
@@ -127,10 +132,10 @@ def inheritOptions(self, emulator: Emulator):
127132
if scope==str(self.getAsn()) and typ in ['rnode','hnode','csnode','rsnode'] ]
128133
for n in all_nodes:
129134
self.handDown(n)
130-
135+
131136
def scope(self)-> Scope:
132137
"""return a scope specific to this AS"""
133-
return Scope(ScopeTier.AS, as_id=self.getAsn())
138+
return Scope(ScopeTier.AS, as_id=self.getAsn())
134139

135140

136141
def configure(self, emulator: Emulator):
@@ -234,9 +239,8 @@ def createRealWorldRouter(self, name: str, hideHops: bool = True, prefixes: List
234239
"""
235240
assert name not in self.__routers, 'Router with name {} already exists.'.format(name)
236241

237-
router: RealWorldRouter = Router(name, NodeRole.Router, self.__asn)
238-
router.__class__ = RealWorldRouter
239-
router.initRealWorld(hideHops)
242+
router: RealWorldRouterMixin = Router(name, NodeRole.Router, self.__asn)
243+
router = promote_to_real_world_router(router, hideHops)
240244

241245
if prefixes == None:
242246
prefixes = self.getPrefixList()

seedemu/core/Binding.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ def getCandidate(self, vnode: str, emulator: Emulator, peek: bool = False) -> No
230230
candidates: List[Node] = []
231231

232232
for (scope, type, name), obj in registry.getAll().items():
233-
if type != 'hnode': continue
233+
if type not in ['hnode', 'rnode', 'csnode']: continue
234234
node: Node = obj
235235
filter = self.filter
236236

0 commit comments

Comments
 (0)