Reformatting RO
[osm/RO.git] / RO-plugin / osm_ro_plugin / openflow_conn.py
index f46c6cf..17351b0 100644 (file)
@@ -31,6 +31,7 @@ __date__ = "2019-11-11"
 
 class OpenflowConnException(Exception):
     """Common and base class Exception for all vimconnector exceptions"""
 
 class OpenflowConnException(Exception):
     """Common and base class Exception for all vimconnector exceptions"""
+
     def __init__(self, message, http_code=HTTPStatus.BAD_REQUEST.value):
         Exception.__init__(self, message)
         self.http_code = http_code
     def __init__(self, message, http_code=HTTPStatus.BAD_REQUEST.value):
         Exception.__init__(self, message)
         self.http_code = http_code
@@ -38,42 +39,49 @@ class OpenflowConnException(Exception):
 
 class OpenflowConnConnectionException(OpenflowConnException):
     """Connectivity error with the VIM"""
 
 class OpenflowConnConnectionException(OpenflowConnException):
     """Connectivity error with the VIM"""
+
     def __init__(self, message, http_code=HTTPStatus.SERVICE_UNAVAILABLE.value):
         OpenflowConnException.__init__(self, message, http_code)
 
 
 class OpenflowConnUnexpectedResponse(OpenflowConnException):
     """Get an wrong response from VIM"""
     def __init__(self, message, http_code=HTTPStatus.SERVICE_UNAVAILABLE.value):
         OpenflowConnException.__init__(self, message, http_code)
 
 
 class OpenflowConnUnexpectedResponse(OpenflowConnException):
     """Get an wrong response from VIM"""
+
     def __init__(self, message, http_code=HTTPStatus.INTERNAL_SERVER_ERROR.value):
         OpenflowConnException.__init__(self, message, http_code)
 
 
 class OpenflowConnAuthException(OpenflowConnException):
     """Invalid credentials or authorization to perform this action over the VIM"""
     def __init__(self, message, http_code=HTTPStatus.INTERNAL_SERVER_ERROR.value):
         OpenflowConnException.__init__(self, message, http_code)
 
 
 class OpenflowConnAuthException(OpenflowConnException):
     """Invalid credentials or authorization to perform this action over the VIM"""
+
     def __init__(self, message, http_code=HTTPStatus.UNAUTHORIZED.value):
         OpenflowConnException.__init__(self, message, http_code)
 
 
 class OpenflowConnNotFoundException(OpenflowConnException):
     """The item is not found at VIM"""
     def __init__(self, message, http_code=HTTPStatus.UNAUTHORIZED.value):
         OpenflowConnException.__init__(self, message, http_code)
 
 
 class OpenflowConnNotFoundException(OpenflowConnException):
     """The item is not found at VIM"""
+
     def __init__(self, message, http_code=HTTPStatus.NOT_FOUND.value):
         OpenflowConnException.__init__(self, message, http_code)
 
 
 class OpenflowConnConflictException(OpenflowConnException):
     """There is a conflict, e.g. more item found than one"""
     def __init__(self, message, http_code=HTTPStatus.NOT_FOUND.value):
         OpenflowConnException.__init__(self, message, http_code)
 
 
 class OpenflowConnConflictException(OpenflowConnException):
     """There is a conflict, e.g. more item found than one"""
+
     def __init__(self, message, http_code=HTTPStatus.CONFLICT.value):
         OpenflowConnException.__init__(self, message, http_code)
 
 
 class OpenflowConnNotSupportedException(OpenflowConnException):
     """The request is not supported by connector"""
     def __init__(self, message, http_code=HTTPStatus.CONFLICT.value):
         OpenflowConnException.__init__(self, message, http_code)
 
 
 class OpenflowConnNotSupportedException(OpenflowConnException):
     """The request is not supported by connector"""
+
     def __init__(self, message, http_code=HTTPStatus.SERVICE_UNAVAILABLE.value):
         OpenflowConnException.__init__(self, message, http_code)
 
 
 class OpenflowConnNotImplemented(OpenflowConnException):
     """The method is not implemented by the connected"""
     def __init__(self, message, http_code=HTTPStatus.SERVICE_UNAVAILABLE.value):
         OpenflowConnException.__init__(self, message, http_code)
 
 
 class OpenflowConnNotImplemented(OpenflowConnException):
     """The method is not implemented by the connected"""
