To receive notifications about scheduled maintenance, please subscribe to the mailing-list gitlab-operations@sympa.ethz.ch. You can subscribe to the mailing-list at https://sympa.ethz.ch

Commit 129549e5 authored by cedgar's avatar cedgar
Browse files

release exercise 3

parent 4d14dcf7
This diff is collapsed.
"""
Inspired in the mininet CLI.
"""
import subprocess
from cmd import Cmd
from os import isatty
from select import poll, POLLIN
import select
import sys
import os
import atexit
class RSVPCLI( Cmd ):
"Simple command-line interface to talk to nodes."
prompt = 'rsvp-menu> '
def __init__( self, controller, stdin=sys.stdin, script=None,
*args, **kwargs ):
self.controller = controller
# Local variable bindings for py command
self.locals = { 'controller': controller }
# Attempt to handle input
self.inPoller = poll()
self.inPoller.register( stdin )
self.inputFile = script
Cmd.__init__( self, *args, stdin=stdin, **kwargs )
self.hello_msg()
if self.inputFile:
self.do_source( self.inputFile )
return
self.initReadline()
self.run()
readlineInited = False
def hello_msg(self):
"""
"""
print '======================================================================'
print 'Welcome to the RSVP CLI'
print '======================================================================'
print 'You can now make reservations for your hosts in the network.'
print 'To add a reservation run:'
print 'add_reservation <src> <dst> <duration> <bw> <priority>'
print ''
print 'To delete a reservation run: '
print 'del_reservation <src> <dst>'
print ''
@classmethod
def initReadline( cls ):
"Set up history if readline is available"
# Only set up readline once to prevent multiplying the history file
if cls.readlineInited:
return
cls.readlineInited = True
try:
from readline import ( read_history_file, write_history_file,
set_history_length )
except ImportError:
pass
else:
history_path = os.path.expanduser( '~/.rsvp_controller_history' )
if os.path.isfile( history_path ):
read_history_file( history_path )
set_history_length( 1000 )
atexit.register( lambda: write_history_file( history_path ) )
def run( self ):
"Run our cmdloop(), catching KeyboardInterrupt"
while True:
try:
if self.isatty():
subprocess.call( 'stty echo sane intr ^C',shell=True)
self.cmdloop()
break
except KeyboardInterrupt:
# Output a message - unless it's also interrupted
# pylint: disable=broad-except
try:
print( '\nInterrupt\n' )
except Exception:
pass
# pylint: enable=broad-except
def emptyline( self ):
"Don't repeat last command when you hit return."
pass
def getLocals( self ):
"Local variable bindings for py command"
self.locals.update( self.mn )
return self.locals
helpStr = (
'To add a reservation run:\n'
'add_reservation <src> <dst> <duration> <bw> <priority>\n'
'\n'
'To delete a reservation run: \n'
'del_reservation <src> <dst>\n'
''
)
def do_help( self, line ):
"Describe available CLI commands."
Cmd.do_help( self, line )
if line == '':
print( self.helpStr )
def do_exit( self, _line ):
"Exit"
assert self # satisfy pylint and allow override
return 'exited by user command'
def do_quit( self, line ):
"Exit"
return self.do_exit( line )
def do_EOF( self, line ):
"Exit"
print( '\n' )
return self.do_exit( line )
def isatty( self ):
"Is our standard input a tty?"
return isatty( self.stdin.fileno() )
"""
RSVP COMMANDS
"""
def do_add_reservation(self, line=""):
"""Adds a reservation using mpls.
add_reservation <src> <dst> <duration> <bw> <priority>
"""
# geta rguments
args = line.split()
# defaults
duration = 9999
bw = 1
priority = 1
if len(args) < 2:
print("Not enough args!")
return
elif len(args) == 2:
src, dst = args
elif len(args) == 3:
src, dst, duration = args
elif len(args) == 4:
src, dst, duration, bw = args
elif len(args) == 5:
src, dst, bw, duration, priority = args
else:
print("Too many args!")
return
# casts
duration = float(duration)
bw = float(bw)
priority = int(priority)
# add entry
res = self.controller.add_reservation(src, dst, duration, bw, priority)
def do_del_reservation(self, line=""):
"""Deletes a reservation"""
# gets arguments
args = line.split()
if len(args) < 2:
print("Not enough args!")
return
elif len(args) == 2:
src, dst = args[:2]
else:
print("Too many args!")
return
# add entry
res = self.controller.del_reservation(src, dst)
def do_del_all_reservations(self, line =""):
"""Deletes all the reservations"""
res = self.controller.del_all_reservations()
def do_print_reservations(self, line = ""):
"""Prints current reservations"""
print("Current Reservations:")
print("---------------------")
for i, ((src, dst), data) in enumerate(self.controller.current_reservations.items()):
print("{:>3} {}->{} : {}, bw:{}, priority:{}, timeout:{}".format(i, src, dst,
"->".join(data['path']), data['bw'], data['priority'], data["timeout"] ))
def do_print_link_capacity(self, line=""):
"""Prints current link capacities"""
print("Current Link Capacities:")
print("---------------------")
for edge, bw in self.controller.links_capacity.items():
print("{} -> {}".format(edge, bw))
\ No newline at end of file
<mxfile host="app.diagrams.net" modified="2020-09-28T16:28:42.488Z" agent="5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36" etag="u_q2yKSmjVGhZPcg4dIA" version="13.7.5" type="device" pages="2"><diagram id="B0WK-qs8H3m_uyVk83sW" name="Page-1">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</diagram><diagram name="Copy of Page-1" id="Jq4Bd32oKz4DNX3u5gQL">7V3Rcps4FP0aP8aDJBDw2KR1d2e2M5nJzG73aYcaYrPFyAty7PTrV9gShisSg2MDaeXO1OaCJOCcK917kMiE3K12n7NgvfzCwiiZYCvcTcjHCcbYR1R8FZZnaUFYWhZZHB5s6Gh4iH9E0mhJ6yYOo7x2IGcs4fG6bpyzNI3mvGYLsoxt64c9sqTe6jpYRJrhYR4kuvWvOOTLg9VzrKP9tyheLFXLyJJ7VoE6WBryZRCybcVEPk3IXcYYP/xa7e6ipLh76r4sUnR/iz7/8+PPZ/R5+3v4xbfubg6VzboUKS8hi1J+2arxoeqnINnI+yWvlT+rGzjfZE9RUQeakNsoDT8UoIjNeRLkeTwXxiVfJXJ/zjP2PbpjCcv2pQm28e1sVu5REFBhObQUhRp+Jy5THpezTTaPXrs2XIIk6B2xVcSzZ1Fwe6SBYsGywgBly6Ik4PFT/eQCycZFWV3Zwj2LxWljSzrKDcV06tRLHU5ZHliFSpWVbkd8eQ6qLtfX6uJBtoi4VpdAJ3iuHLYuDsgbTlM2dWMT2BZSbb10ejeYgjIeOVlGu6STzSAMijgUFBE/Dtertio4H017P+jgE+QqPlFlvuYls5klPm/1id6prrB1LAiuhaaeZ1PkkP3/+EJ+QNH1/ACyzbW6+4HjdfeDk83AEqedrQT2xUau4zn2ac8Rg+i6+LnaLYqAYzqP8zmbZmzDoyyX33X3CYN8ufe1wj8e4ySp+I1lEUIbPepx/9G8T8B/+xRlPBYBwh/Btyi5Z3nMY5aKfd8Y52xVOeBDEi+KHZyt5YWJHdFucgnPLGnnQqhKdKve63oN3ktedtQKzt1hdAyMXWFE2B8djNTA2BVG7NtgwHHosCC67UFM4vR7Hax/I86fZUoWbDgTJpbxJVuwVNxwJm6kjGB2Mf9aYCoGbbn5937Tl1sfdxLx/caz2kjFFX6tbhxKOWrzWGy/VSt3H2WxuEUFv8qaoe1N0VCLDEGCfQghTnnSYNEV8TAcza3z4qkbhGA3Bat6IZy6VITg9UtnhM+hM3qndHZ+NTpj16lX5VC7Vzr7ZojtPsQCzDw8eKSktEqDY2scbYDi4IESQgbDjhhiJe6XPfEIXBGbgPfKEcJwMiGCA//ZCrntgu5HPZXqaeBHLURiE8ieS1M0qJyNVR90AZ4iDMfJvonaQZO9Qn+Kfu7+tK2A4A/a7xIfEhqmSe0zLk0g80jLJzIXY3QHefoKXe8JRjeQ8KLdcS8RwugZjQigoas/GGzPaQuGwV7bp4wX47TR6rsmLzCY9DAePHcZVqz/ycfatj0TGlbetGFnYoGAr22/pCZNlCOt6/fdKw2r1v/kI60SrEZOaIxAqn02oZENpzp4uG9GdxDs38DoS3a1b6ThSXbZg/aWDtJmKmm9XOtAzkZ4SmF+4vSbb+MOjxKMfjmK6YvYs6cE+eUHSouuN/Ws4wefx07ioymt1ENAK6hnnnZ4XGJi1ffAUxejaWWv753LU+c1norcuF+e4tM8fWQpr6W2cjJ1UzbaIolNwI654MQ+tQ5kPaWh4hEi/RZuIvJotYrlvJxbpPZhHB0vJ2Vp1JiKQzUgjfiWZd/z6XoOM//JlTJw0WfBwduWo2/FIcr1NFWPcK2Xyf+mFBzrz2WWSCOMuBF88sq6FXnXq/BJk0YByLFVHIZFM7fbZcyjh3WwzwG2AiNhy9gmDY+KjKDtgzwppLYPfSryrombA+ccU+pruNkNsOGrwdbiKYXx8kG83IZrOzzFjOGcXH8CsNT58ms7ua0l21RXR/v18RYat/HxQXxcX2flkgYxvWcv19X0JTFe/rqXO77XAFy/fq6rxrkJweCyLwfOC3Gbpt71C5wujuZmWIXTl134fIcODhzRNcfc9JSngHN8fcZyv7DpElxODWw12GCm6vjDe5uuSOWOge1V2FzaNDmjX9h0ZSh3DWz1BQEERiUjGNx0aSi3DW5g+TmcsjyCcJI0zdOkCZf3pYYf/W/D1I6bfH/HPogDMFnvjjvFr4X83tfyDRrOrdaal/n70UiKz2ymN79XG4paVLPi7hxarp+NMGtnqB06ShpfjaY2fF+K6zfpDGqOcT80bZKlrsGn2axgVA90rtOUGJp2pil8JRYl/uA01dWw9yqqAJHXs4p/18RTez0VHUEWoatk71Vr6R1PouY2HF+20+Sf/eKpi2fvVYIZAZ5WU1jQK562rqkZ/2wrtcFFj81rM/rFUxfbzPjZ1j9hPDQGPHUVzvhnW/+Eb4GiqubB0NTFOeOd53rn8Gjqkt17Vex6R9MDT6moZw/e1epCnglt206RBbqsS4YfOXXBy/S1rV/zCjOVhtde9YumrguZOKgtmpocbaHBvdPoQufiiRBwzjGkKbosZDrblg+j8ejQdIwodL5zwoW5Q2cpjlGEzgbTGxuWuhpkMs6W3SwMgqhLBgZTF4NMvtkSTA++F2twz9S1INPLtn09L0w27cG1IEfXgkwE1HbQhNKeWnV1eTDF5vHvEh6W4h//vCP59D8=</diagram></mxfile>
\ No newline at end of file
{
"program": "rsvp.p4",
"switch": "simple_switch",
"compiler": "p4c",
"options": "--target bmv2 --arch v1model --std p4-16",
"switch_cli": "simple_switch_CLI",
"cli": true,
"pcap_dump": false,
"enable_log": false,
"topo_module": {
"file_path": "",
"module_name": "p4utils.mininetlib.apptopo",
"object_name": "AppTopoStrategies"
},
"controller_module": null,
"topodb_module": {
"file_path": "",
"module_name": "p4utils.utils.topology",
"object_name": "Topology"
},
"mininet_module": {
"file_path": "",
"module_name": "p4utils.mininetlib.p4net",
"object_name": "P4Mininet"
},
"topology": {
"assignment_strategy": "l3",
"default_bw": 10,
"links": [["h1", "s1"],
["h2", "s1"],
["s1", "s2"],
["s1", "s3"],
["s2", "s3"],
["h3", "s2"],
["h4", "s2"],
["h5", "s3"],
["h6", "s3"]],
"hosts": {
"h1": {
},
"h2": {
},
"h3": {
},
"h4": {
},
"h5": {
},
"h6": {
}
},
"switches": {
"s1": {
},
"s2": {
},
"s3": {
}
}
}
}
{
"program": "rsvp.p4",
"switch": "simple_switch",
"compiler": "p4c",
"options": "--target bmv2 --arch v1model --std p4-16",
"switch_cli": "simple_switch_CLI",
"cli": true,
"pcap_dump": true,
"enable_log": true,
"topo_module": {
"file_path": "",
"module_name": "p4utils.mininetlib.apptopo",
"object_name": "AppTopoStrategies"
},
"controller_module": null,
"topodb_module": {
"file_path": "",
"module_name": "p4utils.utils.topology",
"object_name": "Topology"
},
"mininet_module": {
"file_path": "",
"module_name": "p4utils.mininetlib.p4net",
"object_name": "P4Mininet"
},
"topology": {
"assignment_strategy": "l3",
"default_bw" : 10,
"links": [["h1", "s1"],
["h2", "s1"],
["s1", "s2"],
["s1", "s3"],
["s2", "s4"],
["s3", "s4"],
["s2", "s5"],
["s3", "s6"],
["s4", "s5"],
["s4", "s6"],
["s5", "s7"],
["s6", "s7"],
["s7", "h5"],
["s7", "h6"],
["h3", "s3"],
["h4", "s5"]
],
"hosts": {
"h1": {
},
"h2": {
},
"h3": {
},
"h4": {
},
"h5": {
},
"h6": {
}
},
"switches": {
"s1": {
},
"s2": {
},
"s3": {
},
"s4": {
},
"s5": {
},
"s6": {
},
"s7": {
}
}
}
}
from p4utils.utils.topology import Topology
from p4utils.utils.sswitch_API import SimpleSwitchAPI
from cli import RSVPCLI
import os
import threading
import time
class RSVPController(object):
def __init__(self):
"""Initializes the topology and data structures
"""
if not os.path.exists("topology.db"):
print("Could not find topology object!!!\n")
raise(Exception)
self.topo = Topology(db="topology.db")
self.controllers = {}
self.init()
# sorted by timeouts
self.current_reservations = {}
# initial link capacity
self.links_capacity = self.build_links_capacity()
self.update_lock = threading.Lock()
self.timeout_thread = threading.Thread(target=self.reservations_timeout_thread, args=(1, ))
self.timeout_thread.daemon = True
self.timeout_thread.start()
def init(self):
"""Connects to switches and resets.
"""
self.connect_to_switches()
self.reset_states()
def reset_states(self):
"""Resets registers, tables, etc.
"""
[controller.reset_state() for controller in self.controllers.values()]
def connect_to_switches(self):
"""Connects to all the switches in the topology and saves them
in self.controllers.
"""
for p4switch in self.topo.get_p4switches():
thrift_port = self.topo.get_thrift_port(p4switch)
self.controllers[p4switch] = SimpleSwitchAPI(thrift_port)
def build_links_capacity(self):
"""Builds link capacities dictionary
Returns:
dict: {edge: bw}
"""
links_capacity = {}
# Iterates all the edges in the topology formed by switches
for src, dst in self.topo.network_graph.keep_only_p4switches().edges:
bw = self.topo.network_graph.edges[(src, dst)]['bw']
# add both directions
links_capacity[(src, dst)] = bw
links_capacity[(dst, src)] = bw
return links_capacity
def reservations_timeout_thread(self, refresh_rate = 1):
"""Every refresh_rate checks all the reservations. If any times out
tries to delete it.
Args:
refresh_rate (int, optional): Refresh rate. Defaults to 1.
"""
while True:
# sleeps
time.sleep(refresh_rate)
# locks the self.current_reservations data structure. This is done
# because the CLI can also access the reservations.
with self.update_lock:
pass
# PART 1, TASK 5.1 Iterate self.current_reservations, update timeout, and if any
# entry expired, delete it.
def set_mpls_tbl_labels(self):
"""We set all the table defaults to reach all the hosts/networks in the network
"""
# for all switches
for sw_name, controller in self.controllers.items():
pass
# TODO PART 1 TASK 2
# 1) for all the hosts connected to this switch add the FEC_tbl entry
# 2) for all switches connected to this switch add the 2 mplt_tbl entries
def build_mpls_path(self, switches_path):
"""Using a path of switches builds the mpls path. In our simplification
labels are port indexes.
Args:
switches_path (list): path of switches to allocate
Returns:
list: label path
"""
label_path = []
# PART 1, TASK 3.2 Get mpls stack of labels
return label_path
def get_sorted_paths(self, src, dst):
"""Gets all paths between src, dst
sorted by length. This function uses the internal networkx API.
Args:
src (str): src name
dst (str): dst name
Returns:
list: paths between src and dst
"""
paths = self.topo.get_all_paths_between_nodes(src, dst)
# trimp src and dst
paths = [x[1:-1] for x in paths]
return paths
def get_shortest_path(self, src, dst):
"""Computes shortest path. Simple function used to test the system
by always allocating the shortest path.
Args:
src (str): src name
dst (str): dst name
Returns:
list: shortest path between src,dst
"""
return self.get_sorted_paths(src, dst)[0]
def check_if_reservation_fits(self, path, bw):
"""Checks if a the candidate reservation fits in the current
state of the network. Using the path of switches, checks if all
the edges (links) have enough space. Otherwise, returns False.
Args:
path (list): list of switches
bw (float): requested bandwidth in mbps
Returns:
bool: true if allocation can be performed on path
"""
# PART 1, TASK 3.1 Implement this function and its helper check_if_reservation_fits
def add_link_capacity(self, path, bw):
"""Adds bw capacity to a all the edges along path. This
function is used when an allocation is removed.
Args:
path (list): list of switches
bw (float): requested bandwidth in mbps
"""
# PART 1, TASK 3.4 add bw to edges
def sub_link_capacity(self, path, bw):
"""subtracts bw capacity to a all the edges along path. This
function is used when an allocation is added.
Args:
path (list): list of switches
bw (float): requested bandwidth in mbps
"""
# PART 1, TASK 3.4 sub bw to edges
def get_available_path(self, src, dst, bw):
"""Checks all paths from src to dst and picks the
shortest path that can allocate bw.
Args:
src (str): src name
dst (str): dst name
bw (float): requested bandwidth in mbps
Returns:
list/bool: best path/ False if none
"""
# PART 1, TASK 3.1 Implement this function and its helper check_if_reservation_fits
def add_reservation(self, src, dst,duration, bandwidth, priority):
"""[summary]
Args:
src (str): src name
dst (str): dst name
duration (float): reservation timeout
bw (float): requested bandwidth in mbps
priority (int): reservation priority
"""
# locks the self.current_reservations data structure. This is done
# because there is a thread that could access it concurrently.
with self.update_lock:
# PART 1, TASK 3.4 check if there is an existing reservation for (src,dst).
# you can use the self.current_reservations dictionary to check it.
# If the reservation exists get the path and bw and update the links capacity
# data structure using `self.add_link_capacity(path, bw)`
# PART 1, TASK 3.1. Once get_available_path is implemented call it to get a path.
path = self.get_available_path(src, dst, bandwidth)
# PART 1, TASK 3.2 If there is an available path
if path:
pass
# PART 1, TASK 3.2 Get mpls stack of labels
# PART 1, TASK 3.3 get:
# 1) ingress switch name
# 2) action name using `mpls_ingress_x_hop` set x as number of labels
# 3) src and dst ips (your match)
# 4) make sure all your labels are strings and use them as action parameters
# PART 1, TASK 3.4
# check if its a new or an existing reservation (to update)
# add entry or modify
# update controllers data structures: self.current_reservation & self.links_capacity
# PART 1, TASK 3.2 otherwise we print no path available
else:
print("\033[91mRESERVATION FAILURE: no bandwidth available!\033[0m")
def del_reservation(self, src, dst):
"""Deletes a reservation between src and dst, if exists. To
delete the reservation the self.current_reservations data structure
is used to retrieve all the needed information. After deleting the reservation
from the ingress switch, path capacities are updated.