Commit dfa3e035 authored by Andrea Sgambelluri's avatar Andrea Sgambelluri
Browse files

working with disjoint and multiple bands

parent 6ef57ac5
Loading
Loading
Loading
Loading
+8 −6
Original line number Diff line number Diff line
@@ -70,23 +70,25 @@ class AddLightpath(Resource):

#@optical.route('/AddFlexLightpath/<string:src>/<string:dst>/<int:bitrate>')
@optical.route('/AddFlexLightpath/<string:src>/<string:dst>/<int:bitrate>',
               defaults={"bidir": 1, "band": None})
               defaults={"bidir": 1, "band": None, "obx_idx": None})
@optical.route('/AddFlexLightpath/<string:src>/<string:dst>/<int:bitrate>/<int:bidir>',
               defaults={"band": None})
@optical.route('/AddFlexLightpath/<string:src>/<string:dst>/<int:bitrate>/<int:bidir>/<int:band>',)
               defaults={"band": None, "obx_idx": None})
@optical.route('/AddFlexLightpath/<string:src>/<string:dst>/<int:bitrate>/<int:bidir>/<int:band>',
               defaults={"obx_idx": None})
@optical.route('/AddFlexLightpath/<string:src>/<string:dst>/<int:bitrate>/<int:bidir>/<int:band>/<int:obx_idx>')
@optical.response(200, 'Success')
@optical.response(404, 'Error, not found')
class AddFlexLightpath(Resource):
    @staticmethod
    def put(src, dst, bitrate, bidir=1, band=None):
    def put(src, dst, bitrate, bidir=1, band=None, obx_idx = None):

        print("INFO: New FlexLightpath request from {} to {} with rate {} and band {}".format(src, dst, bitrate, band))
        print("INFO: New MGON request from {} to {} with rate {} and band {}".format(src, dst, bitrate, band))
        t0 = time.time()*1000.0
        #if debug:
        #    rsa.g.printGraph()

        if rsa is not None:
            flow_id, optical_band_id = rsa.rsa_fs_computation(src, dst, bitrate, bidir, band)
            flow_id, optical_band_id = rsa.rsa_fs_computation(src, dst, bitrate, bidir, band, obx_idx)
            if flow_id is not None:
                if rsa.db_flows[flow_id]["op-mode"] == 0:
                    return 'No path found', 404
+53 −9
Original line number Diff line number Diff line
@@ -147,7 +147,31 @@ class RSA():
        self.g.reset_graph()
        return links, path

    def get_slots(self, links, slots, optical_band_id=None):
    def compute_disjoint_path(self, src, dst, path1=None):
        if path1 == None:
            path1 = shortest_path(self.g, self.g.get_vertex(src), self.g.get_vertex(dst))
        path = disjoint_path(self.g, src, dst, path1, False)      
        print("INFO: Path from {} to {} with distance: {}".format(src, dst, self.g.get_vertex(dst).get_distance()))
        if debug:
            print(path)
        links = []
        for i in range(0, len(path) - 1):
            s = path[i]
            if debug:
                print(s)
            if i < len(path) - 1:
                d = path[i + 1]
                link_id = "{}-{}".format(s, d)
                if debug:
                    #print(link_id, self.links_dict[link_id])
                    print(link_id, self.get_link_by_name(link_id))

                links.append(link_id)
        self.g.reset_graph()
        return links, path


    def get_slots(self, links, slots, optical_band_id=None, old_band_x=None):

        if isinstance(slots, int):
            val_c = slots
@@ -246,6 +270,7 @@ class RSA():
                l_slots[l] = combine(l_slots[l], consecutives(fib["l_slots"], val_l))
                l_found = 1'''
        if optical_band_id is not None:
            print(f"NEW_DISJOINT: {self.optical_bands[optical_band_id]}")
            if "c_slots" in self.optical_bands[optical_band_id].keys():
                if len(self.optical_bands[optical_band_id]["c_slots"]) > 0:
                    a_c = c_sts
@@ -269,6 +294,14 @@ class RSA():
                    s_sts = common_slots(a_s, b_s)
            else:
                s_sts = []
        if old_band_x == "c_slots":
            c_sts = []
            l_sts = []
        if old_band_x == "l_slots":
            c_sts = []
            l_sts = []
        if old_band_x == "s_slots":
            s_sts = []
        
        return c_sts, l_sts, s_sts

@@ -839,7 +872,7 @@ class RSA():
        #self.db_flows[flow_id]["parent_opt_band"] = 0
        #self.db_flows[flow_id]["new_optical_band"] = 0

    def create_optical_band(self, links, path, bidir, num_slots):
    def create_optical_band(self, links, path, bidir, num_slots, old_band_x=None):
        print("INFO: Creating optical-band of {} slots".format(num_slots))
        if self.opt_band_id == 0:
            self.opt_band_id += 1
@@ -888,8 +921,7 @@ class RSA():
        if bidir:
            self.optical_bands[back_opt_band_id]["src"] = path[-1]
        '''

        c_slots, l_slots, s_slots = self.get_slots(links, num_slots)
        c_slots, l_slots, s_slots = self.get_slots(links, num_slots, optical_band_id=None, old_band_x=old_band_x)
        if debug:
            print(c_slots)
            print(l_slots)
