├── .gitignore ├── README.md ├── controller └── sdvanet.py ├── log_files └── .keep ├── network_agent ├── README.md ├── __init__.py ├── __main__.py ├── default_agent.py ├── rsu_agent.py └── vehicle_agent.py ├── network_controller ├── __init__.py └── poxcontroller.py ├── network_ia ├── __init__.py ├── datasets.py ├── decidermanager.py └── roaddecider.py ├── network_log ├── __init__.py └── logger.py ├── requirements.txt ├── run_controller.py ├── run_scenario.py ├── sdvanets ├── __init__.py ├── __main__.py └── do_cfg.py ├── sumo_files ├── 1 │ ├── file.settings.xml │ ├── map.sumocfg │ ├── net.net.xml │ ├── reroute.add.xml │ └── route.rou.xml ├── README.md └── minimal │ ├── file.settings.xml │ ├── map.sumocfg │ ├── net.net.xml │ └── route.rou.xml ├── topology ├── __init__.py ├── minimal_scenario.py └── scenario.py └── utils ├── __init__.py ├── fileutils.py ├── log_cleaner.py ├── process_killer.py └── subnetutils.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | #*.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 98 | __pypackages__/ 99 | 100 | # Celery stuff 101 | celerybeat-schedule 102 | celerybeat.pid 103 | 104 | # SageMath parsed files 105 | *.sage.py 106 | 107 | # Environments 108 | .env 109 | .venv 110 | env/ 111 | venv/ 112 | ENV/ 113 | env.bak/ 114 | venv.bak/ 115 | 116 | # Spyder project settings 117 | .spyderproject 118 | .spyproject 119 | 120 | # Rope project settings 121 | .ropeproject 122 | 123 | # mkdocs documentation 124 | /site 125 | 126 | # mypy 127 | .mypy_cache/ 128 | .dmypy.json 129 | dmypy.json 130 | 131 | # Pyre type checker 132 | .pyre/ 133 | 134 | # pytype static type analyzer 135 | .pytype/ 136 | 137 | # Cython debug symbols 138 | cython_debug/ 139 | .idea/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | # [S]oftware [D]efined [V]ehicular [A]d-hoc [NET]work 5 | 6 | This project contains experiments using the concept of Software Defined Network and combines with the concept of Vehicular Ad-hoc Network to improve the communication between the network nodes. 7 | 8 | ## Prerequisites 9 | - Linux System's 10 | - [Mininet-WiFi](https://github.com/intrig-unicamp/mininet-wifi) 11 | - [Simulation of Urban MObility](https://www.eclipse.org/sumo/) 12 | 13 | 14 | ## Getting Started 15 | ```bash 16 | ~/sdvantes$ pip install -r requirements.txt 17 | ``` 18 | Before you run the commands below, see more about [setting up the scenario](sumo_files/README.md) and [how to use the agent](network_agent/README.md). 19 | After all, if that is your first try, you'll need to setup the mininet's sumo scenario, 20 | by running the following command: 21 | 22 | ```bash 23 | ~/sdvanets$ sudo python -m sdvanets --set-sumo=minimal 24 | ``` 25 | 26 | After, you just need to run this command: 27 | ```bash 28 | ~/sdvanets$ sudo python -m sdvanets 29 | ``` 30 | -------------------------------------------------------------------------------- /controller/sdvanet.py: -------------------------------------------------------------------------------- 1 | # Copyright 2011-2012 James McCauley 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 | # !/usr/bin/env python 17 | # -*- coding: utf-8 -*- 18 | 19 | """ 20 | An L2 learning switch. 21 | 22 | It is derived from one written live for an SDN crash course. 23 | It is somwhat similar to NOX's pyswitch in that it installs 24 | exact-match rules for each flow. 25 | """ 26 | 27 | from pox.core import core 28 | import pox.openflow.libopenflow_01 as of 29 | from pox.lib.util import dpid_to_str 30 | from pox.lib.util import str_to_bool 31 | import time 32 | from datetime import date 33 | 34 | log = core.getLogger() 35 | 36 | # We don't want to flood immediately when a switch connects. 37 | # Can be overriden on commandline. 38 | _flood_delay = 0 39 | 40 | 41 | def authorize(packet): 42 | log.debug("\nSrc address %s ...\n" % (packet.src)) 43 | log.debug("\nDst address %s ...\n" % (packet.dst)) 44 | 45 | return True 46 | 47 | 48 | class LearningSwitch(object): 49 | """ 50 | The learning switch "brain" associated with a single OpenFlow switch. 51 | 52 | When we see a packet, we'd like to output it on a port which will 53 | eventually lead to the destination. To accomplish this, we build a 54 | table that maps addresses to ports. 55 | 56 | We populate the table by observing traffic. When we see a packet 57 | from some source coming from some port, we know that source is out 58 | that port. 59 | 60 | When we want to forward traffic, we look up the desintation in our 61 | table. If we don't know the port, we simply send the message out 62 | all ports except the one it came in on. (In the presence of loops, 63 | this is bad!). 64 | 65 | In short, our algorithm looks like this: 66 | 67 | For each packet from the switch: 68 | 1) Use source address and switch port to update address/port table 69 | 2) Is transparent = False and either Ethertype is LLDP or the packet's 70 | destination address is a Bridge Filtered address? 71 | Yes: 72 | 2a) Drop packet -- don't forward link-local traffic (LLDP, 802.1x) 73 | DONE 74 | 3) Is destination multicast? 75 | Yes: 76 | 3a) Flood the packet 77 | DONE 78 | 4) Port for destination address in our address/port table? 79 | No: 80 | 4a) Flood the packet 81 | DONE 82 | 5) Is output port the same as input port? 83 | Yes: 84 | 5a) Drop packet and similar ones for a while 85 | 6) Install flow table entry in the switch so that this 86 | flow goes out the appopriate port 87 | 6a) Send the packet out appropriate port 88 | """ 89 | 90 | def __init__(self, connection, transparent): 91 | # Switch we'll be adding L2 learning switch capabilities to 92 | self.connection = connection 93 | self.transparent = transparent 94 | 95 | # Our table 96 | self.macToPort = {} 97 | 98 | # We want to hear PacketIn messages, so we listen 99 | # to the connection 100 | connection.addListeners(self) 101 | 102 | # We just use this to know when to log a helpful message 103 | self.hold_down_expired = _flood_delay == 0 104 | 105 | # log.debug("Initializing LearningSwitch, transparent=%s", 106 | # str(self.transparent)) 107 | 108 | def _handle_PacketIn(self, event): 109 | 110 | """ 111 | Handle packet in messages from the switch to implement above algorithm. 112 | """ 113 | 114 | packet = event.parsed 115 | 116 | def flood(message=None): 117 | """ Floods the packet """ 118 | msg = of.ofp_packet_out() 119 | if time.time() - self.connection.connect_time >= _flood_delay: 120 | # Only flood if we've been connected for a little while... 121 | 122 | if self.hold_down_expired is False: 123 | # Oh yes it is! 124 | self.hold_down_expired = True 125 | log.info("%s: Flood hold-down expired -- flooding", 126 | dpid_to_str(event.dpid)) 127 | 128 | if message is not None: log.debug(message) 129 | # log.debug("%i: flood %s -> %s", event.dpid,packet.src,packet.dst) 130 | # OFPP_FLOOD is optional; on some switches you may need to change 131 | # this to OFPP_ALL. 132 | msg.actions.append(of.ofp_action_output(port=of.OFPP_FLOOD)) 133 | else: 134 | pass 135 | # log.info("Holding down flood for %s", dpid_to_str(event.dpid)) 136 | msg.data = event.ofp 137 | msg.in_port = event.port 138 | self.connection.send(msg) 139 | 140 | def drop(duration=None): 141 | """ 142 | Drops this packet and optionally installs a flow to continue 143 | dropping similar ones for a while 144 | """ 145 | if duration is not None: 146 | if not isinstance(duration, tuple): 147 | duration = (duration, duration) 148 | msg = of.ofp_flow_mod() 149 | msg.match = of.ofp_match.from_packet(packet) 150 | msg.idle_timeout = duration[0] 151 | msg.hard_timeout = duration[1] 152 | msg.buffer_id = event.ofp.buffer_id 153 | self.connection.send(msg) 154 | elif event.ofp.buffer_id is not None: 155 | msg = of.ofp_packet_out() 156 | msg.buffer_id = event.ofp.buffer_id 157 | msg.in_port = event.port 158 | self.connection.send(msg) 159 | 160 | if authorize(packet): 161 | self.macToPort[packet.src] = event.port # 1 162 | 163 | if not self.transparent: # 2 164 | if packet.type == packet.LLDP_TYPE or packet.dst.isBridgeFiltered(): 165 | drop() # 2a 166 | return 167 | 168 | if packet.dst.is_multicast: 169 | flood() # 3a 170 | else: 171 | if packet.dst not in self.macToPort: # 4 172 | flood("Porta desconhecida para dispositivo %s -- 'flooding'" % (packet.dst,)) # 4a 173 | else: 174 | port = self.macToPort[packet.dst] 175 | if port == event.port: # 5 176 | # 5a 177 | log.warning("Porta de origem e destino igual para %s -> %s on %s.%s. Drop." 178 | % (packet.src, packet.dst, dpid_to_str(event.dpid), port)) 179 | drop(10) 180 | return 181 | # 6 182 | log.debug("\ninstalando fluxo para %s.%i -> %s.%i\n" % 183 | (packet.src, event.port, packet.dst, port)) 184 | msg = of.ofp_flow_mod() 185 | msg.match = of.ofp_match.from_packet(packet, event.port) 186 | msg.idle_timeout = 10 187 | msg.hard_timeout = 30 188 | msg.actions.append(of.ofp_action_output(port=port)) 189 | msg.data = event.ofp # 6a 190 | self.connection.send(msg) 191 | else: 192 | drop(5) 193 | log.debug("\nDispositivo: %s nao autorizado!!\n" % (packet.src)) 194 | 195 | 196 | class l2_learning(object): 197 | """ 198 | Waits for OpenFlow switches to connect and makes them learning switches. 199 | """ 200 | 201 | def __init__(self, transparent): 202 | core.openflow.addListeners(self) 203 | self.transparent = transparent 204 | 205 | def _handle_ConnectionUp(self, event): 206 | log.debug("Connection %s" % (event.connection,)) 207 | LearningSwitch(event.connection, self.transparent) 208 | 209 | 210 | def launch(transparent=False, hold_down=_flood_delay): 211 | """ 212 | Starts an L2 learning switch. 213 | """ 214 | try: 215 | global _flood_delay 216 | _flood_delay = int(str(hold_down), 10) 217 | assert _flood_delay >= 0 218 | except: 219 | raise RuntimeError("Expected hold-down to be a number") 220 | 221 | core.registerNew(l2_learning, str_to_bool(transparent)) 222 | -------------------------------------------------------------------------------- /log_files/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrismachado/sdvanets/1ce4f7ef0259cc4c60fc30b1e2a0fa7b8864f8d8/log_files/.keep -------------------------------------------------------------------------------- /network_agent/README.md: -------------------------------------------------------------------------------- 1 | # :cop: Agents 2 | The main idea is have an intelligence inside car, and this intelligence can be used to serve us with however information 3 | we want and we need. The agent can send any type of information. 4 | 5 | 6 | ## :blue_car: Vehicle Agent 7 | This agent run inside a vehicle. He can broadcast beacon messages for his neighbors, request or response some specific 8 | information. 9 | 10 | ## :traffic_light: RSU Agent 11 | This agent run inside a RSU. Its function is to communicate with the controller by updating it on the state of the road. 12 | 13 | ### Usage 14 | ```bash 15 | ~/sdvantes$ sudo python -m network_agent -h 16 | usage: agent.py [-h] [--log] [-s] [-n] [-r] [-m] [-e] [-d] [-w] [-c] [--filename [FILENAME]] [--filetime [FILETIME]] 17 | [--path [PATH]] [--name [NAME]] [--rsu] [--verbose] 18 | 19 | Sending and monitoring messages in vehicle ad-hoc network (VANET). Using flags to update the network. 20 | 21 | optional arguments: 22 | -h, --help show this help message and exit 23 | --log Enable log messages 24 | -s Log sent messages 25 | -n Log new neighbors 26 | -r Log received messages 27 | -m Log basic messages 28 | -e Log error messages 29 | -d Log debug messages 30 | -w Log warning messages 31 | -c Log critical messages 32 | --filename [FILENAME] Define filename to log file 33 | --filetime [FILETIME] Pass the time format to be appended in filename. (e.g) python -m network_agent --log --filetime %Y --filename=foo 34 | this command will result in the name: foo2020.log 35 | --path [PATH] If you want your won root path for save log files 36 | --name [NAME] Define name of agent (should be same of the car) 37 | --rsu Set the agent to be a RSU 38 | --verbose Allow the agent to send verbose messages 39 | 40 | ``` 41 | 42 | ### Examples 43 | 44 | Running the command below, you can see the file result example.log in log_files directory. 45 | ```bash 46 | ~/sdvantes$ sudo python agent.py --log -srnm --filename=example --name=example --verbose 47 | ``` 48 | 49 | ### Log formats 50 | 51 | The format of an agent's log is simple, but it will depend of the parameters you've choose. We have some examples in 52 | log_files directory, in our example, we've used the flags -srnm --verbose 53 | 54 | ```log 55 | 2020-09-26 20:23:45,754 rsu1 INFO Total received packets at iteration 24 : 63 56 | 2020-09-26 20:23:45,779 rsu1 INFO New neighbor MAC: 02:00:00:00:0f:00 | IP: 192.168.1.8 57 | 2020-09-26 20:23:45,779 rsu1 INFO Neighbors 3. 58 | 2020-09-26 20:23:45,780 rsu1 INFO Device rsu1 rebroadcast packet data b'code=18,name=car8,id=car8-25,n=0,t=1601162623.5860639' 59 | 2020-09-26 20:23:45,848 rsu1 INFO new update message received b'code=18,name=car8,id=car8-25,n=0,t=1601162623.5860639' 60 | ``` 61 | ### Agents codes 62 | To identify which agent is running, specific codes are used for each. 63 | ```python 64 | Agent.AGENT_CODE = 0x10 65 | RSUAgent.AGENT_CODE = 0x11 66 | VehicleAgent.AGENT_CODE = 0x12 67 | ``` 68 | 69 | -------------------------------------------------------------------------------- /network_agent/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrismachado/sdvanets/1ce4f7ef0259cc4c60fc30b1e2a0fa7b8864f8d8/network_agent/__init__.py -------------------------------------------------------------------------------- /network_agent/__main__.py: -------------------------------------------------------------------------------- 1 | from network_agent.default_agent import Agent 2 | from network_agent.rsu_agent import RSUAgent 3 | from network_agent.vehicle_agent import VehicleAgent 4 | 5 | import argparse 6 | import time 7 | 8 | if __name__ == '__main__': 9 | parser = argparse.ArgumentParser(description="Sending and monitoring messages in vehicle ad-hoc network (VANET). " 10 | "Using flags to update the network.") 11 | parser.add_argument('--log', action='store_true', help='Enable log messages') 12 | parser.add_argument('-s', action='store_true', help='Log sent messages') 13 | parser.add_argument('-n', action='store_true', help='Log new neighbors') 14 | parser.add_argument('-r', action='store_true', help='Log received messages') 15 | parser.add_argument('-m', action='store_true', help='Log basic messages') 16 | parser.add_argument('-e', action='store_true', help='Log error messages') 17 | parser.add_argument('-d', action='store_true', help='Log debug messages') 18 | parser.add_argument('-w', action='store_true', help='Log warning messages') 19 | parser.add_argument('-c', action='store_true', help='Log critical messages') 20 | parser.add_argument('--filename', nargs='?', const=str, help="Define filename to log file") 21 | parser.add_argument('--filetime', nargs='?', const=str, help='Pass the time format to be appended in filename. ' 22 | '(e.g) python -m network_agent --log --filetime %%Y ' 23 | '--filename=foo this command will result in the name:' 24 | ' foo{0}.log'.format(time.strftime('%Y'))) 25 | parser.add_argument('--path', nargs='?', const=str, help="If you want your won root path for save log files") 26 | parser.add_argument('--name', nargs='?', const=str, help="Define name of agent (should be same of the car)") 27 | parser.add_argument('--rsu', action='store_true', help='Set the agent to be a RSU') 28 | parser.add_argument('--verbose', action='store_true', help='Allow the agent to send verbose messages') 29 | 30 | args = parser.parse_args() 31 | d_args = vars(args) 32 | 33 | if d_args.pop('rsu'): 34 | agent = RSUAgent(name=d_args.pop('name'), args=d_args) 35 | else: 36 | agent = VehicleAgent(name=d_args.pop('name'), args=d_args) 37 | 38 | agent.run() 39 | -------------------------------------------------------------------------------- /network_agent/default_agent.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import scapy.all 3 | import time 4 | import logging 5 | import os 6 | 7 | from scapy.all import conf 8 | from scapy.all import AsyncSniffer, send 9 | from scapy.layers.inet import Ether, IP, ICMP 10 | from time import sleep 11 | from random import randint 12 | from threading import Thread 13 | from network_log.logger import Logging 14 | from utils.subnetutils import SubnetUtils 15 | 16 | 17 | # class Statistic(IntEnum): 18 | # # CNC = 1 19 | # DSN = 8 # max number of car neighbors 20 | # CNG = 120 # max number of packets received 21 | # MIN_DSN = 50 # 22 | # MED_DSN = 100 23 | 24 | 25 | class Agent: 26 | """ 27 | AGENT_CODE: Identification code of an agent. 28 | 0x10: Default agent; 29 | 0x11: RSU agent; 30 | 0x12: Vehicle agent. 31 | """ 32 | AGENT_CODE = 0x10 # 16 33 | START_TX_TIME = 2 # sec 34 | TX_DELAY = 5 # transmission delay in seconds 35 | RX_DELAY = 5 # receiver delay in seconds 36 | 37 | def __init__(self, name, **kwargs): 38 | 39 | if 'args' not in kwargs: 40 | raise ValueError('Args need to be specified. Use -h for help.') 41 | self.agent_name = name 42 | self.args = kwargs.pop('args') 43 | self.log = None # Logger class 44 | 45 | self.ifaces_names = [] # Interfaces with yours ip address 46 | self.ifaces_ip = [] # Ip of interfaces 47 | self.ifaces_netmask = [] 48 | self.ifaces_dict = dict() 49 | 50 | self.broadcast_addresses = None # Store broadcast address for each network 51 | self.receiver_packets = 0 # Count how many packets were received 52 | self.threads_monitor = None # Store sniffer thread 53 | 54 | self.neighbors = [] # Store MAC of nearby cars 55 | self.neighbors_timeout = dict() # Time to live for each neighbor 56 | self.neighbors_ip = dict() # A simple ARP table MAC -> IP 57 | 58 | self.network_status = [] 59 | self.id = 0 # Initial ID for message 60 | self.runtime_packets = dict() # Register the packets received during the simulation 61 | 62 | logging.getLogger("scapy.runtime").setLevel(logging.ERROR) # suppress scapy warnings 63 | 64 | def run(self): 65 | """ 66 | Start the agent and his functionalities 67 | """ 68 | self.get_ifaces_config() # set iface and ifaces_ip values 69 | self.mount_broadcast_address() # make all broadcast addresses 70 | self.config_log_features() 71 | 72 | iteration_count = 0 73 | try: 74 | self.log.log("%s entered the simulation" % self.agent_name, 'info', self.args['m']) 75 | 76 | while True: 77 | sleep_time = randint(3, Agent.TX_DELAY) - Agent.START_TX_TIME 78 | sleep(sleep_time) # wait time to transmit 79 | threads = [] 80 | for fnc in (self.broadcast, self.async_monitoring): 81 | process = Thread(target=fnc) 82 | process.start() 83 | threads.append(process) 84 | 85 | for process in threads: 86 | process.join(timeout=3) 87 | 88 | # Time for receive packets 89 | sleep(randint(3, Agent.RX_DELAY)) 90 | for process in self.threads_monitor: 91 | # process.join(timeout=5) # if you specify how many packets do you want to collect use this 92 | result = process.stop() 93 | self.network_status.append(process.results) 94 | self.receiver_packets += len(process.results) 95 | self.log.log(result, 'debug', self.args['d']) # log the amount of received packets 96 | if result is not None: 97 | for raw_packet in result: 98 | if raw_packet[IP].src not in self.ifaces_ip: 99 | if raw_packet[Ether].src not in self.neighbors: 100 | self.log.log("New neighbor MAC: %s | IP: %s" % 101 | (raw_packet[Ether].src, raw_packet[IP].src), 'info', self.args['n']) 102 | self.add_neighbor(raw_packet) # raw_packet[Ether].src MAC Address 103 | self.rebroadcast(packet=raw_packet) 104 | self.runtime_packets_log(packet=raw_packet) 105 | msg = "Total received packets at iteration %d : %d" % (iteration_count, self.receiver_packets) 106 | self.log.log(msg, 'info', flag=self.args['r']) 107 | self.network_status = [] 108 | 109 | # Start timeout for neighbors 110 | for neighbor in self.neighbors: 111 | process = Thread(target=self.update_neighbor, args=[neighbor]) 112 | process.start() 113 | 114 | # Flags updates 115 | # for target in (self.congestion(), self.density(), self.verify_density_packets()): 116 | # process = Thread(target=target) 117 | # process.start() 118 | 119 | # self.receiver_packets = 0 120 | iteration_count += 1 121 | self.log.do_runtime_packets(agent=self) 122 | 123 | except (KeyboardInterrupt, SystemExit): 124 | self.log.log("%s leave the simulation" % self.agent_name, 'info', self.args['m']) 125 | raise KeyboardInterrupt("Interrupt, exiting...") 126 | 127 | except OSError as error: 128 | self.log.log("%s" % error, 'critical', True) 129 | raise OSError("Critical error occurred.") 130 | 131 | except Exception as e: 132 | self.log.log("Agent stops by unknown error:\n%s" % e, 'error', self.args['e']) 133 | raise KeyboardInterrupt("Exiting...") 134 | 135 | def get_ifaces_config(self): 136 | """ 137 | configure ifaces per name, ip and makes a dict. 138 | :return: self.ifaces_dict 139 | """ 140 | _routes = conf.route.routes # getting ifaces config 141 | for _r in _routes: 142 | if _r[4] != '127.0.0.1': 143 | if _r[3] not in self.ifaces_names and _r[1] != 0: 144 | self.ifaces_names.append(_r[3]) 145 | self.ifaces_ip.append(_r[4]) 146 | self.ifaces_netmask.append(SubnetUtils(netmask=int(_r[1])).int_to_dotted_string()) 147 | self.ifaces_dict.update([(self.ifaces_names[-1], (self.ifaces_ip[-1], self.ifaces_netmask[-1]))]) 148 | return self.ifaces_dict 149 | 150 | def broadcast(self): 151 | """ 152 | Send broadcast message to each network 153 | :return: packets[] 154 | """ 155 | packets = [] 156 | try: 157 | for src, dst, iface in zip(self.ifaces_ip, self.broadcast_addresses, self.ifaces_names): 158 | self.log.log("Sending into iface: %s." % iface, 'info', self.args['s']) 159 | packets.append(self.build_own_packet(src=src, 160 | dst=dst, 161 | message=self.beacon_message())) 162 | send(packets[-1], iface=iface, count=len(self.neighbors) + 1, 163 | verbose=0) 164 | except PermissionError: 165 | raise PermissionError("Permission denied at broadcast, try run as superuser.") 166 | 167 | return packets 168 | 169 | def rebroadcast(self, packet): 170 | """ 171 | Rebroadcast received message from other vehicles (we can implement a lot of things here) 172 | :param packet: Message received from other vehicles 173 | :return: packet 174 | """ 175 | try: 176 | msg = "Device %s rebroadcast packet data %s " % (self.ifaces_names[0].split('-')[0], packet[ICMP].load) 177 | self.log.log(msg, 'info', True) 178 | send(packet, count=len(self.neighbors) + 1, verbose=1) 179 | except PermissionError: 180 | raise PermissionError("Permission denied at rebroadcast, try run as superuser") 181 | return packet 182 | 183 | def async_monitoring(self): 184 | """ 185 | Start threads for each interface that will sniff all packets incoming to the network 186 | :return: self.threads_monitor 187 | """ 188 | if len(self.ifaces_names) != 0: 189 | self.threads_monitor = [] 190 | for name, ip in zip(self.ifaces_names, self.ifaces_ip): 191 | monitor_process = AsyncSniffer(iface=name, filter='icmp and not host %s' % ip) 192 | monitor_process.start() 193 | self.threads_monitor.append(monitor_process) 194 | 195 | def mount_broadcast_address(self): 196 | """ 197 | Configure network broadcast address for each interface 198 | :return: self.broadcast_addresses 199 | """ 200 | if self.broadcast_addresses is None: 201 | self.broadcast_addresses = [] 202 | if len(self.ifaces_ip) != 0: 203 | for ip in self.ifaces_ip: 204 | separator = '.' 205 | split_ip = ip.split(separator) 206 | split_ip[3] = '255' 207 | self.broadcast_addresses.append(separator.join(split_ip)) 208 | 209 | return self.broadcast_addresses 210 | 211 | # TODO: consertar esse metodo, arrumando algum jeito de remover o estatico 212 | @staticmethod 213 | def build_own_packet(src, dst, message): 214 | """ 215 | Creates packet to be sent in the network. 216 | :param message: string message to be send 217 | :param src: source address 218 | :param dst: destination address 219 | :return: packet with layer 3, 4 and the message -> IP / ICMP / Message. 220 | """ 221 | return IP(src=src, dst=dst) / ICMP() / message 222 | 223 | def add_neighbor(self, neighbor): 224 | """ 225 | Add neighbor to the list of neighbors and define timeout for it. 226 | :param neighbor: neighbor's mac address 227 | :return: self.neighbors 228 | """ 229 | neighbor_mac = neighbor[Ether].src 230 | neighbor_ip = neighbor[IP].src 231 | 232 | self.neighbors.append(neighbor_mac) 233 | self.neighbors_ip.update([(neighbor_mac, neighbor_ip)]) 234 | self.neighbors_timeout.update([(neighbor_mac, randint(8, 12))]) 235 | self.log.log("Neighbors %d." % len(self.neighbors), 'info', self.args['n']) 236 | return self.neighbors 237 | 238 | def update_neighbor(self, neighbor): 239 | """ 240 | Update list of neighbor by the time of each neighbor have. 241 | :param neighbor: neighbor's mac address 242 | :return: self.neighbors_timeout 243 | """ 244 | try: 245 | while self.neighbors_timeout[neighbor] >= 1: 246 | sleep(1) # wait 1 second 247 | self.neighbors_timeout[neighbor] -= 1 248 | self.neighbors.remove(neighbor) 249 | self.neighbors_ip.pop(neighbor) 250 | self.neighbors_timeout.pop(neighbor) 251 | except KeyError as kex: 252 | self.log.log("Key %s was already removed. " % kex, 'warn') 253 | finally: 254 | return self.neighbors_timeout 255 | 256 | def runtime_packets_log(self, packet): 257 | """ 258 | Store into the log file the runtime packet content 259 | :param packet: Packet from other vehicle, a build packet message 260 | :return: content of the packet 261 | """ 262 | icmp_load = packet[ICMP].load 263 | if icmp_load in self.runtime_packets: 264 | self.runtime_packets[icmp_load] += 1 265 | else: 266 | self.runtime_packets[icmp_load] = 1 267 | self.log.log('new update message received %s' % icmp_load, 'info', self.args['r']) 268 | 269 | return icmp_load 270 | 271 | def config_log_features(self): 272 | """ 273 | Configure log class with parameters. 274 | :return: self.log 275 | """ 276 | filename = self.args['filename'] 277 | store_log_hour = self.args['filetime'] 278 | 279 | if filename is None: 280 | filename = 'default-log-name' 281 | 282 | if store_log_hour is not None: 283 | filename = '%s%s' % (filename, time.strftime(store_log_hour)) 284 | path = self.args['path'] 285 | if path is None: 286 | path = "%s/log_files/" % os.getcwd() 287 | self.log = Logging(path=path, filename='%s.log' % filename, 288 | log=self.args['log']) # setup log file location 289 | self.log.config_log(logger_name=filename) 290 | 291 | return self.log 292 | 293 | def beacon_message(self): 294 | """ 295 | Create message by using the id, flags and timestamp. (It's like a beacon message) 296 | :return: string 297 | """ 298 | timestamp = time.time() 299 | 300 | params = (self.AGENT_CODE, 301 | self.agent_name, 302 | self.generate_message_id(), 303 | len(self.neighbors), 304 | timestamp) 305 | 306 | if self.args['verbose']: 307 | message = "code={0[0]},name={0[1]},id={0[2]},n={0[3]},t={0[4]}".format(params) 308 | else: 309 | message = "{0[0]},{0[1]},{0[2]},{0[3]},{0[4]}".format(params) 310 | 311 | self.id += 1 312 | 313 | return message 314 | 315 | def generate_message_id(self): 316 | return "%s-%d" % (self.ifaces_names[0].split('-')[0], self.id) 317 | 318 | def neighbor_info(self): 319 | arp_table = [] 320 | for key, value in self.neighbors_ip.items(): 321 | arp_table.append('%s,%s' % (key, value)) 322 | return str(arp_table) 323 | 324 | def response(self, packet): 325 | pass 326 | 327 | def request(self): 328 | # neighbor_ip = packet[IP].src 329 | # icmp_load = packet[ICMP].load 330 | # request syntax `req?1,car1,,12,1200392091` or 331 | # no request syntax `req?-1,car1,11,231232251` 332 | pass 333 | -------------------------------------------------------------------------------- /network_agent/rsu_agent.py: -------------------------------------------------------------------------------- 1 | import scapy.all 2 | import time 3 | import logging 4 | import os 5 | 6 | from scapy.all import conf 7 | from scapy.all import AsyncSniffer, send 8 | from scapy.layers.inet import Ether, IP, ICMP 9 | from time import sleep 10 | from random import randint 11 | from threading import Thread 12 | from network_log.logger import Logging 13 | from utils.subnetutils import SubnetUtils 14 | from .default_agent import Agent 15 | 16 | 17 | class RSUAgent(Agent): 18 | 19 | def __init__(self, name, **kwargs): 20 | super(RSUAgent, self).__init__(name, **kwargs) 21 | self.AGENT_CODE = 0x11 # 17 22 | 23 | def response(self, packet): 24 | pass 25 | 26 | def request(self): 27 | pass 28 | -------------------------------------------------------------------------------- /network_agent/vehicle_agent.py: -------------------------------------------------------------------------------- 1 | import scapy.all 2 | import time 3 | import logging 4 | import os 5 | 6 | from scapy.all import conf 7 | from scapy.all import AsyncSniffer, send 8 | from scapy.layers.inet import Ether, IP, ICMP 9 | from time import sleep 10 | from random import randint 11 | from threading import Thread 12 | from network_log.logger import Logging 13 | from utils.subnetutils import SubnetUtils 14 | from .default_agent import Agent 15 | 16 | 17 | class VehicleAgent(Agent): 18 | 19 | def __init__(self, name, **kwargs): 20 | super(VehicleAgent, self).__init__(name, **kwargs) 21 | self.AGENT_CODE = 0x12 # 18 22 | 23 | def response(self, packet): 24 | pass 25 | 26 | def request(self): 27 | pass 28 | -------------------------------------------------------------------------------- /network_controller/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /network_controller/poxcontroller.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | 3 | 4 | class PoxController(object): 5 | def __init__(self, cmd, **kwargs): 6 | ''' 7 | This class will execute the Pox Controller. 8 | :param cmd: A command to execute the pox, should input the path too 9 | :param kwargs: Arguments that should go to the pox 10 | ''' 11 | self.cmd = cmd 12 | self.params = kwargs 13 | 14 | def run(self): 15 | self.start_pox() 16 | 17 | def start_pox(self): 18 | _cmd = self.__mount_exec_cmd() 19 | pox = subprocess.Popen(_cmd, 20 | stdin=subprocess.PIPE, 21 | stdout=subprocess.PIPE, 22 | stderr=subprocess.PIPE, 23 | shell=True) 24 | out, err = pox.communicate() 25 | if err: 26 | raise Exception(f'Error has occurred {err}') 27 | 28 | print('Pox controller started.') 29 | 30 | def __mount_exec_cmd(self): 31 | ''' 32 | Create the command to be use on the pox controller thread 33 | :return: string command 34 | ''' 35 | _cmd = 'gnome-terminal -- ' + self.cmd 36 | for values in self.params.values(): 37 | _cmd += ' ' + values 38 | 39 | return _cmd 40 | -------------------------------------------------------------------------------- /network_ia/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrismachado/sdvanets/1ce4f7ef0259cc4c60fc30b1e2a0fa7b8864f8d8/network_ia/__init__.py -------------------------------------------------------------------------------- /network_ia/datasets.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import random 3 | 4 | 5 | def make_dataset(days=30, hours=24, car_var=(1, 100, 100), min_var=0.5, target_values=(0, 1)): 6 | entry = [] 7 | target = [] 8 | for day in range(days): 9 | for hour in range(hours): 10 | cars = random.randint(car_var[0], car_var[1]) 11 | cons = random.randint(0, car_var[2]) 12 | entry.append([cars, cons, hour, 10.0/cars, 60.0/cars]) 13 | 14 | variation = float(cons)/float(cars) # Acceptance criteria 15 | 16 | if variation >= min_var: 17 | target.append(target_values[1]) 18 | else: 19 | target.append(target_values[0]) 20 | 21 | return np.array(entry, dtype=float), np.array(target, dtype=float) 22 | 23 | 24 | def normalize(X): 25 | for i in range(X.shape[1]): 26 | imax = max(X[:, i]) 27 | imin = min(X[:, i]) 28 | for j in range(X.shape[0]): 29 | X[j, i] = (X[j, i] - imin)/(imax - imin) 30 | 31 | -------------------------------------------------------------------------------- /network_ia/decidermanager.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | class DeciderManager(object): 4 | def __init__(self): 5 | pass 6 | 7 | def compare(self, deciders, hour=None): 8 | best = deciders[0] 9 | for decider in deciders[1:]: 10 | print("%s: %f < %s: %f" % (best.name, best.eval(hour=hour), decider.name, decider.eval(hour=hour))) 11 | if best.eval(hour=hour) < decider.eval(hour=hour): 12 | best = decider 13 | return best 14 | 15 | 16 | from utils.filereader import read_inputs 17 | from datasets import make_dataset 18 | from roaddecider import Decider 19 | 20 | samples1 = read_inputs('/home/wifi/PycharmProjects/data-extractor/data_extractor/service/examples', 'output.csv') 21 | samples2 = read_inputs('/home/wifi/PycharmProjects/data-extractor/data_extractor/service/examples', 'output2.csv') 22 | 23 | decider1 = Decider(inputs=samples1, name='rsu1') 24 | decider2 = Decider(inputs=samples2, name='rsu2') 25 | 26 | trainsamples, traintargets = make_dataset() 27 | decider1.clf.fit(trainsamples, traintargets) 28 | decider2.clf.fit(trainsamples, traintargets) 29 | 30 | rtargets1 = decider1.verify_road() 31 | rtargets2 = decider2.verify_road() 32 | 33 | decider_manager = DeciderManager() 34 | best = decider_manager.compare([decider1, decider2]) 35 | print('melhor caminho [geral] : %s' % best.name) 36 | best_per_hour = decider_manager.compare([decider1, decider2], hour=16) 37 | print('melhor caminho [horario, %d] : %s' % (16, best_per_hour.name)) 38 | 39 | print(decider1.eval(16)) 40 | print(decider2.eval(16)) 41 | 42 | print(rtargets1) 43 | print(rtargets2) -------------------------------------------------------------------------------- /network_ia/roaddecider.py: -------------------------------------------------------------------------------- 1 | from sklearn.linear_model import Perceptron 2 | from datasets import normalize 3 | import math 4 | 5 | 6 | class Decider(object): 7 | def __init__(self, inputs, name): 8 | self._inputs = inputs 9 | self.clf = Perceptron(max_iter=1000, eta0=0.15, tol=1e-3) 10 | self.name = name 11 | 12 | def set_inputs(self, new_inputs): 13 | self._inputs = new_inputs 14 | 15 | def get_inputs(self): 16 | return self._inputs 17 | 18 | def verify_road(self): 19 | return self.clf.predict(self._inputs) 20 | 21 | def eval(self, hour=None): 22 | if not len(self._inputs): 23 | return -1 24 | 25 | if hour is not None: 26 | inputs_ = [i for i in self._inputs if i[2] == hour] 27 | else: 28 | inputs_ = self._inputs 29 | 30 | rvalue = 0 31 | for inputs in inputs_: 32 | rvalue += (inputs[1] + (inputs[3] / inputs[4])) / inputs[0] 33 | return rvalue / len(inputs_) 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /network_log/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrismachado/sdvanets/1ce4f7ef0259cc4c60fc30b1e2a0fa7b8864f8d8/network_log/__init__.py -------------------------------------------------------------------------------- /network_log/logger.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | 4 | 5 | class Logging: 6 | def __init__(self, **kwargs): 7 | self.str_form = "%(asctime)s %(name)s %(levelname)s %(message)s" 8 | self.__rm_privileges = dict() 9 | filename = '' 10 | try: 11 | if 'filename' not in kwargs: 12 | raise ValueError('filename must be specified') 13 | if 'path' in kwargs: 14 | self.path = kwargs.pop('path') 15 | filename = self.path + kwargs.pop('filename') 16 | else: 17 | filename = kwargs.pop('filename') 18 | if 'log' not in kwargs: 19 | raise ValueError('log must be specified at the script\'s parameters') 20 | self.is_log = kwargs.pop('log') 21 | if not self.is_log: 22 | print('Logs was disabled') 23 | logging.basicConfig(filename=filename, format=self.str_form) 24 | self.logger = None 25 | 26 | except PermissionError: 27 | raise PermissionError('Permission denied, try with sudo.') 28 | 29 | except IOError: 30 | raise IOError('No such file or directory: %s' % filename) 31 | 32 | def log(self, msg, lvl, flag=None): 33 | if flag and self.is_log: 34 | if lvl == 'debug': 35 | self.logger.debug(msg) 36 | elif lvl == 'info': 37 | self.logger.info(msg) 38 | elif lvl == 'warn': 39 | self.logger.warn(msg) 40 | elif lvl == 'error': 41 | self.logger.error(msg) 42 | elif lvl == 'critical': 43 | self.logger.critical(msg) 44 | 45 | def config_log(self, logger_name): 46 | self.logger = logging.getLogger(logger_name) 47 | self.logger.setLevel(level=logging.DEBUG) 48 | 49 | ch = logging.StreamHandler() 50 | ch.setLevel(level=logging.DEBUG) 51 | formatter = logging.Formatter(self.str_form) 52 | ch.setFormatter(formatter) 53 | 54 | self.logger.addHandler(ch) 55 | 56 | def set_str_form(self, str_form): 57 | self.str_form = str_form 58 | 59 | def do_runtime_packets(self, agent): 60 | if agent.agent_name not in self.__rm_privileges: 61 | self.__rm_privileges.update([(agent.agent_name, False)]) 62 | 63 | if self.path: 64 | try: 65 | if not os.path.exists(self.path + 'runtime_packets'): 66 | os.mkdir(self.path + 'runtime_packets') 67 | 68 | filename = self.path + 'runtime_packets/%s_runtime.log' % agent.agent_name 69 | with open(filename, 'w+') as f: 70 | f.write("CODE: %d | NAME: %s\n" % (agent.AGENT_CODE, agent.agent_name)) 71 | for key, value in agent.runtime_packets.items(): 72 | f.write("%s: %d\n" % (key, value)) 73 | 74 | if not self.__rm_privileges[agent.agent_name]: 75 | self.__rm_privileges[agent.agent_name] = True 76 | os.system("chmod -R 777 %s" % filename) 77 | 78 | print("Logging runtime packets") 79 | 80 | except FileNotFoundError: 81 | raise FileNotFoundError("File not found.") 82 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | backports.functools-lru-cache==1.6.1 2 | cycler==0.10.0 3 | kiwisolver==1.1.0 4 | kiwisolver==1.1.0 5 | matplotlib==2.2.5 6 | numpy==1.16.6 7 | pyparsing==2.4.7 8 | python-dateutil==2.8.1 9 | pytz==2020.1 10 | scapy==2.4.3 11 | six==1.15.0 12 | subprocess32==3.5.4 13 | 14 | mininet~=2.3.0.dev6 15 | enum34~=1.1.10 -------------------------------------------------------------------------------- /run_controller.py: -------------------------------------------------------------------------------- 1 | from network_controller.poxcontroller import PoxController 2 | 3 | if __name__ == '__main__': 4 | pox = PoxController(cmd='/home/ubuntu/pox/pox.py', 5 | script='forwarding.l3_learning', 6 | ofst='openflow.spanning_tree --no-flood --hold-down', 7 | debug='log.level --DEBUG', 8 | pretty_log='samples.pretty_log', 9 | ofdc='openflow.discovery host_tracker info.packet_dump', 10 | ofport='openflow.of_01 --port=6653', 11 | log='log --file=/home/ubuntu/SDVANETS/log_files/pox.log' 12 | ) 13 | pox.run() 14 | -------------------------------------------------------------------------------- /run_scenario.py: -------------------------------------------------------------------------------- 1 | from mininet.log import setLogLevel 2 | from topology import scenario 3 | 4 | if __name__ == '__main__': 5 | setLogLevel('info') 6 | scenario.topology() 7 | -------------------------------------------------------------------------------- /sdvanets/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrismachado/sdvanets/1ce4f7ef0259cc4c60fc30b1e2a0fa7b8864f8d8/sdvanets/__init__.py -------------------------------------------------------------------------------- /sdvanets/__main__.py: -------------------------------------------------------------------------------- 1 | from .do_cfg import * 2 | import argparse 3 | 4 | if __name__ == '__main__': 5 | parser = argparse.ArgumentParser(description="[S]oftware [D]efined [V]ehicular [A]d-hoc [NET]work.\n" 6 | "This project contains experiments using the concept of Software " 7 | "Defined Network and combines with the concept of Vehicular Ad-hoc " 8 | "Network to improve the communication between the network nodes.") 9 | parser.add_argument('-c', action='store_true', help='Allow script to run mn -c, mininet garbage collector') 10 | parser.add_argument('--set-sumo', nargs='?', help='Pass the sumo scenarios to set mininet\'s sumo files') 11 | parser.add_argument('--mn-path', nargs='?', const=str, help="Path to mininet-wifi directory") 12 | parser.add_argument('--mn-dirname', nargs='?', const=str, help="Mininet-wifi directory name") 13 | parser.add_argument('--no-pox', action='store_true', help='Do this command if you do not want use pox controller') 14 | parser.add_argument('--scenario', nargs='?', const=str, help="Change to specific scenario, specify the full path," 15 | " e.g PATH/file.py") 16 | 17 | args = parser.parse_args() 18 | d_args = vars(args) 19 | 20 | if d_args['mn_dirname']: 21 | print('Defining mininet-wifi dirname {%s}' % d_args["mn_dirname"]) 22 | DIR_MN = d_args['mn_dirname'] 23 | 24 | if d_args['mn_path']: 25 | print('Defining mininet-wifi path {%s}' % d_args["mn_path"]) 26 | MN_WIFI_PATH = d_args['mn_path'] 27 | 28 | if not does_paths_exists(): 29 | print('Verify if the following paths are correct:') 30 | for PATH in ALL_PATHS: 31 | print(PATH) 32 | exit(0) 33 | 34 | if d_args['set_sumo']: 35 | print('Preparing mininet scenario into mininet-wifi...') 36 | do_change_sumo_files(dir_opt=d_args['set_sumo']) 37 | do_make() 38 | 39 | if d_args['c']: 40 | print('Cleaning mininet garbage...') 41 | do_mn_c() 42 | 43 | if not d_args['no_pox']: 44 | print('Running Pox Controller...') 45 | do_pox() 46 | 47 | print('Running Scenario...') 48 | if d_args['scenario']: 49 | print('Opening {%s}.py...' % d_args["scenario"]) 50 | do_scenario(d_args['scenario']) 51 | else: 52 | print('Setting to default scenario...') 53 | do_scenario() 54 | -------------------------------------------------------------------------------- /sdvanets/do_cfg.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | DIR_MN = 'mininet-wifi' 4 | DIR_POX = 'pox' 5 | ABS_PATH = os.path.abspath('') 6 | MN_WIFI_PATH = os.path.abspath('../%s/' % DIR_MN) 7 | POX_PATH = os.path.abspath('../%s/' % DIR_POX) 8 | 9 | ALL_PATHS = [ABS_PATH, MN_WIFI_PATH, POX_PATH] 10 | 11 | __FILES_TO = 'map.sumocfg net.net.xml reroute.add.xml route.rou.xml file.settings.xml' 12 | 13 | 14 | def do_change_sumo_files(dir_opt): 15 | if not os.path.exists('%s/sumo_files/%s/' % (ABS_PATH, dir_opt)): 16 | raise FileNotFoundError('Try with valid option.') 17 | 18 | print('Changing files sumo...') 19 | try: 20 | print('Removing all sumo files from %s/mn_wifi/sumo/data/' % MN_WIFI_PATH) 21 | os.system('cd %s/mn_wifi/sumo/data/ && rm -f -v %s' % (MN_WIFI_PATH, MN_WIFI_PATH)) 22 | print('Copying sumo files...') 23 | os.system('cd %s/sumo_files/%s/ && cp -v %s %s/mn_wifi/sumo/data/' 24 | % (ABS_PATH, dir_opt, __FILES_TO, MN_WIFI_PATH)) 25 | 26 | except PermissionError: 27 | raise PermissionError('Try run again as superuser.') 28 | 29 | 30 | def do_make(): 31 | print('Doing mininet make install ...') 32 | try: 33 | os.system('cd %s && make install' % MN_WIFI_PATH) 34 | except PermissionError: 35 | raise PermissionError('Try run again as superuser.') 36 | 37 | 38 | def do_mn_c(): 39 | try: 40 | os.system('mn -c') 41 | except PermissionError: 42 | raise PermissionError('Try run again as superuser.') 43 | 44 | 45 | def do_pox(): 46 | try: 47 | from network_controller.poxcontroller import PoxController 48 | 49 | pox = PoxController(cmd='%s/pox.py' % POX_PATH, 50 | script='forwarding.l3_learning', 51 | ofst='openflow.spanning_tree --no-flood --hold-down', 52 | debug='log.level --DEBUG', 53 | pretty_log='samples.pretty_log', 54 | ofdc='openflow.discovery host_tracker info.packet_dump', 55 | ofport='openflow.of_01 --port=6653', 56 | log='log --file=%s/log_files/pox.log' % ABS_PATH 57 | ) 58 | pox.run() 59 | except PermissionError: 60 | raise PermissionError('Try run again as superuser.') 61 | 62 | 63 | def do_scenario(scenario='topology/minimal_scenario.py'): 64 | try: 65 | import subprocess 66 | pox = subprocess.Popen('gnome-terminal -- python %s' % scenario, 67 | stdin=subprocess.PIPE, 68 | stdout=subprocess.PIPE, 69 | stderr=subprocess.PIPE, 70 | shell=True) 71 | 72 | out, err = pox.communicate() 73 | except PermissionError: 74 | raise PermissionError('Try run again as superuser.') 75 | 76 | except FileNotFoundError: 77 | raise FileNotFoundError('Could not found your scenario: {%s}' % scenario) 78 | 79 | 80 | def does_paths_exists(): 81 | exists = os.path.exists(ABS_PATH) 82 | exists &= os.path.exists(MN_WIFI_PATH) 83 | exists &= os.path.exists(POX_PATH) 84 | 85 | return exists 86 | -------------------------------------------------------------------------------- /sumo_files/1/file.settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /sumo_files/1/map.sumocfg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /sumo_files/1/net.net.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | -------------------------------------------------------------------------------- /sumo_files/1/reroute.add.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /sumo_files/1/route.rou.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /sumo_files/README.md: -------------------------------------------------------------------------------- 1 | # :wrench: Setting up the scenario 2 | Changing the standard sumo scenario of mininet-wifi. This changing is necessary to run our scenario. 3 | 4 | ## Changing default files 5 | ```bash 6 | ~/sdvanets$ cd sumo_files/1/ 7 | ~/sdvanets/sumo_files/1$ cp *.xml sumo.cfg PATH/mininet-wifi/mn_wifi/sumo/data/ 8 | 9 | ~/sdvanets/sumo_files/1$ cd PATH/mininet-wifi/ 10 | ~/mininet-wifi$ sudo make install 11 | ``` 12 | _note 1: PATH should be the real path to the directory mininet-wifi/ on your system_ 13 | 14 | _note 2: This scenario is syncronized with python scenario file_ 15 | 16 | >Every time that you change, this files you need to **execute the last command**. 17 | 18 | ## :warning: Important files 19 | - route.rou.xml 20 | 21 | In that file you'll have the route settings of all the cars in SUMO. It's important to define exactly the same number of the cars here and the main scenario script. 22 | 23 | - reroute.add.xml 24 | 25 | This file allows the cars to have route options to follow. For example at an intersection, they can follow any available path, based on a predefined probability 26 | 27 | - net.net.xml 28 | 29 | This is a file generated by the NETCONVERT command available by SUMO itself through other subfiles ([edge, node, type].xml). It is from him that SUMO creates the scenario. 30 | 31 | - file.settings.xml 32 | 33 | This file contains all the view configuration for SUMO's GUI. 34 | 35 | - map.sumocfg 36 | 37 | SUMO configuration file. It link all files cited above 38 | 39 | > Be careful when you change some of this files, the synchronization with mininet-wifi can be affected. 40 | 41 | 42 | You can find more information about SUMO [here](https://www.eclipse.org/sumo/). -------------------------------------------------------------------------------- /sumo_files/minimal/file.settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /sumo_files/minimal/map.sumocfg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /sumo_files/minimal/net.net.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | -------------------------------------------------------------------------------- /sumo_files/minimal/route.rou.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 7 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /topology/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrismachado/sdvanets/1ce4f7ef0259cc4c60fc30b1e2a0fa7b8864f8d8/topology/__init__.py -------------------------------------------------------------------------------- /topology/minimal_scenario.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """Sample file for SUMO 4 | 5 | ***Requirements***: 6 | 7 | sumo 1.1.0 8 | sumo-gui""" 9 | 10 | from mininet.node import RemoteController 11 | from mininet.log import info 12 | from mn_wifi.node import UserAP 13 | from mn_wifi.cli import CLI 14 | from mn_wifi.net import Mininet_wifi 15 | from mn_wifi.sumo.runner import sumo 16 | from mn_wifi.link import wmediumd, mesh 17 | from mn_wifi.wmediumdConnector import interference 18 | 19 | 20 | def topology(): 21 | "Create a network." 22 | net = Mininet_wifi(controller=RemoteController, accessPoint=UserAP, 23 | link=wmediumd, wmediumd_mode=interference) 24 | 25 | info("*** Creating nodes: car\n") 26 | cars = [] 27 | for id in range(0, 8): 28 | cars.append(net.addCar('car%s' % (id + 1), wlans=2, encrypt='wpa2,')) 29 | 30 | info("*** Creating nodes: rsu\n") 31 | rsus = [] 32 | for id in range(0, 3): 33 | rsus.append(net.addCar('rsu%s' % (id + 1), wlans=2, encrypt='wpa2,')) 34 | 35 | info("*** Creating nodes: controller\n") 36 | c1 = net.addController(name='c1', ip='127.0.0.1', port=6653, protocol='tcp') 37 | 38 | poss = ['100.00,100.00,0.0', '250.00,100.00,0.0', '400.00,100.00,0.0'] 39 | e1 = net.addAccessPoint('e1', ssid='vanet-ssid', mac='00:00:00:11:00:01', 40 | mode='g', channel='1', passwd='123456789a', 41 | encrypt='wpa2', position=poss[0]) 42 | e2 = net.addAccessPoint('e2', ssid='vanet-ssid', mac='00:00:00:11:00:02', 43 | mode='g', channel='6', passwd='123456789a', 44 | encrypt='wpa2', position=poss[1]) 45 | e3 = net.addAccessPoint('e3', ssid='vanet-ssid', mac='00:00:00:11:00:03', 46 | mode='g', channel='1', passwd='123456789a', 47 | encrypt='wpa2', position=poss[2]) 48 | 49 | info("*** Configuring Propagation Model\n") 50 | net.setPropagationModel(model="logDistance", exp=3.8) 51 | 52 | info("*** Configuring wifi nodes\n") 53 | net.configureWifiNodes() 54 | 55 | info("*** Adding link\n") 56 | net.addLink(rsus[0], rsus[1]) 57 | net.addLink(rsus[1], rsus[2]) 58 | 59 | net.addLink(e1, e2) 60 | net.addLink(e2, e3) 61 | 62 | for rsu in rsus: 63 | net.addLink(rsu, intf=rsu.wintfs[1].name, 64 | cls=mesh, ssid='mesh-ssid', channel=5) 65 | 66 | for car in cars: 67 | net.addLink(car, intf=car.wintfs[1].name, 68 | cls=mesh, ssid='mesh-ssid', channel=5) 69 | 70 | info("*** Starting sumo\n") 71 | # change config_file name if you want 72 | # use --random for active the probability attribute of sumo 73 | net.useExternalProgram(program=sumo, port=8813, 74 | # config_file='map.sumocfg', 75 | extra_params=["--start --delay 1000"], 76 | clients=1, exec_order=0 77 | ) 78 | 79 | info("*** Starting network\n") 80 | net.build() 81 | c1.start() 82 | e1.start([c1]) 83 | e2.start([c1]) 84 | e3.start([c1]) 85 | 86 | for rsu in rsus: 87 | rsu.setIP('192.168.0.%s/24' % (int(rsus.index(rsu)) + 101), 88 | intf='%s-wlan0' % rsu) 89 | rsu.setIP('192.168.1.%s/24' % (int(rsus.index(rsu)) + 101), 90 | intf='%s-mp1' % rsu) 91 | 92 | for rsu, pos in zip(rsus, poss): 93 | rsu.setPosition(pos=pos) 94 | 95 | for car in cars: 96 | car.setIP('192.168.0.%s/24' % (int(cars.index(car)) + 1), 97 | intf='%s-wlan0' % car) 98 | car.setIP('192.168.1.%s/24' % (int(cars.index(car)) + 1), 99 | intf='%s-mp1' % car) 100 | 101 | info("*** Starting telemetry\n") 102 | # Track the position of the nodes 103 | nodes = net.cars + net.aps 104 | net.telemetry(nodes=nodes, data_type='position', 105 | min_x=0, min_y=0, 106 | max_x=650, max_y=650) 107 | 108 | info("*** Starting agents\n") 109 | for car in net.cars: 110 | if car.name in [rsu.name for rsu in rsus]: 111 | car.cmd('xterm -e python3 -m network_agent ' 112 | '--log -srnm --filename %s --name=%s --verbose --rsu &' % (car, car)) 113 | else: 114 | car.cmd('xterm -e python3 -m network_agent --name=%s -srmn --verbose &' % car) 115 | 116 | info("*** Running CLI\n") 117 | CLI(net) 118 | 119 | info("*** Stopping network\n") 120 | net.stop() 121 | 122 | 123 | if __name__ == '__main__': 124 | from mininet.log import setLogLevel 125 | 126 | setLogLevel('info') 127 | topology() 128 | -------------------------------------------------------------------------------- /topology/scenario.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """Sample file for SUMO 4 | 5 | ***Requirements***: 6 | 7 | sumo 1.1.0 8 | sumo-gui""" 9 | 10 | from mininet.node import RemoteController 11 | from mininet.log import info 12 | from mn_wifi.node import UserAP 13 | from mn_wifi.cli import CLI 14 | from mn_wifi.net import Mininet_wifi 15 | from mn_wifi.sumo.runner import sumo 16 | from mn_wifi.link import wmediumd, mesh 17 | from mn_wifi.wmediumdConnector import interference 18 | 19 | 20 | def topology(): 21 | "Create a network." 22 | net = Mininet_wifi(controller=RemoteController, accessPoint=UserAP, 23 | link=wmediumd, wmediumd_mode=interference) 24 | 25 | info("*** Creating nodes: car\n") 26 | cars = [] 27 | for id in range(0, 21): 28 | cars.append(net.addCar('car%s' % (id + 1), wlans=2, encrypt='wpa2,')) 29 | 30 | info("*** Creating nodes: rsu\n") 31 | rsus = [] 32 | for id in range(0, 4): 33 | rsus.append(net.addCar('rsu%s' % (id + 1), wlans=2, encrypt='wpa2,')) 34 | 35 | info("*** Creating nodes: controller\n") 36 | c1 = net.addController(name='c1', ip='127.0.0.1', port=6653, protocol='tcp') 37 | 38 | e1 = net.addAccessPoint('e1', ssid='vanet-ssid', mac='00:00:00:11:00:01', 39 | mode='g', channel='1', passwd='123456789a', 40 | encrypt='wpa2', position='215.35,300.51,0.0') 41 | e2 = net.addAccessPoint('e2', ssid='vanet-ssid', mac='00:00:00:11:00:02', 42 | mode='g', channel='6', passwd='123456789a', 43 | encrypt='wpa2', position='300.81,206.09,0.0') 44 | e3 = net.addAccessPoint('e3', ssid='vanet-ssid', mac='00:00:00:11:00:03', 45 | mode='g', channel='1', passwd='123456789a', 46 | encrypt='wpa2', position='408.97,304.93,0.0') 47 | e4 = net.addAccessPoint('e4', ssid='vanet-ssid', mac='00:00:00:11:00:04', 48 | mode='g', channel='6', passwd='123456789a', 49 | encrypt='wpa2', position='519.27,206.09,0.0') 50 | 51 | info("*** Configuring Propagation Model\n") 52 | net.setPropagationModel(model="logDistance", exp=4) 53 | 54 | info("*** Configuring wifi nodes\n") 55 | net.configureWifiNodes() 56 | 57 | info("*** Adding link\n") 58 | net.addLink(rsus[0], rsus[1]) 59 | net.addLink(rsus[1], rsus[2]) 60 | net.addLink(rsus[2], rsus[3]) 61 | net.addLink(e1, e2) 62 | net.addLink(e2, e3) 63 | net.addLink(e3, e4) 64 | 65 | for rsu in rsus: 66 | net.addLink(rsu, intf=rsu.wintfs[1].name, 67 | cls=mesh, ssid='mesh-ssid', channel=5) 68 | 69 | for car in cars: 70 | net.addLink(car, intf=car.wintfs[1].name, 71 | cls=mesh, ssid='mesh-ssid', channel=5) 72 | 73 | info("*** Starting sumo\n") 74 | # change config_file name if you want 75 | # use --random for active the probability attribute of sumo 76 | net.useExternalProgram(program=sumo, port=8813, 77 | # config_file='map.sumocfg', 78 | extra_params=["--start --delay 1000"], 79 | clients=1, exec_order=0 80 | ) 81 | 82 | info("*** Starting network\n") 83 | net.build() 84 | c1.start() 85 | e1.start([c1]) 86 | e2.start([c1]) 87 | e3.start([c1]) 88 | e4.start([c1]) 89 | 90 | for rsu in rsus: 91 | rsu.setIP('192.168.0.%s/24' % (int(rsus.index(rsu)) + 101), 92 | intf='%s-wlan0' % rsu) 93 | rsu.setIP('192.168.1.%s/24' % (int(rsus.index(rsu)) + 101), 94 | intf='%s-mp1' % rsu) 95 | 96 | poss = ['215.35,300.51,0.0', '300.81,206.09,0.0', '408.97,304.93,0.0', '519.27,206.09,0.0'] 97 | for rsu, pos in zip(rsus, poss): 98 | rsu.setPosition(pos=pos) 99 | 100 | for car in cars: 101 | car.setIP('192.168.0.%s/24' % (int(cars.index(car)) + 1), 102 | intf='%s-wlan0' % car) 103 | car.setIP('192.168.1.%s/24' % (int(cars.index(car)) + 1), 104 | intf='%s-mp1' % car) 105 | 106 | info("*** Starting telemetry\n") 107 | # Track the position of the nodes 108 | nodes = net.cars + net.aps 109 | print(nodes) 110 | net.telemetry(nodes=nodes, data_type='position', 111 | min_x=0, min_y=0, 112 | max_x=850, max_y=650) 113 | 114 | info("*** Starting agents\n") 115 | for car in net.cars: 116 | if car.name in rsus: 117 | car.cmd('xterm -e python3 -m network_agent ' 118 | '--log -srnm --filename %s --name=%s --verbose --rsu &' % (car, car)) 119 | else: 120 | car.cmd('xterm -e python3 -m network_agent --name=%s -srmn --verbose &' % car) 121 | 122 | info("*** Running CLI\n") 123 | CLI(net) 124 | 125 | info("*** Stopping network\n") 126 | net.stop() 127 | 128 | 129 | if __name__ == '__main__': 130 | from mininet.log import setLogLevel 131 | 132 | setLogLevel('info') 133 | topology() 134 | -------------------------------------------------------------------------------- /utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrismachado/sdvanets/1ce4f7ef0259cc4c60fc30b1e2a0fa7b8864f8d8/utils/__init__.py -------------------------------------------------------------------------------- /utils/fileutils.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | 3 | 4 | class FileUtils: 5 | def __init__(self, **kwargs): 6 | # Thread.__init__(self) 7 | if "path" not in kwargs: 8 | raise ValueError("Path parameters not specified.") 9 | 10 | self.path = kwargs.pop("path") 11 | 12 | if "car" not in kwargs: 13 | raise ValueError("Car should be specified.") 14 | 15 | self.car = kwargs.pop("car") 16 | if type(self.car) is not str: 17 | self.path += "%s.txt" % self.car.name 18 | if 'position' not in self.car.params: 19 | print("Car doesn't have position argument. Write_pos method won't work.") 20 | else: 21 | self.path += "%s.txt" % self.car 22 | 23 | def write_pos(self): 24 | with open(self.path, 'a+') as f: 25 | f.write("%s\n" % str(self.car.params['position'])) 26 | 27 | def read_pos(self): 28 | with open(self.path, 'r') as f: 29 | last_line = f.read().splitlines()[-1] 30 | 31 | return last_line 32 | 33 | def write_forever(self, stop): 34 | while True: 35 | self.write_pos() 36 | sleep(1) # wait 1 sec to update again 37 | if stop(): 38 | break 39 | -------------------------------------------------------------------------------- /utils/log_cleaner.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | 4 | class LogCleaner: 5 | def __init__(self): 6 | self.path = '/'.join(os.path.abspath(__file__).split('/')[:-2]) 7 | 8 | def clean(self): 9 | try: 10 | cmd = 'cd %s && rm -rf -v log_files/*' % self.path 11 | print(cmd) 12 | os.system(cmd) 13 | except PermissionError: 14 | raise PermissionError("Try run again as superuser.") 15 | 16 | 17 | if __name__ == '__main__': 18 | LogCleaner().clean() 19 | -------------------------------------------------------------------------------- /utils/process_killer.py: -------------------------------------------------------------------------------- 1 | import os 2 | import subprocess 3 | import signal 4 | 5 | 6 | class ProcessKiller: 7 | def __init__(self, expression): 8 | self.expression = expression 9 | 10 | def stop(self): 11 | process_list = self.get_process_list() 12 | 13 | if not process_list: 14 | print('No process with expression \'{%s}\' was found.' % self.expression) 15 | return 16 | 17 | try: 18 | print('Trying to kill the process...') 19 | if len(process_list) <= 2: 20 | print('Process list is empty.') 21 | 22 | for process in process_list[:-2]: 23 | print('\tKilling process {%s}' % process) 24 | os.kill(int(process[0]), signal.SIGKILL) 25 | 26 | except PermissionError: 27 | raise PermissionError('Try again with sudo') 28 | 29 | except ProcessLookupError: 30 | raise ProcessLookupError('Can\'t find the process {%s}' % process[0]) 31 | 32 | def get_process_list(self): 33 | ps = subprocess.Popen('ps -ax | grep -E \'{%s}\'' % self.expression, 34 | stdout=subprocess.PIPE, 35 | stderr=subprocess.PIPE, 36 | shell=True) 37 | 38 | outs, err = ps.communicate() 39 | 40 | if err: 41 | raise Exception('Error has occurred') 42 | 43 | outs = outs.decode('utf-8').split('\n') 44 | out_str = [] 45 | for out in outs: 46 | out_aux = [] 47 | for _out in out.strip().split(' '): 48 | if _out != '' and _out != []: 49 | out_aux.append(_out) 50 | 51 | if out_aux: 52 | out_str.append(out_aux) 53 | 54 | return out_str 55 | 56 | 57 | if __name__ == '__main__': 58 | expression = 'python2.7|mininet|scenario|poxcontroller|mininet-wifi' 59 | ProcessKiller(expression=expression).stop() 60 | -------------------------------------------------------------------------------- /utils/subnetutils.py: -------------------------------------------------------------------------------- 1 | class SubnetUtils: 2 | 3 | def __init__(self, **kwargs): 4 | try: 5 | if 'netmask' not in kwargs: 6 | raise ValueError('Netmask not specified') 7 | if type(kwargs['netmask']) is not int: 8 | raise TypeError('Netmask should be integer current type %s' % type(kwargs['netmask'])) 9 | 10 | self.netmask = kwargs.pop('netmask') 11 | 12 | finally: 13 | pass 14 | 15 | def int_to_dotted_string(self): 16 | binary = bin(self.netmask).split('0b')[1] 17 | aux = '' 18 | result = '' 19 | for i in range(len(binary)): 20 | if i == 8 or i == 16 or i == 24 or i == 31: 21 | result += str(int(aux, 2)) 22 | if i != 31: 23 | result += '.' 24 | aux = binary[i] 25 | else: 26 | aux += binary[i] 27 | return result 28 | --------------------------------------------------------------------------------