1
# Copyright 2012-2013 NEC Corporation. All rights reserved.
3
# Licensed under the Apache License, Version 2.0 (the "License"); you may
4
# not use this file except in compliance with the License. You may obtain
5
# a copy of the License at
7
# http://www.apache.org/licenses/LICENSE-2.0
9
# Unless required by applicable law or agreed to in writing, software
10
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
# License for the specific language governing permissions and limitations
15
from oslo.utils import excutils
17
from neutron.i18n import _LE
18
from neutron.openstack.common import log as logging
19
from neutron.plugins.nec.common import config
20
from neutron.plugins.nec.common import exceptions as nexc
21
from neutron.plugins.nec.db import packetfilter as pf_db
24
LOG = logging.getLogger(__name__)
27
class PacketFilterMixin(pf_db.PacketFilterDbMixin):
28
"""Mixin class to add packet filter to NECPluginV2."""
31
def packet_filter_enabled(self):
32
if not hasattr(self, '_packet_filter_enabled'):
33
self._packet_filter_enabled = (
34
config.OFC.enable_packet_filter and
35
self.ofc.driver.filter_supported())
36
return self._packet_filter_enabled
38
def remove_packet_filter_extension_if_disabled(self, aliases):
39
if not self.packet_filter_enabled:
40
LOG.debug('Disabled packet-filter extension.')
41
aliases.remove('packet-filter')
43
def create_packet_filter(self, context, packet_filter):
44
"""Create a new packet_filter entry on DB, then try to activate it."""
45
LOG.debug("create_packet_filter() called, packet_filter=%s .",
48
if hasattr(self.ofc.driver, 'validate_filter_create'):
49
pf = packet_filter['packet_filter']
50
self.ofc.driver.validate_filter_create(context, pf)
51
pf = super(PacketFilterMixin, self).create_packet_filter(
52
context, packet_filter)
54
return self.activate_packet_filter_if_ready(context, pf)
56
def update_packet_filter(self, context, id, packet_filter):
57
"""Update packet_filter entry on DB, and recreate it if changed.
59
If any rule of the packet_filter was changed, recreate it on OFC.
61
LOG.debug("update_packet_filter() called, "
62
"id=%(id)s packet_filter=%(packet_filter)s .",
63
{'id': id, 'packet_filter': packet_filter})
65
pf_data = packet_filter['packet_filter']
66
if hasattr(self.ofc.driver, 'validate_filter_update'):
67
self.ofc.driver.validate_filter_update(context, pf_data)
70
pf_old = self.get_packet_filter(context, id)
72
pf = super(PacketFilterMixin, self).update_packet_filter(
73
context, id, packet_filter)
75
def _packet_filter_changed(old_pf, new_pf):
76
LOG.debug('old_pf=%(old_pf)s, new_pf=%(new_pf)s',
77
{'old_pf': old_pf, 'new_pf': new_pf})
78
# When the status is ERROR, force sync to OFC.
79
if old_pf['status'] == pf_db.PF_STATUS_ERROR:
80
LOG.debug('update_packet_filter: Force filter update '
81
'because the previous status is ERROR.')
84
if key in ('id', 'name', 'tenant_id', 'network_id',
87
if old_pf[key] != new_pf[key]:
91
if _packet_filter_changed(pf_old, pf):
92
if hasattr(self.ofc.driver, 'update_filter'):
93
# admin_state is changed
94
if pf_old['admin_state_up'] != pf['admin_state_up']:
95
LOG.debug('update_packet_filter: admin_state '
96
'is changed to %s', pf['admin_state_up'])
97
if pf['admin_state_up']:
98
self.activate_packet_filter_if_ready(context, pf)
100
self.deactivate_packet_filter(context, pf)
101
elif pf['admin_state_up']:
102
LOG.debug('update_packet_filter: admin_state is '
104
if self.ofc.exists_ofc_packet_filter(context, id):
105
pf = self._update_packet_filter(context, pf, pf_data)
107
pf = self.activate_packet_filter_if_ready(context, pf)
109
LOG.debug('update_packet_filter: admin_state is unchanged '
110
'(False). No need to update OFC filter.')
112
pf = self.deactivate_packet_filter(context, pf)
113
pf = self.activate_packet_filter_if_ready(context, pf)
117
def _update_packet_filter(self, context, new_pf, pf_data):
119
prev_status = new_pf['status']
121
# If previous status is ERROR, try to sync all attributes.
122
pf = new_pf if prev_status == pf_db.PF_STATUS_ERROR else pf_data
123
self.ofc.update_ofc_packet_filter(context, pf_id, pf)
124
new_status = pf_db.PF_STATUS_ACTIVE
125
if new_status != prev_status:
126
self._update_resource_status(context, "packet_filter",
128
new_pf['status'] = new_status
130
except Exception as exc:
131
with excutils.save_and_reraise_exception():
132
if (isinstance(exc, nexc.OFCException) or
133
isinstance(exc, nexc.OFCConsistencyBroken)):
134
LOG.error(_LE("Failed to create packet_filter id=%(id)s "
136
{'id': pf_id, 'exc': exc})
137
new_status = pf_db.PF_STATUS_ERROR
138
if new_status != prev_status:
139
self._update_resource_status(context, "packet_filter",
142
def delete_packet_filter(self, context, id):
143
"""Deactivate and delete packet_filter."""
144
LOG.debug("delete_packet_filter() called, id=%s .", id)
147
pf = self.get_packet_filter(context, id)
149
# deactivate_packet_filter() raises an exception
150
# if an error occurs during processing.
151
pf = self.deactivate_packet_filter(context, pf)
153
super(PacketFilterMixin, self).delete_packet_filter(context, id)
155
def activate_packet_filter_if_ready(self, context, packet_filter):
156
"""Activate packet_filter by creating filter on OFC if ready.
158
Conditions to create packet_filter on OFC are:
159
* packet_filter admin_state is UP
160
* (if 'in_port' is specified) portinfo is available
162
LOG.debug("activate_packet_filter_if_ready() called, "
163
"packet_filter=%s.", packet_filter)
165
pf_id = packet_filter['id']
166
current = packet_filter['status']
169
if not packet_filter['admin_state_up']:
170
LOG.debug("activate_packet_filter_if_ready(): skip pf_id=%s, "
171
"packet_filter.admin_state_up is False.", pf_id)
172
elif self.ofc.exists_ofc_packet_filter(context, packet_filter['id']):
173
LOG.debug("_activate_packet_filter_if_ready(): skip, "
174
"ofc_packet_filter already exists.")
176
LOG.debug("activate_packet_filter_if_ready(): create "
177
"packet_filter id=%s on OFC.", pf_id)
179
self.ofc.create_ofc_packet_filter(context, pf_id,
181
pf_status = pf_db.PF_STATUS_ACTIVE
182
except nexc.PortInfoNotFound:
183
LOG.debug("Skipped to create a packet filter pf_id=%s "
184
"on OFC, no portinfo for the in_port.", pf_id)
185
except (nexc.OFCException, nexc.OFCMappingNotFound) as exc:
186
LOG.error(_LE("Failed to create packet_filter id=%(id)s on "
187
"OFC: %(exc)s"), {'id': pf_id, 'exc': exc})
188
pf_status = pf_db.PF_STATUS_ERROR
190
if pf_status != current:
191
self._update_resource_status(context, "packet_filter", pf_id,
193
packet_filter.update({'status': pf_status})
197
def deactivate_packet_filter(self, context, packet_filter):
198
"""Deactivate packet_filter by deleting filter from OFC if exixts."""
199
LOG.debug("deactivate_packet_filter_if_ready() called, "
200
"packet_filter=%s.", packet_filter)
201
pf_id = packet_filter['id']
203
if not self.ofc.exists_ofc_packet_filter(context, pf_id):
204
LOG.debug("deactivate_packet_filter(): skip, "
205
"Not found OFC Mapping for packet_filter id=%s.",
209
LOG.debug("deactivate_packet_filter(): "
210
"deleting packet_filter id=%s from OFC.", pf_id)
212
self.ofc.delete_ofc_packet_filter(context, pf_id)
213
self._update_resource_status_if_changed(
214
context, "packet_filter", packet_filter, pf_db.PF_STATUS_DOWN)
216
except (nexc.OFCException, nexc.OFCMappingNotFound) as exc:
217
with excutils.save_and_reraise_exception():
218
LOG.error(_LE("Failed to delete packet_filter id=%(id)s "
219
"from OFC: %(exc)s"),
220
{'id': pf_id, 'exc': exc})
221
self._update_resource_status_if_changed(
222
context, "packet_filter", packet_filter,
223
pf_db.PF_STATUS_ERROR)
225
def activate_packet_filters_by_port(self, context, port_id):
226
if not self.packet_filter_enabled:
229
filters = {'in_port': [port_id], 'admin_state_up': [True],
230
'status': [pf_db.PF_STATUS_DOWN]}
231
pfs = self.get_packet_filters(context, filters=filters)
233
self.activate_packet_filter_if_ready(context, pf)
235
def deactivate_packet_filters_by_port(self, context, port_id,
237
if not self.packet_filter_enabled:
240
filters = {'in_port': [port_id], 'status': [pf_db.PF_STATUS_ACTIVE]}
241
pfs = self.get_packet_filters(context, filters=filters)
245
self.deactivate_packet_filter(context, pf)
246
except (nexc.OFCException, nexc.OFCMappingNotFound):
248
if raise_exc and error:
249
raise nexc.OFCException(_('Error occurred while disabling packet '
250
'filter(s) for port %s'), port_id)
252
def get_packet_filters_for_port(self, context, port):
253
if self.packet_filter_enabled:
254
return super(PacketFilterMixin,
255
self).get_packet_filters_for_port(context, port)