Example #1
0
  def check_connectivity(simulation):
    ''' Return any pairs that couldn't reach each other '''
    # Always check liveness
    down_controllers = InvariantChecker.check_liveness(simulation)
    if down_controllers != []:
      return down_controllers

    # Effectively, run compute physical omega, ignore concrete values of headers, and
    # check that all pairs can reach eachother
    physical_omega = InvariantChecker.compute_physical_omega(simulation.topology.live_switches,
                                                             simulation.topology.live_links,
                                                             simulation.topology.access_links)
    connected_pairs = set()
    # Omegas are { original port -> [(final hs1, final port1), (final hs2, final port2)...] }
    for start_port, final_location_list in physical_omega.iteritems():
      for _, final_port in final_location_list:
        connected_pairs.add((start_port, final_port))

    # TODO(cs): translate HSA port numbers to ofp_phy_ports in the
    # headerspace/ module instead of computing uniq_port_id here
    access_links = simulation.topology.access_links
    all_pairs = [ (get_uniq_port_id(l1.switch, l1.switch_port),get_uniq_port_id(l2.switch, l2.switch_port))
                  for l1 in access_links
                  for l2 in access_links if l1 != l2 ]
    all_pairs = set(all_pairs)
    remaining_pairs = all_pairs - connected_pairs
    # TODO(cs): don't print results here
    if len(remaining_pairs) > 0:
      msg.fail("Not all %d pairs are connected! (%d missing)" %
               (len(all_pairs),len(remaining_pairs)))
      log.info("remaining_pairs: %s" % (str(remaining_pairs)))
    else:
      msg.success("Fully connected!")
    return list(remaining_pairs)
Example #2
0
def invoke_hassel_c(start_port, edge_ports):
  ''' invoke reachability test, and return the proc object '''
  if type(start_port) != int:
    start_port = get_uniq_port_id(start_port.switch, start_port.switch_port)

  if type(edge_ports) != list:
    edge_ports = list(edge_ports)
  if type(edge_ports[0]) != int:
    edge_ports = map(lambda access_link: get_uniq_port_id(access_link.switch, access_link.switch_port), edge_ports)

  edge_ports.remove(start_port)
  # Note that invoking
  #  `sts 200002 200002 1000002` returns nothing, whereas
  #  `sts 200002 100002 2000002` returns something.
  # It appears that hassel-c assumes that the out ports are sorted.
  edge_ports.sort()

  log.debug("port %d is being checked" % start_port)

  str_start_port = str(start_port)
  str_edge_ports = map(str, edge_ports)
  old_cwd = os.getcwd()
  try:
    os.chdir(HASSEL_C_PATH)
    proc = subprocess.Popen(["./sts", str(start_port)] + str_edge_ports,
                            stdout=subprocess.PIPE,
                            stderr=open('/dev/null', "w"))
  finally:
    os.chdir(old_cwd)
  return proc
Example #3
0
def invoke_hassel_c(start_port, edge_ports):
  ''' invoke reachability test, and return the proc object '''
  if type(start_port) != int:
    start_port = get_uniq_port_id(start_port.switch, start_port.switch_port)

  if type(edge_ports) != list:
    edge_ports = list(edge_ports)
  if type(edge_ports[0]) != int:
    edge_ports = map(lambda access_link: get_uniq_port_id(access_link.switch, access_link.switch_port), edge_ports)

  # TODO(cs): just noticed that invoking
  #  `sts 200002 200002 1000002` returns nothing, whereas
  #  `sts 200002 100002 2000002` returns something.
  # Why should the order of the out ports matter? Need to check that
  # hassel-c is actually computing all paths for all out ports
  edge_ports.remove(start_port)

  log.debug("port %d is being checked" % start_port)

  str_start_port = str(start_port)
  str_edge_ports = map(str, edge_ports)
  old_cwd = os.getcwd()
  try:
    os.chdir(HASSEL_C_PATH)
    proc = subprocess.Popen(["./sts", str(start_port)] + str_edge_ports,
                            stdout=subprocess.PIPE,
                            stderr=open('/dev/null', "w"))
  finally:
    os.chdir(old_cwd)
  return proc