+
     def __init__(self, message, http_code=HTTPStatus.NOT_IMPLEMENTED.value):
         OpenflowConnException.__init__(self, message, http_code)
 
     def __init__(self, message, http_code=HTTPStatus.NOT_IMPLEMENTED.value):
         OpenflowConnException.__init__(self, message, http_code)
 
@@ -82,14 +90,15 @@ class OpenflowConn:
     """
     Openflow controller connector abstract implementeation.
     """
     """
     Openflow controller connector abstract implementeation.
     """
+
     def __init__(self, params):
         self.name = "openflow_conector"
         self.pp2ofi = {}  # From Physical Port to OpenFlow Index
         self.ofi2pp = {}  # From OpenFlow Index to Physical Port
     def __init__(self, params):
         self.name = "openflow_conector"
         self.pp2ofi = {}  # From Physical Port to OpenFlow Index
         self.ofi2pp = {}  # From OpenFlow Index to Physical Port
-        self.logger = logging.getLogger('ro.sdn.openflow_conn')
+        self.logger = logging.getLogger("ro.sdn.openflow_conn")
 
     def get_of_switches(self):
 
     def get_of_switches(self):
-        """"
+        """
         Obtain a a list of switches or DPID detected by this controller
         :return: list length, and a list where each element a tuple pair (DPID, IP address), text_error: if fails
         """
         Obtain a a list of switches or DPID detected by this controller
         :return: list length, and a list where each element a tuple pair (DPID, IP address), text_error: if fails
         """
@@ -146,7 +155,7 @@ class OpenflowConn:
         raise OpenflowConnNotImplemented("Should have implemented this")
 
     def clear_all_flows(self):
         raise OpenflowConnNotImplemented("Should have implemented this")
 
     def clear_all_flows(self):
-        """"
+        """
         Delete all existing rules
         :return: None if ok, text_error if fails
         """
         Delete all existing rules
         :return: None if ok, text_error if fails
         """
@@ -157,13 +166,24 @@ class SdnConnectorOpenFlow(SdnConnectorBase):
     """
     This class is the base engine of SDN plugins base on openflow rules
     """
     """
     This class is the base engine of SDN plugins base on openflow rules
     """
-    flow_fields = ('priority', 'vlan', 'ingress_port', 'actions', 'dst_mac', 'src_mac', 'net_id')
+
+    flow_fields = (
+        "priority",
+        "vlan",
+        "ingress_port",
+        "actions",
+        "dst_mac",
+        "src_mac",
+        "net_id",
+    )
 
     def __init__(self, wim, wim_account, config=None, logger=None, of_connector=None):
 
     def __init__(self, wim, wim_account, config=None, logger=None, of_connector=None):
-        self.logger = logger or logging.getLogger('ro.sdn.openflow_conn')
+        self.logger = logger or logging.getLogger("ro.sdn.openflow_conn")
         self.of_connector = of_connector
         config = config or {}
         self.of_connector = of_connector
         config = config or {}
-        self.of_controller_nets_with_same_vlan = config.get("of_controller_nets_with_same_vlan", False)
+        self.of_controller_nets_with_same_vlan = config.get(
+            "of_controller_nets_with_same_vlan", False
+        )
 
     def check_credentials(self):
         try:
 
     def check_credentials(self):
         try:
@@ -182,16 +202,23 @@ class SdnConnectorOpenFlow(SdnConnectorBase):
     def create_connectivity_service(self, service_type, connection_points, **kwargs):
         net_id = str(uuid4())
         ports = []
     def create_connectivity_service(self, service_type, connection_points, **kwargs):
         net_id = str(uuid4())
         ports = []
+
         for cp in connection_points:
             port = {
                 "uuid": cp["service_endpoint_id"],
                 "vlan": cp.get("service_endpoint_encapsulation_info", {}).get("vlan"),
                 "mac": cp.get("service_endpoint_encapsulation_info", {}).get("mac"),
         for cp in connection_points:
             port = {
                 "uuid": cp["service_endpoint_id"],
                 "vlan": cp.get("service_endpoint_encapsulation_info", {}).get("vlan"),
                 "mac": cp.get("service_endpoint_encapsulation_info", {}).get("mac"),
-                "switch_port": cp.get("service_endpoint_encapsulation_info", {}).get("switch_port"),
+                "switch_port": cp.get("service_endpoint_encapsulation_info", {}).get(
+                    "switch_port"
+                ),
             }
             ports.append(port)
             }
             ports.append(port)
