Пример #1
0
    def clear_all_flows(self):
        """
        Delete all existing rules
        :return: None if ok
                 Raise an openflowconnUnexpectedResponse exception if fails with text_error
        """

        try:
            # autodiscover version
            if self.version == None:
                sw_list = self.get_of_switches()
                if len(sw_list) == 0:  # empty
                    return None

            url = self.url + "/wm/%s/clear/%s/json" % (
                self.ver_names["URLmodifier"], self.dpid)
            of_response = requests.get(url)
            error_text = "Openflow response %d: %s" % (of_response.status_code,
                                                       of_response.text)
            if of_response.status_code < 200 or of_response.status_code >= 300:
                self.logger.warning("clear_all_flows " + error_text)
                raise openflow_conn.OpenflowconnUnexpectedResponse(error_text)
            self.logger.debug("clear_all_flows OK " + error_text)
            return None
        except requests.exceptions.RequestException as e:
            error_text = type(e).__name__ + ": " + str(e)
            self.logger.error("clear_all_flows " + error_text)
            raise openflow_conn.OpenflowconnConnectionException(error_text)
        except Exception as e:
            # ValueError in the case that JSON can not be decoded
            error_text = type(e).__name__ + ": " + str(e)
            self.logger.error("clear_all_flows " + error_text)
            raise openflow_conn.OpenflowconnUnexpectedResponse(error_text)
Пример #2
0
    def obtain_port_correspondence(self):
        """
        Obtain the correspondence between physical and openflow port names
        :return: dictionary with physical name as key, openflow name as value
                 Raise a openflowconnUnexpectedResponse expection in case of failure
        """
        try:
            self.headers['content-type'] = 'text/plain'
            of_response = requests.get(self.url + "devices/" + self.id +
                                       "/ports",
                                       headers=self.headers)
            error_text = "Openflow response %d: %s" % (of_response.status_code,
                                                       of_response.text)
            if of_response.status_code != 200:
                self.logger.warning("obtain_port_correspondence " + error_text)
                raise openflow_conn.OpenflowconnUnexpectedResponse(error_text)

            self.logger.debug("obtain_port_correspondence " + error_text)
            info = of_response.json()

            node_connector_list = info.get('ports')
            if type(node_connector_list) is not list:
                self.logger.error(
                    "obtain_port_correspondence. Unexpected response at 'ports', not found or not a list: %s",
                    str(node_connector_list))
                raise openflow_conn.OpenflowconnUnexpectedResponse(
                    "Unexpected response at 'ports', not found  or not "
                    "a list. Wrong version?")

            for node_connector in node_connector_list:
                if node_connector['port'] != "local":
                    self.pp2ofi[str(
                        node_connector['annotations']['portName'])] = str(
                            node_connector['port'])
                    self.ofi2pp[str(node_connector['port'])] = str(
                        node_connector['annotations']['portName'])

            node_ip_address = info['annotations']['managementAddress']
            if node_ip_address is None:
                self.logger.error(
                    "obtain_port_correspondence. Unexpected response at 'managementAddress', not found: %s",
                    str(self.id))
                raise openflow_conn.OpenflowconnUnexpectedResponse(
                    "Unexpected response at 'managementAddress', "
                    "not found. Wrong version?")
            self.ip_address = node_ip_address

            # print self.name, ": obtain_port_correspondence ports:", self.pp2ofi
            return self.pp2ofi
        except requests.exceptions.RequestException as e:
            error_text = type(e).__name__ + ": " + str(e)
            self.logger.error("obtain_port_correspondence " + error_text)
            raise openflow_conn.OpenflowconnConnectionException(error_text)
        except ValueError as e:
            # ValueError in the case that JSON can not be decoded
            error_text = type(e).__name__ + ": " + str(e)
            self.logger.error("obtain_port_correspondence " + error_text)
            raise openflow_conn.OpenflowconnUnexpectedResponse(error_text)
Пример #3
0
    def get_of_switches(self):
        """
        Obtain a a list of switches or DPID detected by this controller
        :return: list where each element a tuple pair (DPID, IP address)
                      Raise an OpenflowconnConnectionException or OpenflowconnConnectionException exception if same
                      parameter is missing or wrong
        """
        try:
            of_response = requests.get(self.url +
                                       "/wm/core/controller/switches/json",
                                       headers=self.headers)
            error_text = "Openflow response %d: %s" % (of_response.status_code,
                                                       of_response.text)
            if of_response.status_code != 200:
                self.logger.warning("get_of_switches " + error_text)
                raise openflow_conn.OpenflowconnUnexpectedResponse(error_text)
            self.logger.debug("get_of_switches " + error_text)
            info = of_response.json()
            if type(info) != list and type(info) != tuple:
                self.logger.error(
                    "get_of_switches. Unexpected response not a list %s",
                    str(type(info)))
                raise openflow_conn.OpenflowconnUnexpectedResponse(
                    "Unexpected response, not a list. Wrong version?")
            if len(info) == 0:
                return info
            # autodiscover version
            if self.version == None:
                if 'dpid' in info[0] and 'inetAddress' in info[0]:
                    self._set_version("0.9")
                # elif 'switchDPID' in info[0] and 'inetAddress' in info[0]:
                #     self._set_version("1.X")
                else:
                    self.logger.error(
                        "get_of_switches. Unexpected response, not found 'dpid' or 'switchDPID' field: %s",
                        str(info[0]))
                    raise openflow_conn.OpenflowconnUnexpectedResponse(
                        "Unexpected response, not found 'dpid' or "
                        "'switchDPID' field. Wrong version?")

            switch_list = []
            for switch in info:
                switch_list.append(
                    (switch[self.ver_names["dpid"]], switch['inetAddress']))
            return switch_list
        except requests.exceptions.RequestException as e:
            error_text = type(e).__name__ + ": " + str(e)
            self.logger.error("get_of_switches " + error_text)
            raise openflow_conn.OpenflowconnConnectionException(error_text)
        except Exception as e:
            # ValueError in the case that JSON can not be decoded
            error_text = type(e).__name__ + ": " + str(e)
            self.logger.error("get_of_switches " + error_text)
            raise openflow_conn.OpenflowconnUnexpectedResponse(error_text)
    def del_flow(self, flow_name):
        """
        Delete an existing rule
        :param flow_name: this is the rule name
        :return: None if ok
                 Raise an openflowconnUnexpectedResponse exception if fails with text_error
        """
        try:

            # Raise an openflowconnUnexpectedResponse exception if fails with text_error
            # autodiscover version

            if self.version == None:
                self.get_of_switches()

            of_response = requests.delete(self.url + "/wm/%s/json" % self.ver_names["URLmodifier"],
                                          headers=self.headers,
                                          data='{"switch":"%s","name":"%s"}' % (self.dpid, flow_name)
                                          )
            error_text = "Openflow response %d: %s" % (of_response.status_code, of_response.text)
            if of_response.status_code != 200:
                self.logger.warning("del_flow " + error_text)
                raise openflow_conn.OpenflowconnUnexpectedResponse(error_text)
            self.logger.debug("del_flow OK " + error_text)
            return None

        except requests.exceptions.RequestException as e:
            error_text = type(e).__name__ + ": " + str(e)
            self.logger.error("del_flow " + error_text)
            raise openflow_conn.OpenflowconnConnectionException(error_text)
