├── openoptics ├── .gitignore ├── README.md ├── dashboard │ ├── dashboard │ │ ├── __init__.py │ │ ├── wsgi.py │ │ ├── asgi.py │ │ ├── urls.py │ │ └── settings.py │ ├── dashboardapp │ │ ├── tests.py │ │ ├── admin.py │ │ ├── static │ │ │ └── logo.png │ │ ├── __init__.py │ │ ├── routing.py │ │ ├── apps.py │ │ ├── urls.py │ │ ├── simulate_push.py │ │ ├── consumers.py │ │ ├── models.py │ │ └── views.py │ ├── init.sh │ └── manage.py ├── __init__.py └── DeviceManager.py ├── assets ├── how-to-add-new-functionality-to-switches.md ├── arch.png ├── dashboard.png ├── task8-routing.png ├── example_connect.png ├── openoptics-diagram.pdf ├── openoptics-diagram.png ├── how-to-debug.md └── how-to-add-new-telemetry.md ├── targets ├── Makefile.am ├── tor_switch │ ├── tests │ │ ├── .gitignore │ │ ├── CLI_tests │ │ │ ├── testdata │ │ │ │ ├── .gitignore │ │ │ │ ├── table_dump_extra.in │ │ │ │ ├── mc_dump.in │ │ │ │ ├── table_dump_extra.p4 │ │ │ │ ├── indirect_res.in │ │ │ │ ├── table_dump_extra.out │ │ │ │ ├── indirect_res.out │ │ │ │ ├── table_dump_old.in │ │ │ │ ├── table_dump.in │ │ │ │ ├── mc_dump.out │ │ │ │ ├── table_dump_old.out │ │ │ │ ├── indirect_res.p4 │ │ │ │ └── table_dump_extra.json │ │ │ ├── .gitignore │ │ │ ├── table_dump.test │ │ │ ├── table_dump_old.test │ │ │ ├── indirect_res.test │ │ │ ├── mc_dump.test │ │ │ ├── table_dump_extra.test │ │ │ └── Makefile.am │ │ ├── main.cpp │ │ ├── Makefile.am │ │ ├── utils.h │ │ └── test_recirc.cpp │ ├── .gitignore │ ├── CPPLINT.cfg │ ├── tswitch_CLI │ ├── tor_switch_CLI.in │ ├── bm │ │ └── tor_switch │ │ │ └── runner.h │ └── thrift │ │ └── tor_switch.thrift └── optical_switch │ ├── tests │ ├── .gitignore │ ├── CLI_tests │ │ ├── testdata │ │ │ ├── .gitignore │ │ │ ├── table_dump_extra.in │ │ │ ├── mc_dump.in │ │ │ ├── table_dump_extra.p4 │ │ │ ├── indirect_res.in │ │ │ ├── table_dump_extra.out │ │ │ ├── indirect_res.out │ │ │ ├── table_dump_old.in │ │ │ ├── table_dump.in │ │ │ ├── mc_dump.out │ │ │ ├── table_dump_old.out │ │ │ ├── indirect_res.p4 │ │ │ └── table_dump_extra.json │ │ ├── .gitignore │ │ ├── table_dump.test │ │ ├── mc_dump.test │ │ ├── table_dump_old.test │ │ ├── indirect_res.test │ │ ├── table_dump_extra.test │ │ └── Makefile.am │ ├── main.cpp │ ├── Makefile.am │ └── utils.h │ ├── CPPLINT.cfg │ ├── .gitignore │ ├── oswitch_CLI │ ├── optical_switch_CLI.in │ ├── bm │ └── optical_switch │ │ └── runner.h │ ├── thrift │ └── optical_switch.thrift │ └── main.cpp ├── docs ├── README.md ├── _static │ └── openoptics.ico ├── apis │ ├── dashboard.rst │ ├── generated │ │ ├── openoptics.OpticalTopo.opera.rst │ │ ├── openoptics.OpticalTopo.shale.rst │ │ ├── openoptics.utils.load_table.rst │ │ ├── openoptics.utils.clear_table.rst │ │ ├── openoptics.utils.path2entries.rst │ │ ├── openoptics.OpticalTopo.draw_topo.rst │ │ ├── openoptics.OpticalTopo.port_offset.rst │ │ ├── openoptics.OpticalTopo.round_robin.rst │ │ ├── openoptics.OpticalTopo.static_topo.rst │ │ ├── openoptics.utils.gen_ocs_commands.rst │ │ ├── openoptics.utils.gen_tor_commands.rst │ │ ├── openoptics.utils.metric_to_matrix.rst │ │ ├── openoptics.Toolbox.BaseNetwork.start.rst │ │ ├── openoptics.OpticalRouting.routing_ksp.rst │ │ ├── openoptics.OpticalRouting.routing_vlb.rst │ │ ├── openoptics.Toolbox.BaseNetwork.connect.rst │ │ ├── openoptics.utils.tor_table_ip_to_dst.rst │ │ ├── openoptics.OpticalRouting.routing_hoho.rst │ │ ├── openoptics.Toolbox.BaseNetwork.get_topo.rst │ │ ├── openoptics.OpticalRouting.routing_direct.rst │ │ ├── openoptics.Toolbox.BaseNetwork.disconnect.rst │ │ ├── openoptics.Toolbox.BaseNetwork.setup_ocs.rst │ │ ├── openoptics.Toolbox.BaseNetwork.start_cli.rst │ │ ├── openoptics.OpticalRouting.find_send_port.rst │ │ ├── openoptics.OpticalTopo.bipartite_matching.rst │ │ ├── openoptics.OpticalTopo.topo_randomize_ts.rst │ │ ├── openoptics.Toolbox.BaseNetwork.deploy_topo.rst │ │ ├── openoptics.Toolbox.BaseNetwork.setup_nodes.rst │ │ ├── openoptics.utils.tor_table_arrive_at_dst.rst │ │ ├── openoptics.OpticalRouting.find_direct_path.rst │ │ ├── openoptics.Toolbox.BaseNetwork.create_nodes.rst │ │ ├── openoptics.Toolbox.BaseNetwork.stop_network.rst │ │ ├── openoptics.utils.tor_table_routing_source.rst │ │ ├── openoptics.OpticalRouting.routing_direct_ta.rst │ │ ├── openoptics.Toolbox.BaseNetwork.start_monitor.rst │ │ ├── openoptics.utils.tor_table_routing_per_hop.rst │ │ ├── openoptics.Toolbox.BaseNetwork.deploy_routing.rst │ │ ├── openoptics.utils.tor_table_verify_desired_node.rst │ │ ├── openoptics.Toolbox.BaseNetwork.setup_mininet_nodes.rst │ │ ├── openoptics.Toolbox.BaseNetwork.start_traffic_aware.rst │ │ ├── openoptics.OpticalTopo.get_nb_links_from_circuits.rst │ │ ├── openoptics.Toolbox.BaseNetwork.add_time_flow_entry.rst │ │ ├── openoptics.Toolbox.BaseNetwork.pause_calendar_queue.rst │ │ ├── openoptics.utils.tor_table_cal_port_slice_to_node.rst │ │ ├── openoptics.OpticalRouting.find_n_hop_path_node_pair.rst │ │ ├── openoptics.Toolbox.BaseNetwork.activate_calendar_queue.rst │ │ ├── openoptics.DeviceManager.DeviceManager.set_active_queue.rst │ │ ├── openoptics.DeviceManager.DeviceManager.get_device_metric.rst │ │ ├── openoptics.OpticalTopo.get_nb_time_slice_from_circuits.rst │ │ ├── openoptics.Toolbox.BaseNetwork.cal_node_port_to_ocs_port.rst │ │ ├── openoptics.OpticalRouting.extend_paths_to_all_time_slice.rst │ │ ├── openoptics.TimeFlowTable.Path.rst │ │ ├── openoptics.TimeFlowTable.Step.rst │ │ ├── openoptics.TimeFlowTable.TimeFlowHop.rst │ │ └── openoptics.TimeFlowTable.TimeFlowEntry.rst │ ├── devicemanager.rst │ ├── timeflowtable.rst │ ├── utils.rst │ ├── topo.rst │ ├── routing.rst │ └── basenetwork.rst ├── _templates │ └── tem_author.html ├── examples │ ├── example_src │ │ ├── shale.rst │ │ ├── source_routing.rst │ │ ├── add_entry.rst │ │ ├── opera.rst │ │ ├── connect.rst │ │ ├── direct_perhop.rst │ │ ├── ta.rst │ │ ├── hoho.rst │ │ └── vlb.rst │ └── examples.rst ├── publish2mpi.sh ├── publish2dev.sh ├── contribute.rst ├── tutorials │ ├── tutorial_index.rst │ ├── 2-connect.md │ ├── 5-multi-hop-routing.md │ ├── 6-traffic-aware.md │ ├── 4-time-flow-table.md │ ├── 3-flow-table.md │ ├── 7-topology.md │ ├── 8-routing.md │ └── 1-get-started.md ├── Makefile ├── about.rst ├── make.bat ├── installation.md ├── apis_index.rst ├── index.rst └── conf.py ├── examples ├── README.md ├── __init__.py ├── topo_shale.py ├── topo_round_robin.py ├── topo_opera.py ├── routing_direct_next_node_source.py ├── routing_direct_source.py ├── routing_direct_perhop.py ├── routing_direct_perhop_4nodes.py ├── routing_hoho_source.py ├── routing_hoho_per_hop.py ├── routing_opera.py ├── routing_vlb.py ├── topo_connect.py ├── routing_direct_2nodes.py ├── routing_direct_path_with_helper_function.py ├── ta.py └── routing_add_entry.py ├── tutorials ├── cheat-sheet.pdf ├── cheat-sheet.md ├── 6-traffic-aware-1.py ├── 6-traffic-aware-2.py ├── 1-get-started.py ├── 2-connect.py ├── solutions │ ├── 2-connect-solution.py │ ├── 7-topologies-solution.py │ ├── 4-time-flow-table-solution.py │ ├── 5-multi-hop-routing-solution.py │ ├── 3-flow-table-solution.py │ ├── 8-routings-solution.py │ └── 8-routings-solution-2.py ├── 5-multi-hop-routing.py ├── 4-time-flow-table.py ├── 3-flow-table.py ├── 7-topologies.py └── 8-routings.py ├── .gitignore ├── tests └── test_port_occupancy.py ├── trouble_shooting.md ├── .devcontainer └── devcontainer.json ├── pyproject.toml └── Dockerfile /openoptics/.gitignore: -------------------------------------------------------------------------------- 1 | *.pcap -------------------------------------------------------------------------------- /openoptics/README.md: -------------------------------------------------------------------------------- 1 | ## OpenOptics 2 | -------------------------------------------------------------------------------- /openoptics/dashboard/dashboard/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/how-to-add-new-functionality-to-switches.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /targets/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = optical_switch tor_switch 2 | -------------------------------------------------------------------------------- /targets/tor_switch/tests/.gitignore: -------------------------------------------------------------------------------- 1 | test* 2 | !test*.cpp 3 | -------------------------------------------------------------------------------- /targets/optical_switch/tests/.gitignore: -------------------------------------------------------------------------------- 1 | test* 2 | !test*.cpp 3 | -------------------------------------------------------------------------------- /targets/tor_switch/tests/CLI_tests/testdata/.gitignore: -------------------------------------------------------------------------------- 1 | !*.out 2 | -------------------------------------------------------------------------------- /openoptics/dashboard/dashboardapp/tests.py: -------------------------------------------------------------------------------- 1 | # Create your tests here. 2 | -------------------------------------------------------------------------------- /targets/optical_switch/tests/CLI_tests/testdata/.gitignore: -------------------------------------------------------------------------------- 1 | !*.out 2 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | ``` 2 | python3 -m http.server 3 | ``` 4 | To start browsing. -------------------------------------------------------------------------------- /openoptics/dashboard/dashboardapp/admin.py: -------------------------------------------------------------------------------- 1 | # Register your models here. 2 | -------------------------------------------------------------------------------- /targets/optical_switch/tests/CLI_tests/.gitignore: -------------------------------------------------------------------------------- 1 | run_one_test.py 2 | !testdata 3 | -------------------------------------------------------------------------------- /targets/tor_switch/tests/CLI_tests/.gitignore: -------------------------------------------------------------------------------- 1 | run_one_test.py 2 | !testdata 3 | -------------------------------------------------------------------------------- /assets/arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpi-ncs/openoptics/HEAD/assets/arch.png -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | ## Run examples: 2 | 3 | ```python 4 | python3 topo_opera.py 5 | ``` -------------------------------------------------------------------------------- /assets/dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpi-ncs/openoptics/HEAD/assets/dashboard.png -------------------------------------------------------------------------------- /assets/task8-routing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpi-ncs/openoptics/HEAD/assets/task8-routing.png -------------------------------------------------------------------------------- /targets/tor_switch/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /tor_switch 3 | /*.pcap 4 | tswitch_runtime 5 | tor_switch_CLI -------------------------------------------------------------------------------- /assets/example_connect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpi-ncs/openoptics/HEAD/assets/example_connect.png -------------------------------------------------------------------------------- /docs/_static/openoptics.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpi-ncs/openoptics/HEAD/docs/_static/openoptics.ico -------------------------------------------------------------------------------- /docs/apis/dashboard.rst: -------------------------------------------------------------------------------- 1 | Dashboard 2 | ============== 3 | 4 | .. automodule:: openoptics.Dashboard 5 | 6 | -------------------------------------------------------------------------------- /targets/tor_switch/CPPLINT.cfg: -------------------------------------------------------------------------------- 1 | # in case the src dir is used as the build dir 2 | exclude_files=gen-cpp 3 | -------------------------------------------------------------------------------- /tutorials/cheat-sheet.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpi-ncs/openoptics/HEAD/tutorials/cheat-sheet.pdf -------------------------------------------------------------------------------- /assets/openoptics-diagram.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpi-ncs/openoptics/HEAD/assets/openoptics-diagram.pdf -------------------------------------------------------------------------------- /assets/openoptics-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpi-ncs/openoptics/HEAD/assets/openoptics-diagram.png -------------------------------------------------------------------------------- /docs/_templates/tem_author.html: -------------------------------------------------------------------------------- 1 | 2 | Yiming Lei 3 | {{ author }} -------------------------------------------------------------------------------- /targets/optical_switch/CPPLINT.cfg: -------------------------------------------------------------------------------- 1 | # in case the src dir is used as the build dir 2 | exclude_files=gen-cpp 3 | -------------------------------------------------------------------------------- /targets/optical_switch/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /optical_switch 3 | /*.pcap 4 | oswitch_runtime 5 | optical_switch_CLI -------------------------------------------------------------------------------- /targets/optical_switch/tests/CLI_tests/table_dump.test: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ./run_one_test.py $srcdir/testdata table_dump ecmp.json 3 | -------------------------------------------------------------------------------- /targets/tor_switch/tests/CLI_tests/table_dump.test: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ./run_one_test.py $srcdir/testdata table_dump ecmp.json 3 | -------------------------------------------------------------------------------- /targets/tor_switch/tests/CLI_tests/table_dump_old.test: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ./run_one_test.py $srcdir/testdata table_dump_old ecmp.json 3 | -------------------------------------------------------------------------------- /targets/optical_switch/tests/CLI_tests/mc_dump.test: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ./run_one_test.py $srcdir/testdata mc_dump ecmp.json --pre TorPreLAG 3 | -------------------------------------------------------------------------------- /targets/optical_switch/tests/CLI_tests/table_dump_old.test: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ./run_one_test.py $srcdir/testdata table_dump_old ecmp.json 3 | -------------------------------------------------------------------------------- /targets/tor_switch/tests/CLI_tests/indirect_res.test: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ./run_one_test.py $srcdir/testdata indirect_res indirect_res.json 3 | -------------------------------------------------------------------------------- /targets/tor_switch/tests/CLI_tests/mc_dump.test: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ./run_one_test.py $srcdir/testdata mc_dump ecmp.json --pre TorPreLAG 3 | -------------------------------------------------------------------------------- /targets/optical_switch/tests/CLI_tests/indirect_res.test: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ./run_one_test.py $srcdir/testdata indirect_res indirect_res.json 3 | -------------------------------------------------------------------------------- /targets/tor_switch/tests/CLI_tests/table_dump_extra.test: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ./run_one_test.py $srcdir/testdata table_dump_extra table_dump_extra.json 3 | -------------------------------------------------------------------------------- /openoptics/dashboard/dashboardapp/static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpi-ncs/openoptics/HEAD/openoptics/dashboard/dashboardapp/static/logo.png -------------------------------------------------------------------------------- /targets/optical_switch/tests/CLI_tests/table_dump_extra.test: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ./run_one_test.py $srcdir/testdata table_dump_extra table_dump_extra.json 3 | -------------------------------------------------------------------------------- /docs/examples/example_src/shale.rst: -------------------------------------------------------------------------------- 1 | .. [1] `Shale: A Practical, Scalable Oblivious Reconfigurable Network `_, SIGCOMM'24 -------------------------------------------------------------------------------- /docs/publish2mpi.sh: -------------------------------------------------------------------------------- 1 | ssh ylei@infcontact2 'rm -rf /www/inf-websites-10/openoptics.mpi-inf.mpg.de/*' 2 | scp -r _build/html/* ylei@infcontact2:/www/inf-websites-10/openoptics.mpi-inf.mpg.de -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.OpticalTopo.opera.rst: -------------------------------------------------------------------------------- 1 | openoptics.OpticalTopo.opera 2 | ============================ 3 | 4 | .. currentmodule:: openoptics.OpticalTopo 5 | 6 | .. autofunction:: opera -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.OpticalTopo.shale.rst: -------------------------------------------------------------------------------- 1 | openoptics.OpticalTopo.shale 2 | ============================ 3 | 4 | .. currentmodule:: openoptics.OpticalTopo 5 | 6 | .. autofunction:: shale -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.utils.load_table.rst: -------------------------------------------------------------------------------- 1 | openoptics.utils.load\_table 2 | ============================ 3 | 4 | .. currentmodule:: openoptics.utils 5 | 6 | .. autofunction:: load_table -------------------------------------------------------------------------------- /docs/publish2dev.sh: -------------------------------------------------------------------------------- 1 | ssh ylei@infcontact2 'rm -rf /www/inf-websites-10/openoptics-dev.mpi-inf.mpg.de/*' 2 | scp -r _build/html/* ylei@infcontact2:/www/inf-websites-10/openoptics-dev.mpi-inf.mpg.de -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.utils.clear_table.rst: -------------------------------------------------------------------------------- 1 | openoptics.utils.clear\_table 2 | ============================= 3 | 4 | .. currentmodule:: openoptics.utils 5 | 6 | .. autofunction:: clear_table -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.utils.path2entries.rst: -------------------------------------------------------------------------------- 1 | openoptics.utils.path2entries 2 | ============================= 3 | 4 | .. currentmodule:: openoptics.utils 5 | 6 | .. autofunction:: path2entries -------------------------------------------------------------------------------- /openoptics/dashboard/init.sh: -------------------------------------------------------------------------------- 1 | service redis-server start 2 | python3 /openoptics/openoptics/dashboard/manage.py makemigrations dashboardapp 3 | python3 /openoptics/openoptics/dashboard/manage.py migrate 4 | -------------------------------------------------------------------------------- /targets/optical_switch/tests/CLI_tests/testdata/table_dump_extra.in: -------------------------------------------------------------------------------- 1 | table_dump empty_key 2 | table_set_default empty_key _nop 3 | table_dump empty_key 4 | table_reset_default empty_key 5 | table_dump empty_key 6 | -------------------------------------------------------------------------------- /targets/tor_switch/tests/CLI_tests/testdata/table_dump_extra.in: -------------------------------------------------------------------------------- 1 | table_dump empty_key 2 | table_set_default empty_key _nop 3 | table_dump empty_key 4 | table_reset_default empty_key 5 | table_dump empty_key 6 | -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.OpticalTopo.draw_topo.rst: -------------------------------------------------------------------------------- 1 | openoptics.OpticalTopo.draw\_topo 2 | ================================= 3 | 4 | .. currentmodule:: openoptics.OpticalTopo 5 | 6 | .. autofunction:: draw_topo -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.OpticalTopo.port_offset.rst: -------------------------------------------------------------------------------- 1 | openoptics.OpticalTopo.port\_offset 2 | =================================== 3 | 4 | .. currentmodule:: openoptics.OpticalTopo 5 | 6 | .. autofunction:: port_offset -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.OpticalTopo.round_robin.rst: -------------------------------------------------------------------------------- 1 | openoptics.OpticalTopo.round\_robin 2 | =================================== 3 | 4 | .. currentmodule:: openoptics.OpticalTopo 5 | 6 | .. autofunction:: round_robin -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.OpticalTopo.static_topo.rst: -------------------------------------------------------------------------------- 1 | openoptics.OpticalTopo.static\_topo 2 | =================================== 3 | 4 | .. currentmodule:: openoptics.OpticalTopo 5 | 6 | .. autofunction:: static_topo -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.utils.gen_ocs_commands.rst: -------------------------------------------------------------------------------- 1 | openoptics.utils.gen\_ocs\_commands 2 | =================================== 3 | 4 | .. currentmodule:: openoptics.utils 5 | 6 | .. autofunction:: gen_ocs_commands -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.utils.gen_tor_commands.rst: -------------------------------------------------------------------------------- 1 | openoptics.utils.gen\_tor\_commands 2 | =================================== 3 | 4 | .. currentmodule:: openoptics.utils 5 | 6 | .. autofunction:: gen_tor_commands -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.utils.metric_to_matrix.rst: -------------------------------------------------------------------------------- 1 | openoptics.utils.metric\_to\_matrix 2 | =================================== 3 | 4 | .. currentmodule:: openoptics.utils 5 | 6 | .. autofunction:: metric_to_matrix -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.Toolbox.BaseNetwork.start.rst: -------------------------------------------------------------------------------- 1 | openoptics.Toolbox.BaseNetwork.start 2 | ==================================== 3 | 4 | .. currentmodule:: openoptics.Toolbox 5 | 6 | .. automethod:: BaseNetwork.start -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.OpticalRouting.routing_ksp.rst: -------------------------------------------------------------------------------- 1 | openoptics.OpticalRouting.routing\_ksp 2 | ====================================== 3 | 4 | .. currentmodule:: openoptics.OpticalRouting 5 | 6 | .. autofunction:: routing_ksp -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.OpticalRouting.routing_vlb.rst: -------------------------------------------------------------------------------- 1 | openoptics.OpticalRouting.routing\_vlb 2 | ====================================== 3 | 4 | .. currentmodule:: openoptics.OpticalRouting 5 | 6 | .. autofunction:: routing_vlb -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.Toolbox.BaseNetwork.connect.rst: -------------------------------------------------------------------------------- 1 | openoptics.Toolbox.BaseNetwork.connect 2 | ====================================== 3 | 4 | .. currentmodule:: openoptics.Toolbox 5 | 6 | .. automethod:: BaseNetwork.connect -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.utils.tor_table_ip_to_dst.rst: -------------------------------------------------------------------------------- 1 | openoptics.utils.tor\_table\_ip\_to\_dst 2 | ======================================== 3 | 4 | .. currentmodule:: openoptics.utils 5 | 6 | .. autofunction:: tor_table_ip_to_dst -------------------------------------------------------------------------------- /targets/tor_switch/tests/CLI_tests/testdata/mc_dump.in: -------------------------------------------------------------------------------- 1 | mc_mgrp_create 1 2 | mc_node_create 2 1 5 8 | 1 3 3 | mc_node_associate 1 0 4 | mc_node_create 4 5 8 | 1 2 5 | mc_node_associate 1 1 6 | mc_set_lag_membership 1 6 9 12 7 | mc_dump 8 | -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.OpticalRouting.routing_hoho.rst: -------------------------------------------------------------------------------- 1 | openoptics.OpticalRouting.routing\_hoho 2 | ======================================= 3 | 4 | .. currentmodule:: openoptics.OpticalRouting 5 | 6 | .. autofunction:: routing_hoho -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.Toolbox.BaseNetwork.get_topo.rst: -------------------------------------------------------------------------------- 1 | openoptics.Toolbox.BaseNetwork.get\_topo 2 | ======================================== 3 | 4 | .. currentmodule:: openoptics.Toolbox 5 | 6 | .. automethod:: BaseNetwork.get_topo -------------------------------------------------------------------------------- /targets/optical_switch/tests/CLI_tests/testdata/mc_dump.in: -------------------------------------------------------------------------------- 1 | mc_mgrp_create 1 2 | mc_node_create 2 1 5 8 | 1 3 3 | mc_node_associate 1 0 4 | mc_node_create 4 5 8 | 1 2 5 | mc_node_associate 1 1 6 | mc_set_lag_membership 1 6 9 12 7 | mc_dump 8 | -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.OpticalRouting.routing_direct.rst: -------------------------------------------------------------------------------- 1 | openoptics.OpticalRouting.routing\_direct 2 | ========================================= 3 | 4 | .. currentmodule:: openoptics.OpticalRouting 5 | 6 | .. autofunction:: routing_direct -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.Toolbox.BaseNetwork.disconnect.rst: -------------------------------------------------------------------------------- 1 | openoptics.Toolbox.BaseNetwork.disconnect 2 | ========================================= 3 | 4 | .. currentmodule:: openoptics.Toolbox 5 | 6 | .. automethod:: BaseNetwork.disconnect -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.Toolbox.BaseNetwork.setup_ocs.rst: -------------------------------------------------------------------------------- 1 | openoptics.Toolbox.BaseNetwork.setup\_ocs 2 | ========================================= 3 | 4 | .. currentmodule:: openoptics.Toolbox 5 | 6 | .. automethod:: BaseNetwork.setup_ocs -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.Toolbox.BaseNetwork.start_cli.rst: -------------------------------------------------------------------------------- 1 | openoptics.Toolbox.BaseNetwork.start\_cli 2 | ========================================= 3 | 4 | .. currentmodule:: openoptics.Toolbox 5 | 6 | .. automethod:: BaseNetwork.start_cli -------------------------------------------------------------------------------- /docs/contribute.rst: -------------------------------------------------------------------------------- 1 | Contribute 2 | ================== 3 | 4 | Contributions are welcome! You could create issues or pull requests on GitHub. 5 | Don't hesitate to reach out to authors (ylei@mpi-inf.mp.de) for discussions about your thoughts. 6 | -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.OpticalRouting.find_send_port.rst: -------------------------------------------------------------------------------- 1 | openoptics.OpticalRouting.find\_send\_port 2 | ========================================== 3 | 4 | .. currentmodule:: openoptics.OpticalRouting 5 | 6 | .. autofunction:: find_send_port -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.OpticalTopo.bipartite_matching.rst: -------------------------------------------------------------------------------- 1 | openoptics.OpticalTopo.bipartite\_matching 2 | ========================================== 3 | 4 | .. currentmodule:: openoptics.OpticalTopo 5 | 6 | .. autofunction:: bipartite_matching -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.OpticalTopo.topo_randomize_ts.rst: -------------------------------------------------------------------------------- 1 | openoptics.OpticalTopo.topo\_randomize\_ts 2 | ========================================== 3 | 4 | .. currentmodule:: openoptics.OpticalTopo 5 | 6 | .. autofunction:: topo_randomize_ts -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.Toolbox.BaseNetwork.deploy_topo.rst: -------------------------------------------------------------------------------- 1 | openoptics.Toolbox.BaseNetwork.deploy\_topo 2 | =========================================== 3 | 4 | .. currentmodule:: openoptics.Toolbox 5 | 6 | .. automethod:: BaseNetwork.deploy_topo -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.Toolbox.BaseNetwork.setup_nodes.rst: -------------------------------------------------------------------------------- 1 | openoptics.Toolbox.BaseNetwork.setup\_nodes 2 | =========================================== 3 | 4 | .. currentmodule:: openoptics.Toolbox 5 | 6 | .. automethod:: BaseNetwork.setup_nodes -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.utils.tor_table_arrive_at_dst.rst: -------------------------------------------------------------------------------- 1 | openoptics.utils.tor\_table\_arrive\_at\_dst 2 | ============================================ 3 | 4 | .. currentmodule:: openoptics.utils 5 | 6 | .. autofunction:: tor_table_arrive_at_dst -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.OpticalRouting.find_direct_path.rst: -------------------------------------------------------------------------------- 1 | openoptics.OpticalRouting.find\_direct\_path 2 | ============================================ 3 | 4 | .. currentmodule:: openoptics.OpticalRouting 5 | 6 | .. autofunction:: find_direct_path -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.Toolbox.BaseNetwork.create_nodes.rst: -------------------------------------------------------------------------------- 1 | openoptics.Toolbox.BaseNetwork.create\_nodes 2 | ============================================ 3 | 4 | .. currentmodule:: openoptics.Toolbox 5 | 6 | .. automethod:: BaseNetwork.create_nodes -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.Toolbox.BaseNetwork.stop_network.rst: -------------------------------------------------------------------------------- 1 | openoptics.Toolbox.BaseNetwork.stop\_network 2 | ============================================ 3 | 4 | .. currentmodule:: openoptics.Toolbox 5 | 6 | .. automethod:: BaseNetwork.stop_network -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.utils.tor_table_routing_source.rst: -------------------------------------------------------------------------------- 1 | openoptics.utils.tor\_table\_routing\_source 2 | ============================================ 3 | 4 | .. currentmodule:: openoptics.utils 5 | 6 | .. autofunction:: tor_table_routing_source -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.OpticalRouting.routing_direct_ta.rst: -------------------------------------------------------------------------------- 1 | openoptics.OpticalRouting.routing\_direct\_ta 2 | ============================================= 3 | 4 | .. currentmodule:: openoptics.OpticalRouting 5 | 6 | .. autofunction:: routing_direct_ta -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.Toolbox.BaseNetwork.start_monitor.rst: -------------------------------------------------------------------------------- 1 | openoptics.Toolbox.BaseNetwork.start\_monitor 2 | ============================================= 3 | 4 | .. currentmodule:: openoptics.Toolbox 5 | 6 | .. automethod:: BaseNetwork.start_monitor -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.utils.tor_table_routing_per_hop.rst: -------------------------------------------------------------------------------- 1 | openoptics.utils.tor\_table\_routing\_per\_hop 2 | ============================================== 3 | 4 | .. currentmodule:: openoptics.utils 5 | 6 | .. autofunction:: tor_table_routing_per_hop -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.Toolbox.BaseNetwork.deploy_routing.rst: -------------------------------------------------------------------------------- 1 | openoptics.Toolbox.BaseNetwork.deploy\_routing 2 | ============================================== 3 | 4 | .. currentmodule:: openoptics.Toolbox 5 | 6 | .. automethod:: BaseNetwork.deploy_routing -------------------------------------------------------------------------------- /targets/tor_switch/tests/CLI_tests/testdata/table_dump_extra.p4: -------------------------------------------------------------------------------- 1 | parser start { 2 | return ingress; 3 | } 4 | 5 | action _nop() { } 6 | 7 | table empty_key { 8 | actions { _nop; } 9 | } 10 | 11 | control ingress { 12 | apply(empty_key); 13 | } 14 | -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.utils.tor_table_verify_desired_node.rst: -------------------------------------------------------------------------------- 1 | openoptics.utils.tor\_table\_verify\_desired\_node 2 | ================================================== 3 | 4 | .. currentmodule:: openoptics.utils 5 | 6 | .. autofunction:: tor_table_verify_desired_node -------------------------------------------------------------------------------- /targets/optical_switch/tests/CLI_tests/testdata/table_dump_extra.p4: -------------------------------------------------------------------------------- 1 | parser start { 2 | return ingress; 3 | } 4 | 5 | action _nop() { } 6 | 7 | table empty_key { 8 | actions { _nop; } 9 | } 10 | 11 | control ingress { 12 | apply(empty_key); 13 | } 14 | -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.Toolbox.BaseNetwork.setup_mininet_nodes.rst: -------------------------------------------------------------------------------- 1 | openoptics.Toolbox.BaseNetwork.setup\_mininet\_nodes 2 | ==================================================== 3 | 4 | .. currentmodule:: openoptics.Toolbox 5 | 6 | .. automethod:: BaseNetwork.create_nodes -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.Toolbox.BaseNetwork.start_traffic_aware.rst: -------------------------------------------------------------------------------- 1 | openoptics.Toolbox.BaseNetwork.start\_traffic\_aware 2 | ==================================================== 3 | 4 | .. currentmodule:: openoptics.Toolbox 5 | 6 | .. automethod:: BaseNetwork.start_traffic_aware -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.OpticalTopo.get_nb_links_from_circuits.rst: -------------------------------------------------------------------------------- 1 | openoptics.OpticalTopo.get\_nb\_links\_from\_circuits 2 | ===================================================== 3 | 4 | .. currentmodule:: openoptics.OpticalTopo 5 | 6 | .. autofunction:: get_nb_links_from_circuits -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.Toolbox.BaseNetwork.add_time_flow_entry.rst: -------------------------------------------------------------------------------- 1 | openoptics.Toolbox.BaseNetwork.add\_time\_flow\_entry 2 | ===================================================== 3 | 4 | .. currentmodule:: openoptics.Toolbox 5 | 6 | .. automethod:: BaseNetwork.add_time_flow_entry -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.Toolbox.BaseNetwork.pause_calendar_queue.rst: -------------------------------------------------------------------------------- 1 | openoptics.Toolbox.BaseNetwork.pause\_calendar\_queue 2 | ===================================================== 3 | 4 | .. currentmodule:: openoptics.Toolbox 5 | 6 | .. automethod:: BaseNetwork.pause_calendar_queue -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.utils.tor_table_cal_port_slice_to_node.rst: -------------------------------------------------------------------------------- 1 | openoptics.utils.tor\_table\_cal\_port\_slice\_to\_node 2 | ======================================================= 3 | 4 | .. currentmodule:: openoptics.utils 5 | 6 | .. autofunction:: tor_table_cal_port_slice_to_node -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.OpticalRouting.find_n_hop_path_node_pair.rst: -------------------------------------------------------------------------------- 1 | openoptics.OpticalRouting.find\_n\_hop\_path\_node\_pair 2 | ======================================================== 3 | 4 | .. currentmodule:: openoptics.OpticalRouting 5 | 6 | .. autofunction:: find_n_hop_path_node_pair -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.Toolbox.BaseNetwork.activate_calendar_queue.rst: -------------------------------------------------------------------------------- 1 | openoptics.Toolbox.BaseNetwork.activate\_calendar\_queue 2 | ======================================================== 3 | 4 | .. currentmodule:: openoptics.Toolbox 5 | 6 | .. automethod:: BaseNetwork.activate_calendar_queue -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.DeviceManager.DeviceManager.set_active_queue.rst: -------------------------------------------------------------------------------- 1 | openoptics.DeviceManager.DeviceManager.set\_active\_queue 2 | ========================================================= 3 | 4 | .. currentmodule:: openoptics.DeviceManager 5 | 6 | .. automethod:: DeviceManager.set_active_queue -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.DeviceManager.DeviceManager.get_device_metric.rst: -------------------------------------------------------------------------------- 1 | openoptics.DeviceManager.DeviceManager.get\_device\_metric 2 | ========================================================== 3 | 4 | .. currentmodule:: openoptics.DeviceManager 5 | 6 | .. automethod:: DeviceManager.get_device_metric -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.OpticalTopo.get_nb_time_slice_from_circuits.rst: -------------------------------------------------------------------------------- 1 | openoptics.OpticalTopo.get\_nb\_time\_slice\_from\_circuits 2 | =========================================================== 3 | 4 | .. currentmodule:: openoptics.OpticalTopo 5 | 6 | .. autofunction:: get_nb_time_slice_from_circuits -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.Toolbox.BaseNetwork.cal_node_port_to_ocs_port.rst: -------------------------------------------------------------------------------- 1 | openoptics.Toolbox.BaseNetwork.cal\_node\_port\_to\_ocs\_port 2 | ============================================================= 3 | 4 | .. currentmodule:: openoptics.Toolbox 5 | 6 | .. automethod:: BaseNetwork.cal_node_port_to_ocs_port -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.OpticalRouting.extend_paths_to_all_time_slice.rst: -------------------------------------------------------------------------------- 1 | openoptics.OpticalRouting.extend\_paths\_to\_all\_time\_slice 2 | ============================================================= 3 | 4 | .. currentmodule:: openoptics.OpticalRouting 5 | 6 | .. autofunction:: extend_paths_to_all_time_slice -------------------------------------------------------------------------------- /docs/apis/devicemanager.rst: -------------------------------------------------------------------------------- 1 | DeviceManager 2 | ============== 3 | 4 | .. automodule:: openoptics.DeviceManager.DeviceManager 5 | 6 | .. autosummary:: 7 | :toctree: generated/ 8 | 9 | openoptics.DeviceManager.DeviceManager.get_device_metric 10 | openoptics.DeviceManager.DeviceManager.set_active_queue -------------------------------------------------------------------------------- /docs/apis/timeflowtable.rst: -------------------------------------------------------------------------------- 1 | Path and Time Flow Table 2 | ========================== 3 | 4 | 5 | .. autosummary:: 6 | :toctree: generated/ 7 | 8 | openoptics.TimeFlowTable.Path 9 | openoptics.TimeFlowTable.Step 10 | openoptics.TimeFlowTable.TimeFlowEntry 11 | openoptics.TimeFlowTable.TimeFlowHop -------------------------------------------------------------------------------- /assets/how-to-debug.md: -------------------------------------------------------------------------------- 1 | # How to debug bmv2 with gdb 2 | 3 | gdb --args /behavioral-model/targets/tor_switch/.libs/tor_switch \ 4 | -i 0@tor1-eth0 -i 10@tor1-eth10 --thrift-port 9092 --nanolog ipc:///tmp/bm-2-log.ipc --device-id 2 /openoptics/p4/tor/tor.json --debugger --log-console -- --nb-time-slices 4 --time-slice-duration-ms 128 --calendar-queue-mode 1 --tor-id 1 -------------------------------------------------------------------------------- /docs/tutorials/tutorial_index.rst: -------------------------------------------------------------------------------- 1 | Tutorials 2 | =========================== 3 | 4 | These tutorials cover basic usage of OpenOptics and its features. 5 | 6 | .. toctree:: 7 | :maxdepth: 1 8 | 9 | 1-get-started 10 | 2-connect 11 | 3-flow-table 12 | 4-time-flow-table 13 | 5-multi-hop-routing 14 | 6-traffic-aware 15 | 7-topology 16 | 8-routing -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.cpython* 3 | __pycache__/ 4 | .vscode/ 5 | db.sqlite3 6 | graph_slices*.png 7 | migrations/ 8 | behavioral-model/ 9 | *.pcap 10 | 11 | # uv 12 | .ruff_cache 13 | .venv 14 | *egg-info 15 | openopticslib 16 | 17 | # C++ 18 | *.so 19 | 20 | # Django stuff: 21 | *.log 22 | *.pot 23 | 24 | # Ignore Sphinx build output 25 | docs/_build/ 26 | docs/generated/ -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.TimeFlowTable.Path.rst: -------------------------------------------------------------------------------- 1 | openoptics.TimeFlowTable.Path 2 | ============================= 3 | 4 | .. currentmodule:: openoptics.TimeFlowTable 5 | 6 | .. autoclass:: Path 7 | 8 | 9 | .. automethod:: __init__ 10 | 11 | 12 | .. rubric:: Methods 13 | 14 | .. autosummary:: 15 | 16 | ~Path.__init__ 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.TimeFlowTable.Step.rst: -------------------------------------------------------------------------------- 1 | openoptics.TimeFlowTable.Step 2 | ============================= 3 | 4 | .. currentmodule:: openoptics.TimeFlowTable 5 | 6 | .. autoclass:: Step 7 | 8 | 9 | .. automethod:: __init__ 10 | 11 | 12 | .. rubric:: Methods 13 | 14 | .. autosummary:: 15 | 16 | ~Step.__init__ 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.TimeFlowTable.TimeFlowHop.rst: -------------------------------------------------------------------------------- 1 | openoptics.TimeFlowTable.TimeFlowHop 2 | ==================================== 3 | 4 | .. currentmodule:: openoptics.TimeFlowTable 5 | 6 | .. autoclass:: TimeFlowHop 7 | 8 | 9 | .. automethod:: __init__ 10 | 11 | 12 | .. rubric:: Methods 13 | 14 | .. autosummary:: 15 | 16 | ~TimeFlowHop.__init__ 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /examples/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = [ 2 | "topo_connect", 3 | "topo_opera", 4 | "topo_round_robin", 5 | "topo_shale", 6 | "routing_add_entry", 7 | "routing_direct_perhop", 8 | "routing_direct_source", 9 | "routing_hoho_per_hop", 10 | "routing_hoho_source", 11 | "routing_opera", 12 | "routing_round_robin", 13 | "routing_round_robin_per_hop", 14 | "routing_vlb", 15 | "ta", 16 | ] 17 | -------------------------------------------------------------------------------- /docs/apis/generated/openoptics.TimeFlowTable.TimeFlowEntry.rst: -------------------------------------------------------------------------------- 1 | openoptics.TimeFlowTable.TimeFlowEntry 2 | ====================================== 3 | 4 | .. currentmodule:: openoptics.TimeFlowTable 5 | 6 | .. autoclass:: TimeFlowEntry 7 | 8 | 9 | .. automethod:: __init__ 10 | 11 | 12 | .. rubric:: Methods 13 | 14 | .. autosummary:: 15 | 16 | ~TimeFlowEntry.__init__ 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /targets/tor_switch/tests/CLI_tests/testdata/indirect_res.in: -------------------------------------------------------------------------------- 1 | counter_read my_indirect_counter 0 2 | counter_read my_indirect_counter 16 3 | meter_set_rates my_indirect_meter 0 1:1 2:1 4 | meter_set_rates my_indirect_meter 16 1:1 2:1 5 | meter_set_rates my_indirect_meter 0 2:1 1:1 6 | meter_get_rates my_indirect_meter 0 7 | register_read my_register 0 8 | register_read my_register 16 9 | register_write my_register 0 1 10 | register_write my_register 16 1 11 | -------------------------------------------------------------------------------- /targets/optical_switch/tests/CLI_tests/testdata/indirect_res.in: -------------------------------------------------------------------------------- 1 | counter_read my_indirect_counter 0 2 | counter_read my_indirect_counter 16 3 | meter_set_rates my_indirect_meter 0 1:1 2:1 4 | meter_set_rates my_indirect_meter 16 1:1 2:1 5 | meter_set_rates my_indirect_meter 0 2:1 1:1 6 | meter_get_rates my_indirect_meter 0 7 | register_read my_register 0 8 | register_read my_register 16 9 | register_write my_register 0 1 10 | register_write my_register 16 1 11 | -------------------------------------------------------------------------------- /docs/examples/examples.rst: -------------------------------------------------------------------------------- 1 | Examples 2 | ======== 3 | 4 | .. toctree:: 5 | :maxdepth: 1 6 | 7 | example_src/connect 8 | example_src/add_entry 9 | example_src/direct_perhop 10 | example_src/hoho 11 | example_src/source_routing 12 | example_src/opera 13 | example_src/vlb 14 | example_src/ta 15 | 16 | .. 17 | examples_src/routing_hoho 18 | examples_src/routing_hoho_per_hop 19 | examples_src/topo_opera 20 | examples_src/topo_round_robin 21 | examples_src/topo_shale -------------------------------------------------------------------------------- /openoptics/dashboard/dashboard/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for dashboard project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dashboard.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /targets/tor_switch/tests/CLI_tests/testdata/table_dump_extra.out: -------------------------------------------------------------------------------- 1 | ???? 2 | ========== 3 | TABLE ENTRIES 4 | ========== 5 | Dumping default entry 6 | EMPTY 7 | ========== 8 | ???? 9 | Setting default action of empty_key 10 | action: _nop 11 | runtime data: 12 | ???? 13 | ========== 14 | TABLE ENTRIES 15 | ========== 16 | Dumping default entry 17 | Action entry: _nop - 18 | ========== 19 | ???? 20 | ???? 21 | ========== 22 | TABLE ENTRIES 23 | ========== 24 | Dumping default entry 25 | EMPTY 26 | ========== 27 | ???? 28 | -------------------------------------------------------------------------------- /targets/optical_switch/tests/CLI_tests/testdata/table_dump_extra.out: -------------------------------------------------------------------------------- 1 | ???? 2 | ========== 3 | TABLE ENTRIES 4 | ========== 5 | Dumping default entry 6 | EMPTY 7 | ========== 8 | ???? 9 | Setting default action of empty_key 10 | action: _nop 11 | runtime data: 12 | ???? 13 | ========== 14 | TABLE ENTRIES 15 | ========== 16 | Dumping default entry 17 | Action entry: _nop - 18 | ========== 19 | ???? 20 | ???? 21 | ========== 22 | TABLE ENTRIES 23 | ========== 24 | Dumping default entry 25 | EMPTY 26 | ========== 27 | ???? 28 | -------------------------------------------------------------------------------- /openoptics/dashboard/dashboardapp/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Max-Planck-Gesellschaft zur Förderung der Wissenschaften e.V. 2 | # Developed at the Max Planck Institute for Informatics, Network and Cloud Systems Group 3 | # 4 | # Author: Yiming Lei (ylei@mpi-inf.mpg.de) 5 | # 6 | # This software is licensed for non-commercial scientific research purposes only. 7 | # 8 | # License text: Creative Commons NC BY SA 4.0 9 | # https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en 10 | 11 | default_app_config = "dashboardapp.apps.DashboardappConfig" 12 | -------------------------------------------------------------------------------- /targets/tor_switch/tests/CLI_tests/testdata/indirect_res.out: -------------------------------------------------------------------------------- 1 | ???? 2 | my_indirect_counter[0]= (0 bytes, 0 packets) 3 | ???? 4 | Invalid counter operation (INVALID_INDEX) 5 | ???? 6 | ???? 7 | Invalid meter operation (INVALID_INDEX) 8 | ???? 9 | Invalid meter operation (INVALID_INFO_RATE_VALUE) 10 | ???? 11 | 0: info rate = 1.0, burst size = 1 12 | 1: info rate = 2.0, burst size = 1 13 | ???? 14 | my_register[0]= 0 15 | ???? 16 | Invalid register operation (INVALID_INDEX) 17 | ???? 18 | ???? 19 | Invalid register operation (INVALID_INDEX) 20 | ???? 21 | -------------------------------------------------------------------------------- /targets/optical_switch/tests/CLI_tests/testdata/indirect_res.out: -------------------------------------------------------------------------------- 1 | ???? 2 | my_indirect_counter[0]= (0 bytes, 0 packets) 3 | ???? 4 | Invalid counter operation (INVALID_INDEX) 5 | ???? 6 | ???? 7 | Invalid meter operation (INVALID_INDEX) 8 | ???? 9 | Invalid meter operation (INVALID_INFO_RATE_VALUE) 10 | ???? 11 | 0: info rate = 1.0, burst size = 1 12 | 1: info rate = 2.0, burst size = 1 13 | ???? 14 | my_register[0]= 0 15 | ???? 16 | Invalid register operation (INVALID_INDEX) 17 | ???? 18 | ???? 19 | Invalid register operation (INVALID_INDEX) 20 | ???? 21 | -------------------------------------------------------------------------------- /examples/topo_shale.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) 5 | 6 | from openoptics import OpticalTopo, Toolbox 7 | 8 | if __name__ == "__main__": 9 | net = Toolbox.BaseNetwork( 10 | name="opera", 11 | backend="Mininet", 12 | nb_node=27, 13 | time_slice_duration_ms=256, # in ms 14 | use_webserver=True, 15 | ) 16 | 17 | circuits = OpticalTopo.shale(27, 3) 18 | 19 | print(circuits) 20 | assert net.deploy_topo(circuits) 21 | 22 | net.start() 23 | -------------------------------------------------------------------------------- /tests/test_port_occupancy.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) 5 | 6 | from openoptics import Toolbox 7 | 8 | if __name__ == "__main__": 9 | root = "" 10 | net = Toolbox.BaseNetwork( 11 | name="my_network", backend="Mininet", nb_node=2, nb_link=4, use_webserver=True 12 | ) 13 | 14 | assert net.connect(0, 0, 1, 0, 0) == True 15 | assert net.connect(0, 0, 1, 1, 1) == True 16 | assert net.connect(0, 0, 1, 0, 2) == False 17 | assert net.connect(0, 0, 1, 2, 3) == True 18 | 19 | # net.start(mode="Mininet") 20 | -------------------------------------------------------------------------------- /targets/tor_switch/tests/CLI_tests/testdata/table_dump_old.in: -------------------------------------------------------------------------------- 1 | table_num_entries ecmp_group 2 | table_indirect_create_group ecmp_group 3 | table_indirect_create_member ecmp_group set_nhop 10.0.0.1 1 4 | table_indirect_add ecmp_group 10.0.0.1/12 => 0 5 | table_indirect_add_member_to_group ecmp_group 0 0 6 | table_indirect_add_with_group ecmp_group 10.0.1.1/32 => 0 7 | table_dump ecmp_group 8 | table_num_entries ecmp_group 9 | table_dump_entry ecmp_group 0 10 | table_dump_member ecmp_group 0 11 | table_dump_group ecmp_group 0 12 | table_dump_entry_from_key ecmp_group 10.0.0.1/12 13 | table_clear ecmp_group 14 | table_num_entries ecmp_group 15 | -------------------------------------------------------------------------------- /docs/examples/example_src/source_routing.rst: -------------------------------------------------------------------------------- 1 | Source Routing 2 | ========================================= 3 | 4 | Source routing allows a sender of a data packet to completely specify the route the packet takes through the network. 5 | OpenOptics' :py:meth:`openoptics.TimeFlowTable.TimeFlowEntry` supports source routing as well as per-hop routing. 6 | Users can specify source routing by setting the ``routing_mode="Source`` in :py:meth:`openoptics.Toolbox.BaseNetwork.deploy_routing`. 7 | 8 | .. literalinclude:: ../../../examples/routing_hoho_source.py 9 | :language: python 10 | :linenos: 11 | :caption: examples/routing_hoho_source.py -------------------------------------------------------------------------------- /examples/topo_round_robin.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) 5 | 6 | from openoptics import Toolbox, OpticalTopo 7 | 8 | if __name__ == "__main__": 9 | nb_node = 4 10 | 11 | net = Toolbox.BaseNetwork( 12 | name="my_network", 13 | backend="Mininet", 14 | nb_node=nb_node, 15 | time_slice_duration_ms=256, # in ms 16 | use_webserver=True, 17 | ) 18 | 19 | circuits = OpticalTopo.round_robin(nb_node=nb_node) 20 | # print(circuits) 21 | assert net.deploy_topo(circuits) 22 | 23 | net.start() 24 | -------------------------------------------------------------------------------- /targets/optical_switch/tests/CLI_tests/testdata/table_dump_old.in: -------------------------------------------------------------------------------- 1 | table_num_entries ecmp_group 2 | table_indirect_create_group ecmp_group 3 | table_indirect_create_member ecmp_group set_nhop 10.0.0.1 1 4 | table_indirect_add ecmp_group 10.0.0.1/12 => 0 5 | table_indirect_add_member_to_group ecmp_group 0 0 6 | table_indirect_add_with_group ecmp_group 10.0.1.1/32 => 0 7 | table_dump ecmp_group 8 | table_num_entries ecmp_group 9 | table_dump_entry ecmp_group 0 10 | table_dump_member ecmp_group 0 11 | table_dump_group ecmp_group 0 12 | table_dump_entry_from_key ecmp_group 10.0.0.1/12 13 | table_clear ecmp_group 14 | table_num_entries ecmp_group 15 | -------------------------------------------------------------------------------- /openoptics/dashboard/dashboardapp/routing.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Max-Planck-Gesellschaft zur Förderung der Wissenschaften e.V. 2 | # Developed at the Max Planck Institute for Informatics, Network and Cloud Systems Group 3 | # 4 | # Author: Yiming Lei (ylei@mpi-inf.mpg.de) 5 | # 6 | # This software is licensed for non-commercial scientific research purposes only. 7 | # 8 | # License text: Creative Commons NC BY SA 4.0 9 | # https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en 10 | 11 | from django.urls import path 12 | from . import consumers 13 | 14 | websocket_urlpatterns = [ 15 | path("ws/metrics/", consumers.MetricConsumer.as_asgi()), 16 | ] 17 | -------------------------------------------------------------------------------- /docs/apis/utils.rst: -------------------------------------------------------------------------------- 1 | Utility functions 2 | ==================== 3 | 4 | .. autosummary:: 5 | :toctree: generated/ 6 | 7 | openoptics.utils.clear_table 8 | openoptics.utils.gen_ocs_commands 9 | openoptics.utils.gen_tor_commands 10 | openoptics.utils.load_table 11 | openoptics.utils.metric_to_matrix 12 | openoptics.utils.path2entries 13 | openoptics.utils.tor_table_arrive_at_dst 14 | openoptics.utils.tor_table_cal_port_slice_to_node 15 | openoptics.utils.tor_table_ip_to_dst 16 | openoptics.utils.tor_table_routing_per_hop 17 | openoptics.utils.tor_table_routing_source 18 | openoptics.utils.tor_table_verify_desired_node 19 | -------------------------------------------------------------------------------- /openoptics/dashboard/dashboardapp/apps.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Max-Planck-Gesellschaft zur Förderung der Wissenschaften e.V. 2 | # Developed at the Max Planck Institute for Informatics, Network and Cloud Systems Group 3 | # 4 | # Author: Yiming Lei (ylei@mpi-inf.mpg.de) 5 | # 6 | # This software is licensed for non-commercial scientific research purposes only. 7 | # 8 | # License text: Creative Commons NC BY SA 4.0 9 | # https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en 10 | 11 | from django.apps import AppConfig 12 | 13 | 14 | class DashboardappConfig(AppConfig): 15 | default_auto_field = "django.db.models.BigAutoField" 16 | name = "dashboardapp" 17 | -------------------------------------------------------------------------------- /trouble_shooting.md: -------------------------------------------------------------------------------- 1 | # Troubleshooting Guide 2 | 3 | ## Common Issues and Solutions 4 | 5 | ### Redis Connection Error 6 | redis.exceptions.ConnectionError: Error 111 connecting to 127.0.0.1:6379. Connect call failed ('127.0.0.1', 6379). 7 | 8 | ### Database Table Missing Error 9 | django.db.utils.OperationalError: no such table: dashboardapp_epochs 10 | 11 | ### Solution 12 | 13 | These error messages indicate that either: 14 | - The Redis server is not running 15 | - The database has not been initialized 16 | 17 | To resolve these issues, run the initialization script: 18 | 19 | ```bash 20 | cd openoptics 21 | bash ./openoptics/dashboard/init.sh 22 | `` 23 | -------------------------------------------------------------------------------- /targets/tor_switch/tests/CLI_tests/testdata/table_dump.in: -------------------------------------------------------------------------------- 1 | table_num_entries ecmp_group 2 | act_prof_create_group ecmp_action_profile 3 | act_prof_create_member ecmp_action_profile set_nhop 10.0.0.1 1 4 | table_indirect_add ecmp_group 10.0.0.1/12 => 0 5 | act_prof_add_member_to_group ecmp_action_profile 0 0 6 | table_indirect_add_with_group ecmp_group 10.0.1.1/32 => 0 7 | table_dump ecmp_group 8 | table_num_entries ecmp_group 9 | table_dump_entry ecmp_group 0 10 | act_prof_dump_member ecmp_action_profile 0 11 | act_prof_dump_group ecmp_action_profile 0 12 | table_dump_entry_from_key ecmp_group 10.0.0.1/12 13 | table_clear ecmp_group 14 | table_num_entries ecmp_group 15 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "openoptics", 3 | "runArgs": [ 4 | "--privileged", 5 | "--network", "host", 6 | "--name", "openoptics", 7 | "-v", "${localWorkspaceFolder}:/openoptics" 8 | ], 9 | "image": "ymlei/openoptics:latest", 10 | "postStartCommand": "bash", 11 | "overrideCommand": true, 12 | "remoteUser": "root", 13 | "workspaceFolder": "/openoptics", 14 | "customizations": { 15 | "vscode": { 16 | //"settings": { 17 | // "extensions.verifySignature": false 18 | //}, 19 | "extensions": [ 20 | "ms-vscode.cpptools", 21 | "ms-python.python" 22 | ] 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /targets/optical_switch/tests/CLI_tests/testdata/table_dump.in: -------------------------------------------------------------------------------- 1 | table_num_entries ecmp_group 2 | act_prof_create_group ecmp_action_profile 3 | act_prof_create_member ecmp_action_profile set_nhop 10.0.0.1 1 4 | table_indirect_add ecmp_group 10.0.0.1/12 => 0 5 | act_prof_add_member_to_group ecmp_action_profile 0 0 6 | table_indirect_add_with_group ecmp_group 10.0.1.1/32 => 0 7 | table_dump ecmp_group 8 | table_num_entries ecmp_group 9 | table_dump_entry ecmp_group 0 10 | act_prof_dump_member ecmp_action_profile 0 11 | act_prof_dump_group ecmp_action_profile 0 12 | table_dump_entry_from_key ecmp_group 10.0.0.1/12 13 | table_clear ecmp_group 14 | table_num_entries ecmp_group 15 | -------------------------------------------------------------------------------- /examples/topo_opera.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) 5 | 6 | from openoptics import Toolbox, OpticalTopo 7 | 8 | if __name__ == "__main__": 9 | nb_node = 8 10 | nb_link = 4 11 | 12 | net = Toolbox.BaseNetwork( 13 | name="opera", 14 | backend="Mininet", 15 | nb_node=nb_node, 16 | nb_link=nb_link, 17 | time_slice_duration_ms=256, # in ms 18 | use_webserver=True, 19 | ) 20 | 21 | circuits = OpticalTopo.opera(nb_node, nb_link) 22 | # print(circuits) 23 | assert net.deploy_topo(circuits) 24 | 25 | net.start() 26 | -------------------------------------------------------------------------------- /docs/examples/example_src/add_entry.rst: -------------------------------------------------------------------------------- 1 | Routing Primitive 2 | ======================================================================== 3 | 4 | From the previous example, we already have a 3-slice topology consisting of 4 nodes. 5 | This example demonstrates how to add time-flow entries to switches to enable network routing. 6 | For simplicity, we implement direct routing by adding time-flow entries only to nodes 0 and 1. 7 | The detailed definition of the time-flow entry can be found in the :doc:`../../apis/timeflowtable`. 8 | 9 | 10 | .. literalinclude:: ../../../examples/routing_add_entry.py 11 | :language: python 12 | :linenos: 13 | :caption: examples/routing_add_entry.py -------------------------------------------------------------------------------- /docs/examples/example_src/opera.rst: -------------------------------------------------------------------------------- 1 | Opera 2 | ================== 3 | 4 | This example demonstrates how to use OpenOptics library functions to implement Opera [1]_. 5 | You can specify the number of nodes and links per node using the topology function 6 | :py:meth:`openoptics.OpticalTopo.opera`, and configure routing 7 | with :py:meth:`openoptics.OpticalRouting.routing_ksp` 8 | 9 | .. literalinclude:: ../../../examples/routing_opera.py 10 | :language: python 11 | :linenos: 12 | :caption: examples/routing_opera.py 13 | 14 | .. [1] `Expanding across time to deliver bandwidth efficiency and low latency `_, NSDI'20, -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "openoptics" 3 | version = "0.1.0" 4 | description = "Add your description here" 5 | readme = "README.md" 6 | requires-python = ">=3.8" 7 | 8 | [project.urls] 9 | Homepage = "https://openoptics.mpi-inf.mpg.de" 10 | Documentation = "https://openoptics.mpi-inf.mpg.de/tutorials/1-get-started.html" 11 | Repository = "https://github.com/your-org/openoptics" 12 | 13 | #dependencies = [ 14 | # "django>=5.2.5", 15 | # "matplotlib>=3.10.5", 16 | # "mininet>=2.3.0.dev6", 17 | # "networkx>=3.5", 18 | # "thrift>=0.22.0", 19 | #] 20 | 21 | [tool.setuptools] 22 | packages = [ 23 | "openoptics", 24 | # "openopticslib" 25 | ] 26 | 27 | 28 | -------------------------------------------------------------------------------- /assets/how-to-add-new-telemetry.md: -------------------------------------------------------------------------------- 1 | ## How to add new network telemetry to OpenOptics 2 | python -> thrift_api -> tor_switch.cpp functions 3 | 4 | We need to define thrift apis in tor_switch.thrift 5 | 6 | Add function in tor_switch.cpp 7 | 8 | 9 | Add server API at targets/tor_switch/thrift/src/TorSwitch_server.cpp 10 | 11 | ```python 12 | void get_device_metric(std::string& _return) { 13 | bm::Logger::get()->trace("get_device_metric"); 14 | switch_->get_device_metric(_return); 15 | } 16 | ``` 17 | 18 | 19 | targets/tor_switch/main.cpp 20 | Add parser 21 | 22 | 23 | Update TorSwitch_server.cpp 24 | Define thrift return struct. 25 | 26 | 27 | 28 | 29 | Update dashboard 30 | 31 | views.py -------------------------------------------------------------------------------- /docs/examples/example_src/connect.rst: -------------------------------------------------------------------------------- 1 | Topology Primitive 2 | ======================================================================== 3 | 4 | This example demonstrates how to construct a time-sliced topology using :py:meth:`openoptics.Toolbox.BaseNetwork.connect`. 5 | We build a network consisting of 4 nodes, with each node connected to an optical switch via one upper link. 6 | Across all time slices, each node establishes a connection with every other node exactly once. 7 | 8 | .. literalinclude:: ../../../examples/topo_connect.py 9 | :language: python 10 | :linenos: 11 | :caption: examples/topo_connect.py 12 | 13 | .. image:: ../../../assets/example_connect.png 14 | :alt: Topology -------------------------------------------------------------------------------- /openoptics/dashboard/dashboardapp/urls.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Max-Planck-Gesellschaft zur Förderung der Wissenschaften e.V. 2 | # Developed at the Max Planck Institute for Informatics, Network and Cloud Systems Group 3 | # 4 | # Author: Yiming Lei (ylei@mpi-inf.mpg.de) 5 | # 6 | # This software is licensed for non-commercial scientific research purposes only. 7 | # 8 | # License text: Creative Commons NC BY SA 4.0 9 | # https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en 10 | 11 | from django.urls import path 12 | from . import views 13 | 14 | urlpatterns = [ 15 | path("", views.render_dashboard, name="render_dashboard"), 16 | path("render/", views.render_dashboard, name="render_dashboard"), 17 | ] 18 | -------------------------------------------------------------------------------- /tutorials/cheat-sheet.md: -------------------------------------------------------------------------------- 1 | ### How do I exit OpenOptics CLI? 2 | 3 | ``` 4 | Ctrl+D 5 | ``` 6 | or in Mac 7 | ``` 8 | Command+D 9 | ``` 10 | 11 | ### Where is my dashboard? 12 | 13 | Open http://localhost:8001 on your browser 14 | 15 | ### Why doesn't the dashboard work? 16 | Check if you enable port forwarding: 17 | ssh -L localhost:8001:localhost:8001 or 18 | LocalForward localhost:8001 localhost:8001 in your host's .ssh/config 19 | 20 | ### Exception: Error creating interface pair (ocs-eth0,tor0-eth0): RTNETLINK answers: File exists 21 | 22 | ``` 23 | mn -c 24 | ``` 25 | 26 | ### ModuleNotFoundError: No module named 'openoptics' 27 | 28 | Under openoptic/ 29 | ``` 30 | pip install -e . 31 | ``` 32 | -------------------------------------------------------------------------------- /targets/tor_switch/tswitch_CLI: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | THIS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | 5 | json="" 6 | if [ $# -eq 1 ]; then 7 | echo "Using JSON input $1" 8 | json="--json $1" 9 | fi 10 | port="" 11 | if [ $# -eq 2 ]; then 12 | echo "Using Thrift port $2" 13 | port="--thrift-port $2" 14 | else 15 | echo "No Thrift port specified, using CLI default" 16 | fi 17 | if [ $# -gt 2 ]; then 18 | echo "Invalid number of arguments" 19 | echo "Usage: $0 [ []]" 20 | exit 1 21 | fi 22 | 23 | CLI=$THIS_DIR/tswitch_CLI.py 24 | TOOLS_DIR=$THIS_DIR/../../tools/ 25 | 26 | PYTHONPATH=$PYTHONPATH:$TOOLS_DIR python3 $CLI $json $port 27 | -------------------------------------------------------------------------------- /targets/optical_switch/oswitch_CLI: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | THIS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | 5 | json="" 6 | if [ $# -eq 1 ]; then 7 | echo "Using JSON input $1" 8 | json="--json $1" 9 | fi 10 | port="" 11 | if [ $# -eq 2 ]; then 12 | echo "Using Thrift port $2" 13 | port="--thrift-port $2" 14 | else 15 | echo "No Thrift port specified, using CLI default" 16 | fi 17 | if [ $# -gt 2 ]; then 18 | echo "Invalid number of arguments" 19 | echo "Usage: $0 [ []]" 20 | exit 1 21 | fi 22 | 23 | CLI=$THIS_DIR/oswitch_CLI.py 24 | TOOLS_DIR=$THIS_DIR/../../tools/ 25 | 26 | PYTHONPATH=$PYTHONPATH:$TOOLS_DIR python3 $CLI $json $port 27 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= python3 -m sphinx 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/apis/topo.rst: -------------------------------------------------------------------------------- 1 | OpticalTopo 2 | ========================== 3 | 4 | User APIs 5 | ----------- 6 | 7 | .. autosummary:: 8 | :toctree: generated/ 9 | 10 | openoptics.OpticalTopo.round_robin 11 | openoptics.OpticalTopo.opera 12 | openoptics.OpticalTopo.shale 13 | openoptics.OpticalTopo.static_topo 14 | openoptics.OpticalTopo.bipartite_matching 15 | 16 | 17 | Helper Functions 18 | ------------------ 19 | 20 | .. autosummary:: 21 | :toctree: generated/ 22 | 23 | openoptics.OpticalTopo.draw_topo 24 | openoptics.OpticalTopo.topo_randomize_ts 25 | openoptics.OpticalTopo.port_offset 26 | openoptics.OpticalTopo.get_nb_time_slice_from_circuits 27 | openoptics.OpticalTopo.get_nb_links_from_circuits 28 | 29 | -------------------------------------------------------------------------------- /targets/optical_switch/tests/CLI_tests/testdata/mc_dump.out: -------------------------------------------------------------------------------- 1 | ???? 2 | Creating multicast group 1 3 | ???? 4 | Creating node with rid 2 , port map 100100010 and lag map 1010 5 | node was created with handle 0 6 | ???? 7 | Associating node 0 to multicast group 1 8 | ???? 9 | Creating node with rid 4 , port map 100100000 and lag map 110 10 | node was created with handle 1 11 | ???? 12 | Associating node 1 to multicast group 1 13 | ???? 14 | Setting lag membership: 1 <- 1001001000000 15 | ???? 16 | ========== 17 | MC ENTRIES 18 | ********** 19 | mgrp(1) 20 | -> (L1h=0, rid=2) -> (ports=[1, 5, 8], lags=[1, 3]) 21 | -> (L1h=1, rid=4) -> (ports=[5, 8], lags=[1, 2]) 22 | ========== 23 | LAGS 24 | lag(1) -> ports=[5, 8] 25 | ========== 26 | ???? 27 | -------------------------------------------------------------------------------- /targets/tor_switch/tests/CLI_tests/testdata/mc_dump.out: -------------------------------------------------------------------------------- 1 | ???? 2 | Creating multicast group 1 3 | ???? 4 | Creating node with rid 2 , port map 100100010 and lag map 1010 5 | node was created with handle 0 6 | ???? 7 | Associating node 0 to multicast group 1 8 | ???? 9 | Creating node with rid 4 , port map 100100000 and lag map 110 10 | node was created with handle 1 11 | ???? 12 | Associating node 1 to multicast group 1 13 | ???? 14 | Setting lag membership: 1 <- 1001001000000 15 | ???? 16 | ========== 17 | MC ENTRIES 18 | ********** 19 | mgrp(1) 20 | -> (L1h=0, rid=2) -> (ports=[1, 5, 8], lags=[1, 3]) 21 | -> (L1h=1, rid=4) -> (ports=[5, 8], lags=[1, 2]) 22 | ========== 23 | LAGS 24 | lag(1) -> ports=[5, 8] 25 | ========== 26 | ???? 27 | -------------------------------------------------------------------------------- /docs/apis/routing.rst: -------------------------------------------------------------------------------- 1 | OpticalRouting 2 | ============================ 3 | 4 | 5 | User APIs 6 | --------------- 7 | 8 | .. autosummary:: 9 | :toctree: generated/ 10 | 11 | openoptics.OpticalRouting.routing_direct 12 | openoptics.OpticalRouting.routing_direct_ta 13 | openoptics.OpticalRouting.routing_hoho 14 | openoptics.OpticalRouting.routing_ksp 15 | openoptics.OpticalRouting.routing_vlb 16 | 17 | Helper Functions 18 | ----------------- 19 | 20 | .. autosummary:: 21 | :toctree: generated/ 22 | 23 | openoptics.OpticalRouting.find_direct_path 24 | openoptics.OpticalRouting.find_n_hop_path_node_pair 25 | openoptics.OpticalRouting.extend_paths_to_all_time_slice 26 | openoptics.OpticalRouting.find_send_port -------------------------------------------------------------------------------- /docs/examples/example_src/direct_perhop.rst: -------------------------------------------------------------------------------- 1 | Direct Routing 2 | ========================================= 3 | 4 | This example demonstrates a direct per-hop routing implementation in a time-sliced optical network. 5 | The per-hop routing approach configures each switch node to make independent forwarding decisions based 6 | on the destination address, enabling packets to traverse the network hop-by-hop until they reach their 7 | final destination. This method provides a straightforward routing mechanism where each intermediate 8 | node determines the next hop based on local routing information. 9 | 10 | .. literalinclude:: ../../../examples/routing_direct_perhop.py 11 | :language: python 12 | :linenos: 13 | :caption: examples/routing_direct_perhop.py -------------------------------------------------------------------------------- /examples/routing_direct_next_node_source.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) 5 | 6 | from openoptics import Toolbox, OpticalTopo, OpticalRouting 7 | 8 | if __name__ == "__main__": 9 | net = Toolbox.BaseNetwork( 10 | name="my_network", 11 | backend="Mininet", 12 | nb_node=8, 13 | time_slice_duration_ms=2, # in ms 14 | use_webserver=False, 15 | ) 16 | 17 | circuits = OpticalTopo.round_robin(nb_node=8) 18 | # print(circuits) 19 | assert net.deploy_topo(circuits) 20 | 21 | paths = OpticalRouting.routing_direct_next_node(net.get_topo()) 22 | net.deploy_routing(paths, routing_mode="Source") 23 | 24 | net.start() 25 | -------------------------------------------------------------------------------- /examples/routing_direct_source.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) 5 | 6 | from openoptics import Toolbox, OpticalTopo, OpticalRouting 7 | 8 | if __name__ == "__main__": 9 | nb_node = 8 10 | 11 | net = Toolbox.BaseNetwork( 12 | name="my_network", 13 | backend="Mininet", 14 | nb_node=8, 15 | time_slice_duration_ms=256, # in ms 16 | use_webserver=True, 17 | ) 18 | 19 | circuits = OpticalTopo.round_robin(nb_node=8) 20 | # print(circuits) 21 | assert net.deploy_topo(circuits) 22 | 23 | paths = OpticalRouting.routing_direct(net.get_topo()) 24 | net.deploy_routing(paths, routing_mode="Source") 25 | 26 | net.start() 27 | -------------------------------------------------------------------------------- /examples/routing_direct_perhop.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) 5 | 6 | from openoptics import Toolbox, OpticalTopo, OpticalRouting 7 | 8 | if __name__ == "__main__": 9 | nb_node = 4 10 | 11 | net = Toolbox.BaseNetwork( 12 | name="my_network", 13 | backend="Mininet", 14 | nb_node=nb_node, 15 | time_slice_duration_ms=1024, # in ms 16 | use_webserver=True, 17 | ) 18 | 19 | circuits = OpticalTopo.round_robin(nb_node=nb_node) 20 | # print(circuits) 21 | assert net.deploy_topo(circuits) 22 | 23 | paths = OpticalRouting.routing_direct(net.get_topo()) 24 | net.deploy_routing(paths, routing_mode="Per-hop") 25 | 26 | net.start() 27 | -------------------------------------------------------------------------------- /openoptics/dashboard/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """Django's command-line utility for administrative tasks.""" 3 | 4 | import os 5 | import sys 6 | 7 | 8 | def main(): 9 | """Run administrative tasks.""" 10 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dashboard.settings") 11 | try: 12 | from django.core.management import execute_from_command_line 13 | except ImportError as exc: 14 | raise ImportError( 15 | "Couldn't import Django. Are you sure it's installed and " 16 | "available on your PYTHONPATH environment variable? Did you " 17 | "forget to activate a virtual environment?" 18 | ) from exc 19 | execute_from_command_line(sys.argv) 20 | 21 | 22 | if __name__ == "__main__": 23 | main() 24 | -------------------------------------------------------------------------------- /examples/routing_direct_perhop_4nodes.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) 5 | 6 | from openoptics import Toolbox, OpticalTopo, OpticalRouting 7 | 8 | if __name__ == "__main__": 9 | nb_node = 4 10 | 11 | net = Toolbox.BaseNetwork( 12 | name="my_network", 13 | backend="Mininet", 14 | nb_node=nb_node, 15 | time_slice_duration_ms=256, # in ms 16 | use_webserver=True, 17 | ) 18 | 19 | circuits = OpticalTopo.round_robin(nb_node=nb_node) 20 | # print(circuits) 21 | assert net.deploy_topo(circuits) 22 | 23 | paths = OpticalRouting.routing_direct(net.get_topo()) 24 | net.deploy_routing(paths, routing_mode="Per-hop") 25 | 26 | net.start() 27 | -------------------------------------------------------------------------------- /examples/routing_hoho_source.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) 5 | 6 | from openoptics import Toolbox, OpticalTopo, OpticalRouting 7 | 8 | if __name__ == "__main__": 9 | nb_node = 4 10 | nb_link = 1 11 | 12 | net = Toolbox.BaseNetwork( 13 | name="my_network", 14 | backend="Mininet", 15 | nb_node=nb_node, 16 | time_slice_duration_ms=128, # in ms 17 | use_webserver=True, 18 | ) 19 | 20 | circuits = OpticalTopo.opera(nb_node=nb_node, nb_link=nb_link) 21 | assert net.deploy_topo(circuits) 22 | 23 | paths = OpticalRouting.routing_hoho(net.get_topo(), max_hop=2) 24 | assert net.deploy_routing(paths, routing_mode="Source") 25 | 26 | net.start() 27 | -------------------------------------------------------------------------------- /examples/routing_hoho_per_hop.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) 5 | 6 | from openoptics import Toolbox, OpticalTopo, OpticalRouting 7 | 8 | if __name__ == "__main__": 9 | nb_node = 4 10 | nb_link = 1 11 | 12 | net = Toolbox.BaseNetwork( 13 | name="my_network", 14 | backend="Mininet", 15 | nb_node=nb_node, 16 | time_slice_duration_ms=128, # in ms 17 | use_webserver=True, 18 | ) 19 | 20 | circuits = OpticalTopo.opera(nb_node=nb_node, nb_link=nb_link) 21 | assert net.deploy_topo(circuits) 22 | 23 | paths = OpticalRouting.routing_hoho(net.get_topo(), max_hop=2) 24 | assert net.deploy_routing(paths, routing_mode="Per-hop") 25 | 26 | net.start() 27 | -------------------------------------------------------------------------------- /examples/routing_opera.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) 5 | 6 | from openoptics import Toolbox, OpticalTopo, OpticalRouting 7 | 8 | if __name__ == "__main__": 9 | node_nb = 8 10 | nb_link = 4 11 | 12 | net = Toolbox.BaseNetwork( 13 | name="my_network", 14 | backend="Mininet", 15 | nb_node=node_nb, 16 | nb_link=nb_link, 17 | time_slice_duration_ms=64, # in ms 18 | use_webserver=True, 19 | ) 20 | 21 | circuits = OpticalTopo.opera(nb_node=node_nb, nb_link=nb_link) 22 | assert net.deploy_topo(circuits) 23 | 24 | paths = OpticalRouting.routing_ksp(net.get_topo()) 25 | net.deploy_routing(paths, routing_mode="Source") 26 | 27 | net.start() 28 | -------------------------------------------------------------------------------- /openoptics/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Max-Planck-Gesellschaft zur Förderung der Wissenschaften e.V. 2 | # Developed at the Max Planck Institute for Informatics, Network and Cloud Systems Group 3 | # 4 | # Author: Yiming Lei (ylei@mpi-inf.mpg.de) 5 | # 6 | # This software is licensed for non-commercial scientific research purposes only. 7 | # 8 | # License text: Creative Commons NC BY SA 4.0 9 | # https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en 10 | 11 | """ 12 | OpenOptics - An open framework for designing, testing, and deploying optical datacenter networks 13 | """ 14 | 15 | __all__ = [ 16 | "Toolbox", 17 | "OpticalRouting", 18 | "OpticalTopo", 19 | "TimeFlowTable", 20 | "DeviceManager", 21 | "Dashboard", 22 | "OpticalCLI", 23 | "p4_mininet", 24 | "utils", 25 | ] 26 | -------------------------------------------------------------------------------- /examples/routing_vlb.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) 5 | 6 | from openoptics import Toolbox, OpticalTopo, OpticalRouting 7 | 8 | if __name__ == "__main__": 9 | nb_node = 8 10 | 11 | net = Toolbox.BaseNetwork( 12 | name="VLB", 13 | backend="Mininet", 14 | nb_node=nb_node, 15 | time_slice_duration_ms=64, # in ms 16 | use_webserver=False, 17 | ) 18 | 19 | circuits = OpticalTopo.round_robin(nb_node=nb_node) 20 | assert net.deploy_topo(circuits) 21 | 22 | paths = OpticalRouting.routing_vlb(net.get_topo(), net.tor_ocs_ports) 23 | # for path in paths: 24 | # print(path) 25 | assert net.deploy_routing(paths, routing_mode="Source") 26 | 27 | net.start() 28 | -------------------------------------------------------------------------------- /examples/topo_connect.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) 5 | 6 | from openoptics import Toolbox 7 | 8 | if __name__ == "__main__": 9 | root = "" 10 | net = Toolbox.BaseNetwork( 11 | name="my_network", 12 | backend="Mininet", 13 | nb_node=4, 14 | time_slice_duration_ms=256, # in ms 15 | use_webserver=True, 16 | ) 17 | 18 | net.connect(node1=0, node2=1, time_slice=0) 19 | net.connect(node1=2, node2=3, time_slice=0) 20 | 21 | net.connect(node1=0, node2=2, time_slice=1) 22 | net.connect(node1=1, node2=3, time_slice=1) 23 | 24 | net.connect(node1=0, node2=3, time_slice=2) 25 | net.connect(node1=1, node2=2, time_slice=2) 26 | 27 | net.deploy_topo() 28 | 29 | net.start() 30 | -------------------------------------------------------------------------------- /openoptics/dashboard/dashboard/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for dashboard project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | from channels.auth import AuthMiddlewareStack 12 | from channels.routing import ProtocolTypeRouter, URLRouter 13 | from django.core.asgi import get_asgi_application 14 | import dashboardapp.routing 15 | 16 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dashboard.settings") 17 | 18 | application = ProtocolTypeRouter( 19 | { 20 | "http": get_asgi_application(), 21 | "websocket": AuthMiddlewareStack( 22 | URLRouter(dashboardapp.routing.websocket_urlpatterns) 23 | ), 24 | } 25 | ) 26 | -------------------------------------------------------------------------------- /docs/apis/basenetwork.rst: -------------------------------------------------------------------------------- 1 | BaseNetwork 2 | ========================== 3 | 4 | .. currentmodule:: openoptics.Toolbox 5 | 6 | .. automodule:: openoptics.Toolbox.BaseNetwork 7 | .. automethod:: openoptics.Toolbox.BaseNetwork.__init__ 8 | 9 | User APIs 10 | ----------------- 11 | 12 | .. autosummary:: 13 | :toctree: generated/ 14 | 15 | connect 16 | disconnect 17 | add_time_flow_entry 18 | deploy_topo 19 | deploy_routing 20 | start 21 | start_traffic_aware 22 | activate_calendar_queue 23 | pause_calendar_queue 24 | get_topo 25 | 26 | .. 27 | Internal APIs 28 | ----------------- 29 | 30 | .. autosummary:: 31 | :toctree: generated/ 32 | 33 | create_nodes 34 | setup_ocs 35 | setup_nodes 36 | start_cli 37 | start_monitor 38 | stop_network 39 | cal_node_port_to_ocs_port -------------------------------------------------------------------------------- /docs/examples/example_src/ta.rst: -------------------------------------------------------------------------------- 1 | Traffic Aware Workflow 2 | ======================== 3 | 4 | Unlike traffic-oblivious topologies, traffic-aware architectures dynamically adapt the network topology based on runtime traffic patterns. 5 | This requires a feedback loop to collect traffic information and update the network topology accordingly. 6 | All of this functionality is encapsulated in :py:meth:`openoptics.Toolbox.BaseNetwork.start_traffic_aware`, where users only need to 7 | specify the topology generation function and the routing algorithm they wish to use. 8 | The configuration workflow is nearly identical to the previous examples of traffic-oblivious architectures. 9 | 10 | Try ping between nodes, what do you observe on the dashboard? 11 | 12 | .. literalinclude:: ../../../examples/ta.py 13 | :language: python 14 | :linenos: 15 | :caption: examples/ta.py -------------------------------------------------------------------------------- /docs/examples/example_src/hoho.rst: -------------------------------------------------------------------------------- 1 | Fastest Path Routing 2 | ========================================= 3 | 4 | This example demonstrates how to use OpenOptics library functions to implement URO [1]_/HOHO [2]_. 5 | URO routes packets through the fastest path on arbitary topologies. 6 | You can configure HOHO routing with :py:meth:`openoptics.OpticalRouting.routing_hoho`. 7 | 8 | .. literalinclude:: ../../../examples/routing_hoho_per_hop.py 9 | :language: python 10 | :linenos: 11 | :caption: examples/routing_hoho.py 12 | 13 | .. [1] `Unlocking Diversity of Fast-Switched Optical Data Center Networks With Unified Routing `_, IEEE Transactions on Networking, 2025 14 | .. [2] `Hop-On Hop-Off Routing: A Fast Tour across the Optical Data Center Network for Latency-Sensitive Flows `_, APNet'22 -------------------------------------------------------------------------------- /docs/about.rst: -------------------------------------------------------------------------------- 1 | About Us 2 | ================= 3 | 4 | OpenOptics is built by network and cloud systems research group at Max Planck Institute for Informatics (MPI-INF). 5 | 6 | Team: 7 | ----- 8 | 9 | `Yiming Lei `_, PhD Student at MPI-INF. 10 | 11 | `Yiting Xia `_, tenure-track faculty at MPI-INF. 12 | 13 | `Federico De Marchi `_, PhD Student at MPI-INF. 14 | 15 | Former Contributors: 16 | ----------------------------------- 17 | 18 | `Sami Hatna `_, former intern at MPI-INF, now at Meta. 19 | 20 | `Alexander Liggesmeyer `_, former intern at MPI-INF, now at CISPA. 21 | 22 | Linshu Yang, former intern at MPI-INF, now at UIUC. 23 | 24 | Contact: 25 | -------- 26 | 27 | Yiming Lei (ylei@mpi-inf.mpg.de) -------------------------------------------------------------------------------- /examples/routing_direct_2nodes.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) 5 | 6 | from openoptics import Toolbox, OpticalTopo, OpticalRouting 7 | 8 | if __name__ == "__main__": 9 | net = Toolbox.BaseNetwork( 10 | name="my_network", 11 | backend="Mininet", 12 | nb_node=8, 13 | time_slice_duration_ms=2, # in ms 14 | use_webserver=True, 15 | ) 16 | 17 | circuits = OpticalTopo.round_robin(nb_node=8) 18 | # print(circuits) 19 | assert net.deploy_topo(circuits) 20 | 21 | paths = OpticalRouting.find_direct_path(net.get_topo(), node1=0, node2=1) 22 | paths.extend(OpticalRouting.find_direct_path(net.get_topo(), node1=1, node2=0)) 23 | # for path in paths: 24 | # print(str(path)) 25 | net.deploy_routing(paths, routing_mode="Per-hop") 26 | 27 | net.start() 28 | -------------------------------------------------------------------------------- /examples/routing_direct_path_with_helper_function.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) 5 | 6 | from openoptics import Toolbox, OpticalTopo, OpticalRouting 7 | 8 | if __name__ == "__main__": 9 | net = Toolbox.BaseNetwork( 10 | name="my_network", 11 | backend="Mininet", 12 | nb_node=8, 13 | time_slice_duration_ms=2, # in ms 14 | use_webserver=True, 15 | ) 16 | 17 | circuits = OpticalTopo.round_robin(nb_node=8) 18 | # print(circuits) 19 | assert net.deploy_topo(circuits) 20 | 21 | paths = OpticalRouting.find_direct_path(net.get_topo(), node1=0, node2=1) 22 | paths.extend(OpticalRouting.find_direct_path(net.get_topo(), node1=1, node2=0)) 23 | # for path in paths: 24 | # print(str(path)) 25 | net.deploy_routing(paths, routing_mode="Per-hop") 26 | 27 | net.start() 28 | -------------------------------------------------------------------------------- /targets/tor_switch/tests/CLI_tests/Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS} -I m4 2 | 3 | TESTS = \ 4 | table_dump_old.test \ 5 | table_dump.test \ 6 | table_dump_extra.test \ 7 | indirect_res.test \ 8 | mc_dump.test 9 | 10 | # run_one_test.py.in included by default 11 | # note that we do not distribute the P4 files on purpose (there is no point), 12 | # even though they are checked in 13 | EXTRA_DIST = \ 14 | table_dump_old.test \ 15 | testdata/table_dump_old.in \ 16 | testdata/table_dump_old.out \ 17 | table_dump.test \ 18 | testdata/table_dump.in \ 19 | testdata/table_dump.out \ 20 | testdata/ecmp.json \ 21 | table_dump_extra.test \ 22 | testdata/table_dump_extra.in \ 23 | testdata/table_dump_extra.out \ 24 | testdata/table_dump_extra.json \ 25 | indirect_res.test \ 26 | testdata/indirect_res.in \ 27 | testdata/indirect_res.out \ 28 | testdata/indirect_res.json \ 29 | mc_dump.test \ 30 | testdata/mc_dump.in \ 31 | testdata/mc_dump.out 32 | -------------------------------------------------------------------------------- /targets/optical_switch/tests/CLI_tests/Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS} -I m4 2 | 3 | TESTS = \ 4 | table_dump_old.test \ 5 | table_dump.test \ 6 | table_dump_extra.test \ 7 | indirect_res.test \ 8 | mc_dump.test 9 | 10 | # run_one_test.py.in included by default 11 | # note that we do not distribute the P4 files on purpose (there is no point), 12 | # even though they are checked in 13 | EXTRA_DIST = \ 14 | table_dump_old.test \ 15 | testdata/table_dump_old.in \ 16 | testdata/table_dump_old.out \ 17 | table_dump.test \ 18 | testdata/table_dump.in \ 19 | testdata/table_dump.out \ 20 | testdata/ecmp.json \ 21 | table_dump_extra.test \ 22 | testdata/table_dump_extra.in \ 23 | testdata/table_dump_extra.out \ 24 | testdata/table_dump_extra.json \ 25 | indirect_res.test \ 26 | testdata/indirect_res.in \ 27 | testdata/indirect_res.out \ 28 | testdata/indirect_res.json \ 29 | mc_dump.test \ 30 | testdata/mc_dump.in \ 31 | testdata/mc_dump.out 32 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | %SPHINXBUILD% >NUL 2>NUL 14 | if errorlevel 9009 ( 15 | echo. 16 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 17 | echo.installed, then set the SPHINXBUILD environment variable to point 18 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 19 | echo.may add the Sphinx directory to PATH. 20 | echo. 21 | echo.If you don't have Sphinx installed, grab it from 22 | echo.https://www.sphinx-doc.org/ 23 | exit /b 1 24 | ) 25 | 26 | if "%1" == "" goto help 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /openoptics/dashboard/dashboardapp/simulate_push.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Max-Planck-Gesellschaft zur Förderung der Wissenschaften e.V. 2 | # Developed at the Max Planck Institute for Informatics, Network and Cloud Systems Group 3 | # 4 | # Author: Yiming Lei (ylei@mpi-inf.mpg.de) 5 | # 6 | # This software is licensed for non-commercial scientific research purposes only. 7 | # 8 | # License text: Creative Commons NC BY SA 4.0 9 | # https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en 10 | 11 | from channels.layers import get_channel_layer 12 | from asgiref.sync import async_to_sync 13 | 14 | channel_layer = get_channel_layer() 15 | async_to_sync(channel_layer.group_send)( 16 | "metrics", 17 | { 18 | "type": "send.metric", 19 | "data": { 20 | "device_name": "tor0", 21 | "label": "(0,0)", 22 | "epoch": 1, 23 | "timestep": 5, 24 | "depth": 20, 25 | "loss_ctr": 0.05, 26 | }, 27 | }, 28 | ) 29 | -------------------------------------------------------------------------------- /targets/tor_switch/tests/main.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright 2013-present Barefoot Networks, Inc. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | /* 17 | * Antonin Bas (antonin@barefootnetworks.com) 18 | * 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | bool WITH_VALGRIND = false; 28 | 29 | int main(int argc, char* argv[]) { 30 | ::testing::InitGoogleTest(&argc, argv); 31 | return RUN_ALL_TESTS(); 32 | } 33 | -------------------------------------------------------------------------------- /targets/optical_switch/tests/main.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright 2013-present Barefoot Networks, Inc. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | /* 17 | * Antonin Bas (antonin@barefootnetworks.com) 18 | * 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | bool WITH_VALGRIND = false; 28 | 29 | int main(int argc, char* argv[]) { 30 | ::testing::InitGoogleTest(&argc, argv); 31 | return RUN_ALL_TESTS(); 32 | } 33 | -------------------------------------------------------------------------------- /targets/optical_switch/optical_switch_CLI.in: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright 2013-present Barefoot Networks, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | # 18 | # Antonin Bas (antonin@barefootnetworks.com) 19 | # 20 | # 21 | 22 | # This is just a wrapper script around sswitch_CLI.py 23 | # It makes sure that the script works correctly no matter where Python 24 | # dependencies are installed 25 | 26 | import sys 27 | sys.path.append("@pythondir@") 28 | 29 | import oswitch_CLI 30 | oswitch_CLI.main() -------------------------------------------------------------------------------- /targets/tor_switch/tor_switch_CLI.in: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright 2013-present Barefoot Networks, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | # 18 | # Antonin Bas (antonin@barefootnetworks.com) 19 | # 20 | # 21 | 22 | # This is just a wrapper script around tswitch_CLI.py 23 | # It makes sure that the script works correctly no matter where Python 24 | # dependencies are installed 25 | 26 | import sys 27 | sys.path.append("@pythondir@") 28 | 29 | import tswitch_CLI 30 | tswitch_CLI.main() 31 | -------------------------------------------------------------------------------- /examples/ta.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) 5 | 6 | from openoptics import Toolbox, OpticalTopo, OpticalRouting 7 | 8 | import threading 9 | 10 | stop_event = threading.Event() 11 | 12 | if __name__ == "__main__": 13 | nb_node = 4 14 | nb_link = 1 15 | 16 | net = Toolbox.BaseNetwork( 17 | name="TA", 18 | backend="Mininet", 19 | nb_node=nb_node, 20 | nb_link=nb_link, 21 | arch_mode="TA", 22 | use_webserver=True, 23 | ) 24 | 25 | circuits = OpticalTopo.static_topo(nb_node=nb_node, nb_link=nb_link) 26 | assert net.deploy_topo(circuits) 27 | 28 | paths = OpticalRouting.routing_direct_ta(net.get_topo()) 29 | 30 | net.deploy_routing(paths, routing_mode="Per-hop", arch_mode="TA", start_fresh=True) 31 | 32 | net.start_traffic_aware( 33 | OpticalTopo.bipartite_matching, 34 | OpticalRouting.routing_direct_ta, 35 | routing_mode="Per-hop", 36 | update_interval=2, 37 | ) 38 | -------------------------------------------------------------------------------- /openoptics/dashboard/dashboard/urls.py: -------------------------------------------------------------------------------- 1 | """dashboard URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/3.2/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | 17 | from django.contrib import admin 18 | from django.urls import path, include 19 | from django.conf import settings 20 | from django.conf.urls.static import static 21 | 22 | urlpatterns = [path("admin/", admin.site.urls), path("", include("dashboardapp.urls"))] 23 | 24 | urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) 25 | -------------------------------------------------------------------------------- /tutorials/6-traffic-aware-1.py: -------------------------------------------------------------------------------- 1 | ########################################################################################## 2 | # For detailed instructions: https://openoptics.mpi-inf.mpg.de/tutorials/6-traffic-aware.html 3 | ########################################################################################## 4 | 5 | from openoptics import Toolbox, OpticalTopo, OpticalRouting 6 | 7 | import threading 8 | 9 | stop_event = threading.Event() 10 | 11 | if __name__ == "__main__": 12 | nb_node = 4 13 | nb_link = 1 14 | 15 | net = Toolbox.BaseNetwork( 16 | name="task6-ta", 17 | backend="Mininet", 18 | nb_node=nb_node, 19 | nb_link=nb_link, 20 | arch_mode="TA", 21 | use_webserver=True, 22 | ) 23 | 24 | circuits = OpticalTopo.static_topo(nb_node=nb_node, nb_link=nb_link) 25 | assert net.deploy_topo(circuits) 26 | 27 | paths = OpticalRouting.routing_direct_ta(net.get_topo()) 28 | 29 | net.deploy_routing(paths, routing_mode="Per-hop", arch_mode="TA", start_fresh=True) 30 | 31 | net.start_traffic_aware( 32 | update_interval=2, 33 | ) 34 | -------------------------------------------------------------------------------- /tutorials/6-traffic-aware-2.py: -------------------------------------------------------------------------------- 1 | ########################################################################################## 2 | # For detailed instructions: https://openoptics.mpi-inf.mpg.de/tutorials/6-traffic-aware.html 3 | ########################################################################################## 4 | 5 | from openoptics import Toolbox, OpticalTopo, OpticalRouting 6 | 7 | import threading 8 | 9 | stop_event = threading.Event() 10 | 11 | if __name__ == "__main__": 12 | nb_node = 4 13 | nb_link = 1 14 | 15 | net = Toolbox.BaseNetwork( 16 | name="task6-ta", 17 | backend="Mininet", 18 | nb_node=nb_node, 19 | nb_link=nb_link, 20 | arch_mode="TA", 21 | use_webserver=True, 22 | ) 23 | 24 | circuits = OpticalTopo.static_topo(nb_node=nb_node, nb_link=nb_link) 25 | assert net.deploy_topo(circuits) 26 | 27 | paths = OpticalRouting.routing_direct_ta(net.get_topo()) 28 | 29 | net.deploy_routing(paths, routing_mode="Per-hop", arch_mode="TA", start_fresh=True) 30 | 31 | net.start_traffic_aware( 32 | OpticalTopo.bipartite_matching, 33 | OpticalRouting.routing_direct_ta, 34 | routing_mode="Per-hop", 35 | update_interval=2, 36 | ) 37 | -------------------------------------------------------------------------------- /tutorials/1-get-started.py: -------------------------------------------------------------------------------- 1 | ########################################################################################## 2 | # In this task, you will 3 | # (1) Run a pre-defined script to deploy a simple optical DCN. 4 | # (2) Open dashboard on http://localhost:8001 to check topology and real time queue depth. 5 | # (3) Test the network with ping to check reachability and delay. 6 | # e.g. `h0 ping h1` # Equvilent to execute "ping h1" at h0 7 | # (4) Modify slice duration and observe change of ping delay and queue depth. 8 | # 9 | # Detailed instructions: https://openoptics.mpi-inf.mpg.de/tutorials/1-get-started.html 10 | ########################################################################################## 11 | 12 | from openoptics import Toolbox, OpticalTopo, OpticalRouting 13 | 14 | if __name__ == "__main__": 15 | nb_node = 8 16 | 17 | net = Toolbox.BaseNetwork( 18 | name="task1", 19 | backend="Mininet", 20 | nb_node=nb_node, 21 | nb_host_per_tor=1, 22 | time_slice_duration_ms=512, # in ms 23 | use_webserver=True, 24 | ) 25 | 26 | circuits = OpticalTopo.round_robin(nb_node=nb_node) 27 | assert net.deploy_topo(circuits) 28 | 29 | paths = OpticalRouting.routing_direct(net.get_topo()) 30 | assert net.deploy_routing(paths) 31 | 32 | net.start() 33 | -------------------------------------------------------------------------------- /targets/tor_switch/tests/CLI_tests/testdata/table_dump_old.out: -------------------------------------------------------------------------------- 1 | ???? 2 | 0 3 | ???? 4 | Group has been created with handle 0 5 | ???? 6 | Member has been created with handle 0 7 | ???? 8 | Adding entry to indirect match table ecmp_group 9 | Entry has been added with handle 0 10 | ???? 11 | ???? 12 | Adding entry to indirect match table ecmp_group 13 | Entry has been added with handle 1 14 | ???? 15 | ========== 16 | TABLE ENTRIES 17 | ********** 18 | Dumping entry 0x0 19 | Match key: 20 | * ipv4.dstAddr : LPM 0a000001/12 21 | Index: member(0) 22 | ********** 23 | Dumping entry 0x1 24 | Match key: 25 | * ipv4.dstAddr : LPM 0a000101/32 26 | Index: group(0) 27 | ========== 28 | MEMBERS 29 | ********** 30 | Dumping member 0 31 | Action entry: set_nhop - 0a000001, 01 32 | ========== 33 | GROUPS 34 | ********** 35 | Dumping group 0 36 | Members: [0] 37 | ========== 38 | Dumping default entry 39 | EMPTY 40 | ========== 41 | ???? 42 | 2 43 | ???? 44 | Dumping entry 0x0 45 | Match key: 46 | * ipv4.dstAddr : LPM 0a000001/12 47 | Index: member(0) 48 | ???? 49 | Dumping member 0 50 | Action entry: set_nhop - 0a000001, 01 51 | ???? 52 | Dumping group 0 53 | Members: [0] 54 | ???? 55 | Dumping entry 0x0 56 | Match key: 57 | * ipv4.dstAddr : LPM 0a000001/12 58 | Index: member(0) 59 | ???? 60 | ???? 61 | 0 62 | ???? 63 | -------------------------------------------------------------------------------- /docs/examples/example_src/vlb.rst: -------------------------------------------------------------------------------- 1 | Valiant Load Balancing (VLB) 2 | ============================ 3 | 4 | VLB [1]_ is an oblivious routing scheme that achieves provably optimal load balancing in some settings. 5 | VLB itself and its variants are used in many traffic-oblivious optical DCN architectures, such as RotorNet [2]_, Opera [3]_, and Sirius [4]_. 6 | In vanilla VLB, packets are first routed to an intermediate node selected randomly to achieve load balancing, 7 | and then forwarded to the final destination node through a direct connection. 8 | You can use the :py:meth:`openoptics.OpticalRouting.routing_vlb` function to configure VLB routing. 9 | 10 | .. literalinclude:: ../../../examples/routing_vlb.py 11 | :language: python 12 | :linenos: 13 | :caption: examples/routing_vlb.py 14 | 15 | .. [1] `Universal schemes for parallel communication `_, STOC'81 16 | .. [2] `RotorNet: A Scalable, Low-complexity, Optical Datacenter Network `_, SIGCOMM'17 17 | .. [3] `Expanding across time to deliver bandwidth efficiency and low latency `_, NSDI'20 18 | .. [4] `Sirius: A Flat Datacenter Network with Nanosecond Optical Switching `_, SIGCOMM'20 19 | -------------------------------------------------------------------------------- /targets/optical_switch/tests/CLI_tests/testdata/table_dump_old.out: -------------------------------------------------------------------------------- 1 | ???? 2 | 0 3 | ???? 4 | Group has been created with handle 0 5 | ???? 6 | Member has been created with handle 0 7 | ???? 8 | Adding entry to indirect match table ecmp_group 9 | Entry has been added with handle 0 10 | ???? 11 | ???? 12 | Adding entry to indirect match table ecmp_group 13 | Entry has been added with handle 1 14 | ???? 15 | ========== 16 | TABLE ENTRIES 17 | ********** 18 | Dumping entry 0x0 19 | Match key: 20 | * ipv4.dstAddr : LPM 0a000001/12 21 | Index: member(0) 22 | ********** 23 | Dumping entry 0x1 24 | Match key: 25 | * ipv4.dstAddr : LPM 0a000101/32 26 | Index: group(0) 27 | ========== 28 | MEMBERS 29 | ********** 30 | Dumping member 0 31 | Action entry: set_nhop - 0a000001, 01 32 | ========== 33 | GROUPS 34 | ********** 35 | Dumping group 0 36 | Members: [0] 37 | ========== 38 | Dumping default entry 39 | EMPTY 40 | ========== 41 | ???? 42 | 2 43 | ???? 44 | Dumping entry 0x0 45 | Match key: 46 | * ipv4.dstAddr : LPM 0a000001/12 47 | Index: member(0) 48 | ???? 49 | Dumping member 0 50 | Action entry: set_nhop - 0a000001, 01 51 | ???? 52 | Dumping group 0 53 | Members: [0] 54 | ???? 55 | Dumping entry 0x0 56 | Match key: 57 | * ipv4.dstAddr : LPM 0a000001/12 58 | Index: member(0) 59 | ???? 60 | ???? 61 | 0 62 | ???? 63 | -------------------------------------------------------------------------------- /tutorials/2-connect.py: -------------------------------------------------------------------------------- 1 | ########################################################################################## 2 | # In this task, you will: 3 | # (1) Use the connect API to create a 4-node topology, 4 | # (2) such that: 5 | # • In each time slice, each node connects to one other node (because each node only has one link). 6 | # • Across all time slices, each node connects every other node once. 7 | # You can check the visualized topology via the dashboard on http://localhost:8001 8 | # 9 | # Detailed instructions: https://openoptics.mpi-inf.mpg.de/tutorials/2-connect.html 10 | ########################################################################################## 11 | 12 | from openoptics import Toolbox 13 | 14 | if __name__ == "__main__": 15 | net = Toolbox.BaseNetwork( 16 | name="task2", 17 | backend="Mininet", 18 | nb_node=4, 19 | time_slice_duration_ms=256, # in ms 20 | use_webserver=True, 21 | ) 22 | ########################################## 23 | # Modification starts from here: 24 | 25 | # Create your topology schedule with net.connect() 26 | # Nodes are indexed as 0, 1, 2, 3 27 | net.connect(time_slice=0, node1=0, node2=1) 28 | 29 | # Modification ends here. 30 | ########################################## 31 | 32 | net.deploy_topo() 33 | 34 | net.start() 35 | -------------------------------------------------------------------------------- /docs/installation.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | ## I just wanna give it a try 4 | 5 | If you want to try out OpenOptics, the easiest way is to use the pre-built Docker image. 6 | Please refer to [Quick Start](quickstart.rst). 7 | 8 | ## Build OpenOptics from Source 9 | 10 | [BMv2](https://github.com/p4lang/behavioral-model) is the P4-programmable reference software switch required by the Mininet backend. 11 | OpenOptics contains two custom BMv2 targets in the `targets/` directory, and their accompanying compiled P4 files in the `p4/` directory. To build BMv2 for OpenOptics: 12 | 13 | 1. Clone the BMv2 repo and move it into the OpenOptics directory 14 | 2. Checkout commit 8e183a39b372cb9dc563e9d0cf593323249cd88b of BMv2 15 | 3. Copy the `optical_switch` and `tor_switch` target directories into the `behavioral-model/targets/` directory 16 | 4. Install BMv2's dependencies, either by manually following the instructions in BMv2's README, or by running the script `behavioral-model/install_deps.sh` 17 | 5. Replace `behavioral-model/configure.ac` with `targets/configure.ac` 18 | 6. Replace `behavioral-model/targets/Makefile.am` with `targets/Makefile.am` 19 | 7. `cd` into `behavioral-model/` and compile BMv2 by running: 20 | ``` 21 | ./autogen.sh && ./configure && make -j8 22 | ``` 23 | 8. Install OpenOptics' Python dependencies by navigating to `src/` and running: 24 | ``` 25 | pip3 install . 26 | ``` -------------------------------------------------------------------------------- /docs/tutorials/2-connect.md: -------------------------------------------------------------------------------- 1 | # Tutorial 2: Connect Nodes with Time-Sliced Topologies 2 | 3 | In optical DCNs, topologies are determined by the internal connections of optical circuit switches (OCS). 4 | 5 | As in the following figure: 6 | 7 | ![Architecture](../../assets/arch.png) 8 | 9 | With OpenOptics, you can define a **topology schedule** that specifies how electrical nodes (e.g., ToRs in the figure) connect to each other over time. 10 | This schedule will be executed repeatedly, one after another. 11 | 12 | The primitive API is: 13 | 14 | ```python 15 | connect(time_slice, node1, node2) 16 | ``` 17 | 18 | This primitive API lets you add an entry to the topology schedule to connect node1 and node2 in the given time slice. 19 | 20 | ## Your Tasks 21 | 22 | You will: 23 | 1. Use the {doc}`connect()<../apis/generated/openoptics.Toolbox.BaseNetwork.connect>` API to create a **4-node** topology schedule, 24 | 2. Ensure the following: 25 | - In each time slice, each node connects to exactly one other node (i.e. each node has one link) 26 | - Across all time slices, every node connects to every other node **exactly once**. 27 | 28 | This schedule guarantees that, over a period of time, each node can directly communicate with all other nodes. 29 | 30 | You will implement your solution in `openoptics/tutorial/2-connect.py`. 31 | Run the script to generate and visualize your topology schedule on the dashboard: 32 | 33 | ```python 34 | python3 2-connect.py 35 | ``` -------------------------------------------------------------------------------- /docs/apis_index.rst: -------------------------------------------------------------------------------- 1 | APIs 2 | ========================== 3 | 4 | 5 | Network Configurations 6 | ------------------------- 7 | 8 | - Basic functions needed by the network configuring workflow. 9 | 10 | .. toctree:: 11 | :maxdepth: 1 12 | 13 | apis/basenetwork 14 | 15 | 16 | Time Flow Table 17 | ------------------------- 18 | 19 | - Time flow table and Path defination for unifying diverse routings. 20 | 21 | .. toctree:: 22 | :maxdepth: 1 23 | 24 | apis/timeflowtable 25 | 26 | Optical Topology Library 27 | ------------------------- 28 | 29 | - Library functions for optical topology generation. 30 | 31 | .. toctree:: 32 | :maxdepth: 1 33 | 34 | apis/topo 35 | 36 | 37 | Optical Routing Library 38 | ------------------------- 39 | 40 | - Library functions for optical routing generation. 41 | 42 | .. toctree:: 43 | :maxdepth: 1 44 | 45 | apis/routing 46 | 47 | .. 48 | Dashboard 49 | ------------------------- 50 | - OpenOptics Dashboard 51 | 52 | .. toctree:: 53 | :maxdepth: 1 54 | 55 | apis/dashboard 56 | 57 | 58 | DeviceManager 59 | ------------------------- 60 | - OpenOptics device manager for monitoring and pausable queue management. 61 | 62 | .. toctree:: 63 | :maxdepth: 1 64 | 65 | apis/devicemanager 66 | 67 | Utils 68 | ------------------------- 69 | - OpenOptics utility functions. 70 | 71 | .. toctree:: 72 | :maxdepth: 1 73 | 74 | apis/utils -------------------------------------------------------------------------------- /openoptics/dashboard/dashboardapp/consumers.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Max-Planck-Gesellschaft zur Förderung der Wissenschaften e.V. 2 | # Developed at the Max Planck Institute for Informatics, Network and Cloud Systems Group 3 | # 4 | # Author: Yiming Lei (ylei@mpi-inf.mpg.de) 5 | # 6 | # This software is licensed for non-commercial scientific research purposes only. 7 | # 8 | # License text: Creative Commons NC BY SA 4.0 9 | # https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en 10 | 11 | import json 12 | from channels.generic.websocket import AsyncWebsocketConsumer 13 | 14 | 15 | class MetricConsumer(AsyncWebsocketConsumer): 16 | """ 17 | A consumer that accepts WebSocket connections on the path /ws/metrics/ 18 | """ 19 | 20 | async def connect(self): 21 | self.group_name = "metric_updates_group" 22 | await self.channel_layer.group_add(self.group_name, self.channel_name) 23 | await self.accept() 24 | 25 | async def disconnect(self, close_code): 26 | await self.channel_layer.group_discard(self.group_name, self.channel_name) 27 | 28 | async def receive(self, text_data): 29 | """ 30 | Receive data from WebSocket 31 | """ 32 | pass 33 | 34 | async def send_update_to_websocket(self, event): 35 | """ 36 | Send new data to html via WebSocket. Triggered by model updates (models.py:new_metric) 37 | """ 38 | data = event["data"] 39 | await self.send(text_data=json.dumps(data)) 40 | -------------------------------------------------------------------------------- /targets/tor_switch/tests/CLI_tests/testdata/indirect_res.p4: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013-present Barefoot Networks, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | parser start { 18 | return ingress; 19 | } 20 | 21 | header_type meta_t { 22 | fields { 23 | f : 32; 24 | } 25 | } 26 | 27 | header meta_t meta; 28 | 29 | counter my_indirect_counter { 30 | type: packets; 31 | static: m_table; 32 | instance_count: 16; 33 | } 34 | 35 | meter my_indirect_meter { 36 | type: packets; 37 | static: m_table; 38 | instance_count: 16; 39 | } 40 | 41 | register my_register { 42 | width: 32; 43 | static: m_table; 44 | instance_count: 16; 45 | } 46 | 47 | action m_action() { 48 | count(my_indirect_counter, 1); 49 | execute_meter(my_indirect_meter, 1, meta.f); 50 | register_write(my_register, 1, 0xab); 51 | } 52 | 53 | table m_table { 54 | actions { m_action; } 55 | size : 1024; 56 | } 57 | 58 | control ingress { 59 | apply(m_table); 60 | } 61 | 62 | control egress { 63 | } 64 | -------------------------------------------------------------------------------- /targets/optical_switch/tests/CLI_tests/testdata/indirect_res.p4: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013-present Barefoot Networks, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | parser start { 18 | return ingress; 19 | } 20 | 21 | header_type meta_t { 22 | fields { 23 | f : 32; 24 | } 25 | } 26 | 27 | header meta_t meta; 28 | 29 | counter my_indirect_counter { 30 | type: packets; 31 | static: m_table; 32 | instance_count: 16; 33 | } 34 | 35 | meter my_indirect_meter { 36 | type: packets; 37 | static: m_table; 38 | instance_count: 16; 39 | } 40 | 41 | register my_register { 42 | width: 32; 43 | static: m_table; 44 | instance_count: 16; 45 | } 46 | 47 | action m_action() { 48 | count(my_indirect_counter, 1); 49 | execute_meter(my_indirect_meter, 1, meta.f); 50 | register_write(my_register, 1, 0xab); 51 | } 52 | 53 | table m_table { 54 | actions { m_action; } 55 | size : 1024; 56 | } 57 | 58 | control ingress { 59 | apply(m_table); 60 | } 61 | 62 | control egress { 63 | } 64 | -------------------------------------------------------------------------------- /tutorials/solutions/2-connect-solution.py: -------------------------------------------------------------------------------- 1 | ########################################################################################## 2 | # In this task, you will: 3 | # (1) Use the connect API to create a 4-node topology, 4 | # (2) such that: 5 | # • In each time slice, each node connects to one other node (because each node only has one link). 6 | # • Across all time slices, each node connects every other node once. 7 | # You can check the visualized topology via the dashboard on http://localhost:8001 8 | ########################################################################################## 9 | 10 | from openoptics import Toolbox 11 | 12 | if __name__ == "__main__": 13 | net = Toolbox.BaseNetwork( 14 | name="task2", 15 | backend="Mininet", 16 | nb_node=4, 17 | nb_link=1, 18 | time_slice_duration_ms=256, # in ms 19 | use_webserver=True, 20 | ) 21 | 22 | ########################################## 23 | # Modification starts from here: 24 | 25 | # Create your topology schedule with net.connect() 26 | # Nodes are indexed as 0, 1, 2, 3 27 | net.connect(time_slice=0, node1=0, node2=1) 28 | net.connect(time_slice=0, node1=2, node2=3) 29 | 30 | net.connect(time_slice=1, node1=0, node2=2) 31 | net.connect(time_slice=1, node1=1, node2=3) 32 | 33 | net.connect(time_slice=2, node1=0, node2=3) 34 | net.connect(time_slice=2, node1=1, node2=2) 35 | # Modification ends here. 36 | ########################################## 37 | 38 | net.deploy_topo() 39 | 40 | net.start() 41 | -------------------------------------------------------------------------------- /targets/tor_switch/tests/Makefile.am: -------------------------------------------------------------------------------- 1 | if COND_THRIFT 2 | MAYBE_CLI_TESTS = CLI_tests 3 | endif 4 | 5 | SUBDIRS = . $(MAYBE_CLI_TESTS) 6 | 7 | AM_CPPFLAGS += \ 8 | -isystem $(top_srcdir)/third_party/gtest/include \ 9 | -I$(srcdir)/.. \ 10 | -I$(srcdir)/ \ 11 | -DTESTDATADIR=\"$(srcdir)/testdata\" 12 | LDADD = $(builddir)/../libtorswitch.la \ 13 | $(top_builddir)/third_party/gtest/libgtest.la \ 14 | $(top_builddir)/src/bm_apps/libbmapps.la \ 15 | -lboost_filesystem 16 | 17 | # Define unit tests 18 | common_source = main.cpp utils.cpp utils.h 19 | TESTS = test_packet_redirect \ 20 | test_truncate \ 21 | test_swap \ 22 | test_queueing \ 23 | test_recirc \ 24 | test_parser_error 25 | 26 | check_PROGRAMS = $(TESTS) test_all 27 | 28 | # Sources for tests 29 | test_packet_redirect_SOURCES = $(common_source) test_packet_redirect.cpp 30 | test_truncate_SOURCES = $(common_source) test_truncate.cpp 31 | test_swap_SOURCES = $(common_source) test_swap.cpp 32 | test_queueing_SOURCES = $(common_source) test_queueing.cpp 33 | test_recirc_SOURCES = $(common_source) test_recirc.cpp 34 | test_parser_error_SOURCES = $(common_source) test_parser_error.cpp 35 | 36 | test_all_SOURCES = $(common_source) \ 37 | test_packet_redirect.cpp \ 38 | test_truncate.cpp \ 39 | test_swap.cpp \ 40 | test_queueing.cpp \ 41 | test_recirc.cpp \ 42 | test_parser_error.cpp 43 | 44 | EXTRA_DIST = \ 45 | testdata/packet_redirect.json \ 46 | testdata/truncate.json \ 47 | testdata/swap_1.json \ 48 | testdata/swap_2.json \ 49 | testdata/queueing.json \ 50 | testdata/recirc.json \ 51 | testdata/parser_error.p4 \ 52 | testdata/parser_error.json 53 | -------------------------------------------------------------------------------- /targets/optical_switch/tests/Makefile.am: -------------------------------------------------------------------------------- 1 | if COND_THRIFT 2 | MAYBE_CLI_TESTS = CLI_tests 3 | endif 4 | 5 | SUBDIRS = . $(MAYBE_CLI_TESTS) 6 | 7 | AM_CPPFLAGS += \ 8 | -isystem $(top_srcdir)/third_party/gtest/include \ 9 | -I$(srcdir)/.. \ 10 | -I$(srcdir)/ \ 11 | -DTESTDATADIR=\"$(srcdir)/testdata\" 12 | LDADD = $(builddir)/../libtorswitch.la \ 13 | $(top_builddir)/third_party/gtest/libgtest.la \ 14 | $(top_builddir)/src/bm_apps/libbmapps.la \ 15 | -lboost_filesystem 16 | 17 | # Define unit tests 18 | common_source = main.cpp utils.cpp utils.h 19 | TESTS = test_packet_redirect \ 20 | test_truncate \ 21 | test_swap \ 22 | test_queueing \ 23 | test_recirc \ 24 | test_parser_error 25 | 26 | check_PROGRAMS = $(TESTS) test_all 27 | 28 | # Sources for tests 29 | test_packet_redirect_SOURCES = $(common_source) test_packet_redirect.cpp 30 | test_truncate_SOURCES = $(common_source) test_truncate.cpp 31 | test_swap_SOURCES = $(common_source) test_swap.cpp 32 | test_queueing_SOURCES = $(common_source) test_queueing.cpp 33 | test_recirc_SOURCES = $(common_source) test_recirc.cpp 34 | test_parser_error_SOURCES = $(common_source) test_parser_error.cpp 35 | 36 | test_all_SOURCES = $(common_source) \ 37 | test_packet_redirect.cpp \ 38 | test_truncate.cpp \ 39 | test_swap.cpp \ 40 | test_queueing.cpp \ 41 | test_recirc.cpp \ 42 | test_parser_error.cpp 43 | 44 | EXTRA_DIST = \ 45 | testdata/packet_redirect.json \ 46 | testdata/truncate.json \ 47 | testdata/swap_1.json \ 48 | testdata/swap_2.json \ 49 | testdata/queueing.json \ 50 | testdata/recirc.json \ 51 | testdata/parser_error.p4 \ 52 | testdata/parser_error.json 53 | -------------------------------------------------------------------------------- /docs/tutorials/5-multi-hop-routing.md: -------------------------------------------------------------------------------- 1 | # Tutorial 5: Multi-Hop Routing with Time Flow Tables 2 | 3 | In the previous task, packets were always sent from the source to the destination through the next available direct connection. 4 | Now we till try something different, **multi-hop routing**, where packets are forwarded through intermediate nodes when a direct path is not immediately available. 5 | 6 | Consider the following topology schedule: 7 | 8 | ![topo](../../assets/example_connect.png) 9 | 10 | Suppose `h0` wants to send a packet to `h1` at time slice 1. 11 | With the direct routing you implemented earlier, the packet cannot be transmitted until time slice 0 of the next cycle, when a direct connection between `h0` and `h1` exists. 12 | 13 | But with multi-hop routing, the packet can be sent from `h0` to `h2` at time slice 1, and then forwarded from `h2` to `h1` at time slice 2. 14 | This allows earlier delivery by leveraging intermediate nodes. 15 | 16 | ## Your Tasks 17 | 18 | You will implement **multi-hop routing** with time flow tables in your optical DCN: 19 | 20 | 1. Add time flow table entries to enable routing between `h0` and `h1` (You don't have to add time flow table entries for routing packets between any other node pairs but feel free to do so if you wish). 21 | 2. Verify that in the `ping` test, no packet loss occurs. 22 | 3. Compare the `ping` RTT with that of direct routing. Is the result what you expected? Why or why not? 23 | 24 | Run the script with: 25 | ```python 26 | python3 5-multi-hop-routing.py 27 | ``` 28 | 29 | Then, in the CLI, test your solution with 30 | ``` 31 | OpenOptics> h0 ping h1 32 | ``` -------------------------------------------------------------------------------- /targets/tor_switch/bm/tor_switch/runner.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2018-present Barefoot Networks, Inc. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | /* 17 | * Antonin Bas (antonin@barefootnetworks.com) 18 | * 19 | */ 20 | 21 | #ifndef TOR_SWITCH_BM_TOR_SWITCH_RUNNER_H_ 22 | #define TOR_SWITCH_BM_TOR_SWITCH_RUNNER_H_ 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | class TorSwitch; 32 | 33 | namespace bm { 34 | 35 | namespace sswitch { 36 | 37 | class TorSwitchRunner { 38 | public: 39 | static constexpr uint32_t default_drop_port = 511; 40 | 41 | explicit TorSwitchRunner(uint32_t cpu_port = 0, 42 | uint32_t drop_port = default_drop_port); 43 | ~TorSwitchRunner(); 44 | 45 | int init_and_start(const bm::OptionsParser &parser); 46 | 47 | device_id_t get_device_id() const; 48 | 49 | DevMgr *get_dev_mgr(); 50 | 51 | private: 52 | uint32_t cpu_port{0}; 53 | std::unique_ptr tor_switch; 54 | }; 55 | 56 | } // namespace sswitch 57 | 58 | } // namespace bm 59 | 60 | #endif // TOR_SWITCH_BM_TOR_SWITCH_RUNNER_H_ 61 | -------------------------------------------------------------------------------- /targets/optical_switch/bm/optical_switch/runner.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2018-present Barefoot Networks, Inc. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | /* 17 | * Antonin Bas (antonin@barefootnetworks.com) 18 | * 19 | */ 20 | 21 | #ifndef TOR_SWITCH_BM_TOR_SWITCH_RUNNER_H_ 22 | #define TOR_SWITCH_BM_TOR_SWITCH_RUNNER_H_ 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | class OpticalSwitch; 32 | 33 | namespace bm { 34 | 35 | namespace sswitch { 36 | 37 | class OpticalSwitchRunner { 38 | public: 39 | static constexpr uint32_t default_drop_port = 511; 40 | 41 | explicit OpticalSwitchRunner(uint32_t cpu_port = 0, 42 | uint32_t drop_port = default_drop_port); 43 | ~OpticalSwitchRunner(); 44 | 45 | int init_and_start(const bm::OptionsParser &parser); 46 | 47 | device_id_t get_device_id() const; 48 | 49 | DevMgr *get_dev_mgr(); 50 | 51 | private: 52 | uint32_t cpu_port{0}; 53 | std::unique_ptr optical_switch; 54 | }; 55 | 56 | } // namespace sswitch 57 | 58 | } // namespace bm 59 | 60 | #endif // TOR_SWITCH_BM_TOR_SWITCH_RUNNER_H_ 61 | -------------------------------------------------------------------------------- /tutorials/solutions/7-topologies-solution.py: -------------------------------------------------------------------------------- 1 | ########################################################################################## 2 | # Programming with low-level APIs can be tedious and error-prone. 3 | # This example demonstrates how to use OpenOptics' high-level APIs to 4 | # build optical data center networks (DCNs) with just a few lines of code. 5 | # 6 | # In this task, your challenge is to modify the round_robin topology functions 7 | # of use it to build your own topology function to reduce average RTT of a 8 | # cutomized application. 9 | ########################################################################################## 10 | 11 | from openoptics import Toolbox, OpticalTopo, OpticalRouting 12 | 13 | """ 14 | Circuit: 15 | [time_slice, node1, node2, port1, port2] 16 | """ 17 | 18 | def my_topology(nb_node): 19 | nodes = list(range(nb_node)) 20 | middle = nb_node // 2 21 | micro_ts = middle - 1 22 | 23 | circuits = [] 24 | circuits += OpticalTopo.round_robin(nodes=nodes[:middle], start_time_slice=0) 25 | circuits += OpticalTopo.round_robin(nodes=nodes[middle:], start_time_slice=0) 26 | circuits += OpticalTopo.round_robin(nodes=nodes, start_time_slice=micro_ts) 27 | 28 | return circuits 29 | 30 | if __name__ == "__main__": 31 | nb_node = 8 32 | nb_link = 1 33 | 34 | net = Toolbox.BaseNetwork( 35 | name="task7-topology", 36 | backend="Mininet", 37 | nb_node=nb_node, 38 | nb_link=nb_link, 39 | time_slice_duration_ms=128, # in ms 40 | use_webserver=True, 41 | ) 42 | 43 | circuits = my_topology(nb_node) 44 | assert net.deploy_topo(circuits) 45 | 46 | paths = OpticalRouting.routing_direct(net.get_topo()) 47 | assert net.deploy_routing(paths) 48 | 49 | net.start() 50 | -------------------------------------------------------------------------------- /tutorials/5-multi-hop-routing.py: -------------------------------------------------------------------------------- 1 | ########################################################################################## 2 | # So far, you have only used source routing, where the entire path is embedded 3 | # in the time flow table and included in the packet. 4 | # 5 | # In this task, you will implement multi-hop routing in per-hop path mode. 6 | # In this mode, packets do not carry the full path. Instead, each node (ToR) 7 | # uses its own per-hop time flow table to determine how to forward packets. 8 | # 9 | # Detailed instructions: https://openoptics.mpi-inf.mpg.de/tutorials/5-multi-hop-routing.html 10 | ########################################################################################## 11 | 12 | from openoptics import Toolbox 13 | from openoptics.TimeFlowTable import TimeFlowHop, TimeFlowEntry 14 | 15 | if __name__ == "__main__": 16 | net = Toolbox.BaseNetwork( 17 | name="task2", 18 | backend="Mininet", 19 | nb_node=4, 20 | time_slice_duration_ms=256, # in ms 21 | use_webserver=True, 22 | ) 23 | 24 | ########################################## 25 | # Modification starts from here: 26 | 27 | # Copy your topology here 28 | net.connect(node1=0, node2=1, time_slice=0) 29 | net.deploy_topo() 30 | 31 | # Create Entries for per-hop routing here 32 | node0_entries = [] 33 | node1_entries = [] 34 | node2_entries = [] 35 | node3_entries = [] 36 | 37 | net.add_time_flow_entry(node_id=0, entries=node0_entries) 38 | net.add_time_flow_entry(node_id=1, entries=node1_entries) 39 | net.add_time_flow_entry(node_id=2, entries=node2_entries) 40 | net.add_time_flow_entry(node_id=3, entries=node3_entries) 41 | 42 | # Modification ends here. 43 | ########################################## 44 | net.start() 45 | -------------------------------------------------------------------------------- /tutorials/4-time-flow-table.py: -------------------------------------------------------------------------------- 1 | ########################################################################################## 2 | # In this task, the goal is making ping work without packet loss. You will: 3 | # (1) Add usual flow table entries for node 0 and node 1, by setting send time slice (send_ts) 4 | # the same as arrival time slice (arrival_ts) 5 | # (2) Test reachability with ping: `h0 ping h1` 6 | # (3) Update flow table to time flow table - 7 | # adjust send_ts and arrival_ts according to time sliced topology. 8 | # (4) Test reachability again with ping: `h0 ping h1` 9 | # 10 | # Detailed instructions: https://openoptics.mpi-inf.mpg.de/tutorials/4-time-flow-table.html 11 | ########################################################################################## 12 | 13 | from openoptics import Toolbox 14 | from openoptics.TimeFlowTable import TimeFlowHop, TimeFlowEntry 15 | 16 | if __name__ == "__main__": 17 | net = Toolbox.BaseNetwork( 18 | name="task2", 19 | backend="Mininet", 20 | nb_node=4, 21 | time_slice_duration_ms=256, # in ms 22 | use_webserver=True, 23 | ) 24 | 25 | ########################################## 26 | # Modification starts from here: 27 | 28 | 29 | # Copy your topology here 30 | net.connect(time_slice=0, node1=0, node2=1) 31 | net.deploy_topo() 32 | 33 | # Add flow table entries here 34 | node0_entries = [ 35 | # An example: 36 | # As each node has only one link connected to OCS, always set send_port=0. 37 | TimeFlowEntry( 38 | dst=1, arrival_ts=0, 39 | hops=TimeFlowHop(send_port=0, send_ts=0) 40 | ), 41 | ] 42 | node1_entries = [] 43 | 44 | net.add_time_flow_entry(node_id=0, entries=node0_entries) 45 | net.add_time_flow_entry(node_id=1, entries=node1_entries) 46 | 47 | # Modification ends here. 48 | ########################################## 49 | 50 | net.start() 51 | -------------------------------------------------------------------------------- /examples/routing_add_entry.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) 5 | 6 | from openoptics import Toolbox 7 | from openoptics.TimeFlowTable import TimeFlowHop, TimeFlowEntry 8 | 9 | if __name__ == "__main__": 10 | nb_node = 4 11 | 12 | net = Toolbox.BaseNetwork( 13 | name="add_entry", 14 | backend="Mininet", 15 | nb_node=nb_node, 16 | time_slice_duration_ms=256, # in ms 17 | use_webserver=True, 18 | ) 19 | 20 | net.connect(node1=0, node2=1, time_slice=0) 21 | net.connect(node1=2, node2=3, time_slice=0) 22 | 23 | net.connect(node1=0, node2=2, time_slice=1) 24 | net.connect(node1=1, node2=3, time_slice=1) 25 | 26 | net.connect(node1=0, node2=3, time_slice=2) 27 | net.connect(node1=1, node2=2, time_slice=2) 28 | 29 | net.deploy_topo() 30 | 31 | node0_entries = [] 32 | node1_entries = [] 33 | 34 | node0_entries = [ 35 | TimeFlowEntry( 36 | dst=1, arrival_ts=0, hops=[TimeFlowHop(cur_node=0, send_ts=0, send_port=0)] 37 | ), 38 | TimeFlowEntry( 39 | dst=1, arrival_ts=1, hops=[TimeFlowHop(cur_node=0, send_ts=0, send_port=0)] 40 | ), 41 | TimeFlowEntry( 42 | dst=1, arrival_ts=2, hops=[TimeFlowHop(cur_node=0, send_ts=0, send_port=0)] 43 | ), 44 | ] 45 | 46 | node1_entries = [ 47 | TimeFlowEntry( 48 | dst=0, arrival_ts=0, hops=[TimeFlowHop(cur_node=1, send_ts=0, send_port=0)] 49 | ), 50 | TimeFlowEntry( 51 | dst=0, arrival_ts=1, hops=[TimeFlowHop(cur_node=1, send_ts=0, send_port=0)] 52 | ), 53 | TimeFlowEntry( 54 | dst=0, arrival_ts=2, hops=[TimeFlowHop(cur_node=1, send_ts=0, send_port=0)] 55 | ), 56 | ] 57 | 58 | net.add_time_flow_entry(node_id=0, entries=node0_entries, routing_mode="Source") 59 | net.add_time_flow_entry(node_id=1, entries=node1_entries, routing_mode="Source") 60 | 61 | net.start() 62 | -------------------------------------------------------------------------------- /docs/tutorials/6-traffic-aware.md: -------------------------------------------------------------------------------- 1 | # Tutorial 6: Workflow of Traffic-Aware Architectures 2 | 3 | So far, we have used **traffic-oblivious** architectures, where topology schedules are pre-defined and remain fixed regardless of the actual traffic. 4 | 5 | Another common approach in optical DCNs is **traffic-aware** topology, where the topology can change at runtime to better match the current traffic patterns. 6 | 7 | ## Manually Connect and Disconnect 8 | 9 | Let’s first try this manually. Run the following script: 10 | 11 | ```bash 12 | python3 6-traffic-aware-1.py 13 | ``` 14 | This script creates a network with one fixed topology, where only `h0-h3` and `h1-h2` are connected. 15 | 16 | Your task is to make `ping` work between h1 and h3 by using `connect` and `disconnect` commands in the OpenOptics CLI. 17 | 18 | ```bash 19 | OpenOptics> disconnect 20 | Usage: disconnect [] [ ] 21 | ``` 22 | Example: 23 | - `disconnect 1 0 3` 24 | - `disconnect 1 h0 h3` 25 | Both commands remove the connection at time slice `1` between `h0` and `h3`. 26 | 27 | 28 | and 29 | ```bash 30 | OpenOptics> connect 31 | Usage: connect [] [ ] 32 | ``` 33 | Example: 34 | - `connect 1 0 3` 35 | - `connect 1 h0 h3` 36 | Both commands add a connection at time slice `1` between `h0` and `h3`. 37 | 38 | 39 | ## Automatic Topology Generation 40 | 41 | Manual reconfiguration works, but it would be much better if the network could adapt automatically. 42 | 43 | The following script demonstrates this using `OpticalTopo.bipartite_matching` which generates topologies dynamically based on runtime traffic metrics, and using `net.start_traffic_aware(OpticalTopo.bipartite_matching, update_interval=2)` to configure topology update condition, e.g. every 2 seconds. 44 | 45 | Run the script with: 46 | ```bash 47 | python3 tutorials/6-traffic-aware-2.py 48 | ``` 49 | 50 | After starting the script, try `ping` between random pairs of nodes. 51 | Observe what happens in the dashboard and in the CLI. 52 | 53 | No source code changes are required for this task. -------------------------------------------------------------------------------- /tutorials/3-flow-table.py: -------------------------------------------------------------------------------- 1 | ########################################################################################## 2 | # You will now enable routing in your optical DCN: 3 | 4 | # 1. Add flow table entries for nodes 0 and 1 to enable routing between them. 5 | # 2. Test reachability with ping: `h0 ping h1`, check packets' sequence numbers `icmp_seq`, and reason the packet loss. 6 | # 3. To reduce packet loss, you could add flow table entries for nodes 2 and 3. 7 | # 4. Test reachability again with ping: `h0 ping h1`, and check icmp_seq now. 8 | # 9 | # Detailed instructions: https://openoptics.mpi-inf.mpg.de/tutorials/3-flow-table.html 10 | ########################################################################################## 11 | 12 | from openoptics import Toolbox 13 | from openoptics.TimeFlowTable import TimeFlowHop, TimeFlowEntry 14 | 15 | if __name__ == "__main__": 16 | net = Toolbox.BaseNetwork( 17 | name="task3", 18 | backend="Mininet", 19 | nb_node=4, 20 | time_slice_duration_ms=256, # in ms 21 | use_webserver=True, 22 | ) 23 | ########################################## 24 | # Modification starts from here: 25 | 26 | # Copy your topology here 27 | net.connect(node1=0, node2=1, time_slice=0) 28 | 29 | net.deploy_topo() # No need to change this line 30 | 31 | 32 | # Add flow table entries here 33 | 34 | node0_entries = [ 35 | # An example: 36 | # As each node has only one link connected to OCS, always set send_port=0. 37 | TimeFlowEntry(dst=1, hops=TimeFlowHop(send_port=0)), 38 | ] 39 | node1_entries = [] 40 | node2_entries = [] 41 | node3_entries = [] 42 | 43 | # Load flow table entries to ToR 0-3 44 | net.add_time_flow_entry(node_id=0, entries=node0_entries) 45 | net.add_time_flow_entry(node_id=1, entries=node1_entries) 46 | net.add_time_flow_entry(node_id=2, entries=node2_entries) 47 | net.add_time_flow_entry(node_id=3, entries=node3_entries) 48 | 49 | # Modification ends here. 50 | ########################################## 51 | 52 | net.start() 53 | -------------------------------------------------------------------------------- /tutorials/7-topologies.py: -------------------------------------------------------------------------------- 1 | ########################################################################################## 2 | # Programming with low-level APIs can be tedious and error-prone. 3 | # The following two tutorials demonstrate how to use OpenOptics' high-level APIs to 4 | # build optical data center networks (DCNs) with just a few lines of code. 5 | # 6 | # In this task, your challenge is to use the round_robin topology functions 7 | # to build your own topology function for a cutomized application. 8 | # 9 | # Detailed instructions: https://openoptics.mpi-inf.mpg.de/tutorials/7-topology.html 10 | ########################################################################################## 11 | 12 | from openoptics import Toolbox, OpticalTopo, OpticalRouting 13 | 14 | 15 | def my_topology(nb_node): 16 | 17 | nodes = list(range(nb_node)) 18 | circuits = [] 19 | """ 20 | A circuit: [time_slice, node1, node2, port1, port2] 21 | As each ToR has only one link, port1/port2 should be 0 (the first port). 22 | """ 23 | ########################################## 24 | # Modification starts from here: 25 | 26 | circuits += OpticalTopo.round_robin( 27 | nodes=nodes, # The nodes group to have round-robin topology 28 | start_time_slice=0 # The starting time slice of the round-robin topology 29 | ) 30 | 31 | # Modification ends here. 32 | ########################################## 33 | 34 | return circuits 35 | 36 | if __name__ == "__main__": 37 | nb_node = 8 38 | nb_link = 1 39 | 40 | net = Toolbox.BaseNetwork( 41 | name="task7-topology", 42 | backend="Mininet", 43 | nb_node=nb_node, 44 | nb_link=nb_link, 45 | time_slice_duration_ms=128, # in ms 46 | use_webserver=True, 47 | ) 48 | 49 | # No modifications needed here. 50 | # You are supposed to modify the implementation of my_topology function. 51 | 52 | circuits = my_topology(nb_node=nb_node) 53 | assert net.deploy_topo(circuits) 54 | 55 | paths = OpticalRouting.routing_direct(net.get_topo()) 56 | assert net.deploy_routing(paths) 57 | 58 | net.start() 59 | -------------------------------------------------------------------------------- /docs/tutorials/4-time-flow-table.md: -------------------------------------------------------------------------------- 1 | # Tutorial 4: Improve Routing with Time Flow Tables 2 | 3 | The previous routing is not ideal for optical DCNs because flow tables are not time-aware. 4 | Since an optical DCN operates with a **time-sliced topology**, the forwarding tables must also take **time** into account. 5 | 6 | Therefore, OpenOptics provides time flow table: 7 | ``` 8 | +------------------------------------- ------------------------------------+ 9 | | Match Fields || Action (forward) | 10 | +--------------------------------------||----------------------------------+ 11 | | Destination | Arrival Time Slice || Send Port | Send Time Slice | 12 | +--------------------------------------------------------------------------+ 13 | ``` 14 | 15 | Compared to the previous flow table, a time flow table has two additional fields: 16 | 17 | **Arrival Time Slice**: The time slice at which the packet arrives at the switch. 18 | 19 | **Send Time Slice**: The time slice at which the packet should be transmitted from the switch. 20 | 21 | 22 | ## Define Time Flow Table Entries in OpenOptics 23 | 24 | In OpenOptics, time flow table entry can be defined as: 25 | 26 | ```python 27 | TimeFlowEntry(dst=1, arrival_ts=0, hops=TimeFlowHop(send_port=0, send_ts=1)) 28 | ``` 29 | 30 | This means that packets destined for node 1 that arrive at the ToR at time slice 0 should be forwarded out of port 0 at time slice 1. 31 | 32 | ```{note} 33 | To enforce the such a time flow table, the underlying switch implementation should support buffering 34 | packet until a specified time slice. 35 | The switch implementation for the Mininet backend is a P4 software switch, [bmv2](https://github.com/p4lang/behavioral-model). 36 | OpenOptics is bundled with a modified version of bmv2 that supports time-based buffering. 37 | ``` 38 | 39 | ## Your Tasks 40 | 41 | You will improve the routing in your optical DCN: 42 | 43 | 1. Add time flow table entries for nodes 0 and 1 to enable routing between `h0` and `h1`. 44 | 2. Verify that in the `ping` test, no packet loss or reordering occurs. 45 | 46 | Run the script with: 47 | ```python 48 | python3 4-time-flow-table.py 49 | ``` 50 | 51 | Then, in the CLI, test your solution with 52 | ``` 53 | OpenOptics> h0 ping h1 54 | ``` -------------------------------------------------------------------------------- /targets/optical_switch/thrift/optical_switch.thrift: -------------------------------------------------------------------------------- 1 | /* Copyright 2013-present Barefoot Networks, Inc. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | /* 17 | * Antonin Bas (antonin@barefootnetworks.com) 18 | * 19 | */ 20 | 21 | namespace cpp oswitch_runtime 22 | namespace py oswitch_runtime 23 | 24 | struct MirroringSessionConfig { 25 | 1:optional i32 port; 26 | 2:optional i32 mgid; 27 | } 28 | 29 | enum MirroringOperationErrorCode { 30 | SESSION_NOT_FOUND = 1, 31 | } 32 | 33 | exception InvalidMirroringOperation { 34 | 1:MirroringOperationErrorCode code; 35 | } 36 | 37 | service OpticalSwitch { 38 | 39 | // deprecated, use the mirroring_session_* RPCs instead 40 | i32 mirroring_mapping_add(1:i32 mirror_id, 2:i32 egress_port); 41 | i32 mirroring_mapping_delete(1:i32 mirror_id); 42 | i32 mirroring_mapping_get_egress_port(1:i32 mirror_id); 43 | 44 | void mirroring_session_add(1:i32 mirror_id, 2:MirroringSessionConfig config) 45 | throws (1:InvalidMirroringOperation ouch); 46 | void mirroring_session_delete(1:i32 mirror_id) 47 | throws (1:InvalidMirroringOperation ouch); 48 | MirroringSessionConfig mirroring_session_get(1:i32 mirror_id) 49 | throws (1:InvalidMirroringOperation ouch); 50 | 51 | i32 set_egress_priority_queue_depth(1:i32 port_num, 2:i32 priority, 3:i32 depth_pkts); 52 | i32 set_egress_queue_depth(1:i32 port_num, 2:i32 depth_pkts); 53 | i32 set_all_egress_queue_depths(1:i32 depth_pkts); 54 | i32 set_egress_priority_queue_rate(1:i32 port_num, 2:i32 priority, 3:i64 rate_pps); 55 | i32 set_egress_queue_rate(1:i32 port_num, 2:i64 rate_pps); 56 | i32 set_all_egress_queue_rates(1:i64 rate_pps); 57 | 58 | // these methods are here as an experiment, prefer get_time_elapsed_us() when 59 | // possible 60 | i64 get_time_elapsed_us(); 61 | i64 get_time_since_epoch_us(); 62 | 63 | } 64 | -------------------------------------------------------------------------------- /openoptics/dashboard/dashboardapp/models.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Max-Planck-Gesellschaft zur Förderung der Wissenschaften e.V. 2 | # Developed at the Max Planck Institute for Informatics, Network and Cloud Systems Group 3 | # 4 | # Author: Yiming Lei (ylei@mpi-inf.mpg.de) 5 | # 6 | # This software is licensed for non-commercial scientific research purposes only. 7 | # 8 | # License text: Creative Commons NC BY SA 4.0 9 | # https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en 10 | 11 | from django.db import models 12 | from django.db.models.signals import post_save 13 | from django.dispatch import receiver 14 | from asgiref.sync import async_to_sync 15 | from channels.layers import get_channel_layer 16 | 17 | 18 | class Epochs(models.Model): 19 | display_name = models.CharField(max_length=100) 20 | topo_image = models.ImageField(upload_to="topos/") 21 | 22 | 23 | class UniformMetrics(models.Model): 24 | device_name = models.CharField(max_length=100) 25 | label = models.CharField(max_length=100) # (port,queue) or tor name 26 | depth = models.IntegerField() 27 | loss_ctr = models.FloatField() 28 | timestep = models.IntegerField() 29 | epoch = models.ForeignKey(Epochs, on_delete=models.CASCADE, related_name="metrics") 30 | 31 | 32 | @receiver(post_save, sender=Epochs) 33 | def new_topo(sender, instance, created, **kwargs): 34 | channel_layer = get_channel_layer() 35 | 36 | payload = {"type": "topo", "topo_image": instance.topo_image.url} 37 | 38 | async_to_sync(channel_layer.group_send)( 39 | "metric_updates_group", {"type": "send_update_to_websocket", "data": payload} 40 | ) 41 | 42 | 43 | # After saving DeviceMetrics, this functions is called to send data to websocket 44 | @receiver(post_save, sender=UniformMetrics) 45 | def new_metric(sender, instance, created, **kwargs): 46 | if not created: 47 | return # Only send on new insertions 48 | 49 | channel_layer = get_channel_layer() 50 | 51 | payload = { 52 | "type": "metric", 53 | "device_name": instance.device_name, 54 | "label": instance.label, 55 | "depth": instance.depth, 56 | "timestep": instance.timestep, 57 | "loss_ctr": instance.loss_ctr, 58 | "epoch": instance.epoch.id, 59 | } 60 | 61 | async_to_sync(channel_layer.group_send)( 62 | "metric_updates_group", {"type": "send_update_to_websocket", "data": payload} 63 | ) 64 | -------------------------------------------------------------------------------- /docs/tutorials/3-flow-table.md: -------------------------------------------------------------------------------- 1 | # Tutorial 3: Enable Routing with Flow Tables 2 | 3 | After setting up the time-sliced topology, the next step is to implement routing for your network. 4 | 5 | In traditional software-defined networks (SDNs), routing is implemented at switches using flow tables. 6 | A flow table is a match-action table that defines how packets are looked up, modified, and forwarded. 7 | 8 | Here, we introduce a minimal version of a flow table entry: 9 | 10 | ``` 11 | ------------------------------------- 12 | | Match fields || Action (forward)| 13 | +----------------||-----------------+ 14 | | Destination || Send Port | 15 | ------------------------------------- 16 | ``` 17 | For example, at ToR0, the following flow table entry: 18 | ``` 19 | ------------------------------------- 20 | | Match fields || Action (forward)| 21 | +----------------||-----------------+ 22 | | Dst: 1 || Send Port: 0 | 23 | ------------------------------------- 24 | ``` 25 | instructs the switch to forward packets destined for node 1 out of port 0, 26 | whenever the switch receives a packet. 27 | 28 | If this is the only flow table entry on the switch, any packet not destined for node 1 (no match) will be dropped. 29 | 30 | 31 | ## Define Flow Table Entries in OpenOptics 32 | 33 | With OpenOptics, the above entry can be defined as: 34 | 35 | ```python 36 | # Without any time-related fields specified, it is just a normal flow table entry. 37 | TimeFlowEntry(dst=1, hops=TimeFlowHop(send_port=0)) 38 | ``` 39 | 40 | You can then add this flow table entry to a ToR switch (indexed by its node_id) using: 41 | 42 | ```python 43 | net.add_time_flow_entry(node_id, entry) 44 | ``` 45 | 46 | Please note that the above entry will be loaded at **ToR switches**, not OCSes. 47 | OCS does nothing else but transmitting received packets to a port based on the topology schedule. 48 | 49 | ## Your Tasks 50 | 51 | You will now enable routing in your optical DCN: 52 | 53 | 1. Add flow table entries for nodes 0 and 1 to enable routing between them. 54 | 2. Test reachability with ping: `h0 ping h1`, check packets' sequence numbers `icmp_seq`, and reason the packet loss. 55 | 3. To reduce packet loss, you could add flow table entries for nodes 2 and 3. 56 | 4. Test reachability again with ping: `h0 ping h1`, and check icmp_seq now. 57 | 58 | Run the script and test your solution in the CLI with `OpenOptics> h0 ping h1`: 59 | ```python 60 | python3 3-flow-table.py 61 | ``` -------------------------------------------------------------------------------- /tutorials/solutions/4-time-flow-table-solution.py: -------------------------------------------------------------------------------- 1 | ########################################################################################## 2 | # In this task, the goal is making ping work without packet loss. You will: 3 | # (1) Add usual flow table entries for node 0 and node 1, by setting send time slice (send_ts) 4 | # the same as arrival time slice (arrival_ts) 5 | # (2) Test reachability with ping: `h0 ping h1` 6 | # (3) Update flow table to time flow table - 7 | # adjust send_ts and arrival_ts according to time sliced topology. 8 | # (4) Test reachability again with ping: `h0 ping h1` 9 | ########################################################################################## 10 | 11 | from openoptics import Toolbox 12 | from openoptics.TimeFlowTable import TimeFlowHop, TimeFlowEntry 13 | 14 | if __name__ == "__main__": 15 | net = Toolbox.BaseNetwork( 16 | name="task2", 17 | backend="Mininet", 18 | nb_node=4, 19 | time_slice_duration_ms=256, # in ms 20 | use_webserver=True, 21 | ) 22 | 23 | # Copy your topology here 24 | net.connect(node1=0, node2=1, time_slice=0) 25 | net.connect(node1=2, node2=3, time_slice=0) 26 | 27 | net.connect(node1=0, node2=2, time_slice=1) 28 | net.connect(node1=1, node2=3, time_slice=1) 29 | 30 | net.connect(node1=0, node2=3, time_slice=2) 31 | net.connect(node1=1, node2=2, time_slice=2) 32 | 33 | net.deploy_topo() 34 | 35 | # Add flow table entries here 36 | node0_entries = [] 37 | node1_entries = [] 38 | 39 | node0_entries = [ 40 | TimeFlowEntry( 41 | dst=1, arrival_ts=0, hops=[TimeFlowHop(send_ts=0, send_port=0)] 42 | ), 43 | TimeFlowEntry( 44 | dst=1, arrival_ts=1, hops=[TimeFlowHop(send_ts=0, send_port=0)] 45 | ), 46 | TimeFlowEntry( 47 | dst=1, arrival_ts=2, hops=[TimeFlowHop(send_ts=0, send_port=0)] 48 | ), 49 | ] 50 | 51 | node1_entries = [ 52 | TimeFlowEntry( 53 | dst=0, arrival_ts=0, hops=[TimeFlowHop(send_ts=0, send_port=0)] 54 | ), 55 | TimeFlowEntry( 56 | dst=0, arrival_ts=1, hops=[TimeFlowHop(send_ts=0, send_port=0)] 57 | ), 58 | TimeFlowEntry( 59 | dst=0, arrival_ts=2, hops=[TimeFlowHop(send_ts=0, send_port=0)] 60 | ), 61 | ] 62 | 63 | net.add_time_flow_entry(node_id=0, entries=node0_entries) 64 | net.add_time_flow_entry(node_id=1, entries=node1_entries) 65 | 66 | # Modification ends here. 67 | ########################################## 68 | 69 | net.start() 70 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. OpenOptics documentation master file, created by 2 | sphinx-quickstart on Thu Jul 31 14:51:27 2025. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | OpenOptics: Democratizing Optical DCNs 7 | ============================================================================ 8 | .. 9 | .. image:: ../assets/openoptics_words.svg 10 | :alt: OpenOptics Logo 11 | :align: center 12 | 13 | .. 14 | .. centered:: 15 | 16 | **Easy design, testing, and deployment of optical DCNs for everyone.** 17 | 18 | .. note:: 19 | 20 | We will hold a tutorial at `SIGCOMM'25 `_! Attend to build your own optical DCNs with us! 21 | 22 | OpenOptics is a general framework for realizing different optical data center network architectures in a plug-and-play manner. 23 | With OpenOptics, users can deploy customized optical data center networks on the testbed, emulation, or simulation with ~10 lines of Python code. 24 | Under the hood, user configurations are translated into table entries and control plane programs, 25 | which are then deployed to the underlying optical and P4-programmable switches. 26 | 27 | .. code-block:: python 28 | 29 | from openoptics import Toolbox, OpticalTopo, OpticalRouting 30 | 31 | nb_node = 8 32 | net = Toolbox.BaseNetwork(nb_node = nb_node, time_slice_duration_ms = 512, backend="Mininet") 33 | circuits = OpticalTopo.round_robin(nb_node=nb_node) 34 | net.deploy_topo(circuits) 35 | paths = OpticalRouting.routing_direct(net.get_topo()) 36 | net.deploy_routing(paths) 37 | net.start() 38 | 39 | After deployment, users can monitor the network with OpenOptics Dashboard. 40 | 41 | .. image:: ../assets/dashboard.png 42 | :alt: OpenOptics Dashboard 43 | 44 | We have now published the Mininet backend, where users can realize optical DCNs in a full software emulation using BMv2 software switches and Mininet networks. 45 | The Tofino-based backend will be released soon. 46 | 47 | .. toctree:: 48 | :maxdepth: 1 49 | 50 | quickstart 51 | installation 52 | examples/examples 53 | tutorials/tutorial_index 54 | apis_index 55 | about 56 | 57 | .. 58 | Indices and tables 59 | ================== 60 | 61 | * :ref:`genindex` 62 | * :ref:`modindex` 63 | * * :ref:`search` 64 | 65 | .. raw:: html 66 | 67 | Imprint / Data Protection 68 | 69 | -------------------------------------------------------------------------------- /targets/tor_switch/tests/utils.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2013-present Barefoot Networks, Inc. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | /* 17 | * Antonin Bas (antonin@barefootnetworks.com) 18 | * 19 | */ 20 | 21 | #ifndef TOR_SWITCH_TESTS_UTILS_H_ 22 | #define TOR_SWITCH_TESTS_UTILS_H_ 23 | 24 | #include 25 | 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | class NNEventListener { 36 | public: 37 | enum NNEventType { 38 | TABLE_HIT = 12, 39 | TABLE_MISS = 13, 40 | ACTION_EXECUTE = 14 41 | }; 42 | 43 | struct NNEvent { 44 | NNEventType type; 45 | int id; 46 | }; 47 | 48 | explicit NNEventListener(const std::string &addr); 49 | 50 | ~NNEventListener(); 51 | 52 | void start(); 53 | 54 | void get_and_remove_events(const std::string &pid, 55 | std::vector *pevents, 56 | size_t num_events, 57 | unsigned int timeout_ms = 1000); 58 | 59 | private: 60 | void receive_loop(); 61 | 62 | std::string addr{}; 63 | nn::socket s; 64 | std::unordered_map > events; 65 | 66 | std::thread receive_thread{}; 67 | bool stop_receive_thread{false}; 68 | bool started{false}; 69 | mutable std::mutex mutex{}; 70 | mutable std::condition_variable cond_new_event{}; 71 | }; 72 | 73 | 74 | class PacketInReceiver { 75 | public: 76 | enum class Status { CAN_READ, CAN_RECEIVE }; 77 | 78 | PacketInReceiver(); 79 | 80 | void receive(int port_num, const char *buffer, int len, void *cookie); 81 | 82 | size_t read(char *dst, size_t max_size, int *recv_port); 83 | 84 | Status check_status(); 85 | 86 | private: 87 | std::vector buffer_{}; 88 | int port; 89 | Status status{Status::CAN_RECEIVE}; 90 | mutable std::mutex mutex{}; 91 | mutable std::condition_variable can_receive{}; 92 | mutable std::condition_variable can_read{}; 93 | }; 94 | 95 | #endif // TOR_SWITCH_TESTS_UTILS_H_ 96 | -------------------------------------------------------------------------------- /targets/optical_switch/tests/utils.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2013-present Barefoot Networks, Inc. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | /* 17 | * Antonin Bas (antonin@barefootnetworks.com) 18 | * 19 | */ 20 | 21 | #ifndef TOR_SWITCH_TESTS_UTILS_H_ 22 | #define TOR_SWITCH_TESTS_UTILS_H_ 23 | 24 | #include 25 | 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | class NNEventListener { 36 | public: 37 | enum NNEventType { 38 | TABLE_HIT = 12, 39 | TABLE_MISS = 13, 40 | ACTION_EXECUTE = 14 41 | }; 42 | 43 | struct NNEvent { 44 | NNEventType type; 45 | int id; 46 | }; 47 | 48 | explicit NNEventListener(const std::string &addr); 49 | 50 | ~NNEventListener(); 51 | 52 | void start(); 53 | 54 | void get_and_remove_events(const std::string &pid, 55 | std::vector *pevents, 56 | size_t num_events, 57 | unsigned int timeout_ms = 1000); 58 | 59 | private: 60 | void receive_loop(); 61 | 62 | std::string addr{}; 63 | nn::socket s; 64 | std::unordered_map > events; 65 | 66 | std::thread receive_thread{}; 67 | bool stop_receive_thread{false}; 68 | bool started{false}; 69 | mutable std::mutex mutex{}; 70 | mutable std::condition_variable cond_new_event{}; 71 | }; 72 | 73 | 74 | class PacketInReceiver { 75 | public: 76 | enum class Status { CAN_READ, CAN_RECEIVE }; 77 | 78 | PacketInReceiver(); 79 | 80 | void receive(int port_num, const char *buffer, int len, void *cookie); 81 | 82 | size_t read(char *dst, size_t max_size, int *recv_port); 83 | 84 | Status check_status(); 85 | 86 | private: 87 | std::vector buffer_{}; 88 | int port; 89 | Status status{Status::CAN_RECEIVE}; 90 | mutable std::mutex mutex{}; 91 | mutable std::condition_variable can_receive{}; 92 | mutable std::condition_variable can_read{}; 93 | }; 94 | 95 | #endif // TOR_SWITCH_TESTS_UTILS_H_ 96 | -------------------------------------------------------------------------------- /tutorials/solutions/5-multi-hop-routing-solution.py: -------------------------------------------------------------------------------- 1 | ########################################################################################## 2 | # In this task, you will route packets through multi-hop paths, instead of 3 | # waiting for the direct connection to be established. Goals are: 4 | # (1) make ping work without packet loss 5 | # (2) route packets via multi-hop paths to reduce waiting time. 6 | ########################################################################################## 7 | 8 | from openoptics import Toolbox 9 | from openoptics.TimeFlowTable import TimeFlowHop, TimeFlowEntry 10 | 11 | if __name__ == "__main__": 12 | net = Toolbox.BaseNetwork( 13 | name="task2", 14 | backend="Mininet", 15 | nb_node=4, 16 | time_slice_duration_ms=256, # in ms 17 | use_webserver=True, 18 | ) 19 | 20 | # Copy your topology here 21 | net.connect(node1=0, node2=1, time_slice=0) 22 | net.connect(node1=2, node2=3, time_slice=0) 23 | 24 | net.connect(node1=0, node2=2, time_slice=1) 25 | net.connect(node1=1, node2=3, time_slice=1) 26 | 27 | net.connect(node1=0, node2=3, time_slice=2) 28 | net.connect(node1=1, node2=2, time_slice=2) 29 | net.deploy_topo() 30 | 31 | node0_entries = [ 32 | TimeFlowEntry( 33 | dst=1, arrival_ts=0, hops=[TimeFlowHop(send_ts=0, send_port=0)] 34 | ), 35 | TimeFlowEntry( 36 | dst=1, arrival_ts=1, hops=[TimeFlowHop(send_ts=1, send_port=0)] 37 | ), # Send to node2 38 | TimeFlowEntry( 39 | dst=1, arrival_ts=2, hops=[TimeFlowHop(send_ts=0, send_port=0)] 40 | ), 41 | ] 42 | 43 | node1_entries = [ 44 | TimeFlowEntry( 45 | dst=0, arrival_ts=0, hops=[TimeFlowHop(send_ts=0, send_port=0)] 46 | ), 47 | TimeFlowEntry( 48 | dst=0, arrival_ts=1, hops=[TimeFlowHop(send_ts=1, send_port=0)] 49 | ), # Send to node3 50 | TimeFlowEntry( 51 | dst=0, arrival_ts=2, hops=[TimeFlowHop(send_ts=0, send_port=0)] 52 | ), 53 | ] 54 | 55 | node2_entries = [ 56 | TimeFlowEntry( 57 | dst=1, arrival_ts=1, hops=[TimeFlowHop(send_ts=2, send_port=0)] 58 | ) # Forward for 0->1 59 | ] 60 | 61 | node3_entries = [ 62 | TimeFlowEntry( 63 | dst=0, arrival_ts=1, hops=[TimeFlowHop(send_ts=2, send_port=0)] 64 | ) # Forward for 1->0 65 | ] 66 | 67 | net.add_time_flow_entry(node_id=0, entries=node0_entries) 68 | net.add_time_flow_entry(node_id=1, entries=node1_entries) 69 | net.add_time_flow_entry(node_id=2, entries=node2_entries) 70 | net.add_time_flow_entry(node_id=3, entries=node3_entries) 71 | 72 | net.start() 73 | -------------------------------------------------------------------------------- /targets/tor_switch/thrift/tor_switch.thrift: -------------------------------------------------------------------------------- 1 | /* Copyright 2013-present Barefoot Networks, Inc. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | /* 17 | * Antonin Bas (antonin@barefootnetworks.com) 18 | * Yiming Lei (ylei@mpi-inf.mpg.de) 19 | */ 20 | 21 | namespace cpp tswitch_runtime 22 | namespace py tswitch_runtime 23 | 24 | struct MirroringSessionConfig { 25 | 1:optional i32 port; 26 | 2:optional i32 mgid; 27 | } 28 | 29 | enum MirroringOperationErrorCode { 30 | SESSION_NOT_FOUND = 1, 31 | } 32 | 33 | exception InvalidMirroringOperation { 34 | 1:MirroringOperationErrorCode code; 35 | } 36 | 37 | struct PortQueueMetric { 38 | 1:required i32 port; 39 | 2:required i32 queue; 40 | 3:required i32 depth; //in packets 41 | //To-do: add queue depth watermark 42 | //4:required i32 drop_ctr; 43 | } 44 | 45 | struct MonitorResult { 46 | 1:required list port_queue_metrics; 47 | 2:required i32 drop_ctr; 48 | } 49 | 50 | service TorSwitch { 51 | 52 | // deprecated, use the mirroring_session_* RPCs instead 53 | i32 mirroring_mapping_add(1:i32 mirror_id, 2:i32 egress_port); 54 | i32 mirroring_mapping_delete(1:i32 mirror_id); 55 | i32 mirroring_mapping_get_egress_port(1:i32 mirror_id); 56 | 57 | void mirroring_session_add(1:i32 mirror_id, 2:MirroringSessionConfig config) 58 | throws (1:InvalidMirroringOperation ouch); 59 | void mirroring_session_delete(1:i32 mirror_id) 60 | throws (1:InvalidMirroringOperation ouch); 61 | MirroringSessionConfig mirroring_session_get(1:i32 mirror_id) 62 | throws (1:InvalidMirroringOperation ouch); 63 | 64 | i32 set_egress_priority_queue_depth(1:i32 port_num, 2:i32 priority, 3:i32 depth_pkts); 65 | i32 set_egress_queue_depth(1:i32 port_num, 2:i32 depth_pkts); 66 | i32 set_all_egress_queue_depths(1:i32 depth_pkts); 67 | i32 set_egress_priority_queue_rate(1:i32 port_num, 2:i32 priority, 3:i64 rate_pps); 68 | i32 set_egress_queue_rate(1:i32 port_num, 2:i64 rate_pps); 69 | i32 set_all_egress_queue_rates(1:i64 rate_pps); 70 | 71 | i32 set_active_queue(1:i32 qid); 72 | i32 get_active_queue(); 73 | 74 | // these methods are here as an experiment, prefer get_time_elapsed_us() when 75 | // possible 76 | i64 get_time_elapsed_us(); 77 | i64 get_time_since_epoch_us(); 78 | 79 | MonitorResult get_device_metric(); 80 | 81 | string get_num_queued_packets(); 82 | string get_packet_loss_rate(); 83 | } 84 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # For the full list of built-in configuration values, see the documentation: 4 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 5 | 6 | import os 7 | import sys 8 | 9 | sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) 10 | 11 | 12 | # -- Project information ----------------------------------------------------- 13 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information 14 | 15 | project = "OpenOptics" 16 | copyright = "2025, Network and Cloud Systems Group, MPI-INF" 17 | author = "Yiming Lei" 18 | version = "0.0.1" 19 | 20 | # -- General configuration --------------------------------------------------- 21 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration 22 | 23 | extensions = [ 24 | "sphinx.ext.autodoc", 25 | "sphinx.ext.autosummary", 26 | "sphinx.ext.viewcode", 27 | "sphinx.ext.napoleon", 28 | "sphinx.ext.autosectionlabel", 29 | "myst_parser", # md 30 | ] 31 | 32 | autosummary_generate = True 33 | autosectionlabel_prefix_document = True 34 | autodoc_member_order = "bysource" 35 | 36 | autodoc_default_options = { 37 | "members": True, 38 | "undoc-members": True, 39 | "show-inheritance": True, 40 | } 41 | 42 | templates_path = ["_templates"] 43 | exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] 44 | 45 | 46 | # -- Options for HTML output ------------------------------------------------- 47 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output 48 | 49 | html_static_path = ["_static"] 50 | 51 | html_theme = "alabaster" 52 | html_theme = "pydata_sphinx_theme" 53 | """ 54 | html_theme_options = { 55 | "navigation_depth": 3, 56 | "show_nav_level": 2, 57 | "collapse_navigation": False, 58 | "footer_start": ["copyright"], 59 | #"footer_end": ["tem_author"], 60 | "github_url" : "www.github.com" 61 | } 62 | html_sidebars = { 63 | "**": ["sidebar-nav-bs"] 64 | } 65 | """ 66 | html_theme = "sphinx_book_theme" 67 | 68 | html_logo = "_static/openoptics_words.svg" 69 | html_favicon = "_static/openoptics.ico" 70 | 71 | html_theme_options = { 72 | "show_toc_level": 2, 73 | "show_navbar_depth": 2, 74 | # "search_bar_text": "Search this book...", 75 | } 76 | 77 | html_context = { 78 | "display_github": True, 79 | "github_user": "ymlei", 80 | "github_repo": "", 81 | "github_version": "main", 82 | "conf_py_path": "/docs/", 83 | } 84 | 85 | """ 86 | html_sidebars = { 87 | "**": ["navbar-logo.html", "search-field.html", "sbt-sidebar-nav.html"] 88 | } 89 | """ 90 | 91 | autodoc_mock_imports = [ 92 | "networkx", 93 | "tswitch_CLI", 94 | "runtime_CLI", 95 | "django", 96 | "matplotlib", 97 | "mininet", 98 | ] 99 | 100 | exclude_patterns = [ 101 | #"tutorials/*", 102 | ] 103 | -------------------------------------------------------------------------------- /openoptics/dashboard/dashboardapp/views.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Max-Planck-Gesellschaft zur Förderung der Wissenschaften e.V. 2 | # Developed at the Max Planck Institute for Informatics, Network and Cloud Systems Group 3 | # 4 | # Author: Yiming Lei (ylei@mpi-inf.mpg.de) 5 | # 6 | # This software is licensed for non-commercial scientific research purposes only. 7 | # 8 | # License text: Creative Commons NC BY SA 4.0 9 | # https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en 10 | 11 | from django.shortcuts import render 12 | from dashboardapp.models import Epochs, UniformMetrics 13 | from django.utils.safestring import mark_safe 14 | 15 | import json 16 | from collections import defaultdict 17 | 18 | 19 | def render_dashboard(request): 20 | """ 21 | View is a single time execution. It renders old data into a dashboard if the showing epoch is old. 22 | Following data update is handled by websocket and consumers.py 23 | """ 24 | epoch_id = request.GET.get("epoch_id", None) 25 | if epoch_id is None: 26 | showing_epoch = Epochs.objects.order_by("id").last() 27 | else: 28 | showing_epoch = Epochs.objects.filter(id=epoch_id).first() 29 | 30 | metric_data = UniformMetrics.objects.filter(epoch=showing_epoch).order_by( 31 | "timestep" 32 | ) 33 | time_steps = list(metric_data.values_list("timestep", flat=True).distinct()) 34 | 35 | devices = sorted( 36 | list(UniformMetrics.objects.values_list("device_name", flat=True).distinct()) 37 | ) 38 | 39 | metrics = [field.name for field in UniformMetrics._meta.get_fields()] 40 | excluded_metrics = {"device_name", "id", "label", "timestep", "epoch"} 41 | metrics = [field for field in metrics if field not in excluded_metrics] 42 | 43 | if showing_epoch is not None: 44 | topo_img_url = showing_epoch.topo_image.url 45 | else: 46 | topo_img_url = "" 47 | 48 | depth = defaultdict(lambda: defaultdict(list)) 49 | loss_ctr = defaultdict(lambda: defaultdict(list)) 50 | for m in metric_data: 51 | depth[m.device_name][m.label].append((m.timestep, m.depth)) 52 | loss_ctr[m.device_name][m.label].append((m.timestep, m.loss_ctr)) 53 | 54 | chart_depth_data = {} 55 | for device, label_data in depth.items(): 56 | chart_depth_data[device] = [] 57 | for label, data in label_data.items(): 58 | chart_depth_data[device].append({"label": label, "data": data}) 59 | 60 | chart_loss_data = {} 61 | for device, label_data in loss_ctr.items(): 62 | chart_loss_data[device] = [] 63 | for label, data in label_data.items(): 64 | chart_loss_data[device].append({"label": label, "data": data}) 65 | 66 | context = { 67 | "epochs": Epochs.objects.all(), 68 | "current_epoch": showing_epoch, 69 | "devices": devices, 70 | "metrics": metrics, 71 | "time_steps": time_steps, 72 | "depth_json": mark_safe(json.dumps(chart_depth_data)), 73 | "loss_ctr_json": mark_safe(json.dumps(chart_loss_data)), 74 | "topo_img_url": topo_img_url, 75 | } 76 | return render(request, "dashboard.html", context) 77 | -------------------------------------------------------------------------------- /tutorials/solutions/3-flow-table-solution.py: -------------------------------------------------------------------------------- 1 | ########################################################################################## 2 | # You will now enable routing in your optical DCN: 3 | 4 | # 1. Add flow table entries for nodes 0 and 1 to enable routing between them. 5 | # 2. Test reachability with ping: `h0 ping h1`, check packets' sequence numbers `icmp_seq`, and reason the packet loss. 6 | # 3. To reduce packet loss, you could add flow table entries for nodes 2 and 3. 7 | # 4. Test reachability again with ping: `h0 ping h1`, and check icmp_seq now. 8 | ########################################################################################## 9 | 10 | from openoptics import Toolbox 11 | from openoptics.TimeFlowTable import TimeFlowHop, TimeFlowEntry 12 | 13 | if __name__ == "__main__": 14 | net = Toolbox.BaseNetwork( 15 | name="task3", 16 | backend="Mininet", 17 | nb_node=4, 18 | time_slice_duration_ms=256, # in ms 19 | use_webserver=True, 20 | ) 21 | ########################################## 22 | # Modify starting from here: 23 | 24 | # Copy your topology here: 25 | net.connect(time_slice=0, node1=0, node2=1) 26 | net.connect(time_slice=0, node1=2, node2=3) 27 | 28 | net.connect(time_slice=1, node1=0, node2=2) 29 | net.connect(time_slice=1, node1=1, node2=3) 30 | 31 | net.connect(time_slice=2, node1=0, node2=3) 32 | net.connect(time_slice=2, node1=1, node2=2) 33 | 34 | net.deploy_topo() 35 | 36 | # Add flow table entries here 37 | 38 | node0_entries = [ 39 | TimeFlowEntry( 40 | dst=1, hops=TimeFlowHop(send_port=0) 41 | ), 42 | TimeFlowEntry( 43 | dst=2, hops=TimeFlowHop(send_port=0) 44 | ), 45 | TimeFlowEntry( 46 | dst=3, hops=TimeFlowHop(send_port=0) 47 | ), 48 | ] 49 | 50 | node1_entries = [ 51 | TimeFlowEntry( 52 | dst=0, hops=TimeFlowHop(send_port=0) 53 | ), 54 | TimeFlowEntry( 55 | dst=2, hops=TimeFlowHop(send_port=0) 56 | ), 57 | TimeFlowEntry( 58 | dst=3, hops=TimeFlowHop(send_port=0) 59 | ), 60 | ] 61 | 62 | """ 63 | 64 | node2_entries = [ 65 | TimeFlowEntry( 66 | dst=0, hops=TimeFlowHop(send_port=0) 67 | ), 68 | TimeFlowEntry( 69 | dst=1, hops=TimeFlowHop(send_port=0) 70 | ), 71 | TimeFlowEntry( 72 | dst=3, hops=TimeFlowHop(send_port=0) 73 | ), 74 | ] 75 | 76 | node3_entries = [ 77 | TimeFlowEntry( 78 | dst=0, hops=TimeFlowHop(send_port=0) 79 | ), 80 | TimeFlowEntry( 81 | dst=1, hops=TimeFlowHop(send_port=0) 82 | ), 83 | TimeFlowEntry( 84 | dst=2, hops=TimeFlowHop(send_port=0) 85 | ), 86 | ] 87 | """ 88 | 89 | net.add_time_flow_entry(node_id=0, entries=node0_entries) 90 | net.add_time_flow_entry(node_id=1, entries=node1_entries) 91 | #net.add_time_flow_entry(node_id=2, entries=node2_entries) 92 | #net.add_time_flow_entry(node_id=3, entries=node3_entries) 93 | 94 | net.start() 95 | -------------------------------------------------------------------------------- /tutorials/solutions/8-routings-solution.py: -------------------------------------------------------------------------------- 1 | import networkx as nx 2 | from typing import Dict 3 | 4 | from openoptics import Toolbox, OpticalTopo, OpticalRouting 5 | from openoptics.TimeFlowTable import Path, Step 6 | 7 | def my_topology(nb_node): 8 | # Do NOT change this function 9 | 10 | nodes = list(range(nb_node)) 11 | half = nb_node // 2 12 | circuits = [] 13 | """ 14 | A circuit: [time_slice, node1, node2, port1, port2] 15 | """ 16 | 17 | # Internal circuits 18 | circuits += OpticalTopo.round_robin(nodes=nodes[:half], start_time_slice=0) 19 | circuits += OpticalTopo.round_robin(nodes=nodes[half:], start_time_slice=0) 20 | circuits += [ 21 | [half-1, 0, 4, 0, 0], 22 | [half-1, 1, 5, 0, 0], 23 | [half-1, 2, 6, 0, 0], 24 | [half-1, 3, 7, 0, 0] 25 | ] 26 | 27 | return circuits 28 | 29 | def my_routing(slice_to_topo: Dict[int, nx.Graph]): 30 | """ 31 | This is the implementation of multi-hop routing. 32 | """ 33 | paths = [] 34 | 35 | nodes = slice_to_topo[0].nodes() 36 | for node1 in nodes: 37 | for node2 in nodes: 38 | if node1 == node2: 39 | continue 40 | if (node1 // 4 == node2 // 4) or (node1 % 4 == node2 % 4): 41 | # Nodes within the same cluster, wait for the direct path. 42 | #print(f"Find direct path for {node1} and {node2}") 43 | paths.extend(OpticalRouting.find_direct_path(slice_to_topo, node1, node2)) 44 | else: 45 | # Nodes are in different clusters and they don't have direct connections. 46 | intermidiate_node = int((node1 + len(nodes)/2) % len(nodes)) 47 | # for 0 -> 5, intermidiate node = (0+4)%8 = 4 48 | # for 2 -> 5, intermidiate node = (2+4)%8 = 6 49 | # for 5 -> 2, intermidiate node = (5+4)%8 = 1 50 | 51 | paths_to_the_other_gorup = OpticalRouting.find_direct_path(slice_to_topo, node1, intermidiate_node) 52 | paths_to_dst = OpticalRouting.find_direct_path(slice_to_topo, intermidiate_node, node2) 53 | 54 | for path in paths_to_the_other_gorup: 55 | path.dst = node2 56 | for sec_hop in paths_to_dst: 57 | if sec_hop.arrival_ts == sec_hop.steps[0].send_ts: 58 | # this is the step we need 59 | path.steps.append(sec_hop.steps[0]) 60 | paths.append(path) 61 | 62 | #print(f"Paths: {paths}") 63 | return paths 64 | 65 | if __name__ == "__main__": 66 | nb_node = 8 67 | nb_link = 1 68 | 69 | net = Toolbox.BaseNetwork( 70 | name="task8-routings", 71 | backend="Mininet", 72 | nb_node=nb_node, 73 | nb_link=nb_link, 74 | time_slice_duration_ms=128, # in ms 75 | use_webserver=True, 76 | ) 77 | 78 | circuits = my_topology(nb_node) 79 | assert net.deploy_topo(circuits) 80 | 81 | paths = my_routing(net.get_topo()) 82 | assert net.deploy_routing(paths, routing_mode="Source") 83 | 84 | net.start() 85 | -------------------------------------------------------------------------------- /docs/tutorials/7-topology.md: -------------------------------------------------------------------------------- 1 | # Tutorial 7: Design Topology for an Application 2 | 3 | Programming with low-level APIs can be tedious and error-prone. 4 | The following two tutorials demonstrate how to use OpenOptics' high-level APIs to 5 | build optical DCNs with just a few lines of code. 6 | 7 | In this tutorial, you will design a network topology tailored for a custom distributed application. 8 | 9 | The application is deployed on 8 hosts in an 8-ToR (Top-of-Rack switch) network, with one host per ToR. 10 | Each host may send traffic to every other host. 11 | 12 | The diagram below illustrates the application's traffic pattern: 13 | 14 | Group A (Hosts 0–3) Group B (Hosts 4–7) 15 | ┌───────────────┐ ┌───────────────┐ 16 | │ dense traffic │ │ dense traffic │ 17 | │ within group │ │ within group │ 18 | └───────────────┘ └───────────────┘ 19 | 20 | h0 --- h1 h4 --- h5 21 | | X | | X | 22 | h2 --- h3 h6 --- h7 23 | 24 | \ / 25 | \ / 26 | \______ light traffic _________/ 27 | between nodes in different groups 28 | 29 | • The applications are divided into two groups. 30 | 31 | • Group A = hosts 0–3; Group B = hosts 4–7. 32 | 33 | • Groups have denser intra-group communication and lighter inter-group communication. 34 | 35 | • Traffic ratio (intra-group : inter-group) = 2:1. (You don’t need to fit the topology perfectly to this ratio.) 36 | 37 | By default, the script tutorials/7-topology.py creates a round-robin topology across all nodes (you will modify this topology in the this task): 38 | • Each node connects directly to one other node per time slice. 39 | • Across all time slices, each node has a direct connection to every other node. 40 | 41 | ```{note} 42 | Run the script first and inspect the topology on the dashboard to understand the default round-robin schedule. 43 | Then, modify the input arguments of `round_robin()` to check when topologies are generated. 44 | ``` 45 | 46 | ## Your Tasks 47 | 48 | We will use direct routing for this task. Your goal is to design a topology that: 49 | 50 | 1. Ensures **no packet loss**: the schedule must include direct connections between all node pairs. 51 | 2. Allocates **more connections within groups** than across groups. 52 | 3. **Bonus**: After completing the above, try to reduce the **maximum message RTT** to within 10 time slices, if you haven't. 53 | 54 | 55 | ### Notice: 56 | 57 | - Don't change the application. 58 | - Don't change the routing. 59 | - Don't change the slice duration. 60 | - Don't change the number of links per ToR 61 | 62 | 63 | ```{note} 64 | You can complete this task using only `OpticalTopo.round_robin()` inside the topology generator function `my_topology`. 65 | ``` 66 | 67 | To test your design in the OpenOptics CLI: 68 | 69 | ```bash 70 | OpenOptics-> test_task7 71 | ``` 72 | 73 | You will see **PASS** if your solution satisfies all requirements. 74 | 75 | You can also use `ping` between individual hosts to check connectivity and delay. -------------------------------------------------------------------------------- /tutorials/8-routings.py: -------------------------------------------------------------------------------- 1 | ########################################################################################## 2 | # In this tutorial, you are given a topology that does NOT provide 3 | # direct connections between every pair of nodes. Your goal is to 4 | # design a routing on this topology to deliver all packets. 5 | # 6 | # Detailed instructions: https://openoptics.mpi-inf.mpg.de/tutorials/8-routing.html 7 | ########################################################################################## 8 | 9 | import networkx as nx 10 | from typing import Dict 11 | 12 | from openoptics import Toolbox, OpticalTopo, OpticalRouting 13 | from openoptics.TimeFlowTable import Path, Step 14 | 15 | def my_topology(nb_node): 16 | # Do NOT change this function 17 | 18 | nodes = list(range(nb_node)) 19 | half = nb_node // 2 20 | circuits = [] 21 | """ 22 | A circuit: [time_slice, node1, node2, port1, port2] 23 | """ 24 | 25 | # Internal circuits 26 | circuits += OpticalTopo.round_robin(nodes=nodes[:half], start_time_slice=0) 27 | circuits += OpticalTopo.round_robin(nodes=nodes[half:], start_time_slice=0) 28 | circuits += [ 29 | [half-1, 0, 4, 0, 0], 30 | [half-1, 1, 5, 0, 0], 31 | [half-1, 2, 6, 0, 0], 32 | [half-1, 3, 7, 0, 0] 33 | ] 34 | 35 | return circuits 36 | 37 | def my_routing(slice_to_topo: Dict[int, nx.Graph]): 38 | """ 39 | This is the implementation of your routing. 40 | """ 41 | nodes = slice_to_topo[0].nodes() 42 | paths = [] 43 | # path: Path(src, arrival_ts, dst, steps=[Step(send_port, send_ts)]) 44 | 45 | ########################################## 46 | # Modification starts from here: 47 | 48 | for node1 in nodes: 49 | for node2 in nodes: 50 | if node1 == node2: 51 | continue 52 | paths.extend(OpticalRouting.find_direct_path(slice_to_topo, node1, node2)) 53 | """ 54 | # If you prefer to add paths manually 55 | paths.append( 56 | Path(src=0, arrival_ts=0, dst=5, 57 | steps=[ 58 | Step(cur_node=0, send_port=0, send_ts=3), # First send to node 4 at time slice 3 59 | Step(cur_node=4, send_port=0, send_ts=1) # Send from node 4 to node 5 at time slice 2 60 | ]) 61 | ) 62 | # cur_node is for source routing to check whether the node the packet arrives is as expected, 63 | # the apcket will be dropped if cur_node doesn't match the actual arrival node. 64 | """ 65 | print(paths) 66 | # Modification ends here. 67 | ########################################## 68 | 69 | return paths 70 | 71 | if __name__ == "__main__": 72 | nb_node = 8 73 | nb_link = 1 74 | 75 | net = Toolbox.BaseNetwork( 76 | name="task8-routings", 77 | backend="Mininet", 78 | nb_node=nb_node, 79 | nb_link=nb_link, 80 | time_slice_duration_ms=128, # in ms 81 | use_webserver=True, 82 | ) 83 | 84 | circuits = my_topology(nb_node) 85 | assert net.deploy_topo(circuits) 86 | 87 | # No modifications needed here. 88 | # You are supposed to modify the implementation of my_routing function. 89 | paths = my_routing(net.get_topo()) 90 | assert net.deploy_routing(paths, routing_mode="Source") 91 | 92 | net.start() 93 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ARG PARENT_VERSION=latest 2 | FROM p4lang/p4c:${PARENT_VERSION} 3 | LABEL maintainer="P4 Developers " 4 | 5 | COPY . /openoptics/ 6 | WORKDIR / 7 | 8 | RUN apt-get update -qq && \ 9 | apt-get install -qq --no-install-recommends \ 10 | wget \ 11 | python3 \ 12 | python3-pip \ 13 | python3-dev \ 14 | make \ 15 | g++ \ 16 | autoconf \ 17 | libtool 18 | 19 | ENV BM_DEPS automake \ 20 | build-essential \ 21 | clang-8 \ 22 | clang-10 \ 23 | curl \ 24 | git \ 25 | lcov \ 26 | libgmp-dev \ 27 | libpcap-dev \ 28 | libboost-dev \ 29 | libboost-iostreams1.71.0 \ 30 | libboost-program-options-dev \ 31 | libboost-system-dev \ 32 | libboost-filesystem-dev \ 33 | libboost-thread-dev \ 34 | libtool \ 35 | pkg-config 36 | ENV BM_RUNTIME_DEPS libboost-program-options1.71.0 \ 37 | libboost-system1.71.0 \ 38 | libboost-filesystem1.71.0 \ 39 | libboost-thread1.71.0 \ 40 | libgmp10 \ 41 | libpcap0.8 \ 42 | python3 \ 43 | python-is-python3 44 | RUN apt-get update -qq && apt-get install -qq --no-install-recommends $BM_DEPS $BM_RUNTIME_DEPS 45 | 46 | RUN pip install --upgrade pip 47 | RUN pip install --upgrade setuptools wheel packaging 48 | RUN pip install --no-cache-dir networkx matplotlib mininet 49 | RUN pip install --no-cache-dir asgiref Django 50 | RUN pip uninstall channels 51 | # Install Django first then channels["daphne"] to avoid some errors for installing daphne 52 | RUN pip install --no-cache-dir channels-redis channels["daphne"] 53 | RUN pip install --no-cache-dir nnpy 54 | 55 | RUN rm -rf /usr/local/bin/thrift /usr/local/include/thrift /usr/local/include/bm/ /usr/local/bin/bm_CLI /usr/local/bin/bm_nanomsg_events /usr/local/bin/bm_p4dbg 56 | 57 | WORKDIR / 58 | RUN wget https://dlcdn.apache.org/thrift/0.22.0/thrift-0.22.0.tar.gz 59 | RUN tar -xvf thrift-0.22.0.tar.gz 60 | WORKDIR thrift-0.22.0 61 | RUN ./bootstrap.sh 62 | RUN ./configure 63 | RUN make -j$(nproc) 64 | RUN make install 65 | RUN ldconfig 66 | # This is for python can import thrift 67 | WORKDIR /thrift-0.22.0/lib/py 68 | RUN python3 -m pip install . 69 | 70 | WORKDIR / 71 | RUN git clone https://github.com/p4lang/behavioral-model.git 72 | WORKDIR /behavioral-model 73 | RUN git checkout 8e183a39b372cb9dc563e9d0cf593323249cd88b 74 | RUN cp -r /openoptics/targets/tor_switch ./targets 75 | RUN cp -r /openoptics/targets/optical_switch ./targets 76 | RUN cp /openoptics/targets/configure.ac ./configure.ac 77 | RUN cp /openoptics/targets/Makefile.am ./targets 78 | 79 | RUN ./autogen.sh 80 | #RUN ./configure 'CXXFLAGS=-O0 -g' --enable-debugger 81 | RUN ./configure --enable-debugger 82 | RUN make -j$(nproc) 83 | RUN make install 84 | 85 | RUN rm -r /openoptics/ 86 | 87 | RUN apt-get install -qq --no-install-recommends \ 88 | git \ 89 | mininet \ 90 | lsb-release \ 91 | iputils-ping \ 92 | ssh \ 93 | redis-server \ 94 | ethtool 95 | 96 | #networkx mininet Django matplotlib daphne channels-redis 97 | RUN service redis-server start 98 | 99 | #EXPOSE 5201/tcp 5201/udp 100 | #EXPOSE 5001/tcp 5001/udp 101 | 102 | WORKDIR .. -------------------------------------------------------------------------------- /openoptics/DeviceManager.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Max-Planck-Gesellschaft zur Förderung der Wissenschaften e.V. 2 | # Developed at the Max Planck Institute for Informatics, Network and Cloud Systems Group 3 | # 4 | # Author: Yiming Lei (ylei@mpi-inf.mpg.de) 5 | # 6 | # This software is licensed for non-commercial scientific research purposes only. 7 | # 8 | # License text: Creative Commons NC BY SA 4.0 9 | # https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en 10 | 11 | from mininet.net import Mininet 12 | 13 | import sys 14 | 15 | sys.path.insert(1, "../behavioral-model/targets/tor_switch") 16 | sys.path.insert(1, "../behavioral-model/tools") 17 | from tswitch_CLI import TorSwitchAPI 18 | import runtime_CLI 19 | 20 | 21 | class DeviceManager: 22 | """ 23 | OpenOptics DeviceManager. Monitor and configure the network at runtime. 24 | """ 25 | 26 | def __init__(self, mininet_net: Mininet, tor_ocs_ports, nb_queue): 27 | self.mininet_net = mininet_net 28 | 29 | self.switches = [ 30 | switch 31 | for switch in self.mininet_net.switches 32 | if switch.switch_type() == "tor" 33 | ] 34 | self.switch_clients = {} # switch name -> client 35 | 36 | services = TorSwitchAPI.get_thrift_services() 37 | 38 | for switch in self.switches: 39 | switch_client = runtime_CLI.thrift_connect( 40 | "localhost", switch.thrift_port, services 41 | )[0] 42 | self.switch_clients[switch.name] = switch_client 43 | 44 | self.tor_ocs_ports = tor_ocs_ports 45 | self.nb_queue = nb_queue 46 | 47 | def get_device_metric(self) -> dict: 48 | """ 49 | Get device metric (queue depth, loss rate, ...) 50 | 51 | Return: 52 | A dict with key [pq_depth] and [drop_ctr]. 53 | Values of pq_depth is a dict with key (port, queue) 54 | """ 55 | dict_device_metric = {} 56 | for sw_name, switch_client in self.switch_clients.items(): 57 | try: 58 | device_metric = switch_client.get_device_metric() 59 | dict_device_metric[sw_name] = { 60 | "pq_depth": {}, 61 | "drop_ctr": device_metric.drop_ctr, 62 | } 63 | 64 | for pq_metric in device_metric.port_queue_metrics: 65 | # print(f"Update data from switches: {(pq_metric.port, pq_metric.queue), pq_metric.depth}") 66 | dict_device_metric[sw_name]["pq_depth"].update( 67 | {(pq_metric.port, pq_metric.queue): pq_metric.depth} 68 | ) 69 | except Exception: 70 | # print(f"Error getting device metric for {sw_name}: {e}") 71 | dict_device_metric[sw_name] = {"pq_depth": {}, "drop_ctr": 0} 72 | 73 | # print(device_metric) 74 | return dict_device_metric 75 | 76 | def set_active_queue(self, sw_name, active_qid): 77 | """ 78 | Set the active queue for a specific switch. 79 | 80 | Args: 81 | sw_name: The name of the switch to configure 82 | active_qid: The ID of the queue to set as active 83 | """ 84 | # print(f"{sw_name} set active queue to {active_qid}") 85 | # self.switch_clients[sw_name].set_active_queue(active_qid) 86 | try: 87 | self.switch_clients[sw_name].set_active_queue(active_qid) 88 | except Exception: 89 | pass 90 | # print(f"Error setting active queue for {sw_name}: {e}") 91 | -------------------------------------------------------------------------------- /docs/tutorials/8-routing.md: -------------------------------------------------------------------------------- 1 | # Tutorial 8: Design Routing for an Application 2 | 3 | In this tutorial, you are given a topology that does **NOT** provide direct connections between every pair of nodes. 4 | Your goal is to design a **routing** on this topology for the same customized application introduced in Tutorial 7. 5 | 6 | ![topo](../../assets/task8-routing.png) 7 | 8 | You can now use **Source Routing**, a scheme that allows the sender of a packet to explicitly specify the entire path it should take through the network. 9 | 10 | ## Defining Paths in OpenOptics 11 | 12 | A path in OpenOptics can be defined as: 13 | ``` 14 | Path(src=0, arrival_ts=0, dst=5, steps=[Step(send_port=0, send_ts=3), Step(send_port=0, send_ts=2)]) 15 | ``` 16 | This example defines a path from node 0 to node 5 for packets that arrive at time slice 0. 17 | The packet takes two hops: 18 | - At the source 0, it is forwarded out at time slice 3. 19 | - At the next hop, it is forwarded out again at time slice 2. 20 | 21 | OpenOptics also provides helper functions to generate paths based on the topology schedule. 22 | For example, the default `my_routing` function in `tutorials/8-routing.py` generates direct paths for all node pairs with `find_direct_path()` 23 | ``` 24 | paths = OpticalRouting.find_direct_path(slice_to_topo, node1, node2) 25 | ``` 26 | Print out `paths` to check what paths are generated. 27 | 28 | The path information is embedded in the packet header by the sender ToR, and the following ToRs enforce this path when forwarding the packet. 29 | 30 | You can install a list of paths into the ToRs with `routing_mode` as **Source Routing**: 31 | ```python 32 | net.deploy_routing(paths, routing_mode="Source") 33 | ``` 34 | 35 | ## Application Setting (same as Tutorial 7) 36 | 37 | Group A (Hosts 0–3) Group B (Hosts 4–7) 38 | ┌───────────────┐ ┌───────────────┐ 39 | │ dense traffic │ │ dense traffic │ 40 | │ within group │ │ within group │ 41 | └───────────────┘ └───────────────┘ 42 | 43 | h0 --- h1 h4 --- h5 44 | | X | | X | 45 | h2 --- h3 h6 --- h7 46 | 47 | \ / 48 | \ / 49 | \______ light traffic _________/ 50 | between nodes in different groups 51 | 52 | • The applications are divided into two groups. 53 | 54 | • Group A = hosts 0–3; Group B = hosts 4–7. 55 | 56 | • Groups have denser intra-group communication and lighter inter-group communication. 57 | 58 | • Traffic ratio (intra-group : inter-group) = 2:1. (You don’t need to worry about this for this task.) 59 | 60 | By default, the script `tutorials/8-routing.py` creates direct routing on all nodes. 61 | This leads to packet loss, since not all node pairs have direct connections. 62 | 63 | ## Your Goal 64 | 65 | Design a routing scheme for the given topology that: 66 | 67 | 1. Ensures no packet loss. 68 | 2. **Bonus**: How much is your `ping`'s max RTT between `h0` and `h5`? Could you reduce it more? Share your tail `RTT` (reported by `OpenOptics-> test_task8_bonus`) with your peers. 69 | 70 | 71 | ```{note} 72 | For attendees of the SIGCOMM'25 Tutorial: You may notice some packet loss on the VMs. This is caused by limited computational resources. You will still pass tests with correct routing. 73 | ``` 74 | 75 | 76 | ### Notice: 77 | 78 | - Don't change the application. 79 | - Don't change the topology. 80 | - Don't change the slice duration. 81 | 82 | 83 | To test your design in the OpenOptics CLI: 84 | 85 | ```bash 86 | OpenOptics-> test_task8 87 | ``` 88 | Or only run the bonus test: 89 | ```bash 90 | OpenOptics-> test_task8_bonus 91 | ``` 92 | 93 | You will see **PASS** if your solution meets all requirements. 94 | 95 | You can also use `ping` between individual hosts to check connectivity and delay. -------------------------------------------------------------------------------- /tutorials/solutions/8-routings-solution-2.py: -------------------------------------------------------------------------------- 1 | import networkx as nx 2 | from typing import Dict 3 | 4 | from openoptics import Toolbox, OpticalTopo, OpticalRouting 5 | from openoptics.TimeFlowTable import Path, Step 6 | 7 | def my_topology(nb_node): 8 | # Do NOT change this function 9 | 10 | nodes = list(range(nb_node)) 11 | half = nb_node // 2 12 | circuits = [] 13 | """ 14 | A circuit: [time_slice, node1, node2, port1, port2] 15 | """ 16 | 17 | # Internal circuits 18 | circuits += OpticalTopo.round_robin(nodes=nodes[:half], start_time_slice=0) 19 | circuits += OpticalTopo.round_robin(nodes=nodes[half:], start_time_slice=0) 20 | circuits += [ 21 | [half-1, 0, 4, 0, 0], 22 | [half-1, 1, 5, 0, 0], 23 | [half-1, 2, 6, 0, 0], 24 | [half-1, 3, 7, 0, 0] 25 | ] 26 | 27 | return circuits 28 | 29 | def my_routing(slice_to_topo: Dict[int, nx.Graph]): 30 | """ 31 | This is the implementation of multi-hop routing. 32 | For h0-5 only. 33 | """ 34 | paths = [] 35 | 36 | nodes = slice_to_topo[0].nodes() 37 | 38 | # paths for node 0 39 | paths.extend([ 40 | Path(src=0, arrival_ts=0, dst=5, 41 | steps=[ 42 | Step(send_port=0, send_ts=2), # First send to node 1 at time slice 2 43 | Step(send_port=0, send_ts=3) # Send from node 1 to node 5 at time slice 3 44 | ]), 45 | Path(src=0, arrival_ts=1, dst=5, 46 | steps=[ 47 | Step(send_port=0, send_ts=2), # First send to node 1 at time slice 2 48 | Step(send_port=0, send_ts=3) # Send from node 1 to node 5 at time slice 3 49 | ]), 50 | Path(src=0, arrival_ts=2, dst=5, 51 | steps=[ 52 | Step(send_port=0, send_ts=2), # First send to node 1 at time slice 2 53 | Step(send_port=0, send_ts=3) # Send from node 1 to node 5 at time slice 3 54 | ]), 55 | 56 | Path(src=0, arrival_ts=3, dst=5, 57 | steps=[ 58 | Step(send_port=0, send_ts=3), # First send to node 4 at time slice 3 59 | Step(send_port=0, send_ts=2) # Send from node 4 to node 5 at time slice 2 60 | ]) 61 | ]) 62 | 63 | # paths for node 5 64 | paths.extend([ 65 | Path(src=5, arrival_ts=0, dst=0, 66 | steps=[ 67 | Step(send_port=0, send_ts=2), # First send to node 4 at time slice 2 68 | Step(send_port=0, send_ts=3) # Send from node 4 to node 0 at time slice 3 69 | ]), 70 | Path(src=5, arrival_ts=1, dst=0, 71 | steps=[ 72 | Step(send_port=0, send_ts=2), # First send to node 4 at time slice 2 73 | Step(send_port=0, send_ts=3) # Send from node 4 to node 0 at time slice 3 74 | ]), 75 | Path(src=5, arrival_ts=2, dst=0, 76 | steps=[ 77 | Step(send_port=0, send_ts=2), # First send to node 4 at time slice 2 78 | Step(send_port=0, send_ts=3) # Send from node 4 to node 0 at time slice 3 79 | ]), 80 | 81 | Path(src=5, arrival_ts=3, dst=0, 82 | steps=[ 83 | Step(send_port=0, send_ts=3), # First send to node 1 at time slice 3 84 | Step(send_port=0, send_ts=2) # Send from node 1 to node 0 at time slice 2 85 | ]), 86 | ]) 87 | #print(f"Paths: {paths}") 88 | return paths 89 | 90 | if __name__ == "__main__": 91 | nb_node = 8 92 | nb_link = 1 93 | 94 | net = Toolbox.BaseNetwork( 95 | name="task8-routings", 96 | backend="Mininet", 97 | nb_node=nb_node, 98 | nb_link=nb_link, 99 | time_slice_duration_ms=128, # in ms 100 | use_webserver=True, 101 | ) 102 | 103 | circuits = my_topology(nb_node) 104 | assert net.deploy_topo(circuits) 105 | 106 | paths = my_routing(net.get_topo()) 107 | assert net.deploy_routing(paths, routing_mode="Source") 108 | 109 | net.start() 110 | -------------------------------------------------------------------------------- /openoptics/dashboard/dashboard/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for dashboard project. 3 | 4 | Generated by 'django-admin startproject' using Django 3.2.19. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.2/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/3.2/ref/settings/ 11 | """ 12 | 13 | from pathlib import Path 14 | import os 15 | 16 | # Build paths inside the project like this: BASE_DIR / 'subdir'. 17 | BASE_DIR = Path(__file__).resolve().parent.parent 18 | 19 | 20 | # Quick-start development settings - unsuitable for production 21 | # See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ 22 | 23 | # SECURITY WARNING: keep the secret key used in production secret! 24 | SECRET_KEY = "django-insecure-n9%j2#86ur+cqthkdqzddebqg=&_n2k-&+6g-d9p(fum%!#*b(" 25 | 26 | # SECURITY WARNING: don't run with debug turned on in production! 27 | DEBUG = True 28 | 29 | ALLOWED_HOSTS = ["*"] 30 | 31 | # Application definition 32 | 33 | INSTALLED_APPS = [ 34 | "daphne", 35 | "django.contrib.admin", 36 | "django.contrib.auth", 37 | "django.contrib.contenttypes", 38 | "django.contrib.sessions", 39 | "django.contrib.messages", 40 | "django.contrib.staticfiles", 41 | "dashboardapp", 42 | "channels", 43 | ] 44 | 45 | MIDDLEWARE = [ 46 | "django.middleware.security.SecurityMiddleware", 47 | "django.contrib.sessions.middleware.SessionMiddleware", 48 | "django.middleware.common.CommonMiddleware", 49 | "django.middleware.csrf.CsrfViewMiddleware", 50 | "django.contrib.auth.middleware.AuthenticationMiddleware", 51 | "django.contrib.messages.middleware.MessageMiddleware", 52 | "django.middleware.clickjacking.XFrameOptionsMiddleware", 53 | ] 54 | 55 | ROOT_URLCONF = "dashboard.urls" 56 | 57 | TEMPLATES = [ 58 | { 59 | "BACKEND": "django.template.backends.django.DjangoTemplates", 60 | "DIRS": [], 61 | "APP_DIRS": True, 62 | "OPTIONS": { 63 | "context_processors": [ 64 | "django.template.context_processors.debug", 65 | "django.template.context_processors.request", 66 | "django.contrib.auth.context_processors.auth", 67 | "django.contrib.messages.context_processors.messages", 68 | ], 69 | }, 70 | }, 71 | ] 72 | 73 | WSGI_APPLICATION = "dashboard.wsgi.application" 74 | ASGI_APPLICATION = "dashboard.asgi.application" 75 | 76 | 77 | # Database 78 | # https://docs.djangoproject.com/en/3.2/ref/settings/#databases 79 | 80 | DATABASES = { 81 | "default": { 82 | "ENGINE": "django.db.backends.sqlite3", 83 | "NAME": BASE_DIR / "db.sqlite3", 84 | } 85 | } 86 | 87 | 88 | # Password validation 89 | # https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators 90 | 91 | AUTH_PASSWORD_VALIDATORS = [ 92 | { 93 | "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", 94 | }, 95 | { 96 | "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", 97 | }, 98 | { 99 | "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", 100 | }, 101 | { 102 | "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", 103 | }, 104 | ] 105 | 106 | 107 | # Internationalization 108 | # https://docs.djangoproject.com/en/3.2/topics/i18n/ 109 | 110 | LANGUAGE_CODE = "en-us" 111 | 112 | TIME_ZONE = "UTC" 113 | 114 | USE_I18N = True 115 | 116 | USE_L10N = True 117 | 118 | USE_TZ = True 119 | 120 | 121 | # Static files (CSS, JavaScript, Images) 122 | # https://docs.djangoproject.com/en/3.2/howto/static-files/ 123 | 124 | STATIC_URL = "/static/" 125 | 126 | # Default primary key field type 127 | # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field 128 | 129 | DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" 130 | 131 | CHANNEL_LAYERS = { 132 | "default": { 133 | "BACKEND": "channels_redis.core.RedisChannelLayer", 134 | "CONFIG": { 135 | "hosts": [("127.0.0.1", 6379)], 136 | }, 137 | }, 138 | } 139 | 140 | MEDIA_ROOT = os.path.join(BASE_DIR, "media") 141 | MEDIA_URL = "/media/" 142 | 143 | STATIC_ROOT = os.path.join(BASE_DIR, "static") 144 | -------------------------------------------------------------------------------- /docs/tutorials/1-get-started.md: -------------------------------------------------------------------------------- 1 | # Tutorial 1: Get Started 2 | 3 | Welcome to OpenOptics Tutorial! 4 | This first tutorial will help you get familiar with the basic workflow and dashboard. 5 | You’ll run a Python script to deploy a simple optical data center network (DCN) in an emulation environment (Mininet). 6 | 7 | If you are attending SIGCOMM’25 OpenOptics tutorial, you can log in to your assigned virtual machine (VM) using the commands below. 8 | If not, please follow the installation instruction at [Quick Start](../quickstart) to set up your environment if you haven't. 9 | 10 | ```{admonition} Acknowledgments 11 | Many thanks to [measurement.network](https://measurement.network/) for providing the VMs for this SIGCOMM'25 Tutorial, and to the team ([Tobias Fiebig](https://www.mpi-inf.mpg.de/departments/inet/people/tobias-fiebig)) for managing this wonderful project. 12 | ``` 13 | 14 | --- 15 | 16 | ## Step 1: Log into Your VM 17 | 18 | First, log into your VM. The `-L` flag forwards the port for the web dashboard, allowing you to access it from your local machine. 19 | 20 | ```bash 21 | ssh -L localhost:8001:localhost:8001 USER_NAME@YOUR_HOST_NAME 22 | ``` 23 | 24 | If you are using VS Code with Remote Development, you can also use this command to connect your editor to the VM. 25 | 26 | ## Step 2: Enter the OpenOptics Environment 27 | 28 | ### Option A: With VS Code 29 | 30 | 1. Make sure you have connected to the new remote with the above `ssh` command. 31 | 2. With Dev Containers extension installed, press: 32 | - Ctrl+Shift+P (Windows/Linux) 33 | - Command+Shift+P (Mac) 34 | 3. Run **Dev Containers: Attach to Running Container** and pick /openoptics. 35 | 36 | ```{note} 37 | Do NOT select **Dev Containers: Reopen in Container**. 38 | ``` 39 | 40 | ### Option B: With Terminal 41 | Execute the following command after you log into your VM 42 | 43 | ``` 44 | sudo docker exec -it openoptics bash 45 | ``` 46 | 47 | You are all set! Let's get started! 48 | 49 | ### 1. Execute the OpenOptics Python Script. 50 | 51 | ```bash 52 | cd /openoptics/tutorials 53 | python3 1-get-started.py 54 | ``` 55 | 56 | The script (`tutorials/1-get-started.py`) contains: 57 | 58 | ```python 59 | from openoptics import Toolbox, OpticalTopo, OpticalRouting 60 | 61 | if __name__ == "__main__": 62 | 63 | nb_node = 8 64 | 65 | net = Toolbox.BaseNetwork( 66 | name="task1", 67 | backend="Mininet", 68 | nb_node = nb_node, 69 | nb_host_per_tor = 1, 70 | time_slice_duration_ms = 512, # in ms 71 | use_webserver=True) 72 | 73 | circuits = OpticalTopo.round_robin(nb_node=nb_node) 74 | assert net.deploy_topo(circuits) 75 | 76 | paths = OpticalRouting.routing_direct(net.get_topo()) 77 | assert net.deploy_routing(paths) 78 | 79 | net.start() 80 | ``` 81 | 82 | This script creates an optical DCN with: 83 | 84 | * An 8-node optical network. 85 | * A round-robin optical topology. 86 | * A direct routing between nodes. 87 | * A web server for monitoring at http://localhost:8001. 88 | 89 | ![Architecture](../../assets/arch.png) 90 | 91 | 92 | Under the hood, `BaseNetwork` creates a Mininet network with OCS, switches, and hosts (`h0`-`h7`). 93 | 94 | Each ToR switch is connected to a port of optical circuit switch (OCS), 95 | and each ToR switch is connected to a host, as we set `nb_host_per_tor = 1`. 96 | 97 | ### 2. View the dashboard. 98 | 99 | After running the script, open your browser and navigate to http://localhost:8001. 100 | You should see the network topology and real-time network metrics. 101 | 102 | ![Dashboard Example](../../assets/dashboard.png) 103 | 104 | ### 3. Test Network Connectivity 105 | 106 | Use `ping` to test connectivity and delay between hosts: 107 | 108 | For example: 109 | ```bash 110 | # The first host is named with h0 111 | OpenOptics-> h0 ping h1 # Equivalent to execute "ping h1" at h0 112 | ``` 113 | 114 | You should also see queue depth changes on the dashboard during the `ping` test. 115 | 116 | ### 4. Experiment with Time Slice Duration 117 | 118 | Stop the script (Ctrl+D), then modify the `time_slice_duration_ms` parameter. 119 | 120 | For example, change it from **512 -> 1024** 121 | ```python 122 | ... 123 | time_slice_duration_ms = 1024 124 | ... 125 | ``` 126 | 127 | Then rerun the script and observe the change in `ping` delay at CLI and queue depth on the dashboard. 128 | With a longer slice duration, you should see both **delay** and **queue depth** increase. -------------------------------------------------------------------------------- /targets/tor_switch/tests/CLI_tests/testdata/table_dump_extra.json: -------------------------------------------------------------------------------- 1 | { 2 | "header_types": [ 3 | { 4 | "name": "standard_metadata_t", 5 | "id": 0, 6 | "fields": [ 7 | [ 8 | "ingress_port", 9 | 9 10 | ], 11 | [ 12 | "packet_length", 13 | 32 14 | ], 15 | [ 16 | "egress_spec", 17 | 9 18 | ], 19 | [ 20 | "egress_port", 21 | 9 22 | ], 23 | [ 24 | "egress_instance", 25 | 32 26 | ], 27 | [ 28 | "instance_type", 29 | 32 30 | ], 31 | [ 32 | "clone_spec", 33 | 32 34 | ], 35 | [ 36 | "_padding", 37 | 5 38 | ] 39 | ], 40 | "length_exp": null, 41 | "max_length": null 42 | } 43 | ], 44 | "headers": [ 45 | { 46 | "name": "standard_metadata", 47 | "id": 0, 48 | "header_type": "standard_metadata_t", 49 | "metadata": true 50 | } 51 | ], 52 | "header_stacks": [], 53 | "parsers": [ 54 | { 55 | "name": "parser", 56 | "id": 0, 57 | "init_state": "start", 58 | "parse_states": [ 59 | { 60 | "name": "start", 61 | "id": 0, 62 | "parser_ops": [], 63 | "transition_key": [], 64 | "transitions": [ 65 | { 66 | "value": "default", 67 | "mask": null, 68 | "next_state": null 69 | } 70 | ] 71 | } 72 | ] 73 | } 74 | ], 75 | "deparsers": [ 76 | { 77 | "name": "deparser", 78 | "id": 0, 79 | "order": [] 80 | } 81 | ], 82 | "meter_arrays": [], 83 | "actions": [ 84 | { 85 | "name": "_nop", 86 | "id": 0, 87 | "runtime_data": [], 88 | "primitives": [] 89 | } 90 | ], 91 | "pipelines": [ 92 | { 93 | "name": "ingress", 94 | "id": 0, 95 | "init_table": "empty_key", 96 | "tables": [ 97 | { 98 | "name": "empty_key", 99 | "id": 0, 100 | "match_type": "exact", 101 | "type": "tor", 102 | "max_size": 16384, 103 | "with_counters": false, 104 | "direct_meters": null, 105 | "support_timeout": false, 106 | "key": [], 107 | "actions": [ 108 | "_nop" 109 | ], 110 | "next_tables": { 111 | "_nop": null 112 | }, 113 | "base_default_next": null 114 | } 115 | ], 116 | "conditionals": [] 117 | }, 118 | { 119 | "name": "egress", 120 | "id": 1, 121 | "init_table": null, 122 | "tables": [], 123 | "conditionals": [] 124 | } 125 | ], 126 | "calculations": [], 127 | "checksums": [], 128 | "learn_lists": [], 129 | "field_lists": [], 130 | "counter_arrays": [], 131 | "register_arrays": [], 132 | "force_arith": [ 133 | [ 134 | "standard_metadata", 135 | "ingress_port" 136 | ], 137 | [ 138 | "standard_metadata", 139 | "packet_length" 140 | ], 141 | [ 142 | "standard_metadata", 143 | "egress_spec" 144 | ], 145 | [ 146 | "standard_metadata", 147 | "egress_port" 148 | ], 149 | [ 150 | "standard_metadata", 151 | "egress_instance" 152 | ], 153 | [ 154 | "standard_metadata", 155 | "instance_type" 156 | ], 157 | [ 158 | "standard_metadata", 159 | "clone_spec" 160 | ], 161 | [ 162 | "standard_metadata", 163 | "_padding" 164 | ] 165 | ] 166 | } -------------------------------------------------------------------------------- /targets/optical_switch/tests/CLI_tests/testdata/table_dump_extra.json: -------------------------------------------------------------------------------- 1 | { 2 | "header_types": [ 3 | { 4 | "name": "standard_metadata_t", 5 | "id": 0, 6 | "fields": [ 7 | [ 8 | "ingress_port", 9 | 9 10 | ], 11 | [ 12 | "packet_length", 13 | 32 14 | ], 15 | [ 16 | "egress_spec", 17 | 9 18 | ], 19 | [ 20 | "egress_port", 21 | 9 22 | ], 23 | [ 24 | "egress_instance", 25 | 32 26 | ], 27 | [ 28 | "instance_type", 29 | 32 30 | ], 31 | [ 32 | "clone_spec", 33 | 32 34 | ], 35 | [ 36 | "_padding", 37 | 5 38 | ] 39 | ], 40 | "length_exp": null, 41 | "max_length": null 42 | } 43 | ], 44 | "headers": [ 45 | { 46 | "name": "standard_metadata", 47 | "id": 0, 48 | "header_type": "standard_metadata_t", 49 | "metadata": true 50 | } 51 | ], 52 | "header_stacks": [], 53 | "parsers": [ 54 | { 55 | "name": "parser", 56 | "id": 0, 57 | "init_state": "start", 58 | "parse_states": [ 59 | { 60 | "name": "start", 61 | "id": 0, 62 | "parser_ops": [], 63 | "transition_key": [], 64 | "transitions": [ 65 | { 66 | "value": "default", 67 | "mask": null, 68 | "next_state": null 69 | } 70 | ] 71 | } 72 | ] 73 | } 74 | ], 75 | "deparsers": [ 76 | { 77 | "name": "deparser", 78 | "id": 0, 79 | "order": [] 80 | } 81 | ], 82 | "meter_arrays": [], 83 | "actions": [ 84 | { 85 | "name": "_nop", 86 | "id": 0, 87 | "runtime_data": [], 88 | "primitives": [] 89 | } 90 | ], 91 | "pipelines": [ 92 | { 93 | "name": "ingress", 94 | "id": 0, 95 | "init_table": "empty_key", 96 | "tables": [ 97 | { 98 | "name": "empty_key", 99 | "id": 0, 100 | "match_type": "exact", 101 | "type": "tor", 102 | "max_size": 16384, 103 | "with_counters": false, 104 | "direct_meters": null, 105 | "support_timeout": false, 106 | "key": [], 107 | "actions": [ 108 | "_nop" 109 | ], 110 | "next_tables": { 111 | "_nop": null 112 | }, 113 | "base_default_next": null 114 | } 115 | ], 116 | "conditionals": [] 117 | }, 118 | { 119 | "name": "egress", 120 | "id": 1, 121 | "init_table": null, 122 | "tables": [], 123 | "conditionals": [] 124 | } 125 | ], 126 | "calculations": [], 127 | "checksums": [], 128 | "learn_lists": [], 129 | "field_lists": [], 130 | "counter_arrays": [], 131 | "register_arrays": [], 132 | "force_arith": [ 133 | [ 134 | "standard_metadata", 135 | "ingress_port" 136 | ], 137 | [ 138 | "standard_metadata", 139 | "packet_length" 140 | ], 141 | [ 142 | "standard_metadata", 143 | "egress_spec" 144 | ], 145 | [ 146 | "standard_metadata", 147 | "egress_port" 148 | ], 149 | [ 150 | "standard_metadata", 151 | "egress_instance" 152 | ], 153 | [ 154 | "standard_metadata", 155 | "instance_type" 156 | ], 157 | [ 158 | "standard_metadata", 159 | "clone_spec" 160 | ], 161 | [ 162 | "standard_metadata", 163 | "_padding" 164 | ] 165 | ] 166 | } -------------------------------------------------------------------------------- /targets/tor_switch/tests/test_recirc.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright 2013-present Barefoot Networks, Inc. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include 17 | 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | #include // for std::fill_n 24 | 25 | #include 26 | 27 | #include "tor_switch.h" 28 | 29 | #include "utils.h" 30 | 31 | namespace fs = boost::filesystem; 32 | 33 | using bm::MatchErrorCode; 34 | using bm::ActionData; 35 | using bm::MatchKeyParam; 36 | using bm::entry_handle_t; 37 | 38 | namespace { 39 | 40 | void 41 | packet_handler(int port_num, const char *buffer, int len, void *cookie) { 42 | static_cast(cookie)->receive(port_num, buffer, len); 43 | } 44 | 45 | } // namespace 46 | 47 | class TorSwitch_RecircP4 : public ::testing::Test { 48 | protected: 49 | static constexpr size_t kMaxBufSize = 512; 50 | 51 | static constexpr bm::device_id_t device_id{0}; 52 | 53 | TorSwitch_RecircP4() 54 | : packet_inject(packet_in_addr) { } 55 | 56 | // Per-test-case set-up. 57 | // We make the switch a shared resource for all tests. This is mainly because 58 | // the tor_switch target detaches threads 59 | static void SetUpTestCase() { 60 | // bm::Logger::set_logger_console(); 61 | 62 | test_switch = new TorSwitch(8); // 8 ports 63 | 64 | // load JSON 65 | fs::path json_path = fs::path(testdata_dir) / fs::path(test_json); 66 | test_switch->init_objects(json_path.string()); 67 | 68 | // packet in - packet out 69 | test_switch->set_dev_mgr_packet_in(device_id, packet_in_addr, nullptr); 70 | test_switch->Switch::start(); // there is a start member in TorSwitch 71 | test_switch->set_packet_handler(packet_handler, 72 | static_cast(test_switch)); 73 | test_switch->start_and_return(); 74 | } 75 | 76 | // Per-test-case tear-down. 77 | static void TearDownTestCase() { 78 | delete test_switch; 79 | } 80 | 81 | virtual void SetUp() { 82 | packet_inject.start(); 83 | auto cb = std::bind(&PacketInReceiver::receive, &receiver, 84 | std::placeholders::_1, std::placeholders::_2, 85 | std::placeholders::_3, std::placeholders::_4); 86 | packet_inject.set_packet_receiver(cb, nullptr); 87 | 88 | // default actions for all tables 89 | test_switch->mt_set_default_action(0, "t_ingress", "_nop", ActionData()); 90 | } 91 | 92 | virtual void TearDown() { 93 | // kind of experimental, so reserved for testing 94 | test_switch->reset_state(); 95 | } 96 | 97 | protected: 98 | static const char packet_in_addr[]; 99 | static TorSwitch *test_switch; 100 | bm_apps::PacketInject packet_inject; 101 | PacketInReceiver receiver{}; 102 | 103 | private: 104 | static const char testdata_dir[]; 105 | static const char test_json[]; 106 | }; 107 | 108 | const char TorSwitch_RecircP4::packet_in_addr[] = 109 | "inproc://packets"; 110 | 111 | TorSwitch *TorSwitch_RecircP4::test_switch = nullptr; 112 | 113 | const char TorSwitch_RecircP4::testdata_dir[] = TESTDATADIR; 114 | const char TorSwitch_RecircP4::test_json[] = 115 | "recirc.json"; 116 | 117 | // Test added for this issue: 118 | // https://github.com/p4lang/behavioral-model/issues/626 119 | // The parser used the ingress_length field of Packet to determine whether the 120 | // packet has enough available bytes for an extract, which may not be correct 121 | // (e.g. an architecture like PSA may have an egress parser...). In this 122 | // specific case, the ingress_length field wasn't updated properly for 123 | // recirculated packet, which exposed the issue (by raising a PacketTooShort 124 | // exception in the parser). 125 | TEST_F(TorSwitch_RecircP4, Recirc) { 126 | static constexpr int port = 1; 127 | 128 | const char pkt[] = {'\x00'}; 129 | packet_inject.send(port, pkt, sizeof(pkt)); 130 | char recv_buffer[] = {'\x00', '\x00'}; 131 | int recv_port = -1; 132 | size_t recv_size = receiver.read( 133 | recv_buffer, sizeof(recv_buffer), &recv_port); 134 | EXPECT_EQ(port, recv_port); 135 | EXPECT_EQ(2, recv_size); 136 | EXPECT_EQ('\xab', recv_buffer[1]); 137 | } 138 | -------------------------------------------------------------------------------- /targets/optical_switch/main.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright 2013-present Barefoot Networks, Inc. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | /* 17 | * Antonin Bas (antonin@barefootnetworks.com) 18 | * 19 | */ 20 | 21 | /* Switch instance */ 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "optical_switch.h" 31 | 32 | namespace { 33 | OpticalSwitch *optical_switch; 34 | } // namespace 35 | 36 | namespace oswitch_runtime { 37 | shared_ptr get_handler(OpticalSwitch *sw); 38 | } // namespace oswitch_runtime 39 | 40 | int 41 | main(int argc, char* argv[]) { 42 | bm::TargetParserBasicWithDynModules optical_switch_parser; 43 | optical_switch_parser.add_flag_option( 44 | "enable-swap", 45 | "Enable JSON swapping at runtime"); 46 | optical_switch_parser.add_uint_option( 47 | "drop-port", 48 | "Choose drop port number (default is 511)"); 49 | optical_switch_parser.add_uint_option( 50 | "priority-queues", 51 | "Number of priority queues (default is 1)"); 52 | optical_switch_parser.add_uint_option( 53 | "nb-time-slices", 54 | "Number of time slices (default is 1)"); 55 | optical_switch_parser.add_uint_option( 56 | "time-slice-duration-ms", 57 | "Time slice duration in ms (default is 0)"); 58 | 59 | bm::OptionsParser parser; 60 | parser.parse(argc, argv, &optical_switch_parser); 61 | 62 | bool enable_swap_flag = false; 63 | if (optical_switch_parser.get_flag_option("enable-swap", &enable_swap_flag) 64 | != bm::TargetParserBasic::ReturnCode::SUCCESS) { 65 | std::exit(1); 66 | } 67 | 68 | uint32_t drop_port = 0xffffffff; 69 | { 70 | auto rc = optical_switch_parser.get_uint_option("drop-port", &drop_port); 71 | if (rc == bm::TargetParserBasic::ReturnCode::OPTION_NOT_PROVIDED) 72 | drop_port = OpticalSwitch::default_drop_port; 73 | else if (rc != bm::TargetParserBasic::ReturnCode::SUCCESS) 74 | std::exit(1); 75 | } 76 | 77 | uint32_t priority_queues = 0xffffffff; 78 | { 79 | auto rc = optical_switch_parser.get_uint_option( 80 | "priority-queues", &priority_queues); 81 | if (rc == bm::TargetParserBasic::ReturnCode::OPTION_NOT_PROVIDED) 82 | priority_queues = OpticalSwitch::default_nb_queues_per_port; 83 | else if (rc != bm::TargetParserBasic::ReturnCode::SUCCESS) 84 | std::exit(1); 85 | } 86 | 87 | uint32_t nb_time_slices = 0xffffffff; 88 | { 89 | auto rc = optical_switch_parser.get_uint_option( 90 | "nb-time-slices", &nb_time_slices); 91 | if (rc == bm::TargetParserBasic::ReturnCode::OPTION_NOT_PROVIDED) 92 | nb_time_slices = OpticalSwitch::default_nb_time_slices; 93 | else if (rc != bm::TargetParserBasic::ReturnCode::SUCCESS) 94 | std::exit(1); 95 | } 96 | 97 | uint32_t time_slice_duration_ms = 0xffffffff; 98 | { 99 | auto rc = optical_switch_parser.get_uint_option( 100 | "time-slice-duration-ms", &time_slice_duration_ms); 101 | if (rc == bm::TargetParserBasic::ReturnCode::OPTION_NOT_PROVIDED) 102 | time_slice_duration_ms = OpticalSwitch::default_time_slice_duration_ms; 103 | else if (rc != bm::TargetParserBasic::ReturnCode::SUCCESS) 104 | std::exit(1); 105 | } 106 | 107 | optical_switch = new OpticalSwitch(enable_swap_flag, drop_port, 108 | priority_queues, 109 | nb_time_slices, 110 | time_slice_duration_ms); 111 | 112 | int status = optical_switch->init_from_options_parser(parser); 113 | if (status != 0) std::exit(status); 114 | 115 | int thrift_port = optical_switch->get_runtime_port(); 116 | bm_runtime::start_server(optical_switch, thrift_port); 117 | using ::oswitch_runtime::OpticalSwitchIf; 118 | using ::oswitch_runtime::OpticalSwitchProcessor; 119 | bm_runtime::add_service( 120 | "optical_switch", oswitch_runtime::get_handler(optical_switch)); 121 | optical_switch->start_and_return(); 122 | 123 | while (true) std::this_thread::sleep_for(std::chrono::seconds(100)); 124 | 125 | return 0; 126 | } 127 | --------------------------------------------------------------------------------