+
         try:
         try:
-            created_items = self._set_openflow_rules(service_type, net_id, ports, created_items=None)
+            created_items = self._set_openflow_rules(
+                service_type, net_id, ports, created_items=None
+            )
+
             return net_id, created_items
         except (SdnConnectorError, OpenflowConnException) as e:
             raise SdnConnectorError(e, http_code=e.http_code)
             return net_id, created_items
         except (SdnConnectorError, OpenflowConnException) as e:
             raise SdnConnectorError(e, http_code=e.http_code)
@@ -200,24 +227,36 @@ class SdnConnectorOpenFlow(SdnConnectorBase):
         try:
             service_type = "ELAN"
             ports = []
         try:
             service_type = "ELAN"
             ports = []
-            self._set_openflow_rules(service_type, service_uuid, ports, created_items=conn_info)
+            self._set_openflow_rules(
+                service_type, service_uuid, ports, created_items=conn_info
+            )
+
             return None
         except (SdnConnectorError, OpenflowConnException) as e:
             raise SdnConnectorError(e, http_code=e.http_code)
 
             return None
         except (SdnConnectorError, OpenflowConnException) as e:
             raise SdnConnectorError(e, http_code=e.http_code)
 
-    def edit_connectivity_service(self, service_uuid, conn_info=None, connection_points=None, **kwargs):
+    def edit_connectivity_service(
+        self, service_uuid, conn_info=None, connection_points=None, **kwargs
+    ):
         ports = []
         for cp in connection_points:
             port = {
                 "uuid": cp["service_endpoint_id"],
                 "vlan": cp.get("service_endpoint_encapsulation_info", {}).get("vlan"),
                 "mac": cp.get("service_endpoint_encapsulation_info", {}).get("mac"),
         ports = []
         for cp in connection_points:
             port = {
                 "uuid": cp["service_endpoint_id"],
                 "vlan": cp.get("service_endpoint_encapsulation_info", {}).get("vlan"),
                 "mac": cp.get("service_endpoint_encapsulation_info", {}).get("mac"),
-                "switch_port": cp.get("service_endpoint_encapsulation_info", {}).get("switch_port"),
+                "switch_port": cp.get("service_endpoint_encapsulation_info", {}).get(
+                    "switch_port"
+                ),
             }
             ports.append(port)
             }
             ports.append(port)
+
         service_type = "ELAN"  # TODO. Store at conn_info for later use
         service_type = "ELAN"  # TODO. Store at conn_info for later use
+
         try:
         try:
-            created_items = self._set_openflow_rules(service_type, service_uuid, ports, created_items=conn_info)
+            created_items = self._set_openflow_rules(
+                service_type, service_uuid, ports, created_items=conn_info
+            )
+
             return created_items
         except (SdnConnectorError, OpenflowConnException) as e:
             raise SdnConnectorError(e, http_code=e.http_code)
             return created_items
         except (SdnConnectorError, OpenflowConnException) as e:
             raise SdnConnectorError(e, http_code=e.http_code)
@@ -234,8 +273,13 @@ class SdnConnectorOpenFlow(SdnConnectorBase):
 
     def _set_openflow_rules(self, net_type, net_id, ports, created_items=None):
         ifaces_nb = len(ports)
 
     def _set_openflow_rules(self, net_type, net_id, ports, created_items=None):
         ifaces_nb = len(ports)
+
         if not created_items:
         if not created_items:
-            created_items = {"status": None, "error_msg": None, "installed_rules_ids": []}
+            created_items = {
+                "status": None,
+                "error_msg": None,
+                "installed_rules_ids": [],
+            }
         rules_to_delete = created_items.get("installed_rules_ids") or []
         new_installed_rules_ids = []
         error_list = []
         rules_to_delete = created_items.get("installed_rules_ids") or []
         new_installed_rules_ids = []
         error_list = []
