Srikanth Vavilapalli | 1725e49 | 2014-12-01 17:50:52 -0800 | [diff] [blame] | 1 | # |
| 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 | |
| 19 | import urllib |
| 20 | import urllib2 |
| 21 | |
| 22 | import base64 |
| 23 | import struct |
| 24 | import time |
| 25 | import re |
| 26 | from datetime import datetime, timedelta, tzinfo |
| 27 | from calendar import timegm |
| 28 | from timesince import timesince, timesince_sec |
| 29 | import doctest |
| 30 | import traceback |
| 31 | import utif |
| 32 | import command |
| 33 | import json |
| 34 | |
Srikanth Vavilapalli | ca79f96 | 2015-04-01 18:48:05 -0700 | [diff] [blame^] | 35 | onos = 1 |
Srikanth Vavilapalli | 1725e49 | 2014-12-01 17:50:52 -0800 | [diff] [blame] | 36 | |
| 37 | # Timezone constants |
| 38 | class 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) |
| 45 | UTC = Utc() |
| 46 | |
| 47 | |
| 48 | class 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) |
| 55 | PST = Pst() |
| 56 | |
| 57 | |
| 58 | alias_dicts = {} |
| 59 | |
| 60 | |
| 61 | def 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 Vavilapalli | ca79f96 | 2015-04-01 18:48:05 -0700 | [diff] [blame^] | 71 | switchIdField = 'dpid' |
| 72 | if onos==2: |
| 73 | entries = entries['devices'] |
| 74 | switchIdField = 'id' |
Srikanth Vavilapalli | 1725e49 | 2014-12-01 17:50:52 -0800 | [diff] [blame] | 75 | #eprint entries |
| 76 | for switch in entries: |
| 77 | #print switch |
Srikanth Vavilapalli | ca79f96 | 2015-04-01 18:48:05 -0700 | [diff] [blame^] | 78 | 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 Vavilapalli | 1725e49 | 2014-12-01 17:50:52 -0800 | [diff] [blame] | 83 | #print switch.get("dpid") |
| 84 | #print switch.get("stringAttributes").get('name') |
| 85 | return switches_dpid_name |
| 86 | |
| 87 | |
| 88 | def 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 | |
| 96 | def 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 | |
| 103 | def 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 | |
| 114 | def 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 | |
| 120 | def convert_integer_to_bitmask(i, data=None): |
| 121 | if i == "*" or i == "": |
| 122 | return "*" |
| 123 | return bin(i) |
| 124 | |
| 125 | |
| 126 | def 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 | |
| 133 | def 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 | |
| 145 | def 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 | |
| 152 | def 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 | |
| 161 | def print_hex(i, data=None): |
| 162 | if i == "" or not int(i): |
| 163 | return "" |
| 164 | else: |
| 165 | return hex(i) |
| 166 | |
| 167 | |
| 168 | def 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 | |
| 174 | def utc_timestr_to_timestamp(s): |
| 175 | return timegm(time.strptime(s, "%Y-%m-%d %H:%M:%S.%f")) * 1000 |
| 176 | |
| 177 | |
| 178 | def 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 | |
| 202 | def print_time_since_utc(i, data=None): |
| 203 | if i == None or i == '': |
| 204 | return '' |
| 205 | return timesince(datetime.fromtimestamp((i/1000))) |
| 206 | |
| 207 | |
| 208 | def 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 | |
| 242 | def print_timesince_msec_since(i, data=None): |
| 243 | if i == '': |
| 244 | return i |
| 245 | return timesince_sec(int(i)/1000) |
| 246 | |
| 247 | def 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 | |
| 257 | def 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 | |
| 267 | def 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 | |
| 287 | def 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 | |
| 305 | def 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 | |
| 334 | def print_byte_rate(i, data=None): |
| 335 | return print_byte_unit(i, data, 'ps') |
| 336 | |
| 337 | def 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 | |
| 366 | def print_bit_rate(i, data=None): |
| 367 | return print_bit_unit(i, data, 'ps') |
| 368 | |
| 369 | |
| 370 | def 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 | |
| 401 | def decode_openflow_port_src_switch(i, data=None): |
| 402 | return decode_openflow_port(i, data, 'src-switch') |
| 403 | |
| 404 | |
| 405 | def decode_openflow_port_source_switch(i, data=None): |
| 406 | return decode_openflow_port(i, data, 'Source-Switch') |
| 407 | |
| 408 | |
| 409 | def decode_openflow_port_dst_switch(i, data=None): |
| 410 | return decode_openflow_port(i, data, 'dst-switch') |
| 411 | |
| 412 | |
| 413 | def decode_openflow_port_dest_switch(i, data=None): |
| 414 | return decode_openflow_port(i, data, 'Dest-Switch') |
| 415 | |
| 416 | |
| 417 | def decode_openflow_port_inputSwitch(i, data=None): |
| 418 | return decode_openflow_port(i, data, 'inputSwitch') |
| 419 | |
| 420 | |
| 421 | def 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 |
| 426 | cookie_app_ids = { |
| 427 | 1: "lswitch", |
| 428 | 2: "FL:forw", |
| 429 | 3: "TUN:forw", |
| 430 | 4: "VTA:forw", |
| 431 | 10: "static", |
| 432 | } |
| 433 | |
| 434 | flow_cookie_registry = { } |
| 435 | |
| 436 | def 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 | |
| 450 | def 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 | |
| 456 | def 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 | |
| 497 | ether_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 | |
| 513 | ether_type_to_number_dict = dict([[v, n] for (n,v) in ether_type_to_name_dict.items()]) |
| 514 | |
| 515 | |
| 516 | def 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 | |
| 531 | def 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 | |
| 566 | tcp_decode_port_dict = { |
| 567 | 22 : "ssh", |
| 568 | 53 : "dns", |
| 569 | 80 : 'http', |
| 570 | 443 : 'https' |
| 571 | } |
| 572 | |
| 573 | tcp_name_to_number_dict = dict([[v, n] for (n,v) in tcp_decode_port_dict.items()]) |
| 574 | |
| 575 | # fill in values if we want! |
| 576 | def decode_tcp_port(i): |
| 577 | return print_enum_string_and_int(tcp_decode_port_dict, i) |
| 578 | |
| 579 | |
| 580 | udp_decode_port_dict = { |
| 581 | 53 : "dns", |
| 582 | } |
| 583 | |
| 584 | udp_name_to_number_dict = dict([[v, n] for (n,v) in udp_decode_port_dict.items()]) |
| 585 | |
| 586 | def decode_udp_port(i): |
| 587 | values = { |
| 588 | } |
| 589 | return print_enum_string_and_int(values, i) |
| 590 | |
| 591 | |
| 592 | icmp_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 | |
| 636 | def 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 | |
| 643 | def 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 | |
| 654 | def 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 | |
| 675 | def 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 | |
| 696 | def 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 | |
| 764 | def decode_port_counter(i, data=None): |
| 765 | if i == -1: |
| 766 | return "n/a" |
| 767 | else: |
| 768 | return i |
| 769 | |
| 770 | |
| 771 | def 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 | |
| 782 | def 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 | |
| 796 | def 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 | |
| 812 | def 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 | |
| 832 | def decode_port_up_down(i, data=None): |
| 833 | if i == '': |
| 834 | return 'Unknown' |
| 835 | return "down" if i == 1 else 'up' |
| 836 | |
| 837 | |
| 838 | def 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 | |
| 851 | def 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 | |
| 868 | def 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 | |
| 886 | def 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 | |
| 899 | def 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 | |
| 919 | wildcards = { |
| 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 | |
| 932 | def 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 | |
| 972 | def 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 | |
| 1017 | def 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 | |
| 1023 | def 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 | |
| 1029 | def 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 | |
| 1049 | def 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 | |
| 1058 | def 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 | |
| 1067 | def print_cluster_id(i, data=None): |
| 1068 | return str(i) |
| 1069 | |
| 1070 | |
| 1071 | def print_switches(i, data=None): |
| 1072 | return ' '.join([replace_switch_with_alias(dpid) for dpid in i]) |
| 1073 | |
| 1074 | |
| 1075 | def print_single_tag(tag): |
| 1076 | fields = tag.split('|') |
| 1077 | return "%s.%s=%s" % (fields[0],fields[1],fields[2]) |
| 1078 | |
| 1079 | def 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 | |
| 1096 | def 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 | |
| 1104 | def 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 | |
| 1130 | def 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 | |
| 1136 | def print_devicemanager_ip_addresses(i, data=None): |
| 1137 | if i == None: |
| 1138 | return '' |
| 1139 | return ' '.join([x['ip'] for x in i]) |
| 1140 | |
| 1141 | |
| 1142 | def print_join_list(i, data=None): |
| 1143 | return ', '.join(i) |
| 1144 | |
| 1145 | |
| 1146 | def 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 | |
| 1157 | def 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 | |
| 1173 | def 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 | |
| 1178 | def print_switch_interface_and_alias(i, data=None): |
| 1179 | """ |
| 1180 | """ |
| 1181 | switch_interface = str(i) |
| 1182 | return switch_interface |
| 1183 | |
| 1184 | |
| 1185 | def 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 | |
| 1209 | def 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 | |
| 1216 | def 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 | |
| 1220 | def 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) |
| 1228 | def 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 | |
| 1248 | def replace_switch_with_alias(i, data=None): |
| 1249 | return replace_with_alias("switch-config", i, data) |
| 1250 | |
| 1251 | def 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 | |
| 1260 | def replace_host_with_alias(i, data=None): |
| 1261 | return replace_with_alias("host-config", i, data) |
| 1262 | |
| 1263 | |
| 1264 | def replace_controller_node_with_alias(i, data=None): |
| 1265 | return replace_with_alias("controller-node", i, data) |
| 1266 | |
| 1267 | |
| 1268 | def 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 | |
| 1284 | def print_vns_physical_interface_id(i, data=None): |
| 1285 | return i.split('|')[2] |
| 1286 | |
| 1287 | |
| 1288 | def 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 | |
| 1297 | def print_all_domain_name_servers(i, data=None): |
| 1298 | if i == None: |
| 1299 | return '' |
| 1300 | return ', '.join(i) |
| 1301 | |
| 1302 | |
| 1303 | def print_clock_string(i, data = None): |
| 1304 | print i, data |
| 1305 | |
| 1306 | |
| 1307 | def replace_boolean_with_enable_disable(i, data=None): |
| 1308 | return { True : 'enabled', False : 'disabled' } [i] |
| 1309 | |
| 1310 | |
| 1311 | def sanitize_unicode(i, data=None): |
| 1312 | return unicode(i, errors='ignore') |
| 1313 | |
| 1314 | |
| 1315 | def controller_node_me_entry(i, data=None): |
| 1316 | if data.get('me', '') == '': |
| 1317 | return 'Not current controller' |
| 1318 | return 'current controller' |
| 1319 | |
| 1320 | def controller_node_me(i, data=None): |
| 1321 | if 'me' in data: |
| 1322 | return '*' |
| 1323 | return '' |
| 1324 | |
| 1325 | |
| 1326 | def 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 | |