@@ -991,7 +1023,7 @@ class RSA():
                result.append(ob_id)
        return result

    def rsa_fs_computation(self, src, dst, rate, bidir, band):
    def rsa_fs_computation(self, src, dst, rate, bidir, band, bandx_id):
        if band is not None:
            num_slots_ob = map_band_to_slot(band)
            print(band, num_slots_ob)
@@ -999,11 +1031,23 @@ class RSA():
            num_slots_ob = "full_band"
        if self.nodes_dict[src]["type"] == "OC-ROADM" and self.nodes_dict[dst]["type"] == "OC-ROADM":
            print("INFO: ROADM to ROADM connection")
            old_band_x = None
            if bandx_id != None:
                if bandx_id in self.optical_bands.keys():
                    path_x = self.optical_bands[bandx_id]["path"]
                    old_band_x = self.optical_bands[bandx_id]["band_type"]
                    links, path = self.compute_disjoint_path(src, dst, path_x)
                else:
                    links, path = self.compute_disjoint_path(src, dst, None)
                if len(path) < 1:
                    print("INFO: no disjoint path found, installing in the shortest path")
                    links, path = self.compute_path(src, dst)
            else:
                links, path = self.compute_path(src, dst)
            if len(path) < 1:
                self.null_values_ob(self.opt_band_id)
                return self.opt_band_id, []
            optical_band_id, temp_links = self.create_optical_band(links, path, bidir, num_slots_ob)
            optical_band_id, temp_links = self.create_optical_band(links, path, bidir, num_slots_ob, old_band_x)
            return None, optical_band_id
        print("INFO: TP to TP connection")
        if self.flow_id == 0:
+157 −12
Original line number Diff line number Diff line
@@ -129,9 +129,20 @@ class Graph:
        self.vert_dict[frm].add_neighbor(self.vert_dict[to], [port_frm, w])
        self.vert_dict[to].add_neighbor(self.vert_dict[frm], [port_to, w])

    '''
    def del_edge(self, frm, to, cost = 0):
        self.vert_dict[frm].del_neighbor(self.vert_dict[to])
        self.vert_dict[to].del_neighbor(self.vert_dict[frm])
    '''

    def del_edge(self, frm, to, cost=0):
        if frm in self.vert_dict and to in self.vert_dict:
            v_from = self.vert_dict[frm]
            v_to = self.vert_dict[to]
            if v_to in v_from.adjacent:
                v_from.del_neighbor(v_to)
            if v_from in v_to.adjacent:
                v_to.del_neighbor(v_from)

    def get_vertices(self):
        return self.vert_dict.keys()
@@ -142,6 +153,45 @@ class Graph:
    def get_previous(self, current):
        return self.previous

    def copy(self):
        """
        Returns a deep copy of the graph (vertices, edges, ports, and weights).
        """
        new_graph = Graph()

        # First, create all vertices
        for node_id in self.vert_dict:
            new_graph.add_vertex(node_id)

        # Then, add all edges with the same attributes
        for v in self:
            for neighbor in v.get_connections():
                frm = v.get_id()
                to = neighbor.get_id()
                port_frm = v.get_port(neighbor)
                port_to = neighbor.get_port(v)
                weight = v.get_weight(neighbor)
                
                # To avoid adding the same undirected edge twice
                if frm < to:
                    new_graph.add_edge(frm, to, port_frm, port_to, weight)

        return new_graph

    def copy2(self):
        new_g = Graph()
        # Copy vertices
        for node_id in self.vert_dict:
            new_g.add_vertex(node_id)
        # Copy edges
        for frm in self.vert_dict:
            for to in self.vert_dict[frm].adjacent:
                port_frm, weight = self.vert_dict[frm].adjacent[to]
                port_to, _ = self.vert_dict[to].adjacent[frm]
                if not new_g.get_vertex(frm).adjacent.get(new_g.get_vertex(to)):
                    new_g.add_edge(frm, to.get_id(), port_frm, port_to, weight)
        return new_g