@@ -244,22 +288,31 @@ class SdnConnectorOpenFlow(SdnConnectorBase):
             step = "Checking ports and network type compatibility"
             if ifaces_nb < 2:
                 pass
             step = "Checking ports and network type compatibility"
             if ifaces_nb < 2:
                 pass
-            elif net_type == 'ELINE':
+            elif net_type == "ELINE":
                 if ifaces_nb > 2:
                 if ifaces_nb > 2:
-                    raise SdnConnectorError("'ELINE' type network cannot connect {} interfaces, only 2".format(
-                        ifaces_nb))
-            elif net_type == 'ELAN':
+                    raise SdnConnectorError(
+                        "'ELINE' type network cannot connect {} interfaces, only 2".format(
+                            ifaces_nb
+                        )
+                    )
+            elif net_type == "ELAN":
                 if ifaces_nb > 2 and self.of_controller_nets_with_same_vlan:
                     # check all ports are VLAN (tagged) or none
                     vlan_tags = []
                 if ifaces_nb > 2 and self.of_controller_nets_with_same_vlan:
                     # check all ports are VLAN (tagged) or none
                     vlan_tags = []
+
                     for port in ports:
                         if port["vlan"] not in vlan_tags:
                             vlan_tags.append(port["vlan"])
                     for port in ports:
                         if port["vlan"] not in vlan_tags:
                             vlan_tags.append(port["vlan"])
+
                     if len(vlan_tags) > 1:
                     if len(vlan_tags) > 1:
-                        raise SdnConnectorError("This pluging cannot connect ports with diferent VLAN tags when flag "
-                                                "'of_controller_nets_with_same_vlan' is active")
+                        raise SdnConnectorError(
+                            "This pluging cannot connect ports with diferent VLAN tags when flag "
+                            "'of_controller_nets_with_same_vlan' is active"
+                        )
             else:
             else:
-                raise SdnConnectorError('Only ELINE or ELAN network types are supported for openflow')
+                raise SdnConnectorError(
+                    "Only ELINE or ELAN network types are supported for openflow"
+                )
 
             # Get the existing flows at openflow controller
             step = "Getting installed openflow rules"
 
             # Get the existing flows at openflow controller
             step = "Getting installed openflow rules"
@@ -274,16 +327,20 @@ class SdnConnectorOpenFlow(SdnConnectorBase):
             for flow in new_flows:
                 # 1 check if an equal flow is already present
                 index = self._check_flow_already_present(flow, existing_flows)
             for flow in new_flows:
                 # 1 check if an equal flow is already present
                 index = self._check_flow_already_present(flow, existing_flows)
+
                 if index >= 0:
                     flow_id = existing_flows[index]["name"]
                     self.logger.debug("Skipping already present flow %s", str(flow))
                 else:
                     # 2 look for a non used name
                     flow_name = flow["net_id"] + "." + str(name_index)
                 if index >= 0:
                     flow_id = existing_flows[index]["name"]
                     self.logger.debug("Skipping already present flow %s", str(flow))
                 else:
                     # 2 look for a non used name
                     flow_name = flow["net_id"] + "." + str(name_index)
+
                     while flow_name in existing_flows_ids:
                         name_index += 1
                         flow_name = flow["net_id"] + "." + str(name_index)
                     while flow_name in existing_flows_ids:
                         name_index += 1
                         flow_name = flow["net_id"] + "." + str(name_index)
-                    flow['name'] = flow_name
+
+                    flow["name"] = flow_name
+
                     # 3 insert at openflow
                     try:
                         self.of_connector.new_flow(flow)
                     # 3 insert at openflow
                     try:
                         self.of_connector.new_flow(flow)
@@ -291,8 +348,11 @@ class SdnConnectorOpenFlow(SdnConnectorBase):
                         existing_flows_ids.append(flow_id)
                     except OpenflowConnException as e:
                         flow_id = None
                         existing_flows_ids.append(flow_id)
                     except OpenflowConnException as e:
                         flow_id = None
-                        error_list.append("Cannot create rule for ingress_port={}, dst_mac={}: {}"
-                                          .format(flow["ingress_port"], flow["dst_mac"], e))
+                        error_list.append(
+                            "Cannot create rule for ingress_port={}, dst_mac={}: {}".format(
+                                flow["ingress_port"], flow["dst_mac"], e
+                            )
+                        )
 
                 # 4 insert at database
                 if flow_id:
 
                 # 4 insert at database
                 if flow_id:
@@ -311,13 +371,16 @@ class SdnConnectorOpenFlow(SdnConnectorBase):
                     error_text = "Cannot remove rule '{}': {}".format(flow_id, e)
                     error_list.append(error_text)
                     self.logger.error(error_text)
                     error_text = "Cannot remove rule '{}': {}".format(flow_id, e)
                     error_list.append(error_text)
                     self.logger.error(error_text)
+
             created_items["installed_rules_ids"] = new_installed_rules_ids
             created_items["installed_rules_ids"] = new_installed_rules_ids
+
             if error_list:
                 created_items["error_msg"] = ";".join(error_list)[:1000]
                 created_items["error_msg"] = "ERROR"
             else:
                 created_items["error_msg"] = None
                 created_items["status"] = "ACTIVE"
             if error_list:
                 created_items["error_msg"] = ";".join(error_list)[:1000]
                 created_items["error_msg"] = "ERROR"
             else:
                 created_items["error_msg"] = None
                 created_items["status"] = "ACTIVE"
+
             return created_items
         except (SdnConnectorError, OpenflowConnException) as e:
             raise SdnConnectorError("Error while {}: {}".format(step, e)) from e
             return created_items
         except (SdnConnectorError, OpenflowConnException) as e:
             raise SdnConnectorError("Error while {}: {}".format(step, e)) from e
@@ -334,54 +397,69 @@ class SdnConnectorOpenFlow(SdnConnectorBase):
         # Check switch_port information is right
         for port in ports:
             nb_ports += 1
         # Check switch_port information is right
         for port in ports:
             nb_ports += 1
-            if str(port['switch_port']) not in self.of_connector.pp2ofi:
-                raise SdnConnectorError("switch port name '{}' is not valid for the openflow controller".
-                                        format(port['switch_port']))
+
+            if str(port["switch_port"]) not in self.of_connector.pp2ofi:
+                raise SdnConnectorError(
+                    "switch port name '{}' is not valid for the openflow controller".format(
+                        port["switch_port"]
+                    )
+                )
+
         priority = 1000  # 1100
 
         for src_port in ports:
             # if src_port.get("groups")
         priority = 1000  # 1100
 
         for src_port in ports:
             # if src_port.get("groups")
-            vlan_in = src_port['vlan']
+            vlan_in = src_port["vlan"]
 
             # BROADCAST:
 
             # BROADCAST:
-            broadcast_key = src_port['uuid'] + "." + str(vlan_in)
+            broadcast_key = src_port["uuid"] + "." + str(vlan_in)
             if broadcast_key in new_broadcast_flows:
                 flow_broadcast = new_broadcast_flows[broadcast_key]
             else:
             if broadcast_key in new_broadcast_flows:
                 flow_broadcast = new_broadcast_flows[broadcast_key]
             else:
-                flow_broadcast = {'priority': priority,
-                                  'net_id': net_id,
-                                  'dst_mac': 'ff:ff:ff:ff:ff:ff',
-                                  "ingress_port": str(src_port['switch_port']),
-                                  'vlan_id': vlan_in,
-                                  'actions': []
-                                  }
+                flow_broadcast = {
+                    "priority": priority,
+                    "net_id": net_id,
+                    "dst_mac": "ff:ff:ff:ff:ff:ff",
+                    "ingress_port": str(src_port["switch_port"]),
+                    "vlan_id": vlan_in,
+                    "actions": [],
+                }
                 new_broadcast_flows[broadcast_key] = flow_broadcast
                 new_broadcast_flows[broadcast_key] = flow_broadcast
+
                 if vlan_in is not None:
                 if vlan_in is not None:
-                    flow_broadcast['vlan_id'] = str(vlan_in)
+                    flow_broadcast["vlan_id"] = str(vlan_in)
 
             for dst_port in ports:
 
             for dst_port in ports:
