18 from bottle
import run, get, response, request, post, error, install
20 import multiprocessing
26 from logging.config
import dictConfig
27 from functools
import wraps
29 logger = logging.getLogger()
34 Wrap a Bottle request so that a log line is emitted after it's handled. 35 (This decorator can be extended to take the desired logger as a param.) 38 def _log_to_logger(*args, **kwargs):
39 actual_response = fn(*args, **kwargs)
40 logger.info(
'%s %s %s %s' % (request.remote_addr,
44 return actual_response
47 install(log_to_logger)
49 number_of_packets = 1000
51 of_ctl =
"ovs-ofctl -O openflow13" 58 if request.query.get(_)
is None:
60 return "%s: %s must be specified\n" % (request.path, _)
61 return __(dict([(_, request.query.get(_))
for _
in pars]))
66 def respond(status, ok_message, fail_message):
76 return "Thank you, Mario! but our princess is in another castle!\n" 79 @post(
'/set_link_state')
82 iface =
"%s-eth%s" % (p[
'switch'], p[
'port'])
83 newstate = iface, p[
'newstate']
84 result = os.system(
"ifconfig %s %s" % newstate)
86 "Successfully put link %s in state %s\n" % newstate,
87 "Failed to put link %s in state %s\n" % newstate)
90 @
get(
'/checkflowtraffic')
94 def traffic_sender(linkid, vlanid):
95 payload = s.Ether()/s.Dot1Q(vlan=int(vlanid))/s.IP()/s.ICMP()
96 s.sendp(payload, iface=linkid, count=number_of_packets)
98 def traffic_listener(traffic_goes_through, vlanid, link):
111 result = s.sniff(timeout=5, iface=link)
112 received = sum(1
for _
in result
if _.haslayer(s.ICMP))
113 if number_of_packets - received < expected_delta:
114 traffic_goes_through.value =
True 116 traffic_goes_through = multiprocessing.Value(ctypes.c_bool,
False)
117 sender = multiprocessing.Process(
118 target=traffic_sender,
119 args=(
"%s-eth%s" % (p[
'srcswitch'], p[
'srcport']), p[
'srcvlan']))
120 checker = multiprocessing.Process(
121 target=traffic_listener,
122 args=(traffic_goes_through, p[
'dstvlan'],
123 "%s-eth%s" % (p[
'dstswitch'], p[
'dstport'])))
124 checker.start(), sender.start(), sender.join(5), checker.join(7)
126 return respond(traffic_goes_through.value,
127 "Traffic seems to go through\n",
128 "Traffic does not seem to go through\n")
131 @post(
"/knockoutswitch")
134 result = os.system(
"ovs-vsctl del-controller %s" % p[
'switch'])
136 "Switch %s is successfully knocked out\n" % p[
'switch'],
137 "Failed to knock out switch %s\n" % p[
'switch'])
140 @post(
"/reviveswitch")
143 params = p[
'controller'].split(
":", 3)
144 ip = socket.gethostbyname(params[1])
145 controller = params[0] +
":" + ip +
":" + params[2]
146 result = os.system(
"ovs-vsctl set-controller %s %s" %
147 (p[
'switch'], controller))
149 "Switch %s is successfully revived\n" % p[
'switch'],
150 "Failed to revive switch %s\n" % p[
'switch'])
156 sppair = (p[
'switch'], p[
'port'])
157 result = os.system(
"ovs-ofctl add-flow %s priority=65500,in_port=%s," 158 "action=drop -O openflow13" % sppair)
160 "Link to switch %s port %s is successfully cut\n" % sppair,
161 "Failed to cut link to switch %s port %s\n" % sppair)
164 @post(
"/restorelink")
167 sppair = (p[
'switch'], p[
'port'])
168 result = os.system(
"ovs-ofctl del-flows %s -O openflow13 \"priority=65500" 169 ",in_port=%s\" --strict" % (p[
'switch'], p[
'port']))
171 "Link to switch %s port %s is restored\n" % sppair,
172 "Failed to restore link to switch %s port %s\n" % sppair)
176 return os.system(
"%s mod-port %s %s %s" % (of_ctl, switch, port, action))
182 result =
port_mod(p[
'switch'], p[
'port'],
'down')
184 "Switch %s port %s down\n" % (p[
'switch'], p[
'port']),
185 "Fail switch %s port %s down\n" % (p[
'switch'], p[
'port']))
191 result =
port_mod(p[
'switch'], p[
'port'],
'up')
193 "Switch %s port %s up\n" % (p[
'switch'], p[
'port']),
194 "Fail switch %s port %s up\n" % (p[
'switch'], p[
'port']))
197 @post(
"/send_malformed_packet")
202 data =
'\x02\x07\x04\xbe\xef\x00\x00\x00\x02\x04\x03\x02\x00\x01\x06\x02' \
203 '\x00x\xfe\x0c\x00&\xe1\x00\xde\xad\xbe\xef\x00\x00\x00\x02\xfe' \
204 '\x0c\x00&\xe1\x01\x00\x00\x01_\xb6\x8c\xacG\xfe\x08\x00&\xe1\x02' \
205 '\x00\x00\x00\x00\x00\x00' 207 payload = (s.Ether(dst=
"00:26:e1:ff:ff:ff") /
208 s.IP(dst=
"192.168.0.255") /
209 s.UDP(dport=61231, sport=61231) /
213 s.sendp(payload, iface=
"00000001-eth1")
215 except Exception
as ex:
216 response.status = 500
217 return "can't send malformed packet {}".
format(ex)
221 with open(
"/app/log.json",
"r") as fd: 222 logging.config.dictConfig(json.load(fd)) 224 run(host='0.0.0.0', port=17191, debug=
True)