Example #4
0
    def check_connectivity(simulation):
        ''' Return any pairs that couldn't reach each other '''
        # Always check liveness
        down_controllers = InvariantChecker.check_liveness(simulation)
        if down_controllers != []:
            return down_controllers

        # Effectively, run compute physical omega, ignore concrete values of headers, and
        # check that all pairs can reach eachother
        physical_omega = InvariantChecker.compute_physical_omega(
            simulation.topology.live_switches, simulation.topology.live_links,
            simulation.topology.access_links)
        connected_pairs = set()
        # Omegas are { original port -> [(final hs1, final port1), (final hs2, final port2)...] }
        for start_port, final_location_list in physical_omega.iteritems():
            for _, final_port in final_location_list:
                connected_pairs.add((start_port, final_port))

        # TODO(cs): translate HSA port numbers to ofp_phy_ports in the
        # headerspace/ module instead of computing uniq_port_id here
        access_links = simulation.topology.access_links
        all_pairs = [(get_uniq_port_id(l1.switch, l1.switch_port),
                      get_uniq_port_id(l2.switch, l2.switch_port))
                     for l1 in access_links for l2 in access_links if l1 != l2]
        all_pairs = set(all_pairs)
        remaining_pairs = all_pairs - connected_pairs
        # TODO(cs): don't print results here
        if len(remaining_pairs) > 0:
            msg.fail("Not all %d pairs are connected! (%d missing)" %
                     (len(all_pairs), len(remaining_pairs)))
            log.info("remaining_pairs: %s" % (str(remaining_pairs)))
        else:
            msg.success("Fully connected!")
        return list(remaining_pairs)
Example #5
0
 def _get_all_pairs(simulation):
   # TODO(cs): translate HSA port numbers to ofp_phy_ports in the
   # headerspace/ module instead of computing uniq_port_id here
   access_links = simulation.topology.access_links
   all_pairs = [ (get_uniq_port_id(l1.switch, l1.switch_port),get_uniq_port_id(l2.switch, l2.switch_port))
                 for l1 in access_links
                 for l2 in access_links if l1 != l2 ]
   all_pairs = set(all_pairs)
   return all_pairs
Example #6
0
def generate_TTF(all_links):
  ''' Takes a list of sts.debugger_entities.Link objects (directed) '''
  ttf = tf.TF(of.HS_FORMAT())

  for link in all_links:
    uniq_from_port = of.get_uniq_port_id(link.start_software_switch, link.start_port)
    uniq_to_port = of.get_uniq_port_id(link.end_software_switch, link.end_port)
    rule = tf.TF.create_standard_rule([uniq_from_port], None,[uniq_to_port], None, None)
    ttf.add_link_rule(rule)

  log.debug("topology transfer function (links): %s" % str(ttf))
  return ttf
Example #7
0
def translate_ports(ports):
  ports = list(ports)
  if type(ports[0]) != int:
    # They are switch objects
    port_nos = []
    for sw in ports:
      for port_no in sw.ports.keys():
        port_nos.append(get_uniq_port_id(sw, port_no))
    ports = port_nos
  return ports
Example #8
0
def detect_loop(NTF, TTF, ports, reverse_map, test_packet = None):
    if type(ports[0]) != int:
        ports = map(lambda access_link: get_uniq_port_id(access_link.switch, access_link.switch_port), ports)

    loops = []
    for port in ports:
        log.debug("port %d is being checked"%port)
        propagation = []

        # put all-x test packet in propagation graph
        test_pkt = test_packet
        if test_pkt == None:
          test_pkt = get_all_x(NTF)

        p_node = {}
        p_node["hdr"] = test_pkt
        p_node["port"] = port
        p_node["visits"] = []
        p_node["hs_history"] = []

        propagation.append(p_node)
        while len(propagation)>0:
            #get the next node in propagation graph and apply it to NTF and TTF
            log.debug("Propagation has length: %d"%len(propagation))
            tmp_propag = []
            for p_node in propagation:
                # hp is "header port"
                next_hp = NTF.T(p_node["hdr"],p_node["port"])
                for (next_h,next_ps) in next_hp:
                    for next_p in next_ps:
                        linked = TTF.T(next_h,next_p)
                        for (linked_h,linked_ports) in linked:
                            for linked_p in linked_ports:
                                new_p_node = {}
                                new_p_node["hdr"] = linked_h
                                new_p_node["port"] = linked_p
                                new_p_node["visits"] = list(p_node["visits"])
                                new_p_node["visits"].append(p_node["port"])
                                #new_p_node["visits"].append(next_p)
                                new_p_node["hs_history"] = list(p_node["hs_history"])
                                new_p_node["hs_history"].append(p_node["hdr"])
                                #print new_p_node
                                if len(new_p_node["visits"]) > 0 and new_p_node["visits"][0] == linked_p:
                                    loops.append(new_p_node)
                                    log.warn("loop detected")
                                elif linked_p in new_p_node["visits"]:
#                                    if (linked_p not in ports):
#                                        print "WARNING: detected a loop whose port is not in checked ports - branch aborted:"
#                                        print_loops([new_p_node],reverse_map)
#                                        print "END OF WARNING"
                                    pass
                                else:
                                    tmp_propag.append(new_p_node)
            propagation = tmp_propag
    return loops