-                vlan_out = dst_port['vlan']
-                if src_port['switch_port'] == dst_port['switch_port'] and vlan_in == vlan_out:
+                vlan_out = dst_port["vlan"]
+
+                if (
+                    src_port["switch_port"] == dst_port["switch_port"]
+                    and vlan_in == vlan_out
+                ):
                     continue
                     continue
+
                 flow = {
                     "priority": priority,
                 flow = {
                     "priority": priority,
-                    'net_id': net_id,
-                    "ingress_port": str(src_port['switch_port']),
-                    'vlan_id': vlan_in,
-                    'actions': []
+                    "net_id": net_id,
+                    "ingress_port": str(src_port["switch_port"]),
+                    "vlan_id": vlan_in,
+                    "actions": [],
                 }
                 }
+
                 # allow that one port have no mac
                 # allow that one port have no mac
-                if dst_port['mac'] is None or nb_ports == 2:  # point to point or nets with 2 elements
-                    flow['priority'] = priority - 5  # less priority
+                # point to point or nets with 2 elements
+                if dst_port["mac"] is None or nb_ports == 2:
+                    flow["priority"] = priority - 5  # less priority
                 else:
                 else:
-                    flow['dst_mac'] = str(dst_port['mac'])
+                    flow["dst_mac"] = str(dst_port["mac"])
 
                 if vlan_out is None:
                     if vlan_in:
 
                 if vlan_out is None:
                     if vlan_in:
-                        flow['actions'].append(('vlan', None))
+                        flow["actions"].append(("vlan", None))
                 else:
                 else:
-                    flow['actions'].append(('vlan', vlan_out))
-                flow['actions'].append(('out', str(dst_port['switch_port'])))
+                    flow["actions"].append(("vlan", vlan_out))
+
+                flow["actions"].append(("out", str(dst_port["switch_port"])))
 
                 if self._check_flow_already_present(flow, new_flows) >= 0:
                     self.logger.debug("Skipping repeated flow '%s'", str(flow))
 
                 if self._check_flow_already_present(flow, new_flows) >= 0:
                     self.logger.debug("Skipping repeated flow '%s'", str(flow))
@@ -390,33 +468,45 @@ class SdnConnectorOpenFlow(SdnConnectorBase):
                 new_flows.append(flow)
 
                 # BROADCAST:
                 new_flows.append(flow)
 
                 # BROADCAST:
-                if nb_ports <= 2:  # point to multipoint or nets with more than 2 elements
+                # point to multipoint or nets with more than 2 elements
+                if nb_ports <= 2:
                     continue
                     continue
-                out = (vlan_out, str(dst_port['switch_port']))
-                if out not in flow_broadcast['actions']:
-                    flow_broadcast['actions'].append(out)
+
+                out = (vlan_out, str(dst_port["switch_port"]))
+
+                if out not in flow_broadcast["actions"]:
+                    flow_broadcast["actions"].append(out)
 
         # BROADCAST
         for flow_broadcast in new_broadcast_flows.values():
 
         # BROADCAST
         for flow_broadcast in new_broadcast_flows.values():
-            if len(flow_broadcast['actions']) == 0:
+            if len(flow_broadcast["actions"]) == 0:
                 continue  # nothing to do, skip
                 continue  # nothing to do, skip
-            flow_broadcast['actions'].sort()
-            if 'vlan_id' in flow_broadcast:
-                previous_vlan = 0  # indicates that a packet contains a vlan, and the vlan
+
+            flow_broadcast["actions"].sort()
+
+            if "vlan_id" in flow_broadcast:
+                # indicates that a packet contains a vlan, and the vlan
+                previous_vlan = 0
             else:
                 previous_vlan = None
             else:
                 previous_vlan = None
+
             final_actions = []
             action_number = 0
             final_actions = []
             action_number = 0
-            for action in flow_broadcast['actions']:
+
+            for action in flow_broadcast["actions"]:
                 if action[0] != previous_vlan:
                 if action[0] != previous_vlan:
-                    final_actions.append(('vlan', action[0]))
+                    final_actions.append(("vlan", action[0]))
                     previous_vlan = action[0]
                     previous_vlan = action[0]
+
                     if self.of_controller_nets_with_same_vlan and action_number:
                     if self.of_controller_nets_with_same_vlan and action_number:
-                        raise SdnConnectorError("Cannot interconnect different vlan tags in a network when flag "
-                                                "'of_controller_nets_with_same_vlan' is True.")
+                        raise SdnConnectorError(
+                            "Cannot interconnect different vlan tags in a network when flag "
+                            "'of_controller_nets_with_same_vlan' is True."
+                        )
+
                     action_number += 1
                     action_number += 1
-                final_actions.append(('out', action[1]))
-            flow_broadcast['actions'] = final_actions
+                final_actions.append(("out", action[1]))
+            flow_broadcast["actions"] = final_actions
 
             if self._check_flow_already_present(flow_broadcast, new_flows) >= 0:
                 self.logger.debug("Skipping repeated flow '%s'", str(flow_broadcast))
 
             if self._check_flow_already_present(flow_broadcast, new_flows) >= 0:
                 self.logger.debug("Skipping repeated flow '%s'", str(flow_broadcast))
@@ -427,39 +517,51 @@ class SdnConnectorOpenFlow(SdnConnectorBase):
         # UNIFY openflow rules with the same input port and vlan and the same output actions
         # These flows differ at the dst_mac; and they are unified by not filtering by dst_mac
         # this can happen if there is only two ports. It is converted to a point to point connection
         # UNIFY openflow rules with the same input port and vlan and the same output actions
         # These flows differ at the dst_mac; and they are unified by not filtering by dst_mac
         # this can happen if there is only two ports. It is converted to a point to point connection
-        flow_dict = {}  # use as key vlan_id+ingress_port and as value the list of flows matching these values
+        # use as key vlan_id+ingress_port and as value the list of flows matching these values
+        flow_dict = {}
         for flow in new_flows:
             key = str(flow.get("vlan_id")) + ":" + flow["ingress_port"]
         for flow in new_flows:
             key = str(flow.get("vlan_id")) + ":" + flow["ingress_port"]
+
             if key in flow_dict:
                 flow_dict[key].append(flow)
             else:
                 flow_dict[key] = [flow]
             if key in flow_dict:
                 flow_dict[key].append(flow)
             else:
                 flow_dict[key] = [flow]
+
         new_flows2 = []
         new_flows2 = []
+
         for flow_list in flow_dict.values():
             convert2ptp = False
         for flow_list in flow_dict.values():
             convert2ptp = False
+
             if len(flow_list) >= 2:
                 convert2ptp = True
             if len(flow_list) >= 2:
                 convert2ptp = True
+
                 for f in flow_list:
                 for f in flow_list:
-                    if f['actions'] != flow_list[0]['actions']:
+                    if f["actions"] != flow_list[0]["actions"]:
                         convert2ptp = False
                         break
                         convert2ptp = False
                         break
+
             if convert2ptp:  # add only one unified rule without dst_mac
             if convert2ptp:  # add only one unified rule without dst_mac
-                self.logger.debug("Convert flow rules to NON mac dst_address " + str(flow_list))
-                flow_list[0].pop('dst_mac')
+                self.logger.debug(
+                    "Convert flow rules to NON mac dst_address " + str(flow_list)
+                )
+                flow_list[0].pop("dst_mac")
                 flow_list[0]["priority"] -= 5
                 new_flows2.append(flow_list[0])
             else:  # add all the rules
                 new_flows2 += flow_list
                 flow_list[0]["priority"] -= 5
                 new_flows2.append(flow_list[0])
             else:  # add all the rules
                 new_flows2 += flow_list
+
         return new_flows2
 
     def _check_flow_already_present(self, new_flow, flow_list):
         return new_flows2
 
     def _check_flow_already_present(self, new_flow, flow_list):
-        '''check if the same flow is already present in the flow list
+        """check if the same flow is already present in the flow list
         The flow is repeated if all the fields, apart from name, are equal
         The flow is repeated if all the fields, apart from name, are equal
-        Return the index of matching flow, -1 if not match'''
+        Return the index of matching flow, -1 if not match
+        """
         for index, flow in enumerate(flow_list):
             for f in self.flow_fields:
                 if flow.get(f) != new_flow.get(f):
                     break
             else:
                 return index
         for index, flow in enumerate(flow_list):
             for f in self.flow_fields:
                 if flow.get(f) != new_flow.get(f):
                     break
             else:
                 return index
+
         return -1
         return -1