1 # vim: tabstop=4 shiftwidth=4 softtabstop=4
2 # Copyright 2011 Nicira Networks, Inc.
5 # Licensed under the Apache License, Version 2.0 (the "License"); you may
6 # not use this file except in compliance with the License. You may obtain
7 # a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 # License for the specific language governing permissions and limitations
16 # @author: Somik Behera, Nicira Networks, Inc.
17 # @author: Brad Hall, Nicira Networks, Inc.
18 # @author: Dan Wendlandt, Nicira Networks, Inc.
19 # @author: Dave Lapsley, Nicira Networks, Inc.
20 # @author: Aaron Rosen, Nicira Networks, Inc.
21 # @author: Bob Kukura, Red Hat, Inc.
22 # @author: Seetharama Ayyadevara, Freescale Semiconductor, Inc.
26 from oslo.config import cfg
28 from neutron.agent import securitygroups_rpc as sg_rpc
29 from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api
30 from neutron.api.rpc.agentnotifiers import l3_rpc_agent_api
31 from neutron.api.v2 import attributes
32 from neutron.common import constants as q_const
33 from neutron.common import exceptions as q_exc
34 from neutron.common import rpc as q_rpc
35 from neutron.common import topics
36 from neutron.common import utils
37 from neutron.db import agents_db
38 from neutron.db import agentschedulers_db
39 from neutron.db import allowedaddresspairs_db as addr_pair_db
40 from neutron.db import db_base_plugin_v2
41 from neutron.db import dhcp_rpc_base
42 from neutron.db import external_net_db
43 from neutron.db import extradhcpopt_db
44 from neutron.db import extraroute_db
45 from neutron.db import l3_agentschedulers_db
46 from neutron.db import l3_gwmode_db
47 from neutron.db import l3_rpc_base
48 from neutron.db import portbindings_db
49 from neutron.db import quota_db # noqa
50 from neutron.db import securitygroups_rpc_base as sg_db_rpc
51 from neutron.extensions import allowedaddresspairs as addr_pair
52 from neutron.extensions import extra_dhcp_opt as edo_ext
53 from neutron.extensions import portbindings
54 from neutron.extensions import providernet as provider
55 from neutron.extensions import nat
56 from neutron import manager
57 from neutron.openstack.common import importutils
58 from neutron.openstack.common import log as logging
59 from neutron.openstack.common import rpc
60 from neutron.openstack.common.rpc import proxy
61 from neutron.plugins.common import constants as svc_constants
62 from neutron.plugins.common import utils as plugin_utils
63 from neutron.plugins.openvswitch.common import config # noqa
64 from neutron.plugins.openvswitch.common import constants
65 from neutron.plugins.openvswitch import ovs_db_v2
68 LOG = logging.getLogger(__name__)
71 class OVSRpcCallbacks(dhcp_rpc_base.DhcpRpcCallbackMixin,
72 l3_rpc_base.L3RpcCallbackMixin,
73 sg_db_rpc.SecurityGroupServerRpcCallbackMixin):
77 # 1.1 Support Security Group RPC
79 RPC_API_VERSION = '1.1'
81 def __init__(self, notifier, tunnel_type):
82 self.notifier = notifier
83 self.tunnel_type = tunnel_type
85 def create_rpc_dispatcher(self):
86 '''Get the rpc dispatcher for this manager.
88 If a manager would like to set an rpc API version, or support more than
89 one class as the target of rpc messages, override this method.
91 return q_rpc.PluginRpcDispatcher([self,
92 agents_db.AgentExtRpcCallback()])
95 def get_port_from_device(cls, device):
96 port = ovs_db_v2.get_port_from_device(device)
98 port['device'] = device
101 def get_device_details(self, rpc_context, **kwargs):
102 """Agent requests device details."""
103 agent_id = kwargs.get('agent_id')
104 device = kwargs.get('device')
105 LOG.debug(_("Device %(device)s details requested from %(agent_id)s"),
106 {'device': device, 'agent_id': agent_id})
107 port = ovs_db_v2.get_port(device)
109 binding = ovs_db_v2.get_network_binding(None, port['network_id'])
110 entry = {'device': device,
111 'network_id': port['network_id'],
112 'port_id': port['id'],
113 'admin_state_up': port['admin_state_up'],
114 'network_type': binding.network_type,
115 'segmentation_id': binding.segmentation_id,
116 'physical_network': binding.physical_network}
117 new_status = (q_const.PORT_STATUS_ACTIVE if port['admin_state_up']
118 else q_const.PORT_STATUS_DOWN)
119 if port['status'] != new_status:
120 ovs_db_v2.set_port_status(port['id'], new_status)
122 entry = {'device': device}
123 LOG.debug(_("%s can not be found in database"), device)
126 def update_device_down(self, rpc_context, **kwargs):
127 """Device no longer exists on agent."""
128 agent_id = kwargs.get('agent_id')
129 device = kwargs.get('device')
130 host = kwargs.get('host')
131 port = ovs_db_v2.get_port(device)
132 LOG.debug(_("Device %(device)s no longer exists on %(agent_id)s"),
133 {'device': device, 'agent_id': agent_id})
135 entry = {'device': device,
137 plugin = manager.NeutronManager.get_plugin()
139 not plugin.get_port_host(rpc_context, port['id']) == host):
140 LOG.debug(_("Device %(device)s not bound to the"
141 " agent host %(host)s"),
142 {'device': device, 'host': host})
143 elif port['status'] != q_const.PORT_STATUS_DOWN:
144 # Set port status to DOWN
145 ovs_db_v2.set_port_status(port['id'],
146 q_const.PORT_STATUS_DOWN)
148 entry = {'device': device,
150 LOG.debug(_("%s can not be found in database"), device)
153 def update_device_up(self, rpc_context, **kwargs):
154 """Device is up on agent."""
155 agent_id = kwargs.get('agent_id')
156 device = kwargs.get('device')
157 host = kwargs.get('host')
158 port = ovs_db_v2.get_port(device)
159 LOG.debug(_("Device %(device)s up on %(agent_id)s"),
160 {'device': device, 'agent_id': agent_id})
161 plugin = manager.NeutronManager.get_plugin()
164 not plugin.get_port_host(rpc_context, port['id']) == host):
165 LOG.debug(_("Device %(device)s not bound to the"
166 " agent host %(host)s"),
167 {'device': device, 'host': host})
169 elif port['status'] != q_const.PORT_STATUS_ACTIVE:
170 ovs_db_v2.set_port_status(port['id'],
171 q_const.PORT_STATUS_ACTIVE)
173 LOG.debug(_("%s can not be found in database"), device)
175 def tunnel_sync(self, rpc_context, **kwargs):
176 """Update new tunnel.
178 Updates the datbase with the tunnel IP. All listening agents will also
179 be notified about the new tunnel IP.
181 tunnel_ip = kwargs.get('tunnel_ip')
182 # Update the database with the IP
183 tunnel = ovs_db_v2.add_tunnel_endpoint(tunnel_ip)
184 tunnels = ovs_db_v2.get_tunnel_endpoints()
186 entry['tunnels'] = tunnels
187 # Notify all other listening agents
188 self.notifier.tunnel_update(rpc_context, tunnel.ip_address,
189 tunnel.id, self.tunnel_type)
190 # Return the list of tunnels IP's to the agent
194 class AgentNotifierApi(proxy.RpcProxy,
195 sg_rpc.SecurityGroupAgentRpcApiMixin):
196 '''Agent side of the openvswitch rpc API.
199 1.0 - Initial version.
203 BASE_RPC_API_VERSION = '1.0'
205 def __init__(self, topic):
206 super(AgentNotifierApi, self).__init__(
207 topic=topic, default_version=self.BASE_RPC_API_VERSION)
208 self.topic_network_delete = topics.get_topic_name(topic,
211 self.topic_port_update = topics.get_topic_name(topic,
214 self.topic_tunnel_update = topics.get_topic_name(topic,
218 def network_delete(self, context, network_id):
219 self.fanout_cast(context,
220 self.make_msg('network_delete',
221 network_id=network_id),
222 topic=self.topic_network_delete)
224 def port_update(self, context, port, network_type, segmentation_id,
226 self.fanout_cast(context,
227 self.make_msg('port_update',
229 network_type=network_type,
230 segmentation_id=segmentation_id,
231 physical_network=physical_network),
232 topic=self.topic_port_update)
234 def tunnel_update(self, context, tunnel_ip, tunnel_id, tunnel_type):
235 self.fanout_cast(context,
236 self.make_msg('tunnel_update',
239 tunnel_type=tunnel_type),
240 topic=self.topic_tunnel_update)
243 class OVSNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
244 external_net_db.External_net_db_mixin,
245 extraroute_db.ExtraRoute_db_mixin,
246 l3_gwmode_db.L3_NAT_db_mixin,
247 sg_db_rpc.SecurityGroupServerRpcMixin,
248 l3_agentschedulers_db.L3AgentSchedulerDbMixin,
249 agentschedulers_db.DhcpAgentSchedulerDbMixin,
250 portbindings_db.PortBindingMixin,
251 extradhcpopt_db.ExtraDhcpOptMixin,
252 addr_pair_db.AllowedAddressPairsMixin):
254 """Implement the Neutron abstractions using Open vSwitch.
256 Depending on whether tunneling is enabled, either a GRE, VXLAN tunnel or
257 a new VLAN is created for each network. An agent is relied upon to
258 perform the actual OVS configuration on each host.
260 The provider extension is also supported. As discussed in
261 https://bugs.launchpad.net/neutron/+bug/1023156, this class could
262 be simplified, and filtering on extended attributes could be
263 handled, by adding support for extended attributes to the
264 NeutronDbPluginV2 base class. When that occurs, this class should
265 be updated to take advantage of it.
267 The port binding extension enables an external application relay
268 information to and from the plugin.
271 # This attribute specifies whether the plugin supports or not
272 # bulk/pagination/sorting operations. Name mangling is used in
273 # order to ensure it is qualified by class
274 __native_bulk_support = True
275 __native_pagination_support = True
276 __native_sorting_support = True
278 _supported_extension_aliases = ["provider", "external-net", "router",
279 "ext-gw-mode", "binding", "quotas",
280 "security-group", "agent", "extraroute",
281 "l3_agent_scheduler",
282 "dhcp_agent_scheduler",
284 "allowed-address-pairs",
288 def supported_extension_aliases(self):
289 if not hasattr(self, '_aliases'):
290 aliases = self._supported_extension_aliases[:]
291 sg_rpc.disable_security_group_extension_if_noop_driver(aliases)
292 self._aliases = aliases
295 def __init__(self, configfile=None):
296 self.base_binding_dict = {
297 portbindings.VIF_TYPE: portbindings.VIF_TYPE_OVS,
298 portbindings.CAPABILITIES: {
299 portbindings.CAP_PORT_FILTER:
300 'security-group' in self.supported_extension_aliases}}
301 ovs_db_v2.initialize()
302 self._parse_network_vlan_ranges()
303 ovs_db_v2.sync_vlan_allocations(self.network_vlan_ranges)
304 self.tenant_network_type = cfg.CONF.OVS.tenant_network_type
305 if self.tenant_network_type not in [constants.TYPE_LOCAL,
308 constants.TYPE_VXLAN,
309 constants.TYPE_NONE]:
310 LOG.error(_("Invalid tenant_network_type: %s. "
311 "Server terminated!"),
312 self.tenant_network_type)
314 self.enable_tunneling = cfg.CONF.OVS.enable_tunneling
315 self.tunnel_type = None
316 if self.enable_tunneling:
317 self.tunnel_type = cfg.CONF.OVS.tunnel_type or constants.TYPE_GRE
318 elif cfg.CONF.OVS.tunnel_type:
319 self.tunnel_type = cfg.CONF.OVS.tunnel_type
320 self.enable_tunneling = True
321 self.tunnel_id_ranges = []
322 if self.enable_tunneling:
323 self._parse_tunnel_id_ranges()
324 ovs_db_v2.sync_tunnel_allocations(self.tunnel_id_ranges)
325 elif self.tenant_network_type in constants.TUNNEL_NETWORK_TYPES:
326 LOG.error(_("Tunneling disabled but tenant_network_type is '%s'. "
327 "Server terminated!"), self.tenant_network_type)
330 self.network_scheduler = importutils.import_object(
331 cfg.CONF.network_scheduler_driver
333 self.router_scheduler = importutils.import_object(
334 cfg.CONF.router_scheduler_driver
339 self.service_topics = {svc_constants.CORE: topics.PLUGIN,
340 svc_constants.L3_ROUTER_NAT: topics.L3PLUGIN}
341 self.conn = rpc.create_connection(new=True)
342 self.notifier = AgentNotifierApi(topics.AGENT)
343 self.agent_notifiers[q_const.AGENT_TYPE_DHCP] = (
344 dhcp_rpc_agent_api.DhcpAgentNotifyAPI()
346 self.agent_notifiers[q_const.AGENT_TYPE_L3] = (
347 l3_rpc_agent_api.L3AgentNotify
349 self.callbacks = OVSRpcCallbacks(self.notifier, self.tunnel_type)
350 self.dispatcher = self.callbacks.create_rpc_dispatcher()
351 for svc_topic in self.service_topics.values():
352 self.conn.create_consumer(svc_topic, self.dispatcher, fanout=False)
353 # Consume from all consumers in a thread
354 self.conn.consume_in_thread()
356 def _parse_network_vlan_ranges(self):
358 self.network_vlan_ranges = plugin_utils.parse_network_vlan_ranges(
359 cfg.CONF.OVS.network_vlan_ranges)
360 except Exception as ex:
361 LOG.error(_("%s. Server terminated!"), ex)
363 LOG.info(_("Network VLAN ranges: %s"), self.network_vlan_ranges)
365 def _parse_tunnel_id_ranges(self):
366 for entry in cfg.CONF.OVS.tunnel_id_ranges:
367 entry = entry.strip()
369 tun_min, tun_max = entry.split(':')
370 self.tunnel_id_ranges.append((int(tun_min), int(tun_max)))
371 except ValueError as ex:
372 LOG.error(_("Invalid tunnel ID range: "
373 "'%(range)s' - %(e)s. Server terminated!"),
374 {'range': entry, 'e': ex})
376 LOG.info(_("Tunnel ID ranges: %s"), self.tunnel_id_ranges)
378 def _extend_network_dict_provider(self, context, network):
379 binding = ovs_db_v2.get_network_binding(context.session,
381 network[provider.NETWORK_TYPE] = binding.network_type
382 if binding.network_type in constants.TUNNEL_NETWORK_TYPES:
383 network[provider.PHYSICAL_NETWORK] = None
384 network[provider.SEGMENTATION_ID] = binding.segmentation_id
385 elif binding.network_type == constants.TYPE_FLAT:
386 network[provider.PHYSICAL_NETWORK] = binding.physical_network
387 network[provider.SEGMENTATION_ID] = None
388 elif binding.network_type == constants.TYPE_VLAN:
389 network[provider.PHYSICAL_NETWORK] = binding.physical_network
390 network[provider.SEGMENTATION_ID] = binding.segmentation_id
391 elif binding.network_type == constants.TYPE_LOCAL:
392 network[provider.PHYSICAL_NETWORK] = None
393 network[provider.SEGMENTATION_ID] = None
395 def _process_provider_create(self, context, attrs):
396 network_type = attrs.get(provider.NETWORK_TYPE)
397 physical_network = attrs.get(provider.PHYSICAL_NETWORK)
398 segmentation_id = attrs.get(provider.SEGMENTATION_ID)
400 network_type_set = attributes.is_attr_set(network_type)
401 physical_network_set = attributes.is_attr_set(physical_network)
402 segmentation_id_set = attributes.is_attr_set(segmentation_id)
404 if not (network_type_set or physical_network_set or
405 segmentation_id_set):
406 return (None, None, None)
408 if not network_type_set:
409 msg = _("provider:network_type required")
410 raise q_exc.InvalidInput(error_message=msg)
411 elif network_type == constants.TYPE_FLAT:
412 if segmentation_id_set:
413 msg = _("provider:segmentation_id specified for flat network")
414 raise q_exc.InvalidInput(error_message=msg)
416 segmentation_id = constants.FLAT_VLAN_ID
417 elif network_type == constants.TYPE_VLAN:
418 if not segmentation_id_set:
419 msg = _("provider:segmentation_id required")
420 raise q_exc.InvalidInput(error_message=msg)
421 if not utils.is_valid_vlan_tag(segmentation_id):
422 msg = (_("provider:segmentation_id out of range "
423 "(%(min_id)s through %(max_id)s)") %
424 {'min_id': q_const.MIN_VLAN_TAG,
425 'max_id': q_const.MAX_VLAN_TAG})
426 raise q_exc.InvalidInput(error_message=msg)
427 elif network_type in constants.TUNNEL_NETWORK_TYPES:
428 if not self.enable_tunneling:
429 msg = _("%s networks are not enabled") % network_type
430 raise q_exc.InvalidInput(error_message=msg)
431 if physical_network_set:
432 msg = _("provider:physical_network specified for %s "
433 "network") % network_type
434 raise q_exc.InvalidInput(error_message=msg)
436 physical_network = None
437 if not segmentation_id_set:
438 msg = _("provider:segmentation_id required")
439 raise q_exc.InvalidInput(error_message=msg)
440 elif network_type == constants.TYPE_LOCAL:
441 if physical_network_set:
442 msg = _("provider:physical_network specified for local "
444 raise q_exc.InvalidInput(error_message=msg)
446 physical_network = None
447 if segmentation_id_set:
448 msg = _("provider:segmentation_id specified for local "
450 raise q_exc.InvalidInput(error_message=msg)
452 segmentation_id = None
454 msg = _("provider:network_type %s not supported") % network_type
455 raise q_exc.InvalidInput(error_message=msg)
457 if network_type in [constants.TYPE_VLAN, constants.TYPE_FLAT]:
458 if physical_network_set:
459 if physical_network not in self.network_vlan_ranges:
460 msg = _("Unknown provider:physical_network "
461 "%s") % physical_network
462 raise q_exc.InvalidInput(error_message=msg)
463 elif 'default' in self.network_vlan_ranges:
464 physical_network = 'default'
466 msg = _("provider:physical_network required")
467 raise q_exc.InvalidInput(error_message=msg)
469 return (network_type, physical_network, segmentation_id)
471 def create_network(self, context, network):
472 (network_type, physical_network,
473 segmentation_id) = self._process_provider_create(context,
476 session = context.session
477 #set up default security groups
478 tenant_id = self._get_tenant_id_for_create(
479 context, network['network'])
480 self._ensure_default_security_group(context, tenant_id)
482 with session.begin(subtransactions=True):
485 network_type = self.tenant_network_type
486 if network_type == constants.TYPE_NONE:
487 raise q_exc.TenantNetworksDisabled()
488 elif network_type == constants.TYPE_VLAN:
490 segmentation_id) = ovs_db_v2.reserve_vlan(session)
491 elif network_type in constants.TUNNEL_NETWORK_TYPES:
492 segmentation_id = ovs_db_v2.reserve_tunnel(session)
493 # no reservation needed for TYPE_LOCAL
496 if network_type in [constants.TYPE_VLAN, constants.TYPE_FLAT]:
497 ovs_db_v2.reserve_specific_vlan(session, physical_network,
499 elif network_type in constants.TUNNEL_NETWORK_TYPES:
500 ovs_db_v2.reserve_specific_tunnel(session, segmentation_id)
501 # no reservation needed for TYPE_LOCAL
502 net = super(OVSNeutronPluginV2, self).create_network(context,
504 ovs_db_v2.add_network_binding(session, net['id'], network_type,
505 physical_network, segmentation_id)
507 self._process_l3_create(context, net, network['network'])
508 self._extend_network_dict_provider(context, net)
509 # note - exception will rollback entire transaction
510 LOG.debug(_("Created network: %s"), net['id'])
513 def update_network(self, context, id, network):
514 provider._raise_if_updates_provider_attributes(network['network'])
516 session = context.session
517 with session.begin(subtransactions=True):
518 net = super(OVSNeutronPluginV2, self).update_network(context, id,
520 self._process_l3_update(context, net, network['network'])
521 self._extend_network_dict_provider(context, net)
524 def delete_network(self, context, id):
525 session = context.session
526 with session.begin(subtransactions=True):
527 binding = ovs_db_v2.get_network_binding(session, id)
528 super(OVSNeutronPluginV2, self).delete_network(context, id)
529 if binding.network_type in constants.TUNNEL_NETWORK_TYPES:
530 ovs_db_v2.release_tunnel(session, binding.segmentation_id,
531 self.tunnel_id_ranges)
532 elif binding.network_type in [constants.TYPE_VLAN,
533 constants.TYPE_FLAT]:
534 ovs_db_v2.release_vlan(session, binding.physical_network,
535 binding.segmentation_id,
536 self.network_vlan_ranges)
537 # the network_binding record is deleted via cascade from
538 # the network record, so explicit removal is not necessary
539 self.notifier.network_delete(context, id)
541 def get_network(self, context, id, fields=None):
542 session = context.session
543 with session.begin(subtransactions=True):
544 net = super(OVSNeutronPluginV2, self).get_network(context,
546 self._extend_network_dict_provider(context, net)
547 return self._fields(net, fields)
549 def get_networks(self, context, filters=None, fields=None,
551 limit=None, marker=None, page_reverse=False):
552 session = context.session
553 with session.begin(subtransactions=True):
554 nets = super(OVSNeutronPluginV2,
555 self).get_networks(context, filters, None, sorts,
556 limit, marker, page_reverse)
558 self._extend_network_dict_provider(context, net)
560 return [self._fields(net, fields) for net in nets]
562 def create_port(self, context, port):
563 # Set port status as 'DOWN'. This will be updated by agent
564 port['port']['status'] = q_const.PORT_STATUS_DOWN
565 port_data = port['port']
566 session = context.session
567 with session.begin(subtransactions=True):
568 self._ensure_default_security_group_on_port(context, port)
569 sgids = self._get_security_groups_on_port(context, port)
570 dhcp_opts = port['port'].get(edo_ext.EXTRADHCPOPTS, [])
571 port = super(OVSNeutronPluginV2, self).create_port(context, port)
572 self._process_portbindings_create_and_update(context,
574 self._process_port_create_security_group(context, port, sgids)
575 self._process_port_create_extra_dhcp_opts(context, port,
577 port[addr_pair.ADDRESS_PAIRS] = (
578 self._process_create_allowed_address_pairs(
580 port_data.get(addr_pair.ADDRESS_PAIRS)))
581 self.notify_security_groups_member_updated(context, port)
584 def _extend_port_dict_nat(self, context, port):
585 forward = ovs_db_v2.get_port_forwarding(context.session, port['id'])
587 port[nat.FORWARD_PORTS] = forward
589 port[nat.FORWARD_PORTS] = None
591 def _process_nat_update(self, context, attrs, id):
592 forward_ports = attrs.get(nat.FORWARD_PORTS)
593 forward_ports_set = attributes.is_attr_set(forward_ports)
595 if not forward_ports_set:
598 # LOG.info("forward ports %s" % forward_ports)
599 valid_protocols = ["tcp", "udp"]
600 for entry in forward_ports:
601 if not isinstance(entry, dict):
602 msg = _("nat:forward_ports: must specify a list of dicts (ex: 'l4_protocol=tcp,l4_port=80')")
603 raise q_exc.InvalidInput(error_message=msg)
604 if not ("l4_protocol" in entry and "l4_port" in entry):
605 msg = _("nat:forward_ports: dict is missing l4_protocol and l4_port (ex: 'l4_protocol=tcp,l4_port=80')")
606 raise q_exc.InvalidInput(error_message=msg)
607 if entry['l4_protocol'] not in valid_protocols:
608 msg = _("nat:forward_ports: invalid protocol (only tcp and udp allowed)")
609 raise q_exc.InvalidInput(error_message=msg)
611 l4_port = entry['l4_port']
614 (first, last) = l4_port.split(":")
618 msg = _("nat:forward_ports: l4_port range must be integer:integer")
619 raise q_exc.InvalidInput(error_message=msg)
622 l4_port = int(l4_port)
624 msg = _("nat:forward_ports: l4_port must be an integer")
625 raise q_exc.InvalidInput(error_message=msg)
629 def get_port(self, context, id, fields=None):
630 session = context.session
631 with session.begin(subtransactions=True):
632 port = super(OVSNeutronPluginV2, self).get_port(context, id, None)
633 self._extend_port_dict_nat(context, port)
634 return self._fields(port, fields)
636 def get_ports(self, context, filters=None, fields=None):
637 session = context.session
638 with session.begin(subtransactions=True):
639 ports = super(OVSNeutronPluginV2, self).get_ports(context, filters,
642 self._extend_port_dict_nat(context, port)
644 return [self._fields(port, fields) for port in ports]
646 def update_port(self, context, id, port):
647 forward_ports = self._process_nat_update(context, port['port'], id)
649 session = context.session
650 need_port_update_notify = False
651 changed_fixed_ips = 'fixed_ips' in port['port']
652 with session.begin(subtransactions=True):
653 original_port = super(OVSNeutronPluginV2, self).get_port(
655 updated_port = super(OVSNeutronPluginV2, self).update_port(
657 if addr_pair.ADDRESS_PAIRS in port['port']:
658 self._delete_allowed_address_pairs(context, id)
659 self._process_create_allowed_address_pairs(
660 context, updated_port,
661 port['port'][addr_pair.ADDRESS_PAIRS])
662 need_port_update_notify = True
663 elif changed_fixed_ips:
664 self._check_fixed_ips_and_address_pairs_no_overlap(
665 context, updated_port)
668 ovs_db_v2.clear_port_forwarding(session, updated_port['id'])
669 ovs_db_v2.add_port_forwarding(session, updated_port['id'], forward_ports)
\r
670 self._extend_port_dict_nat(context, updated_port)
672 need_port_update_notify |= self.update_security_group_on_port(
673 context, id, port, original_port, updated_port)
674 self._process_portbindings_create_and_update(context,
677 need_port_update_notify |= self._update_extra_dhcp_opts_on_port(
678 context, id, port, updated_port)
680 need_port_update_notify |= self.is_security_group_member_updated(
681 context, original_port, updated_port)
682 if original_port['admin_state_up'] != updated_port['admin_state_up']:
683 need_port_update_notify = True
685 if need_port_update_notify:
686 binding = ovs_db_v2.get_network_binding(None,
687 updated_port['network_id'])
688 self.notifier.port_update(context, updated_port,
689 binding.network_type,
690 binding.segmentation_id,
691 binding.physical_network)
694 def delete_port(self, context, id, l3_port_check=True):
696 # if needed, check to see if this is a port owned by
697 # and l3-router. If so, we should prevent deletion.
699 self.prevent_l3_port_deletion(context, id)
701 session = context.session
702 with session.begin(subtransactions=True):
703 self.disassociate_floatingips(context, id)
704 port = self.get_port(context, id)
705 self._delete_port_security_group_bindings(context, id)
706 super(OVSNeutronPluginV2, self).delete_port(context, id)
708 self.notify_security_groups_member_updated(context, port)