blob: aca97ca20919916f612138f37b8b8f2f8d2ef628 [file] [log] [blame]
Srikanth Vavilapalli1725e492014-12-01 17:50:52 -08001#
2# Copyright (c) 2012,2013 Big Switch Networks, Inc.
3#
4# Licensed under the Eclipse Public License, Version 1.0 (the
5# "License"); you may not use this file except in compliance with the
6# License. You may obtain a copy of the License at
7#
8# http://www.eclipse.org/legal/epl-v10.html
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
13# implied. See the License for the specific language governing
14# permissions and limitations under the License.
15#
16
17# sdnsh - The Controller Shell
18
19import urllib
20import urllib2
21
22import base64
23import struct
24import time
25import re
26from datetime import datetime, timedelta, tzinfo
27from calendar import timegm
28from timesince import timesince, timesince_sec
29import doctest
30import traceback
31import utif
32import command
33import json
34
Srikanth Vavilapallica79f962015-04-01 18:48:05 -070035onos = 1
Srikanth Vavilapalli1725e492014-12-01 17:50:52 -080036
37# Timezone constants
38class Utc(tzinfo):
39 def utcoffset(self, dt):
40 return timedelta(0)
41 def tzname(self, dt):
42 return "UTC"
43 def dst(self, dt):
44 return timedelta(0)
45UTC = Utc()
46
47
48class Pst(tzinfo):
49 def utcoffset(self, dt):
50 return timedelta(0,0,0,0,0,-8)
51 def tzname(self, dt):
52 return "PST"
53 def dst(self, dt):
54 return timedelta(0,0,0,0,0,-7)
55PST = Pst()
56
57
58alias_dicts = {}
59
60
61def get_switches_names(object, data =None):
62 """
63 return the switches name (for ONOS)
64 """
65 switches_dpid_name ={}
66 url = "http://127.0.0.1:8000/rest/v1/switches"
67 result = urllib2.urlopen(url).read()
68 #result = command.sdnsh.store.rest_simple_request(query_url)
69 entries = result
70 entries = json.loads(result)
Srikanth Vavilapallica79f962015-04-01 18:48:05 -070071 switchIdField = 'dpid'
72 if onos==2:
73 entries = entries['devices']
74 switchIdField = 'id'
Srikanth Vavilapalli1725e492014-12-01 17:50:52 -080075 #eprint entries
76 for switch in entries:
77 #print switch
Srikanth Vavilapallica79f962015-04-01 18:48:05 -070078 if onos == 1:
79 switches_dpid_name[switch.get(switchIdField)] = switch.get("stringAttributes").get('name')
80 elif onos == 2:
81 switches_dpid_name[switch.get(switchIdField)] = switch.get(switchIdField)
82
Srikanth Vavilapalli1725e492014-12-01 17:50:52 -080083 #print switch.get("dpid")
84 #print switch.get("stringAttributes").get('name')
85 return switches_dpid_name
86
87
88def update_alias_dict(obj_type, dict):
89 """
90 Update alias dictionaries: for switch, host, etc.
91 """
92 global alias_dicts
93 alias_dicts[obj_type] = dict
94
95
96def convert_mac_in_base64_byte_array_to_hex_string(i, data=None):
97 # hmmm - tasty python
98 if i == "*" or i == "":
99 return "*"
100 return ":".join(["%0.2x" % x for x in struct.unpack('BBBBBB', base64.b64decode(i))])
101
102
103def convert_mac_in_decimal_to_hex_string(i, data=None):
104 if i == "*" or i == "":
105 return "*"
106 mac = hex(i)
107 # some python implementations append 'L' to hex() so we need to remove it
108 if mac[len(mac)-1] == 'L':
109 mac = mac[:len(mac)-1]
110 mac = ('0' * (14 - len(mac)) + mac[2:])
111 return ':'.join([mac[x:x+2] for x in xrange(0, len(mac), 2)])
112
113
114def convert_ip_in_integer_to_dotted_decimal(i, data=None):
115 if i == "*" or i == "":
116 return "*"
117 return '.'.join(reversed([ (str((i >> (8*x)) & 0xff)) for x in range(0,4)]))
118
119
120def convert_integer_to_bitmask(i, data=None):
121 if i == "*" or i == "":
122 return "*"
123 return bin(i)
124
125
126def convert_long_to_dpid(i, data=None):
127 if i == "*" or i == "":
128 return "*"
129 i = int(i)
130 return ':'.join(reversed([ "%-.2x" % ((i >> (8*x)) & 0xff) for x in range(0,8)]))
131
132
133def convert_signed_short_to_unsigned(i, data=None):
134 try:
135 i = int(i)
136 except:
137 return i
138
139 if i < 0:
140 return i + 2**16
141 else:
142 return i
143
144
145def convert_signed_short_for_vlan(i, data=None):
146 if i == -1:
147 return "-"
148 else:
149 return convert_signed_short_to_unsigned(i, data)
150
151
152def convert_to_string(i, data=None):
153 if type(i) == list:
154 return ', '.join(i)
155 elif type(i) == dict:
156 return ', '.join(["%s:%s" % x for x in i.dict()])
157 else:
158 return str(i)
159
160
161def print_hex(i, data=None):
162 if i == "" or not int(i):
163 return ""
164 else:
165 return hex(i)
166
167
168def timestamp_to_local_timestr(i, data=None):
169 if i == '':
170 return ''
171 return time.strftime("%Y-%m-%d %H:%M:%S %Z", time.localtime(i/1000))
172
173
174def utc_timestr_to_timestamp(s):
175 return timegm(time.strptime(s, "%Y-%m-%d %H:%M:%S.%f")) * 1000
176
177
178def print_from_utc_timestr(s, data=None):
179 """Converts from a UTC time string like 2010-12-12 15:27:41.650000
180 to time string in local timezone like 2011-06-23 02:51:41 PDT
181
182 # Doctest only valid in Pacific Time ;-|
183 >>> print_from_utc_timestr('2010-12-12 15:27:41.650000')
184 '2010-12-12 07:27:41 PST'
185 >>> print_from_utc_timestr('2010-06-12 15:27:41.650000')
186 '2010-06-12 08:27:41 PDT'
187 >>> print_from_utc_timestr('')
188 ''
189 >>> print_from_utc_timestr(None)
190 ''
191 >>> print_from_utc_timestr('Not a valid timestamp')
192 ''
193 """
194 ret = ''
195 try:
196 ret = timestamp_to_local_timestr(utc_timestr_to_timestamp(s))
197 except:
198 pass
199 return ret
200
201
202def print_time_since_utc(i, data=None):
203 if i == None or i == '':
204 return ''
205 return timesince(datetime.fromtimestamp((i/1000)))
206
207
208def print_time_since_utc_timestr(s, data=None, now=None):
209 """Converts from a UTC time string like 2010-12-12 15:27:41.65000
210 to human readabel string like 'Last seen 4 minutes ago'
211
212 >>> now = datetime(*(time.strptime('2010-12-12 15:27:41.650000', "%Y-%m-%d %H:%M:%S.%f")[0:6]+(0, PST)))
213 >>> print_time_since_utc_timestr('2010-12-12 15:27:41.650000', now=now)
214 '8 hours'
215 >>> print_time_since_utc_timestr('')
216 ''
217 >>> print_time_since_utc_timestr(None)
218 ''
219 >>> print_time_since_utc_timestr('Not a valid timestamp')
220 ''
221 """
222 ret = ''
223 if s == '':
224 return ''
225 try:
226 date_obj = datetime(*(time.strptime(s, "%Y-%m-%d %H:%M:%S.%f")[0:6] + (0, UTC)))
227 ret = timesince(date_obj, now)
228 except Exception, e:
229 try:
230 date_obj = datetime(*(time.strptime(s, "%Y-%m-%d %H:%M:%S")[0:6] + (0, UTC)))
231 ret = timesince(date_obj, now)
232 except Exception, e:
233 try:
234 date_obj = datetime(*(time.strptime(s, "%Y-%m-%dT%H:%M:%S.%fZ")[0:6] + (0, UTC)))
235 ret = timesince(date_obj, now)
236 except Exception, e:
237 ret = "<fail>"
238 pass
239 return ret
240
241
242def print_timesince_msec_since(i, data=None):
243 if i == '':
244 return i
245 return timesince_sec(int(i)/1000)
246
247def print_enum_string_and_int(values, i, not_found_val = None):
248 if values and i in values:
249 return "%s(%s)" % (values[i], i)
250 else:
251 if not_found_val:
252 return not_found_val
253 else:
254 return i
255
256
257def print_enum_string_and_hex_int(values, i, not_found_val = None):
258 if values and i in values:
259 return "%s(%#x)" % (values[i], int(i))
260 else:
261 if not_found_val:
262 return not_found_val
263 else:
264 return i
265
266
267def print_mask_enum_string_and_int(values, bits):
268 if bits == "":
269 return bits
270 bits_copy = bits
271 enums = []
272 bit_test = 1
273 while bits_copy:
274 if bit_test & bits_copy:
275 if bit_test in values:
276 enums.append(values[bit_test])
277 bits_copy &= bits_copy-1
278 bit_test <<= 1
279 if enums:
280 return ",".join(enums) + "(%s)" % (hex(bits) if bits > 9 else bits)
281 else:
282 if bits > 9:
283 return hex(int(bits))
284 return "0"
285
286
287def print_physical_port(i, data=None, switch_key=None):
288 global alias_dicts
289
290 if not data:
291 return str(i)
292 name_dict = alias_dicts.get("portNames")
293 if not name_dict:
294 return str(i)
295 if switch_key:
296 key_string = data[switch_key] + '.' + "%d" % i
297 elif 'switch' in data:
298 key_string = data['switch'] + '.' + "%d" % i
299 elif 'Switch' in data:
300 key_string = data['Switch'] + '.' + "%d" % i
301 # return the physical name if it exists, otherwise i
302 return str(name_dict.get(key_string, i))
303
304
305def print_byte_unit(i, data=None, suffix=None):
306 """
307 Convert the value of 'i' into a byte rate value,
308 for example '10 GB'
309 """
310 try:
311 value = int(i)
312 except:
313 if i == '':
314 return 'Unknown'
315 return i
316
317 converter = (
318 (1024 * 1028 * 1024 * 1024 * 1024 , ' PB'),
319 (1024 * 1028 * 1024 * 1024 , ' TB'),
320 (1024 * 1028 * 1024 , ' GB'),
321 (1028 * 1024 , ' MB'),
322 (1024 , ' KB'),
323 )
324 if suffix == None:
325 suffix = ''
326
327 for idx, (boundary, name) in enumerate(converter):
328 value = i / boundary
329 if value:
330 return '%s%s%s' % (value, name, suffix)
331 else:
332 return '%s B%s' % (i, suffix)
333
334def print_byte_rate(i, data=None):
335 return print_byte_unit(i, data, 'ps')
336
337def print_bit_unit(i, data=None, suffix=None):
338 """
339 Convert the value of 'i' into a bit rate value,
340 for example '10 Gb'
341 """
342 try:
343 value = int(i)
344 except:
345 if i == '':
346 return 'Unknown'
347 return i
348
349 converter = (
350 (1000 * 1000 * 1000 * 1000 * 1000 , ' Pb'),
351 (1000 * 1000 * 1000 * 1000 , ' Tb'),
352 (1000 * 1000 * 1000 , ' Gb'),
353 (1000 * 1000 , ' Mb'),
354 (1000 , ' Kb'),
355 )
356 if suffix == None:
357 suffix = ''
358
359 for idx, (boundary, name) in enumerate(converter):
360 value = i / boundary
361 if value:
362 return '%s%s%s' % (value, name, suffix)
363 else:
364 return '%s b%s' % (i, suffix)
365
366def print_bit_rate(i, data=None):
367 return print_bit_unit(i, data, 'ps')
368
369
370def decode_openflow_port(i, data=None, switch_key=None):
371 if i == "*" or i == "":
372 return "*"
373 # If the first character of the port name is a plus sign ('+')
374 # this is intended to bypass any lookup -- its a way to indicate
375 # the field is already an openflow interface.
376 if isinstance(i, unicode) and i[0] == '+':
377 return i[1:]
378 i = convert_signed_short_to_unsigned(i)
379 i &= 0xffff
380 values = {
381 0xfff8 : "input",
382 0xfff9 : "table",
383 0xfffa : "normal",
384 0xfffb : "flood",
385 0xfffc : "all",
386 0xfffd : "controller",
387 0xfffe : "local",
388 0xffff : "none",
389 }
390 if i >= 0xff00:
391 if i in values:
392 return "%s (%s)" % (i, values[i])
393 else:
394 return "%s" % values[i]
395 phys_port = print_physical_port(i, data, switch_key)
396 if str(i) != phys_port:
397 return str(i) + ' (' + phys_port + ')'
398 return str(i)
399
400
401def decode_openflow_port_src_switch(i, data=None):
402 return decode_openflow_port(i, data, 'src-switch')
403
404
405def decode_openflow_port_source_switch(i, data=None):
406 return decode_openflow_port(i, data, 'Source-Switch')
407
408
409def decode_openflow_port_dst_switch(i, data=None):
410 return decode_openflow_port(i, data, 'dst-switch')
411
412
413def decode_openflow_port_dest_switch(i, data=None):
414 return decode_openflow_port(i, data, 'Dest-Switch')
415
416
417def decode_openflow_port_inputSwitch(i, data=None):
418 return decode_openflow_port(i, data, 'inputSwitch')
419
420
421def decode_openflow_port_dpid(i, data=None):
422 return decode_openflow_port(i, data, 'dpid')
423
424
425# well known cookie id's managed directly, other's can be registered
426cookie_app_ids = {
427 1: "lswitch",
428 2: "FL:forw",
429 3: "TUN:forw",
430 4: "VTA:forw",
431 10: "static",
432}
433
434flow_cookie_registry = { }
435
436def register_flow_cookie_decoder(name, app_id, encoder_proc, decoder_proc, conversion_dict_name):
437 """
438 Register a flow encoding/decoding strategy
439 """
440 # should be provide a return code?
441
442 cookie_app_ids[app_id] = name
443 flow_cookie_registry[int(app_id)] = {
444 'name' : name,
445 'encoder' : encoder_proc,
446 'decoder' : decoder_proc,
447 'cvt' : conversion_dict_name
448 }
449
450def callout_flow_encoders(context):
451 for (registrant, registry) in flow_cookie_registry.items():
452 dict_name = registry['cvt']
453 alias_dicts[dict_name] = registry['encoder'](context)
454
455
456def decode_flow_cookie(i, data=None):
457 cookie = i
458 new_cookie = None
459
460 # 12 bits app id - 20 bits flow hash - 32 bits user cookie
461 app_id = (cookie >> 52) & ((1 << 12) - 1)
462
463 flow_hash = (cookie >> 32) & ((1 << 20) - 1)
464 if app_id in cookie_app_ids:
465 new_cookie = cookie_app_ids[app_id]
466 if cookie_app_ids[app_id] == "static":
467 global alias_dicts
468 flow_map = alias_dicts.get("staticflow", [])
469 if flow_hash in flow_map:
470 new_cookie += "-%s" % flow_map[flow_hash]
471 else:
472 new_cookie += "-flow_hash: %s" % flow_hash
473 else:
474 if flow_hash != 0:
475 new_cookie += "-flow_hash: %s" % flow_hash
476 user_cookie = (cookie & ((1 << 32) - 1))
477
478 if user_cookie:
479 if app_id in flow_cookie_registry:
480 # Call registered function with the conversion dictionary
481 # and the cookie
482 conversion_dict_name = flow_cookie_registry[app_id]['cvt']
483 new_cookie = (flow_cookie_registry[app_id]['decoder'])(
484 alias_dicts.get(conversion_dict_name), cookie)
485 else:
486 new_cookie += ", cookie: %#x" % user_cookie
487 else:
488 # if the app_id isn't known, display all 64 bits of the cookie
489 new_cookie = "unknown %s, cookie %s" % (app_id, cookie)
490
491 if new_cookie:
492 return new_cookie
493
494 return '%#x' % cookie
495
496
497ether_type_to_name_dict = {
498 0x0800 : "ip",
499 0x0806 : "arp",
500 0x8035 : "rarp",
501 0x809B : "appletalk",
502 0x809B : "appletalk-aarp",
503 0x8100 : "802.1Q",
504 0x8137 : "ipx",
505 0x8138 : "novell",
506 0x86dd : "ipv6",
507 0x8847 : "mpls",
508 0x8848 : "mpls-mc",
509 0x88cc : "lldp",
510}
511
512
513ether_type_to_number_dict = dict([[v, n] for (n,v) in ether_type_to_name_dict.items()])
514
515
516def decode_ether_type(i, data=None):
517 if i == "*" or i == "":
518 return "*"
519 if type(i) != int and i.startswith("0x"):
520 i = int(i, 16) # i is in hex
521 i = convert_signed_short_to_unsigned(i)
522
523 try:
524 i &= 0xffff
525 except:
526 return '*cvt %s %s*' % (i, type(i))
527
528 return print_enum_string_and_hex_int(ether_type_to_name_dict, i)
529
530
531def decode_network_protocol(i, data=None):
532 if i == "*" or i == "":
533 return "*"
534 ether_type = "ip" # default
535 if data:
536 if 'ether-type' in data:
537 ether_type = decode_ether_type(data['ether-type'])
538 elif 'dataLayerType' in data:
539 ether_type = decode_ether_type(data['dataLayerType'])
540 ether_type = str(ether_type).split('(')[0]
541 net_proto_hash = {
542 "ip" : {
543 1 : "icmp",
544 2 : "igmp",
545 3 : "ggp",
546 4 : "ip-in-ip",
547 6 : "tcp",
548 17 : "udp",
549 50 : "esp",
550 51 : "ah"
551 },
552 "arp": {
553 1 : "arp-req",
554 2 : "arp-rep",
555 3 : "rarp-req",
556 4 : "rarp-rep",
557 5 : "drarp-req",
558 6 : "drarp-rep",
559 7 : "drarp-err",
560 8 : "inarp-req",
561 9 : "inarp-rep",
562 }
563 }
564 return print_enum_string_and_int(net_proto_hash.get(ether_type, None), i)
565
566tcp_decode_port_dict = {
567 22 : "ssh",
568 53 : "dns",
569 80 : 'http',
570 443 : 'https'
571}
572
573tcp_name_to_number_dict = dict([[v, n] for (n,v) in tcp_decode_port_dict.items()])
574
575# fill in values if we want!
576def decode_tcp_port(i):
577 return print_enum_string_and_int(tcp_decode_port_dict, i)
578
579
580udp_decode_port_dict = {
581 53 : "dns",
582}
583
584udp_name_to_number_dict = dict([[v, n] for (n,v) in udp_decode_port_dict.items()])
585
586def decode_udp_port(i):
587 values = {
588 }
589 return print_enum_string_and_int(values, i)
590
591
592icmp_type_code_hash = {
593 0 : { "name" : "echo-rep" },
594 3 : { "name" : "dest-unreach",
595 "codes" : { 0 : "net-unreach",
596 1 : "host-unreach",
597 2 : "proto-unreach",
598 3 : "port-unreach",
599 4 : "frag-needed",
600 5 : "src-rt-fail",
601 6 : "dest-net-unk",
602 7 : "dest-host-unk",
603 8 : "src-host-isol",
604 9 : "prohibit-dest-net",
605 10 : "prohibit-dest-host",
606 11 : "dest-net-unreach-for-tos",
607 12 : "dest-host-unreach-for-tos",
608 13 : "prohibit-comm" } },
609 4 : { "name" : "src-quench" },
610 5 : { "name" : "redirect",
611 "codes" : { 0 : "redir-for-net",
612 1 : "redir-for-host",
613 2 : "redir-for-net-for-tos",
614 3 : "redir-for-host-for-tos" } },
615 6 : { "name" : "alt-addr-for-host" },
616 8 : { "name" : "echo-req" },
617 9 : { "name" : "router-advert" },
618 10: { "name" : "router-sel" },
619 11: { "name" : "time-exceeded",
620 "codes" : { 0 : "ttl-exceeded",
621 1 : "frag-reassemble-exceeded" } },
622 12: { "name" : "param-problem",
623 "codes" : { 0 : "pointer-error",
624 1 : "missing-opt",
625 2 : "bad-length" } },
626 13: { "name" : "timestamp-request" },
627 14: { "name" : "timestamp-reply" },
628 15: { "name" : "info-request" },
629 16: { "name" : "info-reply" },
630 17: { "name" : "addr-mask-request" },
631 18: { "name" : "addr-mask-reply" },
632 30: { "name" : "traceroute" }
633}
634
635
636def decode_icmp_type(i, data=None):
637 if i in icmp_type_code_hash:
638 return "%s(%s)" % (icmp_type_code_hash[i]['name'], i)
639 else:
640 return i
641
642
643def decode_icmp_code(i, data=None):
644 if data and 'transportSource' in data:
645 icmp_type = decode_icmp_type(data['transportSource'], data)
646 elif data and 'src-port' in data:
647 icmp_type = decode_icmp_type(data['src-port'], data)
648 try:
649 return print_enum_string_and_int(icmp_type_code_hash[icmp_type]["codes"], i, "-")
650 except:
651 return "-"
652
653
654def decode_src_port(i, data=None):
655 i = convert_signed_short_to_unsigned(i)
656 if data:
657 if 'networkProtocol' in data:
658 net_proto = decode_network_protocol(data['networkProtocol'], data)
659 elif 'protocol' in data:
660 net_proto = decode_network_protocol(data['protocol'], data)
661 elif 'Protocol' in data:
662 net_proto = decode_network_protocol(data['Protocol'], data)
663 else:
664 return i
665 net_proto = str(net_proto).split('(')[0]
666 if net_proto == "icmp":
667 return decode_icmp_type(i)
668 elif net_proto == "tcp":
669 return decode_tcp_port(i)
670 elif net_proto == "udp":
671 return decode_udp_port(i)
672 return i
673
674
675def decode_dst_port(i, data=None):
676 i = convert_signed_short_to_unsigned(i)
677 if data:
678 if 'networkProtocol' in data:
679 net_proto = decode_network_protocol(data['networkProtocol'], data)
680 elif 'protocol' in data:
681 net_proto = decode_network_protocol(data['protocol'], data)
682 elif 'Protocol' in data:
683 net_proto = decode_network_protocol(data['Protocol'], data)
684 else:
685 return i
686 net_proto = str(net_proto).split('(')[0]
687 if net_proto == "icmp":
688 return decode_icmp_code(i, data)
689 elif net_proto == "tcp":
690 return decode_tcp_port(i)
691 elif net_proto == "udp":
692 return decode_udp_port(i)
693 return i
694
695
696def decode_actions(action_list, data=None):
697 TTL_DECREMENT_SUBTYPE = 18
698 SET_TUNNEL_DST_SUBTYPE = 2
699 NICIRA_VENDOR_ID=8992 #0x00002320
700 BSN_VENDOR_ID=6035143 #0x5c16c7
701 decoded_actions = []
702 for a in action_list:
703 decoded_action = a['type']
704 if decoded_action == "OUTPUT":
705 port = decode_openflow_port(a['port'], data)
706 decoded_action = "output=%s" % (port,)
707 elif decoded_action == "OPAQUE_ENQUEUE":
708 # LOOK! Not decoded to physical port since the configuration part of CLI does not do the translation either
709 decoded_action = "enqueue=%d:0x%02x" % (a['port'], a['queueId'])
710 elif decoded_action == "SET_VLAN_ID":
711 decoded_action = "set-vlan-id=%d" % a['virtualLanIdentifier']
712 elif decoded_action == "SET_VLAN_PCP":
713 decoded_action = "set-vlan-priority=0x%02x" % a['virtualLanPriorityCodePoint']
714 elif decoded_action == "STRIP_VLAN":
715 decoded_action = "strip-vlan"
716 elif decoded_action == "SET_DL_SRC":
717 decoded_action = "set-src-mac=%s" % a['dataLayerAddress']
718 elif decoded_action == "SET_DL_DST":
719 decoded_action = "set-dst-mac=%s" % a['dataLayerAddress']
720 elif decoded_action == "SET_NW_SRC":
721 decoded_action = "set-src-ip=%s" % decode_ipaddr(a['networkAddress'])
722 elif decoded_action == "SET_NW_DST":
723 decoded_action = "set-dst-ip=%s" % decode_ipaddr(a['networkAddress'])
724 elif decoded_action == "SET_NW_TOS":
725 decoded_action = "set-tos-bits=0x%02x" % a['networkTypeOfService']
726 elif decoded_action == "SET_TP_SRC":
727 decoded_action = "set-src-port=%d" % a['transportPort']
728 elif decoded_action == "SET_TP_DST":
729 decoded_action = "set-dst-port=%d" % a['transportPort']
730 elif decoded_action =="VENDOR":
731 if 'vendor' in a:
732 if a['vendor']==NICIRA_VENDOR_ID:
733 if 'vendorData' in a:
734 vendordata=a['vendorData'].decode('base64','strict')
735 vendordata=vendordata.encode('hex')
736 if vendordata.startswith('0012'):
737 decoded_action="nicira_vendor:dec TTL"
738 else:
739 decoded_action="nicira_vendor:unknown"
740 if a['vendor']==BSN_VENDOR_ID:
741 if 'vendorData' in a:
742 vendordata=a['vendorData'].decode('base64','strict')
743 vendordata=vendordata.encode('hex')
744 if vendordata.startswith('00000001'): #BSN_ACTION_MIRROR
745 decoded_action="bsn_vendor:MIRROR"
746 elif vendordata.startswith('00000002'): #SET_TUNNEL_DST_SUBTYPE
747 ip=vendordata[8:]
748 ipaddr=[]
749 for i in [6,4,2,0]:
750 ipint= ip[i:i+2]
751 ipint= str(int(ipint,16))
752 ipaddr.append(ipint)
753 ipstr='.'.join(ipaddr)
754 decoded_action="bsn_vendor:TUNNL:" + ipstr
755 else:
756 decoded_action="bsn_vendor:unknown"
757 decoded_actions.append(decoded_action)
758 if len(decoded_actions) == 0:
759 return "drop"
760 else:
761 return ",".join(decoded_actions)
762
763
764def decode_port_counter(i, data=None):
765 if i == -1:
766 return "n/a"
767 else:
768 return i
769
770
771def decode_macaddr(addr):
772 ret = 'invalid-mac-addr'
773 try:
774 macbytes = base64.b64decode(addr)
775 ret = ':'.join(["%02x" % ord(b) for b in macbytes])
776 except:
777 # ignore exception, the address is already set to invalid
778 pass
779 return ret
780
781
782def decode_ipaddr(addr):
783 ret = 'invalid-ip-addr'
784 try:
785 ipbytes = [0, 0, 0, 0]
786 for i in range(4):
787 ipbytes[3-i] = addr & 0x000000ff
788 addr = addr>>8
789 ret = '.'.join(["%d" % b for b in ipbytes])
790 except:
791 # ignore exception, the address is already set to invalid
792 pass
793 return ret
794
795
796def decode_port_config(i, data=None):
797 i = abs(i)
798 values = {
799 1 << 0 : "port-down",
800 1 << 1 : "no-stp",
801 1 << 2 : "no-recv",
802 1 << 3 : "no-recv-stp",
803 1 << 4 : "no-flood",
804 1 << 5 : "no-fwd",
805 1 << 6 : "no-pkt-in",
806 1 << 31 : "mirror",
807 }
808 if i == 0 or i == '':
809 return ''
810 return print_mask_enum_string_and_int(values, i)
811
812def decode_port_state(i, data=None):
813 if i == '':
814 return 'Unknown'
815
816 # The two bits at (3 << 8) are a mask for the STP value
817 # which are listed in the following dictionary. Note that these
818 # aren't simply bit masks, so we can't use print_mask_enum_string_and_int
819 # here. So instead we special case the formatting of this field. We could
820 # probably factor some of this logic into a utility function, but
821 # this works for now.
822 stp_values = {
823 0 << 8 : ": stp-listen",
824 1 << 8 : ": stp-learn-no-relay",
825 2 << 8 : ": stp-forward",
826 3 << 8 : ": stp-block-broadcast",
827 }
828 value = "link-down" if i == 1 else "link-up" + stp_values.get(i, '')
829 return "%s(%s)" % (value, hex(i) if i > 9 else i)
830
831
832def decode_port_up_down(i, data=None):
833 if i == '':
834 return 'Unknown'
835 return "down" if i == 1 else 'up'
836
837
838def decode_port_stp_state(i, data=None):
839 if i == '':
840 return ''
841 stp_values = {
842 0 << 8 : "listen",
843 1 << 8 : "learn-no-relay",
844 2 << 8 : "forward",
845 3 << 8 : "block-broadcast",
846 }
847 value = '' if i == 1 else stp_values.get(i)
848 return "%s(%s)" % (value, hex(i) if i > 9 else i)
849
850
851def decode_port_linkrate(i, data=None):
852 values = {
853 1 << 0 : "10mb-hd",
854 1 << 1 : "10mb-fd",
855 1 << 2 : "100mb-hd",
856 1 << 3 : "100mb-fd",
857 1 << 4 : "1gb-hd",
858 1 << 5 : "1gb-fd",
859 1 << 6 : "10gb-fd",
860 }
861 if type(i) != int:
862 return "Unknown"
863 if (int(i) & 0x7f) == 0:
864 return "Unknown"
865 return print_mask_enum_string_and_int(values, int(i) & 0x7f)
866
867
868def decode_port_features(i, data=None):
869 values = {
870 1 << 0 : "10mb-hd",
871 1 << 1 : "10mb-fd",
872 1 << 2 : "100mb-hd",
873 1 << 3 : "100mb-fd",
874 1 << 4 : "1gb-hd",
875 1 << 5 : "1gb-fd",
876 1 << 6 : "10gb-fd",
877 1 << 7 : "copper",
878 1 << 8 : "fiber",
879 1 << 9 : "autoneg",
880 1 << 10 : "pause",
881 1 << 11 : "pause-asym",
882 }
883 return print_mask_enum_string_and_int(values, i)
884
885
886def decode_switch_capabilities(i, data=None):
887 values = {
888 1 << 0 : "flow",
889 1 << 1 : "tbl",
890 1 << 2 : "port",
891 1 << 3 : "stp",
892 1 << 5 : "ip-reasm",
893 1 << 6 : "queue-stats",
894 1 << 7 : "match-ip-in-arp",
895 }
896 return print_mask_enum_string_and_int(values, i)
897
898
899def decode_switch_actions(i, data=None):
900 values = {
901 1 << 0 : "output",
902 1 << 1 : "vlan-vid",
903 1 << 2 : "vlan-pcp",
904 1 << 3 : "strip-vlan",
905 1 << 4 : "dl-src",
906 1 << 5 : "dl-dst",
907 1 << 6 : "nw-src",
908 1 << 7 : "nw-dst",
909 1 << 8 : "nw-tos",
910 1 << 9 : "tp-src",
911 1 << 10 : "tp-dst",
912 1 << 11 : "enqueue",
913 }
914 if (i == 0):
915 return "mirror"
916 return print_mask_enum_string_and_int(values, i)
917
918
919wildcards = {
920 1 << 0 : 'in port',
921 1 << 1 : 'vlan',
922 1 << 2 : 'pri',
923 1 << 3 : 'eth',
924 1 << 4 : 'tos',
925 1 << 5 : 'proto',
926 1 << 6 : 'src',
927 1 << 7 : 'dst',
928 1 << 8 : 'mpls',
929 1 << 9 : 'tc',
930}
931
932def realtime_flow_brief(i, data=None):
933 brief = []
934 wildcard = data['wildcards']
935 # wild = print_mask_enum_string_and_int(wildcards, wildcard)
936 try:
937 i = int(wildcard)
938 except:
939 return ''
940
941 if not wildcard & 0x1:
942 brief.append('rx=%s' % decode_openflow_port(data['inputPort'], data))
943 if (not wildcard & 0x2) and (data['dataLayerVirtualLan'] != -1):
944 brief.append('vlan:%s' % data['dataLayerVirtualLan'])
945 if (not wildcard & 0x4) and (data['dataLayerVirtualLanPriorityCodePoint'] != '*'):
946 brief.append('pri:%s' % data['dataLayerVirtualLanPriorityCodePoint'])
947 if (not wildcard & 0x8) and (data['dataLayerType'] != '*') :
948 brief.append('eth:%s' % data['dataLayerType'])
949 if not wildcard & 0x10:
950 brief.append('tos:%s' % data['networkTypeOfService'])
951 if not wildcard & 0x20:
952 brief.append('ip:%s' % data['networkProtocol'])
953 if data['networkSourceMaskLen']:
954 brief.append('src:%s' % utif.ip_and_neg_mask(data['networkSource'],
955 data['networkSourceMaskLen']))
956 if not wildcard & 0x40:
957 brief.append('sport:%s' % data['transportSource'])
958 if data['networkSourceMaskLen']:
959 brief.append('src:%s' % utif.ip_and_neg_mask(data['networkSource'],
960 data['networkSourceMaskLen']))
961 if not wildcard & 0x80:
962 brief.append('dport:%s' % data['transportDestination'])
963 # mpls not in OF1.0
964 #if not wildcard & 0x100:
965 #brief.append('mpls: ?')
966 #if not wildcard & 0x200:
967 #brief.append('mpls-tc: ?')
968
969 return ', '.join(brief)
970
971
972def formatter_to_alias_update(formatter, update):
973 """
974 Associate the items which need updating with the formatter.
975 the update parameter is a dict, allowing multiple updates
976 over several distinct fields
977
978 Update this procedure as new decoding procedures are
979 added which require some alias translation to be updated
980
981 @param formatter function which is called to format a field
982 @param update dictionry passed in, updated with alias types to update
983 """
984 name = formatter.__name__
985 if name in ['print_host_and_alias',
986 'print_all_host_attachment_points',
987 'print_devicemanager_attachment_points',
988 'replace_host_with_alias',
989 ]:
990 update['host'] = True
991 if name in ['print_host_attachment_point',
992 'print_vns_physical_interface_id',
993 'decode_openflow_port',
994 'decode_openflow_port_src_switch',
995 'decode_openflow_port_dst_switch',
996 'decode_openflow_port_source_switch',
997 'decode_openflow_port_inputSwitch',
998 'decode_openflow_port_dpid',
999 'realtime_flow_brief',
1000 ]:
1001 update['switch'] = True # port implies switch
1002 update['port'] = True
1003 if name in ['print_switch_and_alias',
1004 'print_switch_and_alias_dpid_as_long',
1005 'print_switches',
1006 'replace_switch_with_alias',
1007 ]:
1008 update['switch'] = True
1009 if name in ['decode_flow_cookie'
1010 ]:
1011 update['flow'] = True
1012 if name in ['replace_controller_node_with_alias',
1013 ]:
1014 update['controller-node'] = True
1015 return update
1016
1017def print_switch_port_list(i, data=None):
1018 if i == None:
1019 return ''
1020 return ' '.join([replace_switch_with_alias(x['switch']) + \
1021 '/' + decode_openflow_port(x['port']) for x in i])
1022
1023def print_switch_port(i):
1024 if i == None:
1025 return ''
1026 return replace_switch_with_alias(x['switch']) + \
1027 '/' + decode_openflow_port(x['port'])
1028
1029def print_host_attachment_point(i, data=None):
1030 if i == None:
1031 return "Inactive"
1032 if len(i) == 1:
1033 if_name = decode_openflow_port(i[0]['ingress-port'],
1034 data['attachment-points'][0])
1035 dpid = str(i[0]['switch'])
1036 #print print_switch_and_alias(dpid, data)
1037 return print_switch_and_alias(i[0]['switch']) + '/' + if_name
1038 if len(i) == 0:
1039 return ""
1040 first = i[0]
1041 if 'prime' in first:
1042 if_name = decode_openflow_port(i[0]['ingress-port'],
1043 data['attachment-points'][0])
1044 return "%s/%s+[%s]" % (replace_switch_with_alias(i[0]['switch']),
1045 if_name, str(len(i)-1))
1046 return "multiple (" + str(len(i)) + ")"
1047
1048
1049def print_all_host_attachment_points(i, data=None):
1050 if i == None:
1051 return ''
1052 return ' '.join([replace_switch_with_alias(x['switch']) + \
1053 '/' + decode_openflow_port(x['ingress-port'],
1054 data['attachment-points'][0])
1055 for x in i])
1056
1057
1058def print_devicemanager_attachment_points(i, data=None):
1059 if i == None:
1060 return ''
1061 return ' '.join([replace_switch_with_alias(x['switch']) + \
1062 '/' + decode_openflow_port(x['port'],
1063 data['attachment-points'][0])
1064 for x in i])
1065
1066
1067def print_cluster_id(i, data=None):
1068 return str(i)
1069
1070
1071def print_switches(i, data=None):
1072 return ' '.join([replace_switch_with_alias(dpid) for dpid in i])
1073
1074
1075def print_single_tag(tag):
1076 fields = tag.split('|')
1077 return "%s.%s=%s" % (fields[0],fields[1],fields[2])
1078
1079def print_host_tags(i, data=None):
1080 if i == None or len(i) == 0:
1081 return ""
1082 tag = i
1083 if type(tag) == dict:
1084 tag = [i]
1085
1086 if len(tag) == 1:
1087 # 'tag' is a complete row from the store, specifically 'tag-mapping'
1088 # the 'tag' key holds a name which looks like: <namespace>|<name>|<value>
1089 # which is then split, and recombined for display
1090 return print_single_tag(tag[0]['tag'])
1091 if len(tag) == 0:
1092 return ""
1093 return "multiple (" + str(len(tag)) + ")"
1094
1095
1096def print_all_host_tags(i, data=None):
1097 if i == None:
1098 return ''
1099 if i == dict:
1100 return print_single_tag(i['tag'])
1101 return ' '.join([print_single_tag(x['tag']) for x in i])
1102
1103
1104def print_ip_addresses(i, data=None):
1105 if i != None:
1106 if len(i) == 1:
1107 return str(i[0]['ip-address'])
1108 if len(i) == 0:
1109 return ""
1110 # if there are multiple addressed, see if some of the addresses
1111 # are "less" important than others.
1112 less_interesting = 0
1113 more_interesting = None
1114 for ips in i:
1115 if ips['ip-address'] == '0.0.0.0':
1116 less_interesting += 1
1117 elif re.match(r'169.254.*', ips['ip-address']):
1118 less_interesting += 1
1119 else:
1120 more_interesting = ips['ip-address']
1121
1122 if len(i) == less_interesting + 1:
1123 return "%s+(%d)" % (more_interesting, less_interesting)
1124 s = sorted(i, key=lambda k: k['last-seen'])
1125 return "%s+(%d)" % (s[-1]['ip-address'], len(s) - 1)
1126 # return "multiple (" + str(len(i)) + ")"
1127 return "Unknown"
1128
1129
1130def print_all_ip_addresses(i, data=None):
1131 if i == None:
1132 return ''
1133 return ' '.join([x['ip-address'] for x in i])
1134
1135
1136def print_devicemanager_ip_addresses(i, data=None):
1137 if i == None:
1138 return ''
1139 return ' '.join([x['ip'] for x in i])
1140
1141
1142def print_join_list(i, data=None):
1143 return ', '.join(i)
1144
1145
1146def replace_with_alias(object_type, i, data=None):
1147 """
1148 use when we have aliases for other objects
1149 """
1150 global alias_dicts
1151 alias_dict = alias_dicts.get(object_type, {i : i})
1152 if not alias_dict:
1153 return i
1154 return alias_dict.get(i, i)
1155
1156
1157def print_switch_and_alias(i, data=None):
1158 """
1159 """
1160 dpid = str(i)
1161 alias = replace_switch_with_alias(i, data)
1162 if dpid == alias:
1163 dpid_name = get_switches_names(object, data)
1164 if i in dpid_name:
1165 alias = dpid_name[i]
1166 return dpid + ' (' + alias + ')'
1167 else:
1168 return dpid
1169 else:
1170 return dpid + ' (' + alias + ')'
1171
1172
1173def print_switch_and_alias_dpid_as_long(i, data=None):
1174 dpid = convert_long_to_dpid(i)
1175 return print_switch_and_alias(dpid)
1176
1177
1178def print_switch_interface_and_alias(i, data=None):
1179 """
1180 """
1181 switch_interface = str(i)
1182 return switch_interface
1183
1184
1185def print_host_and_alias(i, data=None):
1186 # The value of 'i' here ought to be the primary key
1187 # for the host, which is a compound key. Try hard to
1188 # not deal with the construction of the key.
1189 mac = str(i)
1190 # if the host address is eight hex values, chop off the prefix
1191 # nasty hack to deal with the use of a int64 to hold a host
1192 if len(mac) == 23:
1193 mac = mac[6:]
1194 i = mac
1195 name = replace_host_with_alias(mac, data)
1196 if data == None:
1197 data = {}
1198
1199 mac_in_data = data.get('mac')
1200 suffix = ''
1201 if name != mac:
1202 suffix = ' (%s)' % name
1203
1204 if mac_in_data:
1205 return mac_in_data + suffix
1206 return mac + suffix
1207
1208
1209def print_vlan_and_alias(i, data=None):
1210 vlan = int(i)
1211 # if the host address is eight hex values, chop off the prefix
1212 # nasty hack to deal with the use of a int64 to hold a host
1213 return vlan
1214
1215
1216def print_host_and_alias_mac_as_long(i, data=None):
1217 mac = convert_mac_in_decimal_to_hex_string(i)
1218 return print_host_and_alias(mac, data)
1219
1220def print_host_and_alias_mac_as_long_str(i, data=None):
1221 # i is long decimal as string, e.g. "1342"
1222 mac_decimal = int(i)
1223 mac = convert_mac_in_decimal_to_hex_string(mac_decimal)
1224 return print_host_and_alias(mac, data)
1225
1226
1227# host list may also contain other items (ie: not macs)
1228def print_host_list_and_alias(i, data=None):
1229 # use at most 60 columns
1230
1231 more = 0
1232 output = ""
1233 for host in i:
1234 mac = str(host)
1235 name = replace_host_with_alias(host, data)
1236 if name != mac:
1237 mac += ' (' + name + ')'
1238 if len(output) + len(mac) > 60:
1239 more += 1
1240 else:
1241 output += mac
1242 output += ' '
1243 if more:
1244 return "%s+(%s)" % (output, more)
1245 return output
1246
1247
1248def replace_switch_with_alias(i, data=None):
1249 return replace_with_alias("switch-config", i, data)
1250
1251def convert_inverse_netmask_handler(i, data=None):
1252 if not '.' in i:
1253 return i
1254 split_bytes = i.split('.')
1255 return "%s.%s.%s.%s" % (255-int(split_bytes[0]),
1256 255-int(split_bytes[1]),
1257 255-int(split_bytes[2]),
1258 255-int(split_bytes[3]))
1259
1260def replace_host_with_alias(i, data=None):
1261 return replace_with_alias("host-config", i, data)
1262
1263
1264def replace_controller_node_with_alias(i, data=None):
1265 return replace_with_alias("controller-node", i, data)
1266
1267
1268def print_vns_count_dict(i, data=None):
1269 output = ""
1270 more = 0
1271 for vns in i:
1272 # possibly vns:refs instead?
1273 #item = '%s:%s ' % (vns, i[vns])
1274 item = '%s ' % vns
1275 if len(output) > 40:
1276 more += 1
1277 else:
1278 output += item
1279 if more:
1280 return "%s +(%s)" % (output, more)
1281 return output
1282
1283
1284def print_vns_physical_interface_id(i, data=None):
1285 return i.split('|')[2]
1286
1287
1288def print_domain_name_servers(i, data=None):
1289 if len(i) == 0:
1290 return 'None'
1291 result = i[0]
1292 if len(i) > 1:
1293 result += ' +(%d)' % (len(i)-1)
1294 return result
1295
1296
1297def print_all_domain_name_servers(i, data=None):
1298 if i == None:
1299 return ''
1300 return ', '.join(i)
1301
1302
1303def print_clock_string(i, data = None):
1304 print i, data
1305
1306
1307def replace_boolean_with_enable_disable(i, data=None):
1308 return { True : 'enabled', False : 'disabled' } [i]
1309
1310
1311def sanitize_unicode(i, data=None):
1312 return unicode(i, errors='ignore')
1313
1314
1315def controller_node_me_entry(i, data=None):
1316 if data.get('me', '') == '':
1317 return 'Not current controller'
1318 return 'current controller'
1319
1320def controller_node_me(i, data=None):
1321 if 'me' in data:
1322 return '*'
1323 return ''
1324
1325
1326def print_ipv4addr(i, data=None):
1327 ipaddr = data['ip']
1328 mask = data['masklen']
1329 if (ipaddr != "*"):
1330 ipaddr_int = reduce(lambda a,b: a<<8 | b, map(int, ipaddr.split(".")))
1331 mask = (1 << mask) - 1
1332 ipaddr_int = ipaddr_int & ~mask
1333 ipaddr = ".".join(map(lambda n: str(ipaddr_int >>n & 0xFF), [24,16,8,0]))
1334 return ipaddr
1335