blob: e16145bd6bc3a71aab908063d83fe02449fa4d73 [file] [log] [blame]
# -*- coding: utf-8 -*-
##
# Copyright 2015 Telefonica Investigacion 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