Пример #5
0
    def del_flow(self, flow_name):
        """
        Delete an existing rule
        :param flow_name:
        :return: Raise a openflowconnUnexpectedResponse expection in case of failure
        """

        try:
            self.headers['content-type'] = None
            of_response = requests.delete(self.url + "flows/" + self.id + "/" +
                                          flow_name,
                                          headers=self.headers)
            error_text = "Openflow response %d: %s" % (of_response.status_code,
                                                       of_response.text)

            if of_response.status_code != 204:
                self.logger.warning("del_flow " + error_text)
                raise openflow_conn.OpenflowconnUnexpectedResponse(error_text)

            self.logger.debug("del_flow OK " + error_text)
            return None

        except requests.exceptions.RequestException as e:
            error_text = type(e).__name__ + ": " + str(e)
            self.logger.error("del_flow " + error_text)
            raise openflow_conn.OpenflowconnConnectionException(error_text)
Пример #6
0
    def del_flow(self, flow_name):
        """
        Delete an existing rule
        :param flow_name: flow_name, this is the rule name
        :return: Raise a OpenflowconnConnectionException expection in case of failure
        """

        try:
            of_response = requests.delete(
                self.url +
                "/restconf/config/opendaylight-inventory:nodes/node/" +
                self.id + "/table/0/flow/" + flow_name,
                headers=self.headers)
            error_text = "Openflow response %d: %s" % (of_response.status_code,
                                                       of_response.text)
            if of_response.status_code != 200:
                self.logger.warning("del_flow " + error_text)
                raise openflow_conn.OpenflowconnUnexpectedResponse(error_text)
            self.logger.debug("del_flow OK " + error_text)
            return None
        except requests.exceptions.RequestException as e:
            # raise an exception in case of contection error
            error_text = type(e).__name__ + ": " + str(e)
            self.logger.error("del_flow " + error_text)
            raise openflow_conn.OpenflowconnConnectionException(error_text)
Пример #7
0
 def clear_all_flows(self):
     """
     Delete all existing rules
     :return: Raise a OpenflowconnConnectionException expection in case of failure
     """
     try:
         of_response = requests.delete(
             self.url +
             "/restconf/config/opendaylight-inventory:nodes/node/" +
             self.id + "/table/0",
             headers=self.headers)
         error_text = "Openflow response %d: %s" % (of_response.status_code,
                                                    of_response.text)
         if of_response.status_code != 200 and of_response.status_code != 404:  #HTTP_Not_Found
             self.logger.warning("clear_all_flows " + error_text)
             raise openflow_conn.OpenflowconnUnexpectedResponse(error_text)
         self.logger.debug("clear_all_flows OK " + error_text)
     except requests.exceptions.RequestException as e:
         error_text = type(e).__name__ + ": " + str(e)
         self.logger.error("clear_all_flows " + error_text)
         raise openflow_conn.OpenflowconnConnectionException(error_text)
