ec12ac444c
Previously one could update a port to match one of the address_pairs. This patch prevents that. Fixes bug: 1223646 Change-Id: Ic8cecfdb83b3fd9d2691bb41e0427cf578577fc8
127 lines
5.5 KiB
Python
127 lines
5.5 KiB
Python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
#
|
|
# Copyright 2013 Nicira Networks, Inc. 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.
|
|
#
|
|
# @author: Aaron Rosen, Nicira, Inc
|
|
|
|
import sqlalchemy as sa
|
|
from sqlalchemy import orm
|
|
|
|
from neutron.api.v2 import attributes as attr
|
|
from neutron.db import db_base_plugin_v2
|
|
from neutron.db import model_base
|
|
from neutron.db import models_v2
|
|
from neutron.extensions import allowedaddresspairs as addr_pair
|
|
|
|
|
|
class AllowedAddressPair(model_base.BASEV2):
|
|
port_id = sa.Column(sa.String(36),
|
|
sa.ForeignKey('ports.id', ondelete="CASCADE"),
|
|
primary_key=True)
|
|
mac_address = sa.Column(sa.String(32), nullable=False, primary_key=True)
|
|
ip_address = sa.Column(sa.String(64), nullable=False, primary_key=True)
|
|
|
|
port = orm.relationship(
|
|
models_v2.Port,
|
|
backref=orm.backref("allowed_address_pairs",
|
|
lazy="joined", cascade="delete"))
|
|
|
|
|
|
class AllowedAddressPairsMixin(object):
|
|
"""Mixin class for allowed address pairs."""
|
|
|
|
def _process_create_allowed_address_pairs(self, context, port,
|
|
allowed_address_pairs):
|
|
if not attr.is_attr_set(allowed_address_pairs):
|
|
return []
|
|
with context.session.begin(subtransactions=True):
|
|
for address_pair in allowed_address_pairs:
|
|
# use port.mac_address if no mac address in address pair
|
|
if 'mac_address' not in address_pair:
|
|
address_pair['mac_address'] = port['mac_address']
|
|
for fixed_ip in port['fixed_ips']:
|
|
if ((fixed_ip['ip_address'] == address_pair['ip_address'])
|
|
and (port['mac_address'] ==
|
|
address_pair['mac_address'])):
|
|
raise addr_pair.AddressPairMatchesPortFixedIPAndMac()
|
|
db_pair = AllowedAddressPair(
|
|
port_id=port['id'],
|
|
mac_address=address_pair['mac_address'],
|
|
ip_address=address_pair['ip_address'])
|
|
context.session.add(db_pair)
|
|
|
|
return allowed_address_pairs
|
|
|
|
def _check_fixed_ips_and_address_pairs_no_overlap(self, context, port):
|
|
address_pairs = self.get_allowed_address_pairs(context, port['id'])
|
|
for fixed_ip in port['fixed_ips']:
|
|
for address_pair in address_pairs:
|
|
if (fixed_ip['ip_address'] == address_pair['ip_address']
|
|
and port['mac_address'] == address_pair['mac_address']):
|
|
raise addr_pair.AddressPairMatchesPortFixedIPAndMac()
|
|
|
|
def get_allowed_address_pairs(self, context, port_id):
|
|
pairs = (context.session.query(AllowedAddressPair).
|
|
filter_by(port_id=port_id))
|
|
return [self._make_allowed_address_pairs_dict(pair)
|
|
for pair in pairs]
|
|
|
|
def _extend_port_dict_allowed_address_pairs(self, port_res, port_db):
|
|
# If port_db is provided, allowed address pairs will be accessed via
|
|
# sqlalchemy models. As they're loaded together with ports this
|
|
# will not cause an extra query.
|
|
allowed_address_pairs = [
|
|
self._make_allowed_address_pairs_dict(address_pair) for
|
|
address_pair in port_db.allowed_address_pairs]
|
|
port_res[addr_pair.ADDRESS_PAIRS] = allowed_address_pairs
|
|
return port_res
|
|
|
|
# Register dict extend functions for ports
|
|
db_base_plugin_v2.NeutronDbPluginV2.register_dict_extend_funcs(
|
|
attr.PORTS, ['_extend_port_dict_allowed_address_pairs'])
|
|
|
|
def _delete_allowed_address_pairs(self, context, id):
|
|
query = self._model_query(context, AllowedAddressPair)
|
|
with context.session.begin(subtransactions=True):
|
|
query.filter(AllowedAddressPair.port_id == id).delete()
|
|
|
|
def _make_allowed_address_pairs_dict(self, allowed_address_pairs,
|
|
fields=None):
|
|
res = {'mac_address': allowed_address_pairs['mac_address'],
|
|
'ip_address': allowed_address_pairs['ip_address']}
|
|
return self._fields(res, fields)
|
|
|
|
def _has_address_pairs(self, port):
|
|
return (attr.is_attr_set(port['port'][addr_pair.ADDRESS_PAIRS])
|
|
and port['port'][addr_pair.ADDRESS_PAIRS] != [])
|
|
|
|
def _check_update_has_allowed_address_pairs(self, port):
|
|
"""Determine if request has an allowed address pair.
|
|
|
|
Return True if the port parameter has a non-empty
|
|
'allowed_address_pairs' attribute. Otherwise returns False.
|
|
"""
|
|
return (addr_pair.ADDRESS_PAIRS in port['port'] and
|
|
self._has_address_pairs(port))
|
|
|
|
def _check_update_deletes_allowed_address_pairs(self, port):
|
|
"""Determine if request deletes address pair.
|
|
|
|
Return True if port has as a allowed address pair and its value
|
|
is either [] or not is_attr_set, otherwise return False
|
|
"""
|
|
return (addr_pair.ADDRESS_PAIRS in port['port'] and
|
|
not self._has_address_pairs(port))
|