Example #9
0
def compute_omega(name_tf_pairs, TTF, edge_links):
  prepare_hassel_c(name_tf_pairs, TTF)
  omega = {}
  # TODO(cs): need to model host end of link, or does switch end suffice?
  edge_ports = map(lambda access_link: get_uniq_port_id(access_link.switch, access_link.switch_port), edge_links)
  log.debug("edge_ports: %s" % edge_ports)

  for start_port in edge_ports:
    port_omega = compute_single_omega(start_port, list(edge_ports))
    omega = dict(omega.items() + port_omega.items())
  return omega
Example #10
0
def compute_single_omega(start_port, edge_ports):
    if type(start_port) != int:
      start_port = get_uniq_port_id(start_port.switch, start_port.switch_port)

    proc = invoke_hassel_c(start_port, edge_ports)

    omega = { start_port : [] }
    second_to_last_line = ''
    last_line = ''
    while True:
      # Format is:

      #  <Original> Port: ...
      #  <Next> Port: ...
      #  ...
      #  <Edge> Port: ...
      #  HS: D0,D0,D0,D8,D123,D123,...
      # -----
      #  <Original> Port -> ...
      #  ...

      line = proc.stdout.readline()
      if line == '':
        break
      print line.rstrip()

      if line.startswith("-----"):
        hs_string = last_line.split(":")[1].strip()
        # Get rid of commas (otherwise, will yield incorrect byte array)
        hs_string = hs_string.replace(",", "")
        port_stripped = second_to_last_line.split(":")[1].lstrip()
        out_port_string = port_stripped[0:port_stripped.index(",")]
        out_port = int(out_port_string)
        readable_hs = headerspace(of.hs_format)
        readable_hs.add_hs(hs_string_to_byte_array(hs_string))
        omega[start_port].append((readable_hs, out_port))

      second_to_last_line = last_line
      last_line = line

    return omega
Example #11
0
def check_partitions(switches, live_links, access_links):
  # TODO(cs): lifted directly from pox.forwarding.l2_multi. Highly
  # redundant!

  # Adjacency map.  [sw1][sw2] -> port from sw1 to sw2
  adjacency = defaultdict(lambda:defaultdict(lambda:None))

  for link in live_links:
    # Make sure to disregard links that are adjacent to down switches
    # (technically those links are still `live', but it's easier to treat it
    #  this way)
    if not (link.start_software_switch.failed or
            link.end_software_switch.failed):
      adjacency[link.start_software_switch][link.end_software_switch] = link

  # Switches we know of.  [dpid] -> Switch
  switches = { sw.dpid : sw for sw in switches }

  # [sw1][sw2] -> (distance, intermediate)
  path_map = defaultdict(lambda:defaultdict(lambda:(None,None)))

  def _calc_paths ():
    """
    Essentially Floyd-Warshall algorithm
    """
    sws = switches.values()
    path_map.clear()
    for k in sws:
      for j,port in adjacency[k].iteritems():
        if port is None: continue
        path_map[k][j] = (1,None)
      path_map[k][k] = (0,None) # distance, intermediate

    """
    for i in sws:
      for j in sws:
        a = path_map[i][j][0]
        #a = adjacency[i][j]
        if a is None: a = "*"
        print a,
      print
    """

    for k in sws:
      for i in sws:
        for j in sws:
          if path_map[i][k][0] is not None:
            if path_map[k][j][0] is not None:
              # i -> k -> j exists
              ikj_dist = path_map[i][k][0]+path_map[k][j][0]
              if path_map[i][j][0] is None or ikj_dist < path_map[i][j][0]:
                # i -> k -> j is better than existing
                path_map[i][j] = (ikj_dist, k)

    """
    print "--------------------"
    for i in sws:
      for j in sws:
        print path_map[i][j][0],
      print
    """

  all_link_pairs = [ (l1,l2) for l1 in access_links
                                for l2 in access_links if l1 != l2 ]

  _calc_paths()
  partioned_pairs = set()
  for link_pair in all_link_pairs:
    if path_map[link_pair[0].switch][link_pair[1].switch] == (None,None):
      id1 = get_uniq_port_id(link_pair[0].switch, link_pair[0].switch_port)
      id2 = get_uniq_port_id(link_pair[1].switch, link_pair[1].switch_port)
      partioned_pairs.add((id1,id2))
  return partioned_pairs