def shortest(v, path):
    if v.previous:
        path.append(v.previous.get_id())
@@ -198,6 +248,90 @@ def shortest_path(graph, src, dst):
    shortest(target, path)
    return path[::-1]


def compute_disjoint_paths(graph, src, dst, k=2, disjoint_type="link", debug=False):
    """
    Compute up to k disjoint shortest paths between src and dst using Dijkstra.
    disjoint_type: "link" (edge-disjoint) or "node" (vertex-disjoint)
    """
    
    paths = []
    removed_edges = []  # Keep track of removed edges
    removed_nodes = []  # Keep track of removed nodes

    for i in range(k):
        # Compute shortest path using the existing Dijkstra-based function
        path = shortest_path(graph, src, dst)

        # Stop if no valid path found
        if not path or len(path) < 2:
            if debug:
                print(f"[INFO] No more disjoint paths found after {i} iterations.")
            break

        paths.append(path)
        if debug:
            print(f"[INFO] Path {i+1}: {path}")

        # Depending on disjointness type, remove edges or nodes from graph
        if disjoint_type == "link":
            for u, v in zip(path[:-1], path[1:]):
                if debug:
                    print(f"  Removing edge {u}-{v}")
                removed_edges.append((u, v))
                # Remove edge in both directions
                graph.del_edge(u, v)

        elif disjoint_type == "node":
            # Remove intermediate nodes (not source or destination)
            for n in path[1:-1]:
                if debug:
                    print(f"  Removing node {n}")
                removed_nodes.append(n)
                # Remove all edges involving this node
                v = graph.get_vertex(n)
                if v is not None:
                    for neighbor in list(v.get_connections()):
                        graph.del_edge(n, neighbor.get_id())
                    graph.del_Vertex(n)
        else:
            raise ValueError("disjoint_type must be 'link' or 'node'")

        # Reset distances & visited flags for the next run
        graph.reset_graph()

    if debug:
        print(f"[INFO] Found {len(paths)} disjoint paths.")

    return paths

def disjoint_path(graph, src_id, dst_id, pathz, debug=False):
    g2 = graph.copy()
    src = g2.get_vertex(src_id)
    dst = g2.get_vertex(dst_id)
    removed_edges = []  # Keep track of removed edges
    removed_nodes = []  # Keep track of removed nodes
    for u, v in zip(pathz[:-1], pathz[1:]):
       if debug:
          print(f"  Removing edge {u}-{v}") 
       removed_edges.append((u, v))
       # Remove edge in both directions
       g2.del_edge(u, v)
    # Compute shortest path using the existing Dijkstra-based function
    g2.reset_graph()
    pathx = shortest_path(g2, src, dst)

    # Stop if no valid path found
    if not pathx or len(pathx) < 2:
        if debug:
            print(f"[INFO] No more disjoint paths found.")
            return []

    g2.reset_graph()

    return pathx


if __name__ == '__main__':

    print("Testing Algo")
@@ -210,15 +344,15 @@ if __name__ == '__main__':
    g.add_vertex('e')
    g.add_vertex('f')

    g.add_edge('a', 'b', 7)  
    g.add_edge('a', 'c', 9)
    g.add_edge('a', 'f', 14)
    g.add_edge('b', 'c', 10)
    g.add_edge('b', 'd', 15)
    g.add_edge('c', 'd', 11)
    g.add_edge('c', 'f', 2)
    g.add_edge('d', 'e', 6)
    g.add_edge('e', 'f', 9)
    g.add_edge('a', 'b', 1, 1, 7)  
    g.add_edge('a', 'c', 2, 1, 9)
    g.add_edge('a', 'f', 3, 1, 14)
    g.add_edge('b', 'c', 2, 2, 10)
    g.add_edge('b', 'd', 3, 1, 15)
    g.add_edge('c', 'd', 3, 2, 11)
    g.add_edge('c', 'f', 4, 2, 2)
    g.add_edge('d', 'e', 4, 1, 6)
    g.add_edge('e', 'f', 2, 3, 9)


    """print ('Graph data:')
@@ -235,6 +369,17 @@ if __name__ == '__main__':
    path = [target.get_id()]
    shortest(target, path)
    print ('The shortest path : %s' %(path[::-1]))"""

    p = shortest_path(g, g.get_vertex('a'), g.get_vertex('e'))
    print(p)
    #print(g.printGraph())
    pat = shortest_path(g, g.get_vertex('a'), g.get_vertex('e'))
    print(pat)
    
    #paths = compute_disjoint_paths(g, g.get_vertex('a'), g.get_vertex('e'), k=2, disjoint_type="link", debug=False)
    #paths = compute_disjoint_paths(g, g.get_vertex('a'), g.get_vertex('e'), k=2, disjoint_type="link", debug=False)
    #print(paths)
    path2 = compute_disjoint_path(g, 'a', 'e', pat, False)
    print(path2)
    
    pat = shortest_path(g, g.get_vertex('a'), g.get_vertex('d'))
    print(pat)
    path2 = compute_disjoint_path(g, 'a', 'd', pat, False)
    print(path2)
 No newline at end of file