Пример #8
0
    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)
                 Raise an OpenflowconnConnectionException exception if fails with text_error
        """
        try:
            of_response = requests.get(
                self.url +
                "/restconf/operational/opendaylight-inventory:nodes",
                headers=self.headers)
            error_text = "Openflow response %d: %s" % (of_response.status_code,
                                                       of_response.text)
            if of_response.status_code != 200:
                self.logger.warning("get_of_switches " + error_text)
                raise openflow_conn.OpenflowconnUnexpectedResponse(
                    "Error get_of_switches " + error_text)

            self.logger.debug("get_of_switches " + error_text)
            info = of_response.json()

            if type(info) != dict:
                self.logger.error(
                    "get_of_switches. Unexpected response, not a dict: %s",
                    str(info))
                raise openflow_conn.OpenflowconnUnexpectedResponse(
                    "Unexpected response, not a dict. Wrong version?")

            nodes = info.get('nodes')
            if type(nodes) is not dict:
                self.logger.error(
                    "get_of_switches. Unexpected response at 'nodes', not found or not a dict: %s",
                    str(type(info)))
                raise openflow_conn.OpenflowconnUnexpectedResponse(
                    "Unexpected response at 'nodes', not found or "
                    "not a dict. Wrong version?")

            node_list = nodes.get('node')
            if type(node_list) is not list:
                self.logger.error(
                    "get_of_switches. Unexpected response, at 'nodes':'node', "
                    "not found or not a list: %s", str(type(node_list)))
                raise openflow_conn.OpenflowconnUnexpectedResponse(
                    "Unexpected response, at 'nodes':'node', not found "
                    "or not a list. Wrong version?")

            switch_list = []
            for node in node_list:
                node_id = node.get('id')
                if node_id is None:
                    self.logger.error(
                        "get_of_switches. Unexpected response at 'nodes':'node'[]:'id', not found: %s",
                        str(node))
                    raise openflow_conn.OpenflowconnUnexpectedResponse(
                        "Unexpected response at 'nodes':'node'[]:'id', "
                        "not found . Wrong version?")

                if node_id == 'controller-config':
                    continue

                node_ip_address = node.get('flow-node-inventory:ip-address')
                if node_ip_address is None:
                    self.logger.error(
                        "get_of_switches. Unexpected response at 'nodes':'node'[]:'flow-node-inventory:"
                        "ip-address', not found: %s", str(node))
                    raise openflow_conn.OpenflowconnUnexpectedResponse(
                        "Unexpected response at 'nodes':'node'[]:"
                        "'flow-node-inventory:ip-address', "
                        "not found. Wrong version?")

                node_id_hex = hex(int(
                    node_id.split(':')[1])).split('x')[1].zfill(16)
                switch_list.append((':'.join(
                    a + b
                    for a, b in zip(node_id_hex[::2], node_id_hex[1::2])),
                                    node_ip_address))

            return len(switch_list), switch_list
        except requests.exceptions.RequestException as e:
            error_text = type(e).__name__ + ": " + str(e)
            self.logger.error("get_of_switches " + error_text)
            raise openflow_conn.OpenflowconnConnectionException(error_text)
        except ValueError as e:
            # ValueError in the case that JSON can not be decoded
            error_text = type(e).__name__ + ": " + str(e)
            self.logger.error("get_of_switches " + error_text)
            raise openflow_conn.OpenflowconnUnexpectedResponse(error_text)
Пример #9
0
    def new_flow(self, data):
        """
        Insert a new static rule
        :param data: dictionary with the following content:
                priority:     rule priority
                name:         rule name
                ingress_port: match input port of the rule
                dst_mac:      match destination mac address of the rule, missing or None if not apply
                vlan_id:      match vlan tag of the rule, missing or None if not apply
                actions:      list of actions, composed by a pair tuples with these posibilities:
                    ('vlan', None/int): for stripping/setting a vlan tag
                    ('out', port):      send to this port
        :return: Raise a OpenflowconnConnectionException expection in case of failure
        """

        try:

            if len(self.pp2ofi) == 0:
                self.obtain_port_correspondence()

            # We have to build the data for the opendaylight call from the generic data
            sdata = dict()
            sdata['flow-node-inventory:flow'] = list()
            sdata['flow-node-inventory:flow'].append(dict())
            flow = sdata['flow-node-inventory:flow'][0]
            flow['id'] = data['name']
            flow['flow-name'] = data['name']
            flow['idle-timeout'] = 0
            flow['hard-timeout'] = 0
            flow['table_id'] = 0
            flow['priority'] = data.get('priority')
            flow['match'] = dict()
            if not data['ingress_port'] in self.pp2ofi:
                error_text = 'Error. Port ' + data[
                    'ingress_port'] + ' is not present in the switch'
                self.logger.warning("new_flow " + error_text)
                raise openflow_conn.OpenflowconnUnexpectedResponse(error_text)
            flow['match']['in-port'] = self.pp2ofi[data['ingress_port']]
            if 'dst_mac' in data:
                flow['match']['ethernet-match'] = dict()
                flow['match']['ethernet-match']['ethernet-destination'] = dict(
                )
                flow['match']['ethernet-match']['ethernet-destination'][
                    'address'] = data['dst_mac']
            if data.get('vlan_id'):
                flow['match']['vlan-match'] = dict()
                flow['match']['vlan-match']['vlan-id'] = dict()
                flow['match']['vlan-match']['vlan-id'][
                    'vlan-id-present'] = True
                flow['match']['vlan-match']['vlan-id']['vlan-id'] = int(
                    data['vlan_id'])
            flow['instructions'] = dict()
            flow['instructions']['instruction'] = list()
            flow['instructions']['instruction'].append(dict())
            flow['instructions']['instruction'][0]['order'] = 1
            flow['instructions']['instruction'][0]['apply-actions'] = dict()
            flow['instructions']['instruction'][0]['apply-actions'][
                'action'] = list()
            actions = flow['instructions']['instruction'][0]['apply-actions'][
                'action']

            order = 0
            for action in data['actions']:
                new_action = {'order': order}
                if action[0] == "vlan":
                    if action[1] == None:
                        # strip vlan
                        new_action['strip-vlan-action'] = dict()
                    else:
                        new_action['set-field'] = dict()
                        new_action['set-field']['vlan-match'] = dict()
                        new_action['set-field']['vlan-match'][
                            'vlan-id'] = dict()
                        new_action['set-field']['vlan-match']['vlan-id'][
                            'vlan-id-present'] = True
                        new_action['set-field']['vlan-match']['vlan-id'][
                            'vlan-id'] = int(action[1])
                elif action[0] == 'out':
                    new_action['output-action'] = dict()
                    if not action[1] in self.pp2ofi:
                        error_msj = 'Port ' + action[
                            1] + ' is not present in the switch'
                        raise openflow_conn.OpenflowconnUnexpectedResponse(
                            error_msj)

                    new_action['output-action'][
                        'output-node-connector'] = self.pp2ofi[action[1]]
                else:
                    error_msj = "Unknown item '%s' in action list" % action[0]
                    self.logger.error("new_flow " + error_msj)
                    raise openflow_conn.OpenflowconnUnexpectedResponse(
                        error_msj)

                actions.append(new_action)
                order += 1

            # print json.dumps(sdata)
            of_response = requests.put(
                self.url +
                "/restconf/config/opendaylight-inventory:nodes/node/" +
                self.id + "/table/0/flow/" + data['name'],
                headers=self.headers,
                data=json.dumps(sdata))
            error_text = "Openflow response %d: %s" % (of_response.status_code,
                                                       of_response.text)
            if of_response.status_code != 200:
                self.logger.warning("new_flow " + error_text)
                raise openflow_conn.OpenflowconnUnexpectedResponse(error_text)
            self.logger.debug("new_flow OK " + error_text)
            return None

        except requests.exceptions.RequestException as e:
            # raise an exception in case of contection error
            error_text = type(e).__name__ + ": " + str(e)
            self.logger.error("new_flow " + error_text)
            raise openflow_conn.OpenflowconnConnectionException(error_text)
Пример #10
0
    def get_of_rules(self, translate_of_ports=True):
        """
        Obtain the rules inserted at openflow controller
        :param translate_of_ports:
        :return: dict if ok: with the rule name as key and value is another dictionary with the following content:
                    priority: rule priority
                    name:         rule name (present also as the master dict key)
                    ingress_port: match input port of the rule
                    dst_mac:      match destination mac address of the rule, can be missing or None if not apply
                    vlan_id:      match vlan tag of the rule, can be missing or None if not apply
                    actions:      list of actions, composed by a pair tuples:
                        (vlan, None/int): for stripping/setting a vlan tag
                        (out, port):      send to this port
                    switch:       DPID, all
                    Raise a OpenflowconnConnectionException expection in case of failure

        """

        try:
            # get rules
            if len(self.ofi2pp) == 0:
                self.obtain_port_correspondence()

            of_response = requests.get(
                self.url +
                "/restconf/config/opendaylight-inventory:nodes/node/" +
                self.id + "/table/0",
                headers=self.headers)
            error_text = "Openflow response %d: %s" % (of_response.status_code,
                                                       of_response.text)

            # The configured page does not exist if there are no rules installed. In that case we return an empty dict
            if of_response.status_code == 404:
                return {}

            elif of_response.status_code != 200:
                self.logger.warning("get_of_rules " + error_text)
                raise openflow_conn.OpenflowconnUnexpectedResponse(error_text)

            self.logger.debug("get_of_rules " + error_text)

            info = of_response.json()

            if type(info) != dict:
                self.logger.error(
                    "get_of_rules. Unexpected response not a dict: %s",
                    str(info))
                raise openflow_conn.OpenflowconnUnexpectedResponse(
                    "Unexpected openflow response, not a dict. "
                    "Wrong version?")

            table = info.get('flow-node-inventory:table')
            if type(table) is not list:
                self.logger.error(
                    "get_of_rules. Unexpected response at 'flow-node-inventory:table', "
                    "not a list: %s", str(type(table)))
                raise openflow_conn.OpenflowconnUnexpectedResponse(
                    "Unexpected response at 'flow-node-inventory:table',"
                    " not a list. Wrong version?")

            flow_list = table[0].get('flow')
            if flow_list is None:
                return {}

            if type(flow_list) is not list:
                self.logger.error(
                    "get_of_rules. Unexpected response at 'flow-node-inventory:table'[0]:'flow', not a list: %s",
                    str(type(flow_list)))
                raise openflow_conn.OpenflowconnUnexpectedResponse(
                    "Unexpected response at 'flow-node-inventory:"
                    "table'[0]:'flow', not a list. Wrong version?")

            # TODO translate ports according to translate_of_ports parameter

            rules = dict()
            for flow in flow_list:
                if not ('id' in flow and 'match' in flow and 'instructions'
                        in flow and 'instruction' in flow['instructions']
                        and 'apply-actions'
                        in flow['instructions']['instruction'][0]
                        and 'action' in flow['instructions']['instruction'][0]
                        ['apply-actions']):
                    raise openflow_conn.OpenflowconnUnexpectedResponse(
                        "unexpected openflow response, one or more "
                        "elements are missing. Wrong version?")

                flow['instructions']['instruction'][0]['apply-actions'][
                    'action']

                rule = dict()
                rule['switch'] = self.dpid
                rule['priority'] = flow.get('priority')
                # rule['name'] = flow['id']
                # rule['cookie'] = flow['cookie']
                if 'in-port' in flow['match']:
                    in_port = flow['match']['in-port']
                    if not in_port in self.ofi2pp:
                        raise openflow_conn.OpenflowconnUnexpectedResponse(
                            "Error: Ingress port " + in_port +
                            " is not in switch port list")

                    if translate_of_ports:
                        in_port = self.ofi2pp[in_port]

                    rule['ingress_port'] = in_port

                    if 'vlan-match' in flow['match'] and 'vlan-id' in flow['match']['vlan-match'] and \
                                'vlan-id' in flow['match']['vlan-match']['vlan-id'] and \
                                'vlan-id-present' in flow['match']['vlan-match']['vlan-id'] and \
                                flow['match']['vlan-match']['vlan-id']['vlan-id-present'] == True:
                        rule['vlan_id'] = flow['match']['vlan-match'][
                            'vlan-id']['vlan-id']

                    if 'ethernet-match' in flow['match'] and 'ethernet-destination' in flow['match']['ethernet-match'] and \
                        'address' in flow['match']['ethernet-match']['ethernet-destination']:
                        rule['dst_mac'] = flow['match']['ethernet-match'][
                            'ethernet-destination']['address']

                instructions = flow['instructions']['instruction'][0][
                    'apply-actions']['action']

                max_index = 0
                for instruction in instructions:
                    if instruction['order'] > max_index:
                        max_index = instruction['order']

                actions = [None] * (max_index + 1)
                for instruction in instructions:
                    if 'output-action' in instruction:
                        if not 'output-node-connector' in instruction[
                                'output-action']:
                            raise openflow_conn.OpenflowconnUnexpectedResponse(
                                "unexpected openflow response, one or "
                                "more elementa are missing. "
                                "Wrong version?")

                        out_port = instruction['output-action'][
                            'output-node-connector']
                        if not out_port in self.ofi2pp:
                            raise openflow_conn.OpenflowconnUnexpectedResponse(
                                "Error: Output port " + out_port +
                                " is not in switch port list")

                        if translate_of_ports:
                            out_port = self.ofi2pp[out_port]

                        actions[instruction['order']] = ('out', out_port)

                    elif 'strip-vlan-action' in instruction:
                        actions[instruction['order']] = ('vlan', None)

                    elif 'set-field' in instruction:
                        if not ('vlan-match' in instruction['set-field']
                                and 'vlan-id'
                                in instruction['set-field']['vlan-match']
                                and 'vlan-id' in instruction['set-field']
                                ['vlan-match']['vlan-id']):
                            raise openflow_conn.OpenflowconnUnexpectedResponse(
                                "unexpected openflow response, one or "
                                "more elements are missing. "
                                "Wrong version?")

                        actions[instruction['order']] = (
                            'vlan', instruction['set-field']['vlan-match']
                            ['vlan-id']['vlan-id'])

                actions = [x for x in actions if x != None]

                rule['actions'] = list(actions)
                rules[flow['id']] = dict(rule)

                #flow['id']
                #flow['priority']
                #flow['cookie']
                #flow['match']['in-port']
                #flow['match']['vlan-match']['vlan-id']['vlan-id']
                # match -> in-port
                #      -> vlan-match -> vlan-id -> vlan-id
                #flow['match']['vlan-match']['vlan-id']['vlan-id-present']
                #TODO we asume that is not using rules with vlan-id-present:false
                #instructions -> instruction -> apply-actions -> action
                #instructions=flow['instructions']['instruction'][0]['apply-actions']['action']
                #Es una lista. Posibles elementos:
                #max_index=0
                #for instruction in instructions:
                #  if instruction['order'] > max_index:
                #    max_index = instruction['order']
                #actions=[None]*(max_index+1)
                #for instruction in instructions:
                #   if 'output-action' in instruction:
                #     actions[instruction['order']] = ('out',instruction['output-action']['output-node-connector'])
                #   elif 'strip-vlan-action' in instruction:
                #     actions[instruction['order']] = ('vlan', None)
                #   elif 'set-field' in instruction:
                #     actions[instruction['order']] = ('vlan', instruction['set-field']['vlan-match']['vlan-id']['vlan-id'])
                #
                #actions = [x for x in actions if x != None]
                #                                                       -> output-action -> output-node-connector
                #                                                       -> pop-vlan-action
            return rules
        except requests.exceptions.RequestException as e:
            error_text = type(e).__name__ + ": " + str(e)
            self.logger.error("get_of_rules " + error_text)
            raise openflow_conn.OpenflowconnConnectionException(error_text)
        except ValueError as e:
            # ValueError in the case that JSON can not be decoded
            error_text = type(e).__name__ + ": " + str(e)
            self.logger.error("get_of_rules " + error_text)
            raise openflow_conn.OpenflowconnUnexpectedResponse(error_text)
Пример #11
0
    def get_of_switches(self):
        """
        Obtain a a list of switches or DPID detected by this controller
        :return: list where each element a tuple pair (DPID, IP address)
                 Raise a openflowconnUnexpectedResponse expection in case of failure
        """
        try:
            self.headers['content-type'] = 'text/plain'
            of_response = requests.get(self.url + "devices",
                                       headers=self.headers)
            error_text = "Openflow response %d: %s" % (of_response.status_code,
                                                       of_response.text)
            if of_response.status_code != 200:
                self.logger.warning("get_of_switches " + error_text)
                raise openflow_conn.OpenflowconnUnexpectedResponse(error_text)

            self.logger.debug("get_of_switches " + error_text)
            info = of_response.json()

            if type(info) != dict:
                self.logger.error(
                    "get_of_switches. Unexpected response, not a dict: %s",
                    str(info))
                raise openflow_conn.OpenflowconnUnexpectedResponse(
                    "Unexpected response, not a dict. Wrong version?")

            node_list = info.get('devices')

            if type(node_list) is not list:
                self.logger.error(
                    "get_of_switches. Unexpected response, at 'devices', not found or not a list: %s",
                    str(type(node_list)))
                raise openflow_conn.OpenflowconnUnexpectedResponse(
                    "Unexpected response, at 'devices', not found "
                    "or not a list. Wrong version?")

            switch_list = []
            for node in node_list:
                node_id = node.get('id')
                if node_id is None:
                    self.logger.error(
                        "get_of_switches. Unexpected response at 'device':'id', not found: %s",
                        str(node))
                    raise openflow_conn.OpenflowconnUnexpectedResponse(
                        "Unexpected response at 'device':'id', "
                        "not found . Wrong version?")

                node_ip_address = node.get('annotations').get(
                    'managementAddress')
                if node_ip_address is None:
                    self.logger.error(
                        "get_of_switches. Unexpected response at 'device':'managementAddress', not found: %s",
                        str(node))
                    raise openflow_conn.OpenflowconnUnexpectedResponse(
                        "Unexpected response at 'device':'managementAddress', not found. Wrong version?"
                    )

                node_id_hex = hex(int(
                    node_id.split(':')[1])).split('x')[1].zfill(16)

                switch_list.append((':'.join(
                    a + b
                    for a, b in zip(node_id_hex[::2], node_id_hex[1::2])),
                                    node_ip_address))
            raise switch_list

        except requests.exceptions.RequestException as e:
            error_text = type(e).__name__ + ": " + str(e)
            self.logger.error("get_of_switches " + error_text)
            raise openflow_conn.OpenflowconnConnectionException(error_text)
        except ValueError as e:
            # ValueError in the case that JSON can not be decoded
            error_text = type(e).__name__ + ": " + str(e)
            self.logger.error("get_of_switches " + error_text)
            raise openflow_conn.OpenflowconnUnexpectedResponse(error_text)
Пример #12
0
    def obtain_port_correspondence(self):
        """
        Obtain the correspondence between physical and openflow port names
        :return: dictionary: with physical name as key, openflow name as value,
                 Raise a OpenflowconnConnectionException expection in case of failure
        """
        try:
            of_response = requests.get(
                self.url +
                "/restconf/operational/opendaylight-inventory:nodes",
                headers=self.headers)
            error_text = "Openflow response %d: %s" % (of_response.status_code,
                                                       of_response.text)
            if of_response.status_code != 200:
                self.logger.warning("obtain_port_correspondence " + error_text)
                raise openflow_conn.OpenflowconnUnexpectedResponse(error_text)
            self.logger.debug("obtain_port_correspondence " + error_text)
            info = of_response.json()

            if type(info) != dict:
                self.logger.error(
                    "obtain_port_correspondence. Unexpected response not a dict: %s",
                    str(info))
                raise openflow_conn.OpenflowconnUnexpectedResponse(
                    "Unexpected openflow response, not a dict. "
                    "Wrong version?")

            nodes = info.get('nodes')
            if type(nodes) is not dict:
                self.logger.error(
                    "obtain_port_correspondence. Unexpected response at 'nodes', "
                    "not found or not a dict: %s", str(type(nodes)))
                raise openflow_conn.OpenflowconnUnexpectedResponse(
                    "Unexpected response at 'nodes',not found or not a dict. Wrong version?"
                )

            node_list = nodes.get('node')
            if type(node_list) is not list:
                self.logger.error(
                    "obtain_port_correspondence. Unexpected response, at 'nodes':'node', "
                    "not found or not a list: %s", str(type(node_list)))
                raise openflow_conn.OpenflowconnUnexpectedResponse(
                    "Unexpected response, at 'nodes':'node', "
                    "not found or not a list. Wrong version?")

            for node in node_list:
                node_id = node.get('id')
                if node_id is None:
                    self.logger.error(
                        "obtain_port_correspondence. Unexpected response at 'nodes':'node'[]:'id', "
                        "not found: %s", str(node))
                    raise openflow_conn.OpenflowconnUnexpectedResponse(
                        "Unexpected response at 'nodes':'node'[]:'id', "
                        "not found . Wrong version?")

                if node_id == 'controller-config':
                    continue

                # Figure out if this is the appropriate switch. The 'id' is 'openflow:' plus the decimal value
                # of the dpid
                #  In case this is not the desired switch, continue
                if self.id != node_id:
                    continue

                node_connector_list = node.get('node-connector')
                if type(node_connector_list) is not list:
                    self.logger.error(
                        "obtain_port_correspondence. Unexpected response at "
                        "'nodes':'node'[]:'node-connector', not found or not a list: %s",
                        str(node))
                    raise openflow_conn.OpenflowconnUnexpectedResponse(
                        "Unexpected response at 'nodes':'node'[]:"
                        "'node-connector', not found  or not a list. "
                        "Wrong version?")

                for node_connector in node_connector_list:
                    self.pp2ofi[str(
                        node_connector['flow-node-inventory:name'])] = str(
                            node_connector['id'])
                    self.ofi2pp[node_connector['id']] = str(
                        node_connector['flow-node-inventory:name'])

                node_ip_address = node.get('flow-node-inventory:ip-address')
                if node_ip_address is None:
                    self.logger.error(
                        "obtain_port_correspondence. Unexpected response at 'nodes':'node'[]:"
                        "'flow-node-inventory:ip-address', not found: %s",
                        str(node))
                    raise openflow_conn.OpenflowconnUnexpectedResponse(
                        "Unexpected response at 'nodes':'node'[]:"
                        "'flow-node-inventory:ip-address', not found. Wrong version?"
                    )
                self.ip_address = node_ip_address

                # If we found the appropriate dpid no need to continue in the for loop
                break

            # print self.name, ": obtain_port_correspondence ports:", self.pp2ofi
            return self.pp2ofi
        except requests.exceptions.RequestException as e:
            error_text = type(e).__name__ + ": " + str(e)
            self.logger.error("obtain_port_correspondence " + error_text)
            raise openflow_conn.OpenflowconnConnectionException(error_text)
        except ValueError as e:
            # ValueError in the case that JSON can not be decoded
            error_text = type(e).__name__ + ": " + str(e)
            self.logger.error("obtain_port_correspondence " + error_text)
            raise openflow_conn.OpenflowconnUnexpectedResponse(error_text)
Пример #13
0
    def new_flow(self, data):
        """
        Insert a new static rule
        :param data: dictionary with the following content:
                priority:     rule priority
                name:         rule name
                ingress_port: match input port of the rule
                dst_mac:      match destination mac address of the rule, missing or None if not apply
                vlan_id:      match vlan tag of the rule, missing or None if not apply
                actions:      list of actions, composed by a pair tuples with these posibilities:
                    ('vlan', None/int): for stripping/setting a vlan tag
                    ('out', port):      send to this port
        :return: Raise a openflowconnUnexpectedResponse expection in case of failure
        """
        try:

            if len(self.pp2ofi) == 0:
                self.obtain_port_correspondence()

            # Build the dictionary with the flow rule information for ONOS
            flow = dict()
            #flow['id'] = data['name']
            flow['tableId'] = 0
            flow['priority'] = data.get('priority')
            flow['timeout'] = 0
            flow['isPermanent'] = "true"
            flow['appId'] = 10  # FIXME We should create an appId for OSM
            flow['selector'] = dict()
            flow['selector']['criteria'] = list()

            # Flow rule matching criteria
            if not data['ingress_port'] in self.pp2ofi:
                error_text = 'Error. Port ' + data[
                    'ingress_port'] + ' is not present in the switch'
                self.logger.warning("new_flow " + error_text)
                raise openflow_conn.OpenflowconnUnexpectedResponse(error_text)

            ingress_port_criteria = dict()
            ingress_port_criteria['type'] = "IN_PORT"
            ingress_port_criteria['port'] = self.pp2ofi[data['ingress_port']]
            flow['selector']['criteria'].append(ingress_port_criteria)

            if 'dst_mac' in data:
                dst_mac_criteria = dict()
                dst_mac_criteria["type"] = "ETH_DST"
                dst_mac_criteria["mac"] = data['dst_mac']
                flow['selector']['criteria'].append(dst_mac_criteria)

            if data.get('vlan_id'):
                vlan_criteria = dict()
                vlan_criteria["type"] = "VLAN_VID"
                vlan_criteria["vlanId"] = int(data['vlan_id'])
                flow['selector']['criteria'].append(vlan_criteria)

            # Flow rule treatment
            flow['treatment'] = dict()
            flow['treatment']['instructions'] = list()
            flow['treatment']['deferred'] = list()

            for action in data['actions']:
                new_action = dict()
                if action[0] == "vlan":
                    new_action['type'] = "L2MODIFICATION"
                    if action[1] == None:
                        new_action['subtype'] = "VLAN_POP"
                    else:
                        new_action['subtype'] = "VLAN_ID"
                        new_action['vlanId'] = int(action[1])
                elif action[0] == 'out':
                    new_action['type'] = "OUTPUT"
                    if not action[1] in self.pp2ofi:
                        error_msj = 'Port ' + action[
                            1] + ' is not present in the switch'
                        raise openflow_conn.OpenflowconnUnexpectedResponse(
                            error_msj)
                    new_action['port'] = self.pp2ofi[action[1]]
                else:
                    error_msj = "Unknown item '%s' in action list" % action[0]
                    self.logger.error("new_flow " + error_msj)
                    raise openflow_conn.OpenflowconnUnexpectedResponse(
                        error_msj)

                flow['treatment']['instructions'].append(new_action)

            self.headers['content-type'] = 'application/json'
            path = self.url + "flows/" + self.id
            of_response = requests.post(path,
                                        headers=self.headers,
                                        data=json.dumps(flow))

            error_text = "Openflow response %d: %s" % (of_response.status_code,
                                                       of_response.text)
            if of_response.status_code != 201:
                self.logger.warning("new_flow " + error_text)
                raise openflow_conn.OpenflowconnUnexpectedResponse(error_text)

            flowId = of_response.headers['location'][path.__len__() + 1:]

            data['name'] = flowId

            self.logger.debug("new_flow OK " + error_text)
            return None

        except requests.exceptions.RequestException as e:
            error_text = type(e).__name__ + ": " + str(e)
            self.logger.error("new_flow " + error_text)
            raise openflow_conn.OpenflowconnConnectionException(error_text)
Пример #14
0
    def get_of_rules(self, translate_of_ports=True):
        """
        Obtain the rules inserted at openflow controller
        :param translate_of_ports: if True it translates ports from openflow index to physical switch name
        :return: dict if ok: with the rule name as key and value is another dictionary with the following content:
                    priority: rule priority
                    name:         rule name (present also as the master dict key)
                    ingress_port: match input port of the rule
                    dst_mac:      match destination mac address of the rule, can be missing or None if not apply
                    vlan_id:      match vlan tag of the rule, can be missing or None if not apply
                    actions:      list of actions, composed by a pair tuples:
                        (vlan, None/int): for stripping/setting a vlan tag
                        (out, port):      send to this port
                    switch:       DPID, all
                Raise an openflowconnUnexpectedResponse exception if fails with text_error
        """

        try:
            # get translation, autodiscover version
            if len(self.ofi2pp) == 0:
                self.obtain_port_correspondence()

            of_response = requests.get(self.url + "/wm/%s/list/%s/json" % (self.ver_names["URLmodifier"], self.dpid),
                                       headers=self.headers)
            error_text = "Openflow response %d: %s" % (of_response.status_code, of_response.text)
            if of_response.status_code != 200:
                self.logger.warning("get_of_rules " + error_text)
                raise openflow_conn.OpenflowconnUnexpectedResponse(error_text)
            self.logger.debug("get_of_rules " + error_text)
            info = of_response.json()
            if type(info) != dict:
                self.logger.error("get_of_rules. Unexpected response not a dict %s", str(type(info)))
                raise openflow_conn.OpenflowconnUnexpectedResponse("Unexpected response, not a dict. Wrong version?")
            rule_dict = {}
            for switch, switch_info in info.iteritems():
                if switch_info == None:
                    continue
                if str(switch) != self.dpid:
                    continue
                for name, details in switch_info.iteritems():
                    rule = {}
                    rule["switch"] = str(switch)
                    # rule["active"] = "true"
                    rule["priority"] = int(details["priority"])
                    if self.version[0] == "0":
                        if translate_of_ports:
                            rule["ingress_port"] = self.ofi2pp[details["match"]["inputPort"]]
                        else:
                            rule["ingress_port"] = str(details["match"]["inputPort"])
                        dst_mac = details["match"]["dataLayerDestination"]
                        if dst_mac != "00:00:00:00:00:00":
                            rule["dst_mac"] = dst_mac
                        vlan = details["match"]["dataLayerVirtualLan"]
                        if vlan != -1:
                            rule["vlan_id"] = vlan
                        actionlist = []
                        for action in details["actions"]:
                            if action["type"] == "OUTPUT":
                                if translate_of_ports:
                                    port = self.ofi2pp[action["port"]]
                                else:
                                    port = action["port"]
                                actionlist.append(("out", port))
                            elif action["type"] == "STRIP_VLAN":
                                actionlist.append(("vlan", None))
                            elif action["type"] == "SET_VLAN_ID":
                                actionlist.append(("vlan", action["virtualLanIdentifier"]))
                            else:
                                actionlist.append((action["type"], str(action)))
                                self.logger.warning("get_of_rules() Unknown action in rule %s: %s", rule["name"],
                                                    str(action))
                            rule["actions"] = actionlist
                    elif self.version[0] == "1":
                        if translate_of_ports:
                            rule["ingress_port"] = self.ofi2pp[details["match"]["in_port"]]
                        else:
                            rule["ingress_port"] = details["match"]["in_port"]
                        if "eth_dst" in details["match"]:
                            dst_mac = details["match"]["eth_dst"]
                            if dst_mac != "00:00:00:00:00:00":
                                rule["dst_mac"] = dst_mac
                        if "eth_vlan_vid" in details["match"]:
                            vlan = int(details["match"]["eth_vlan_vid"], 16) & 0xFFF
                            rule["vlan_id"] = str(vlan)
                        actionlist = []
                        for action in details["instructions"]["instruction_apply_actions"]:
                            if action == "output":
                                if translate_of_ports:
                                    port = self.ofi2pp[details["instructions"]["instruction_apply_actions"]["output"]]
                                else:
                                    port = details["instructions"]["instruction_apply_actions"]["output"]
                                actionlist.append(("out", port))
                            elif action == "strip_vlan":
                                actionlist.append(("vlan", None))
                            elif action == "set_vlan_vid":
                                actionlist.append(
                                    ("vlan", details["instructions"]["instruction_apply_actions"]["set_vlan_vid"]))
                            else:
                                self.logger.error("get_of_rules Unknown action in rule %s: %s", rule["name"],
                                                  str(action))
                                # actionlist.append( (action, str(details["instructions"]["instruction_apply_actions"]) ))
                    rule_dict[str(name)] = rule
            return rule_dict
        except requests.exceptions.RequestException as e:
            error_text = type(e).__name__ + ": " + str(e)
            self.logger.error("get_of_rules " + error_text)
            raise openflow_conn.OpenflowconnConnectionException(error_text)
        except ValueError as e:
            # ValueError in the case that JSON can not be decoded
            error_text = type(e).__name__ + ": " + str(e)
            self.logger.error("get_of_rules " + error_text)
            raise openflow_conn.OpenflowconnUnexpectedResponse(error_text)
Пример #15
0
    def get_of_rules(self, translate_of_ports=True):
        """
        Obtain the rules inserted at openflow controller
        :param translate_of_ports: if True it translates ports from openflow index to physical switch name
        :return: dict if ok: with the rule name as key and value is another dictionary with the following content:
                    priority: rule priority
                    name:         rule name (present also as the master dict key)
                    ingress_port: match input port of the rule
                    dst_mac:      match destination mac address of the rule, can be missing or None if not apply
                    vlan_id:      match vlan tag of the rule, can be missing or None if not apply
                    actions:      list of actions, composed by a pair tuples:
                        (vlan, None/int): for stripping/setting a vlan tag
                        (out, port):      send to this port
                    switch:       DPID, all
                 Raise a openflowconnUnexpectedResponse expection in case of failure
        """

        try:

            if len(self.ofi2pp) == 0:
                self.obtain_port_correspondence()

            # get rules
            self.headers['content-type'] = 'text/plain'
            of_response = requests.get(self.url + "flows/" + self.id,
                                       headers=self.headers)
            error_text = "Openflow response %d: %s" % (of_response.status_code,
                                                       of_response.text)

            # The configured page does not exist if there are no rules installed. In that case we return an empty dict
            if of_response.status_code == 404:
                return {}

            elif of_response.status_code != 200:
                self.logger.warning("get_of_rules " + error_text)
                raise openflow_conn.OpenflowconnUnexpectedResponse(error_text)
            self.logger.debug("get_of_rules " + error_text)

            info = of_response.json()

            if type(info) != dict:
                self.logger.error(
                    "get_of_rules. Unexpected response, not a dict: %s",
                    str(info))
                raise openflow_conn.OpenflowconnUnexpectedResponse(
                    "Unexpected openflow response, not a dict. "
                    "Wrong version?")

            flow_list = info.get('flows')

            if flow_list is None:
                return {}

            if type(flow_list) is not list:
                self.logger.error(
                    "get_of_rules. Unexpected response at 'flows', not a list: %s",
                    str(type(flow_list)))
                raise openflow_conn.OpenflowconnUnexpectedResponse(
                    "Unexpected response at 'flows', not a list. "
                    "Wrong version?")

            rules = dict()  # Response dictionary

            for flow in flow_list:
                if not ('id' in flow and 'selector' in flow and 'treatment' in flow and \
                                    'instructions' in flow['treatment'] and 'criteria' in \
                                    flow['selector']):
                    raise openflow_conn.OpenflowconnUnexpectedResponse(
                        "unexpected openflow response, one or more "
                        "elements are missing. Wrong version?")

                rule = dict()
                rule['switch'] = self.dpid
                rule['priority'] = flow.get('priority')
                rule['name'] = flow['id']

                for criteria in flow['selector']['criteria']:
                    if criteria['type'] == 'IN_PORT':
                        in_port = str(criteria['port'])
                        if in_port != "CONTROLLER":
                            if not in_port in self.ofi2pp:
                                raise openflow_conn.OpenflowconnUnexpectedResponse(
                                    "Error: Ingress port {} is not "
                                    "in switch port list".format(in_port))
                            if translate_of_ports:
                                in_port = self.ofi2pp[in_port]
                        rule['ingress_port'] = in_port

                    elif criteria['type'] == 'VLAN_VID':
                        rule['vlan_id'] = criteria['vlanId']

                    elif criteria['type'] == 'ETH_DST':
                        rule['dst_mac'] = str(criteria['mac']).lower()

                actions = []
                for instruction in flow['treatment']['instructions']:
                    if instruction['type'] == "OUTPUT":
                        out_port = str(instruction['port'])
                        if out_port != "CONTROLLER":
                            if not out_port in self.ofi2pp:
                                raise openflow_conn.OpenflowconnUnexpectedResponse(
                                    "Error: Output port {} is not in "
                                    "switch port list".format(out_port))

                            if translate_of_ports:
                                out_port = self.ofi2pp[out_port]

                        actions.append(('out', out_port))

                    if instruction['type'] == "L2MODIFICATION" and instruction[
                            'subtype'] == "VLAN_POP":
                        actions.append(('vlan', 'None'))
                    if instruction['type'] == "L2MODIFICATION" and instruction[
                            'subtype'] == "VLAN_ID":
                        actions.append(('vlan', instruction['vlanId']))

                rule['actions'] = actions
                rules[flow['id']] = dict(rule)
            return rules

        except requests.exceptions.RequestException as e:
            # ValueError in the case that JSON can not be decoded
            error_text = type(e).__name__ + ": " + str(e)
            self.logger.error("get_of_rules " + error_text)
            raise openflow_conn.OpenflowconnConnectionException(error_text)
        except ValueError as e:
            # ValueError in the case that JSON can not be decoded
            error_text = type(e).__name__ + ": " + str(e)
            self.logger.error("get_of_rules " + error_text)
            raise openflow_conn.OpenflowconnUnexpectedResponse(error_text)
Пример #16
0
    def obtain_port_correspondence(self):
        """
        Obtain the correspondence between physical and openflow port names
        :return: dictionary: with physical name as key, openflow name as value
                 Raise an openflowconnUnexpectedResponse exception if fails with text_error
        """
        try:
            of_response = requests.get(self.url + "/wm/core/controller/switches/json", headers=self.headers)
            # print vim_response.status_code
            error_text = "Openflow response %d: %s" % (of_response.status_code, of_response.text)
            if of_response.status_code != 200:
                self.logger.warning("obtain_port_correspondence " + error_text)
                raise openflow_conn.OpenflowconnUnexpectedResponse(error_text)
            self.logger.debug("obtain_port_correspondence " + error_text)
            info = of_response.json()

            if type(info) != list and type(info) != tuple:
                raise openflow_conn.OpenflowconnUnexpectedResponse("unexpected openflow response, not a list. "
                                                                   "Wrong version?")

            index = -1
            if len(info) > 0:
                # autodiscover version
                if self.version == None:
                    if 'dpid' in info[0] and 'ports' in info[0]:
                        self._set_version("0.9")
                    elif 'switchDPID' in info[0]:
                        self._set_version("1.X")
                    else:
                        raise openflow_conn.OpenflowconnUnexpectedResponse("unexpected openflow response, "
                                                                           "Wrong version?")

            for i in range(0, len(info)):
                if info[i][self.ver_names["dpid"]] == self.dpid:
                    index = i
                    break
            if index == -1:
                text = "DPID '" + self.dpid + "' not present in controller " + self.url
                # print self.name, ": get_of_controller_info ERROR", text
                raise openflow_conn.OpenflowconnUnexpectedResponse(text)
            else:
                if self.version[0] == "0":
                    ports = info[index]["ports"]
                else:  # version 1.X
                    of_response = requests.get(self.url + "/wm/core/switch/%s/port-desc/json" % self.dpid,
                                               headers=self.headers)
                    # print vim_response.status_code
                    error_text = "Openflow response %d: %s" % (of_response.status_code, of_response.text)
                    if of_response.status_code != 200:
                        self.logger.warning("obtain_port_correspondence " + error_text)
                        raise openflow_conn.OpenflowconnUnexpectedResponse(error_text)
                    self.logger.debug("obtain_port_correspondence " + error_text)
                    info = of_response.json()
                    if type(info) != dict:
                        raise openflow_conn.OpenflowconnUnexpectedResponse("unexpected openflow port-desc response, "
                                                                           "not a dict. Wrong version?")
                    if "portDesc" not in info:
                        raise openflow_conn.OpenflowconnUnexpectedResponse("unexpected openflow port-desc response, "
                                                                           "'portDesc' not found. Wrong version?")
                    if type(info["portDesc"]) != list and type(info["portDesc"]) != tuple:
                        raise openflow_conn.OpenflowconnUnexpectedResponse("unexpected openflow port-desc response at "
                                                                           "'portDesc', not a list. Wrong version?")
                    ports = info["portDesc"]
                for port in ports:
                    self.pp2ofi[str(port["name"])] = str(port["portNumber"])
                    self.ofi2pp[port["portNumber"]] = str(port["name"])
                    # print self.name, ": get_of_controller_info ports:", self.pp2ofi
            return self.pp2ofi
        except requests.exceptions.RequestException as e:
            error_text = type(e).__name__ + ": " + str(e)
            self.logger.error("obtain_port_correspondence " + error_text)
            raise openflow_conn.OpenflowconnConnectionException(error_text)
        except ValueError as e:
            # ValueError in the case that JSON can not be decoded
            error_text = type(e).__name__ + ": " + str(e)
            self.logger.error("obtain_port_correspondence " + error_text)
            raise openflow_conn.OpenflowconnUnexpectedResponse(error_text)
Пример #17
0
    def new_flow(self, data):
        """
        Insert a new static rule
        :param data: dictionary with the following content:
                        priority:     rule priority
                        name:         rule name
                        ingress_port: match input port of the rule
                        dst_mac:      match destination mac address of the rule, missing or None if not apply
                        vlan_id:      match vlan tag of the rule, missing or None if not apply
                        actions:      list of actions, composed by a pair tuples with these posibilities:
                            ('vlan', None/int): for stripping/setting a vlan tag
                            ('out', port):      send to this port
        :return: None if ok
                 Raise an openflowconnUnexpectedResponse exception if fails with text_error
        """
        # get translation, autodiscover version
        if len(self.pp2ofi) == 0:
            self.obtain_port_correspondence()

        try:
            # We have to build the data for the floodlight call from the generic data
            sdata = {'active': "true", "name": data["name"]}
            if data.get("priority"):
                sdata["priority"] = str(data["priority"])
            if data.get("vlan_id"):
                sdata[self.ver_names["vlanid"]] = data["vlan_id"]
            if data.get("dst_mac"):
                sdata[self.ver_names["destmac"]] = data["dst_mac"]
            sdata['switch'] = self.dpid
            if not data['ingress_port'] in self.pp2ofi:
                error_text = 'Error. Port ' + data['ingress_port'] + ' is not present in the switch'
                self.logger.warning("new_flow " + error_text)
                raise openflow_conn.OpenflowconnUnexpectedResponse(error_text)

            sdata[self.ver_names["inport"]] = self.pp2ofi[data['ingress_port']]
            sdata['actions'] = ""

            for action in data['actions']:
                if len(sdata['actions']) > 0:
                    sdata['actions'] += ','
                if action[0] == "vlan":
                    if action[1] == None:
                        sdata['actions'] += self.ver_names["stripvlan"]
                    else:
                        sdata['actions'] += self.ver_names["setvlan"] + "=" + str(action[1])
                elif action[0] == 'out':
                    sdata['actions'] += "output=" + self.pp2ofi[action[1]]

            of_response = requests.post(self.url + "/wm/%s/json" % self.ver_names["URLmodifier"],
                                        headers=self.headers, data=json.dumps(sdata))
            error_text = "Openflow response %d: %s" % (of_response.status_code, of_response.text)
            if of_response.status_code != 200:
                self.logger.warning("new_flow " + error_text)
                raise openflow_conn.OpenflowconnUnexpectedResponse(error_text)
            self.logger.debug("new_flow OK" + error_text)
            return None

        except requests.exceptions.RequestException as e:
            error_text = type(e).__name__ + ": " + str(e)
            self.logger.error("new_flow " + error_text)
            raise openflow_conn.OpenflowconnConnectionException(error_text)