Example #12
0
def find_reachability(NTF, TTF, edge_links, test_packet=None):
    edge_ports = map(lambda access_link: get_uniq_port_id(access_link.switch, access_link.switch_port), edge_links)
    paths = defaultdict(list)
    propagation = []

    if len(edge_ports) == 0:
      log.warn("No ports to check!")
      return []

    for in_port in edge_ports:
      out_ports = list(set(edge_ports) - set([in_port]))

      # put all-x test packet in propagation graph
      input_pkt = test_packet
      if input_pkt == None:
        input_pkt = get_all_x(NTF)

      p_node = {}
      p_node["hdr"] = input_pkt
      p_node["port"] = in_port
      p_node["visits"] = []
      p_node["hs_history"] = []
      propagation.append(p_node)

      while len(propagation)>0:
          #get the next node in propagation graph and apply it to NTF and TTF
          log.debug("Propagation has length: %d"%len(propagation))
          tmp_propagate = []
          for p_node in propagation:
              next_hp = NTF.T(p_node["hdr"],p_node["port"])
              for (next_h,next_ps) in next_hp:
                  for next_p in next_ps:
                      if next_p in out_ports:
                          reached = {}
                          reached["hdr"] = next_h
                          reached["port"] = next_p
                          reached["visits"] = list(p_node["visits"])
                          reached["visits"].append(p_node["port"])
                          reached["hs_history"] = list(p_node["hs_history"])
                          paths[in_port].append(reached)
                      else:
                          linked = TTF.T(next_h,next_p)
                          for (linked_h,linked_ports) in linked:
                              for linked_p in linked_ports:
                                  new_p_node = {}
                                  new_p_node["hdr"] = linked_h
                                  new_p_node["port"] = linked_p
                                  new_p_node["visits"] = list(p_node["visits"])
                                  new_p_node["visits"].append(p_node["port"])
                                  new_p_node["visits"].append(next_p)
                                  new_p_node["hs_history"] = list(p_node["hs_history"])
                                  new_p_node["hs_history"].append(p_node["hdr"])
                                  if linked_p in out_ports:
                                      paths[in_port].append(new_p_node)
                                  elif linked_p in new_p_node["visits"]:
                                      log.warn("WARNING: detected a loop - branch aborted: \nHeaderSpace: %s\n Visited Ports: %s\nLast Port %d "%(\
                                          new_p_node["hdr"],new_p_node["visits"],new_p_node["port"]))
                                  else:
                                      tmp_propagate.append(new_p_node)
          propagation = tmp_propagate

    return paths
Example #13
0
def find_blackholes(NTF, TTF, edge_links, test_packet=None):
  '''Do any switches:
       - send packets into a down link?
       - drop packets that are supposed to go out their in_port?

     Specifically, checks whether it's possible for any
     packets to fall into the blackhole in the first place.
  '''
  edge_ports = map(lambda access_link: get_uniq_port_id(access_link.switch, access_link.switch_port), edge_links)
  blackholes = []
  propagation = []

  if len(edge_ports) == 0:
    log.warn("No ports to check!")
    return []

  for in_port in edge_ports:
    out_ports = list(set(edge_ports) - set([in_port]))

    # put all-x test packet in propagation graph
    input_pkt = test_packet
    if input_pkt == None:
      input_pkt = get_all_x(NTF)

    p_node = {}
    p_node["hdr"] = input_pkt
    p_node["port"] = in_port
    p_node["visits"] = []
    p_node["hs_history"] = []
    propagation.append(p_node)

    while len(propagation)>0:
        #get the next node in propagation graph and apply it to NTF and TTF
        log.debug("Propagation has length: %d"%len(propagation))
        tmp_propagate = []
        for p_node in propagation:
            next_hp = NTF.T(p_node["hdr"],p_node["port"])
            propagated = False
            for (next_h,next_ps) in next_hp:
                propagated = True
                for next_p in next_ps:
                    if next_p in out_ports:
                        pass
                    else: # Is an internal port
                        linked = TTF.T(next_h,next_p)
                        for (linked_h,linked_ports) in linked:
                            for linked_p in linked_ports:
                                new_p_node = {}
                                new_p_node["hdr"] = linked_h
                                new_p_node["port"] = linked_p
                                new_p_node["visits"] = list(p_node["visits"])
                                new_p_node["visits"].append(p_node["port"])
                                new_p_node["visits"].append(next_p)
                                new_p_node["hs_history"] = list(p_node["hs_history"])
                                new_p_node["hs_history"].append(p_node["hdr"])
                                if linked_p in out_ports:
                                    pass
                                elif linked_p in new_p_node["visits"]:
                                    log.warn("WARNING: detected a loop - branch aborted: \nHeaderSpace: %s\n Visited Ports: %s\nLast Port %d "%(\
                                        new_p_node["hdr"],new_p_node["visits"],new_p_node["port"]))
                                else:
                                    tmp_propagate.append(new_p_node)
            if not propagated and len(list(p_node["visits"])) != 0:
              # Append a tuple: (last egress port, [preceding ports])
              blackholes.append((next_p,list(p_node["visits"])))

        propagation = tmp_propagate
  return blackholes