--- /dev/null
+# -*- coding: utf-8 -*-
+
+##
+# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
+# This file is part of openmano
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: nfvlabs@tid.es
+##
+import logging
+import base64
+
+"""
+vimconn implement an Abstract class for the vim connector plugins
+ with the definition of the method to be implemented.
+"""
+__author__ = "Alfonso Tierno, Leonardo Mirabal"
+__date__ = "$16-oct-2015 11:09:29$"
+
+
+
+# Error variables
+HTTP_Bad_Request = 400
+HTTP_Unauthorized = 401
+HTTP_Not_Found = 404
+HTTP_Method_Not_Allowed = 405
+HTTP_Request_Timeout = 408
+HTTP_Conflict = 409
+HTTP_Not_Implemented = 501
+HTTP_Service_Unavailable = 503
+HTTP_Internal_Server_Error = 500
+
+
+class OpenflowconnException(Exception):
+ """Common and base class Exception for all vimconnector exceptions"""
+ def __init__(self, message, http_code=HTTP_Bad_Request):
+ Exception.__init__(self, message)
+ self.http_code = http_code
+
+
+class OpenflowconnConnectionException(OpenflowconnException):
+ """Connectivity error with the VIM"""
+ def __init__(self, message, http_code=HTTP_Service_Unavailable):
+ OpenflowconnException.__init__(self, message, http_code)
+
+
+class OpenflowconnUnexpectedResponse(OpenflowconnException):
+ """Get an wrong response from VIM"""
+ def __init__(self, message, http_code=HTTP_Internal_Server_Error):
+ 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=HTTP_Unauthorized):
+ OpenflowconnException.__init__(self, message, http_code)
+
+
+class OpenflowconnNotFoundException(OpenflowconnException):
+ """The item is not found at VIM"""
+ def __init__(self, message, http_code=HTTP_Not_Found):
+ 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=HTTP_Conflict):
+ OpenflowconnException.__init__(self, message, http_code)
+
+
+class OpenflowconnNotSupportedException(OpenflowconnException):
+ """The request is not supported by connector"""
+ def __init__(self, message, http_code=HTTP_Service_Unavailable):
+ OpenflowconnException.__init__(self, message, http_code)
+
+
+class OpenflowconnNotImplemented(OpenflowconnException):
+ """The method is not implemented by the connected"""
+ def __init__(self, message, http_code=HTTP_Not_Implemented):
+ OpenflowconnException.__init__(self, message, http_code)
+
+
+class OpenflowConn:
+ """
+ Openflow controller connector abstract implementeation.
+ """
+ def __init__(self, params):
+ self.name = "openflow_conector"
+ self.headers = {'content-type': 'application/json', 'Accept': 'application/json'}
+ self.auth = None
+ self.pp2ofi = {} # From Physical Port to OpenFlow Index
+ self.ofi2pp = {} # From OpenFlow Index to Physical Port
+ self.dpid = '00:01:02:03:04:05:06:07'
+ self.id = 'openflow:00:01:02:03:04:05:06:07'
+ self.rules = {}
+ self.url = "http://%s:%s" % ('localhost', str(8081))
+ self.auth = base64.b64encode('of_user:of_password')
+ self.headers['Authorization'] = 'Basic ' + self.auth
+ self.logger = logging.getLogger('openflow_conn')
+ self.logger.setLevel(getattr(logging, params.get("of_debug", "ERROR")))
+ self.ip_address = None
+
+ 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
+ """
+ raise OpenflowconnNotImplemented("Should have implemented this")
+
+ 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, error_text: if fails
+ """
+ raise OpenflowconnNotImplemented("Should have implemented this")
+
+ 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
+ text_error if fails
+ """
+ raise OpenflowconnNotImplemented("Should have implemented this")
+
+ def del_flow(self, flow_name):
+ """
+ Delete all existing rules
+ :param flow_name: flow_name, this is the rule name
+ :return: None if ok, text_error if fails
+ """
+ raise OpenflowconnNotImplemented("Should have implemented this")
+
+ 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, text_error if fails
+ """
+ raise OpenflowconnNotImplemented("Should have implemented this")
+
+ def clear_all_flows(self):
+ """"
+ Delete all existing rules
+ :return: None if ok, text_error if fails
+ """
+ raise OpenflowconnNotImplemented("Should have implemented this")
+
+
+class OfTestConnector(OpenflowConn):
+ """
+ This is a fake openflow connector for testing.
+ It does nothing and it is used for running openvim without an openflow controller
+ """
+
+ def __init__(self, params):
+ OpenflowConn.__init__(self, params)
+
+ name = params.get("name", "test-ofc")
+ self.name = name
+ self.dpid = params.get("dpid")
+ self.rules = {}
+ self.logger = logging.getLogger('vim.OF.TEST')
+ self.logger.setLevel(getattr(logging, params.get("of_debug", "ERROR")))
+ self.pp2ofi = {}
+
+ def get_of_switches(self):
+ return ()
+
+ def obtain_port_correspondence(self):
+ return ()
+
+ def del_flow(self, flow_name):
+ if flow_name in self.rules:
+ self.logger.debug("del_flow OK")
+ del self.rules[flow_name]
+ return None
+ else:
+ self.logger.warning("del_flow not found")
+ raise OpenflowconnUnexpectedResponse("flow {} not found".format(flow_name))
+
+ def new_flow(self, data):
+ self.rules[data["name"]] = data
+ self.logger.debug("new_flow OK")
+ return None
+
+ def get_of_rules(self, translate_of_ports=True):
+ return self.rules
+
+ def clear_all_flows(self):
+ self.logger.debug("clear_all_flows OK")
+ self.rules = {}
+ return None