blob: f42f4dcc2fc37f82ce29733350449a624fcae8ba [file] [log] [blame]
mirabal6c600652017-03-16 17:22:57 +01001# -*- coding: utf-8 -*-
2
3##
4# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
5# This file is part of openmano
6# All Rights Reserved.
7#
8# Licensed under the Apache License, Version 2.0 (the "License"); you may
9# not use this file except in compliance with the License. You may obtain
10# a copy of the License at
11#
12# http://www.apache.org/licenses/LICENSE-2.0
13#
14# Unless required by applicable law or agreed to in writing, software
15# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17# License for the specific language governing permissions and limitations
18# under the License.
19#
20# For those usages not covered by the Apache License, Version 2.0 please
21# contact with: nfvlabs@tid.es
22##
23import logging
24import base64
25
26"""
27vimconn implement an Abstract class for the vim connector plugins
28 with the definition of the method to be implemented.
29"""
30__author__ = "Alfonso Tierno, Leonardo Mirabal"
31__date__ = "$16-oct-2015 11:09:29$"
32
33
34
35# Error variables
36HTTP_Bad_Request = 400
37HTTP_Unauthorized = 401
38HTTP_Not_Found = 404
39HTTP_Method_Not_Allowed = 405
40HTTP_Request_Timeout = 408
41HTTP_Conflict = 409
42HTTP_Not_Implemented = 501
43HTTP_Service_Unavailable = 503
44HTTP_Internal_Server_Error = 500
45
46
47class OpenflowconnException(Exception):
48 """Common and base class Exception for all vimconnector exceptions"""
49 def __init__(self, message, http_code=HTTP_Bad_Request):
50 Exception.__init__(self, message)
51 self.http_code = http_code
52
53
54class OpenflowconnConnectionException(OpenflowconnException):
55 """Connectivity error with the VIM"""
56 def __init__(self, message, http_code=HTTP_Service_Unavailable):
57 OpenflowconnException.__init__(self, message, http_code)
58
59
60class OpenflowconnUnexpectedResponse(OpenflowconnException):
61 """Get an wrong response from VIM"""
62 def __init__(self, message, http_code=HTTP_Internal_Server_Error):
63 OpenflowconnException.__init__(self, message, http_code)
64
65
66class OpenflowconnAuthException(OpenflowconnException):
67 """Invalid credentials or authorization to perform this action over the VIM"""
68 def __init__(self, message, http_code=HTTP_Unauthorized):
69 OpenflowconnException.__init__(self, message, http_code)
70
71
72class OpenflowconnNotFoundException(OpenflowconnException):
73 """The item is not found at VIM"""
74 def __init__(self, message, http_code=HTTP_Not_Found):
75 OpenflowconnException.__init__(self, message, http_code)
76
77
78class OpenflowconnConflictException(OpenflowconnException):
79 """There is a conflict, e.g. more item found than one"""
80 def __init__(self, message, http_code=HTTP_Conflict):
81 OpenflowconnException.__init__(self, message, http_code)
82
83
84class OpenflowconnNotSupportedException(OpenflowconnException):
85 """The request is not supported by connector"""
86 def __init__(self, message, http_code=HTTP_Service_Unavailable):
87 OpenflowconnException.__init__(self, message, http_code)
88
89
90class OpenflowconnNotImplemented(OpenflowconnException):
91 """The method is not implemented by the connected"""
92 def __init__(self, message, http_code=HTTP_Not_Implemented):
93 OpenflowconnException.__init__(self, message, http_code)
94
95
96class OpenflowConn:
97 """
98 Openflow controller connector abstract implementeation.
99 """
100 def __init__(self, params):
101 self.name = "openflow_conector"
102 self.headers = {'content-type': 'application/json', 'Accept': 'application/json'}
103 self.auth = None
104 self.pp2ofi = {} # From Physical Port to OpenFlow Index
105 self.ofi2pp = {} # From OpenFlow Index to Physical Port
106 self.dpid = '00:01:02:03:04:05:06:07'
107 self.id = 'openflow:00:01:02:03:04:05:06:07'
108 self.rules = {}
109 self.url = "http://%s:%s" % ('localhost', str(8081))
110 self.auth = base64.b64encode('of_user:of_password')
111 self.headers['Authorization'] = 'Basic ' + self.auth
112 self.logger = logging.getLogger('openflow_conn')
113 self.logger.setLevel(getattr(logging, params.get("of_debug", "ERROR")))
114 self.ip_address = None
115
116 def get_of_switches(self):
117 """"
118 Obtain a a list of switches or DPID detected by this controller
119 :return: list length, and a list where each element a tuple pair (DPID, IP address), text_error: if fails
120 """
121 raise OpenflowconnNotImplemented("Should have implemented this")
122
123 def obtain_port_correspondence(self):
124 """
125 Obtain the correspondence between physical and openflow port names
126 :return: dictionary: with physical name as key, openflow name as value, error_text: if fails
127 """
128 raise OpenflowconnNotImplemented("Should have implemented this")
129
130 def get_of_rules(self, translate_of_ports=True):
131 """
132 Obtain the rules inserted at openflow controller
133 :param translate_of_ports: if True it translates ports from openflow index to physical switch name
134 :return: dict if ok: with the rule name as key and value is another dictionary with the following content:
135 priority: rule priority
136 name: rule name (present also as the master dict key)
137 ingress_port: match input port of the rule
138 dst_mac: match destination mac address of the rule, can be missing or None if not apply
139 vlan_id: match vlan tag of the rule, can be missing or None if not apply
140 actions: list of actions, composed by a pair tuples:
141 (vlan, None/int): for stripping/setting a vlan tag
142 (out, port): send to this port
143 switch: DPID, all
144 text_error if fails
145 """
146 raise OpenflowconnNotImplemented("Should have implemented this")
147
148 def del_flow(self, flow_name):
149 """
150 Delete all existing rules
151 :param flow_name: flow_name, this is the rule name
152 :return: None if ok, text_error if fails
153 """
154 raise OpenflowconnNotImplemented("Should have implemented this")
155
156 def new_flow(self, data):
157 """
158 Insert a new static rule
159 :param data: dictionary with the following content:
160 priority: rule priority
161 name: rule name
162 ingress_port: match input port of the rule
163 dst_mac: match destination mac address of the rule, missing or None if not apply
164 vlan_id: match vlan tag of the rule, missing or None if not apply
165 actions: list of actions, composed by a pair tuples with these posibilities:
166 ('vlan', None/int): for stripping/setting a vlan tag
167 ('out', port): send to this port
168 :return: None if ok, text_error if fails
169 """
170 raise OpenflowconnNotImplemented("Should have implemented this")
171
172 def clear_all_flows(self):
173 """"
174 Delete all existing rules
175 :return: None if ok, text_error if fails
176 """
177 raise OpenflowconnNotImplemented("Should have implemented this")
178
179
180class OfTestConnector(OpenflowConn):
181 """
182 This is a fake openflow connector for testing.
183 It does nothing and it is used for running openvim without an openflow controller
184 """
185
186 def __init__(self, params):
187 OpenflowConn.__init__(self, params)
188
189 name = params.get("name", "test-ofc")
190 self.name = name
191 self.dpid = params.get("dpid")
192 self.rules = {}
193 self.logger = logging.getLogger('vim.OF.TEST')
194 self.logger.setLevel(getattr(logging, params.get("of_debug", "ERROR")))
195 self.pp2ofi = {}
196
197 def get_of_switches(self):
198 return ()
199
200 def obtain_port_correspondence(self):
201 return ()
202
203 def del_flow(self, flow_name):
204 if flow_name in self.rules:
205 self.logger.debug("del_flow OK")
206 del self.rules[flow_name]
207 return None
208 else:
209 self.logger.warning("del_flow not found")
210 raise OpenflowconnUnexpectedResponse("flow {} not found".format(flow_name))
211
212 def new_flow(self, data):
213 self.rules[data["name"]] = data
214 self.logger.debug("new_flow OK")
215 return None
216
217 def get_of_rules(self, translate_of_ports=True):
218 return self.rules
219
220 def clear_all_flows(self):
221 self.logger.debug("clear_all_flows OK")
222 self.rules = {}
223 return None