+9 −5
Original line number Diff line number Diff line
@@ -288,6 +288,7 @@ class ServiceServiceServicerImpl(ServiceServiceServicer):
            ob_band = None
            oc_type = 1
            bitrate = 100
            dj_optical_band_id = None
            for constraint in service.service_constraints:
                if "bandwidth" in constraint.custom.constraint_type:
                    bitrate = int(float(constraint.custom.constraint_value))
@@ -296,19 +297,22 @@ class ServiceServiceServicerImpl(ServiceServiceServicer):
                elif "optical-band-width" in constraint.custom.constraint_type:
                    ob_band = int(constraint.custom.constraint_value)
                elif "type" in constraint.custom.constraint_type:
                    logging.info(f"TEEEEEEEEEEEEEEST {constraint.custom.constraint_type}={constraint.custom.constraint_value}")
                    logging.info(f"{constraint.custom.constraint_type}={constraint.custom.constraint_value}")
                    oc_type = OpticalServiceType(str(constraint.custom.constraint_value))
                    logging.info(f"TEEEEEEEEEEEEEEST {oc_type}")
                    
                    logging.info(f"{oc_type}")
                elif "disjoint_optical_band_id" in constraint.custom.constraint_type:
                    logging.info(f"{constraint.custom.constraint_type}={constraint.custom.constraint_value}")
                    dj_optical_band_id = int(constraint.custom.constraint_value)
                    logging.info(f"{dj_optical_band_id}")    
            reply_txt = ""
            # to get the reply form the optical module
            #multi-granular
            if oc_type == 1:
                reply_txt = add_flex_lightpath(src, dst, bitrate, bidir, ob_band)
                reply_txt = add_flex_lightpath(src, dst, bitrate, bidir, ob_band, dj_optical_band_id)
            elif oc_type == 2:
                reply_txt = add_lightpath(src, dst, bitrate, bidir)
            else:
                reply_txt = add_flex_lightpath(src, dst, bitrate, bidir, ob_band)
                reply_txt = add_flex_lightpath(src, dst, bitrate, bidir, ob_band, dj_optical_band_id)
            logging.info(f"TEEEEEEEEEEEEEEST {oc_type}")
            logging.info(f"POLIMI {reply_txt}")
            if reply_txt == None:
+6 −2
Original line number Diff line number Diff line
@@ -137,11 +137,12 @@ def reconfig_flex_lightpath(flow_id) -> str:
        return reply_bid_txt


def add_flex_lightpath(src, dst, bitrate, bidir, ob_band) -> str:
def add_flex_lightpath(src, dst, bitrate, bidir, ob_band, dj_optical_band_id) -> str:
    if not TESTING:
        urlx = ""
        headers = {"Content-Type": "application/json"}
        base_url = get_optical_controller_base_url()
        
        if ob_band is None:
            if bidir is None:
                bidir = 1
@@ -149,7 +150,10 @@ def add_flex_lightpath(src, dst, bitrate, bidir, ob_band) -> str:
        else:
            if bidir is None:
                bidir = 1
            if dj_optical_band_id is None:
                urlx = "{:s}/AddFlexLightpath/{:s}/{:s}/{:s}/{:s}/{:s}".format(base_url, src, dst, str(bitrate), str(bidir), str(ob_band))
            else:
                urlx = "{:s}/AddFlexLightpath/{:s}/{:s}/{:s}/{:s}/{:s}/{:s}".format(base_url, src, dst, str(bitrate), str(bidir), str(ob_band), str(dj_optical_band_id))                
        r = requests.put(urlx, headers=headers)
        print(f"addpathlight {r}")
        reply = r.text